123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- // SPDX-License-Identifier: GPL-2.0+ OR X11
- /*
- * Copyright 2018-2019 NXP
- *
- * PCIe Gen4 driver for NXP Layerscape SoCs
- * Author: Hou Zhiqiang <Minder.Hou@gmail.com>
- */
- #include <common.h>
- #include <log.h>
- #include <asm/arch/fsl_serdes.h>
- #include <pci.h>
- #include <asm/io.h>
- #include <errno.h>
- #include <malloc.h>
- #include <dm.h>
- #include <linux/sizes.h>
- #include "pcie_layerscape_gen4.h"
- DECLARE_GLOBAL_DATA_PTR;
- LIST_HEAD(ls_pcie_g4_list);
- static u64 bar_size[4] = {
- PCIE_BAR0_SIZE,
- PCIE_BAR1_SIZE,
- PCIE_BAR2_SIZE,
- PCIE_BAR4_SIZE
- };
- static int ls_pcie_g4_ltssm(struct ls_pcie_g4 *pcie)
- {
- u32 state;
- state = pf_ctrl_readl(pcie, PCIE_LTSSM_STA) & LTSSM_STATE_MASK;
- return state;
- }
- static int ls_pcie_g4_link_up(struct ls_pcie_g4 *pcie)
- {
- int ltssm;
- ltssm = ls_pcie_g4_ltssm(pcie);
- if (ltssm != LTSSM_PCIE_L0)
- return 0;
- return 1;
- }
- static void ls_pcie_g4_ep_enable_cfg(struct ls_pcie_g4 *pcie)
- {
- ccsr_writel(pcie, GPEX_CFG_READY, PCIE_CONFIG_READY);
- }
- static void ls_pcie_g4_cfg_set_target(struct ls_pcie_g4 *pcie, u32 target)
- {
- ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(0), target);
- ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(0), 0);
- }
- static int ls_pcie_g4_outbound_win_set(struct ls_pcie_g4 *pcie, int idx,
- int type, u64 phys, u64 bus_addr,
- pci_size_t size)
- {
- u32 val;
- u32 size_h, size_l;
- if (idx >= PAB_WINS_NUM)
- return -EINVAL;
- size_h = upper_32_bits(~(size - 1));
- size_l = lower_32_bits(~(size - 1));
- val = ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(idx));
- val &= ~((AXI_AMAP_CTRL_TYPE_MASK << AXI_AMAP_CTRL_TYPE_SHIFT) |
- (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT) |
- AXI_AMAP_CTRL_EN);
- val |= ((type & AXI_AMAP_CTRL_TYPE_MASK) << AXI_AMAP_CTRL_TYPE_SHIFT) |
- ((size_l >> AXI_AMAP_CTRL_SIZE_SHIFT) <<
- AXI_AMAP_CTRL_SIZE_SHIFT) | AXI_AMAP_CTRL_EN;
- ccsr_writel(pcie, PAB_AXI_AMAP_CTRL(idx), val);
- ccsr_writel(pcie, PAB_AXI_AMAP_AXI_WIN(idx), lower_32_bits(phys));
- ccsr_writel(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(idx), upper_32_bits(phys));
- ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr));
- ccsr_writel(pcie, PAB_AXI_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr));
- ccsr_writel(pcie, PAB_EXT_AXI_AMAP_SIZE(idx), size_h);
- return 0;
- }
- static int ls_pcie_g4_rc_inbound_win_set(struct ls_pcie_g4 *pcie, int idx,
- int type, u64 phys, u64 bus_addr,
- pci_size_t size)
- {
- u32 val;
- pci_size_t win_size = ~(size - 1);
- val = ccsr_readl(pcie, PAB_PEX_AMAP_CTRL(idx));
- val &= ~(PEX_AMAP_CTRL_TYPE_MASK << PEX_AMAP_CTRL_TYPE_SHIFT);
- val &= ~(PEX_AMAP_CTRL_EN_MASK << PEX_AMAP_CTRL_EN_SHIFT);
- val = (val | (type << PEX_AMAP_CTRL_TYPE_SHIFT));
- val = (val | (1 << PEX_AMAP_CTRL_EN_SHIFT));
- ccsr_writel(pcie, PAB_PEX_AMAP_CTRL(idx),
- val | lower_32_bits(win_size));
- ccsr_writel(pcie, PAB_EXT_PEX_AMAP_SIZE(idx), upper_32_bits(win_size));
- ccsr_writel(pcie, PAB_PEX_AMAP_AXI_WIN(idx), lower_32_bits(phys));
- ccsr_writel(pcie, PAB_EXT_PEX_AMAP_AXI_WIN(idx), upper_32_bits(phys));
- ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_L(idx), lower_32_bits(bus_addr));
- ccsr_writel(pcie, PAB_PEX_AMAP_PEX_WIN_H(idx), upper_32_bits(bus_addr));
- return 0;
- }
- static void ls_pcie_g4_dump_wins(struct ls_pcie_g4 *pcie, int wins)
- {
- int i;
- for (i = 0; i < wins; i++) {
- debug("APIO Win%d:\n", i);
- debug("\tLOWER PHYS: 0x%08x\n",
- ccsr_readl(pcie, PAB_AXI_AMAP_AXI_WIN(i)));
- debug("\tUPPER PHYS: 0x%08x\n",
- ccsr_readl(pcie, PAB_EXT_AXI_AMAP_AXI_WIN(i)));
- debug("\tLOWER BUS: 0x%08x\n",
- ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_L(i)));
- debug("\tUPPER BUS: 0x%08x\n",
- ccsr_readl(pcie, PAB_AXI_AMAP_PEX_WIN_H(i)));
- debug("\tSIZE: 0x%08x\n",
- ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i)) &
- (AXI_AMAP_CTRL_SIZE_MASK << AXI_AMAP_CTRL_SIZE_SHIFT));
- debug("\tEXT_SIZE: 0x%08x\n",
- ccsr_readl(pcie, PAB_EXT_AXI_AMAP_SIZE(i)));
- debug("\tPARAM: 0x%08x\n",
- ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(i)));
- debug("\tCTRL: 0x%08x\n",
- ccsr_readl(pcie, PAB_AXI_AMAP_CTRL(i)));
- }
- }
- static void ls_pcie_g4_setup_wins(struct ls_pcie_g4 *pcie)
- {
- struct pci_region *io, *mem, *pref;
- int idx = 1;
- /* INBOUND WIN */
- ls_pcie_g4_rc_inbound_win_set(pcie, 0, IB_TYPE_MEM_F, 0, 0, SIZE_1T);
- /* OUTBOUND WIN 0: CFG */
- ls_pcie_g4_outbound_win_set(pcie, 0, PAB_AXI_TYPE_CFG,
- pcie->cfg_res.start, 0,
- fdt_resource_size(&pcie->cfg_res));
- pci_get_regions(pcie->bus, &io, &mem, &pref);
- if (io)
- /* OUTBOUND WIN: IO */
- ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_IO,
- io->phys_start, io->bus_start,
- io->size);
- if (mem)
- /* OUTBOUND WIN: MEM */
- ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM,
- mem->phys_start, mem->bus_start,
- mem->size);
- if (pref)
- /* OUTBOUND WIN: perf MEM */
- ls_pcie_g4_outbound_win_set(pcie, idx++, PAB_AXI_TYPE_MEM,
- pref->phys_start, pref->bus_start,
- pref->size);
- ls_pcie_g4_dump_wins(pcie, idx);
- }
- /* Return 0 if the address is valid, -errno if not valid */
- static int ls_pcie_g4_addr_valid(struct ls_pcie_g4 *pcie, pci_dev_t bdf)
- {
- struct udevice *bus = pcie->bus;
- if (pcie->mode == PCI_HEADER_TYPE_NORMAL)
- return -ENODEV;
- if (!pcie->enabled)
- return -ENXIO;
- if (PCI_BUS(bdf) < dev_seq(bus))
- return -EINVAL;
- if ((PCI_BUS(bdf) > dev_seq(bus)) && (!ls_pcie_g4_link_up(pcie)))
- return -EINVAL;
- if (PCI_BUS(bdf) <= (dev_seq(bus) + 1) && (PCI_DEV(bdf) > 0))
- return -EINVAL;
- return 0;
- }
- void *ls_pcie_g4_conf_address(struct ls_pcie_g4 *pcie, pci_dev_t bdf,
- int offset)
- {
- struct udevice *bus = pcie->bus;
- u32 target;
- if (PCI_BUS(bdf) == dev_seq(bus)) {
- if (offset < INDIRECT_ADDR_BNDRY) {
- ccsr_set_page(pcie, 0);
- return pcie->ccsr + offset;
- }
- ccsr_set_page(pcie, OFFSET_TO_PAGE_IDX(offset));
- return pcie->ccsr + OFFSET_TO_PAGE_ADDR(offset);
- }
- target = PAB_TARGET_BUS(PCI_BUS(bdf) - dev_seq(bus)) |
- PAB_TARGET_DEV(PCI_DEV(bdf)) |
- PAB_TARGET_FUNC(PCI_FUNC(bdf));
- ls_pcie_g4_cfg_set_target(pcie, target);
- return pcie->cfg + offset;
- }
- static int ls_pcie_g4_read_config(const struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong *valuep,
- enum pci_size_t size)
- {
- struct ls_pcie_g4 *pcie = dev_get_priv(bus);
- void *address;
- int ret = 0;
- if (ls_pcie_g4_addr_valid(pcie, bdf)) {
- *valuep = pci_get_ff(size);
- return 0;
- }
- address = ls_pcie_g4_conf_address(pcie, bdf, offset);
- switch (size) {
- case PCI_SIZE_8:
- *valuep = readb(address);
- break;
- case PCI_SIZE_16:
- *valuep = readw(address);
- break;
- case PCI_SIZE_32:
- *valuep = readl(address);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
- }
- static int ls_pcie_g4_write_config(struct udevice *bus, pci_dev_t bdf,
- uint offset, ulong value,
- enum pci_size_t size)
- {
- struct ls_pcie_g4 *pcie = dev_get_priv(bus);
- void *address;
- if (ls_pcie_g4_addr_valid(pcie, bdf))
- return 0;
- address = ls_pcie_g4_conf_address(pcie, bdf, offset);
- switch (size) {
- case PCI_SIZE_8:
- writeb(value, address);
- return 0;
- case PCI_SIZE_16:
- writew(value, address);
- return 0;
- case PCI_SIZE_32:
- writel(value, address);
- return 0;
- default:
- return -EINVAL;
- }
- }
- static void ls_pcie_g4_setup_ctrl(struct ls_pcie_g4 *pcie)
- {
- u32 val;
- /* Fix class code */
- val = ccsr_readl(pcie, GPEX_CLASSCODE);
- val &= ~(GPEX_CLASSCODE_MASK << GPEX_CLASSCODE_SHIFT);
- val |= PCI_CLASS_BRIDGE_PCI << GPEX_CLASSCODE_SHIFT;
- ccsr_writel(pcie, GPEX_CLASSCODE, val);
- /* Enable APIO and Memory/IO/CFG Wins */
- val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0));
- val |= APIO_EN | MEM_WIN_EN | IO_WIN_EN | CFG_WIN_EN;
- ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val);
- ls_pcie_g4_setup_wins(pcie);
- pcie->stream_id_cur = 0;
- }
- static void ls_pcie_g4_ep_inbound_win_set(struct ls_pcie_g4 *pcie, int pf,
- int bar, u64 phys)
- {
- u32 val;
- /* PF BAR1 is for MSI-X and only need to enable */
- if (bar == 1) {
- ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), BAR_AMAP_EN);
- return;
- }
- val = upper_32_bits(phys);
- ccsr_writel(pcie, PAB_EXT_PEX_BAR_AMAP(pf, bar), val);
- val = lower_32_bits(phys) | BAR_AMAP_EN;
- ccsr_writel(pcie, PAB_PEX_BAR_AMAP(pf, bar), val);
- }
- static void ls_pcie_g4_ep_setup_wins(struct ls_pcie_g4 *pcie, int pf)
- {
- u64 phys;
- int bar;
- u32 val;
- if ((!pcie->sriov_support && pf > LS_G4_PF0) || pf > LS_G4_PF1)
- return;
- phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR_SIZE * 4 * pf;
- for (bar = 0; bar < PF_BAR_NUM; bar++) {
- ls_pcie_g4_ep_inbound_win_set(pcie, pf, bar, phys);
- phys += PCIE_BAR_SIZE;
- }
- /* OUTBOUND: map MEM */
- ls_pcie_g4_outbound_win_set(pcie, pf, PAB_AXI_TYPE_MEM,
- pcie->cfg_res.start +
- CONFIG_SYS_PCI_MEMORY_SIZE * pf, 0x0,
- CONFIG_SYS_PCI_MEMORY_SIZE);
- val = ccsr_readl(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf));
- val &= ~FUNC_NUM_PCIE_MASK;
- val |= pf;
- ccsr_writel(pcie, PAB_AXI_AMAP_PCI_HDR_PARAM(pf), val);
- }
- static void ls_pcie_g4_ep_enable_bar(struct ls_pcie_g4 *pcie, int pf,
- int bar, bool vf_bar, bool enable)
- {
- u32 val;
- u32 bar_pos = BAR_POS(bar, pf, vf_bar);
- val = ccsr_readl(pcie, GPEX_BAR_ENABLE);
- if (enable)
- val |= 1 << bar_pos;
- else
- val &= ~(1 << bar_pos);
- ccsr_writel(pcie, GPEX_BAR_ENABLE, val);
- }
- static void ls_pcie_g4_ep_set_bar_size(struct ls_pcie_g4 *pcie, int pf,
- int bar, bool vf_bar, u64 size)
- {
- u32 bar_pos = BAR_POS(bar, pf, vf_bar);
- u32 mask_l = lower_32_bits(~(size - 1));
- u32 mask_h = upper_32_bits(~(size - 1));
- ccsr_writel(pcie, GPEX_BAR_SELECT, bar_pos);
- ccsr_writel(pcie, GPEX_BAR_SIZE_LDW, mask_l);
- ccsr_writel(pcie, GPEX_BAR_SIZE_UDW, mask_h);
- }
- static void ls_pcie_g4_ep_setup_bar(struct ls_pcie_g4 *pcie, int pf,
- int bar, bool vf_bar, u64 size)
- {
- bool en = size ? true : false;
- ls_pcie_g4_ep_enable_bar(pcie, pf, bar, vf_bar, en);
- ls_pcie_g4_ep_set_bar_size(pcie, pf, bar, vf_bar, size);
- }
- static void ls_pcie_g4_ep_setup_bars(struct ls_pcie_g4 *pcie, int pf)
- {
- int bar;
- /* Setup PF BARs */
- for (bar = 0; bar < PF_BAR_NUM; bar++)
- ls_pcie_g4_ep_setup_bar(pcie, pf, bar, false, bar_size[bar]);
- if (!pcie->sriov_support)
- return;
- /* Setup VF BARs */
- for (bar = 0; bar < VF_BAR_NUM; bar++)
- ls_pcie_g4_ep_setup_bar(pcie, pf, bar, true, bar_size[bar]);
- }
- static void ls_pcie_g4_set_sriov(struct ls_pcie_g4 *pcie, int pf)
- {
- unsigned int val;
- val = ccsr_readl(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf));
- val &= ~(TTL_VF_MASK << TTL_VF_SHIFT);
- val |= PCIE_VF_NUM << TTL_VF_SHIFT;
- val &= ~(INI_VF_MASK << INI_VF_SHIFT);
- val |= PCIE_VF_NUM << INI_VF_SHIFT;
- ccsr_writel(pcie, GPEX_SRIOV_INIT_VFS_TOTAL_VF(pf), val);
- val = ccsr_readl(pcie, PCIE_SRIOV_VF_OFFSET_STRIDE);
- val += PCIE_VF_NUM * pf - pf;
- ccsr_writel(pcie, GPEX_SRIOV_VF_OFFSET_STRIDE(pf), val);
- }
- static void ls_pcie_g4_setup_ep(struct ls_pcie_g4 *pcie)
- {
- u32 pf, sriov;
- u32 val;
- int i;
- /* Enable APIO and Memory Win */
- val = ccsr_readl(pcie, PAB_AXI_PIO_CTRL(0));
- val |= APIO_EN | MEM_WIN_EN;
- ccsr_writel(pcie, PAB_AXI_PIO_CTRL(0), val);
- sriov = ccsr_readl(pcie, PCIE_SRIOV_CAPABILITY);
- if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV)
- pcie->sriov_support = 1;
- pf = pcie->sriov_support ? PCIE_PF_NUM : 1;
- for (i = 0; i < pf; i++) {
- ls_pcie_g4_ep_setup_bars(pcie, i);
- ls_pcie_g4_ep_setup_wins(pcie, i);
- if (pcie->sriov_support)
- ls_pcie_g4_set_sriov(pcie, i);
- }
- ls_pcie_g4_ep_enable_cfg(pcie);
- ls_pcie_g4_dump_wins(pcie, pf);
- }
- static int ls_pcie_g4_probe(struct udevice *dev)
- {
- struct ls_pcie_g4 *pcie = dev_get_priv(dev);
- const void *fdt = gd->fdt_blob;
- int node = dev_of_offset(dev);
- u32 link_ctrl_sta;
- u32 val;
- int ret;
- pcie->bus = dev;
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
- "ccsr", &pcie->ccsr_res);
- if (ret) {
- printf("ls-pcie-g4: resource \"ccsr\" not found\n");
- return ret;
- }
- pcie->idx = (pcie->ccsr_res.start - PCIE_SYS_BASE_ADDR) /
- PCIE_CCSR_SIZE;
- list_add(&pcie->list, &ls_pcie_g4_list);
- pcie->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx));
- if (!pcie->enabled) {
- printf("PCIe%d: %s disabled\n", pcie->idx, dev->name);
- return 0;
- }
- pcie->ccsr = map_physmem(pcie->ccsr_res.start,
- fdt_resource_size(&pcie->ccsr_res),
- MAP_NOCACHE);
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
- "config", &pcie->cfg_res);
- if (ret) {
- printf("%s: resource \"config\" not found\n", dev->name);
- return ret;
- }
- pcie->cfg = map_physmem(pcie->cfg_res.start,
- fdt_resource_size(&pcie->cfg_res),
- MAP_NOCACHE);
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
- "lut", &pcie->lut_res);
- if (ret) {
- printf("ls-pcie-g4: resource \"lut\" not found\n");
- return ret;
- }
- pcie->lut = map_physmem(pcie->lut_res.start,
- fdt_resource_size(&pcie->lut_res),
- MAP_NOCACHE);
- ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
- "pf_ctrl", &pcie->pf_ctrl_res);
- if (ret) {
- printf("ls-pcie-g4: resource \"pf_ctrl\" not found\n");
- return ret;
- }
- pcie->pf_ctrl = map_physmem(pcie->pf_ctrl_res.start,
- fdt_resource_size(&pcie->pf_ctrl_res),
- MAP_NOCACHE);
- pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian");
- debug("%s ccsr:%lx, cfg:0x%lx, big-endian:%d\n",
- dev->name, (unsigned long)pcie->ccsr, (unsigned long)pcie->cfg,
- pcie->big_endian);
- pcie->mode = readb(pcie->ccsr + PCI_HEADER_TYPE) & 0x7f;
- if (pcie->mode == PCI_HEADER_TYPE_NORMAL) {
- printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint");
- ls_pcie_g4_setup_ep(pcie);
- } else {
- printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex");
- ls_pcie_g4_setup_ctrl(pcie);
- }
- /* Enable Amba & PEX PIO */
- val = ccsr_readl(pcie, PAB_CTRL);
- val |= PAB_CTRL_APIO_EN | PAB_CTRL_PPIO_EN;
- ccsr_writel(pcie, PAB_CTRL, val);
- val = ccsr_readl(pcie, PAB_PEX_PIO_CTRL(0));
- val |= PPIO_EN;
- ccsr_writel(pcie, PAB_PEX_PIO_CTRL(0), val);
- if (!ls_pcie_g4_link_up(pcie)) {
- /* Let the user know there's no PCIe link */
- printf(": no link\n");
- return 0;
- }
- /* Print the negotiated PCIe link width */
- link_ctrl_sta = ccsr_readl(pcie, PCIE_LINK_CTRL_STA);
- printf(": x%d gen%d\n",
- (link_ctrl_sta >> PCIE_LINK_WIDTH_SHIFT & PCIE_LINK_WIDTH_MASK),
- (link_ctrl_sta >> PCIE_LINK_SPEED_SHIFT) & PCIE_LINK_SPEED_MASK);
- return 0;
- }
- static const struct dm_pci_ops ls_pcie_g4_ops = {
- .read_config = ls_pcie_g4_read_config,
- .write_config = ls_pcie_g4_write_config,
- };
- static const struct udevice_id ls_pcie_g4_ids[] = {
- { .compatible = "fsl,lx2160a-pcie" },
- { }
- };
- U_BOOT_DRIVER(pcie_layerscape_gen4) = {
- .name = "pcie_layerscape_gen4",
- .id = UCLASS_PCI,
- .of_match = ls_pcie_g4_ids,
- .ops = &ls_pcie_g4_ops,
- .probe = ls_pcie_g4_probe,
- .priv_auto = sizeof(struct ls_pcie_g4),
- };
|