blob: 6dd92518fc2a2bba7a66da4e9577de561526bad5 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 ASR Microelectronics(Shanghai) Co., Ltd.
*
* Copyright (C) 2018 Yu Zhang <yuzhang@asrmicro.com>
*
* Based on upstream Linux kernel driver:
* pcie-nz3.c: Yu Zhang <yuzhang@asrmicro.com>
* pcie-designware.c: Jingoo Han <jg1.han@samsung.com>
*/
#include <common.h>
#include <pci.h>
#include <asm/io.h>
#include <asm-generic/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
#define lower_32_bits(n) ((u32)(n))
#define PCIE_DW_NZ3_DBI_BASE 0xd4209000
#define PCIE_DW_NZ3_LANES 1
#define NZ3_PCIE_PREF_BASE 0xE8000000
#define NZ3_PCIE_PREF_SIZE 0x00100000
#define NZ3_PCIE_IO_BASE 0xE8100000
#define NZ3_PCIE_IO_SIZE 0x00100000
#define NZ3_PCIE_MEM_BASE 0xE0000000
#define NZ3_PCIE_MEM_SIZE 0x01000000
#define NZ3_PCIE_SYS_MEM_BASE 0x00000000
#define NZ3_PCIE_SYS_MEM_SIZE 0x04000000
#define NZ3_PCIE_CFG_BASE 0xE8200000
#define NZ3_PCIE_CFG_SIZE 0x00001000
/* PCIe DBI registers */
#define PCIE_BASE_ADDRESS_0 0x10
#define PCIE_BASE_ADDRESS_1 0x14
#define PCIE_LINK_CTRL_STATUS 0x80
#define PCIE_CAP_LINK_AUTO_BW_INT_EN (1 << 11)
#define PCIE_CAP_LINK_BW_MAN_INT_EN (1 << 10)
#define PCIE_DW_ADV_ERR_CAP_CTRL 0x118
#define ECRC_CHECK_EN (1 << 8)
#define ECRC_GEN_EN (1 << 6)
/* Synopsis specific PCIE configuration registers */
#define PCIE_PORT_LINK_CONTROL 0x710
#define PORT_LINK_MODE_MASK (0x3f << 16)
#define PORT_LINK_MODE_1_LANES (0x1 << 16)
#define PORT_LINK_MODE_2_LANES (0x3 << 16)
#define PORT_LINK_MODE_4_LANES (0x7 << 16)
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
#define PORT_LOGIC_LINK_WIDTH_MASK (0x1ff << 8)
#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8)
/* iATU registers */
#define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
#define PCIE_ATU_CR1 0x904
#define PCIE_ATU_TYPE_MEM (0x0 << 0)
#define PCIE_ATU_TYPE_IO (0x2 << 0)
#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
#define PCIE_ATU_CR2 0x908
#define PCIE_ATU_ENABLE (0x1 << 31)
#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
#define PCIE_ATU_LOWER_BASE 0x90C
#define PCIE_ATU_UPPER_BASE 0x910
#define PCIE_ATU_LIMIT 0x914
#define PCIE_ATU_LOWER_TARGET 0x918
#define PCIE_ATU_UPPER_TARGET 0x91C
/* PCIe APP registers */
#define PCIE_INT_STATUS 0x0
#define RX_MSI_INT (1 << 8)
#define DMA_LOCAL_INT (1 << 2)
#define DLL_LINK_CHA_INT (1 << 1)
#define PCIE_INT_ENABLE 0x8
#define RX_MSI_INT_EN (1 << 8)
#define RX_ASSERT_INTA_EN (1 << 9)
#define DMA_LOCAL_INT_EN (1 << 2)
#define DLL_LINK_CHA_EN (1 << 1)
#define PCIE_MISC_CTRL 0x40
#define APP_LINK_EN (1 << 0)
#define BAR_MASK_WRITE_EN (1 << 5)
#define PCIE_MISC_RST_CTRL 0x0FC
#define APP_RLS_RST (0x7F << 8)
#define PCIE_SYSP_DEV_STATUS 0x104
#define DLL_LINK_UP (1 << 1)
#define PHY_LINK_UP (1 << 0)
/* PCIe PHY registers */
#define PCIE_POWER_REG0 0x4
#define PHY_MODE_MASK (~(7 << 5))
#define PHY_MODE_PCIE (3 << 5)
#define REFCLK_MASK (~(0x1F << 0))
#define REFCLK_26M (0xD << 0)
#define PCIE_INTERFACE_REG1 0x94
#define PHY_MAX_GEN1 (~(3 << 10))
#define PCIE_MISC_REG0 0x13C
#define REFCLK_SEL_GRP1 (~(1 << 10))
#define PIN_TXDCLK_2X (~(1 << 6))
#define REFCLK_EN (1 << 4)
#define PCIE_LANE_STATUS1 0x60C
#define PM_TXDCLK_PCLK_EN (1 << 0)
#define PCIE_GLOB_CLK_CTRL 0x704
#define SOFT_RESET_DEASSERT (~(1 << 0))
#define MODE_CORE_CLK_250M (~(1 << 9))
#define MODE_FIXED_PCLK (1 << 2)
#define PCIE_GLOB_CLK_SRC_LO 0x70C
#define PLL_READY_DLY_MASK (~(7 << 5))
#define PLL_READY_DLY (2 << 5)
#define PCIE_GLOB_PM_CFG0 0x740
#define TXDETRX_DLY_MASK (~(0xFF << 0))
#define TXDETRX_DLY4REFCLK_26M (8 << 0)
/* APMU registers related to PCIE PHY */
#define APMU_USB_CLK_RES_CTRL 0xd428285c
#define APMU_REFCLK_BUFF_CTRL 0xd4282a00
#define PCIE_AXI_RST (0x1 << 25)
#define PCIE_AXI_CLK_ENB (0x1 << 24)
#define PCIE_CORE_RC_MODE (0x4 << 17)
#define PCIE_CORE_MODE_MASK (0xf << 17)
#define PCIE_PHY_RC_MODE (0x1 << 10)
#define PCIE_PHY_EP_MODE (0x1 << 9)
#define PCIE_PHY_DISABLE (0x1 << 8)
#define PCIE_REFCLK_PU (0x1 << 0)
#define PCIE_REFCLK_SEL_EXT (0x1 << 1)
#define PCIE_REFCLK_RX_EN (0x1 << 10)
#define PCIE_REFCLK_TX_EN (0x1 << 11)
#define PCIE_RESET_ASSERT (~(3 << 24))
#define PCIE_RESET_DEASSERT (3 << 24)
/**
* struct nz3_pcie - Nezha3 DW PCIe controller state
*
* @dbi_base: The base address of DW PCIe core register space
* @phy_base: The base address of PHY register space
* @app_base: The base address of SoC APP register space
* @cfg_base: The base address of the configuration space
* @cfg_size: The size of the configuration space which is needed
* as it gets written into the PCIE_ATU_LIMIT register
*/
struct nz3_pcie {
struct pci_controller hose;
void *dbi_base;
void *phy_base;
void *app_base;
void *cfg_base;
unsigned long cfg_size;
int lanes;
};
static inline struct nz3_pcie *
hose_to_nz3_pcie(struct pci_controller *hose)
{
return container_of(hose, struct nz3_pcie, hose);
}
static inline void nz3_pcie_elbi_writel(struct nz3_pcie *pcie, u32 val, u32 reg)
{
writel(val, pcie->dbi_base + reg);
}
static inline u32 nz3_pcie_elbi_readl(struct nz3_pcie *pcie, u32 reg)
{
return readl(pcie->dbi_base + reg);
}
static inline void nz3_pcie_phy_writel(struct nz3_pcie *pcie, u32 val, u32 reg)
{
writel(val, pcie->phy_base + reg);
}
static inline u32 nz3_pcie_phy_readl(struct nz3_pcie *pcie, u32 reg)
{
return readl(pcie->phy_base + reg);
}
static inline void nz3_pcie_app_writel(struct nz3_pcie *pcie, u32 val, u32 reg)
{
writel(val, pcie->app_base + reg);
}
static inline u32 nz3_pcie_app_readl(struct nz3_pcie *pcie, u32 reg)
{
return readl(pcie->app_base + reg);
}
/**
* pcie_dw_prog_outbound_atu() - Configure ATU for outbound accesses
*
* @pcie: Pointer to the PCI controller state
* @index: ATU region index
* @type: ATU accsess type
* @cpu_addr: the physical address for the translation entry
* @pci_addr: the pcie bus address for the translation entry
* @size: the size of the translation entry
*/
static void pcie_dw_prog_outbound_atu(struct nz3_pcie *pcie, int index,
int type, u64 cpu_addr, u64 pci_addr,
u32 size)
{
writel(PCIE_ATU_REGION_OUTBOUND | index,
pcie->dbi_base + PCIE_ATU_VIEWPORT);
writel(lower_32_bits(cpu_addr), pcie->dbi_base + PCIE_ATU_LOWER_BASE);
writel(upper_32_bits(cpu_addr), pcie->dbi_base + PCIE_ATU_UPPER_BASE);
writel(lower_32_bits(cpu_addr + size - 1),
pcie->dbi_base + PCIE_ATU_LIMIT);
writel(lower_32_bits(pci_addr),
pcie->dbi_base + PCIE_ATU_LOWER_TARGET);
writel(upper_32_bits(pci_addr),
pcie->dbi_base + PCIE_ATU_UPPER_TARGET);
writel(type, pcie->dbi_base + PCIE_ATU_CR1);
writel(PCIE_ATU_ENABLE, pcie->dbi_base + PCIE_ATU_CR2);
}
/**
* set_cfg_address() - Configure the PCIe controller config space access
*
* @pcie: Pointer to the PCI controller state
* @d: PCI device to access
* @where: Offset in the configuration space
*
* Configures the PCIe controller to access the configuration space of
* a specific PCIe device and returns the address to use for this
* access.
*
* Return: Address that can be used to access the configation space
* of the requested device / offset
*/
static uintptr_t set_cfg_address(struct nz3_pcie *pcie,
pci_dev_t d, uint where)
{
uintptr_t va_address;
u32 atu_type;
/*
* Region #0 is used for Outbound CFG space access.
* Direction = Outbound
* Region Index = 0
*/
if (PCI_BUS(d) < 2)
/* For local bus, change TLP Type field to 4. */
atu_type = PCIE_ATU_TYPE_CFG0;
else
/* Otherwise, change TLP Type field to 5. */
atu_type = PCIE_ATU_TYPE_CFG1;
if (PCI_BUS(d) == 0) {
/* Accessing root port configuration space. */
va_address = (uintptr_t)pcie->dbi_base;
} else {
d &= 0xffff;
pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
atu_type, (u64)pcie->cfg_base,
d << 8, pcie->cfg_size);
va_address = (uintptr_t)pcie->cfg_base;
}
va_address += where & ~0x3;
return va_address;
}
/**
* pcie_dw_addr_valid() - Check for valid bus address
*
* @d: The PCI device to access
*
* Return 1 (true) if the PCI device can be accessed by this controller.
*
* Return: 1 on valid, 0 on invalid
*/
static int pcie_dw_addr_valid(pci_dev_t d)
{
if ((PCI_BUS(d) == 0) && (PCI_DEV(d) > 0))
return 0;
if ((PCI_BUS(d) == 1) && (PCI_DEV(d) > 0))
return 0;
return 1;
}
/**
* nz3_pcie_read_config() - Read from configuration space
*
* @hose: Pointer to the PCI host
* @bdf: Identifies the PCIe device to access
* @where: The offset into the device's configuration space
* @val: A pointer at which to store the read value
*
* Return: 0 on success
*/
static int nz3_pcie_read_config(struct pci_controller *hose, pci_dev_t bdf,
int where, uint32_t *val)
{
struct nz3_pcie *pcie = hose_to_nz3_pcie(hose);
uint32_t va_address;
debug("PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ",
PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
if (!pcie_dw_addr_valid(bdf)) {
debug("- out of range\n");
*val = 0xffffffff;
return 0;
}
va_address = set_cfg_address(pcie, bdf, where);
*val = readl(va_address);
debug("(addr,val)=(0x%04x, 0x%08lx)\n", where, val);
pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_IO, NZ3_PCIE_IO_BASE,
NZ3_PCIE_IO_BASE, NZ3_PCIE_IO_SIZE);
return 0;
}
/**
* nz3_pcie_write_config() - Write to configuration space
*
* @hose: Pointer to the PCI host
* @bdf: Identifies the PCIe device to access
* @where: The offset into the device's configuration space
* @val: The value to write
*
* Return: 0 on success
*/
static int nz3_pcie_write_config(struct pci_controller *hose, pci_dev_t bdf,
int where, uint32_t val)
{
struct nz3_pcie *pcie = hose_to_nz3_pcie(hose);
uint32_t va_address;
debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ",
PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
debug("(addr,val)=(0x%04x, 0x%08lx)\n", where, val);
if (!pcie_dw_addr_valid(bdf)) {
debug("- out of range\n");
return 0;
}
va_address = set_cfg_address(pcie, bdf, where);
writel(val, va_address);
pcie_dw_prog_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_IO, NZ3_PCIE_IO_BASE,
NZ3_PCIE_IO_BASE, NZ3_PCIE_IO_SIZE);
return 0;
}
/**
* nz3_pcie_clk_enable() - Enable PHY clk and config as RC mode
*
*/
static void nz3_pcie_rc_clk_enable(void)
{
uint32_t val;
val = readl(APMU_USB_CLK_RES_CTRL);
val &= ~(PCIE_CORE_MODE_MASK | PCIE_PHY_RC_MODE |
PCIE_PHY_EP_MODE | PCIE_PHY_DISABLE);
val |= (PCIE_CORE_RC_MODE | PCIE_PHY_RC_MODE);
writel(val, APMU_USB_CLK_RES_CTRL);
val = readl(APMU_REFCLK_BUFF_CTRL);
val &= ~(PCIE_REFCLK_RX_EN);
val |= (PCIE_REFCLK_PU | PCIE_REFCLK_TX_EN);
writel(val, APMU_REFCLK_BUFF_CTRL);
/* Release areset and enable aclock */
val = readl(APMU_USB_CLK_RES_CTRL);
val |= PCIE_AXI_CLK_ENB | PCIE_AXI_RST;
writel(val, APMU_USB_CLK_RES_CTRL);
}
/**
* nz3_pcie_init_phy() - Initialize PCIe PHY
*
* Return: 1 on success, 0 on fail
*/
static int nz3_pcie_init_phy(struct nz3_pcie *pcie)
{
uint32_t val;
int count = 10;
nz3_pcie_rc_clk_enable();
/* set COMPHY signal PIN_PLL_READY_TX sampling delay */
val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_CLK_SRC_LO);
val &= PLL_READY_DLY_MASK;
val |= PLL_READY_DLY;
nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_CLK_SRC_LO);
/* select the correct REFCLK source */
val = nz3_pcie_phy_readl(pcie, PCIE_MISC_REG0);
val &= REFCLK_SEL_GRP1;
val &= PIN_TXDCLK_2X;
val |= REFCLK_EN;
nz3_pcie_phy_writel(pcie, val, PCIE_MISC_REG0);
/* Set PHY as PCIE mode */
val = nz3_pcie_phy_readl(pcie, PCIE_POWER_REG0);
val &= PHY_MODE_MASK;
val |= PHY_MODE_PCIE;
nz3_pcie_phy_writel(pcie, val, PCIE_POWER_REG0);
/* select 26MHz refclk */
val = nz3_pcie_phy_readl(pcie, PCIE_POWER_REG0);
val &= REFCLK_MASK;
val |= REFCLK_26M;
nz3_pcie_phy_writel(pcie, val, PCIE_POWER_REG0);
/* set txdetrx delay time */
val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_PM_CFG0);
val &= TXDETRX_DLY_MASK;
val |= TXDETRX_DLY4REFCLK_26M;
nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_PM_CFG0);
/* set PIPE 250Mhz 8bit mode */
val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_CLK_CTRL);
val &= MODE_CORE_CLK_250M;
/* 8-bit at 250MHz at 2.5GT/s */
val |= MODE_FIXED_PCLK;
nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_CLK_CTRL);
/* set the user intended maximum data rate as 2.5G */
val = nz3_pcie_phy_readl(pcie, PCIE_INTERFACE_REG1);
val &= PHY_MAX_GEN1;
nz3_pcie_phy_writel(pcie, val, PCIE_INTERFACE_REG1);
/* Release soft reset */
val = nz3_pcie_phy_readl(pcie, PCIE_GLOB_CLK_CTRL);
val &= SOFT_RESET_DEASSERT;
nz3_pcie_phy_writel(pcie, val, PCIE_GLOB_CLK_CTRL);
while (count--) {
val = nz3_pcie_phy_readl(pcie, PCIE_LANE_STATUS1);
mdelay(1);
if (val & PM_TXDCLK_PCLK_EN)
break;
}
if (count == 0) {
printf("PCIe PLL isn't ready in time\n");
return 0;
}
return 1;
}
/**
* nz3_pcie_link_up() - Return the link state
*
* Return: 1 (true) for active line and 0 (false) for no link
*/
static int nz3_pcie_link_up(struct nz3_pcie *pcie)
{
u32 status;
status = nz3_pcie_app_readl(pcie, PCIE_SYSP_DEV_STATUS);
if (status & DLL_LINK_UP)
return 1;
return 0;
}
/**
* nz3_pcie_core_reset() - assert/deassert core reset
*
* @reset: ture: de-assert, false: assert
*/
static void nz3_pcie_core_reset(int reset)
{
u32 val;
val = readl(APMU_USB_CLK_RES_CTRL);
if (reset)
val |= PCIE_RESET_DEASSERT;
else
val &= PCIE_RESET_ASSERT;
writel(val, APMU_USB_CLK_RES_CTRL);
}
/**
* nz3_pcie_dw_configure_rc() - Configure RC related stuff
*
* @nz3_pcie: A pointer to the PCIe controller
*
* Configure the link capabilities and speed in the PCIe root complex.
*/
static void nz3_pcie_dw_configure_rc(struct nz3_pcie *pcie)
{
uint32_t val;
uint32_t membase;
uint32_t memlimit;
/* set the number of lanes */
val = nz3_pcie_elbi_readl(pcie, PCIE_PORT_LINK_CONTROL);
val &= ~PORT_LINK_MODE_MASK;
switch (pcie->lanes) {
case 1:
val |= PORT_LINK_MODE_1_LANES;
break;
case 2:
val |= PORT_LINK_MODE_2_LANES;
break;
case 4:
val |= PORT_LINK_MODE_4_LANES;
break;
}
nz3_pcie_elbi_writel(pcie, val, PCIE_PORT_LINK_CONTROL);
/* set link width speed control register */
val = nz3_pcie_elbi_readl(pcie, PCIE_LINK_WIDTH_SPEED_CONTROL);
val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
switch (pcie->lanes) {
case 1:
val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
break;
case 2:
val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
break;
case 4:
val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
break;
}
nz3_pcie_elbi_writel(pcie, val, PCIE_LINK_WIDTH_SPEED_CONTROL);
/* setup RC BARs */
nz3_pcie_elbi_writel(pcie, 0x00000004, PCI_BASE_ADDRESS_0);
nz3_pcie_elbi_writel(pcie, 0x00000000, PCI_BASE_ADDRESS_1);
/* setup interrupt pins */
val = nz3_pcie_elbi_readl(pcie, PCI_INTERRUPT_LINE);
val &= 0xffff00ff;
val |= 0x00000100;
nz3_pcie_elbi_writel(pcie, val, PCI_INTERRUPT_LINE);
/* setup bus numbers */
val = nz3_pcie_elbi_readl(pcie, PCI_PRIMARY_BUS);
val &= 0xff000000;
val |= 0x00010100;
nz3_pcie_elbi_writel(pcie, val, PCI_PRIMARY_BUS);
/* setup memory base, memory limit */
membase = (NZ3_PCIE_MEM_BASE & 0xfff00000) >> 16;
memlimit = (NZ3_PCIE_MEM_BASE + NZ3_PCIE_MEM_SIZE) & 0xfff00000;
val = memlimit | membase;
nz3_pcie_elbi_writel(pcie, val, PCI_MEMORY_BASE);
/* setup command register */
val = nz3_pcie_elbi_readl(pcie, PCI_COMMAND);
val &= 0xffff0000;
val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
nz3_pcie_elbi_writel(pcie, val, PCI_COMMAND);
}
/**
* nz3_pcie_establish_link() - Establish link between RC and EP
*
* @nz3_pcie: A pointer to the PCIe controller
*
* Return: 1 (true) for active line and 0 (false) for no link
*/
static int nz3_pcie_establish_link(struct nz3_pcie *pcie)
{
int ret;
u32 val;
int count = 0;
if (nz3_pcie_link_up(pcie)) {
printf("Link already up\n");
return 1;
}
/* Initialize COMPHY */
ret = nz3_pcie_init_phy(pcie);
if (!ret)
return ret;
/* release reset */
val = nz3_pcie_app_readl(pcie, PCIE_MISC_RST_CTRL);
val |= APP_RLS_RST;
nz3_pcie_app_writel(pcie, val, PCIE_MISC_RST_CTRL);
/* enable ecrc generation and check */
val = nz3_pcie_elbi_readl(pcie, PCIE_DW_ADV_ERR_CAP_CTRL);
val |= (ECRC_CHECK_EN | ECRC_GEN_EN);
nz3_pcie_elbi_writel(pcie, val, PCIE_DW_ADV_ERR_CAP_CTRL);
/*
* enable Link Bandwidth Management and
* Autonomous Bandwidth interrupt
*/
val = nz3_pcie_elbi_readl(pcie, PCIE_LINK_CTRL_STATUS);
val |= PCIE_CAP_LINK_AUTO_BW_INT_EN;
val |= PCIE_CAP_LINK_BW_MAN_INT_EN;
nz3_pcie_elbi_writel(pcie, val, PCIE_LINK_CTRL_STATUS);
nz3_pcie_dw_configure_rc(pcie);
/* Enable BAR mask register write */
val = nz3_pcie_app_readl(pcie, PCIE_MISC_CTRL);
val |= BAR_MASK_WRITE_EN;
nz3_pcie_app_writel(pcie, val, PCIE_MISC_CTRL);
/* Disable RC BAR0 and BAR1 */
nz3_pcie_elbi_writel(pcie, 0, PCIE_BASE_ADDRESS_0);
nz3_pcie_elbi_writel(pcie, 0, PCIE_BASE_ADDRESS_1);
/* Disable BAR mask register write */
val = nz3_pcie_app_readl(pcie, PCIE_MISC_CTRL);
val &= ~BAR_MASK_WRITE_EN;
nz3_pcie_app_writel(pcie, val, PCIE_MISC_CTRL);
/* allow the LTSSM to establish link */
val = nz3_pcie_app_readl(pcie, PCIE_MISC_CTRL);
val |= APP_LINK_EN;
nz3_pcie_app_writel(pcie, val, PCIE_MISC_CTRL);
/* check if the link is up or not */
while (!nz3_pcie_link_up(pcie)) {
mdelay(1);
count++;
if (count == 100) {
printf("PCIe Link Fail\n");
return 0;
}
}
printf("Link up\n");
return 1;
}
/**
* nz3_pcie_init() - Probe Nezha3 PCIe bus for active link
*
*/
void nz3_pcie_init(void)
{
/* Static instance of the controller. */
static struct nz3_pcie pcie;
struct pci_controller *hose = &(pcie.hose);
int ret = 0;
memset(&pcie, 0, sizeof(pcie));
pcie.dbi_base = PCIE_DW_NZ3_DBI_BASE;
pcie.phy_base = pcie.dbi_base + 0x1000;
pcie.app_base = pcie.dbi_base + 0x2000;
pcie.cfg_base = NZ3_PCIE_CFG_BASE;
pcie.cfg_size = NZ3_PCIE_MEM_SIZE;
pcie.lanes = PCIE_DW_NZ3_LANES;
hose->first_busno = 0x0;
hose->last_busno = 0xff;
/* PCI I/O space */
pci_set_region(&hose->regions[0],
NZ3_PCIE_IO_BASE, NZ3_PCIE_IO_BASE,
NZ3_PCIE_IO_SIZE, PCI_REGION_IO);
/* PCI memory space */
pci_set_region(&hose->regions[1],
NZ3_PCIE_MEM_BASE, NZ3_PCIE_MEM_BASE,
NZ3_PCIE_MEM_SIZE, PCI_REGION_MEM);
/* System memory space */
pci_set_region(&hose->regions[2],
NZ3_PCIE_SYS_MEM_BASE, NZ3_PCIE_SYS_MEM_BASE,
NZ3_PCIE_SYS_MEM_SIZE, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
hose->region_count = 3;
pci_set_ops(hose,
pci_hose_read_config_byte_via_dword,
pci_hose_read_config_word_via_dword,
nz3_pcie_read_config,
pci_hose_write_config_byte_via_dword,
pci_hose_write_config_word_via_dword,
nz3_pcie_write_config);
/* Start the controller and establish link. */
ret = nz3_pcie_establish_link(&pcie);
if (!ret) {
pci_register_hose(hose);
hose->last_busno = pci_hose_scan(hose);
}
}
void nz3_pcie_remove(void)
{
nz3_pcie_core_reset(0);
}
/* Probe function. */
void pci_init_board(void)
{
nz3_pcie_init();
}