nyan*: Enable SD card power in initialization.
After a warm reboot, Tegra SD card reader must be re-initialized by cycling its
power GPIO and VDD_SDMMC. Previous loader (ex, Coreboot) should clear the power
settings, and depthcharge MMC module will set GPIO and VDD starting to access SD
card.
BUG=chrome-os-partner:27053
BRANCH=nyan
TEST=emerge-nyan coreboot depthcharge chromeos-bootimage
On a Nyan/Norrin DEV mode, insert Sandisk class 10 SD card,
first boot eMMC system, mount SD card, run "reboot" command,
press Ctrl-U in DEV screen to boot SD card (success).
Run "crossystem recovery_request=1" then "reboot" (success).
Change-Id: I40b251d3400cafac810494ba3627142f10de5baa
Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/196783
Reviewed-by: Gabe Black <gabeblack@chromium.org>
Tested-by: Andrew Bresticker <abrestic@chromium.org>
diff --git a/src/board/nyan/board.c b/src/board/nyan/board.c
index fba3110..60e54ef 100644
--- a/src/board/nyan/board.c
+++ b/src/board/nyan/board.c
@@ -20,6 +20,7 @@
* MA 02111-1307 USA
*/
+#include <assert.h>
#include <libpayload.h>
#include "base/init_funcs.h"
@@ -84,6 +85,44 @@
CLK_H_I2C5 = 0x1 << 15
};
+typedef struct VirtualMmcPowerGpio
+{
+ GpioOps ops;
+
+ GpioOps *gpio;
+ As3722Pmic *as3722;
+ uint8_t reg, enable_val, disable_val; // Params for as3722.
+} VirtualMmcPowerGpio;
+
+static int virtual_mmc_power_set(GpioOps *me, unsigned value)
+{
+ VirtualMmcPowerGpio *power = container_of(me, VirtualMmcPowerGpio, ops);
+ assert(power->gpio && power->as3722);
+ if (power->gpio->set(power->gpio, value) ||
+ power->as3722->set_reg(power->as3722, power->reg, value ?
+ power->enable_val : power->disable_val)) {
+ printf("Failed to enable SD/MMC power.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static VirtualMmcPowerGpio *new_virtual_mmc_power(GpioOps *gpio,
+ As3722Pmic *as3722,
+ uint8_t reg,
+ uint8_t enable_val,
+ uint8_t disable_val)
+{
+ VirtualMmcPowerGpio *power = xzalloc(sizeof(*power));
+ power->gpio = gpio;
+ power->as3722 = as3722;
+ power->reg = reg;
+ power->enable_val = enable_val;
+ power->disable_val = disable_val;
+ power->ops.set = &virtual_mmc_power_set;
+ return power;
+}
+
static int board_setup(void)
{
uint8_t id = board_id();
@@ -155,20 +194,6 @@
cros_ec_set_bus(&new_cros_ec_spi_bus(&spi1->ops)->ops);
- // sdmmc4
- TegraMmcHost *emmc = new_tegra_mmc_host(0x700b0600, 8, 0, NULL);
- // sdmmc3
- TegraGpio *card_detect = new_tegra_gpio_input(GPIO(V, 2));
- GpioOps *card_detect_ops = &card_detect->ops;
- if (id != BOARD_ID_REV0)
- card_detect_ops = new_gpio_not(card_detect_ops);
- TegraMmcHost *sd_card = new_tegra_mmc_host(0x700b0400, 4, 1,
- card_detect_ops);
- list_insert_after(&emmc->mmc.ctrlr.list_node,
- &fixed_block_dev_controllers);
- list_insert_after(&sd_card->mmc.ctrlr.list_node,
- &removable_block_dev_controllers);
-
TegraI2c *pwr_i2c = new_tegra_i2c((void *)0x7000d000, 5,
(void *)CLK_RST_H_RST_SET,
(void *)CLK_RST_H_RST_CLR,
@@ -179,6 +204,25 @@
0);
power_set_ops(&power->ops);
+ // sdmmc4
+ TegraMmcHost *emmc = new_tegra_mmc_host(0x700b0600, 8, 0, NULL, NULL);
+ // sdmmc3
+ TegraGpio *enable_vdd_sd = new_tegra_gpio_output(GPIO(R, 0));
+ // The params in mmc_power set AS3722_LDO6 to 3.3V.
+ VirtualMmcPowerGpio *mmc_power = new_virtual_mmc_power(
+ &enable_vdd_sd->ops, pmic, 0x16, 0x3F, 0);
+ TegraGpio *card_detect = new_tegra_gpio_input(GPIO(V, 2));
+ GpioOps *card_detect_ops = &card_detect->ops;
+ if (id != BOARD_ID_REV0)
+ card_detect_ops = new_gpio_not(card_detect_ops);
+ TegraMmcHost *sd_card = new_tegra_mmc_host(0x700b0400, 4, 1,
+ card_detect_ops,
+ &mmc_power->ops);
+ list_insert_after(&emmc->mmc.ctrlr.list_node,
+ &fixed_block_dev_controllers);
+ list_insert_after(&sd_card->mmc.ctrlr.list_node,
+ &removable_block_dev_controllers);
+
/* Careful: the EHCI base is at offset 0x100 from the SoC's IP base */
UsbHostController *usbd = new_usb_hc(EHCI, 0x7d000100);
/* USB2 is connected to the camera, not needed in firmware */
diff --git a/src/board/nyan_big/board.c b/src/board/nyan_big/board.c
index 03b9063..bf6ebca 100644
--- a/src/board/nyan_big/board.c
+++ b/src/board/nyan_big/board.c
@@ -20,6 +20,7 @@
* MA 02111-1307 USA
*/
+#include <assert.h>
#include <libpayload.h>
#include <stdlib.h>
@@ -97,6 +98,44 @@
CLK_H_I2C5 = 0x1 << 15
};
+typedef struct VirtualMmcPowerGpio
+{
+ GpioOps ops;
+
+ GpioOps *gpio;
+ As3722Pmic *as3722;
+ uint8_t reg, enable_val, disable_val; // Params for as3722.
+} VirtualMmcPowerGpio;
+
+static int virtual_mmc_power_set(GpioOps *me, unsigned value)
+{
+ VirtualMmcPowerGpio *power = container_of(me, VirtualMmcPowerGpio, ops);
+ assert(power->gpio && power->as3722);
+ if (power->gpio->set(power->gpio, value) ||
+ power->as3722->set_reg(power->as3722, power->reg, value ?
+ power->enable_val : power->disable_val)) {
+ printf("Failed to enable SD/MMC power.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static VirtualMmcPowerGpio *new_virtual_mmc_power(GpioOps *gpio,
+ As3722Pmic *as3722,
+ uint8_t reg,
+ uint8_t enable_val,
+ uint8_t disable_val)
+{
+ VirtualMmcPowerGpio *power = xzalloc(sizeof(*power));
+ power->gpio = gpio;
+ power->as3722 = as3722;
+ power->reg = reg;
+ power->enable_val = enable_val;
+ power->disable_val = disable_val;
+ power->ops.set = &virtual_mmc_power_set;
+ return power;
+}
+
static int board_setup(void)
{
uint8_t id = board_id();
@@ -180,21 +219,6 @@
cros_ec_set_bus(&new_cros_ec_spi_bus(&spi1->ops)->ops);
- // sdmmc4
- TegraMmcHost *emmc = new_tegra_mmc_host(0x700b0600, 8, 0, NULL);
- // sdmmc3
- TegraGpio *card_detect = new_tegra_gpio_input(GPIO(V, 2));
- GpioOps *card_detect_ops = &card_detect->ops;
- // invert SD-card CD polarity
- card_detect_ops = new_gpio_not(card_detect_ops);
-
- TegraMmcHost *sd_card = new_tegra_mmc_host(0x700b0400, 4, 1,
- card_detect_ops);
- list_insert_after(&emmc->mmc.ctrlr.list_node,
- &fixed_block_dev_controllers);
- list_insert_after(&sd_card->mmc.ctrlr.list_node,
- &removable_block_dev_controllers);
-
TegraI2c *pwr_i2c = new_tegra_i2c((void *)0x7000d000, 5,
(void *)CLK_RST_H_RST_SET,
(void *)CLK_RST_H_RST_CLR,
@@ -205,6 +229,26 @@
0);
power_set_ops(&power->ops);
+ // sdmmc4
+ TegraMmcHost *emmc = new_tegra_mmc_host(0x700b0600, 8, 0, NULL, NULL);
+ // sdmmc3
+ TegraGpio *enable_vdd_sd = new_tegra_gpio_output(GPIO(R, 0));
+ // The params in mmc_power set AS3722_LDO6 to 3.3V.
+ VirtualMmcPowerGpio *mmc_power = new_virtual_mmc_power(
+ &enable_vdd_sd->ops, pmic, 0x16, 0x3F, 0);
+ TegraGpio *card_detect = new_tegra_gpio_input(GPIO(V, 2));
+ GpioOps *card_detect_ops = &card_detect->ops;
+ // invert SD-card CD polarity
+ card_detect_ops = new_gpio_not(card_detect_ops);
+
+ TegraMmcHost *sd_card = new_tegra_mmc_host(0x700b0400, 4, 1,
+ card_detect_ops,
+ &mmc_power->ops);
+ list_insert_after(&emmc->mmc.ctrlr.list_node,
+ &fixed_block_dev_controllers);
+ list_insert_after(&sd_card->mmc.ctrlr.list_node,
+ &removable_block_dev_controllers);
+
/* Careful: the EHCI base is at offset 0x100 from the SoC's IP base */
UsbHostController *usbd = new_usb_hc(EHCI, 0x7d000100);
/* USB2 is connected to the camera, not needed in firmware */
diff --git a/src/board/nyan_blaze/board.c b/src/board/nyan_blaze/board.c
index 09d4b97..7ff5a36 100644
--- a/src/board/nyan_blaze/board.c
+++ b/src/board/nyan_blaze/board.c
@@ -20,6 +20,7 @@
* MA 02111-1307 USA
*/
+#include <assert.h>
#include <libpayload.h>
#include <stdlib.h>
@@ -97,6 +98,44 @@
CLK_H_I2C5 = 0x1 << 15
};
+typedef struct VirtualMmcPowerGpio
+{
+ GpioOps ops;
+
+ GpioOps *gpio;
+ As3722Pmic *as3722;
+ uint8_t reg, enable_val, disable_val; // Params for as3722.
+} VirtualMmcPowerGpio;
+
+static int virtual_mmc_power_set(GpioOps *me, unsigned value)
+{
+ VirtualMmcPowerGpio *power = container_of(me, VirtualMmcPowerGpio, ops);
+ assert(power->gpio && power->as3722);
+ if (power->gpio->set(power->gpio, value) ||
+ power->as3722->set_reg(power->as3722, power->reg, value ?
+ power->enable_val : power->disable_val)) {
+ printf("Failed to enable SD/MMC power.\n");
+ return -1;
+ }
+ return 0;
+}
+
+static VirtualMmcPowerGpio *new_virtual_mmc_power(GpioOps *gpio,
+ As3722Pmic *as3722,
+ uint8_t reg,
+ uint8_t enable_val,
+ uint8_t disable_val)
+{
+ VirtualMmcPowerGpio *power = xzalloc(sizeof(*power));
+ power->gpio = gpio;
+ power->as3722 = as3722;
+ power->reg = reg;
+ power->enable_val = enable_val;
+ power->disable_val = disable_val;
+ power->ops.set = &virtual_mmc_power_set;
+ return power;
+}
+
static int board_setup(void)
{
uint8_t id = board_id();
@@ -180,21 +219,6 @@
cros_ec_set_bus(&new_cros_ec_spi_bus(&spi1->ops)->ops);
- // sdmmc4
- TegraMmcHost *emmc = new_tegra_mmc_host(0x700b0600, 8, 0, NULL);
- // sdmmc3
- TegraGpio *card_detect = new_tegra_gpio_input(GPIO(V, 2));
- GpioOps *card_detect_ops = &card_detect->ops;
- // invert SD-card CD polarity
- card_detect_ops = new_gpio_not(card_detect_ops);
-
- TegraMmcHost *sd_card = new_tegra_mmc_host(0x700b0400, 4, 1,
- card_detect_ops);
- list_insert_after(&emmc->mmc.ctrlr.list_node,
- &fixed_block_dev_controllers);
- list_insert_after(&sd_card->mmc.ctrlr.list_node,
- &removable_block_dev_controllers);
-
TegraI2c *pwr_i2c = new_tegra_i2c((void *)0x7000d000, 5,
(void *)CLK_RST_H_RST_SET,
(void *)CLK_RST_H_RST_CLR,
@@ -205,6 +229,26 @@
0);
power_set_ops(&power->ops);
+ // sdmmc4
+ TegraMmcHost *emmc = new_tegra_mmc_host(0x700b0600, 8, 0, NULL, NULL);
+ // sdmmc3
+ TegraGpio *enable_vdd_sd = new_tegra_gpio_output(GPIO(R, 0));
+ // The params in mmc_power set AS3722_LDO6 to 3.3V.
+ VirtualMmcPowerGpio *mmc_power = new_virtual_mmc_power(
+ &enable_vdd_sd->ops, pmic, 0x16, 0x3F, 0);
+ TegraGpio *card_detect = new_tegra_gpio_input(GPIO(V, 2));
+ GpioOps *card_detect_ops = &card_detect->ops;
+ // invert SD-card CD polarity
+ card_detect_ops = new_gpio_not(card_detect_ops);
+
+ TegraMmcHost *sd_card = new_tegra_mmc_host(0x700b0400, 4, 1,
+ card_detect_ops,
+ &mmc_power->ops);
+ list_insert_after(&emmc->mmc.ctrlr.list_node,
+ &fixed_block_dev_controllers);
+ list_insert_after(&sd_card->mmc.ctrlr.list_node,
+ &removable_block_dev_controllers);
+
/* Careful: the EHCI base is at offset 0x100 from the SoC's IP base */
UsbHostController *usbd = new_usb_hc(EHCI, 0x7d000100);
/* USB2 is connected to the camera, not needed in firmware */
diff --git a/src/drivers/storage/tegra_mmc.c b/src/drivers/storage/tegra_mmc.c
index bc4e98b..0ddc82c 100644
--- a/src/drivers/storage/tegra_mmc.c
+++ b/src/drivers/storage/tegra_mmc.c
@@ -486,6 +486,10 @@
TegraMmcHost *host = container_of(me, TegraMmcHost, mmc.ctrlr.ops);
unsigned int mask;
mmc_debug("%s called\n", __func__);
+ if (host->power_gpio) {
+ host->power_gpio->set(host->power_gpio, 1);
+ udelay(2000);
+ }
tegra_mmc_reset(host);
@@ -566,7 +570,8 @@
}
TegraMmcHost *new_tegra_mmc_host(uintptr_t ioaddr, int bus_width,
- int removable, GpioOps *card_detect)
+ int removable, GpioOps *card_detect,
+ GpioOps *enable_power)
{
TegraMmcHost *ctrlr = xzalloc(sizeof(*ctrlr));
@@ -596,6 +601,7 @@
ctrlr->removable = removable;
ctrlr->cd_gpio = card_detect;
+ ctrlr->power_gpio = enable_power;
return ctrlr;
}
diff --git a/src/drivers/storage/tegra_mmc.h b/src/drivers/storage/tegra_mmc.h
index cacbfbb..264318f 100644
--- a/src/drivers/storage/tegra_mmc.h
+++ b/src/drivers/storage/tegra_mmc.h
@@ -153,12 +153,14 @@
uint32_t src_hz; // Source clock (hz)
GpioOps *cd_gpio; // Change Detect GPIO
+ GpioOps *power_gpio; // Enable Power GPIO
int initialized;
int removable;
} TegraMmcHost;
TegraMmcHost *new_tegra_mmc_host(uintptr_t ioaddr, int bus_width,
- int removable, GpioOps *card_detect);
+ int removable, GpioOps *card_detect,
+ GpioOps *enable_power);
#endif // __DRIVERS_STORAGE_TEGRA_MMC_H_