Hi all, This is a follow-up patch from my patch on mmc side: [PATCH v4] arm64: dts: rockchip: Fix SD card init on rk3399-nanopi4 https://patchwork.kernel.org/project/linux-rockchip/patch/73F9AED0-D2A8-4294-B6E1-1B92D2A36529@xxxxxxxxxxxxxxxx/ Thanks to Robin Murphy's help, we were able to figure out that my NanoPI R4S's SD-Card voltage regulator was initialized twice and that a voltage drop was the reason for the initialization failure. Adding an mdelay to the init code, or — surprisingly — adding a "regulator-uv-protection-microvolt" declaration had "fixed" the issue in 99/100 tries. Best, Christian from arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi: vcc3v0_sd: vcc3v0-sd { compatible = "regulator-fixed"; enable-active-high; gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&sdmmc0_pwr_h>; regulator-always-on; regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; regulator-name = "vcc3v0_sd"; vin-supply = <&vcc3v3_sys>; }; > Am 15.07.2022 um 22:32 schrieb Christian Kohlschütter <christian@xxxxxxxxxxxxxxxx>: > > Previously, an unresolved regulator supply reference upon calling > regulator_register on an always-on or boot-on regulator caused > set_machine_constraints to be called twice. > > This in turn may initialize the regulator twice, leading to voltage > glitches that are timing-dependent. A simple, unrelated configuration > change may be enough to hide this problem, only to be surfaced by > chance. > > One such example is the SD-Card voltage regulator in a NanoPI R4S that > would not initialize reliably unless the registration flow was just > complex enough to allow the regulator to properly reset between calls. > > Fix this by re-arranging regulator_register, trying resolve the > regulator's supply early enough that set_machine_constraints does not > need to be called twice. > > Signed-off-by: Christian Kohlschütter <christian@xxxxxxxxxxxxxxxx> > --- > drivers/regulator/core.c | 42 ++++++++++++++++++++++++++-------------- > 1 file changed, 28 insertions(+), 14 deletions(-) > > diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c > index c4d844ffad7a..728840827e9c 100644 > --- a/drivers/regulator/core.c > +++ b/drivers/regulator/core.c > @@ -5433,7 +5433,34 @@ regulator_register(const struct regulator_desc *regulator_desc, > BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); > INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); > > - /* preform any regulator specific init */ > + /* set regulator constraints */ > + if (init_data) > + rdev->constraints = kmemdup(&init_data->constraints, > + sizeof(*rdev->constraints), > + GFP_KERNEL); > + else > + rdev->constraints = kzalloc(sizeof(*rdev->constraints), > + GFP_KERNEL); > + > + if (init_data && init_data->supply_regulator) > + rdev->supply_name = init_data->supply_regulator; > + else if (regulator_desc->supply_name) > + rdev->supply_name = regulator_desc->supply_name; > + > + if ((rdev->supply_name && !rdev->supply) && rdev->constraints > + && (rdev->constraints->always_on || rdev->constraints->boot_on)) { > + /* Try to resolve the name of the supplying regulator here first > + * so we prevent double-initializing the regulator, which may > + * cause timing-specific voltage brownouts/glitches that are > + * hard to debug. > + */ > + ret = regulator_resolve_supply(rdev); > + if (ret) > + rdev_dbg(rdev, "unable to resolve supply early: %pe\n", > + ERR_PTR(ret)); > + } > + > + /* perform any regulator specific init */ > if (init_data && init_data->regulator_init) { > ret = init_data->regulator_init(rdev->reg_data); > if (ret < 0) > @@ -5459,24 +5486,11 @@ regulator_register(const struct regulator_desc *regulator_desc, > (unsigned long) atomic_inc_return(®ulator_no)); > dev_set_drvdata(&rdev->dev, rdev); > > - /* set regulator constraints */ > - if (init_data) > - rdev->constraints = kmemdup(&init_data->constraints, > - sizeof(*rdev->constraints), > - GFP_KERNEL); > - else > - rdev->constraints = kzalloc(sizeof(*rdev->constraints), > - GFP_KERNEL); > if (!rdev->constraints) { > ret = -ENOMEM; > goto wash; > } > > - if (init_data && init_data->supply_regulator) > - rdev->supply_name = init_data->supply_regulator; > - else if (regulator_desc->supply_name) > - rdev->supply_name = regulator_desc->supply_name; > - > ret = set_machine_constraints(rdev); > if (ret == -EPROBE_DEFER) { > /* Regulator might be in bypass mode and so needs its supply > -- > 2.36.1 >