mb/google/zork: Add support for WiFi power sequencing

This change replaces variant_wifi_romstage_gpio_table() with
variant_pcie_power_reset_configure() to handle the reset and power
sequencing for WiFi devices pre- and post- v3 version of schematics.

These are the requirements that need to be satisfied:
1. As per PCI Express M.2 Specification Revision 3.0,
Version 1.2, Section 3.1.4 "Power-up Timing", PERST# should stay
disabled until `TPVPGL` time duration after device power has
stabilized.  Value of TPVPGL is implementation specific.
2. For Intel WiFi chip, it is known to get into a bad state if the
above requirement is violated and hence requires a power cycle.
3. On pre-v3 schematics:
  - For both dalboz and trembyle references, GPIO42 drives
  WIFI_AUX_RESET_L which is pulled up to PP3300_WIFI.
  - For both dalboz and trembyle references, PP3300_WIFI is controlled
  using GPIO29. This pad gets pulled high by default on PWRGOOD
  because of internal pull-up. But, at RESET# it is known to have a
  glitch. When GPIO29 gets pulled high, it causes WIFI_AUX_RESET_L to
  be pulled high as well. This violates the PCIe power sequencing
  requirements. Hence, for pre-v3 schematics on both dalboz and
  trembyle, following sequence needs to be followed:
   a. Assert WIFI_AUX_RESET_L.
   b. Disable power to WiFi.
   c. Wait 10ms to allow WiFi power to go low.
   d. Enable power to WiFi.
   e. Wait 50ms as per PCIe specification.
   f. Deassert WIFI_AUX_RESET_L.
4. On v3 schematics:
   - For trembyle: WIFI_AUX_RESET_L is driven by GPIO86 which has an
   internal PU as well as an external PU to PP3300_WIFI.
   - For dalboz: WIFI_AUX_RESET is driven by GPIO29. This is active
   high and has an internal PU. It also has an external 1K PD to
   overcome internal PU.
   - For both dalboz and trembyle references, PP3300_WIFI is
   controlled by GPIO42 which has an internal PU and external
   PD. Trembyle schematics have a comment saying strong PD of 2.2K but
   the stuffed resistor is a weak one (499K). ON dalboz, it uses a
   weak PD (which doesn't look correct and instead should be a strong
   PD just like trembyle). Having a strong PD ensures that the WiFi
   power is kept disabled when coming out of G3 until coreboot
   configures GPIO42 as high.
   - Thus, for v3 schematics, following sequence needs to be followed:
    a. Assert WIFI_AUX_RESET{_L} signal.
    b. Enable power to WiFi.
    c. Wait 50ms as per PCIe specification.
    d. Deassert WIFI_AUX_RESET{_L} signal.

BUG=b:157686402, b:158257076
TEST=Verified that QCA and AX200 cards both continue working. Tested
QCA on Dalboz and Trembyle. Tested AX200 on morphius.

Signed-off-by: Furquan Shaikh <furquan@google.com>
Change-Id: I532131ee911d5efb5130d8710f3e01578f6c9627
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42738
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Furquan Shaikh 2020-06-22 10:45:12 -07:00
parent 462f3ed111
commit 8302585c15
8 changed files with 123 additions and 134 deletions

View File

@ -20,8 +20,7 @@ void mainboard_romstage_entry_s3(int s3_resume)
gpios = variant_romstage_gpio_table(&num_gpios); gpios = variant_romstage_gpio_table(&num_gpios);
program_gpios(gpios, num_gpios); program_gpios(gpios, num_gpios);
gpios = variant_wifi_romstage_gpio_table(&num_gpios); variant_pcie_power_reset_configure();
program_gpios(gpios, num_gpios);
mainboard_ec_init(); mainboard_ec_init();

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */ /* SPDX-License-Identifier: GPL-2.0-or-later */
#include <baseboard/variants.h> #include <baseboard/variants.h>
#include <delay.h>
#include <gpio.h>
#include <soc/gpio.h> #include <soc/gpio.h>
#include <soc/smi.h> #include <soc/smi.h>
#include <stdlib.h> #include <stdlib.h>
@ -20,8 +22,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_pre_v3[] = {
PAD_NF(GPIO_27, PCIE_RST1_L, PULL_NONE), PAD_NF(GPIO_27, PCIE_RST1_L, PULL_NONE),
/* NVME_AUX_RESET_L */ /* NVME_AUX_RESET_L */
PAD_GPO(GPIO_40, HIGH), PAD_GPO(GPIO_40, HIGH),
/* WIFI_AUX_RESET_L */
PAD_GPO(GPIO_42, HIGH),
/* EN_PWR_TOUCHPAD_PS2 - reset */ /* EN_PWR_TOUCHPAD_PS2 - reset */
PAD_GPO(GPIO_67, LOW), PAD_GPO(GPIO_67, LOW),
/* EMMC_RESET - reset (default stuffing unused)*/ /* EMMC_RESET - reset (default stuffing unused)*/
@ -44,11 +44,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_pre_v3[] = {
PAD_GPO(GPIO_142, HIGH), PAD_GPO(GPIO_142, HIGH),
}; };
static const struct soc_amd_gpio gpio_set_wifi_pre_v3[] = {
/* EN_PWR_WIFI */
PAD_GPO(GPIO_29, HIGH),
};
static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = { static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = {
/* PEN_POWER_EN - reset */ /* PEN_POWER_EN - reset */
PAD_GPO(GPIO_5, LOW), PAD_GPO(GPIO_5, LOW),
@ -62,8 +57,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = {
PAD_NF(GPIO_26, PCIE_RST_L, PULL_NONE), PAD_NF(GPIO_26, PCIE_RST_L, PULL_NONE),
/* PCIE_RST1_L - Variable timings (May remove) */ /* PCIE_RST1_L - Variable timings (May remove) */
PAD_NF(GPIO_27, PCIE_RST1_L, PULL_NONE), PAD_NF(GPIO_27, PCIE_RST1_L, PULL_NONE),
/* WIFI_AUX_RESET */
PAD_GPO(GPIO_29, LOW),
/* NVME_AUX_RESET_L */ /* NVME_AUX_RESET_L */
PAD_GPO(GPIO_40, HIGH), PAD_GPO(GPIO_40, HIGH),
/* EMMC_RESET - reset (default stuffing unused)*/ /* EMMC_RESET - reset (default stuffing unused)*/
@ -86,11 +79,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = {
PAD_GPO(GPIO_142, HIGH), PAD_GPO(GPIO_142, HIGH),
}; };
static const struct soc_amd_gpio gpio_set_wifi_v3[] = {
/* EN_PWR_WIFI */
PAD_GPO(GPIO_42, HIGH),
};
static const struct soc_amd_gpio gpio_set_stage_ram[] = { static const struct soc_amd_gpio gpio_set_stage_ram[] = {
/* PWR_BTN_L */ /* PWR_BTN_L */
@ -218,21 +206,6 @@ struct soc_amd_gpio *variant_romstage_gpio_table(size_t *size)
return gpio_set_stage_rom_pre_v3; return gpio_set_stage_rom_pre_v3;
} }
const __weak
struct soc_amd_gpio *variant_wifi_romstage_gpio_table(size_t *size)
{
uint32_t board_version;
if (!google_chromeec_cbi_get_board_version(&board_version) &&
(board_version >= CONFIG_VARIANT_MIN_BOARD_ID_V3_SCHEMATICS)) {
*size = ARRAY_SIZE(gpio_set_wifi_v3);
return gpio_set_wifi_v3;
}
*size = ARRAY_SIZE(gpio_set_wifi_pre_v3);
return gpio_set_wifi_pre_v3;
}
const __weak const __weak
struct soc_amd_gpio *variant_base_gpio_table(size_t *size) struct soc_amd_gpio *variant_base_gpio_table(size_t *size)
{ {
@ -251,3 +224,61 @@ const __weak struct sci_source *get_gpe_table(size_t *num)
{ {
return NULL; return NULL;
} }
static void wifi_power_reset_configure_v3(void)
{
/*
* Configure WiFi GPIOs such that:
* - WIFI_AUX_RESET is configured first to assert PERST# to WiFi device.
* - Enable power to WiFi using EN_PWR_WIFI.
* - Wait for 50ms after power to WiFi is enabled.
* - Deassert PERST# to WiFi device by driving WIFI_AUX_RESET low.
*/
static const struct soc_amd_gpio v3_wifi_table[] = {
/* WIFI_AUX_RESET */
PAD_GPO(GPIO_29, HIGH),
/* EN_PWR_WIFI */
PAD_GPO(GPIO_42, HIGH),
};
program_gpios(v3_wifi_table, ARRAY_SIZE(v3_wifi_table));
mdelay(50);
gpio_set(GPIO_29, 0);
}
static void wifi_power_reset_configure_pre_v3(void)
{
/*
* Configure WiFi GPIOs such that:
* - WIFI_AUX_RESET_L is configured first to assert PERST# to WiFi device.
* - Disable power to WiFi since GPIO_29 goes high on PWRGOOD but has a glitch on RESET#
* deassertion causing WiFi to enter a bad state.
* - Wait 10ms for WiFi power to go low.
* - Enable power to WiFi using EN_PWR_WIFI.
* - Wait for 50ms after power to WiFi is enabled.
* - Deassert WIFI_AUX_RESET_L.
*/
static const struct soc_amd_gpio pre_v3_wifi_table[] = {
/* WIFI_AUX_RESET_L */
PAD_GPO(GPIO_42, LOW),
/* EN_PWR_WIFI */
PAD_GPO(GPIO_29, LOW),
};
program_gpios(pre_v3_wifi_table, ARRAY_SIZE(pre_v3_wifi_table));
mdelay(10);
gpio_set(GPIO_29, 1);
mdelay(50);
gpio_set(GPIO_42, 1);
}
__weak void variant_pcie_power_reset_configure(void)
{
uint32_t board_version;
if (!google_chromeec_cbi_get_board_version(&board_version) &&
(board_version >= CONFIG_VARIANT_MIN_BOARD_ID_V3_SCHEMATICS))
wifi_power_reset_configure_v3();
else
wifi_power_reset_configure_pre_v3();
}

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */ /* SPDX-License-Identifier: GPL-2.0-or-later */
#include <baseboard/variants.h> #include <baseboard/variants.h>
#include <delay.h>
#include <gpio.h>
#include <soc/gpio.h> #include <soc/gpio.h>
#include <soc/smi.h> #include <soc/smi.h>
#include <stdlib.h> #include <stdlib.h>
@ -20,8 +22,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_pre_v3[] = {
PAD_NF(GPIO_27, PCIE_RST1_L, PULL_NONE), PAD_NF(GPIO_27, PCIE_RST1_L, PULL_NONE),
/* NVME_AUX_RESET_L */ /* NVME_AUX_RESET_L */
PAD_GPO(GPIO_40, HIGH), PAD_GPO(GPIO_40, HIGH),
/* WIFI_AUX_RESET_L */
PAD_GPO(GPIO_42, HIGH),
/* EN_PWR_TOUCHPAD_PS2 - reset */ /* EN_PWR_TOUCHPAD_PS2 - reset */
PAD_GPO(GPIO_67, LOW), PAD_GPO(GPIO_67, LOW),
/* EMMC_RESET - reset (default stuffing unused)*/ /* EMMC_RESET - reset (default stuffing unused)*/
@ -42,11 +42,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_pre_v3[] = {
PAD_GPO(GPIO_142, HIGH), PAD_GPO(GPIO_142, HIGH),
}; };
static const struct soc_amd_gpio gpio_set_wifi_pre_v3[] = {
/* EN_PWR_WIFI */
PAD_GPO(GPIO_29, HIGH),
};
static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = { static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = {
/* PEN_POWER_EN - reset */ /* PEN_POWER_EN - reset */
PAD_GPO(GPIO_5, LOW), PAD_GPO(GPIO_5, LOW),
@ -66,8 +61,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = {
PAD_GPO(GPIO_68, HIGH), PAD_GPO(GPIO_68, HIGH),
/* EN_PWR_CAMERA - reset */ /* EN_PWR_CAMERA - reset */
PAD_GPO(GPIO_76, LOW), PAD_GPO(GPIO_76, LOW),
/* WIFI_AUX_RESET_L */
PAD_GPO(GPIO_86, HIGH),
/* CLK_REQ0_L - WIFI */ /* CLK_REQ0_L - WIFI */
PAD_NF(GPIO_92, CLK_REQ0_L, PULL_UP), PAD_NF(GPIO_92, CLK_REQ0_L, PULL_UP),
/* CLK_REQ1_L - SD Card */ /* CLK_REQ1_L - SD Card */
@ -82,11 +75,6 @@ static const struct soc_amd_gpio gpio_set_stage_rom_v3[] = {
PAD_GPO(GPIO_142, HIGH), PAD_GPO(GPIO_142, HIGH),
}; };
static const struct soc_amd_gpio gpio_set_wifi_v3[] = {
/* EN_PWR_WIFI */
PAD_GPO(GPIO_42, HIGH),
};
static const struct soc_amd_gpio gpio_set_stage_ram[] = { static const struct soc_amd_gpio gpio_set_stage_ram[] = {
/* PWR_BTN_L */ /* PWR_BTN_L */
@ -213,21 +201,6 @@ struct soc_amd_gpio *variant_romstage_gpio_table(size_t *size)
return gpio_set_stage_rom_pre_v3; return gpio_set_stage_rom_pre_v3;
} }
const __weak
struct soc_amd_gpio *variant_wifi_romstage_gpio_table(size_t *size)
{
uint32_t board_version;
if (!google_chromeec_cbi_get_board_version(&board_version) &&
(board_version >= CONFIG_VARIANT_MIN_BOARD_ID_V3_SCHEMATICS)) {
*size = ARRAY_SIZE(gpio_set_wifi_v3);
return gpio_set_wifi_v3;
}
*size = ARRAY_SIZE(gpio_set_wifi_pre_v3);
return gpio_set_wifi_pre_v3;
}
const __weak const __weak
struct soc_amd_gpio *variant_base_gpio_table(size_t *size) struct soc_amd_gpio *variant_base_gpio_table(size_t *size)
{ {
@ -246,3 +219,61 @@ const __weak struct sci_source *get_gpe_table(size_t *num)
{ {
return NULL; return NULL;
} }
static void wifi_power_reset_configure_v3(void)
{
/*
* Configure WiFi GPIOs such that:
* - WIFI_AUX_RESET_L is configured first to assert PERST# to WiFi device.
* - Enable power to WiFi using EN_PWR_WIFI.
* - Wait for 50ms after power to WiFi is enabled.
* - Deassert WIFI_AUX_RESET_L.
*/
static const struct soc_amd_gpio v3_wifi_table[] = {
/* WIFI_AUX_RESET_L */
PAD_GPO(GPIO_86, LOW),
/* EN_PWR_WIFI */
PAD_GPO(GPIO_42, HIGH),
};
program_gpios(v3_wifi_table, ARRAY_SIZE(v3_wifi_table));
mdelay(50);
gpio_set(GPIO_86, 1);
}
static void wifi_power_reset_configure_pre_v3(void)
{
/*
* Configure WiFi GPIOs such that:
* - WIFI_AUX_RESET_L is configured first to assert PERST# to WiFi device.
* - Disable power to WiFi since GPIO_29 goes high on PWRGOOD but has a glitch on RESET#
* deassertion causing WiFi to enter a bad state.
* - Wait 10ms for WiFi power to go low.
* - Enable power to WiFi using EN_PWR_WIFI.
* - Wait for 50ms after power to WiFi is enabled.
* - Deassert WIFI_AUX_RESET_L.
*/
static const struct soc_amd_gpio pre_v3_wifi_table[] = {
/* WIFI_AUX_RESET_L */
PAD_GPO(GPIO_42, LOW),
/* EN_PWR_WIFI */
PAD_GPO(GPIO_29, LOW),
};
program_gpios(pre_v3_wifi_table, ARRAY_SIZE(pre_v3_wifi_table));
mdelay(10);
gpio_set(GPIO_29, 1);
mdelay(50);
gpio_set(GPIO_42, 1);
}
__weak void variant_pcie_power_reset_configure(void)
{
uint32_t board_version;
if (!google_chromeec_cbi_get_board_version(&board_version) &&
(board_version >= CONFIG_VARIANT_MIN_BOARD_ID_V3_SCHEMATICS))
wifi_power_reset_configure_v3();
else
wifi_power_reset_configure_pre_v3();
}

View File

@ -13,7 +13,6 @@
const struct sci_source *get_gpe_table(size_t *num); const struct sci_source *get_gpe_table(size_t *num);
const struct soc_amd_gpio *variant_early_gpio_table(size_t *size); const struct soc_amd_gpio *variant_early_gpio_table(size_t *size);
const struct soc_amd_gpio *variant_romstage_gpio_table(size_t *size); const struct soc_amd_gpio *variant_romstage_gpio_table(size_t *size);
const struct soc_amd_gpio *variant_wifi_romstage_gpio_table(size_t *size);
/* /*
* This function provides base GPIO configuration table. It is typically provided by * This function provides base GPIO configuration table. It is typically provided by
* baseboard using a weak implementation. If GPIO configuration for a variant differs * baseboard using a weak implementation. If GPIO configuration for a variant differs
@ -29,6 +28,8 @@ const struct soc_amd_gpio *variant_override_gpio_table(size_t *size);
void variant_romstage_entry(void); void variant_romstage_entry(void);
/* Modify devictree settings during ramstage. */ /* Modify devictree settings during ramstage. */
void variant_devtree_update(void); void variant_devtree_update(void);
/* Configure PCIe power and reset lines as per variant sequencing requirements. */
void variant_pcie_power_reset_configure(void);
/* Per variant FSP-S initialization, default implementation in baseboard and /* Per variant FSP-S initialization, default implementation in baseboard and
* overrideable by the variant. */ * overrideable by the variant. */

View File

@ -2,6 +2,4 @@
subdirs-y += ./spd subdirs-y += ./spd
romstage-y += ./romstage.c
ramstage-y += gpio.c ramstage-y += gpio.c

View File

@ -1,27 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stddef.h>
#include <soc/romstage.h>
#include <baseboard/variants.h>
#include <ec/google/chromeec/ec.h>
#include <gpio.h>
#include <soc/gpio.h>
#include <variant/gpio.h>
void variant_romstage_entry(void)
{
/* Power the wifi card */
gpio_set(EN_PWR_WIFI, 1);
}
static const struct soc_amd_gpio berknip_gpio_set_wifi[] = {
/* EN_PWR_WIFI - Power off. Pull high in romstage.c */
PAD_GPO(GPIO_29, LOW),
};
const struct soc_amd_gpio *variant_wifi_romstage_gpio_table(size_t *size)
{
*size = ARRAY_SIZE(berknip_gpio_set_wifi);
return berknip_gpio_set_wifi;
}

View File

@ -2,6 +2,4 @@
subdirs-y += ./spd subdirs-y += ./spd
romstage-y += ./romstage.c
ramstage-y += gpio.c ramstage-y += gpio.c

View File

@ -1,42 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <stddef.h>
#include <soc/romstage.h>
#include <baseboard/variants.h>
#include <ec/google/chromeec/ec.h>
#include <gpio.h>
#include <soc/gpio.h>
#include <variant/gpio.h>
#include <delay.h>
void variant_romstage_entry(void)
{
//SET WIFI_PCIE_RESET_L HIGH
gpio_set(WIFI_PCIE_RESET_L, 1);
/* Power the wifi card */
/* wait 10ms to discharge EN_PWR_WIFI to 0V */
mdelay(10);
gpio_set(EN_PWR_WIFI, 1);
/* SET WIFI_PCIE_RESET_L LOW */
gpio_set(WIFI_PCIE_RESET_L, 0);
/* Qualcomm Atheros NFA344A needs at least 10ms delay */
mdelay(10);
/* SET WIFI_PCIE_RESET_L HIGH */
gpio_set(WIFI_PCIE_RESET_L, 1);
}
static const struct soc_amd_gpio morphius_gpio_set_wifi[] = {
/* EN_PWR_WIFI - Power off. Pull high in romstage.c */
PAD_GPO(GPIO_29, LOW),
};
const struct soc_amd_gpio *variant_wifi_romstage_gpio_table(size_t *size)
{
*size = ARRAY_SIZE(morphius_gpio_set_wifi);
return morphius_gpio_set_wifi;
}