1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * PLDA XpressRich PCIe host controller common functions. 4 * 5 * Copyright (C) 2023 StarFive Technology Co., Ltd. 6 * 7 */ 8 9#include <common.h> 10#include <clk.h> 11#include <dm.h> 12#include <pci.h> 13#include <pci_ids.h> 14#include <asm/global_data.h> 15#include <asm/io.h> 16#include <dm/device_compat.h> 17#include <linux/delay.h> 18#include <linux/iopoll.h> 19#include "pcie_plda_common.h" 20 21static bool plda_pcie_addr_valid(struct pcie_plda *plda, pci_dev_t bdf) 22{ 23 /* 24 * Single device limitation. 25 * PCIe controller contain HW issue that secondary bus of 26 * host bridge emumerate duplicate devices. 27 * Only can access device 0 in secondary bus. 28 */ 29 if (PCI_BUS(bdf) == plda->sec_busno && PCI_DEV(bdf) > 0) 30 return false; 31 32 return true; 33} 34 35static int plda_pcie_conf_address(const struct udevice *udev, pci_dev_t bdf, 36 uint offset, void **paddr) 37{ 38 struct pcie_plda *priv = dev_get_priv(udev); 39 int where = PCIE_ECAM_OFFSET(PCI_BUS(bdf) - dev_seq(udev), 40 PCI_DEV(bdf), PCI_FUNC(bdf), offset); 41 42 if (!plda_pcie_addr_valid(priv, bdf)) 43 return -ENODEV; 44 45 *paddr = (void *)(priv->cfg_base + where); 46 return 0; 47} 48 49int plda_pcie_config_read(const struct udevice *udev, pci_dev_t bdf, 50 uint offset, ulong *valuep, 51 enum pci_size_t size) 52{ 53 return pci_generic_mmap_read_config(udev, plda_pcie_conf_address, 54 bdf, offset, valuep, size); 55} 56 57int plda_pcie_config_write(struct udevice *udev, pci_dev_t bdf, 58 uint offset, ulong value, 59 enum pci_size_t size) 60{ 61 struct pcie_plda *priv = dev_get_priv(udev); 62 int ret; 63 64 ret = pci_generic_mmap_write_config(udev, plda_pcie_conf_address, 65 bdf, offset, value, size); 66 67 /* record secondary bus number */ 68 if (!ret && PCI_BUS(bdf) == dev_seq(udev) && 69 PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 && 70 (offset == PCI_SECONDARY_BUS || 71 (offset == PCI_PRIMARY_BUS && size != PCI_SIZE_8))) { 72 priv->sec_busno = 73 ((offset == PCI_PRIMARY_BUS) ? (value >> 8) : value) & 0xff; 74 priv->sec_busno += dev_seq(udev); 75 debug("Secondary bus number was changed to %d\n", 76 priv->sec_busno); 77 } 78 return ret; 79} 80 81int plda_pcie_set_atr_entry(struct pcie_plda *plda, phys_addr_t src_addr, 82 phys_addr_t trsl_addr, phys_size_t window_size, 83 int trsl_param) 84{ 85 void __iomem *base = 86 plda->reg_base + XR3PCI_ATR_AXI4_SLV0; 87 88 /* Support AXI4 Slave 0 Address Translation Tables 0-7. */ 89 if (plda->atr_table_num >= XR3PCI_ATR_MAX_TABLE_NUM) { 90 dev_err(plda->dev, "ATR table number %d exceeds max num\n", 91 plda->atr_table_num); 92 return -EINVAL; 93 } 94 base += XR3PCI_ATR_TABLE_OFFSET * plda->atr_table_num; 95 plda->atr_table_num++; 96 97 /* 98 * X3PCI_ATR_SRC_ADDR_LOW: 99 * - bit 0: enable entry, 100 * - bits 1-6: ATR window size: total size in bytes: 2^(ATR_WSIZE + 1) 101 * - bits 7-11: reserved 102 * - bits 12-31: start of source address 103 */ 104 writel((lower_32_bits(src_addr) & XR3PCI_ATR_SRC_ADDR_MASK) | 105 (fls(window_size) - 1) << XR3PCI_ATR_SRC_WIN_SIZE_SHIFT | 1, 106 base + XR3PCI_ATR_SRC_ADDR_LOW); 107 writel(upper_32_bits(src_addr), base + XR3PCI_ATR_SRC_ADDR_HIGH); 108 writel((lower_32_bits(trsl_addr) & XR3PCI_ATR_TRSL_ADDR_MASK), 109 base + XR3PCI_ATR_TRSL_ADDR_LOW); 110 writel(upper_32_bits(trsl_addr), base + XR3PCI_ATR_TRSL_ADDR_HIGH); 111 writel(trsl_param, base + XR3PCI_ATR_TRSL_PARAM); 112 113 dev_dbg(plda->dev, "ATR entry: 0x%010llx %s 0x%010llx [0x%010llx] (param: 0x%06x)\n", 114 src_addr, (trsl_param & XR3PCI_ATR_TRSL_DIR) ? "<-" : "->", 115 trsl_addr, (u64)window_size, trsl_param); 116 return 0; 117} 118