drivers: pcie: ep: iproc: Add reset interrupt handlers

Add reset interrupt handlers for all three types of reset
interrupts that iProc PCIe EP can receive - namely PERST,
INB PERST and FLR.

Signed-off-by: Shivaraj Shetty <shivaraj.shetty@broadcom.com>
Signed-off-by: Abhishek Shah <abhishek.shah@broadcom.com>
This commit is contained in:
Abhishek Shah 2020-05-23 04:04:56 +05:30 committed by Carles Cufí
commit 7d587abc6e
4 changed files with 148 additions and 0 deletions

View file

@ -10,6 +10,8 @@
#include <logging/log.h>
LOG_MODULE_REGISTER(iproc_pcie);
#include <soc.h>
#include "pcie_ep_bcm_iproc.h"
#include "pcie_ep_bcm_iproc_regs.h"
@ -238,6 +240,118 @@ static int iproc_pcie_raise_irq(struct device *dev,
return ret;
}
#if DT_INST_IRQ_HAS_NAME(0, perst)
static void iproc_pcie_perst(void *arg)
{
struct device *dev = arg;
uint32_t data;
data = sys_read32(CRMU_MCU_EXTRA_EVENT_STATUS);
if (data & PCIE0_PERST_INTR) {
LOG_DBG("PERST interrupt [0x%x]", data);
sys_write32(PCIE0_PERST_INTR, CRMU_MCU_EXTRA_EVENT_CLEAR);
}
}
#endif
#if DT_INST_IRQ_HAS_NAME(0, perst_inband)
static void iproc_pcie_hot_reset(void *arg)
{
struct device *dev = arg;
uint32_t data;
data = sys_read32(CRMU_MCU_EXTRA_EVENT_STATUS);
if (data & PCIE0_PERST_INB_INTR) {
LOG_DBG("INBAND PERST interrupt [0x%x]", data);
sys_write32(PCIE0_PERST_INB_INTR, CRMU_MCU_EXTRA_EVENT_CLEAR);
}
}
#endif
#if DT_INST_IRQ_HAS_NAME(0, flr)
static void iproc_pcie_flr(void *arg)
{
struct device *dev = arg;
const struct iproc_pcie_ep_config *cfg = dev->config_info;
uint32_t data;
data = pcie_read32(&cfg->base->paxb_paxb_intr_status);
if (data & PCIE0_FLR_INTR) {
LOG_DBG("FLR interrupt[0x%x]", data);
pcie_write32(PCIE0_FLR_INTR, &cfg->base->paxb_paxb_intr_clear);
} else {
/*
* Other interrupts like PAXB ECC Error interrupt
* could show up at the beginning which are harmless.
* So simply clearing those interrupts here
*/
LOG_DBG("PAXB interrupt[0x%x]", data);
pcie_write32(data, &cfg->base->paxb_paxb_intr_clear);
}
/* Clear FLR in Progress bit */
iproc_pcie_conf_read(dev, PCIE_DEV_CTRL_OFFSET, &data);
data |= FLR_IN_PROGRESS;
iproc_pcie_conf_write(dev, PCIE_DEV_CTRL_OFFSET, data);
}
#endif
DEVICE_DECLARE(iproc_pcie_ep_0);
static void iproc_pcie_reset_config(struct device *dev)
{
uint32_t data;
const struct iproc_pcie_ep_config *cfg = dev->config_info;
/* Clear any possible prior pending interrupts */
sys_write32(PCIE0_PERST_INTR | PCIE0_PERST_INB_INTR,
CRMU_MCU_EXTRA_EVENT_CLEAR);
pcie_write32(PCIE0_FLR_INTR, &cfg->base->paxb_paxb_intr_clear);
/* Enable PERST and Inband PERST interrupts */
data = sys_read32(PCIE_PERSTB_INTR_CTL_STS);
data |= (PCIE0_PERST_FE_INTR | PCIE0_PERST_INB_FE_INTR);
sys_write32(data, PCIE_PERSTB_INTR_CTL_STS);
data = sys_read32(CRMU_MCU_EXTRA_EVENT_MASK);
data &= ~(PCIE0_PERST_INTR | PCIE0_PERST_INB_INTR);
sys_write32(data, CRMU_MCU_EXTRA_EVENT_MASK);
/* Set auto clear FLR and auto clear CRS post FLR */
iproc_pcie_conf_read(dev, PCIE_TL_CTRL0_OFFSET, &data);
data |= (AUTO_CLR_CRS_POST_FLR | AUTO_CLR_FLR_AFTER_DELAY);
iproc_pcie_conf_write(dev, PCIE_TL_CTRL0_OFFSET, data);
/* Enable Function Level Reset */
data = pcie_read32(&cfg->base->paxb_paxb_intr_en);
data |= PCIE0_FLR_INTR;
pcie_write32(data, &cfg->base->paxb_paxb_intr_en);
#if DT_INST_IRQ_HAS_NAME(0, perst)
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, perst, irq),
DT_INST_IRQ_BY_NAME(0, perst, priority),
iproc_pcie_perst, DEVICE_GET(iproc_pcie_ep_0), 0);
irq_enable(DT_INST_IRQ_BY_NAME(0, perst, irq));
#endif
#if DT_INST_IRQ_HAS_NAME(0, perst_inband)
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, perst_inband, irq),
DT_INST_IRQ_BY_NAME(0, perst_inband, priority),
iproc_pcie_hot_reset, DEVICE_GET(iproc_pcie_ep_0), 0);
irq_enable(DT_INST_IRQ_BY_NAME(0, perst_inband, irq));
#endif
#if DT_INST_IRQ_HAS_NAME(0, flr)
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, flr, irq),
DT_INST_IRQ_BY_NAME(0, flr, priority),
iproc_pcie_flr, DEVICE_GET(iproc_pcie_ep_0), 0);
irq_enable(DT_INST_IRQ_BY_NAME(0, flr, irq));
#endif
}
#ifdef CONFIG_PCIE_EP_BCM_IPROC_INIT_CFG
static void iproc_pcie_msix_config(struct device *dev)
{
@ -300,6 +414,8 @@ static int iproc_pcie_ep_init(struct device *dev)
iproc_pcie_msix_config(dev);
#endif
iproc_pcie_reset_config(dev);
ctx->highmem_in_use = false;
ctx->lowmem_in_use = false;
LOG_INF("PCIe initialized successfully\n");

View file

@ -42,6 +42,16 @@
#define PAXB_OARR_VALID BIT(0)
#define PCIE_DEV_CTRL_OFFSET 0x4d8
#define FLR_IN_PROGRESS BIT(27)
#define PCIE_TL_CTRL0_OFFSET 0x800
#define AUTO_CLR_FLR_AFTER_DELAY BIT(13) /* Clears FLR after 55ms */
#define AUTO_CLR_CRS_POST_FLR BIT(14)
#define PCIE0_FLR_INTR BIT(20)
#define PCIE0_FLR_PERST_INTR BIT(21)
enum pcie_outbound_map {
PCIE_MAP_LOWMEM_IDX,
PCIE_MAP_HIGHMEM_IDX,

View file

@ -282,4 +282,15 @@ typedef enum IRQn {
#define __MPU_PRESENT 1
#define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS
/* CRMU registers block */
#define CRMU_MCU_EXTRA_EVENT_STATUS 0x40070054
#define CRMU_MCU_EXTRA_EVENT_CLEAR 0x4007005c
#define CRMU_MCU_EXTRA_EVENT_MASK 0x40070064
#define PCIE0_PERST_INTR BIT(4)
#define PCIE0_PERST_INB_INTR BIT(6)
#define PCIE_PERSTB_INTR_CTL_STS 0x400700e4
#define PCIE0_PERST_FE_INTR BIT(1)
#define PCIE0_PERST_INB_FE_INTR BIT(3)
#endif

View file

@ -284,4 +284,15 @@ typedef enum IRQn {
#define __NVIC_PRIO_BITS NUM_IRQ_PRIO_BITS
#endif
/* CRMU registers block */
#define CRMU_MCU_EXTRA_EVENT_STATUS 0x40070054
#define CRMU_MCU_EXTRA_EVENT_CLEAR 0x4007005c
#define CRMU_MCU_EXTRA_EVENT_MASK 0x40070064
#define PCIE0_PERST_INTR BIT(4)
#define PCIE0_PERST_INB_INTR BIT(6)
#define PCIE_PERSTB_INTR_CTL_STS 0x400700f0
#define PCIE0_PERST_FE_INTR BIT(1)
#define PCIE0_PERST_INB_FE_INTR BIT(3)
#endif