1// SPDX-License-Identifier: GPL-2.0 2/* 3 * (C) Copyright 2019 4 * Heiko Schocher, DENX Software Engineering, hs@denx.de. 5 * 6 */ 7#include <common.h> 8#include <asm/bitops.h> 9#include <pci.h> 10#include <dm.h> 11#include <asm/fsl_law.h> 12 13struct mpc85xx_pci_priv { 14 void __iomem *cfg_addr; 15 void __iomem *cfg_data; 16}; 17 18static int mpc85xx_pci_dm_read_config(const struct udevice *dev, pci_dev_t bdf, 19 uint offset, ulong *value, 20 enum pci_size_t size) 21{ 22 struct mpc85xx_pci_priv *priv = dev_get_priv(dev); 23 u32 addr; 24 25 if (offset > 0xff) { 26 *value = pci_get_ff(size); 27 return 0; 28 } 29 30 /* Skip mpc85xx PCI controller's ATMU inbound registers */ 31 if (PCI_BUS(bdf) == 0 && PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 && 32 (offset & ~3) >= PCI_BASE_ADDRESS_0 && (offset & ~3) <= PCI_BASE_ADDRESS_5) { 33 *value = 0; 34 return 0; 35 } 36 37 addr = PCI_CONF1_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset); 38 out_be32(priv->cfg_addr, addr); 39 sync(); 40 41 switch (size) { 42 case PCI_SIZE_8: 43 *value = in_8(priv->cfg_data + (offset & 3)); 44 break; 45 case PCI_SIZE_16: 46 *value = in_le16(priv->cfg_data + (offset & 2)); 47 break; 48 case PCI_SIZE_32: 49 *value = in_le32(priv->cfg_data); 50 break; 51 } 52 53 return 0; 54} 55 56static int mpc85xx_pci_dm_write_config(struct udevice *dev, pci_dev_t bdf, 57 uint offset, ulong value, 58 enum pci_size_t size) 59{ 60 struct mpc85xx_pci_priv *priv = dev_get_priv(dev); 61 u32 addr; 62 63 if (offset > 0xff) 64 return 0; 65 66 /* Skip mpc85xx PCI controller's ATMU inbound registers */ 67 if (PCI_BUS(bdf) == 0 && PCI_DEV(bdf) == 0 && PCI_FUNC(bdf) == 0 && 68 (offset & ~3) >= PCI_BASE_ADDRESS_0 && (offset & ~3) <= PCI_BASE_ADDRESS_5) 69 return 0; 70 71 addr = PCI_CONF1_ADDRESS(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), offset); 72 out_be32(priv->cfg_addr, addr); 73 sync(); 74 75 switch (size) { 76 case PCI_SIZE_8: 77 out_8(priv->cfg_data + (offset & 3), value); 78 break; 79 case PCI_SIZE_16: 80 out_le16(priv->cfg_data + (offset & 2), value); 81 break; 82 case PCI_SIZE_32: 83 out_le32(priv->cfg_data, value); 84 break; 85 } 86 sync(); 87 88 return 0; 89} 90 91#ifdef CONFIG_FSL_LAW 92static int 93mpc85xx_pci_dm_setup_laws(struct pci_region *io, struct pci_region *mem, 94 struct pci_region *pre) 95{ 96 /* 97 * Unfortunately we have defines for this addresse, 98 * as we have to setup the TLB, and at this stage 99 * we have no access to DT ... may we check here 100 * if the value in the define is the same ? 101 */ 102 if (mem) 103 set_next_law(mem->phys_start, law_size_bits(mem->size), 104 LAW_TRGT_IF_PCI); 105 if (io) 106 set_next_law(io->phys_start, law_size_bits(io->size), 107 LAW_TRGT_IF_PCI); 108 if (pre) 109 set_next_law(pre->phys_start, law_size_bits(pre->size), 110 LAW_TRGT_IF_PCI); 111 112 return 0; 113} 114#endif 115 116static int mpc85xx_pci_dm_probe(struct udevice *dev) 117{ 118 struct mpc85xx_pci_priv *priv = dev_get_priv(dev); 119 struct pci_region *io; 120 struct pci_region *mem; 121 struct pci_region *pre; 122 int count; 123 ccsr_pcix_t *pcix; 124 125 count = pci_get_regions(dev, &io, &mem, &pre); 126 if (count != 2) { 127 printf("%s: wrong count of regions %d only 2 allowed\n", 128 __func__, count); 129 return -EINVAL; 130 } 131 132#ifdef CONFIG_FSL_LAW 133 mpc85xx_pci_dm_setup_laws(io, mem, pre); 134#endif 135 136 pcix = priv->cfg_addr; 137 /* BAR 1: memory */ 138 out_be32(&pcix->potar1, mem->bus_start >> 12); 139 out_be32(&pcix->potear1, (u64)mem->bus_start >> 44); 140 out_be32(&pcix->powbar1, mem->phys_start >> 12); 141 out_be32(&pcix->powbear1, (u64)mem->phys_start >> 44); 142 out_be32(&pcix->powar1, (POWAR_EN | POWAR_MEM_READ | 143 POWAR_MEM_WRITE | (__ilog2(mem->size) - 1))); 144 145 /* BAR 1: IO */ 146 out_be32(&pcix->potar2, io->bus_start >> 12); 147 out_be32(&pcix->potear2, (u64)io->bus_start >> 44); 148 out_be32(&pcix->powbar2, io->phys_start >> 12); 149 out_be32(&pcix->powbear2, (u64)io->phys_start >> 44); 150 out_be32(&pcix->powar2, (POWAR_EN | POWAR_IO_READ | 151 POWAR_IO_WRITE | (__ilog2(io->size) - 1))); 152 153 out_be32(&pcix->pitar1, 0); 154 out_be32(&pcix->piwbar1, 0); 155 out_be32(&pcix->piwar1, (PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | 156 PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | PIWAR_MEM_2G)); 157 158 out_be32(&pcix->powar3, 0); 159 out_be32(&pcix->powar4, 0); 160 out_be32(&pcix->piwar2, 0); 161 out_be32(&pcix->piwar3, 0); 162 163 return 0; 164} 165 166static int mpc85xx_pci_dm_remove(struct udevice *dev) 167{ 168 return 0; 169} 170 171static int mpc85xx_pci_of_to_plat(struct udevice *dev) 172{ 173 struct mpc85xx_pci_priv *priv = dev_get_priv(dev); 174 fdt_addr_t addr; 175 176 addr = devfdt_get_addr_index(dev, 0); 177 if (addr == FDT_ADDR_T_NONE) 178 return -EINVAL; 179 priv->cfg_addr = (void __iomem *)map_physmem(addr, 0, MAP_NOCACHE); 180 priv->cfg_data = (void __iomem *)((ulong)priv->cfg_addr + 4); 181 182 return 0; 183} 184 185static const struct dm_pci_ops mpc85xx_pci_ops = { 186 .read_config = mpc85xx_pci_dm_read_config, 187 .write_config = mpc85xx_pci_dm_write_config, 188}; 189 190static const struct udevice_id mpc85xx_pci_ids[] = { 191 { .compatible = "fsl,mpc8540-pci" }, 192 { } 193}; 194 195U_BOOT_DRIVER(mpc85xx_pci) = { 196 .name = "mpc85xx_pci", 197 .id = UCLASS_PCI, 198 .of_match = mpc85xx_pci_ids, 199 .ops = &mpc85xx_pci_ops, 200 .probe = mpc85xx_pci_dm_probe, 201 .remove = mpc85xx_pci_dm_remove, 202 .of_to_plat = mpc85xx_pci_of_to_plat, 203 .priv_auto = sizeof(struct mpc85xx_pci_priv), 204}; 205