2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2014-10-31 05:43:44 +00:00
|
|
|
/*
|
2020-07-09 15:31:33 +00:00
|
|
|
* Copyright 2017-2020 NXP
|
2015-01-21 09:29:20 +00:00
|
|
|
* Copyright 2014-2015 Freescale Semiconductor, Inc.
|
2014-10-31 05:43:44 +00:00
|
|
|
* Layerscape PCIe driver
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
2020-05-10 17:40:05 +00:00
|
|
|
#include <log.h>
|
2020-10-31 03:38:53 +00:00
|
|
|
#include <asm/global_data.h>
|
2014-10-31 05:43:44 +00:00
|
|
|
#include <asm/io.h>
|
2015-01-21 09:29:20 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <malloc.h>
|
2017-05-17 14:23:06 +00:00
|
|
|
#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \
|
|
|
|
defined(CONFIG_ARM)
|
|
|
|
#include <asm/arch/clock.h>
|
|
|
|
#endif
|
2016-12-13 06:54:16 +00:00
|
|
|
#include "pcie_layerscape.h"
|
2015-01-21 09:29:20 +00:00
|
|
|
|
2016-12-13 06:54:17 +00:00
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
|
|
LIST_HEAD(ls_pcie_list);
|
|
|
|
|
2020-07-09 15:31:33 +00:00
|
|
|
unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
|
|
|
return in_le32(pcie->dbi + offset);
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:31:33 +00:00
|
|
|
void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
|
|
|
out_le32(pcie->dbi + offset, value);
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:31:33 +00:00
|
|
|
unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
|
|
|
if (pcie->big_endian)
|
|
|
|
return in_be32(pcie->ctrl + offset);
|
|
|
|
else
|
|
|
|
return in_le32(pcie->ctrl + offset);
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:31:33 +00:00
|
|
|
void ctrl_writel(struct ls_pcie *pcie, unsigned int value,
|
|
|
|
unsigned int offset)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
|
|
|
if (pcie->big_endian)
|
|
|
|
out_be32(pcie->ctrl + offset, value);
|
|
|
|
else
|
|
|
|
out_le32(pcie->ctrl + offset, value);
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:31:33 +00:00
|
|
|
void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie)
|
|
|
|
{
|
|
|
|
u32 reg, val;
|
|
|
|
|
|
|
|
reg = PCIE_MISC_CONTROL_1_OFF;
|
|
|
|
val = dbi_readl(pcie, reg);
|
|
|
|
val |= PCIE_DBI_RO_WR_EN;
|
|
|
|
dbi_writel(pcie, val, reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie)
|
|
|
|
{
|
|
|
|
u32 reg, val;
|
|
|
|
|
|
|
|
reg = PCIE_MISC_CONTROL_1_OFF;
|
|
|
|
val = dbi_readl(pcie, reg);
|
|
|
|
val &= ~PCIE_DBI_RO_WR_EN;
|
|
|
|
dbi_writel(pcie, val, reg);
|
|
|
|
}
|
|
|
|
|
2016-12-13 06:54:17 +00:00
|
|
|
static int ls_pcie_ltssm(struct ls_pcie *pcie)
|
|
|
|
{
|
|
|
|
u32 state;
|
|
|
|
uint svr;
|
|
|
|
|
|
|
|
svr = get_svr();
|
|
|
|
if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) == SVR_LS102XA) {
|
|
|
|
state = ctrl_readl(pcie, LS1021_PEXMSCPORTSR(pcie->idx));
|
|
|
|
state = (state >> LS1021_LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
|
|
|
|
} else {
|
|
|
|
state = ctrl_readl(pcie, PCIE_PF_DBG) & LTSSM_STATE_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:31:33 +00:00
|
|
|
int ls_pcie_link_up(struct ls_pcie *pcie)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
|
|
|
int ltssm;
|
|
|
|
|
|
|
|
ltssm = ls_pcie_ltssm(pcie);
|
|
|
|
if (ltssm < LTSSM_PCIE_L0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:31:33 +00:00
|
|
|
void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type,
|
2020-07-09 15:31:39 +00:00
|
|
|
u64 phys, u64 bus_addr, u64 size)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
|
|
|
dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | idx, PCIE_ATU_VIEWPORT);
|
|
|
|
dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_BASE);
|
|
|
|
dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_BASE);
|
|
|
|
dbi_writel(pcie, (u32)phys + size - 1, PCIE_ATU_LIMIT);
|
|
|
|
dbi_writel(pcie, (u32)bus_addr, PCIE_ATU_LOWER_TARGET);
|
|
|
|
dbi_writel(pcie, bus_addr >> 32, PCIE_ATU_UPPER_TARGET);
|
|
|
|
dbi_writel(pcie, type, PCIE_ATU_CR1);
|
|
|
|
dbi_writel(pcie, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use bar match mode and MEM type as default */
|
2020-07-09 15:31:39 +00:00
|
|
|
void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag,
|
|
|
|
int type, int idx, int bar, u64 phys)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
|
|
|
dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT);
|
|
|
|
dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET);
|
|
|
|
dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET);
|
2020-07-09 15:31:36 +00:00
|
|
|
dbi_writel(pcie, type | PCIE_ATU_FUNC_NUM(pf), PCIE_ATU_CR1);
|
2016-12-13 06:54:17 +00:00
|
|
|
dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE |
|
2020-07-09 15:31:39 +00:00
|
|
|
(vf_flag ? PCIE_ATU_FUNC_NUM_MATCH_EN : 0) |
|
|
|
|
(vf_flag ? PCIE_ATU_VFBAR_MATCH_MODE_EN : 0) |
|
2016-12-13 06:54:17 +00:00
|
|
|
PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2);
|
|
|
|
}
|
|
|
|
|
2020-07-09 15:31:40 +00:00
|
|
|
void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type)
|
2016-12-13 06:54:17 +00:00
|
|
|
{
|
2020-07-09 15:31:40 +00:00
|
|
|
int win_idx;
|
2016-12-13 06:54:17 +00:00
|
|
|
|
2020-07-09 15:31:40 +00:00
|
|
|
for (win_idx = 0; win_idx < win_num; win_idx++) {
|
|
|
|
dbi_writel(pcie, type | win_idx, PCIE_ATU_VIEWPORT);
|
|
|
|
debug("iATU%d:\n", win_idx);
|
2016-12-13 06:54:17 +00:00
|
|
|
debug("\tLOWER PHYS 0x%08x\n",
|
|
|
|
dbi_readl(pcie, PCIE_ATU_LOWER_BASE));
|
|
|
|
debug("\tUPPER PHYS 0x%08x\n",
|
|
|
|
dbi_readl(pcie, PCIE_ATU_UPPER_BASE));
|
2020-07-09 15:31:40 +00:00
|
|
|
if (type == PCIE_ATU_REGION_OUTBOUND) {
|
|
|
|
debug("\tLOWER BUS 0x%08x\n",
|
|
|
|
dbi_readl(pcie, PCIE_ATU_LOWER_TARGET));
|
|
|
|
debug("\tUPPER BUS 0x%08x\n",
|
|
|
|
dbi_readl(pcie, PCIE_ATU_UPPER_TARGET));
|
|
|
|
debug("\tLIMIT 0x%08x\n",
|
|
|
|
dbi_readl(pcie, PCIE_ATU_LIMIT));
|
|
|
|
}
|
2016-12-13 06:54:17 +00:00
|
|
|
debug("\tCR1 0x%08x\n",
|
|
|
|
dbi_readl(pcie, PCIE_ATU_CR1));
|
|
|
|
debug("\tCR2 0x%08x\n",
|
|
|
|
dbi_readl(pcie, PCIE_ATU_CR2));
|
|
|
|
}
|
|
|
|
}
|