diff options
author | Jae Hyun Yoo <jae.hyun.yoo@intel.com> | 2020-11-20 21:09:31 +0300 |
---|---|---|
committer | Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> | 2021-11-05 10:22:11 +0300 |
commit | 20b020c06aa9b599b626a57a2614e0b890aac9cb (patch) | |
tree | 2869f2fb2bb1808fa28931b8234e8dd15508f6ac /drivers/peci | |
parent | 6735ebdea83d591b2e8c24138c2f0da08d41304c (diff) | |
download | linux-20b020c06aa9b599b626a57a2614e0b890aac9cb.tar.xz |
peci: aspeed: add a WA to cover timing negotiation issue
This commit adds a WA to cover timing negotiation hang issue on
target CPU cold resets by retriggering the timing negotiation.
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Diffstat (limited to 'drivers/peci')
-rw-r--r-- | drivers/peci/busses/peci-aspeed.c | 72 |
1 files changed, 45 insertions, 27 deletions
diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c index b6ccef550c0a..9dd3686a4228 100644 --- a/drivers/peci/busses/peci-aspeed.c +++ b/drivers/peci/busses/peci-aspeed.c @@ -39,6 +39,7 @@ #define ASPEED_PECI_CMD 0x08 #define ASPEED_PECI_CMD_PIN_MON BIT(31) #define ASPEED_PECI_CMD_STS_MASK GENMASK(27, 24) +#define ASPEED_PECI_CMD_STS_ADDR_T_NEGO 0x3 #define ASPEED_PECI_CMD_IDLE_MASK \ (ASPEED_PECI_CMD_STS_MASK | ASPEED_PECI_CMD_PIN_MON) #define ASPEED_PECI_CMD_FIRE BIT(0) @@ -125,11 +126,49 @@ struct aspeed_peci { struct completion xfer_complete; u32 status; u32 cmd_timeout_ms; + u32 msg_timing; + u32 addr_timing; + u32 rd_sampling_point; + u32 clk_div_val; }; +static void aspeed_peci_init_regs(struct aspeed_peci *priv) +{ + writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, + ASPEED_PECI_CLK_DIV_DEFAULT) | + ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL); + + /* + * Timing negotiation period setting. + * The unit of the programmed value is 4 times of PECI clock period. + */ + writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, priv->msg_timing) | + FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, priv->addr_timing), + priv->base + ASPEED_PECI_TIMING_NEGOTIATION); + + /* Clear interrupts */ + writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK, + priv->base + ASPEED_PECI_INT_STS); + + /* Set timing negotiation mode and enable interrupts */ + writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, + ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) | + ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL); + + /* Read sampling point and clock speed setting */ + writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, priv->rd_sampling_point) | + FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, priv->clk_div_val) | + ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN, + priv->base + ASPEED_PECI_CTRL); +} + static inline int aspeed_peci_check_idle(struct aspeed_peci *priv) { - u32 cmd_sts; + u32 cmd_sts = readl(priv->base + ASPEED_PECI_CMD); + + if (FIELD_GET(ASPEED_PECI_CMD_STS_MASK, + cmd_sts) == ASPEED_PECI_CMD_STS_ADDR_T_NEGO) + aspeed_peci_init_regs(priv); return readl_poll_timeout(priv->base + ASPEED_PECI_CMD, cmd_sts, @@ -307,6 +346,7 @@ static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) while ((clk_divisor >>= 1) && (clk_div_val < ASPEED_PECI_CLK_DIV_MAX)) clk_div_val++; + priv->clk_div_val = clk_div_val; ret = device_property_read_u32(priv->dev, "msg-timing", &msg_timing); if (ret || msg_timing > ASPEED_PECI_MSG_TIMING_MAX) { @@ -316,6 +356,7 @@ static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) msg_timing, ASPEED_PECI_MSG_TIMING_DEFAULT); msg_timing = ASPEED_PECI_MSG_TIMING_DEFAULT; } + priv->msg_timing = msg_timing; ret = device_property_read_u32(priv->dev, "addr-timing", &addr_timing); if (ret || addr_timing > ASPEED_PECI_ADDR_TIMING_MAX) { @@ -325,6 +366,7 @@ static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) addr_timing, ASPEED_PECI_ADDR_TIMING_DEFAULT); addr_timing = ASPEED_PECI_ADDR_TIMING_DEFAULT; } + priv->addr_timing = addr_timing; ret = device_property_read_u32(priv->dev, "rd-sampling-point", &rd_sampling_point); @@ -336,6 +378,7 @@ static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT); rd_sampling_point = ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT; } + priv->rd_sampling_point = rd_sampling_point; ret = device_property_read_u32(priv->dev, "cmd-timeout-ms", &priv->cmd_timeout_ms); @@ -349,32 +392,7 @@ static int aspeed_peci_init_ctrl(struct aspeed_peci *priv) priv->cmd_timeout_ms = ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT; } - writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, - ASPEED_PECI_CLK_DIV_DEFAULT) | - ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL); - - /* - * Timing negotiation period setting. - * The unit of the programmed value is 4 times of PECI clock period. - */ - writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, msg_timing) | - FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, addr_timing), - priv->base + ASPEED_PECI_TIMING_NEGOTIATION); - - /* Clear interrupts */ - writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK, - priv->base + ASPEED_PECI_INT_STS); - - /* Set timing negotiation mode and enable interrupts */ - writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK, - ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) | - ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL); - - /* Read sampling point and clock speed setting */ - writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, rd_sampling_point) | - FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_val) | - ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN, - priv->base + ASPEED_PECI_CTRL); + aspeed_peci_init_regs(priv); return 0; } |