soc/mediatek: Ensure PERST# deassertion time follows the spec

According to the PCIe CEM specification, the deassertion of PERST#
should occur at least 100ms after the assertion. To ensure the 100ms
delay requirement is met, calculate the elapsed time since assertion. If
it is smaller than 100ms, do an extra delay.

TEST=Build pass and boot up to kernel successfully via SSD on Dojo
board, here is the measured PERST# time:
[DEBUG]  mtk_pcie_domain_enable: 432517 us elapsed since assert PERST#
[INFO ]  mtk_pcie_domain_enable: PCIe link up success (17 tries)

And the SSD information in boot log is as follows:
 == NVME IDENTIFY CONTROLLER DATA ==
    PCI VID   : 0x15b7
    PCI SSVID : 0x15b7
    SN        : 21517J440114
    MN        : WDC PC SN530 SDBPTPZ-256G-1006
    RAB       : 0x4
    AERL      : 0x7
    SQES      : 0x66
    CQES      : 0x44
    NN        : 0x1
Identified NVMe model WDC PC SN530 SDBPTPZ-256G-1006

BUG=b:178565024
BRANCH=cherry

Signed-off-by: Jianjun Wang <jianjun.wang@mediatek.com>
Change-Id: Ie2b7b6174abdf951af5796ab5ed141c45f32fc71
Reviewed-on: https://review.coreboot.org/c/coreboot/+/62933
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
This commit is contained in:
Jianjun Wang 2022-03-23 15:38:56 +08:00 committed by Paul Fagerburg
parent 2183484e7a
commit aa751cc371
2 changed files with 31 additions and 0 deletions

View File

@ -11,6 +11,7 @@
#include <delay.h> #include <delay.h>
#include <lib.h> #include <lib.h>
#include <soc/addressmap.h> #include <soc/addressmap.h>
#include <soc/early_init.h>
#include <soc/pcie.h> #include <soc/pcie.h>
#include <soc/pcie_common.h> #include <soc/pcie_common.h>
#include <soc/soc_chip.h> #include <soc/soc_chip.h>
@ -214,6 +215,7 @@ void mtk_pcie_domain_enable(struct device *dev)
const mtk_soc_config_t *config = config_of(dev); const mtk_soc_config_t *config = config_of(dev);
const struct mtk_pcie_config *conf = &config->pcie_config; const struct mtk_pcie_config *conf = &config->pcie_config;
const char *ltssm_state; const char *ltssm_state;
uint64_t perst_time_us;
size_t tries = 0; size_t tries = 0;
uint32_t val; uint32_t val;
@ -233,6 +235,32 @@ void mtk_pcie_domain_enable(struct device *dev)
val &= ~PCIE_INTX_ENABLE; val &= ~PCIE_INTX_ENABLE;
write32p(conf->base + PCIE_INT_ENABLE_REG, val); write32p(conf->base + PCIE_INT_ENABLE_REG, val);
perst_time_us = early_init_get_elapsed_time_us(EARLY_INIT_PCIE);
printk(BIOS_DEBUG, "%s: %lld us elapsed since assert PERST#\n",
__func__, perst_time_us);
/*
* Described in PCIe CEM specification sections 2.2
* (PERST# Signal) and 2.2.1 (Initial Power-Up (G3 to S0)).
* The deassertion of PERST# should be delayed 100ms (TPVPERL)
* for the power and clock to become stable.
*/
const uint64_t min_perst_time_us = 100000; /* 100 ms */
if (perst_time_us < min_perst_time_us) {
if (!perst_time_us) {
printk(BIOS_WARNING,
"%s: PCIe early init data not found, sleeping 100ms\n",
__func__);
mtk_pcie_reset(conf->base + PCIE_RST_CTRL_REG, true);
} else {
printk(BIOS_WARNING,
"%s: Need an extra %lld us delay to meet PERST# deassertion requirement\n",
__func__, min_perst_time_us - perst_time_us);
}
udelay(min_perst_time_us - perst_time_us);
}
/* De-assert reset signals */ /* De-assert reset signals */
mtk_pcie_reset(conf->base + PCIE_RST_CTRL_REG, false); mtk_pcie_reset(conf->base + PCIE_RST_CTRL_REG, false);

View File

@ -6,6 +6,7 @@
#include <device/resource.h> #include <device/resource.h>
#include <delay.h> #include <delay.h>
#include <soc/addressmap.h> #include <soc/addressmap.h>
#include <soc/early_init.h>
#include <soc/gpio.h> #include <soc/gpio.h>
#include <soc/pcie.h> #include <soc/pcie.h>
#include <soc/pcie_common.h> #include <soc/pcie_common.h>
@ -72,4 +73,6 @@ void mtk_pcie_pre_init(void)
/* Assert all reset signals at early stage */ /* Assert all reset signals at early stage */
mtk_pcie_reset(PCIE_RST_CTRL_REG, true); mtk_pcie_reset(PCIE_RST_CTRL_REG, true);
early_init_save_time(EARLY_INIT_PCIE);
} }