[U-Boot] [PATCH v7 0/3] mmc: meson: add MMC support for Meson GX (S905)

This patch set implements eMMC on Amlogic Meson GX (S905). It's based on Carlo Caione's work submitted here: http://lists.denx.de/pipermail/u-boot/2016-May/254391.html
Changes to the original version: - BLK support added - fully DT-based now - minor general refactoring
The driver was successfully tested on a Odroid C2.
Note: On Odroid C2 eMMC is MMC device 1. So you have to switch from MMC device 0 to 1 first when testing from uboot prompt.
Latest change in v7: - rebase due to other recent mmc changes
Heiner Kallweit (3): arm: dts: update Meson GXBB / Odroid-C2 DT with recent Linux version mmc: meson: add MMC driver for Meson GX (S905) odroid-c2: enable new Meson GX MMC driver in board defconfig
arch/arm/dts/meson-gx.dtsi | 447 +++++++++++++++++++ arch/arm/dts/meson-gxbb-odroidc2.dts | 147 +++++- arch/arm/dts/meson-gxbb.dtsi | 718 ++++++++++++++++++------------ arch/arm/include/asm/arch-meson/sd_emmc.h | 89 ++++ configs/odroid-c2_defconfig | 5 +- drivers/mmc/Kconfig | 6 + drivers/mmc/Makefile | 1 + drivers/mmc/meson_gx_mmc.c | 291 ++++++++++++ include/dt-bindings/clock/gxbb-aoclkc.h | 66 +++ include/dt-bindings/clock/gxbb-clkc.h | 34 ++ include/dt-bindings/reset/gxbb-aoclkc.h | 66 +++ 11 files changed, 1594 insertions(+), 276 deletions(-) create mode 100644 arch/arm/dts/meson-gx.dtsi create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_gx_mmc.c create mode 100644 include/dt-bindings/clock/gxbb-aoclkc.h create mode 100644 include/dt-bindings/clock/gxbb-clkc.h create mode 100644 include/dt-bindings/reset/gxbb-aoclkc.h

As a prerequisite for adding a Meson GX MMC driver update the Meson GXBB / Odroid-C2 device tree in Uboot with the latest version from Linux.
Signed-off-by: Neil Armstrong narmstrong@baylibre.com Signed-off-by: Carlo Caione carlo@endlessm.com Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com --- v4: - Added SoB of original authors v5: - no changes v6: - changed prefix in subject v7: - rebased --- arch/arm/dts/meson-gx.dtsi | 447 ++++++++++++++++++++ arch/arm/dts/meson-gxbb-odroidc2.dts | 147 ++++++- arch/arm/dts/meson-gxbb.dtsi | 718 ++++++++++++++++++++------------ include/dt-bindings/clock/gxbb-aoclkc.h | 66 +++ include/dt-bindings/clock/gxbb-clkc.h | 34 ++ include/dt-bindings/reset/gxbb-aoclkc.h | 66 +++ 6 files changed, 1203 insertions(+), 275 deletions(-) create mode 100644 arch/arm/dts/meson-gx.dtsi create mode 100644 include/dt-bindings/clock/gxbb-aoclkc.h create mode 100644 include/dt-bindings/clock/gxbb-clkc.h create mode 100644 include/dt-bindings/reset/gxbb-aoclkc.h
diff --git a/arch/arm/dts/meson-gx.dtsi b/arch/arm/dts/meson-gx.dtsi new file mode 100644 index 0000000..c129100 --- /dev/null +++ b/arch/arm/dts/meson-gx.dtsi @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2016 Andreas Färber + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong narmstrong@baylibre.com + * + * Copyright (c) 2016 Endless Computers, Inc. + * Author: Carlo Caione carlo@endlessm.com + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/arm-gic.h> + +/ { + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 16 MiB reserved for Hardware ROM Firmware */ + hwrom_reserved: hwrom@0 { + reg = <0x0 0x0 0x0 0x1000000>; + no-map; + }; + + /* 2 MiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@10000000 { + reg = <0x0 0x10000000 0x0 0x200000>; + no-map; + }; + }; + + cpus { + #address-cells = <0x2>; + #size-cells = <0x0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&l2>; + clocks = <&scpi_dvfs 0>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + next-level-cache = <&l2>; + clocks = <&scpi_dvfs 0>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + next-level-cache = <&l2>; + clocks = <&scpi_dvfs 0>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a53", "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + next-level-cache = <&l2>; + clocks = <&scpi_dvfs 0>; + }; + + l2: l2-cache0 { + compatible = "cache"; + }; + }; + + arm-pmu { + compatible = "arm,cortex-a53-pmu"; + interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; + interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <GIC_PPI 13 + (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 14 + (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 11 + (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>, + <GIC_PPI 10 + (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>; + }; + + xtal: xtal-clk { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; + + firmware { + sm: secure-monitor { + compatible = "amlogic,meson-gx-sm", "amlogic,meson-gxbb-sm"; + }; + }; + + efuse: efuse { + compatible = "amlogic,meson-gx-efuse", "amlogic,meson-gxbb-efuse"; + #address-cells = <1>; + #size-cells = <1>; + + sn: sn@14 { + reg = <0x14 0x10>; + }; + + eth_mac: eth_mac@34 { + reg = <0x34 0x10>; + }; + + bid: bid@46 { + reg = <0x46 0x30>; + }; + }; + + scpi { + compatible = "amlogic,meson-gxbb-scpi", "arm,scpi-pre-1.0"; + mboxes = <&mailbox 1 &mailbox 2>; + shmem = <&cpu_scp_lpri &cpu_scp_hpri>; + + scpi_clocks: clocks { + compatible = "arm,scpi-clocks"; + + scpi_dvfs: scpi_clocks@0 { + compatible = "arm,scpi-dvfs-clocks"; + #clock-cells = <1>; + clock-indices = <0>; + clock-output-names = "vcpu"; + }; + }; + + scpi_sensors: sensors { + compatible = "arm,scpi-sensors"; + #thermal-sensor-cells = <1>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cbus: cbus@c1100000 { + compatible = "simple-bus"; + reg = <0x0 0xc1100000 0x0 0x100000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>; + + reset: reset-controller@4404 { + compatible = "amlogic,meson-gx-reset", "amlogic,meson-gxbb-reset"; + reg = <0x0 0x04404 0x0 0x20>; + #reset-cells = <1>; + }; + + uart_A: serial@84c0 { + compatible = "amlogic,meson-uart"; + reg = <0x0 0x84c0 0x0 0x14>; + interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + + uart_B: serial@84dc { + compatible = "amlogic,meson-uart"; + reg = <0x0 0x84dc 0x0 0x14>; + interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + + i2c_A: i2c@8500 { + compatible = "amlogic,meson-gxbb-i2c"; + reg = <0x0 0x08500 0x0 0x20>; + interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + pwm_ab: pwm@8550 { + compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm"; + reg = <0x0 0x08550 0x0 0x10>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_cd: pwm@8650 { + compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm"; + reg = <0x0 0x08650 0x0 0x10>; + #pwm-cells = <3>; + status = "disabled"; + }; + + pwm_ef: pwm@86c0 { + compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm"; + reg = <0x0 0x086c0 0x0 0x10>; + #pwm-cells = <3>; + status = "disabled"; + }; + + uart_C: serial@8700 { + compatible = "amlogic,meson-uart"; + reg = <0x0 0x8700 0x0 0x14>; + interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + + i2c_B: i2c@87c0 { + compatible = "amlogic,meson-gxbb-i2c"; + reg = <0x0 0x087c0 0x0 0x20>; + interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c_C: i2c@87e0 { + compatible = "amlogic,meson-gxbb-i2c"; + reg = <0x0 0x087e0 0x0 0x20>; + interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + watchdog@98d0 { + compatible = "amlogic,meson-gx-wdt", "amlogic,meson-gxbb-wdt"; + reg = <0x0 0x098d0 0x0 0x10>; + clocks = <&xtal>; + }; + }; + + gic: interrupt-controller@c4301000 { + compatible = "arm,gic-400"; + reg = <0x0 0xc4301000 0 0x1000>, + <0x0 0xc4302000 0 0x2000>, + <0x0 0xc4304000 0 0x2000>, + <0x0 0xc4306000 0 0x2000>; + interrupt-controller; + interrupts = <GIC_PPI 9 + (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>; + #interrupt-cells = <3>; + #address-cells = <0>; + }; + + sram: sram@c8000000 { + compatible = "amlogic,meson-gxbb-sram", "mmio-sram"; + reg = <0x0 0xc8000000 0x0 0x14000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0xc8000000 0x14000>; + + cpu_scp_lpri: scp-shmem@0 { + compatible = "amlogic,meson-gxbb-scp-shmem"; + reg = <0x13000 0x400>; + }; + + cpu_scp_hpri: scp-shmem@200 { + compatible = "amlogic,meson-gxbb-scp-shmem"; + reg = <0x13400 0x400>; + }; + }; + + aobus: aobus@c8100000 { + compatible = "simple-bus"; + reg = <0x0 0xc8100000 0x0 0x100000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>; + + uart_AO: serial@4c0 { + compatible = "amlogic,meson-uart"; + reg = <0x0 0x004c0 0x0 0x14>; + interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + + uart_AO_B: serial@4e0 { + compatible = "amlogic,meson-uart"; + reg = <0x0 0x004e0 0x0 0x14>; + interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + status = "disabled"; + }; + + ir: ir@580 { + compatible = "amlogic,meson-gxbb-ir"; + reg = <0x0 0x00580 0x0 0x40>; + interrupts = <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>; + status = "disabled"; + }; + }; + + periphs: periphs@c8834000 { + compatible = "simple-bus"; + reg = <0x0 0xc8834000 0x0 0x2000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xc8834000 0x0 0x2000>; + + rng { + compatible = "amlogic,meson-rng"; + reg = <0x0 0x0 0x0 0x4>; + }; + }; + + + hiubus: hiubus@c883c000 { + compatible = "simple-bus"; + reg = <0x0 0xc883c000 0x0 0x2000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xc883c000 0x0 0x2000>; + + mailbox: mailbox@404 { + compatible = "amlogic,meson-gx-mhu", "amlogic,meson-gxbb-mhu"; + reg = <0 0x404 0 0x4c>; + interrupts = <0 208 IRQ_TYPE_EDGE_RISING>, + <0 209 IRQ_TYPE_EDGE_RISING>, + <0 210 IRQ_TYPE_EDGE_RISING>; + #mbox-cells = <1>; + }; + }; + + ethmac: ethernet@c9410000 { + compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac"; + reg = <0x0 0xc9410000 0x0 0x10000 + 0x0 0xc8834540 0x0 0x4>; + interrupts = <0 8 1>; + interrupt-names = "macirq"; + phy-mode = "rgmii"; + status = "disabled"; + }; + + apb: apb@d0000000 { + compatible = "simple-bus"; + reg = <0x0 0xd0000000 0x0 0x200000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>; + + sd_emmc_a: mmc@70000 { + compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc"; + reg = <0x0 0x70000 0x0 0x2000>; + interrupts = <GIC_SPI 216 IRQ_TYPE_EDGE_RISING>; + status = "disabled"; + }; + + sd_emmc_b: mmc@72000 { + compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc"; + reg = <0x0 0x72000 0x0 0x2000>; + interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>; + status = "disabled"; + }; + + sd_emmc_c: mmc@74000 { + compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc"; + reg = <0x0 0x74000 0x0 0x2000>; + interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>; + status = "disabled"; + }; + }; + + vpu: vpu@d0100000 { + compatible = "amlogic,meson-gx-vpu"; + reg = <0x0 0xd0100000 0x0 0x100000>, + <0x0 0xc883c000 0x0 0x1000>, + <0x0 0xc8838000 0x0 0x1000>; + reg-names = "vpu", "hhi", "dmc"; + interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + + /* CVBS VDAC output port */ + cvbs_vdac_port: port@0 { + reg = <0>; + }; + }; + }; +}; diff --git a/arch/arm/dts/meson-gxbb-odroidc2.dts b/arch/arm/dts/meson-gxbb-odroidc2.dts index 79bee64..c737183 100644 --- a/arch/arm/dts/meson-gxbb-odroidc2.dts +++ b/arch/arm/dts/meson-gxbb-odroidc2.dts @@ -64,6 +64,18 @@ reg = <0x0 0x0 0x0 0x80000000>; };
+ usb_otg_pwr: regulator-usb-pwrs { + compatible = "regulator-fixed"; + + regulator-name = "USB_OTG_PWR"; + + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + + gpio = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + leds { compatible = "gpio-leds"; blue { @@ -73,6 +85,60 @@ default-state = "off"; }; }; + + tflash_vdd: regulator-tflash_vdd { + /* + * signal name from schematics: TFLASH_VDD_EN + */ + compatible = "regulator-fixed"; + + regulator-name = "TFLASH_VDD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&gpio_ao GPIOAO_12 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + tf_io: gpio-regulator-tf_io { + compatible = "regulator-gpio"; + + regulator-name = "TF_IO"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + /* + * signal name from schematics: TF_3V3N_1V8_EN + */ + gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>; + gpios-states = <0>; + + states = <3300000 0 + 1800000 1>; + }; + + vcc1v8: regulator-vcc1v8 { + compatible = "regulator-fixed"; + regulator-name = "VCC1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + vcc3v3: regulator-vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; + }; +}; + +&scpi_clocks { + status = "disabled"; };
&uart_AO { @@ -83,6 +149,85 @@
ðmac { status = "okay"; - pinctrl-0 = <ð_pins>; + pinctrl-0 = <ð_rgmii_pins>; + pinctrl-names = "default"; + phy-handle = <ð_phy0>; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + eth_phy0: ethernet-phy@0 { + reg = <0>; + eee-broken-1000t; + }; + }; +}; + +&ir { + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default"; }; + +&i2c_A { + status = "okay"; + pinctrl-0 = <&i2c_a_pins>; + pinctrl-names = "default"; +}; + +&usb0_phy { + status = "okay"; + phy-supply = <&usb_otg_pwr>; +}; + +&usb1_phy { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +/* SD */ +&sd_emmc_b { + status = "okay"; + pinctrl-0 = <&sdcard_pins>; + pinctrl-names = "default"; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <100000000>; + disable-wp; + + cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>; + cd-inverted; + + vmmc-supply = <&tflash_vdd>; + vqmmc-supply = <&tf_io>; +}; + +/* eMMC */ +&sd_emmc_c { + status = "okay"; + pinctrl-0 = <&emmc_pins>; + pinctrl-names = "default"; + + bus-width = <8>; + cap-sd-highspeed; + max-frequency = <200000000>; + non-removable; + disable-wp; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vcc3v3>; + vqmmc-supply = <&vcc1v8>; +}; diff --git a/arch/arm/dts/meson-gxbb.dtsi b/arch/arm/dts/meson-gxbb.dtsi index e502c24..39a774a 100644 --- a/arch/arm/dts/meson-gxbb.dtsi +++ b/arch/arm/dts/meson-gxbb.dtsi @@ -40,307 +40,477 @@ * OTHER DEALINGS IN THE SOFTWARE. */
-#include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/interrupt-controller/arm-gic.h> +#include "meson-gx.dtsi" #include <dt-bindings/gpio/meson-gxbb-gpio.h> #include <dt-bindings/reset/amlogic,meson-gxbb-reset.h> +#include <dt-bindings/clock/gxbb-clkc.h> +#include <dt-bindings/clock/gxbb-aoclkc.h> +#include <dt-bindings/reset/gxbb-aoclkc.h>
/ { compatible = "amlogic,meson-gxbb"; - interrupt-parent = <&gic>; - #address-cells = <2>; - #size-cells = <2>;
- cpus { - #address-cells = <0x2>; - #size-cells = <0x0>; - - cpu0: cpu@0 { - device_type = "cpu"; - compatible = "arm,cortex-a53", "arm,armv8"; - reg = <0x0 0x0>; - enable-method = "psci"; + soc { + usb0_phy: phy@c0000000 { + compatible = "amlogic,meson-gxbb-usb2-phy"; + #phy-cells = <0>; + reg = <0x0 0xc0000000 0x0 0x20>; + resets = <&reset RESET_USB_OTG>; + clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>; + clock-names = "usb_general", "usb"; + status = "disabled"; };
- cpu1: cpu@1 { - device_type = "cpu"; - compatible = "arm,cortex-a53", "arm,armv8"; - reg = <0x0 0x1>; - enable-method = "psci"; + usb1_phy: phy@c0000020 { + compatible = "amlogic,meson-gxbb-usb2-phy"; + #phy-cells = <0>; + reg = <0x0 0xc0000020 0x0 0x20>; + resets = <&reset RESET_USB_OTG>; + clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB1>; + clock-names = "usb_general", "usb"; + status = "disabled"; };
- cpu2: cpu@2 { - device_type = "cpu"; - compatible = "arm,cortex-a53", "arm,armv8"; - reg = <0x0 0x2>; - enable-method = "psci"; + usb0: usb@c9000000 { + compatible = "amlogic,meson-gxbb-usb", "snps,dwc2"; + reg = <0x0 0xc9000000 0x0 0x40000>; + interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc CLKID_USB0_DDR_BRIDGE>; + clock-names = "otg"; + phys = <&usb0_phy>; + phy-names = "usb2-phy"; + dr_mode = "host"; + status = "disabled"; };
- cpu3: cpu@3 { - device_type = "cpu"; - compatible = "arm,cortex-a53", "arm,armv8"; - reg = <0x0 0x3>; - enable-method = "psci"; + usb1: usb@c9100000 { + compatible = "amlogic,meson-gxbb-usb", "snps,dwc2"; + reg = <0x0 0xc9100000 0x0 0x40000>; + interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; + clock-names = "otg"; + phys = <&usb1_phy>; + phy-names = "usb2-phy"; + dr_mode = "host"; + status = "disabled"; }; }; +};
- arm-pmu { - compatible = "arm,cortex-a53-pmu"; - interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; - interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>; +&cbus { + spifc: spi@8c80 { + compatible = "amlogic,meson-gxbb-spifc"; + reg = <0x0 0x08c80 0x0 0x80>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc CLKID_SPI>; + status = "disabled"; }; +}; + +ðmac { + clocks = <&clkc CLKID_ETH>, + <&clkc CLKID_FCLK_DIV2>, + <&clkc CLKID_MPLL2>; + clock-names = "stmmaceth", "clkin0", "clkin1"; +}; + +&aobus { + pinctrl_aobus: pinctrl@14 { + compatible = "amlogic,meson-gxbb-aobus-pinctrl"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gpio_ao: bank@14 { + reg = <0x0 0x00014 0x0 0x8>, + <0x0 0x0002c 0x0 0x4>, + <0x0 0x00024 0x0 0x8>; + reg-names = "mux", "pull", "gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + uart_ao_a_pins: uart_ao_a { + mux { + groups = "uart_tx_ao_a", "uart_rx_ao_a"; + function = "uart_ao"; + }; + }; + + uart_ao_a_cts_rts_pins: uart_ao_a_cts_rts { + mux { + groups = "uart_cts_ao_a", + "uart_rts_ao_a"; + function = "uart_ao"; + }; + }; + + uart_ao_b_pins: uart_ao_b { + mux { + groups = "uart_tx_ao_b", "uart_rx_ao_b"; + function = "uart_ao_b"; + }; + }; + + uart_ao_b_cts_rts_pins: uart_ao_b_cts_rts { + mux { + groups = "uart_cts_ao_b", + "uart_rts_ao_b"; + function = "uart_ao_b"; + }; + };
- psci { - compatible = "arm,psci-0.2"; - method = "smc"; + remote_input_ao_pins: remote_input_ao { + mux { + groups = "remote_input_ao"; + function = "remote_input_ao"; + }; + }; + + i2c_ao_pins: i2c_ao { + mux { + groups = "i2c_sck_ao", + "i2c_sda_ao"; + function = "i2c_ao"; + }; + }; + + pwm_ao_a_3_pins: pwm_ao_a_3 { + mux { + groups = "pwm_ao_a_3"; + function = "pwm_ao_a_3"; + }; + }; + + pwm_ao_a_6_pins: pwm_ao_a_6 { + mux { + groups = "pwm_ao_a_6"; + function = "pwm_ao_a_6"; + }; + }; + + pwm_ao_a_12_pins: pwm_ao_a_12 { + mux { + groups = "pwm_ao_a_12"; + function = "pwm_ao_a_12"; + }; + }; + + pwm_ao_b_pins: pwm_ao_b { + mux { + groups = "pwm_ao_b"; + function = "pwm_ao_b"; + }; + }; };
- timer { - compatible = "arm,armv8-timer"; - interrupts = <GIC_PPI 13 - (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>, - <GIC_PPI 14 - (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>, - <GIC_PPI 11 - (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>, - <GIC_PPI 10 - (GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>; + clkc_AO: clock-controller@040 { + compatible = "amlogic,gxbb-aoclkc"; + reg = <0x0 0x00040 0x0 0x4>; + #clock-cells = <1>; + #reset-cells = <1>; };
- xtal: xtal-clk { - compatible = "fixed-clock"; - clock-frequency = <24000000>; - clock-output-names = "xtal"; - #clock-cells = <0>; + pwm_ab_AO: pwm@550 { + compatible = "amlogic,meson-gxbb-pwm"; + reg = <0x0 0x0550 0x0 0x10>; + #pwm-cells = <3>; + status = "disabled"; };
- soc { - compatible = "simple-bus"; + i2c_AO: i2c@500 { + compatible = "amlogic,meson-gxbb-i2c"; + reg = <0x0 0x500 0x0 0x20>; + interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>; + clocks = <&clkc CLKID_AO_I2C>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; +}; + +&periphs { + pinctrl_periphs: pinctrl@4b0 { + compatible = "amlogic,meson-gxbb-periphs-pinctrl"; #address-cells = <2>; #size-cells = <2>; ranges;
- cbus: cbus@c1100000 { - compatible = "simple-bus"; - reg = <0x0 0xc1100000 0x0 0x100000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>; - - reset: reset-controller@4404 { - compatible = "amlogic,meson-gxbb-reset"; - reg = <0x0 0x04404 0x0 0x20>; - #reset-cells = <1>; - }; - - uart_A: serial@84c0 { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x84c0 0x0 0x14>; - interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; - status = "disabled"; - }; - - uart_B: serial@84dc { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x84dc 0x0 0x14>; - interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; - status = "disabled"; - }; - - uart_C: serial@8700 { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x8700 0x0 0x14>; - interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; - status = "disabled"; - }; - }; - - gic: interrupt-controller@c4301000 { - compatible = "arm,gic-400"; - reg = <0x0 0xc4301000 0 0x1000>, - <0x0 0xc4302000 0 0x2000>, - <0x0 0xc4304000 0 0x2000>, - <0x0 0xc4306000 0 0x2000>; - interrupt-controller; - interrupts = <GIC_PPI 9 - (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>; - #interrupt-cells = <3>; - #address-cells = <0>; - }; - - aobus: aobus@c8100000 { - compatible = "simple-bus"; - reg = <0x0 0xc8100000 0x0 0x100000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>; - - pinctrl_aobus: pinctrl@14 { - compatible = "amlogic,meson-gxbb-aobus-pinctrl"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - gpio_ao: bank@14 { - reg = <0x0 0x00014 0x0 0x8>, - <0x0 0x0002c 0x0 0x4>, - <0x0 0x00024 0x0 0x8>; - reg-names = "mux", "pull", "gpio"; - gpio-controller; - #gpio-cells = <2>; - }; - - uart_ao_a_pins: uart_ao_a { - mux { - groups = "uart_tx_ao_a", "uart_rx_ao_a"; - function = "uart_ao"; - }; - }; - }; - - uart_AO: serial@4c0 { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x004c0 0x0 0x14>; - interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; - status = "disabled"; - }; - }; - - periphs: periphs@c8834000 { - compatible = "simple-bus"; - reg = <0x0 0xc8834000 0x0 0x2000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xc8834000 0x0 0x2000>; - - rng { - compatible = "amlogic,meson-rng"; - reg = <0x0 0x0 0x0 0x4>; - }; - - pinctrl_periphs: pinctrl@4b0 { - compatible = "amlogic,meson-gxbb-periphs-pinctrl"; - #address-cells = <2>; - #size-cells = <2>; - ranges; - - gpio: bank@4b0 { - reg = <0x0 0x004b0 0x0 0x28>, - <0x0 0x004e8 0x0 0x14>, - <0x0 0x00120 0x0 0x14>, - <0x0 0x00430 0x0 0x40>; - reg-names = "mux", "pull", "pull-enable", "gpio"; - gpio-controller; - #gpio-cells = <2>; - }; - - emmc_pins: emmc { - mux { - groups = "emmc_nand_d07", - "emmc_cmd", - "emmc_clk"; - function = "emmc"; - }; - }; - - sdcard_pins: sdcard { - mux { - groups = "sdcard_d0", - "sdcard_d1", - "sdcard_d2", - "sdcard_d3", - "sdcard_cmd", - "sdcard_clk"; - function = "sdcard"; - }; - }; - - uart_a_pins: uart_a { - mux { - groups = "uart_tx_a", - "uart_rx_a"; - function = "uart_a"; - }; - }; - - uart_b_pins: uart_b { - mux { - groups = "uart_tx_b", - "uart_rx_b"; - function = "uart_b"; - }; - }; - - uart_c_pins: uart_c { - mux { - groups = "uart_tx_c", - "uart_rx_c"; - function = "uart_c"; - }; - }; - - eth_pins: eth_c { - mux { - groups = "eth_mdio", - "eth_mdc", - "eth_clk_rx_clk", - "eth_rx_dv", - "eth_rxd0", - "eth_rxd1", - "eth_rxd2", - "eth_rxd3", - "eth_rgmii_tx_clk", - "eth_tx_en", - "eth_txd0", - "eth_txd1", - "eth_txd2", - "eth_txd3"; - function = "eth"; - }; - }; - }; - }; - - hiubus: hiubus@c883c000 { - compatible = "simple-bus"; - reg = <0x0 0xc883c000 0x0 0x2000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xc883c000 0x0 0x2000>; - - clkc: clock-controller@0 { - compatible = "amlogic,gxbb-clkc"; - #clock-cells = <1>; - reg = <0x0 0x0 0x0 0x3db>; - }; - }; - - apb: apb@d0000000 { - compatible = "simple-bus"; - reg = <0x0 0xd0000000 0x0 0x200000>; - #address-cells = <2>; - #size-cells = <2>; - ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>; - }; - - ethmac: ethernet@c9410000 { - compatible = "amlogic,meson6-dwmac", "snps,dwmac"; - reg = <0x0 0xc9410000 0x0 0x10000 - 0x0 0xc8834540 0x0 0x4>; - interrupts = <0 8 1>; - interrupt-names = "macirq"; - clocks = <&xtal>; - clock-names = "stmmaceth"; - phy-mode = "rgmii"; - status = "disabled"; + gpio: bank@4b0 { + reg = <0x0 0x004b0 0x0 0x28>, + <0x0 0x004e8 0x0 0x14>, + <0x0 0x00120 0x0 0x14>, + <0x0 0x00430 0x0 0x40>; + reg-names = "mux", "pull", "pull-enable", "gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + emmc_pins: emmc { + mux { + groups = "emmc_nand_d07", + "emmc_cmd", + "emmc_clk", + "emmc_ds"; + function = "emmc"; + }; + }; + + nor_pins: nor { + mux { + groups = "nor_d", + "nor_q", + "nor_c", + "nor_cs"; + function = "nor"; + }; + }; + + sdcard_pins: sdcard { + mux { + groups = "sdcard_d0", + "sdcard_d1", + "sdcard_d2", + "sdcard_d3", + "sdcard_cmd", + "sdcard_clk"; + function = "sdcard"; + }; + }; + + sdio_pins: sdio { + mux { + groups = "sdio_d0", + "sdio_d1", + "sdio_d2", + "sdio_d3", + "sdio_cmd", + "sdio_clk"; + function = "sdio"; + }; + }; + + sdio_irq_pins: sdio_irq { + mux { + groups = "sdio_irq"; + function = "sdio"; + }; + }; + + uart_a_pins: uart_a { + mux { + groups = "uart_tx_a", + "uart_rx_a"; + function = "uart_a"; + }; + }; + + uart_a_cts_rts_pins: uart_a_cts_rts { + mux { + groups = "uart_cts_a", + "uart_rts_a"; + function = "uart_a"; + }; + }; + + uart_b_pins: uart_b { + mux { + groups = "uart_tx_b", + "uart_rx_b"; + function = "uart_b"; + }; + }; + + uart_b_cts_rts_pins: uart_b_cts_rts { + mux { + groups = "uart_cts_b", + "uart_rts_b"; + function = "uart_b"; + }; + }; + + uart_c_pins: uart_c { + mux { + groups = "uart_tx_c", + "uart_rx_c"; + function = "uart_c"; + }; + }; + + uart_c_cts_rts_pins: uart_c_cts_rts { + mux { + groups = "uart_cts_c", + "uart_rts_c"; + function = "uart_c"; + }; + }; + + i2c_a_pins: i2c_a { + mux { + groups = "i2c_sck_a", + "i2c_sda_a"; + function = "i2c_a"; + }; + }; + + i2c_b_pins: i2c_b { + mux { + groups = "i2c_sck_b", + "i2c_sda_b"; + function = "i2c_b"; + }; + }; + + i2c_c_pins: i2c_c { + mux { + groups = "i2c_sck_c", + "i2c_sda_c"; + function = "i2c_c"; + }; + }; + + eth_rgmii_pins: eth-rgmii { + mux { + groups = "eth_mdio", + "eth_mdc", + "eth_clk_rx_clk", + "eth_rx_dv", + "eth_rxd0", + "eth_rxd1", + "eth_rxd2", + "eth_rxd3", + "eth_rgmii_tx_clk", + "eth_tx_en", + "eth_txd0", + "eth_txd1", + "eth_txd2", + "eth_txd3"; + function = "eth"; + }; + }; + + eth_rmii_pins: eth-rmii { + mux { + groups = "eth_mdio", + "eth_mdc", + "eth_clk_rx_clk", + "eth_rx_dv", + "eth_rxd0", + "eth_rxd1", + "eth_tx_en", + "eth_txd0", + "eth_txd1"; + function = "eth"; + }; + }; + + pwm_a_x_pins: pwm_a_x { + mux { + groups = "pwm_a_x"; + function = "pwm_a_x"; + }; + }; + + pwm_a_y_pins: pwm_a_y { + mux { + groups = "pwm_a_y"; + function = "pwm_a_y"; + }; + }; + + pwm_b_pins: pwm_b { + mux { + groups = "pwm_b"; + function = "pwm_b"; + }; + }; + + pwm_d_pins: pwm_d { + mux { + groups = "pwm_d"; + function = "pwm_d"; + }; + }; + + pwm_e_pins: pwm_e { + mux { + groups = "pwm_e"; + function = "pwm_e"; + }; + }; + + pwm_f_x_pins: pwm_f_x { + mux { + groups = "pwm_f_x"; + function = "pwm_f_x"; + }; + }; + + pwm_f_y_pins: pwm_f_y { + mux { + groups = "pwm_f_y"; + function = "pwm_f_y"; + }; + }; + + hdmi_hpd_pins: hdmi_hpd { + mux { + groups = "hdmi_hpd"; + function = "hdmi_hpd"; + }; + }; + + hdmi_i2c_pins: hdmi_i2c { + mux { + groups = "hdmi_sda", "hdmi_scl"; + function = "hdmi_i2c"; + }; }; }; }; + +&hiubus { + clkc: clock-controller@0 { + compatible = "amlogic,gxbb-clkc"; + #clock-cells = <1>; + reg = <0x0 0x0 0x0 0x3db>; + }; +}; + +&i2c_A { + clocks = <&clkc CLKID_I2C>; +}; + +&i2c_B { + clocks = <&clkc CLKID_I2C>; +}; + +&i2c_C { + clocks = <&clkc CLKID_I2C>; +}; + +&sd_emmc_a { + clocks = <&clkc CLKID_SD_EMMC_A>, + <&xtal>, + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; +}; + +&sd_emmc_b { + clocks = <&clkc CLKID_SD_EMMC_B>, + <&xtal>, + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; +}; + +&sd_emmc_c { + clocks = <&clkc CLKID_SD_EMMC_C>, + <&xtal>, + <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; +}; + +&vpu { + compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; +}; diff --git a/include/dt-bindings/clock/gxbb-aoclkc.h b/include/dt-bindings/clock/gxbb-aoclkc.h new file mode 100644 index 0000000..3175148 --- /dev/null +++ b/include/dt-bindings/clock/gxbb-aoclkc.h @@ -0,0 +1,66 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong narmstrong@baylibre.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/licenses/. + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * BSD LICENSE + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong narmstrong@baylibre.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DT_BINDINGS_CLOCK_AMLOGIC_MESON_GXBB_AOCLK +#define DT_BINDINGS_CLOCK_AMLOGIC_MESON_GXBB_AOCLK + +#define CLKID_AO_REMOTE 0 +#define CLKID_AO_I2C_MASTER 1 +#define CLKID_AO_I2C_SLAVE 2 +#define CLKID_AO_UART1 3 +#define CLKID_AO_UART2 4 +#define CLKID_AO_IR_BLASTER 5 + +#endif diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h new file mode 100644 index 0000000..692846c --- /dev/null +++ b/include/dt-bindings/clock/gxbb-clkc.h @@ -0,0 +1,34 @@ +/* + * GXBB clock tree IDs + */ + +#ifndef __GXBB_CLKC_H +#define __GXBB_CLKC_H + +#define CLKID_CPUCLK 1 +#define CLKID_HDMI_PLL 2 +#define CLKID_FCLK_DIV2 4 +#define CLKID_FCLK_DIV3 5 +#define CLKID_FCLK_DIV4 6 +#define CLKID_CLK81 12 +#define CLKID_MPLL2 15 +#define CLKID_SPI 34 +#define CLKID_I2C 22 +#define CLKID_SAR_ADC 23 +#define CLKID_ETH 36 +#define CLKID_USB0 50 +#define CLKID_USB1 51 +#define CLKID_USB 55 +#define CLKID_HDMI_PCLK 63 +#define CLKID_USB1_DDR_BRIDGE 64 +#define CLKID_USB0_DDR_BRIDGE 65 +#define CLKID_SANA 69 +#define CLKID_GCLK_VENCI_INT0 77 +#define CLKID_AO_I2C 93 +#define CLKID_SD_EMMC_A 94 +#define CLKID_SD_EMMC_B 95 +#define CLKID_SD_EMMC_C 96 +#define CLKID_SAR_ADC_CLK 97 +#define CLKID_SAR_ADC_SEL 98 + +#endif /* __GXBB_CLKC_H */ diff --git a/include/dt-bindings/reset/gxbb-aoclkc.h b/include/dt-bindings/reset/gxbb-aoclkc.h new file mode 100644 index 0000000..9e3fd60 --- /dev/null +++ b/include/dt-bindings/reset/gxbb-aoclkc.h @@ -0,0 +1,66 @@ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong narmstrong@baylibre.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see http://www.gnu.org/licenses/. + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * BSD LICENSE + * + * Copyright (c) 2016 BayLibre, SAS. + * Author: Neil Armstrong narmstrong@baylibre.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DT_BINDINGS_RESET_AMLOGIC_MESON_GXBB_AOCLK +#define DT_BINDINGS_RESET_AMLOGIC_MESON_GXBB_AOCLK + +#define RESET_AO_REMOTE 0 +#define RESET_AO_I2C_MASTER 1 +#define RESET_AO_I2C_SLAVE 2 +#define RESET_AO_UART1 3 +#define RESET_AO_UART2 4 +#define RESET_AO_IR_BLASTER 5 + +#endif

On 04/13/2017 03:28 AM, Heiner Kallweit wrote:
As a prerequisite for adding a Meson GX MMC driver update the Meson GXBB / Odroid-C2 device tree in Uboot with the latest version from Linux.
Signed-off-by: Neil Armstrong narmstrong@baylibre.com Signed-off-by: Carlo Caione carlo@endlessm.com Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Best Regards, Jaehoon Chung
v4:
- Added SoB of original authors
v5:
- no changes
v6:
- changed prefix in subject
v7:
- rebased
arch/arm/dts/meson-gx.dtsi | 447 ++++++++++++++++++++ arch/arm/dts/meson-gxbb-odroidc2.dts | 147 ++++++- arch/arm/dts/meson-gxbb.dtsi | 718 ++++++++++++++++++++------------ include/dt-bindings/clock/gxbb-aoclkc.h | 66 +++ include/dt-bindings/clock/gxbb-clkc.h | 34 ++ include/dt-bindings/reset/gxbb-aoclkc.h | 66 +++ 6 files changed, 1203 insertions(+), 275 deletions(-) create mode 100644 arch/arm/dts/meson-gx.dtsi create mode 100644 include/dt-bindings/clock/gxbb-aoclkc.h create mode 100644 include/dt-bindings/clock/gxbb-clkc.h create mode 100644 include/dt-bindings/reset/gxbb-aoclkc.h
diff --git a/arch/arm/dts/meson-gx.dtsi b/arch/arm/dts/meson-gx.dtsi new file mode 100644 index 0000000..c129100 --- /dev/null +++ b/arch/arm/dts/meson-gx.dtsi @@ -0,0 +1,447 @@ +/*
- Copyright (c) 2016 Andreas Färber
- Copyright (c) 2016 BayLibre, SAS.
- Author: Neil Armstrong narmstrong@baylibre.com
- Copyright (c) 2016 Endless Computers, Inc.
- Author: Carlo Caione carlo@endlessm.com
- This file is dual-licensed: you can use it either under the terms
- of the GPL or the X11 license, at your option. Note that this dual
- licensing only applies to this file, and not this project as a
- whole.
- a) This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- Or, alternatively,
- b) Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
- */
+#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/arm-gic.h>
+/ {
- interrupt-parent = <&gic>;
- #address-cells = <2>;
- #size-cells = <2>;
- reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
/* 16 MiB reserved for Hardware ROM Firmware */
hwrom_reserved: hwrom@0 {
reg = <0x0 0x0 0x0 0x1000000>;
no-map;
};
/* 2 MiB reserved for ARM Trusted Firmware (BL31) */
secmon_reserved: secmon@10000000 {
reg = <0x0 0x10000000 0x0 0x200000>;
no-map;
};
- };
- cpus {
#address-cells = <0x2>;
#size-cells = <0x0>;
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
next-level-cache = <&l2>;
clocks = <&scpi_dvfs 0>;
};
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
next-level-cache = <&l2>;
clocks = <&scpi_dvfs 0>;
};
cpu2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
next-level-cache = <&l2>;
clocks = <&scpi_dvfs 0>;
};
cpu3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
next-level-cache = <&l2>;
clocks = <&scpi_dvfs 0>;
};
l2: l2-cache0 {
compatible = "cache";
};
- };
- arm-pmu {
compatible = "arm,cortex-a53-pmu";
interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
- };
- psci {
compatible = "arm,psci-0.2";
method = "smc";
- };
- timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 14
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_LEVEL_LOW)>;
- };
- xtal: xtal-clk {
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "xtal";
#clock-cells = <0>;
- };
- firmware {
sm: secure-monitor {
compatible = "amlogic,meson-gx-sm", "amlogic,meson-gxbb-sm";
};
- };
- efuse: efuse {
compatible = "amlogic,meson-gx-efuse", "amlogic,meson-gxbb-efuse";
#address-cells = <1>;
#size-cells = <1>;
sn: sn@14 {
reg = <0x14 0x10>;
};
eth_mac: eth_mac@34 {
reg = <0x34 0x10>;
};
bid: bid@46 {
reg = <0x46 0x30>;
};
- };
- scpi {
compatible = "amlogic,meson-gxbb-scpi", "arm,scpi-pre-1.0";
mboxes = <&mailbox 1 &mailbox 2>;
shmem = <&cpu_scp_lpri &cpu_scp_hpri>;
scpi_clocks: clocks {
compatible = "arm,scpi-clocks";
scpi_dvfs: scpi_clocks@0 {
compatible = "arm,scpi-dvfs-clocks";
#clock-cells = <1>;
clock-indices = <0>;
clock-output-names = "vcpu";
};
};
scpi_sensors: sensors {
compatible = "arm,scpi-sensors";
#thermal-sensor-cells = <1>;
};
- };
- soc {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <2>;
ranges;
cbus: cbus@c1100000 {
compatible = "simple-bus";
reg = <0x0 0xc1100000 0x0 0x100000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>;
reset: reset-controller@4404 {
compatible = "amlogic,meson-gx-reset", "amlogic,meson-gxbb-reset";
reg = <0x0 0x04404 0x0 0x20>;
#reset-cells = <1>;
};
uart_A: serial@84c0 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x84c0 0x0 0x14>;
interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
uart_B: serial@84dc {
compatible = "amlogic,meson-uart";
reg = <0x0 0x84dc 0x0 0x14>;
interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
i2c_A: i2c@8500 {
compatible = "amlogic,meson-gxbb-i2c";
reg = <0x0 0x08500 0x0 0x20>;
interrupts = <GIC_SPI 21 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
pwm_ab: pwm@8550 {
compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm";
reg = <0x0 0x08550 0x0 0x10>;
#pwm-cells = <3>;
status = "disabled";
};
pwm_cd: pwm@8650 {
compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm";
reg = <0x0 0x08650 0x0 0x10>;
#pwm-cells = <3>;
status = "disabled";
};
pwm_ef: pwm@86c0 {
compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm";
reg = <0x0 0x086c0 0x0 0x10>;
#pwm-cells = <3>;
status = "disabled";
};
uart_C: serial@8700 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x8700 0x0 0x14>;
interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
i2c_B: i2c@87c0 {
compatible = "amlogic,meson-gxbb-i2c";
reg = <0x0 0x087c0 0x0 0x20>;
interrupts = <GIC_SPI 214 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
i2c_C: i2c@87e0 {
compatible = "amlogic,meson-gxbb-i2c";
reg = <0x0 0x087e0 0x0 0x20>;
interrupts = <GIC_SPI 215 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
watchdog@98d0 {
compatible = "amlogic,meson-gx-wdt", "amlogic,meson-gxbb-wdt";
reg = <0x0 0x098d0 0x0 0x10>;
clocks = <&xtal>;
};
};
gic: interrupt-controller@c4301000 {
compatible = "arm,gic-400";
reg = <0x0 0xc4301000 0 0x1000>,
<0x0 0xc4302000 0 0x2000>,
<0x0 0xc4304000 0 0x2000>,
<0x0 0xc4306000 0 0x2000>;
interrupt-controller;
interrupts = <GIC_PPI 9
(GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
#interrupt-cells = <3>;
#address-cells = <0>;
};
sram: sram@c8000000 {
compatible = "amlogic,meson-gxbb-sram", "mmio-sram";
reg = <0x0 0xc8000000 0x0 0x14000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x0 0xc8000000 0x14000>;
cpu_scp_lpri: scp-shmem@0 {
compatible = "amlogic,meson-gxbb-scp-shmem";
reg = <0x13000 0x400>;
};
cpu_scp_hpri: scp-shmem@200 {
compatible = "amlogic,meson-gxbb-scp-shmem";
reg = <0x13400 0x400>;
};
};
aobus: aobus@c8100000 {
compatible = "simple-bus";
reg = <0x0 0xc8100000 0x0 0x100000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
uart_AO: serial@4c0 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x004c0 0x0 0x14>;
interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
uart_AO_B: serial@4e0 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x004e0 0x0 0x14>;
interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
ir: ir@580 {
compatible = "amlogic,meson-gxbb-ir";
reg = <0x0 0x00580 0x0 0x40>;
interrupts = <GIC_SPI 196 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
};
periphs: periphs@c8834000 {
compatible = "simple-bus";
reg = <0x0 0xc8834000 0x0 0x2000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc8834000 0x0 0x2000>;
rng {
compatible = "amlogic,meson-rng";
reg = <0x0 0x0 0x0 0x4>;
};
};
hiubus: hiubus@c883c000 {
compatible = "simple-bus";
reg = <0x0 0xc883c000 0x0 0x2000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc883c000 0x0 0x2000>;
mailbox: mailbox@404 {
compatible = "amlogic,meson-gx-mhu", "amlogic,meson-gxbb-mhu";
reg = <0 0x404 0 0x4c>;
interrupts = <0 208 IRQ_TYPE_EDGE_RISING>,
<0 209 IRQ_TYPE_EDGE_RISING>,
<0 210 IRQ_TYPE_EDGE_RISING>;
#mbox-cells = <1>;
};
};
ethmac: ethernet@c9410000 {
compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac";
reg = <0x0 0xc9410000 0x0 0x10000
0x0 0xc8834540 0x0 0x4>;
interrupts = <0 8 1>;
interrupt-names = "macirq";
phy-mode = "rgmii";
status = "disabled";
};
apb: apb@d0000000 {
compatible = "simple-bus";
reg = <0x0 0xd0000000 0x0 0x200000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>;
sd_emmc_a: mmc@70000 {
compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
reg = <0x0 0x70000 0x0 0x2000>;
interrupts = <GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
sd_emmc_b: mmc@72000 {
compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
reg = <0x0 0x72000 0x0 0x2000>;
interrupts = <GIC_SPI 217 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
sd_emmc_c: mmc@74000 {
compatible = "amlogic,meson-gx-mmc", "amlogic,meson-gxbb-mmc";
reg = <0x0 0x74000 0x0 0x2000>;
interrupts = <GIC_SPI 218 IRQ_TYPE_EDGE_RISING>;
status = "disabled";
};
};
vpu: vpu@d0100000 {
compatible = "amlogic,meson-gx-vpu";
reg = <0x0 0xd0100000 0x0 0x100000>,
<0x0 0xc883c000 0x0 0x1000>,
<0x0 0xc8838000 0x0 0x1000>;
reg-names = "vpu", "hhi", "dmc";
interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
/* CVBS VDAC output port */
cvbs_vdac_port: port@0 {
reg = <0>;
};
};
- };
+}; diff --git a/arch/arm/dts/meson-gxbb-odroidc2.dts b/arch/arm/dts/meson-gxbb-odroidc2.dts index 79bee64..c737183 100644 --- a/arch/arm/dts/meson-gxbb-odroidc2.dts +++ b/arch/arm/dts/meson-gxbb-odroidc2.dts @@ -64,6 +64,18 @@ reg = <0x0 0x0 0x0 0x80000000>; };
- usb_otg_pwr: regulator-usb-pwrs {
compatible = "regulator-fixed";
regulator-name = "USB_OTG_PWR";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
gpio = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>;
enable-active-high;
- };
- leds { compatible = "gpio-leds"; blue {
@@ -73,6 +85,60 @@ default-state = "off"; }; };
- tflash_vdd: regulator-tflash_vdd {
/*
* signal name from schematics: TFLASH_VDD_EN
*/
compatible = "regulator-fixed";
regulator-name = "TFLASH_VDD";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio_ao GPIOAO_12 GPIO_ACTIVE_HIGH>;
enable-active-high;
- };
- tf_io: gpio-regulator-tf_io {
compatible = "regulator-gpio";
regulator-name = "TF_IO";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
/*
* signal name from schematics: TF_3V3N_1V8_EN
*/
gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_HIGH>;
gpios-states = <0>;
states = <3300000 0
1800000 1>;
- };
- vcc1v8: regulator-vcc1v8 {
compatible = "regulator-fixed";
regulator-name = "VCC1V8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- };
- vcc3v3: regulator-vcc3v3 {
compatible = "regulator-fixed";
regulator-name = "VCC3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- };
- emmc_pwrseq: emmc-pwrseq {
compatible = "mmc-pwrseq-emmc";
reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
- };
+};
+&scpi_clocks {
- status = "disabled";
};
&uart_AO { @@ -83,6 +149,85 @@
ðmac { status = "okay";
- pinctrl-0 = <ð_pins>;
- pinctrl-0 = <ð_rgmii_pins>;
- pinctrl-names = "default";
- phy-handle = <ð_phy0>;
- mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
eth_phy0: ethernet-phy@0 {
reg = <0>;
eee-broken-1000t;
};
- };
+};
+&ir {
- status = "okay";
- pinctrl-0 = <&remote_input_ao_pins>; pinctrl-names = "default";
};
+&i2c_A {
- status = "okay";
- pinctrl-0 = <&i2c_a_pins>;
- pinctrl-names = "default";
+};
+&usb0_phy {
- status = "okay";
- phy-supply = <&usb_otg_pwr>;
+};
+&usb1_phy {
- status = "okay";
+};
+&usb0 {
- status = "okay";
+};
+&usb1 {
- status = "okay";
+};
+/* SD */ +&sd_emmc_b {
- status = "okay";
- pinctrl-0 = <&sdcard_pins>;
- pinctrl-names = "default";
- bus-width = <4>;
- cap-sd-highspeed;
- max-frequency = <100000000>;
- disable-wp;
- cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_HIGH>;
- cd-inverted;
- vmmc-supply = <&tflash_vdd>;
- vqmmc-supply = <&tf_io>;
+};
+/* eMMC */ +&sd_emmc_c {
- status = "okay";
- pinctrl-0 = <&emmc_pins>;
- pinctrl-names = "default";
- bus-width = <8>;
- cap-sd-highspeed;
- max-frequency = <200000000>;
- non-removable;
- disable-wp;
- cap-mmc-highspeed;
- mmc-ddr-1_8v;
- mmc-hs200-1_8v;
- mmc-pwrseq = <&emmc_pwrseq>;
- vmmc-supply = <&vcc3v3>;
- vqmmc-supply = <&vcc1v8>;
+}; diff --git a/arch/arm/dts/meson-gxbb.dtsi b/arch/arm/dts/meson-gxbb.dtsi index e502c24..39a774a 100644 --- a/arch/arm/dts/meson-gxbb.dtsi +++ b/arch/arm/dts/meson-gxbb.dtsi @@ -40,307 +40,477 @@
OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <dt-bindings/gpio/gpio.h> -#include <dt-bindings/interrupt-controller/irq.h> -#include <dt-bindings/interrupt-controller/arm-gic.h> +#include "meson-gx.dtsi" #include <dt-bindings/gpio/meson-gxbb-gpio.h> #include <dt-bindings/reset/amlogic,meson-gxbb-reset.h> +#include <dt-bindings/clock/gxbb-clkc.h> +#include <dt-bindings/clock/gxbb-aoclkc.h> +#include <dt-bindings/reset/gxbb-aoclkc.h>
/ { compatible = "amlogic,meson-gxbb";
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
cpus {
#address-cells = <0x2>;
#size-cells = <0x0>;
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
- soc {
usb0_phy: phy@c0000000 {
compatible = "amlogic,meson-gxbb-usb2-phy";
#phy-cells = <0>;
reg = <0x0 0xc0000000 0x0 0x20>;
resets = <&reset RESET_USB_OTG>;
clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>;
clock-names = "usb_general", "usb";
};status = "disabled";
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
usb1_phy: phy@c0000020 {
compatible = "amlogic,meson-gxbb-usb2-phy";
#phy-cells = <0>;
reg = <0x0 0xc0000020 0x0 0x20>;
resets = <&reset RESET_USB_OTG>;
clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB1>;
clock-names = "usb_general", "usb";
};status = "disabled";
cpu2: cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
usb0: usb@c9000000 {
compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
reg = <0x0 0xc9000000 0x0 0x40000>;
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc CLKID_USB0_DDR_BRIDGE>;
clock-names = "otg";
phys = <&usb0_phy>;
phy-names = "usb2-phy";
dr_mode = "host";
};status = "disabled";
cpu3: cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
usb1: usb@c9100000 {
compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
reg = <0x0 0xc9100000 0x0 0x40000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
clock-names = "otg";
phys = <&usb1_phy>;
phy-names = "usb2-phy";
dr_mode = "host";
}; };status = "disabled";
+};
- arm-pmu {
compatible = "arm,cortex-a53-pmu";
interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>;
interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+&cbus {
- spifc: spi@8c80 {
compatible = "amlogic,meson-gxbb-spifc";
reg = <0x0 0x08c80 0x0 0x80>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clkc CLKID_SPI>;
};status = "disabled";
+};
+ðmac {
- clocks = <&clkc CLKID_ETH>,
<&clkc CLKID_FCLK_DIV2>,
<&clkc CLKID_MPLL2>;
- clock-names = "stmmaceth", "clkin0", "clkin1";
+};
+&aobus {
- pinctrl_aobus: pinctrl@14 {
compatible = "amlogic,meson-gxbb-aobus-pinctrl";
#address-cells = <2>;
#size-cells = <2>;
ranges;
gpio_ao: bank@14 {
reg = <0x0 0x00014 0x0 0x8>,
<0x0 0x0002c 0x0 0x4>,
<0x0 0x00024 0x0 0x8>;
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
};
uart_ao_a_pins: uart_ao_a {
mux {
groups = "uart_tx_ao_a", "uart_rx_ao_a";
function = "uart_ao";
};
};
uart_ao_a_cts_rts_pins: uart_ao_a_cts_rts {
mux {
groups = "uart_cts_ao_a",
"uart_rts_ao_a";
function = "uart_ao";
};
};
uart_ao_b_pins: uart_ao_b {
mux {
groups = "uart_tx_ao_b", "uart_rx_ao_b";
function = "uart_ao_b";
};
};
uart_ao_b_cts_rts_pins: uart_ao_b_cts_rts {
mux {
groups = "uart_cts_ao_b",
"uart_rts_ao_b";
function = "uart_ao_b";
};
};
- psci {
compatible = "arm,psci-0.2";
method = "smc";
remote_input_ao_pins: remote_input_ao {
mux {
groups = "remote_input_ao";
function = "remote_input_ao";
};
};
i2c_ao_pins: i2c_ao {
mux {
groups = "i2c_sck_ao",
"i2c_sda_ao";
function = "i2c_ao";
};
};
pwm_ao_a_3_pins: pwm_ao_a_3 {
mux {
groups = "pwm_ao_a_3";
function = "pwm_ao_a_3";
};
};
pwm_ao_a_6_pins: pwm_ao_a_6 {
mux {
groups = "pwm_ao_a_6";
function = "pwm_ao_a_6";
};
};
pwm_ao_a_12_pins: pwm_ao_a_12 {
mux {
groups = "pwm_ao_a_12";
function = "pwm_ao_a_12";
};
};
pwm_ao_b_pins: pwm_ao_b {
mux {
groups = "pwm_ao_b";
function = "pwm_ao_b";
};
};};
- timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>,
<GIC_PPI 14
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>,
<GIC_PPI 11
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>,
<GIC_PPI 10
(GIC_CPU_MASK_RAW(0xff) | IRQ_TYPE_EDGE_RISING)>;
- clkc_AO: clock-controller@040 {
compatible = "amlogic,gxbb-aoclkc";
reg = <0x0 0x00040 0x0 0x4>;
#clock-cells = <1>;
};#reset-cells = <1>;
- xtal: xtal-clk {
compatible = "fixed-clock";
clock-frequency = <24000000>;
clock-output-names = "xtal";
#clock-cells = <0>;
- pwm_ab_AO: pwm@550 {
compatible = "amlogic,meson-gxbb-pwm";
reg = <0x0 0x0550 0x0 0x10>;
#pwm-cells = <3>;
};status = "disabled";
- soc {
compatible = "simple-bus";
- i2c_AO: i2c@500 {
compatible = "amlogic,meson-gxbb-i2c";
reg = <0x0 0x500 0x0 0x20>;
interrupts = <GIC_SPI 195 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc CLKID_AO_I2C>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
- };
+};
+&periphs {
- pinctrl_periphs: pinctrl@4b0 {
#address-cells = <2>; #size-cells = <2>; ranges;compatible = "amlogic,meson-gxbb-periphs-pinctrl";
cbus: cbus@c1100000 {
compatible = "simple-bus";
reg = <0x0 0xc1100000 0x0 0x100000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>;
reset: reset-controller@4404 {
compatible = "amlogic,meson-gxbb-reset";
reg = <0x0 0x04404 0x0 0x20>;
#reset-cells = <1>;
};
uart_A: serial@84c0 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x84c0 0x0 0x14>;
interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
uart_B: serial@84dc {
compatible = "amlogic,meson-uart";
reg = <0x0 0x84dc 0x0 0x14>;
interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
uart_C: serial@8700 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x8700 0x0 0x14>;
interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
};
gic: interrupt-controller@c4301000 {
compatible = "arm,gic-400";
reg = <0x0 0xc4301000 0 0x1000>,
<0x0 0xc4302000 0 0x2000>,
<0x0 0xc4304000 0 0x2000>,
<0x0 0xc4306000 0 0x2000>;
interrupt-controller;
interrupts = <GIC_PPI 9
(GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
#interrupt-cells = <3>;
#address-cells = <0>;
};
aobus: aobus@c8100000 {
compatible = "simple-bus";
reg = <0x0 0xc8100000 0x0 0x100000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
pinctrl_aobus: pinctrl@14 {
compatible = "amlogic,meson-gxbb-aobus-pinctrl";
#address-cells = <2>;
#size-cells = <2>;
ranges;
gpio_ao: bank@14 {
reg = <0x0 0x00014 0x0 0x8>,
<0x0 0x0002c 0x0 0x4>,
<0x0 0x00024 0x0 0x8>;
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
};
uart_ao_a_pins: uart_ao_a {
mux {
groups = "uart_tx_ao_a", "uart_rx_ao_a";
function = "uart_ao";
};
};
};
uart_AO: serial@4c0 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x004c0 0x0 0x14>;
interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>;
clocks = <&xtal>;
status = "disabled";
};
};
periphs: periphs@c8834000 {
compatible = "simple-bus";
reg = <0x0 0xc8834000 0x0 0x2000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc8834000 0x0 0x2000>;
rng {
compatible = "amlogic,meson-rng";
reg = <0x0 0x0 0x0 0x4>;
};
pinctrl_periphs: pinctrl@4b0 {
compatible = "amlogic,meson-gxbb-periphs-pinctrl";
#address-cells = <2>;
#size-cells = <2>;
ranges;
gpio: bank@4b0 {
reg = <0x0 0x004b0 0x0 0x28>,
<0x0 0x004e8 0x0 0x14>,
<0x0 0x00120 0x0 0x14>,
<0x0 0x00430 0x0 0x40>;
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
};
emmc_pins: emmc {
mux {
groups = "emmc_nand_d07",
"emmc_cmd",
"emmc_clk";
function = "emmc";
};
};
sdcard_pins: sdcard {
mux {
groups = "sdcard_d0",
"sdcard_d1",
"sdcard_d2",
"sdcard_d3",
"sdcard_cmd",
"sdcard_clk";
function = "sdcard";
};
};
uart_a_pins: uart_a {
mux {
groups = "uart_tx_a",
"uart_rx_a";
function = "uart_a";
};
};
uart_b_pins: uart_b {
mux {
groups = "uart_tx_b",
"uart_rx_b";
function = "uart_b";
};
};
uart_c_pins: uart_c {
mux {
groups = "uart_tx_c",
"uart_rx_c";
function = "uart_c";
};
};
eth_pins: eth_c {
mux {
groups = "eth_mdio",
"eth_mdc",
"eth_clk_rx_clk",
"eth_rx_dv",
"eth_rxd0",
"eth_rxd1",
"eth_rxd2",
"eth_rxd3",
"eth_rgmii_tx_clk",
"eth_tx_en",
"eth_txd0",
"eth_txd1",
"eth_txd2",
"eth_txd3";
function = "eth";
};
};
};
};
hiubus: hiubus@c883c000 {
compatible = "simple-bus";
reg = <0x0 0xc883c000 0x0 0x2000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc883c000 0x0 0x2000>;
clkc: clock-controller@0 {
compatible = "amlogic,gxbb-clkc";
#clock-cells = <1>;
reg = <0x0 0x0 0x0 0x3db>;
};
};
apb: apb@d0000000 {
compatible = "simple-bus";
reg = <0x0 0xd0000000 0x0 0x200000>;
#address-cells = <2>;
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xd0000000 0x0 0x200000>;
};
ethmac: ethernet@c9410000 {
compatible = "amlogic,meson6-dwmac", "snps,dwmac";
reg = <0x0 0xc9410000 0x0 0x10000
0x0 0xc8834540 0x0 0x4>;
interrupts = <0 8 1>;
interrupt-names = "macirq";
clocks = <&xtal>;
clock-names = "stmmaceth";
phy-mode = "rgmii";
status = "disabled";
gpio: bank@4b0 {
reg = <0x0 0x004b0 0x0 0x28>,
<0x0 0x004e8 0x0 0x14>,
<0x0 0x00120 0x0 0x14>,
<0x0 0x00430 0x0 0x40>;
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
};
emmc_pins: emmc {
mux {
groups = "emmc_nand_d07",
"emmc_cmd",
"emmc_clk",
"emmc_ds";
function = "emmc";
};
};
nor_pins: nor {
mux {
groups = "nor_d",
"nor_q",
"nor_c",
"nor_cs";
function = "nor";
};
};
sdcard_pins: sdcard {
mux {
groups = "sdcard_d0",
"sdcard_d1",
"sdcard_d2",
"sdcard_d3",
"sdcard_cmd",
"sdcard_clk";
function = "sdcard";
};
};
sdio_pins: sdio {
mux {
groups = "sdio_d0",
"sdio_d1",
"sdio_d2",
"sdio_d3",
"sdio_cmd",
"sdio_clk";
function = "sdio";
};
};
sdio_irq_pins: sdio_irq {
mux {
groups = "sdio_irq";
function = "sdio";
};
};
uart_a_pins: uart_a {
mux {
groups = "uart_tx_a",
"uart_rx_a";
function = "uart_a";
};
};
uart_a_cts_rts_pins: uart_a_cts_rts {
mux {
groups = "uart_cts_a",
"uart_rts_a";
function = "uart_a";
};
};
uart_b_pins: uart_b {
mux {
groups = "uart_tx_b",
"uart_rx_b";
function = "uart_b";
};
};
uart_b_cts_rts_pins: uart_b_cts_rts {
mux {
groups = "uart_cts_b",
"uart_rts_b";
function = "uart_b";
};
};
uart_c_pins: uart_c {
mux {
groups = "uart_tx_c",
"uart_rx_c";
function = "uart_c";
};
};
uart_c_cts_rts_pins: uart_c_cts_rts {
mux {
groups = "uart_cts_c",
"uart_rts_c";
function = "uart_c";
};
};
i2c_a_pins: i2c_a {
mux {
groups = "i2c_sck_a",
"i2c_sda_a";
function = "i2c_a";
};
};
i2c_b_pins: i2c_b {
mux {
groups = "i2c_sck_b",
"i2c_sda_b";
function = "i2c_b";
};
};
i2c_c_pins: i2c_c {
mux {
groups = "i2c_sck_c",
"i2c_sda_c";
function = "i2c_c";
};
};
eth_rgmii_pins: eth-rgmii {
mux {
groups = "eth_mdio",
"eth_mdc",
"eth_clk_rx_clk",
"eth_rx_dv",
"eth_rxd0",
"eth_rxd1",
"eth_rxd2",
"eth_rxd3",
"eth_rgmii_tx_clk",
"eth_tx_en",
"eth_txd0",
"eth_txd1",
"eth_txd2",
"eth_txd3";
function = "eth";
};
};
eth_rmii_pins: eth-rmii {
mux {
groups = "eth_mdio",
"eth_mdc",
"eth_clk_rx_clk",
"eth_rx_dv",
"eth_rxd0",
"eth_rxd1",
"eth_tx_en",
"eth_txd0",
"eth_txd1";
function = "eth";
};
};
pwm_a_x_pins: pwm_a_x {
mux {
groups = "pwm_a_x";
function = "pwm_a_x";
};
};
pwm_a_y_pins: pwm_a_y {
mux {
groups = "pwm_a_y";
function = "pwm_a_y";
};
};
pwm_b_pins: pwm_b {
mux {
groups = "pwm_b";
function = "pwm_b";
};
};
pwm_d_pins: pwm_d {
mux {
groups = "pwm_d";
function = "pwm_d";
};
};
pwm_e_pins: pwm_e {
mux {
groups = "pwm_e";
function = "pwm_e";
};
};
pwm_f_x_pins: pwm_f_x {
mux {
groups = "pwm_f_x";
function = "pwm_f_x";
};
};
pwm_f_y_pins: pwm_f_y {
mux {
groups = "pwm_f_y";
function = "pwm_f_y";
};
};
hdmi_hpd_pins: hdmi_hpd {
mux {
groups = "hdmi_hpd";
function = "hdmi_hpd";
};
};
hdmi_i2c_pins: hdmi_i2c {
mux {
groups = "hdmi_sda", "hdmi_scl";
function = "hdmi_i2c";
}; };};
};
+&hiubus {
- clkc: clock-controller@0 {
compatible = "amlogic,gxbb-clkc";
#clock-cells = <1>;
reg = <0x0 0x0 0x0 0x3db>;
- };
+};
+&i2c_A {
- clocks = <&clkc CLKID_I2C>;
+};
+&i2c_B {
- clocks = <&clkc CLKID_I2C>;
+};
+&i2c_C {
- clocks = <&clkc CLKID_I2C>;
+};
+&sd_emmc_a {
- clocks = <&clkc CLKID_SD_EMMC_A>,
<&xtal>,
<&clkc CLKID_FCLK_DIV2>;
- clock-names = "core", "clkin0", "clkin1";
+};
+&sd_emmc_b {
- clocks = <&clkc CLKID_SD_EMMC_B>,
<&xtal>,
<&clkc CLKID_FCLK_DIV2>;
- clock-names = "core", "clkin0", "clkin1";
+};
+&sd_emmc_c {
- clocks = <&clkc CLKID_SD_EMMC_C>,
<&xtal>,
<&clkc CLKID_FCLK_DIV2>;
- clock-names = "core", "clkin0", "clkin1";
+};
+&vpu {
- compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
+}; diff --git a/include/dt-bindings/clock/gxbb-aoclkc.h b/include/dt-bindings/clock/gxbb-aoclkc.h new file mode 100644 index 0000000..3175148 --- /dev/null +++ b/include/dt-bindings/clock/gxbb-aoclkc.h @@ -0,0 +1,66 @@ +/*
- This file is provided under a dual BSD/GPLv2 license. When using or
- redistributing this file, you may do so under either license.
- GPL LICENSE SUMMARY
- Copyright (c) 2016 BayLibre, SAS.
- Author: Neil Armstrong narmstrong@baylibre.com
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see http://www.gnu.org/licenses/.
- The full GNU General Public License is included in this distribution
- in the file called COPYING.
- BSD LICENSE
- Copyright (c) 2016 BayLibre, SAS.
- Author: Neil Armstrong narmstrong@baylibre.com
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
- Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+#ifndef DT_BINDINGS_CLOCK_AMLOGIC_MESON_GXBB_AOCLK +#define DT_BINDINGS_CLOCK_AMLOGIC_MESON_GXBB_AOCLK
+#define CLKID_AO_REMOTE 0 +#define CLKID_AO_I2C_MASTER 1 +#define CLKID_AO_I2C_SLAVE 2 +#define CLKID_AO_UART1 3 +#define CLKID_AO_UART2 4 +#define CLKID_AO_IR_BLASTER 5
+#endif diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h new file mode 100644 index 0000000..692846c --- /dev/null +++ b/include/dt-bindings/clock/gxbb-clkc.h @@ -0,0 +1,34 @@ +/*
- GXBB clock tree IDs
- */
+#ifndef __GXBB_CLKC_H +#define __GXBB_CLKC_H
+#define CLKID_CPUCLK 1 +#define CLKID_HDMI_PLL 2 +#define CLKID_FCLK_DIV2 4 +#define CLKID_FCLK_DIV3 5 +#define CLKID_FCLK_DIV4 6 +#define CLKID_CLK81 12 +#define CLKID_MPLL2 15 +#define CLKID_SPI 34 +#define CLKID_I2C 22 +#define CLKID_SAR_ADC 23 +#define CLKID_ETH 36 +#define CLKID_USB0 50 +#define CLKID_USB1 51 +#define CLKID_USB 55 +#define CLKID_HDMI_PCLK 63 +#define CLKID_USB1_DDR_BRIDGE 64 +#define CLKID_USB0_DDR_BRIDGE 65 +#define CLKID_SANA 69 +#define CLKID_GCLK_VENCI_INT0 77 +#define CLKID_AO_I2C 93 +#define CLKID_SD_EMMC_A 94 +#define CLKID_SD_EMMC_B 95 +#define CLKID_SD_EMMC_C 96 +#define CLKID_SAR_ADC_CLK 97 +#define CLKID_SAR_ADC_SEL 98
+#endif /* __GXBB_CLKC_H */ diff --git a/include/dt-bindings/reset/gxbb-aoclkc.h b/include/dt-bindings/reset/gxbb-aoclkc.h new file mode 100644 index 0000000..9e3fd60 --- /dev/null +++ b/include/dt-bindings/reset/gxbb-aoclkc.h @@ -0,0 +1,66 @@ +/*
- This file is provided under a dual BSD/GPLv2 license. When using or
- redistributing this file, you may do so under either license.
- GPL LICENSE SUMMARY
- Copyright (c) 2016 BayLibre, SAS.
- Author: Neil Armstrong narmstrong@baylibre.com
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, see http://www.gnu.org/licenses/.
- The full GNU General Public License is included in this distribution
- in the file called COPYING.
- BSD LICENSE
- Copyright (c) 2016 BayLibre, SAS.
- Author: Neil Armstrong narmstrong@baylibre.com
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
- Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
+#ifndef DT_BINDINGS_RESET_AMLOGIC_MESON_GXBB_AOCLK +#define DT_BINDINGS_RESET_AMLOGIC_MESON_GXBB_AOCLK
+#define RESET_AO_REMOTE 0 +#define RESET_AO_I2C_MASTER 1 +#define RESET_AO_I2C_SLAVE 2 +#define RESET_AO_UART1 3 +#define RESET_AO_UART2 4 +#define RESET_AO_IR_BLASTER 5
+#endif

From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes: - BLK support added - general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com --- v6: - remove DM_MMC_OPS from Kconfig dependencies - address two minor review comments of Jaehoon v7: - rebased --- arch/arm/include/asm/arch-meson/sd_emmc.h | 89 +++++++++ drivers/mmc/Kconfig | 6 + drivers/mmc/Makefile | 1 + drivers/mmc/meson_gx_mmc.c | 291 ++++++++++++++++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_gx_mmc.c
diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h new file mode 100644 index 0000000..a09e034 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/sd_emmc.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2016 Carlo Caione carlo@caione.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __SD_EMMC_H__ +#define __SD_EMMC_H__ + +#include <mmc.h> + +#define SDIO_PORT_A 0 +#define SDIO_PORT_B 1 +#define SDIO_PORT_C 2 + +#define SD_EMMC_CLKSRC_24M 24000000 /* 24 MHz */ +#define SD_EMMC_CLKSRC_DIV2 1000000000 /* 1 GHz */ + +#define MESON_SD_EMMC_CLOCK 0x00 +#define CLK_MAX_DIV 63 +#define CLK_SRC_24M (0 << 6) +#define CLK_SRC_DIV2 (1 << 6) +#define CLK_CO_PHASE_000 (0 << 8) +#define CLK_CO_PHASE_090 (1 << 8) +#define CLK_CO_PHASE_180 (2 << 8) +#define CLK_CO_PHASE_270 (3 << 8) +#define CLK_TX_PHASE_000 (0 << 10) +#define CLK_TX_PHASE_090 (1 << 10) +#define CLK_TX_PHASE_180 (2 << 10) +#define CLK_TX_PHASE_270 (3 << 10) +#define CLK_ALWAYS_ON BIT(24) + +#define MESON_SD_EMMC_CFG 0x44 +#define CFG_BUS_WIDTH_MASK GENMASK(1, 0) +#define CFG_BUS_WIDTH_1 0 +#define CFG_BUS_WIDTH_4 1 +#define CFG_BUS_WIDTH_8 2 +#define CFG_BL_LEN_MASK GENMASK(7, 4) +#define CFG_BL_LEN_SHIFT 4 +#define CFG_BL_LEN_512 (9 << 4) +#define CFG_RESP_TIMEOUT_MASK GENMASK(11, 8) +#define CFG_RESP_TIMEOUT_256 (8 << 8) +#define CFG_RC_CC_MASK GENMASK(15, 12) +#define CFG_RC_CC_16 (4 << 12) +#define CFG_SDCLK_ALWAYS_ON BIT(18) +#define CFG_AUTO_CLK BIT(23) + +#define MESON_SD_EMMC_STATUS 0x48 +#define STATUS_MASK GENMASK(15, 0) +#define STATUS_ERR_MASK GENMASK(12, 0) +#define STATUS_RXD_ERR_MASK GENMASK(7, 0) +#define STATUS_TXD_ERR BIT(8) +#define STATUS_DESC_ERR BIT(9) +#define STATUS_RESP_ERR BIT(10) +#define STATUS_RESP_TIMEOUT BIT(11) +#define STATUS_DESC_TIMEOUT BIT(12) +#define STATUS_END_OF_CHAIN BIT(13) + +#define MESON_SD_EMMC_IRQ_EN 0x4c + +#define MESON_SD_EMMC_CMD_CFG 0x50 +#define CMD_CFG_LENGTH_MASK GENMASK(8, 0) +#define CMD_CFG_BLOCK_MODE BIT(9) +#define CMD_CFG_R1B BIT(10) +#define CMD_CFG_END_OF_CHAIN BIT(11) +#define CMD_CFG_TIMEOUT_4S (12 << 12) +#define CMD_CFG_NO_RESP BIT(16) +#define CMD_CFG_DATA_IO BIT(18) +#define CMD_CFG_DATA_WR BIT(19) +#define CMD_CFG_RESP_NOCRC BIT(20) +#define CMD_CFG_RESP_128 BIT(21) +#define CMD_CFG_CMD_INDEX_SHIFT 24 +#define CMD_CFG_OWNER BIT(31) + +#define MESON_SD_EMMC_CMD_ARG 0x54 +#define MESON_SD_EMMC_CMD_DAT 0x58 +#define MESON_SD_EMMC_CMD_RSP 0x5c +#define MESON_SD_EMMC_CMD_RSP1 0x60 +#define MESON_SD_EMMC_CMD_RSP2 0x64 +#define MESON_SD_EMMC_CMD_RSP3 0x68 + +struct meson_mmc_platdata { + struct mmc_config cfg; + struct mmc mmc; + void *regbase; + void *w_buf; +}; + +#endif diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 560391f..077b184 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -105,6 +105,12 @@ config MMC_DW_SOCFPGA Synopsys DesignWare Memory Card Interface driver. Select this option for platforms based on Altera SOCFPGA.
+config MMC_MESON_GX + bool "Meson GX EMMC controller support" + depends on DM_MMC && BLK && DM_MMC_OPS && ARCH_MESON + help + Support for EMMC host controller on Meson GX ARM SoCs platform (S905) + config MMC_MXC bool "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" help diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6a26a52..a61a9e9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -29,6 +29,7 @@ ifdef CONFIG_SUPPORT_EMMC_BOOT obj-$(CONFIG_GENERIC_MMC) += mmc_boot.o endif obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o +obj-$(CONFIG_MMC_MESON_GX) += meson_gx_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c new file mode 100644 index 0000000..8e28ab7 --- /dev/null +++ b/drivers/mmc/meson_gx_mmc.c @@ -0,0 +1,291 @@ +/* + * (C) Copyright 2016 Carlo Caione carlo@caione.org + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <malloc.h> +#include <mmc.h> +#include <asm/io.h> +#include <asm/arch/sd_emmc.h> +#include <dm/device.h> +#include <linux/log2.h> + +static inline void *get_regbase(const struct mmc *mmc) +{ + struct meson_mmc_platdata *pdata = mmc->priv; + + return pdata->regbase; +} + +static inline uint32_t meson_read(struct mmc *mmc, int offset) +{ + return readl(get_regbase(mmc) + offset); +} + +static inline void meson_write(struct mmc *mmc, uint32_t val, int offset) +{ + writel(val, get_regbase(mmc) + offset); +} + +static void meson_mmc_config_clock(struct mmc *mmc) +{ + uint32_t meson_mmc_clk = 0; + unsigned int clk, clk_src, clk_div; + + /* 1GHz / CLK_MAX_DIV = 15,9 MHz */ + if (mmc->clock > 16000000) { + clk = SD_EMMC_CLKSRC_DIV2; + clk_src = CLK_SRC_DIV2; + } else { + clk = SD_EMMC_CLKSRC_24M; + clk_src = CLK_SRC_24M; + } + clk_div = DIV_ROUND_UP(clk, mmc->clock); + + /* 180 phase core clock */ + meson_mmc_clk |= CLK_CO_PHASE_180; + + /* 180 phase tx clock */ + meson_mmc_clk |= CLK_TX_PHASE_000; + + /* clock settings */ + meson_mmc_clk |= clk_src; + meson_mmc_clk |= clk_div; + + meson_write(mmc, meson_mmc_clk, MESON_SD_EMMC_CLOCK); +} + +static int meson_dm_mmc_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + uint32_t meson_mmc_cfg; + + meson_mmc_config_clock(mmc); + + meson_mmc_cfg = meson_read(mmc, MESON_SD_EMMC_CFG); + + meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK; + if (mmc->bus_width == 1) + meson_mmc_cfg |= CFG_BUS_WIDTH_1; + else if (mmc->bus_width == 4) + meson_mmc_cfg |= CFG_BUS_WIDTH_4; + else if (mmc->bus_width == 8) + meson_mmc_cfg |= CFG_BUS_WIDTH_8; + else + return -EINVAL; + + /* 512 bytes block length */ + meson_mmc_cfg &= ~CFG_BL_LEN_MASK; + meson_mmc_cfg |= CFG_BL_LEN_512; + + /* Response timeout 256 clk */ + meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK; + meson_mmc_cfg |= CFG_RESP_TIMEOUT_256; + + /* Command-command gap 16 clk */ + meson_mmc_cfg &= ~CFG_RC_CC_MASK; + meson_mmc_cfg |= CFG_RC_CC_16; + + meson_write(mmc, meson_mmc_cfg, MESON_SD_EMMC_CFG); + + return 0; +} + +static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data, + struct mmc_cmd *cmd) +{ + uint32_t meson_mmc_cmd = 0, cfg; + + meson_mmc_cmd |= cmd->cmdidx << CMD_CFG_CMD_INDEX_SHIFT; + + if (cmd->resp_type & MMC_RSP_PRESENT) { + if (cmd->resp_type & MMC_RSP_136) + meson_mmc_cmd |= CMD_CFG_RESP_128; + + if (cmd->resp_type & MMC_RSP_BUSY) + meson_mmc_cmd |= CMD_CFG_R1B; + + if (!(cmd->resp_type & MMC_RSP_CRC)) + meson_mmc_cmd |= CMD_CFG_RESP_NOCRC; + } else { + meson_mmc_cmd |= CMD_CFG_NO_RESP; + } + + if (data) { + cfg = meson_read(mmc, MESON_SD_EMMC_CFG); + cfg &= ~CFG_BL_LEN_MASK; + cfg |= ilog2(data->blocksize) << CFG_BL_LEN_SHIFT; + meson_write(mmc, cfg, MESON_SD_EMMC_CFG); + + if (data->flags == MMC_DATA_WRITE) + meson_mmc_cmd |= CMD_CFG_DATA_WR; + + meson_mmc_cmd |= CMD_CFG_DATA_IO | CMD_CFG_BLOCK_MODE | + data->blocks; + } + + meson_mmc_cmd |= CMD_CFG_TIMEOUT_4S | CMD_CFG_OWNER | + CMD_CFG_END_OF_CHAIN; + + meson_write(mmc, meson_mmc_cmd, MESON_SD_EMMC_CMD_CFG); +} + +static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data) +{ + struct meson_mmc_platdata *pdata = mmc->priv; + unsigned int data_size; + uint32_t data_addr = 0; + + if (data) { + data_size = data->blocks * data->blocksize; + + if (data->flags == MMC_DATA_READ) { + data_addr = (ulong) data->dest; + invalidate_dcache_range(data_addr, + data_addr + data_size); + } else { + pdata->w_buf = calloc(data_size, sizeof(char)); + data_addr = (ulong) pdata->w_buf; + memcpy(pdata->w_buf, data->src, data_size); + flush_dcache_range(data_addr, data_addr + data_size); + } + } + + meson_write(mmc, data_addr, MESON_SD_EMMC_CMD_DAT); +} + +static void meson_mmc_read_response(struct mmc *mmc, struct mmc_cmd *cmd) +{ + if (cmd->resp_type & MMC_RSP_136) { + cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP3); + cmd->response[1] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP2); + cmd->response[2] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP1); + cmd->response[3] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP); + } else { + cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP); + } +} + +static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct meson_mmc_platdata *pdata = mmc->priv; + uint32_t status; + ulong start; + int ret = 0; + + /* max block size supported by chip is 512 byte */ + if (data && data->blocksize > 512) + return -EINVAL; + + meson_mmc_setup_cmd(mmc, data, cmd); + meson_mmc_setup_addr(mmc, data); + + meson_write(mmc, cmd->cmdarg, MESON_SD_EMMC_CMD_ARG); + + /* use 10s timeout */ + start = get_timer(0); + do { + status = meson_read(mmc, MESON_SD_EMMC_STATUS); + } while(!(status & STATUS_END_OF_CHAIN) && get_timer(start) < 10000); + + if (!(status & STATUS_END_OF_CHAIN)) + ret = -ETIMEDOUT; + else if (status & STATUS_RESP_TIMEOUT) + ret = -ETIMEDOUT; + else if (status & STATUS_ERR_MASK) + ret = -EIO; + + meson_mmc_read_response(mmc, cmd); + + if (data && data->flags == MMC_DATA_WRITE) + free(pdata->w_buf); + + /* reset status bits */ + meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS); + + return ret; +} + +static const struct dm_mmc_ops meson_dm_mmc_ops = { + .send_cmd = meson_dm_mmc_send_cmd, + .set_ios = meson_dm_mmc_set_ios, +}; + +static int meson_mmc_ofdata_to_platdata(struct udevice *dev) +{ + struct meson_mmc_platdata *pdata = dev_get_platdata(dev); + fdt_addr_t addr; + + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + pdata->regbase = (void *)addr; + + return 0; +} + +static int meson_mmc_probe(struct udevice *dev) +{ + struct meson_mmc_platdata *pdata = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct mmc *mmc = &pdata->mmc; + struct mmc_config *cfg = &pdata->cfg; + uint32_t val; + + cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 | + MMC_VDD_31_32 | MMC_VDD_165_195; + cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT | + MMC_MODE_HS_52MHz | MMC_MODE_HS; + cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV); + cfg->f_max = 100000000; /* 100 MHz */ + cfg->b_max = 256; /* max 256 blocks */ + cfg->name = dev->name; + + mmc->priv = pdata; + upriv->mmc = mmc; + + mmc_set_clock(mmc, cfg->f_min); + + /* reset all status bits */ + meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS); + + /* disable interrupts */ + meson_write(mmc, 0, MESON_SD_EMMC_IRQ_EN); + + /* enable auto clock mode */ + val = meson_read(mmc, MESON_SD_EMMC_CFG); + val &= ~CFG_SDCLK_ALWAYS_ON; + val |= CFG_AUTO_CLK; + meson_write(mmc, val, MESON_SD_EMMC_CFG); + + return 0; +} + +int meson_mmc_bind(struct udevice *dev) +{ + struct meson_mmc_platdata *pdata = dev_get_platdata(dev); + + return mmc_bind(dev, &pdata->mmc, &pdata->cfg); +} + +static const struct udevice_id meson_mmc_match[] = { + { .compatible = "amlogic,meson-gx-mmc" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(meson_mmc) = { + .name = "meson_gx_mmc", + .id = UCLASS_MMC, + .of_match = meson_mmc_match, + .ops = &meson_dm_mmc_ops, + .probe = meson_mmc_probe, + .bind = meson_mmc_bind, + .ofdata_to_platdata = meson_mmc_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata), +};

On 2017-04-12, Heiner Kallweit wrote:
From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes:
- BLK support added
- general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Tested on odroid-c2, loads and boots kernel + initramfs + devicetree.
Thanks!
Tested-by: Vagrant Cascadian vagrant@debian.org
live well, vagrant
v6:
- remove DM_MMC_OPS from Kconfig dependencies
- address two minor review comments of Jaehoon
v7:
- rebased
arch/arm/include/asm/arch-meson/sd_emmc.h | 89 +++++++++ drivers/mmc/Kconfig | 6 + drivers/mmc/Makefile | 1 + drivers/mmc/meson_gx_mmc.c | 291 ++++++++++++++++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_gx_mmc.c
diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h new file mode 100644 index 0000000..a09e034 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/sd_emmc.h @@ -0,0 +1,89 @@ +/*
- (C) Copyright 2016 Carlo Caione carlo@caione.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __SD_EMMC_H__ +#define __SD_EMMC_H__
+#include <mmc.h>
+#define SDIO_PORT_A 0 +#define SDIO_PORT_B 1 +#define SDIO_PORT_C 2
+#define SD_EMMC_CLKSRC_24M 24000000 /* 24 MHz */ +#define SD_EMMC_CLKSRC_DIV2 1000000000 /* 1 GHz */
+#define MESON_SD_EMMC_CLOCK 0x00 +#define CLK_MAX_DIV 63 +#define CLK_SRC_24M (0 << 6) +#define CLK_SRC_DIV2 (1 << 6) +#define CLK_CO_PHASE_000 (0 << 8) +#define CLK_CO_PHASE_090 (1 << 8) +#define CLK_CO_PHASE_180 (2 << 8) +#define CLK_CO_PHASE_270 (3 << 8) +#define CLK_TX_PHASE_000 (0 << 10) +#define CLK_TX_PHASE_090 (1 << 10) +#define CLK_TX_PHASE_180 (2 << 10) +#define CLK_TX_PHASE_270 (3 << 10) +#define CLK_ALWAYS_ON BIT(24)
+#define MESON_SD_EMMC_CFG 0x44 +#define CFG_BUS_WIDTH_MASK GENMASK(1, 0) +#define CFG_BUS_WIDTH_1 0 +#define CFG_BUS_WIDTH_4 1 +#define CFG_BUS_WIDTH_8 2 +#define CFG_BL_LEN_MASK GENMASK(7, 4) +#define CFG_BL_LEN_SHIFT 4 +#define CFG_BL_LEN_512 (9 << 4) +#define CFG_RESP_TIMEOUT_MASK GENMASK(11, 8) +#define CFG_RESP_TIMEOUT_256 (8 << 8) +#define CFG_RC_CC_MASK GENMASK(15, 12) +#define CFG_RC_CC_16 (4 << 12) +#define CFG_SDCLK_ALWAYS_ON BIT(18) +#define CFG_AUTO_CLK BIT(23)
+#define MESON_SD_EMMC_STATUS 0x48 +#define STATUS_MASK GENMASK(15, 0) +#define STATUS_ERR_MASK GENMASK(12, 0) +#define STATUS_RXD_ERR_MASK GENMASK(7, 0) +#define STATUS_TXD_ERR BIT(8) +#define STATUS_DESC_ERR BIT(9) +#define STATUS_RESP_ERR BIT(10) +#define STATUS_RESP_TIMEOUT BIT(11) +#define STATUS_DESC_TIMEOUT BIT(12) +#define STATUS_END_OF_CHAIN BIT(13)
+#define MESON_SD_EMMC_IRQ_EN 0x4c
+#define MESON_SD_EMMC_CMD_CFG 0x50 +#define CMD_CFG_LENGTH_MASK GENMASK(8, 0) +#define CMD_CFG_BLOCK_MODE BIT(9) +#define CMD_CFG_R1B BIT(10) +#define CMD_CFG_END_OF_CHAIN BIT(11) +#define CMD_CFG_TIMEOUT_4S (12 << 12) +#define CMD_CFG_NO_RESP BIT(16) +#define CMD_CFG_DATA_IO BIT(18) +#define CMD_CFG_DATA_WR BIT(19) +#define CMD_CFG_RESP_NOCRC BIT(20) +#define CMD_CFG_RESP_128 BIT(21) +#define CMD_CFG_CMD_INDEX_SHIFT 24 +#define CMD_CFG_OWNER BIT(31)
+#define MESON_SD_EMMC_CMD_ARG 0x54 +#define MESON_SD_EMMC_CMD_DAT 0x58 +#define MESON_SD_EMMC_CMD_RSP 0x5c +#define MESON_SD_EMMC_CMD_RSP1 0x60 +#define MESON_SD_EMMC_CMD_RSP2 0x64 +#define MESON_SD_EMMC_CMD_RSP3 0x68
+struct meson_mmc_platdata {
- struct mmc_config cfg;
- struct mmc mmc;
- void *regbase;
- void *w_buf;
+};
+#endif diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 560391f..077b184 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -105,6 +105,12 @@ config MMC_DW_SOCFPGA Synopsys DesignWare Memory Card Interface driver. Select this option for platforms based on Altera SOCFPGA.
+config MMC_MESON_GX
- bool "Meson GX EMMC controller support"
- depends on DM_MMC && BLK && DM_MMC_OPS && ARCH_MESON
- help
Support for EMMC host controller on Meson GX ARM SoCs platform (S905)
config MMC_MXC bool "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" help diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6a26a52..a61a9e9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -29,6 +29,7 @@ ifdef CONFIG_SUPPORT_EMMC_BOOT obj-$(CONFIG_GENERIC_MMC) += mmc_boot.o endif obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o +obj-$(CONFIG_MMC_MESON_GX) += meson_gx_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c new file mode 100644 index 0000000..8e28ab7 --- /dev/null +++ b/drivers/mmc/meson_gx_mmc.c @@ -0,0 +1,291 @@ +/*
- (C) Copyright 2016 Carlo Caione carlo@caione.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <malloc.h> +#include <mmc.h> +#include <asm/io.h> +#include <asm/arch/sd_emmc.h> +#include <dm/device.h> +#include <linux/log2.h>
+static inline void *get_regbase(const struct mmc *mmc) +{
- struct meson_mmc_platdata *pdata = mmc->priv;
- return pdata->regbase;
+}
+static inline uint32_t meson_read(struct mmc *mmc, int offset) +{
- return readl(get_regbase(mmc) + offset);
+}
+static inline void meson_write(struct mmc *mmc, uint32_t val, int offset) +{
- writel(val, get_regbase(mmc) + offset);
+}
+static void meson_mmc_config_clock(struct mmc *mmc) +{
- uint32_t meson_mmc_clk = 0;
- unsigned int clk, clk_src, clk_div;
- /* 1GHz / CLK_MAX_DIV = 15,9 MHz */
- if (mmc->clock > 16000000) {
clk = SD_EMMC_CLKSRC_DIV2;
clk_src = CLK_SRC_DIV2;
- } else {
clk = SD_EMMC_CLKSRC_24M;
clk_src = CLK_SRC_24M;
- }
- clk_div = DIV_ROUND_UP(clk, mmc->clock);
- /* 180 phase core clock */
- meson_mmc_clk |= CLK_CO_PHASE_180;
- /* 180 phase tx clock */
- meson_mmc_clk |= CLK_TX_PHASE_000;
- /* clock settings */
- meson_mmc_clk |= clk_src;
- meson_mmc_clk |= clk_div;
- meson_write(mmc, meson_mmc_clk, MESON_SD_EMMC_CLOCK);
+}
+static int meson_dm_mmc_set_ios(struct udevice *dev) +{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- uint32_t meson_mmc_cfg;
- meson_mmc_config_clock(mmc);
- meson_mmc_cfg = meson_read(mmc, MESON_SD_EMMC_CFG);
- meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK;
- if (mmc->bus_width == 1)
meson_mmc_cfg |= CFG_BUS_WIDTH_1;
- else if (mmc->bus_width == 4)
meson_mmc_cfg |= CFG_BUS_WIDTH_4;
- else if (mmc->bus_width == 8)
meson_mmc_cfg |= CFG_BUS_WIDTH_8;
- else
return -EINVAL;
- /* 512 bytes block length */
- meson_mmc_cfg &= ~CFG_BL_LEN_MASK;
- meson_mmc_cfg |= CFG_BL_LEN_512;
- /* Response timeout 256 clk */
- meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK;
- meson_mmc_cfg |= CFG_RESP_TIMEOUT_256;
- /* Command-command gap 16 clk */
- meson_mmc_cfg &= ~CFG_RC_CC_MASK;
- meson_mmc_cfg |= CFG_RC_CC_16;
- meson_write(mmc, meson_mmc_cfg, MESON_SD_EMMC_CFG);
- return 0;
+}
+static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data,
struct mmc_cmd *cmd)
+{
- uint32_t meson_mmc_cmd = 0, cfg;
- meson_mmc_cmd |= cmd->cmdidx << CMD_CFG_CMD_INDEX_SHIFT;
- if (cmd->resp_type & MMC_RSP_PRESENT) {
if (cmd->resp_type & MMC_RSP_136)
meson_mmc_cmd |= CMD_CFG_RESP_128;
if (cmd->resp_type & MMC_RSP_BUSY)
meson_mmc_cmd |= CMD_CFG_R1B;
if (!(cmd->resp_type & MMC_RSP_CRC))
meson_mmc_cmd |= CMD_CFG_RESP_NOCRC;
- } else {
meson_mmc_cmd |= CMD_CFG_NO_RESP;
- }
- if (data) {
cfg = meson_read(mmc, MESON_SD_EMMC_CFG);
cfg &= ~CFG_BL_LEN_MASK;
cfg |= ilog2(data->blocksize) << CFG_BL_LEN_SHIFT;
meson_write(mmc, cfg, MESON_SD_EMMC_CFG);
if (data->flags == MMC_DATA_WRITE)
meson_mmc_cmd |= CMD_CFG_DATA_WR;
meson_mmc_cmd |= CMD_CFG_DATA_IO | CMD_CFG_BLOCK_MODE |
data->blocks;
- }
- meson_mmc_cmd |= CMD_CFG_TIMEOUT_4S | CMD_CFG_OWNER |
CMD_CFG_END_OF_CHAIN;
- meson_write(mmc, meson_mmc_cmd, MESON_SD_EMMC_CMD_CFG);
+}
+static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data) +{
- struct meson_mmc_platdata *pdata = mmc->priv;
- unsigned int data_size;
- uint32_t data_addr = 0;
- if (data) {
data_size = data->blocks * data->blocksize;
if (data->flags == MMC_DATA_READ) {
data_addr = (ulong) data->dest;
invalidate_dcache_range(data_addr,
data_addr + data_size);
} else {
pdata->w_buf = calloc(data_size, sizeof(char));
data_addr = (ulong) pdata->w_buf;
memcpy(pdata->w_buf, data->src, data_size);
flush_dcache_range(data_addr, data_addr + data_size);
}
- }
- meson_write(mmc, data_addr, MESON_SD_EMMC_CMD_DAT);
+}
+static void meson_mmc_read_response(struct mmc *mmc, struct mmc_cmd *cmd) +{
- if (cmd->resp_type & MMC_RSP_136) {
cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP3);
cmd->response[1] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP2);
cmd->response[2] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP1);
cmd->response[3] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP);
- } else {
cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP);
- }
+}
+static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
+{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- struct meson_mmc_platdata *pdata = mmc->priv;
- uint32_t status;
- ulong start;
- int ret = 0;
- /* max block size supported by chip is 512 byte */
- if (data && data->blocksize > 512)
return -EINVAL;
- meson_mmc_setup_cmd(mmc, data, cmd);
- meson_mmc_setup_addr(mmc, data);
- meson_write(mmc, cmd->cmdarg, MESON_SD_EMMC_CMD_ARG);
- /* use 10s timeout */
- start = get_timer(0);
- do {
status = meson_read(mmc, MESON_SD_EMMC_STATUS);
- } while(!(status & STATUS_END_OF_CHAIN) && get_timer(start) < 10000);
- if (!(status & STATUS_END_OF_CHAIN))
ret = -ETIMEDOUT;
- else if (status & STATUS_RESP_TIMEOUT)
ret = -ETIMEDOUT;
- else if (status & STATUS_ERR_MASK)
ret = -EIO;
- meson_mmc_read_response(mmc, cmd);
- if (data && data->flags == MMC_DATA_WRITE)
free(pdata->w_buf);
- /* reset status bits */
- meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS);
- return ret;
+}
+static const struct dm_mmc_ops meson_dm_mmc_ops = {
- .send_cmd = meson_dm_mmc_send_cmd,
- .set_ios = meson_dm_mmc_set_ios,
+};
+static int meson_mmc_ofdata_to_platdata(struct udevice *dev) +{
- struct meson_mmc_platdata *pdata = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = dev_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- pdata->regbase = (void *)addr;
- return 0;
+}
+static int meson_mmc_probe(struct udevice *dev) +{
- struct meson_mmc_platdata *pdata = dev_get_platdata(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct mmc *mmc = &pdata->mmc;
- struct mmc_config *cfg = &pdata->cfg;
- uint32_t val;
- cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
MMC_VDD_31_32 | MMC_VDD_165_195;
- cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
MMC_MODE_HS_52MHz | MMC_MODE_HS;
- cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV);
- cfg->f_max = 100000000; /* 100 MHz */
- cfg->b_max = 256; /* max 256 blocks */
- cfg->name = dev->name;
- mmc->priv = pdata;
- upriv->mmc = mmc;
- mmc_set_clock(mmc, cfg->f_min);
- /* reset all status bits */
- meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS);
- /* disable interrupts */
- meson_write(mmc, 0, MESON_SD_EMMC_IRQ_EN);
- /* enable auto clock mode */
- val = meson_read(mmc, MESON_SD_EMMC_CFG);
- val &= ~CFG_SDCLK_ALWAYS_ON;
- val |= CFG_AUTO_CLK;
- meson_write(mmc, val, MESON_SD_EMMC_CFG);
- return 0;
+}
+int meson_mmc_bind(struct udevice *dev) +{
- struct meson_mmc_platdata *pdata = dev_get_platdata(dev);
- return mmc_bind(dev, &pdata->mmc, &pdata->cfg);
+}
+static const struct udevice_id meson_mmc_match[] = {
- { .compatible = "amlogic,meson-gx-mmc" },
- { /* sentinel */ }
+};
+U_BOOT_DRIVER(meson_mmc) = {
- .name = "meson_gx_mmc",
- .id = UCLASS_MMC,
- .of_match = meson_mmc_match,
- .ops = &meson_dm_mmc_ops,
- .probe = meson_mmc_probe,
- .bind = meson_mmc_bind,
- .ofdata_to_platdata = meson_mmc_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata),
+};

On 04/13/2017 03:30 AM, Heiner Kallweit wrote:
From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes:
- BLK support added
- general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Best Regards, Jaehoon Chung
v6:
- remove DM_MMC_OPS from Kconfig dependencies
- address two minor review comments of Jaehoon
v7:
- rebased
arch/arm/include/asm/arch-meson/sd_emmc.h | 89 +++++++++ drivers/mmc/Kconfig | 6 + drivers/mmc/Makefile | 1 + drivers/mmc/meson_gx_mmc.c | 291 ++++++++++++++++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_gx_mmc.c
diff --git a/arch/arm/include/asm/arch-meson/sd_emmc.h b/arch/arm/include/asm/arch-meson/sd_emmc.h new file mode 100644 index 0000000..a09e034 --- /dev/null +++ b/arch/arm/include/asm/arch-meson/sd_emmc.h @@ -0,0 +1,89 @@ +/*
- (C) Copyright 2016 Carlo Caione carlo@caione.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __SD_EMMC_H__ +#define __SD_EMMC_H__
+#include <mmc.h>
+#define SDIO_PORT_A 0 +#define SDIO_PORT_B 1 +#define SDIO_PORT_C 2
+#define SD_EMMC_CLKSRC_24M 24000000 /* 24 MHz */ +#define SD_EMMC_CLKSRC_DIV2 1000000000 /* 1 GHz */
+#define MESON_SD_EMMC_CLOCK 0x00 +#define CLK_MAX_DIV 63 +#define CLK_SRC_24M (0 << 6) +#define CLK_SRC_DIV2 (1 << 6) +#define CLK_CO_PHASE_000 (0 << 8) +#define CLK_CO_PHASE_090 (1 << 8) +#define CLK_CO_PHASE_180 (2 << 8) +#define CLK_CO_PHASE_270 (3 << 8) +#define CLK_TX_PHASE_000 (0 << 10) +#define CLK_TX_PHASE_090 (1 << 10) +#define CLK_TX_PHASE_180 (2 << 10) +#define CLK_TX_PHASE_270 (3 << 10) +#define CLK_ALWAYS_ON BIT(24)
+#define MESON_SD_EMMC_CFG 0x44 +#define CFG_BUS_WIDTH_MASK GENMASK(1, 0) +#define CFG_BUS_WIDTH_1 0 +#define CFG_BUS_WIDTH_4 1 +#define CFG_BUS_WIDTH_8 2 +#define CFG_BL_LEN_MASK GENMASK(7, 4) +#define CFG_BL_LEN_SHIFT 4 +#define CFG_BL_LEN_512 (9 << 4) +#define CFG_RESP_TIMEOUT_MASK GENMASK(11, 8) +#define CFG_RESP_TIMEOUT_256 (8 << 8) +#define CFG_RC_CC_MASK GENMASK(15, 12) +#define CFG_RC_CC_16 (4 << 12) +#define CFG_SDCLK_ALWAYS_ON BIT(18) +#define CFG_AUTO_CLK BIT(23)
+#define MESON_SD_EMMC_STATUS 0x48 +#define STATUS_MASK GENMASK(15, 0) +#define STATUS_ERR_MASK GENMASK(12, 0) +#define STATUS_RXD_ERR_MASK GENMASK(7, 0) +#define STATUS_TXD_ERR BIT(8) +#define STATUS_DESC_ERR BIT(9) +#define STATUS_RESP_ERR BIT(10) +#define STATUS_RESP_TIMEOUT BIT(11) +#define STATUS_DESC_TIMEOUT BIT(12) +#define STATUS_END_OF_CHAIN BIT(13)
+#define MESON_SD_EMMC_IRQ_EN 0x4c
+#define MESON_SD_EMMC_CMD_CFG 0x50 +#define CMD_CFG_LENGTH_MASK GENMASK(8, 0) +#define CMD_CFG_BLOCK_MODE BIT(9) +#define CMD_CFG_R1B BIT(10) +#define CMD_CFG_END_OF_CHAIN BIT(11) +#define CMD_CFG_TIMEOUT_4S (12 << 12) +#define CMD_CFG_NO_RESP BIT(16) +#define CMD_CFG_DATA_IO BIT(18) +#define CMD_CFG_DATA_WR BIT(19) +#define CMD_CFG_RESP_NOCRC BIT(20) +#define CMD_CFG_RESP_128 BIT(21) +#define CMD_CFG_CMD_INDEX_SHIFT 24 +#define CMD_CFG_OWNER BIT(31)
+#define MESON_SD_EMMC_CMD_ARG 0x54 +#define MESON_SD_EMMC_CMD_DAT 0x58 +#define MESON_SD_EMMC_CMD_RSP 0x5c +#define MESON_SD_EMMC_CMD_RSP1 0x60 +#define MESON_SD_EMMC_CMD_RSP2 0x64 +#define MESON_SD_EMMC_CMD_RSP3 0x68
+struct meson_mmc_platdata {
- struct mmc_config cfg;
- struct mmc mmc;
- void *regbase;
- void *w_buf;
+};
+#endif diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 560391f..077b184 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -105,6 +105,12 @@ config MMC_DW_SOCFPGA Synopsys DesignWare Memory Card Interface driver. Select this option for platforms based on Altera SOCFPGA.
+config MMC_MESON_GX
- bool "Meson GX EMMC controller support"
- depends on DM_MMC && BLK && DM_MMC_OPS && ARCH_MESON
- help
Support for EMMC host controller on Meson GX ARM SoCs platform (S905)
config MMC_MXC bool "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" help diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 6a26a52..a61a9e9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -29,6 +29,7 @@ ifdef CONFIG_SUPPORT_EMMC_BOOT obj-$(CONFIG_GENERIC_MMC) += mmc_boot.o endif obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o +obj-$(CONFIG_MMC_MESON_GX) += meson_gx_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MVEBU_MMC) += mvebu_mmc.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c new file mode 100644 index 0000000..8e28ab7 --- /dev/null +++ b/drivers/mmc/meson_gx_mmc.c @@ -0,0 +1,291 @@ +/*
- (C) Copyright 2016 Carlo Caione carlo@caione.org
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <fdtdec.h> +#include <malloc.h> +#include <mmc.h> +#include <asm/io.h> +#include <asm/arch/sd_emmc.h> +#include <dm/device.h> +#include <linux/log2.h>
+static inline void *get_regbase(const struct mmc *mmc) +{
- struct meson_mmc_platdata *pdata = mmc->priv;
- return pdata->regbase;
+}
+static inline uint32_t meson_read(struct mmc *mmc, int offset) +{
- return readl(get_regbase(mmc) + offset);
+}
+static inline void meson_write(struct mmc *mmc, uint32_t val, int offset) +{
- writel(val, get_regbase(mmc) + offset);
+}
+static void meson_mmc_config_clock(struct mmc *mmc) +{
- uint32_t meson_mmc_clk = 0;
- unsigned int clk, clk_src, clk_div;
- /* 1GHz / CLK_MAX_DIV = 15,9 MHz */
- if (mmc->clock > 16000000) {
clk = SD_EMMC_CLKSRC_DIV2;
clk_src = CLK_SRC_DIV2;
- } else {
clk = SD_EMMC_CLKSRC_24M;
clk_src = CLK_SRC_24M;
- }
- clk_div = DIV_ROUND_UP(clk, mmc->clock);
- /* 180 phase core clock */
- meson_mmc_clk |= CLK_CO_PHASE_180;
- /* 180 phase tx clock */
- meson_mmc_clk |= CLK_TX_PHASE_000;
- /* clock settings */
- meson_mmc_clk |= clk_src;
- meson_mmc_clk |= clk_div;
- meson_write(mmc, meson_mmc_clk, MESON_SD_EMMC_CLOCK);
+}
+static int meson_dm_mmc_set_ios(struct udevice *dev) +{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- uint32_t meson_mmc_cfg;
- meson_mmc_config_clock(mmc);
- meson_mmc_cfg = meson_read(mmc, MESON_SD_EMMC_CFG);
- meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK;
- if (mmc->bus_width == 1)
meson_mmc_cfg |= CFG_BUS_WIDTH_1;
- else if (mmc->bus_width == 4)
meson_mmc_cfg |= CFG_BUS_WIDTH_4;
- else if (mmc->bus_width == 8)
meson_mmc_cfg |= CFG_BUS_WIDTH_8;
- else
return -EINVAL;
- /* 512 bytes block length */
- meson_mmc_cfg &= ~CFG_BL_LEN_MASK;
- meson_mmc_cfg |= CFG_BL_LEN_512;
- /* Response timeout 256 clk */
- meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK;
- meson_mmc_cfg |= CFG_RESP_TIMEOUT_256;
- /* Command-command gap 16 clk */
- meson_mmc_cfg &= ~CFG_RC_CC_MASK;
- meson_mmc_cfg |= CFG_RC_CC_16;
- meson_write(mmc, meson_mmc_cfg, MESON_SD_EMMC_CFG);
- return 0;
+}
+static void meson_mmc_setup_cmd(struct mmc *mmc, struct mmc_data *data,
struct mmc_cmd *cmd)
+{
- uint32_t meson_mmc_cmd = 0, cfg;
- meson_mmc_cmd |= cmd->cmdidx << CMD_CFG_CMD_INDEX_SHIFT;
- if (cmd->resp_type & MMC_RSP_PRESENT) {
if (cmd->resp_type & MMC_RSP_136)
meson_mmc_cmd |= CMD_CFG_RESP_128;
if (cmd->resp_type & MMC_RSP_BUSY)
meson_mmc_cmd |= CMD_CFG_R1B;
if (!(cmd->resp_type & MMC_RSP_CRC))
meson_mmc_cmd |= CMD_CFG_RESP_NOCRC;
- } else {
meson_mmc_cmd |= CMD_CFG_NO_RESP;
- }
- if (data) {
cfg = meson_read(mmc, MESON_SD_EMMC_CFG);
cfg &= ~CFG_BL_LEN_MASK;
cfg |= ilog2(data->blocksize) << CFG_BL_LEN_SHIFT;
meson_write(mmc, cfg, MESON_SD_EMMC_CFG);
if (data->flags == MMC_DATA_WRITE)
meson_mmc_cmd |= CMD_CFG_DATA_WR;
meson_mmc_cmd |= CMD_CFG_DATA_IO | CMD_CFG_BLOCK_MODE |
data->blocks;
- }
- meson_mmc_cmd |= CMD_CFG_TIMEOUT_4S | CMD_CFG_OWNER |
CMD_CFG_END_OF_CHAIN;
- meson_write(mmc, meson_mmc_cmd, MESON_SD_EMMC_CMD_CFG);
+}
+static void meson_mmc_setup_addr(struct mmc *mmc, struct mmc_data *data) +{
- struct meson_mmc_platdata *pdata = mmc->priv;
- unsigned int data_size;
- uint32_t data_addr = 0;
- if (data) {
data_size = data->blocks * data->blocksize;
if (data->flags == MMC_DATA_READ) {
data_addr = (ulong) data->dest;
invalidate_dcache_range(data_addr,
data_addr + data_size);
} else {
pdata->w_buf = calloc(data_size, sizeof(char));
data_addr = (ulong) pdata->w_buf;
memcpy(pdata->w_buf, data->src, data_size);
flush_dcache_range(data_addr, data_addr + data_size);
}
- }
- meson_write(mmc, data_addr, MESON_SD_EMMC_CMD_DAT);
+}
+static void meson_mmc_read_response(struct mmc *mmc, struct mmc_cmd *cmd) +{
- if (cmd->resp_type & MMC_RSP_136) {
cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP3);
cmd->response[1] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP2);
cmd->response[2] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP1);
cmd->response[3] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP);
- } else {
cmd->response[0] = meson_read(mmc, MESON_SD_EMMC_CMD_RSP);
- }
+}
+static int meson_dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
+{
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- struct meson_mmc_platdata *pdata = mmc->priv;
- uint32_t status;
- ulong start;
- int ret = 0;
- /* max block size supported by chip is 512 byte */
- if (data && data->blocksize > 512)
return -EINVAL;
- meson_mmc_setup_cmd(mmc, data, cmd);
- meson_mmc_setup_addr(mmc, data);
- meson_write(mmc, cmd->cmdarg, MESON_SD_EMMC_CMD_ARG);
- /* use 10s timeout */
- start = get_timer(0);
- do {
status = meson_read(mmc, MESON_SD_EMMC_STATUS);
- } while(!(status & STATUS_END_OF_CHAIN) && get_timer(start) < 10000);
- if (!(status & STATUS_END_OF_CHAIN))
ret = -ETIMEDOUT;
- else if (status & STATUS_RESP_TIMEOUT)
ret = -ETIMEDOUT;
- else if (status & STATUS_ERR_MASK)
ret = -EIO;
- meson_mmc_read_response(mmc, cmd);
- if (data && data->flags == MMC_DATA_WRITE)
free(pdata->w_buf);
- /* reset status bits */
- meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS);
- return ret;
+}
+static const struct dm_mmc_ops meson_dm_mmc_ops = {
- .send_cmd = meson_dm_mmc_send_cmd,
- .set_ios = meson_dm_mmc_set_ios,
+};
+static int meson_mmc_ofdata_to_platdata(struct udevice *dev) +{
- struct meson_mmc_platdata *pdata = dev_get_platdata(dev);
- fdt_addr_t addr;
- addr = dev_get_addr(dev);
- if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- pdata->regbase = (void *)addr;
- return 0;
+}
+static int meson_mmc_probe(struct udevice *dev) +{
- struct meson_mmc_platdata *pdata = dev_get_platdata(dev);
- struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
- struct mmc *mmc = &pdata->mmc;
- struct mmc_config *cfg = &pdata->cfg;
- uint32_t val;
- cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
MMC_VDD_31_32 | MMC_VDD_165_195;
- cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
MMC_MODE_HS_52MHz | MMC_MODE_HS;
- cfg->f_min = DIV_ROUND_UP(SD_EMMC_CLKSRC_24M, CLK_MAX_DIV);
- cfg->f_max = 100000000; /* 100 MHz */
- cfg->b_max = 256; /* max 256 blocks */
- cfg->name = dev->name;
- mmc->priv = pdata;
- upriv->mmc = mmc;
- mmc_set_clock(mmc, cfg->f_min);
- /* reset all status bits */
- meson_write(mmc, STATUS_MASK, MESON_SD_EMMC_STATUS);
- /* disable interrupts */
- meson_write(mmc, 0, MESON_SD_EMMC_IRQ_EN);
- /* enable auto clock mode */
- val = meson_read(mmc, MESON_SD_EMMC_CFG);
- val &= ~CFG_SDCLK_ALWAYS_ON;
- val |= CFG_AUTO_CLK;
- meson_write(mmc, val, MESON_SD_EMMC_CFG);
- return 0;
+}
+int meson_mmc_bind(struct udevice *dev) +{
- struct meson_mmc_platdata *pdata = dev_get_platdata(dev);
- return mmc_bind(dev, &pdata->mmc, &pdata->cfg);
+}
+static const struct udevice_id meson_mmc_match[] = {
- { .compatible = "amlogic,meson-gx-mmc" },
- { /* sentinel */ }
+};
+U_BOOT_DRIVER(meson_mmc) = {
- .name = "meson_gx_mmc",
- .id = UCLASS_MMC,
- .of_match = meson_mmc_match,
- .ops = &meson_dm_mmc_ops,
- .probe = meson_mmc_probe,
- .bind = meson_mmc_bind,
- .ofdata_to_platdata = meson_mmc_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct meson_mmc_platdata),
+};

Am 14.04.2017 um 08:22 schrieb Jaehoon Chung:
On 04/13/2017 03:30 AM, Heiner Kallweit wrote:
From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes:
- BLK support added
- general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Thanks guys for all the work on this!
I have tested it successfully on the Odroid-C2.
But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
Regards, Andreas

Am 15.04.2017 um 17:05 schrieb Andreas Färber:
Am 14.04.2017 um 08:22 schrieb Jaehoon Chung:
On 04/13/2017 03:30 AM, Heiner Kallweit wrote:
From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes:
- BLK support added
- general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Thanks guys for all the work on this!
I have tested it successfully on the Odroid-C2.
But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
I'm not familiar with distro boot, but as far as I understand Heinrich's patch it just adds mmc0 and mmc1. Therefore distro boot doesn't try to boot from eMMC.
Rgds, Heiner
Regards, Andreas

On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber:
Am 14.04.2017 um 08:22 schrieb Jaehoon Chung:
On 04/13/2017 03:30 AM, Heiner Kallweit wrote:
From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes:
- BLK support added
- general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Thanks guys for all the work on this!
I have tested it successfully on the Odroid-C2.
But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
I'm not familiar with distro boot, but as far as I understand Heinrich's patch it just adds mmc0 and mmc1. Therefore distro boot doesn't try to boot from eMMC.
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 97a0fc9..a98cd95 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -364,5 +364,6 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) } else { snprintf(devname, sizeof(devname), "%s", path); } +printf("Setting boot device name to '%s'\n", devname); ascii2unicode(bootefi_image_path[0].str, devname); } diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 1e3dca4..f83fa0e 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -207,6 +207,7 @@ static void efi_disk_add_dev(const char *name, if (!desc->lba) return;
+printf("Adding disk device '%s'\n", name); diskobj = calloc(1, objlen);
/* Fill in object data */
Alex

On 04/15/2017 08:27 PM, Alexander Graf wrote:
On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber:
Am 14.04.2017 um 08:22 schrieb Jaehoon Chung:
On 04/13/2017 03:30 AM, Heiner Kallweit wrote:
From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes:
- BLK support added
- general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Thanks guys for all the work on this!
I have tested it successfully on the Odroid-C2.
But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
sd_emmc_a - Wireless SDIO Module sd_emmc_b - SD card sd_emmc_c - eMMC
I'm not familiar with distro boot, but as far as I understand Heinrich's patch it just adds mmc0 and mmc1. Therefore distro boot doesn't try to boot from eMMC.
I will resubmit https://patchwork.ozlabs.org/patch/750859/ odroid-c2: enable MMC as boot target with 3 MMC targets.
I have tested on my Odroid C2 that the fallthrough to DHCP is still working with 3 defined MMC targets.
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
You could enable CONFIG_DISPLAY_BOARDINFO=y CONFIG_CMD_BOOTEFI_HELLO_COMPILE=y
Boardinfo will display the MMC devices detected.
bootefi hello prints the number of disks detected and handed over to the EFI target.
Andreas, please add debug prints like the ones below and check that the device names match:
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 97a0fc9..a98cd95 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -364,5 +364,6 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) } else { snprintf(devname, sizeof(devname), "%s", path); } +printf("Setting boot device name to '%s'\n", devname); ascii2unicode(bootefi_image_path[0].str, devname); } diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 1e3dca4..f83fa0e 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -207,6 +207,7 @@ static void efi_disk_add_dev(const char *name, if (!desc->lba) return;
+printf("Adding disk device '%s'\n", name); diskobj = calloc(1, objlen);
/* Fill in object data */
Alex
Wouldn't it make sense to add Alex's patch to mainline?
Best regards
Heinrich Schuchardt

On 15.04.17 21:13, Heinrich Schuchardt wrote:
On 04/15/2017 08:27 PM, Alexander Graf wrote:
On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber:
Am 14.04.2017 um 08:22 schrieb Jaehoon Chung:
On 04/13/2017 03:30 AM, Heiner Kallweit wrote:
From: Carlo Caione carlo@caione.org This driver implements MMC support on Meson GX (S905) based systems. It's based on Carlo Caione's work, changes:
- BLK support added
- general refactoring
Signed-off-by: Carlo Caione carlo@caione.org Signed-off-by: Andreas Färber afaerber@suse.de Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Thanks guys for all the work on this!
I have tested it successfully on the Odroid-C2.
But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
sd_emmc_a - Wireless SDIO Module sd_emmc_b - SD card sd_emmc_c - eMMC
I'm not familiar with distro boot, but as far as I understand Heinrich's patch it just adds mmc0 and mmc1. Therefore distro boot doesn't try to boot from eMMC.
I will resubmit https://patchwork.ozlabs.org/patch/750859/ odroid-c2: enable MMC as boot target with 3 MMC targets.
I have tested on my Odroid C2 that the fallthrough to DHCP is still working with 3 defined MMC targets.
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
You could enable CONFIG_DISPLAY_BOARDINFO=y CONFIG_CMD_BOOTEFI_HELLO_COMPILE=y
Boardinfo will display the MMC devices detected.
bootefi hello prints the number of disks detected and handed over to the EFI target.
Andreas, please add debug prints like the ones below and check that the device names match:
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 97a0fc9..a98cd95 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -364,5 +364,6 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) } else { snprintf(devname, sizeof(devname), "%s", path); } +printf("Setting boot device name to '%s'\n", devname); ascii2unicode(bootefi_image_path[0].str, devname); } diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 1e3dca4..f83fa0e 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -207,6 +207,7 @@ static void efi_disk_add_dev(const char *name, if (!desc->lba) return;
+printf("Adding disk device '%s'\n", name); diskobj = calloc(1, objlen);
/* Fill in object data */
Alex
Wouldn't it make sense to add Alex's patch to mainline?
You usually don't want these debug messages in a proper u-boot build. Maybe as debug prints.
We really need to simply improve on general debuggability of the efi object model though :). I need to sit down and make grub's "lsefi" just work. Ideally that would give us all the hints we need to find out what's going wrong in situations like this, as it has access to all pieces that we need.
Alex

Am 15.04.2017 um 20:27 schrieb Alexander Graf:
On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber:
But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
[...]
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks Welcome to GRUB!
error: disk `,msdos2' not found. Entering rescue mode... grub rescue>
Regards, Andreas

On 04/15/2017 10:34 PM, Andreas Färber wrote:
Am 15.04.2017 um 20:27 schrieb Alexander Graf:
On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber:
But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
[...]
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks Welcome to GRUB!
error: disk `,msdos2' not found. Entering rescue mode... grub rescue>
Regards, Andreas
What is the output of ls in grub rescue mode?
Best regards
Heinrich

Am 15.04.2017 um 22:52 schrieb Heinrich Schuchardt:
On 04/15/2017 10:34 PM, Andreas Färber wrote:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks Welcome to GRUB!
error: disk `,msdos2' not found. Entering rescue mode... grub rescue>
[...]
What is the output of ls in grub rescue mode?
Entirely empty.
Regards, Andreas

Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de:
Am 15.04.2017 um 20:27 schrieb Alexander Graf:
On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber: But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
[...]
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Alex
Welcome to GRUB!
error: disk `,msdos2' not found. Entering rescue mode... grub rescue>
Regards, Andreas
-- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)

Am 15.04.2017 um 23:04 schrieb Alexander Graf:
Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de:
Am 15.04.2017 um 20:27 schrieb Alexander Graf:
On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber: But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
[...]
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
Regards, Andreas

Am 15.04.2017 um 23:16 schrieb Andreas Färber:
Am 15.04.2017 um 23:04 schrieb Alexander Graf:
Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de:
Am 15.04.2017 um 20:27 schrieb Alexander Graf:
On 15.04.17 20:18, Heiner Kallweit wrote:
Am 15.04.2017 um 17:05 schrieb Andreas Färber: But for the Vega S95 Telos I needed to disable the first of three MMC nodes (SDIO) - otherwise U-Boot would happily iterate over them for distro boot with Heinrich's patch, but GRUB would come up with no disks, so that booting failed. I'm not yet sure why, maybe it's a UEFI-side problem in that it is the first MMC device that is absent rather than the last one?
I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
[...]
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas

On 04/15/2017 11:51 PM, Andreas Färber wrote:
Am 15.04.2017 um 23:16 schrieb Andreas Färber:
Am 15.04.2017 um 23:04 schrieb Alexander Graf:
Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de:
Am 15.04.2017 um 20:27 schrieb Alexander Graf:
On 15.04.17 20:18, Heiner Kallweit wrote: > Am 15.04.2017 um 17:05 schrieb Andreas Färber: > But for the Vega S95 Telos I needed to disable the first of three MMC > nodes (SDIO) - otherwise U-Boot would happily iterate over them for > distro boot with Heinrich's patch, but GRUB would come up with no disks, > so that booting failed. I'm not yet sure why, maybe it's a UEFI-side > problem in that it is the first MMC device that is absent rather than > the last one? > I don't own this device so I can just provide a guess. Based on DT the device ordering most likely is: mmc0: SDIO mmc1: SD mmc2: eMMC
[...]
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas
By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0 - -1 -1 - -1 -1 - -1 -1 - not found set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807 Found 0 disks efi_add_memory_map: 0x7cf52000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf53148 EFI: Entry efi_cout_output_string(000000007ff94b38, 000000007cf53280) Hello, world! EFI: Entry efi_exit(000000007ffa4598, 0, 0, 0000000000000000) ## Application terminated, r = 0
In the debug output you can see that after trying non-existant mmc@70000.blk no further devices are scanned. mmc@72000.blk which has the SD card is not enumerated.
Best regards
Heinrich Schuchardt

On 16.04.17 04:09, Heinrich Schuchardt wrote:
On 04/15/2017 11:51 PM, Andreas Färber wrote:
Am 15.04.2017 um 23:16 schrieb Andreas Färber:
Am 15.04.2017 um 23:04 schrieb Alexander Graf:
Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de:
Am 15.04.2017 um 20:27 schrieb Alexander Graf: > On 15.04.17 20:18, Heiner Kallweit wrote: >> Am 15.04.2017 um 17:05 schrieb Andreas Färber: >> But for the Vega S95 Telos I needed to disable the first of three MMC >> nodes (SDIO) - otherwise U-Boot would happily iterate over them for >> distro boot with Heinrich's patch, but GRUB would come up with no disks, >> so that booting failed. I'm not yet sure why, maybe it's a UEFI-side >> problem in that it is the first MMC device that is absent rather than >> the last one? >> > I don't own this device so I can just provide a guess. > Based on DT the device ordering most likely is: > mmc0: SDIO > mmc1: SD > mmc2: eMMC
[...]
If grub comes up, distro boot has successfully found the target binary and executed it. For some reason, grub can not find its boot origin though.
Andreas, please add debug prints like the ones below and check that the device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas
By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0
- -1 -1
- -1 -1
- -1 -1
- not found
set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807 Found 0 disks efi_add_memory_map: 0x7cf52000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf53148 EFI: Entry efi_cout_output_string(000000007ff94b38, 000000007cf53280) Hello, world! EFI: Entry efi_exit(000000007ffa4598, 0, 0, 0000000000000000) ## Application terminated, r = 0
In the debug output you can see that after trying non-existant mmc@70000.blk no further devices are scanned. mmc@72000.blk which has the SD card is not enumerated.
To me that looks like something wrong with DM code, as there is no explicit abort condition in efi_disk_register() for the CONFIG_BLK case. Let's CC Simon and ask for help :).
Alex

Hi Alex,
On 16 April 2017 at 04:08, Alexander Graf agraf@suse.de wrote:
On 16.04.17 04:09, Heinrich Schuchardt wrote:
On 04/15/2017 11:51 PM, Andreas Färber wrote:
Am 15.04.2017 um 23:16 schrieb Andreas Färber:
Am 15.04.2017 um 23:04 schrieb Alexander Graf:
Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de: > > Am 15.04.2017 um 20:27 schrieb Alexander Graf: >> >> On 15.04.17 20:18, Heiner Kallweit wrote: >>> >>> Am 15.04.2017 um 17:05 schrieb Andreas Färber: >>> But for the Vega S95 Telos I needed to disable the first of three >>> MMC >>> nodes (SDIO) - otherwise U-Boot would happily iterate over them for >>> distro boot with Heinrich's patch, but GRUB would come up with no >>> disks, >>> so that booting failed. I'm not yet sure why, maybe it's a >>> UEFI-side >>> problem in that it is the first MMC device that is absent rather >>> than >>> the last one? >>> >> I don't own this device so I can just provide a guess. >> Based on DT the device ordering most likely is: >> mmc0: SDIO >> mmc1: SD >> mmc2: eMMC
[...] > > If grub comes up, distro boot has successfully found the target > binary > and executed it. For some reason, grub can not find its boot origin > though. > > Andreas, please add debug prints like the ones below and check that > the > device names match:
U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 43 ms (460.9 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 13 ms (9.5 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1807 Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas
By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0
- -1 -1
- -1 -1
- -1 -1
- not found
set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807 Found 0 disks efi_add_memory_map: 0x7cf52000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf53148 EFI: Entry efi_cout_output_string(000000007ff94b38, 000000007cf53280) Hello, world! EFI: Entry efi_exit(000000007ffa4598, 0, 0, 0000000000000000) ## Application terminated, r = 0
In the debug output you can see that after trying non-existant mmc@70000.blk no further devices are scanned. mmc@72000.blk which has the SD card is not enumerated.
To me that looks like something wrong with DM code, as there is no explicit abort condition in efi_disk_register() for the CONFIG_BLK case. Let's CC Simon and ask for help :).
Reviewed-by: Simon Glass sjg@chromium.org
Do you have a board that uses CONFIG_BLK?
Or could we enhance my helloworld test to check the test? I really don't like having to run grub to find bugs :-)
Regards, Simon

On 04/16/2017 09:34 PM, Simon Glass wrote:
Hi Alex,
On 16 April 2017 at 04:08, Alexander Graf agraf@suse.de wrote:
On 16.04.17 04:09, Heinrich Schuchardt wrote:
On 04/15/2017 11:51 PM, Andreas Färber wrote:
Am 15.04.2017 um 23:16 schrieb Andreas Färber:
Am 15.04.2017 um 23:04 schrieb Alexander Graf:
> > Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de: >> >> Am 15.04.2017 um 20:27 schrieb Alexander Graf: >>> >>> On 15.04.17 20:18, Heiner Kallweit wrote: >>>> >>>> Am 15.04.2017 um 17:05 schrieb Andreas Färber: >>>> But for the Vega S95 Telos I needed to disable the first of three >>>> MMC >>>> nodes (SDIO) - otherwise U-Boot would happily iterate over them for >>>> distro boot with Heinrich's patch, but GRUB would come up with no >>>> disks, >>>> so that booting failed. I'm not yet sure why, maybe it's a >>>> UEFI-side >>>> problem in that it is the first MMC device that is absent rather >>>> than >>>> the last one? >>>> >>> I don't own this device so I can just provide a guess. >>> Based on DT the device ordering most likely is: >>> mmc0: SDIO >>> mmc1: SD >>> mmc2: eMMC > > [...] >> >> If grub comes up, distro boot has successfully found the target >> binary >> and executed it. For some reason, grub can not find its boot origin >> though. >> >> Andreas, please add debug prints like the ones below and check that >> the >> device names match: > > > U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) > vega-s95 > > DRAM: 2 GiB > MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 > Using default environment > > In: serial@4c0 > Out: serial@4c0 > Err: serial@4c0 > Net: eth0: ethernet@c9410000 > Hit any key to stop autoboot: 0 > mmc_init: -95, time 1806 > MMC Device 0 not found > no mmc device at slot 0 > switch to partitions #0, OK > mmc1 is current device > Scanning mmc 1:1... > Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' > 20335 bytes read in 43 ms (460.9 KiB/s) > Found EFI removable media binary efi/boot/bootaa64.efi > Setting boot device name to '/efi/boot/bootaa64.efi' > reading efi/boot/bootaa64.efi > 129024 bytes read in 13 ms (9.5 MiB/s) > ## Starting EFI application at 01080000 ... > mmc_init: -95, time 1807 > Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas
By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0
- -1 -1
- -1 -1
- -1 -1
- not found
set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807 Found 0 disks efi_add_memory_map: 0x7cf52000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf53148 EFI: Entry efi_cout_output_string(000000007ff94b38, 000000007cf53280) Hello, world! EFI: Entry efi_exit(000000007ffa4598, 0, 0, 0000000000000000) ## Application terminated, r = 0
In the debug output you can see that after trying non-existant mmc@70000.blk no further devices are scanned. mmc@72000.blk which has the SD card is not enumerated.
To me that looks like something wrong with DM code, as there is no explicit abort condition in efi_disk_register() for the CONFIG_BLK case. Let's CC Simon and ask for help :).
Reviewed-by: Simon Glass sjg@chromium.org
Do you have a board that uses CONFIG_BLK?
make odroid-c2_defconfig results in CONFIG_BLK=y
Or could we enhance my helloworld test to check the test? I really don't like having to run grub to find bugs :-)
The current debug output is sufficient to demonstrate that the MMC devices are not correctly enumerated for bootefi if the first device cannot be probed.
Regards
Heinrich Schuchardt

On 04/18/2017 06:18 AM, Heinrich Schuchardt wrote:
On 04/16/2017 09:34 PM, Simon Glass wrote:
Hi Alex,
On 16 April 2017 at 04:08, Alexander Graf agraf@suse.de wrote:
On 16.04.17 04:09, Heinrich Schuchardt wrote:
On 04/15/2017 11:51 PM, Andreas Färber wrote:
Am 15.04.2017 um 23:16 schrieb Andreas Färber:
Am 15.04.2017 um 23:04 schrieb Alexander Graf: >> >> Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de: >>> >>> Am 15.04.2017 um 20:27 schrieb Alexander Graf: >>>> >>>> On 15.04.17 20:18, Heiner Kallweit wrote: >>>>> >>>>> Am 15.04.2017 um 17:05 schrieb Andreas Färber: >>>>> But for the Vega S95 Telos I needed to disable the first of three >>>>> MMC >>>>> nodes (SDIO) - otherwise U-Boot would happily iterate over them for >>>>> distro boot with Heinrich's patch, but GRUB would come up with no >>>>> disks, >>>>> so that booting failed. I'm not yet sure why, maybe it's a >>>>> UEFI-side >>>>> problem in that it is the first MMC device that is absent rather >>>>> than >>>>> the last one? >>>>> >>>> I don't own this device so I can just provide a guess. >>>> Based on DT the device ordering most likely is: >>>> mmc0: SDIO >>>> mmc1: SD >>>> mmc2: eMMC >> >> [...] >>> >>> If grub comes up, distro boot has successfully found the target >>> binary >>> and executed it. For some reason, grub can not find its boot origin >>> though. >>> >>> Andreas, please add debug prints like the ones below and check that >>> the >>> device names match: >> >> >> U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) >> vega-s95 >> >> DRAM: 2 GiB >> MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 >> Using default environment >> >> In: serial@4c0 >> Out: serial@4c0 >> Err: serial@4c0 >> Net: eth0: ethernet@c9410000 >> Hit any key to stop autoboot: 0 >> mmc_init: -95, time 1806 >> MMC Device 0 not found >> no mmc device at slot 0 >> switch to partitions #0, OK >> mmc1 is current device >> Scanning mmc 1:1... >> Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' >> 20335 bytes read in 43 ms (460.9 KiB/s) >> Found EFI removable media binary efi/boot/bootaa64.efi >> Setting boot device name to '/efi/boot/bootaa64.efi' >> reading efi/boot/bootaa64.efi >> 129024 bytes read in 13 ms (9.5 MiB/s) >> ## Starting EFI application at 01080000 ... >> mmc_init: -95, time 1807 >> Found 0 disks > > > That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas
By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0
- -1 -1
- -1 -1
- -1 -1
- not found
set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807
This error number is "EOPNOTSUPP". Is "cfg->voltages" correct in meson_gx_mmc.c?
Found 0 disks efi_add_memory_map: 0x7cf52000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf53148 EFI: Entry efi_cout_output_string(000000007ff94b38, 000000007cf53280) Hello, world! EFI: Entry efi_exit(000000007ffa4598, 0, 0, 0000000000000000) ## Application terminated, r = 0
In the debug output you can see that after trying non-existant mmc@70000.blk no further devices are scanned. mmc@72000.blk which has the SD card is not enumerated.
To me that looks like something wrong with DM code, as there is no explicit abort condition in efi_disk_register() for the CONFIG_BLK case. Let's CC Simon and ask for help :).
Reviewed-by: Simon Glass sjg@chromium.org
Do you have a board that uses CONFIG_BLK?
make odroid-c2_defconfig results in CONFIG_BLK=y
Or could we enhance my helloworld test to check the test? I really don't like having to run grub to find bugs :-)
The current debug output is sufficient to demonstrate that the MMC devices are not correctly enumerated for bootefi if the first device cannot be probed.
Regards
Heinrich Schuchardt

Hi,
On 17 April 2017 at 16:39, Jaehoon Chung jh80.chung@samsung.com wrote:
On 04/18/2017 06:18 AM, Heinrich Schuchardt wrote:
On 04/16/2017 09:34 PM, Simon Glass wrote:
Hi Alex,
On 16 April 2017 at 04:08, Alexander Graf agraf@suse.de wrote:
On 16.04.17 04:09, Heinrich Schuchardt wrote:
On 04/15/2017 11:51 PM, Andreas Färber wrote:
Am 15.04.2017 um 23:16 schrieb Andreas Färber: > > Am 15.04.2017 um 23:04 schrieb Alexander Graf: >>> >>> Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de: >>>> >>>> Am 15.04.2017 um 20:27 schrieb Alexander Graf: >>>>> >>>>> On 15.04.17 20:18, Heiner Kallweit wrote: >>>>>> >>>>>> Am 15.04.2017 um 17:05 schrieb Andreas Färber: >>>>>> But for the Vega S95 Telos I needed to disable the first of three >>>>>> MMC >>>>>> nodes (SDIO) - otherwise U-Boot would happily iterate over them for >>>>>> distro boot with Heinrich's patch, but GRUB would come up with no >>>>>> disks, >>>>>> so that booting failed. I'm not yet sure why, maybe it's a >>>>>> UEFI-side >>>>>> problem in that it is the first MMC device that is absent rather >>>>>> than >>>>>> the last one? >>>>>> >>>>> I don't own this device so I can just provide a guess. >>>>> Based on DT the device ordering most likely is: >>>>> mmc0: SDIO >>>>> mmc1: SD >>>>> mmc2: eMMC >>> >>> [...] >>>> >>>> If grub comes up, distro boot has successfully found the target >>>> binary >>>> and executed it. For some reason, grub can not find its boot origin >>>> though. >>>> >>>> Andreas, please add debug prints like the ones below and check that >>>> the >>>> device names match: >>> >>> >>> U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) >>> vega-s95 >>> >>> DRAM: 2 GiB >>> MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 >>> Using default environment >>> >>> In: serial@4c0 >>> Out: serial@4c0 >>> Err: serial@4c0 >>> Net: eth0: ethernet@c9410000 >>> Hit any key to stop autoboot: 0 >>> mmc_init: -95, time 1806 >>> MMC Device 0 not found >>> no mmc device at slot 0 >>> switch to partitions #0, OK >>> mmc1 is current device >>> Scanning mmc 1:1... >>> Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' >>> 20335 bytes read in 43 ms (460.9 KiB/s) >>> Found EFI removable media binary efi/boot/bootaa64.efi >>> Setting boot device name to '/efi/boot/bootaa64.efi' >>> reading efi/boot/bootaa64.efi >>> 129024 bytes read in 13 ms (9.5 MiB/s) >>> ## Starting EFI application at 01080000 ... >>> mmc_init: -95, time 1807 >>> Found 0 disks >> >> >> That looks like efi_disk didn't manage to enumerate any devices? > > > Apparently. The last line comes from > lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you > can see, there is not a single "Scanning disk" line, so I guess we do > not iterate over uclass devices properly? > > On the Odroid-C2 I get this: > > Scanning disk mmc@72000.blk... > Card did not respond to voltage select! > mmc_init: -95, time 9 > Found 1 disks > > Therefore my guess that it matters at what point in time - before or > after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas
By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0
- -1 -1
- -1 -1
- -1 -1
- not found
set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807
This error number is "EOPNOTSUPP". Is "cfg->voltages" correct in meson_gx_mmc.c?
Or it could just be that there is no card inserted? See mmc_start_init(). It would be good to update mmc.c to return different errors for the different cases.
Regards, Simon

On 04/24/2017 12:38 PM, Simon Glass wrote:
Hi,
On 17 April 2017 at 16:39, Jaehoon Chung jh80.chung@samsung.com wrote:
On 04/18/2017 06:18 AM, Heinrich Schuchardt wrote:
On 04/16/2017 09:34 PM, Simon Glass wrote:
Hi Alex,
On 16 April 2017 at 04:08, Alexander Graf agraf@suse.de wrote:
On 16.04.17 04:09, Heinrich Schuchardt wrote:
On 04/15/2017 11:51 PM, Andreas Färber wrote: > > Am 15.04.2017 um 23:16 schrieb Andreas Färber: >> >> Am 15.04.2017 um 23:04 schrieb Alexander Graf: >>>> >>>> Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de: >>>>> >>>>> Am 15.04.2017 um 20:27 schrieb Alexander Graf: >>>>>> >>>>>> On 15.04.17 20:18, Heiner Kallweit wrote: >>>>>>> >>>>>>> Am 15.04.2017 um 17:05 schrieb Andreas Färber: >>>>>>> But for the Vega S95 Telos I needed to disable the first of three >>>>>>> MMC >>>>>>> nodes (SDIO) - otherwise U-Boot would happily iterate over them for >>>>>>> distro boot with Heinrich's patch, but GRUB would come up with no >>>>>>> disks, >>>>>>> so that booting failed. I'm not yet sure why, maybe it's a >>>>>>> UEFI-side >>>>>>> problem in that it is the first MMC device that is absent rather >>>>>>> than >>>>>>> the last one? >>>>>>> >>>>>> I don't own this device so I can just provide a guess. >>>>>> Based on DT the device ordering most likely is: >>>>>> mmc0: SDIO >>>>>> mmc1: SD >>>>>> mmc2: eMMC >>>> >>>> [...] >>>>> >>>>> If grub comes up, distro boot has successfully found the target >>>>> binary >>>>> and executed it. For some reason, grub can not find its boot origin >>>>> though. >>>>> >>>>> Andreas, please add debug prints like the ones below and check that >>>>> the >>>>> device names match: >>>> >>>> >>>> U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) >>>> vega-s95 >>>> >>>> DRAM: 2 GiB >>>> MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 >>>> Using default environment >>>> >>>> In: serial@4c0 >>>> Out: serial@4c0 >>>> Err: serial@4c0 >>>> Net: eth0: ethernet@c9410000 >>>> Hit any key to stop autoboot: 0 >>>> mmc_init: -95, time 1806 >>>> MMC Device 0 not found >>>> no mmc device at slot 0 >>>> switch to partitions #0, OK >>>> mmc1 is current device >>>> Scanning mmc 1:1... >>>> Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' >>>> 20335 bytes read in 43 ms (460.9 KiB/s) >>>> Found EFI removable media binary efi/boot/bootaa64.efi >>>> Setting boot device name to '/efi/boot/bootaa64.efi' >>>> reading efi/boot/bootaa64.efi >>>> 129024 bytes read in 13 ms (9.5 MiB/s) >>>> ## Starting EFI application at 01080000 ... >>>> mmc_init: -95, time 1807 >>>> Found 0 disks >>> >>> >>> That looks like efi_disk didn't manage to enumerate any devices? >> >> >> Apparently. The last line comes from >> lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you >> can see, there is not a single "Scanning disk" line, so I guess we do >> not iterate over uclass devices properly? >> >> On the Odroid-C2 I get this: >> >> Scanning disk mmc@72000.blk... >> Card did not respond to voltage select! >> mmc_init: -95, time 9 >> Found 1 disks >> >> Therefore my guess that it matters at what point in time - before or >> after the disk we want - the error accessing an MMC device happens. > > > For comparison, Vega S95 with first MMC node disabled in DT: > > Scanning disk mmc@72000.blk... > Adding disk device 'mmc@72000.blk' > ** First descriptor is NOT a primary desc on 1:1 ** > Scanning disk mmc@74000.blk... > Adding disk device 'mmc@74000.blk' > Found 2 disks > > Regards, > Andreas > By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0
- -1 -1
- -1 -1
- -1 -1
- not found
set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807
This error number is "EOPNOTSUPP". Is "cfg->voltages" correct in meson_gx_mmc.c?
Or it could just be that there is no card inserted? See mmc_start_init(). It would be good to update mmc.c to return different errors for the different cases.
Right..Will update.
Regards, Simon

Hi Alex,
On 16 April 2017 at 13:34, Simon Glass sjg@chromium.org wrote:
Hi Alex,
On 16 April 2017 at 04:08, Alexander Graf agraf@suse.de wrote:
On 16.04.17 04:09, Heinrich Schuchardt wrote:
On 04/15/2017 11:51 PM, Andreas Färber wrote:
Am 15.04.2017 um 23:16 schrieb Andreas Färber:
Am 15.04.2017 um 23:04 schrieb Alexander Graf:
> > Am 15.04.2017 um 22:34 schrieb Andreas Färber afaerber@suse.de: >> >> Am 15.04.2017 um 20:27 schrieb Alexander Graf: >>> >>> On 15.04.17 20:18, Heiner Kallweit wrote: >>>> >>>> Am 15.04.2017 um 17:05 schrieb Andreas Färber: >>>> But for the Vega S95 Telos I needed to disable the first of three >>>> MMC >>>> nodes (SDIO) - otherwise U-Boot would happily iterate over them for >>>> distro boot with Heinrich's patch, but GRUB would come up with no >>>> disks, >>>> so that booting failed. I'm not yet sure why, maybe it's a >>>> UEFI-side >>>> problem in that it is the first MMC device that is absent rather >>>> than >>>> the last one? >>>> >>> I don't own this device so I can just provide a guess. >>> Based on DT the device ordering most likely is: >>> mmc0: SDIO >>> mmc1: SD >>> mmc2: eMMC > > [...] >> >> If grub comes up, distro boot has successfully found the target >> binary >> and executed it. For some reason, grub can not find its boot origin >> though. >> >> Andreas, please add debug prints like the ones below and check that >> the >> device names match: > > > U-Boot 2017.05-rc1-00318-g082535f-dirty (Apr 15 2017 - 22:29:17 +0200) > vega-s95 > > DRAM: 2 GiB > MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 > Using default environment > > In: serial@4c0 > Out: serial@4c0 > Err: serial@4c0 > Net: eth0: ethernet@c9410000 > Hit any key to stop autoboot: 0 > mmc_init: -95, time 1806 > MMC Device 0 not found > no mmc device at slot 0 > switch to partitions #0, OK > mmc1 is current device > Scanning mmc 1:1... > Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' > 20335 bytes read in 43 ms (460.9 KiB/s) > Found EFI removable media binary efi/boot/bootaa64.efi > Setting boot device name to '/efi/boot/bootaa64.efi' > reading efi/boot/bootaa64.efi > 129024 bytes read in 13 ms (9.5 MiB/s) > ## Starting EFI application at 01080000 ... > mmc_init: -95, time 1807 > Found 0 disks
That looks like efi_disk didn't manage to enumerate any devices?
Apparently. The last line comes from lib/efi_loader_efi_disk:efi_disk_register(), and CONFIG_BLK=y. As you can see, there is not a single "Scanning disk" line, so I guess we do not iterate over uclass devices properly?
On the Odroid-C2 I get this:
Scanning disk mmc@72000.blk... Card did not respond to voltage select! mmc_init: -95, time 9 Found 1 disks
Therefore my guess that it matters at what point in time - before or after the disk we want - the error accessing an MMC device happens.
For comparison, Vega S95 with first MMC node disabled in DT:
Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 1:1 ** Scanning disk mmc@74000.blk... Adding disk device 'mmc@74000.blk' Found 2 disks
Regards, Andreas
By adding sd_mmc_a to the odroid-c2.dts I was able to reproduce the problem on the Odroid C2.
While booting from SD card via booti still worked bootefi would not find any block device:
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf53000 0x1 2 yes uclass_find_device_by_seq: 0 -1 uclass_find_device_by_seq: 0 0
- -1 -1
- -1 -1
- -1 -1
- not found
set_state_simple op missing blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_init: -95, time 1807 Found 0 disks efi_add_memory_map: 0x7cf52000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf53148 EFI: Entry efi_cout_output_string(000000007ff94b38, 000000007cf53280) Hello, world! EFI: Entry efi_exit(000000007ffa4598, 0, 0, 0000000000000000) ## Application terminated, r = 0
In the debug output you can see that after trying non-existant mmc@70000.blk no further devices are scanned. mmc@72000.blk which has the SD card is not enumerated.
To me that looks like something wrong with DM code, as there is no explicit abort condition in efi_disk_register() for the CONFIG_BLK case. Let's CC Simon and ask for help :).
Reviewed-by: Simon Glass sjg@chromium.org
Do you have a board that uses CONFIG_BLK?
Or could we enhance my helloworld test to check the test? I really don't like having to run grub to find bugs :-)
Any thoughts on this one?
Regards, Simon

Set devp even if probing fails.
Without the patch the following problem occurs: If the first block device is not probed successfully no block device is passed by bootefi to the EFI executable.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
Reported-by: Andreas Färber afaerber@suse.de Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- drivers/core/uclass.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 04fb45b..b647384 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -349,12 +349,13 @@ int uclass_get_device_tail(struct udevice *dev, int ret, return ret;
assert(dev); + + *devp = dev; + ret = device_probe(dev); if (ret) return ret;
- *devp = dev; - return 0; }

Hi,
On 18 April 2017 at 12:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Set devp even if probing fails.
Without the patch the following problem occurs: If the first block device is not probed successfully no block device is passed by bootefi to the EFI executable.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
Thanks for finding this. Which function is calling this? Can you please explain the call sequence to hit this problem? I am worried that something else is wrong.
Reported-by: Andreas Färber afaerber@suse.de Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
drivers/core/uclass.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 04fb45b..b647384 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -349,12 +349,13 @@ int uclass_get_device_tail(struct udevice *dev, int ret, return ret;
assert(dev);
*devp = dev;
ret = device_probe(dev); if (ret) return ret;
*devp = dev;
return 0;
}
-- 2.1.4
Regards, Simon

Hi Simon,
Am 19.04.2017 um 02:12 schrieb Simon Glass:
On 18 April 2017 at 12:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Set devp even if probing fails.
Without the patch the following problem occurs: If the first block device is not probed successfully no block device is passed by bootefi to the EFI executable.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
Thanks for finding this. Which function is calling this? Can you please explain the call sequence to hit this problem? I am worried that something else is wrong.
It is lib/efi_loader/efi_disk.c:efi_disk_register() that is calling uclass_first_device() and uclass_next_device(). Based on the output we had concluded that uclass_first_device() fails already - therefore Alex CC'ed you.
Unfortunately I find the function interactions inside uclass.c rather complex and unintuitive, so I am truely amazed at Heinrich's findings. (Passing the ret code from one function to the next just to return?!)
Based on his patch we can assume that uclass_find_first_device() set dev to a non-NULL value, otherwise we wouldn't end up in uclass_get_device_tail().
So if you're saying this patch is wrong, then that would leave device_probe(). The actual meson_mmc_probe() function you had given a late Reviewed-by, and it always returns 0.
Jaehoon had asked about cfg->voltages in meson_mmc_probe(), but I don't see how that would lead to probe failure here? Whether the values are correct I have no idea.
The error message "mmc_init: -95, time 1807", which appears to be a result of this iteration/probe process, comes from drivers/mmc/mmc.c:mmc_init(), which is called from mmc-uclass.c:mmc_blk_probe(). mmc_init() calls mmc_start_init(), which returns this -EOPNOTSUPP if sd_send_op_cond return -ETIMEDOUT and mmc_send_op_cond() failed. However, our output does not show "Card did not respond to voltage select!", which it should in that case. So the error must be coming from elsewhere. sd_send_op_cond() may return -EOPNOTSUPP through mmc_start_init(), and so does mmc_complete_op_cond() through mmc_complete_init(). I would expect either to fail, as in my case it's an SDIO, and in Heinrich's case it's not connected to anything. So I don't think MMC is at fault here.
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arc...
See sd_mmc_a, which uses an mmc-pwrseq that depends on a pwm-clock, neither of which have any support in U-Boot, nor is it actually needed for booting.
In any case, failure to probe one device should not break the iteration of other devices. I.e., if a device fails to probe then instead of returning from uclass_{first,next}_device() we should look at the next device until we find one that's okay or have reached the end of the list. How to best implement that in uclass.c I'm less sure of.
If I am right you could test this on any board with multiple, e.g., blk devices where a first or non-last device returns an error code from its probe, i.e. try changing return 0 in some probe function based on a static variable not yet being initialized or something. Probably you could even write some tiny sandbox based test, without actual hardware.
IIUC this patch changes behavior from iterating over no devices to iterating over all devices including ones not probed successfully? And what you intended was to instead iterate over only the probed devices?
Regards, Andreas

Hi,
On 18 April 2017 at 21:03, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 02:12 schrieb Simon Glass:
On 18 April 2017 at 12:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Set devp even if probing fails.
Without the patch the following problem occurs: If the first block device is not probed successfully no block device is passed by bootefi to the EFI executable.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
Thanks for finding this. Which function is calling this? Can you please explain the call sequence to hit this problem? I am worried that something else is wrong.
It is lib/efi_loader/efi_disk.c:efi_disk_register() that is calling uclass_first_device() and uclass_next_device(). Based on the output we had concluded that uclass_first_device() fails already - therefore Alex CC'ed you.
Unfortunately I find the function interactions inside uclass.c rather complex and unintuitive, so I am truely amazed at Heinrich's findings. (Passing the ret code from one function to the next just to return?!)
Based on his patch we can assume that uclass_find_first_device() set dev to a non-NULL value, otherwise we wouldn't end up in uclass_get_device_tail().
So if you're saying this patch is wrong, then that would leave device_probe(). The actual meson_mmc_probe() function you had given a late Reviewed-by, and it always returns 0.
Jaehoon had asked about cfg->voltages in meson_mmc_probe(), but I don't see how that would lead to probe failure here? Whether the values are correct I have no idea.
The error message "mmc_init: -95, time 1807", which appears to be a result of this iteration/probe process, comes from drivers/mmc/mmc.c:mmc_init(), which is called from mmc-uclass.c:mmc_blk_probe(). mmc_init() calls mmc_start_init(), which returns this -EOPNOTSUPP if sd_send_op_cond return -ETIMEDOUT and mmc_send_op_cond() failed. However, our output does not show "Card did not respond to voltage select!", which it should in that case. So the error must be coming from elsewhere. sd_send_op_cond() may return -EOPNOTSUPP through mmc_start_init(), and so does mmc_complete_op_cond() through mmc_complete_init(). I would expect either to fail, as in my case it's an SDIO, and in Heinrich's case it's not connected to anything. So I don't think MMC is at fault here.
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arc...
See sd_mmc_a, which uses an mmc-pwrseq that depends on a pwm-clock, neither of which have any support in U-Boot, nor is it actually needed for booting.
In any case, failure to probe one device should not break the iteration of other devices. I.e., if a device fails to probe then instead of returning from uclass_{first,next}_device() we should look at the next device until we find one that's okay or have reached the end of the list. How to best implement that in uclass.c I'm less sure of.
If I am right you could test this on any board with multiple, e.g., blk devices where a first or non-last device returns an error code from its probe, i.e. try changing return 0 in some probe function based on a static variable not yet being initialized or something. Probably you could even write some tiny sandbox based test, without actual hardware.
IIUC this patch changes behavior from iterating over no devices to iterating over all devices including ones not probed successfully? And what you intended was to instead iterate over only the probed devices?
I think this is a genuine bug, but exactly where is less obvious.
The uclass function don't return a device if they get an error. So at present you need to iterate through the uclass if the intention is to continue after error. That would be uclass_foreach_dev(). But before using the device, device_probe() needs to be called since the iteration does not probe it automatically. That is why people normally use uclass_first/next_device(), since it probes as it goes.
However in this case I think it is reasonable to change uclass_first/next_device() to always return the device, even on error. That can best be done by changing those functions rather than uclass_get_device_tail(), which is shared by many functions. We should not change uclass_get_device_tail() since what is does is correct for all other uses (I think).
In that case, the function comments for the first/next functions should be updated to indicate the new behaviour, and a test created, perhaps in test/dm/core.c.
You were asking about uclass_get_device_tail(). This is common code and is put into a function to ensure consistent behaviour across all functions that return an error code and a device. Consistency is very important with driver model since things can get version confusing when something odd happens in the bowels of the system, as this bug has shown.
Regards, Simon

On 04/19/2017 05:37 AM, Simon Glass wrote:
Hi,
On 18 April 2017 at 21:03, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 02:12 schrieb Simon Glass:
On 18 April 2017 at 12:44, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
Set devp even if probing fails.
Without the patch the following problem occurs: If the first block device is not probed successfully no block device is passed by bootefi to the EFI executable.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
Thanks for finding this. Which function is calling this? Can you please explain the call sequence to hit this problem? I am worried that something else is wrong.
It is lib/efi_loader/efi_disk.c:efi_disk_register() that is calling uclass_first_device() and uclass_next_device(). Based on the output we had concluded that uclass_first_device() fails already - therefore Alex CC'ed you.
Unfortunately I find the function interactions inside uclass.c rather complex and unintuitive, so I am truely amazed at Heinrich's findings. (Passing the ret code from one function to the next just to return?!)
Based on his patch we can assume that uclass_find_first_device() set dev to a non-NULL value, otherwise we wouldn't end up in uclass_get_device_tail().
So if you're saying this patch is wrong, then that would leave device_probe(). The actual meson_mmc_probe() function you had given a late Reviewed-by, and it always returns 0.
Jaehoon had asked about cfg->voltages in meson_mmc_probe(), but I don't see how that would lead to probe failure here? Whether the values are correct I have no idea.
The error message "mmc_init: -95, time 1807", which appears to be a result of this iteration/probe process, comes from drivers/mmc/mmc.c:mmc_init(), which is called from mmc-uclass.c:mmc_blk_probe(). mmc_init() calls mmc_start_init(), which returns this -EOPNOTSUPP if sd_send_op_cond return -ETIMEDOUT and mmc_send_op_cond() failed. However, our output does not show "Card did not respond to voltage select!", which it should in that case. So the error must be coming from elsewhere. sd_send_op_cond() may return -EOPNOTSUPP through mmc_start_init(), and so does mmc_complete_op_cond() through mmc_complete_init(). I would expect either to fail, as in my case it's an SDIO, and in Heinrich's case it's not connected to anything. So I don't think MMC is at fault here.
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/arc...
See sd_mmc_a, which uses an mmc-pwrseq that depends on a pwm-clock, neither of which have any support in U-Boot, nor is it actually needed for booting.
In any case, failure to probe one device should not break the iteration of other devices. I.e., if a device fails to probe then instead of returning from uclass_{first,next}_device() we should look at the next device until we find one that's okay or have reached the end of the list. How to best implement that in uclass.c I'm less sure of.
If I am right you could test this on any board with multiple, e.g., blk devices where a first or non-last device returns an error code from its probe, i.e. try changing return 0 in some probe function based on a static variable not yet being initialized or something. Probably you could even write some tiny sandbox based test, without actual hardware.
IIUC this patch changes behavior from iterating over no devices to iterating over all devices including ones not probed successfully? And what you intended was to instead iterate over only the probed devices?
I think this is a genuine bug, but exactly where is less obvious.
The uclass function don't return a device if they get an error. So at present you need to iterate through the uclass if the intention is to continue after error. That would be uclass_foreach_dev(). But before using the device, device_probe() needs to be called since the iteration does not probe it automatically. That is why people normally use uclass_first/next_device(), since it probes as it goes.
However in this case I think it is reasonable to change uclass_first/next_device() to always return the device, even on error. That can best be done by changing those functions rather than uclass_get_device_tail(), which is shared by many functions. We should not change uclass_get_device_tail() since what is does is correct for all other uses (I think).
In that case, the function comments for the first/next functions should be updated to indicate the new behaviour, and a test created, perhaps in test/dm/core.c.
You were asking about uclass_get_device_tail(). This is common code and is put into a function to ensure consistent behaviour across all functions that return an error code and a device. Consistency is very important with driver model since things can get version confusing when something odd happens in the bowels of the system, as this bug has shown.
Regards, Simon
Thank you Simon for reviewing. I will try to rework the patch.
For reference I append the debug output with and without the current patch. This should make the call sequence clear.
In uclass_first_device: id 12 12 refers to UCLASS_BLK.
Best regards
Heinrich Schuchardt
Without [PATCH 1/1] core/uclass: uclass_get_device_tail: always set devp
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf50000 0x1 2 yes efi_disk_register uclass_first_device: id 12 uclass_find_first_device: id 12 uclass_get_device_tail: ret 0 uclass_resolve_seq: uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq -1, find_req_seq 0 uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq 0, find_req_seq 0 mmc@70000.blk - -1 -1 mmc@72000.blk - -1 -1 mmc@74000.blk - -1 -1 - not found uclass_get_device: id 41, index 0 uclass_get_device_tail: ret 0 set_state_simple op missing find_mmc_device: dev_num 0 blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_blk_probe mmc_init: -95, time 1807 Found 0 disks uclass_first_device: id 18 uclass_find_first_device: id 18 uclass_get_device_tail: ret 0 efi_add_memory_map: 0x7cf4f000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf50148 EFI: Entry efi_cout_output_string(000000007ff93ac0, 000000007cf50274) Hello, world! EFI: Entry efi_exit(000000007ffa47d0, 0, 0, 0000000000000000) ## Application terminated, r = 0 =>
With [PATCH 1/1] core/uclass: uclass_get_device_tail: always set devp
=> bootefi hello ## Starting EFI application at 01000000 ... WARNING: Invalid device tree, expect boot to fail efi_add_memory_map: 0x7cf50000 0x1 2 yes efi_disk_register uclass_first_device: id 12 uclass_find_first_device: id 12 uclass_get_device_tail: ret 0 uclass_resolve_seq: uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq -1, find_req_seq 0 uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq 0, find_req_seq 0 mmc@70000.blk - -1 -1 mmc@72000.blk - -1 0 - found uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq 1, find_req_seq 0 mmc@70000.blk - -1 -1 mmc@72000.blk - -1 0 mmc@74000.blk - -1 -1 - not found uclass_get_device: id 41, index 0 uclass_get_device_tail: ret 0 set_state_simple op missing find_mmc_device: dev_num 0 blk_get_device: if_type=6, devnum=0: mmc@70000.blk, 6, 0 mmc_blk_probe mmc_init: -95, time 1806 Scanning disk mmc@70000.blk... uclass_next_device: uclass_find_next_device: uclass_get_device_tail: ret 0 Scanning disk mmc@72000.blk... Adding disk device 'mmc@72000.blk' uclass_next_device: uclass_find_next_device: uclass_get_device_tail: ret 0 uclass_resolve_seq: uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq -1, find_req_seq 0 uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq 0, find_req_seq 0 mmc@70000.blk - -1 -1 mmc@72000.blk - -1 0 - found uclass_find_device_by_seq: uclass_id 0, seq_or_req_seq 1, find_req_seq 0 mmc@70000.blk - -1 -1 mmc@72000.blk - -1 0 mmc@74000.blk - -1 -1 - not found uclass_get_device: id 41, index 0 uclass_get_device_tail: ret 0 set_state_simple op missing find_mmc_device: dev_num 2 blk_get_device: if_type=6, devnum=2: mmc@70000.blk, 6, 0 blk_get_device: if_type=6, devnum=2: mmc@72000.blk, 6, 1 blk_get_device: if_type=6, devnum=2: mmc@74000.blk, 6, 2 mmc_blk_probe Card did not respond to voltage select! mmc_init: -95, time 10 Scanning disk mmc@74000.blk... uclass_next_device: uclass_find_next_device: Found 3 disks efi_add_memory_map: 0x7cf4f000 0x1 6 yes do_bootefi_exec:234 Jumping to 0x7cf50148 EFI: Entry efi_cout_output_string(000000007ff93ad0, 000000007cf50274) Hello, world! EFI: Entry efi_exit(000000007ffa47e0, 0, 0, 0000000000000000) ## Application terminated, r = 0 =>

When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html --- drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 04fb45b..cff3a3f 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -420,16 +420,30 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent, } #endif
+/** + * uclass_first_device() - Finds first device of an uclass that can be probed + * @id: uclass id + * @devp: device found or NULL + * @return always 0 + * + * For iterating over all devices of an uclass use + * for(uclass_first_device(id, &dev); dev; uclass_next_device(&dev)). + */ int uclass_first_device(enum uclass_id id, struct udevice **devp) { struct udevice *dev; - int ret;
*devp = NULL; - ret = uclass_find_first_device(id, &dev); - if (!dev) - return 0; - return uclass_get_device_tail(dev, ret, devp); + for (uclass_find_first_device(id, &dev); dev; + uclass_find_next_device(&dev)) { + + uclass_get_device_tail(dev, 0, devp); + if (*devp) + break; + } + debug("%s(%d): %s\n", __func__, id, dev ? dev->name : "(EOL)"); + + return 0; }
int uclass_first_device_err(enum uclass_id id, struct udevice **devp) @@ -445,16 +459,24 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp) return 0; }
+/** + * uclass_next_device() - Find next device of an uclass that can be probed + * @devp: device found or NULL + * @return always 0 + */ int uclass_next_device(struct udevice **devp) { struct udevice *dev = *devp; - int ret;
- *devp = NULL; - ret = uclass_find_next_device(&dev); - if (!dev) - return 0; - return uclass_get_device_tail(dev, ret, devp); + for (*devp = NULL; !*devp; ) { + uclass_find_next_device(&dev); + if (!dev) + break; + uclass_get_device_tail(dev, 0, devp); + } + debug("%s: %s\n", __func__, dev ? dev->name : "(EOL)"); + + return 0; }
int uclass_bind_device(struct udevice *dev)

Hi Heinrich,
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
Also don't forget to add a test for this bahaviour. You may need to have sandbox device that returns an error when probing. Perhaps add another compatible string to denx,u-boot-fdt-test?
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Regards, Simon

Hi Simon,
Am 19.04.2017 um 16:28 schrieb Simon Glass:
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
I fear you're missing the key point I made in my lengthy explanation:
Our caller (EFI) wants to iterate over the available devices. SDIO is not available. If we return a non-NULL device it will try to scan the disk. Therefore I think v2 is more correct (not yet tested).
So really the question is what your desired semantics of this function are and how callers here and elsewhere are handling it. If we want to return non-probed devices to the caller, as you now suggest, then we would need to audit and amend all callers of the API with some "if !is_probed() then continue" check. If we simply skip them internally, as done here IIUC, we require no changes on the caller side, thus much less invasive.
Maybe we need a new API uclass_{first,next}_available_device() to make this clear? The change would then only affect callers of the new API, and EFI and possibly others would again need to be audited and updated.
Regards, Andreas

Hi Andreas,
On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 16:28 schrieb Simon Glass:
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
I fear you're missing the key point I made in my lengthy explanation:
That's not entirely impossible.
Our caller (EFI) wants to iterate over the available devices. SDIO is not available. If we return a non-NULL device it will try to scan the disk. Therefore I think v2 is more correct (not yet tested).
So really the question is what your desired semantics of this function are and how callers here and elsewhere are handling it. If we want to return non-probed devices to the caller, as you now suggest, then we would need to audit and amend all callers of the API with some "if !is_probed() then continue" check. If we simply skip them internally, as done here IIUC, we require no changes on the caller side, thus much less invasive.
Well the value of 'ret' gives you that information if you want it. But yes it is a change and on second thoughts I'm not entirely comfortable with it.
Maybe we need a new API uclass_{first,next}_available_device() to make this clear? The change would then only affect callers of the new API, and EFI and possibly others would again need to be audited and updated.
Actually how about we go back to my foreach idea, and have a manual probe. So I mean let's just change the EFI code.
See for example print_cpu_list() for how this is done.
Regards, Simon

Hi Andreas,
On 19 April 2017 at 09:14, Simon Glass sjg@chromium.org wrote:
Hi Andreas,
On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 16:28 schrieb Simon Glass:
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
I fear you're missing the key point I made in my lengthy explanation:
That's not entirely impossible.
Our caller (EFI) wants to iterate over the available devices. SDIO is not available. If we return a non-NULL device it will try to scan the disk. Therefore I think v2 is more correct (not yet tested).
So really the question is what your desired semantics of this function are and how callers here and elsewhere are handling it. If we want to return non-probed devices to the caller, as you now suggest, then we would need to audit and amend all callers of the API with some "if !is_probed() then continue" check. If we simply skip them internally, as done here IIUC, we require no changes on the caller side, thus much less invasive.
Well the value of 'ret' gives you that information if you want it. But yes it is a change and on second thoughts I'm not entirely comfortable with it.
Maybe we need a new API uclass_{first,next}_available_device() to make this clear? The change would then only affect callers of the new API, and EFI and possibly others would again need to be audited and updated.
If you think this is generally useful then you could add this. I think it would be something like:
for (ret = uclass_first_avail_device(UCLASS_..., &dev; dev; ret = uclass_next_avail_device(&dev)) { if (!ret) { // do something } }
Does that sounds right?
Actually how about we go back to my foreach idea, and have a manual probe. So I mean let's just change the EFI code.
See for example print_cpu_list() for how this is done.
Regards, Simon

Am 19.04.2017 um 17:52 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 09:14, Simon Glass sjg@chromium.org wrote:
Hi Andreas,
On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 16:28 schrieb Simon Glass:
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
I fear you're missing the key point I made in my lengthy explanation:
That's not entirely impossible.
Our caller (EFI) wants to iterate over the available devices. SDIO is not available. If we return a non-NULL device it will try to scan the disk. Therefore I think v2 is more correct (not yet tested).
So really the question is what your desired semantics of this function are and how callers here and elsewhere are handling it. If we want to return non-probed devices to the caller, as you now suggest, then we would need to audit and amend all callers of the API with some "if !is_probed() then continue" check. If we simply skip them internally, as done here IIUC, we require no changes on the caller side, thus much less invasive.
Well the value of 'ret' gives you that information if you want it. But yes it is a change and on second thoughts I'm not entirely comfortable with it.
Maybe we need a new API uclass_{first,next}_available_device() to make this clear? The change would then only affect callers of the new API, and EFI and possibly others would again need to be audited and updated.
If you think this is generally useful then you could add this. I think it would be something like:
for (ret = uclass_first_avail_device(UCLASS_..., &dev; dev; ret = uclass_next_avail_device(&dev)) { if (!ret) { // do something } }
Does that sounds right?
No. I think that should be the semantics of uclass_first_device(), i.e. Heinrich's v1, possibly moved out of _tail() as you requested.
The idea behind a separate ..._available_device() implementation was to not have to do that ret check and to simply replace the function name to change the semantics, i.e. Heinrich's v2 implementation, but not inside uclass_{first,next}_device() but in copies with different name.
What use case is there for an incomplete enumeration as done by uclass_first_device() today? In order to continue enumeration devp needs to be set IIUC.
Regards, Andreas

Hi Andreas,
On 19 April 2017 at 10:37, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 17:52 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 09:14, Simon Glass sjg@chromium.org wrote:
Hi Andreas,
On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 16:28 schrieb Simon Glass:
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
I fear you're missing the key point I made in my lengthy explanation:
That's not entirely impossible.
Our caller (EFI) wants to iterate over the available devices. SDIO is not available. If we return a non-NULL device it will try to scan the disk. Therefore I think v2 is more correct (not yet tested).
So really the question is what your desired semantics of this function are and how callers here and elsewhere are handling it. If we want to return non-probed devices to the caller, as you now suggest, then we would need to audit and amend all callers of the API with some "if !is_probed() then continue" check. If we simply skip them internally, as done here IIUC, we require no changes on the caller side, thus much less invasive.
Well the value of 'ret' gives you that information if you want it. But yes it is a change and on second thoughts I'm not entirely comfortable with it.
Maybe we need a new API uclass_{first,next}_available_device() to make this clear? The change would then only affect callers of the new API, and EFI and possibly others would again need to be audited and updated.
If you think this is generally useful then you could add this. I think it would be something like:
for (ret = uclass_first_avail_device(UCLASS_..., &dev; dev; ret = uclass_next_avail_device(&dev)) { if (!ret) { // do something } }
Does that sounds right?
No. I think that should be the semantics of uclass_first_device(), i.e. Heinrich's v1, possibly moved out of _tail() as you requested.
The idea behind a separate ..._available_device() implementation was to not have to do that ret check and to simply replace the function name to change the semantics, i.e. Heinrich's v2 implementation, but not inside uclass_{first,next}_device() but in copies with different name.
How do you know what the error was? If you return a 'dev' then how do you know whether it is OK to process it? I'd prefer that this is provided via the return value rather than checking device_active(), etc.
What use case is there for an incomplete enumeration as done by uclass_first_device() today? In order to continue enumeration devp needs to be set IIUC.
The existing API returns a NULL device when it gets an error, meaning that the device cannot be used. The use case is for devices which don't fail on probe. While I understand that removeable devices can fail to probe today and then succeed later, many devices are not like that, and failing to probe is an error.
Regards, Simon

Am 19.04.2017 um 18:56 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 10:37, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 17:52 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 09:14, Simon Glass sjg@chromium.org wrote:
Hi Andreas,
On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 16:28 schrieb Simon Glass:
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote: > When iterating over the devices of an uclass the iteration stops > at the first device that cannot be probed. > When calling booefi this will result in no block device being > passed to the EFI executable if the first device cannot be probed. > > The problem was reported by Andreas Färber in > https://lists.denx.de/pipermail/u-boot/2017-April/287432.html > > For testing I used an odroid-c2 with a dts including > &sd_emmc_a { > status = "okay"; > } > This device does not exist on the board and cannot be initialized. > > With the patch uclass_first_device and uclass_next_device > iterate internally until they find the first device that can be > probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
I fear you're missing the key point I made in my lengthy explanation:
That's not entirely impossible.
Our caller (EFI) wants to iterate over the available devices. SDIO is not available. If we return a non-NULL device it will try to scan the disk. Therefore I think v2 is more correct (not yet tested).
So really the question is what your desired semantics of this function are and how callers here and elsewhere are handling it. If we want to return non-probed devices to the caller, as you now suggest, then we would need to audit and amend all callers of the API with some "if !is_probed() then continue" check. If we simply skip them internally, as done here IIUC, we require no changes on the caller side, thus much less invasive.
Well the value of 'ret' gives you that information if you want it. But yes it is a change and on second thoughts I'm not entirely comfortable with it.
Maybe we need a new API uclass_{first,next}_available_device() to make this clear? The change would then only affect callers of the new API, and EFI and possibly others would again need to be audited and updated.
If you think this is generally useful then you could add this. I think it would be something like:
for (ret = uclass_first_avail_device(UCLASS_..., &dev; dev; ret = uclass_next_avail_device(&dev)) { if (!ret) { // do something } }
Does that sounds right?
No. I think that should be the semantics of uclass_first_device(), i.e. Heinrich's v1, possibly moved out of _tail() as you requested.
The idea behind a separate ..._available_device() implementation was to not have to do that ret check and to simply replace the function name to change the semantics, i.e. Heinrich's v2 implementation, but not inside uclass_{first,next}_device() but in copies with different name.
How do you know what the error was? If you return a 'dev' then how do you know whether it is OK to process it? I'd prefer that this is provided via the return value rather than checking device_active(), etc.
You misunderstand: That ret handling should be hidden inside _available_device, not exposed to its caller! :)
Note that v2 adds a for loop inside both functions!
So the caller only sees the devices that probed and would never see a non-zero ret, i.e. they could become void (or return the dev, which would change the calling convention).
Andreas

Hi Andreas,
On 19 April 2017 at 11:00, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 18:56 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 10:37, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 17:52 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 09:14, Simon Glass sjg@chromium.org wrote:
Hi Andreas,
On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote:
Hi Simon,
Am 19.04.2017 um 16:28 schrieb Simon Glass: > On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote: >> When iterating over the devices of an uclass the iteration stops >> at the first device that cannot be probed. >> When calling booefi this will result in no block device being >> passed to the EFI executable if the first device cannot be probed. >> >> The problem was reported by Andreas Färber in >> https://lists.denx.de/pipermail/u-boot/2017-April/287432.html >> >> For testing I used an odroid-c2 with a dts including >> &sd_emmc_a { >> status = "okay"; >> } >> This device does not exist on the board and cannot be initialized. >> >> With the patch uclass_first_device and uclass_next_device >> iterate internally until they find the first device that can be >> probed or the end of the device list is reached. > > I would like to avoid changing the API that much. Can you please > change it to stop calling the tail function and always set the device, > like you did in v1?
I fear you're missing the key point I made in my lengthy explanation:
That's not entirely impossible.
Our caller (EFI) wants to iterate over the available devices. SDIO is not available. If we return a non-NULL device it will try to scan the disk. Therefore I think v2 is more correct (not yet tested).
So really the question is what your desired semantics of this function are and how callers here and elsewhere are handling it. If we want to return non-probed devices to the caller, as you now suggest, then we would need to audit and amend all callers of the API with some "if !is_probed() then continue" check. If we simply skip them internally, as done here IIUC, we require no changes on the caller side, thus much less invasive.
Well the value of 'ret' gives you that information if you want it. But yes it is a change and on second thoughts I'm not entirely comfortable with it.
Maybe we need a new API uclass_{first,next}_available_device() to make this clear? The change would then only affect callers of the new API, and EFI and possibly others would again need to be audited and updated.
If you think this is generally useful then you could add this. I think it would be something like:
for (ret = uclass_first_avail_device(UCLASS_..., &dev; dev; ret = uclass_next_avail_device(&dev)) { if (!ret) { // do something } }
Does that sounds right?
No. I think that should be the semantics of uclass_first_device(), i.e. Heinrich's v1, possibly moved out of _tail() as you requested.
The idea behind a separate ..._available_device() implementation was to not have to do that ret check and to simply replace the function name to change the semantics, i.e. Heinrich's v2 implementation, but not inside uclass_{first,next}_device() but in copies with different name.
How do you know what the error was? If you return a 'dev' then how do you know whether it is OK to process it? I'd prefer that this is provided via the return value rather than checking device_active(), etc.
You misunderstand: That ret handling should be hidden inside _available_device, not exposed to its caller! :)
Note that v2 adds a for loop inside both functions!
So the caller only sees the devices that probed and would never see a non-zero ret, i.e. they could become void (or return the dev, which would change the calling convention).
I see, so you want a 'higher level' function that only returns devices which probe without error. Then if you want to report the errors you would have to iterate in a different way. Is that right? So the return value would always be 0, right? Or would you make the function return the device pointer directly?
I am not very keen on this sort of function, since I suspect it would be useful only rarely. But I might be wrong and if you want to put it in, please go ahead.
BTW another point I should have made, is that really this sort of thing should be handled dynamically as needed. The EFI loader should not build its own tables parallel to DM. For example, if I run grub and then insert an MMC card or USB stick, grub won't know about it, right?
Regards, Simon

On 04/19/2017 07:10 PM, Simon Glass wrote:
Hi Andreas,
On 19 April 2017 at 11:00, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 18:56 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 10:37, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 17:52 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 09:14, Simon Glass sjg@chromium.org wrote:
Hi Andreas,
On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote: > Hi Simon, > > Am 19.04.2017 um 16:28 schrieb Simon Glass: >> On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote: >>> When iterating over the devices of an uclass the iteration stops >>> at the first device that cannot be probed. >>> When calling booefi this will result in no block device being >>> passed to the EFI executable if the first device cannot be probed. >>> >>> The problem was reported by Andreas Färber in >>> https://lists.denx.de/pipermail/u-boot/2017-April/287432.html >>> >>> For testing I used an odroid-c2 with a dts including >>> &sd_emmc_a { >>> status = "okay"; >>> } >>> This device does not exist on the board and cannot be initialized. >>> >>> With the patch uclass_first_device and uclass_next_device >>> iterate internally until they find the first device that can be >>> probed or the end of the device list is reached. >> >> I would like to avoid changing the API that much. Can you please >> change it to stop calling the tail function and always set the device, >> like you did in v1? > > I fear you're missing the key point I made in my lengthy explanation:
That's not entirely impossible.
> > Our caller (EFI) wants to iterate over the available devices. SDIO is > not available. If we return a non-NULL device it will try to scan the > disk. Therefore I think v2 is more correct (not yet tested). > > So really the question is what your desired semantics of this function > are and how callers here and elsewhere are handling it. If we want to > return non-probed devices to the caller, as you now suggest, then we > would need to audit and amend all callers of the API with some "if > !is_probed() then continue" check. If we simply skip them internally, as > done here IIUC, we require no changes on the caller side, thus much less > invasive.
Well the value of 'ret' gives you that information if you want it. But yes it is a change and on second thoughts I'm not entirely comfortable with it.
> > Maybe we need a new API uclass_{first,next}_available_device() to make > this clear? The change would then only affect callers of the new API, > and EFI and possibly others would again need to be audited and updated.
If you think this is generally useful then you could add this. I think it would be something like:
for (ret = uclass_first_avail_device(UCLASS_..., &dev; dev; ret = uclass_next_avail_device(&dev)) { if (!ret) { // do something } }
Does that sounds right?
No. I think that should be the semantics of uclass_first_device(), i.e. Heinrich's v1, possibly moved out of _tail() as you requested.
The idea behind a separate ..._available_device() implementation was to not have to do that ret check and to simply replace the function name to change the semantics, i.e. Heinrich's v2 implementation, but not inside uclass_{first,next}_device() but in copies with different name.
How do you know what the error was? If you return a 'dev' then how do you know whether it is OK to process it? I'd prefer that this is provided via the return value rather than checking device_active(), etc.
You misunderstand: That ret handling should be hidden inside _available_device, not exposed to its caller! :)
Note that v2 adds a for loop inside both functions!
So the caller only sees the devices that probed and would never see a non-zero ret, i.e. they could become void (or return the dev, which would change the calling convention).
I see, so you want a 'higher level' function that only returns devices which probe without error. Then if you want to report the errors you would have to iterate in a different way. Is that right? So the return value would always be 0, right? Or would you make the function return the device pointer directly?
uclass_first_device and uclass_next_device are these "higher level" functions: they return only devices probing without error. Unfortunately in some circumstances they do not return all devices. As Álvaro pointed out this bug is a pain in other places too.
This is what my patch fixes. There is no need for any new function.
I am not very keen on this sort of function, since I suspect it would be useful only rarely. But I might be wrong and if you want to put it in, please go ahead.
BTW another point I should have made, is that really this sort of thing should be handled dynamically as needed. The EFI loader should not build its own tables parallel to DM. For example, if I run grub and then insert an MMC card or USB stick, grub won't know about it, right?
According to the UEFI standard EFI_BOOT_SERVICES.LocateHandle() can be called until boot services are terminated.
You could create the drivers tables when this call occurs.
The current implementation first builds lists of all drivers and then calls the executable.
Rewriting this is probably a big job.
Best regards
Heinrich Schuchardt
Regards, Simon

On 19 April 2017 at 12:08, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 04/19/2017 07:10 PM, Simon Glass wrote:
Hi Andreas,
On 19 April 2017 at 11:00, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 18:56 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 10:37, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 17:52 schrieb Simon Glass:
Hi Andreas,
On 19 April 2017 at 09:14, Simon Glass sjg@chromium.org wrote: > Hi Andreas, > > On 19 April 2017 at 08:43, Andreas Färber afaerber@suse.de wrote: >> Hi Simon, >> >> Am 19.04.2017 um 16:28 schrieb Simon Glass: >>> On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote: >>>> When iterating over the devices of an uclass the iteration stops >>>> at the first device that cannot be probed. >>>> When calling booefi this will result in no block device being >>>> passed to the EFI executable if the first device cannot be probed. >>>> >>>> The problem was reported by Andreas Färber in >>>> https://lists.denx.de/pipermail/u-boot/2017-April/287432.html >>>> >>>> For testing I used an odroid-c2 with a dts including >>>> &sd_emmc_a { >>>> status = "okay"; >>>> } >>>> This device does not exist on the board and cannot be initialized. >>>> >>>> With the patch uclass_first_device and uclass_next_device >>>> iterate internally until they find the first device that can be >>>> probed or the end of the device list is reached. >>> >>> I would like to avoid changing the API that much. Can you please >>> change it to stop calling the tail function and always set the device, >>> like you did in v1? >> >> I fear you're missing the key point I made in my lengthy explanation: > > That's not entirely impossible. > >> >> Our caller (EFI) wants to iterate over the available devices. SDIO is >> not available. If we return a non-NULL device it will try to scan the >> disk. Therefore I think v2 is more correct (not yet tested). >> >> So really the question is what your desired semantics of this function >> are and how callers here and elsewhere are handling it. If we want to >> return non-probed devices to the caller, as you now suggest, then we >> would need to audit and amend all callers of the API with some "if >> !is_probed() then continue" check. If we simply skip them internally, as >> done here IIUC, we require no changes on the caller side, thus much less >> invasive. > > Well the value of 'ret' gives you that information if you want it. But > yes it is a change and on second thoughts I'm not entirely comfortable > with it. > >> >> Maybe we need a new API uclass_{first,next}_available_device() to make >> this clear? The change would then only affect callers of the new API, >> and EFI and possibly others would again need to be audited and updated.
If you think this is generally useful then you could add this. I think it would be something like:
for (ret = uclass_first_avail_device(UCLASS_..., &dev; dev; ret = uclass_next_avail_device(&dev)) { if (!ret) { // do something } }
Does that sounds right?
No. I think that should be the semantics of uclass_first_device(), i.e. Heinrich's v1, possibly moved out of _tail() as you requested.
The idea behind a separate ..._available_device() implementation was to not have to do that ret check and to simply replace the function name to change the semantics, i.e. Heinrich's v2 implementation, but not inside uclass_{first,next}_device() but in copies with different name.
How do you know what the error was? If you return a 'dev' then how do you know whether it is OK to process it? I'd prefer that this is provided via the return value rather than checking device_active(), etc.
You misunderstand: That ret handling should be hidden inside _available_device, not exposed to its caller! :)
Note that v2 adds a for loop inside both functions!
So the caller only sees the devices that probed and would never see a non-zero ret, i.e. they could become void (or return the dev, which would change the calling convention).
I see, so you want a 'higher level' function that only returns devices which probe without error. Then if you want to report the errors you would have to iterate in a different way. Is that right? So the return value would always be 0, right? Or would you make the function return the device pointer directly?
uclass_first_device and uclass_next_device are these "higher level" functions: they return only devices probing without error. Unfortunately in some circumstances they do not return all devices. As Álvaro pointed out this bug is a pain in other places too.
This is what my patch fixes. There is no need for any new function.
I do not what uclass_first/next_device to skip devices that don't probe. We need to have new functions.
This discussion seems to be going into the weeds. I'll see if I can work up a few patches and some tests to verify things.
I am not very keen on this sort of function, since I suspect it would be useful only rarely. But I might be wrong and if you want to put it in, please go ahead.
BTW another point I should have made, is that really this sort of thing should be handled dynamically as needed. The EFI loader should not build its own tables parallel to DM. For example, if I run grub and then insert an MMC card or USB stick, grub won't know about it, right?
According to the UEFI standard EFI_BOOT_SERVICES.LocateHandle() can be called until boot services are terminated.
You could create the drivers tables when this call occurs.
The current implementation first builds lists of all drivers and then calls the executable.
Rewriting this is probably a big job.
(this is off-topic from this patch but let me continue :-)
Actually this is how it should have been done in the first place IMO. Since everything is moving to driver model, it doesn't make a lot of sense to design EFI on the pre-driver-model approach.
I think implementing this for the boot-time interface is pretty easy, and I did in fact point this out in the original code review. However for the run-time interface, it is potentially quite painful, which has also already been discussed.
Regards, Simon

On 04/19/2017 04:28 PM, Simon Glass wrote:
Hi Heinrich,
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
Hello Simon,
with the patch nothing changes if the the available devices an contiguous starting at index 0.
Not calling the tail function would really change the API function in all cases. So why would we want to do so?
The current behavior is to stop at the first device that cannot be probed. Which use of uclass_first_device/uclass_next_device do you see in the U-Boot code that would benefit from this?
Also don't forget to add a test for this bahaviour. You may need to have sandbox device that returns an error when probing. Perhaps add another compatible string to denx,u-boot-fdt-test?
I will give it a try.
Best regards
Heinrich
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Regards, Simon

Hi Heinrih,
On 19 April 2017 at 09:55, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 04/19/2017 04:28 PM, Simon Glass wrote:
Hi Heinrich,
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
I would like to avoid changing the API that much. Can you please change it to stop calling the tail function and always set the device, like you did in v1?
Hello Simon,
with the patch nothing changes if the the available devices an contiguous starting at index 0.
Not calling the tail function would really change the API function in all cases. So why would we want to do so?
The current behavior is to stop at the first device that cannot be probed. Which use of uclass_first_device/uclass_next_device do you see in the U-Boot code that would benefit from this?
Also don't forget to add a test for this bahaviour. You may need to have sandbox device that returns an error when probing. Perhaps add another compatible string to denx,u-boot-fdt-test?
I will give it a try.
See my follow-up replies. I don't think we should change that function, actually.
Best regards
Heinrich
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Regards, Simon

In case you decide to apply this version (I see you're yet deciding which is the best way to go), I tested it and it solves my problem with sysreset not bein probed correctly.
So,
Tested-by: Álvaro Fernández Rojas noltari@gmail.com
El 19/04/2017 a las 13:26, Heinrich Schuchardt escribió:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 04fb45b..cff3a3f 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -420,16 +420,30 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent, } #endif
+/**
- uclass_first_device() - Finds first device of an uclass that can be probed
- @id: uclass id
- @devp: device found or NULL
- @return always 0
- For iterating over all devices of an uclass use
- for(uclass_first_device(id, &dev); dev; uclass_next_device(&dev)).
- */
int uclass_first_device(enum uclass_id id, struct udevice **devp) { struct udevice *dev;
int ret;
*devp = NULL;
ret = uclass_find_first_device(id, &dev);
if (!dev)
return 0;
return uclass_get_device_tail(dev, ret, devp);
- for (uclass_find_first_device(id, &dev); dev;
uclass_find_next_device(&dev)) {
uclass_get_device_tail(dev, 0, devp);
if (*devp)
break;
- }
- debug("%s(%d): %s\n", __func__, id, dev ? dev->name : "(EOL)");
- return 0;
}
int uclass_first_device_err(enum uclass_id id, struct udevice **devp) @@ -445,16 +459,24 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp) return 0; }
+/**
- uclass_next_device() - Find next device of an uclass that can be probed
- @devp: device found or NULL
- @return always 0
- */
int uclass_next_device(struct udevice **devp) { struct udevice *dev = *devp;
int ret;
*devp = NULL;
ret = uclass_find_next_device(&dev);
if (!dev)
return 0;
return uclass_get_device_tail(dev, ret, devp);
- for (*devp = NULL; !*devp; ) {
uclass_find_next_device(&dev);
if (!dev)
break;
uclass_get_device_tail(dev, 0, devp);
- }
- debug("%s: %s\n", __func__, dev ? dev->name : "(EOL)");
- return 0;
}
int uclass_bind_device(struct udevice *dev)

Am 19.04.2017 um 18:22 schrieb Álvaro Fernández Rojas:
In case you decide to apply this version (I see you're yet deciding which is the best way to go), I tested it and it solves my problem with sysreset not bein probed correctly.
Can you point us to which call site that is in your case exactly?
Thanks, Andreas

Hi Andreas,
El 19/04/2017 a las 18:25, Andreas Färber escribió:
Am 19.04.2017 um 18:22 schrieb Álvaro Fernández Rojas:
In case you decide to apply this version (I see you're yet deciding which is the best way to go), I tested it and it solves my problem with sysreset not bein probed correctly.
Can you point us to which call site that is in your case exactly?
Sure, see: https://github.com/Noltari/u-boot/commits/bmips-next-v3-fixes And: https://lists.denx.de/pipermail/u-boot/2017-April/288041.html
Thanks, Andreas
Regards, Álvaro.

Am 19.04.2017 um 18:31 schrieb Álvaro Fernández Rojas:
Hi Andreas,
El 19/04/2017 a las 18:25, Andreas Färber escribió:
Am 19.04.2017 um 18:22 schrieb Álvaro Fernández Rojas:
In case you decide to apply this version (I see you're yet deciding which is the best way to go), I tested it and it solves my problem with sysreset not bein probed correctly.
Can you point us to which call site that is in your case exactly?
Sure, see: https://github.com/Noltari/u-boot/commits/bmips-next-v3-fixes And: https://lists.denx.de/pipermail/u-boot/2017-April/288041.html
https://lists.denx.de/pipermail/u-boot/2017-April/288091.html
Hmm, to me that looks like the exact opposite symptom of what we're discussing right now. You seem to be getting into the for loop and adding checks there, whereas our issue is that we're not getting into the for loop due to NULL dev.
IIUC your code would be another candidate for _available_device() under discussion, as your patch is skipping devices that don't probe.
Regards, Andreas

Am 19.04.2017 um 13:26 schrieb Heinrich Schuchardt:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being
"bootefi"
passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Reviewed-by: Andreas Färber afaerber@suse.de Tested-by: Andreas Färber afaerber@suse.de
Confirming that on my Vega S95 Telos this results in a full GRUB menu, and GRUB sees two disks.
Many thanks,
Andreas
## Starting application at 0x01000000 ...
U-Boot 2017.05-rc2-00063-gfc365a8 (Apr 19 2017 - 22:48:23 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 44 ms (451.2 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 12 ms (10.3 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1806 Scanning disk mmc@72000.blk... About to add disk device 'mmc@72000.blk' Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 2:1 ** Scanning disk mmc@74000.blk... About to add disk device 'mmc@74000.blk' Adding disk device 'mmc@74000.blk' Found 2 disks Welcome to GRUB!
[...]
grub>ls (hd0) (hd0,msdos2) (hd0,msdos1) (hd1)

On 19 April 2017 at 15:06, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 13:26 schrieb Heinrich Schuchardt:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being
"bootefi"
passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Reviewed-by: Andreas Färber afaerber@suse.de Tested-by: Andreas Färber afaerber@suse.de
Confirming that on my Vega S95 Telos this results in a full GRUB menu, and GRUB sees two disks.
Many thanks,
Andreas
Just to be clear, I am NAKing this patch. I do not want to change the existing semantics as it requires existing code to check the function return value. Instead I would like to:
- Fix the bug found by Alvaro https://lists.denx.de/pipermail/u-boot/2017-April/288091.html This involves setting *devp to NULL when returning an error. - Add two new functions which return the device whether it probes or not, allowing iteration to continue. Since we have two potential users for these functions, it seems worth it.
I'll take a look at this soon unless someone else does :-)
Regards, SImon
## Starting application at 0x01000000 ...
U-Boot 2017.05-rc2-00063-gfc365a8 (Apr 19 2017 - 22:48:23 +0200) vega-s95
DRAM: 2 GiB MMC: mmc@70000: 0, mmc@72000: 1, mmc@74000: 2 Using default environment
In: serial@4c0 Out: serial@4c0 Err: serial@4c0 Net: eth0: ethernet@c9410000 Hit any key to stop autoboot: 0 mmc_init: -95, time 1806 MMC Device 0 not found no mmc device at slot 0 switch to partitions #0, OK mmc1 is current device Scanning mmc 1:1... Setting boot device name to '//boot/dtb/amlogic/meson-gxbb-v' 20335 bytes read in 44 ms (451.2 KiB/s) Found EFI removable media binary efi/boot/bootaa64.efi Setting boot device name to '/efi/boot/bootaa64.efi' reading efi/boot/bootaa64.efi 129024 bytes read in 12 ms (10.3 MiB/s) ## Starting EFI application at 01080000 ... mmc_init: -95, time 1806 Scanning disk mmc@72000.blk... About to add disk device 'mmc@72000.blk' Adding disk device 'mmc@72000.blk' ** First descriptor is NOT a primary desc on 2:1 ** Scanning disk mmc@74000.blk... About to add disk device 'mmc@74000.blk' Adding disk device 'mmc@74000.blk' Found 2 disks Welcome to GRUB!
[...]
grub>ls (hd0) (hd0,msdos2) (hd0,msdos1) (hd1)
-- SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)

Hi,
On 19 April 2017 at 15:34, Simon Glass sjg@chromium.org wrote:
On 19 April 2017 at 15:06, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 13:26 schrieb Heinrich Schuchardt:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being
"bootefi"
passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Reviewed-by: Andreas Färber afaerber@suse.de Tested-by: Andreas Färber afaerber@suse.de
Confirming that on my Vega S95 Telos this results in a full GRUB menu, and GRUB sees two disks.
Many thanks,
Andreas
Just to be clear, I am NAKing this patch. I do not want to change the existing semantics as it requires existing code to check the function return value. Instead I would like to:
- Fix the bug found by Alvaro
https://lists.denx.de/pipermail/u-boot/2017-April/288091.html This involves setting *devp to NULL when returning an error.
- Add two new functions which return the device whether it probes or
not, allowing iteration to continue. Since we have two potential users for these functions, it seems worth it.
I'll take a look at this soon unless someone else does :-)
Here is my attempt:
http://patchwork.ozlabs.org/patch/752578/ http://patchwork.ozlabs.org/patch/752576/ http://patchwork.ozlabs.org/patch/752577/
Regards, Simon [...]

Am 23.04.2017 um 01:58 schrieb Simon Glass:
Hi,
On 19 April 2017 at 15:34, Simon Glass sjg@chromium.org wrote:
On 19 April 2017 at 15:06, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 13:26 schrieb Heinrich Schuchardt:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being
"bootefi"
passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Reviewed-by: Andreas Färber afaerber@suse.de Tested-by: Andreas Färber afaerber@suse.de
Confirming that on my Vega S95 Telos this results in a full GRUB menu, and GRUB sees two disks.
Many thanks,
Andreas
Just to be clear, I am NAKing this patch. I do not want to change the existing semantics as it requires existing code to check the function return value. Instead I would like to:
- Fix the bug found by Alvaro
https://lists.denx.de/pipermail/u-boot/2017-April/288091.html This involves setting *devp to NULL when returning an error.
- Add two new functions which return the device whether it probes or
not, allowing iteration to continue. Since we have two potential users for these functions, it seems worth it.
I'll take a look at this soon unless someone else does :-)
Here is my attempt:
http://patchwork.ozlabs.org/patch/752578/ http://patchwork.ozlabs.org/patch/752576/ http://patchwork.ozlabs.org/patch/752577/
You have taken my idea with s/available/ok/ and Heinrich's v2 loop implementation and posted it without Suggested-by or Signed-off-by. :(
Regards, Andreas

Hi Andreas,
On 23 April 2017 at 04:48, Andreas Färber afaerber@suse.de wrote:
Am 23.04.2017 um 01:58 schrieb Simon Glass:
Hi,
On 19 April 2017 at 15:34, Simon Glass sjg@chromium.org wrote:
On 19 April 2017 at 15:06, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 13:26 schrieb Heinrich Schuchardt:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being
"bootefi"
passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Reviewed-by: Andreas Färber afaerber@suse.de Tested-by: Andreas Färber afaerber@suse.de
Confirming that on my Vega S95 Telos this results in a full GRUB menu, and GRUB sees two disks.
Many thanks,
Andreas
Just to be clear, I am NAKing this patch. I do not want to change the existing semantics as it requires existing code to check the function return value. Instead I would like to:
- Fix the bug found by Alvaro
https://lists.denx.de/pipermail/u-boot/2017-April/288091.html This involves setting *devp to NULL when returning an error.
- Add two new functions which return the device whether it probes or
not, allowing iteration to continue. Since we have two potential users for these functions, it seems worth it.
I'll take a look at this soon unless someone else does :-)
Here is my attempt:
http://patchwork.ozlabs.org/patch/752578/ http://patchwork.ozlabs.org/patch/752576/ http://patchwork.ozlabs.org/patch/752577/
You have taken my idea with s/available/ok/ and Heinrich's v2 loop implementation and posted it without Suggested-by or Signed-off-by. :(
Please send me what you would like and I'll add it.
I've had second (third?) thoughts on this so will be sending another version.
Regards, Simon

Am 19.04.2017 um 23:34 schrieb Simon Glass:
On 19 April 2017 at 15:06, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 13:26 schrieb Heinrich Schuchardt:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being
"bootefi"
passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Reviewed-by: Andreas Färber afaerber@suse.de Tested-by: Andreas Färber afaerber@suse.de
Confirming that on my Vega S95 Telos this results in a full GRUB menu, and GRUB sees two disks.
Many thanks,
Andreas
Just to be clear, I am NAKing this patch. I do not want to change the existing semantics as it requires existing code to check the function return value.
And to be clear I still think you are mistaken in holding on to an implementation that assumes that all devices will probe okay. We might be able to fix the issue at hand in different ways - be it at the callsite or by adding a new API - but this is papering over other potential problems in the codebase. Hardware might malfunction, drivers might not be implemented in U-Boot or be disabled by user's config, etc.
The caller might notice that some error has occurred by checking the return code, but what do you seriously expect it to do then? If it's supposed to call an alternative iteration function to continue, it could just call that in the first place.
Regards, Andreas

Hi Andreas,
On 23 April 2017 at 04:55, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 23:34 schrieb Simon Glass:
On 19 April 2017 at 15:06, Andreas Färber afaerber@suse.de wrote:
Am 19.04.2017 um 13:26 schrieb Heinrich Schuchardt:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being
"bootefi"
passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Reviewed-by: Andreas Färber afaerber@suse.de Tested-by: Andreas Färber afaerber@suse.de
Confirming that on my Vega S95 Telos this results in a full GRUB menu, and GRUB sees two disks.
Many thanks,
Andreas
Just to be clear, I am NAKing this patch. I do not want to change the existing semantics as it requires existing code to check the function return value.
And to be clear I still think you are mistaken in holding on to an implementation that assumes that all devices will probe okay.
The current API works pretty well and is used ~90 times in U-Boot so I'm reluctant to change it. In particular, having to check the return value to see if you can use dev or not would be a pretty significant change. I think there are some uses for it, but the majority of the time you want devices that work.
be able to fix the issue at hand in different ways - be it at the callsite or by adding a new API - but this is papering over other potential problems in the codebase. Hardware might malfunction, drivers might not be implemented in U-Boot or be disabled by user's config, etc.
This is up to the implementation, but for many boards if an expected device does not work then it is a problem. I suspect the main exception to this is removeable devices and situations where any of a number of boot paths might be chosen, some of which rely on removeable devices.
Anyway I'm not trying to mandate any one way of dealing with devices, just pointing out that the existing API works fairly well.
The caller might notice that some error has occurred by checking the return code, but what do you seriously expect it to do then? If it's supposed to call an alternative iteration function to continue, it could just call that in the first place.
In most cases, it would fail to boot and go to some sort of recovery mode. It often indicates a serious hardware error, and continuing is bad.
Having thought a bit more I think that ignoring errors is not a great way to go. So I'm going to update the series to try a different approach. Please can you reply to that with the tags you would like on it, or suggest another approach if you don't like it.
Regards, Simon

Hi Heinrick,
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
I just re-read this thread and saw this point again.
If this is not on the board, shouldn't the device have "disabled" in its node?
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Regards, Simon

On 04/23/2017 04:10 AM, Simon Glass wrote:
Hi Heinrick,
On 19 April 2017 at 05:26, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
When iterating over the devices of an uclass the iteration stops at the first device that cannot be probed. When calling booefi this will result in no block device being passed to the EFI executable if the first device cannot be probed.
The problem was reported by Andreas Färber in https://lists.denx.de/pipermail/u-boot/2017-April/287432.html
For testing I used an odroid-c2 with a dts including &sd_emmc_a { status = "okay"; } This device does not exist on the board and cannot be initialized.
I just re-read this thread and saw this point again.
If this is not on the board, shouldn't the device have "disabled" in its node?
I wanted to reproduce the probkem Andreas had with his board.
In the U-Boot repository this device is disabled.
Best regards
Heinrich Schuchardt
With the patch uclass_first_device and uclass_next_device iterate internally until they find the first device that can be probed or the end of the device list is reached.
Debug output is provided for the two functions.
Reported-by: Andreas Färber afaerber@suse.de Cc: Simon Glass sjg@chromium.org Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de
v2: As suggested by Simon Glass correct uclass_first_device() and uclass_next_device() instead of uclass_get_device_tail() to avoid side effects. v1: The original patch was posted as core/uclass: uclass_get_device_tail: always set devp https://lists.denx.de/pipermail/u-boot/2017-April/288068.html
drivers/core/uclass.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-)
Regards, Simon

Enable new Meson GX MMC driver in Odroid C2 defconfig.
Signed-off-by: Heiner Kallweit hkallweit1@gmail.com --- v6: - no changes v7: - rebased --- configs/odroid-c2_defconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/configs/odroid-c2_defconfig b/configs/odroid-c2_defconfig index 2cf5011..00da76e 100644 --- a/configs/odroid-c2_defconfig +++ b/configs/odroid-c2_defconfig @@ -14,7 +14,10 @@ CONFIG_DEFAULT_DEVICE_TREE="meson-gxbb-odroidc2" # CONFIG_CMD_SETEXPR is not set CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y -# CONFIG_MMC is not set +CONFIG_MMC=y +CONFIG_DM_MMC=y +CONFIG_MMC_MESON_GX=y +CONFIG_CMD_MMC=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PINCTRL=y

On 04/13/2017 03:32 AM, Heiner Kallweit wrote:
Enable new Meson GX MMC driver in Odroid C2 defconfig.
Signed-off-by: Heiner Kallweit hkallweit1@gmail.com
Applied to u-boot-mmc. Thanks!
Best Regards, Jaehoon Chung
v6:
- no changes
v7:
- rebased
configs/odroid-c2_defconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/configs/odroid-c2_defconfig b/configs/odroid-c2_defconfig index 2cf5011..00da76e 100644 --- a/configs/odroid-c2_defconfig +++ b/configs/odroid-c2_defconfig @@ -14,7 +14,10 @@ CONFIG_DEFAULT_DEVICE_TREE="meson-gxbb-odroidc2" # CONFIG_CMD_SETEXPR is not set CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y -# CONFIG_MMC is not set +CONFIG_MMC=y +CONFIG_DM_MMC=y +CONFIG_MMC_MESON_GX=y +CONFIG_CMD_MMC=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_PINCTRL=y

Hi Heiner,
On 04/13/2017 03:24 AM, Heiner Kallweit wrote:
This patch set implements eMMC on Amlogic Meson GX (S905). It's based on Carlo Caione's work submitted here: http://lists.denx.de/pipermail/u-boot/2016-May/254391.html
Changes to the original version:
- BLK support added
- fully DT-based now
- minor general refactoring
The driver was successfully tested on a Odroid C2.
Note: On Odroid C2 eMMC is MMC device 1. So you have to switch from MMC device 0 to 1 first when testing from uboot prompt.
I'm not sure but i think that you can use the fixed index for eMMC. Maybe you can refer to below commit.
commit 02ad33aa3a84821c8d9a6c4f167f143f6248b084 Refs: v2017.03-rc1-170-g02ad33a Author: Jaehoon Chung jh80.chung@samsung.com AuthorDate: Thu Feb 2 13:41:14 2017 +0900 Commit: Jaehoon Chung jh80.chung@samsung.com CommitDate: Thu Feb 9 20:37:05 2017 +0900
mmc: mmc-uclass: use the fixed devnum with alias node
If there are alias nodes as "mmc", use the devnum as alias index number. This patch is for fixing a problem of Exynos4 series. Problem is the below thing.
Current legacy mode: EXYNOS DWMMC: 0, SAMSUNG SDHCI: 1
After using DM: SAMSUNG SDHCI: 0, EXYNOS DWMMC: 1
Dev index is swapped. Then u-boot can't find the kernel image..because it is already set to 0 as mmcdev. If change from legacy to DM, also needs to touch all exynos4 config file. For using simply, just supporting the fixed devnum with alias node is better than it.
Usage: alaise { .... mmc0 = &sdhci2; /* eMMC */ mmc1 = &sdhci1; /* SD */ ... }
Anyway, I'm testing your patches with buildman..after that, i will apply.. But this patchset was delegated to Minkyu, so i will change it. if you are ok.
Best Regards, Jaehoon Chung
Latest change in v7:
- rebase due to other recent mmc changes
Heiner Kallweit (3): arm: dts: update Meson GXBB / Odroid-C2 DT with recent Linux version mmc: meson: add MMC driver for Meson GX (S905) odroid-c2: enable new Meson GX MMC driver in board defconfig
arch/arm/dts/meson-gx.dtsi | 447 +++++++++++++++++++ arch/arm/dts/meson-gxbb-odroidc2.dts | 147 +++++- arch/arm/dts/meson-gxbb.dtsi | 718 ++++++++++++++++++------------ arch/arm/include/asm/arch-meson/sd_emmc.h | 89 ++++ configs/odroid-c2_defconfig | 5 +- drivers/mmc/Kconfig | 6 + drivers/mmc/Makefile | 1 + drivers/mmc/meson_gx_mmc.c | 291 ++++++++++++ include/dt-bindings/clock/gxbb-aoclkc.h | 66 +++ include/dt-bindings/clock/gxbb-clkc.h | 34 ++ include/dt-bindings/reset/gxbb-aoclkc.h | 66 +++ 11 files changed, 1594 insertions(+), 276 deletions(-) create mode 100644 arch/arm/dts/meson-gx.dtsi create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_gx_mmc.c create mode 100644 include/dt-bindings/clock/gxbb-aoclkc.h create mode 100644 include/dt-bindings/clock/gxbb-clkc.h create mode 100644 include/dt-bindings/reset/gxbb-aoclkc.h
participants (8)
-
Alexander Graf
-
Andreas Färber
-
Heiner Kallweit
-
Heinrich Schuchardt
-
Jaehoon Chung
-
Simon Glass
-
Vagrant Cascadian
-
Álvaro Fernández Rojas