diff options
| -rw-r--r-- | drivers/pci/controller/pci-mvebu.c | 136 |
1 files changed, 63 insertions, 73 deletions
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index 05f863435e5e..9055f03596ef 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c | |||
| @@ -125,6 +125,7 @@ struct mvebu_pcie { | |||
| 125 | struct platform_device *pdev; | 125 | struct platform_device *pdev; |
| 126 | struct mvebu_pcie_port *ports; | 126 | struct mvebu_pcie_port *ports; |
| 127 | struct msi_controller *msi; | 127 | struct msi_controller *msi; |
| 128 | struct list_head resources; | ||
| 128 | struct resource io; | 129 | struct resource io; |
| 129 | struct resource realio; | 130 | struct resource realio; |
| 130 | struct resource mem; | 131 | struct resource mem; |
| @@ -800,7 +801,7 @@ static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie, | |||
| 800 | static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, | 801 | static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, |
| 801 | int where, int size, u32 val) | 802 | int where, int size, u32 val) |
| 802 | { | 803 | { |
| 803 | struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); | 804 | struct mvebu_pcie *pcie = bus->sysdata; |
| 804 | struct mvebu_pcie_port *port; | 805 | struct mvebu_pcie_port *port; |
| 805 | int ret; | 806 | int ret; |
| 806 | 807 | ||
| @@ -826,7 +827,7 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, | |||
| 826 | static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | 827 | static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, |
| 827 | int size, u32 *val) | 828 | int size, u32 *val) |
| 828 | { | 829 | { |
| 829 | struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); | 830 | struct mvebu_pcie *pcie = bus->sysdata; |
| 830 | struct mvebu_pcie_port *port; | 831 | struct mvebu_pcie_port *port; |
| 831 | int ret; | 832 | int ret; |
| 832 | 833 | ||
| @@ -857,36 +858,6 @@ static struct pci_ops mvebu_pcie_ops = { | |||
| 857 | .write = mvebu_pcie_wr_conf, | 858 | .write = mvebu_pcie_wr_conf, |
| 858 | }; | 859 | }; |
| 859 | 860 | ||
| 860 | static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys) | ||
| 861 | { | ||
| 862 | struct mvebu_pcie *pcie = sys_to_pcie(sys); | ||
| 863 | int err, i; | ||
| 864 | |||
| 865 | pcie->mem.name = "PCI MEM"; | ||
| 866 | pcie->realio.name = "PCI I/O"; | ||
| 867 | |||
| 868 | if (resource_size(&pcie->realio) != 0) | ||
| 869 | pci_add_resource_offset(&sys->resources, &pcie->realio, | ||
| 870 | sys->io_offset); | ||
| 871 | |||
| 872 | pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); | ||
| 873 | pci_add_resource(&sys->resources, &pcie->busn); | ||
| 874 | |||
| 875 | err = devm_request_pci_bus_resources(&pcie->pdev->dev, &sys->resources); | ||
| 876 | if (err) | ||
| 877 | return 0; | ||
| 878 | |||
| 879 | for (i = 0; i < pcie->nports; i++) { | ||
| 880 | struct mvebu_pcie_port *port = &pcie->ports[i]; | ||
| 881 | |||
| 882 | if (!port->base) | ||
| 883 | continue; | ||
| 884 | mvebu_pcie_setup_hw(port); | ||
| 885 | } | ||
| 886 | |||
| 887 | return 1; | ||
| 888 | } | ||
| 889 | |||
| 890 | static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, | 861 | static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, |
| 891 | const struct resource *res, | 862 | const struct resource *res, |
| 892 | resource_size_t start, | 863 | resource_size_t start, |
| @@ -917,26 +888,6 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, | |||
| 917 | return start; | 888 | return start; |
| 918 | } | 889 | } |
| 919 | 890 | ||
| 920 | static void mvebu_pcie_enable(struct mvebu_pcie *pcie) | ||
| 921 | { | ||
| 922 | struct hw_pci hw; | ||
| 923 | |||
| 924 | memset(&hw, 0, sizeof(hw)); | ||
| 925 | |||
| 926 | #ifdef CONFIG_PCI_MSI | ||
| 927 | hw.msi_ctrl = pcie->msi; | ||
| 928 | #endif | ||
| 929 | |||
| 930 | hw.nr_controllers = 1; | ||
| 931 | hw.private_data = (void **)&pcie; | ||
| 932 | hw.setup = mvebu_pcie_setup; | ||
| 933 | hw.map_irq = of_irq_parse_and_map_pci; | ||
| 934 | hw.ops = &mvebu_pcie_ops; | ||
| 935 | hw.align_resource = mvebu_pcie_align_resource; | ||
| 936 | |||
| 937 | pci_common_init_dev(&pcie->pdev->dev, &hw); | ||
| 938 | } | ||
| 939 | |||
| 940 | /* | 891 | /* |
| 941 | * Looks up the list of register addresses encoded into the reg = | 892 | * Looks up the list of register addresses encoded into the reg = |
| 942 | * <...> property for one that matches the given port/lane. Once | 893 | * <...> property for one that matches the given port/lane. Once |
| @@ -1190,28 +1141,39 @@ static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port) | |||
| 1190 | clk_disable_unprepare(port->clk); | 1141 | clk_disable_unprepare(port->clk); |
| 1191 | } | 1142 | } |
| 1192 | 1143 | ||
| 1193 | static int mvebu_pcie_probe(struct platform_device *pdev) | 1144 | /* |
| 1145 | * We can't use devm_of_pci_get_host_bridge_resources() because we | ||
| 1146 | * need to parse our special DT properties encoding the MEM and IO | ||
| 1147 | * apertures. | ||
| 1148 | */ | ||
| 1149 | static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie) | ||
| 1194 | { | 1150 | { |
| 1195 | struct device *dev = &pdev->dev; | 1151 | struct device *dev = &pcie->pdev->dev; |
| 1196 | struct mvebu_pcie *pcie; | ||
| 1197 | struct device_node *np = dev->of_node; | 1152 | struct device_node *np = dev->of_node; |
| 1198 | struct device_node *child; | 1153 | unsigned int i; |
| 1199 | int num, i, ret; | 1154 | int ret; |
| 1200 | 1155 | ||
| 1201 | pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); | 1156 | INIT_LIST_HEAD(&pcie->resources); |
| 1202 | if (!pcie) | ||
| 1203 | return -ENOMEM; | ||
| 1204 | 1157 | ||
| 1205 | pcie->pdev = pdev; | 1158 | /* Get the bus range */ |
| 1206 | platform_set_drvdata(pdev, pcie); | 1159 | ret = of_pci_parse_bus_range(np, &pcie->busn); |
| 1160 | if (ret) { | ||
| 1161 | dev_err(dev, "failed to parse bus-range property: %d\n", ret); | ||
| 1162 | return ret; | ||
| 1163 | } | ||
| 1164 | pci_add_resource(&pcie->resources, &pcie->busn); | ||
| 1207 | 1165 | ||
| 1208 | /* Get the PCIe memory and I/O aperture */ | 1166 | /* Get the PCIe memory aperture */ |
| 1209 | mvebu_mbus_get_pcie_mem_aperture(&pcie->mem); | 1167 | mvebu_mbus_get_pcie_mem_aperture(&pcie->mem); |
| 1210 | if (resource_size(&pcie->mem) == 0) { | 1168 | if (resource_size(&pcie->mem) == 0) { |
| 1211 | dev_err(dev, "invalid memory aperture size\n"); | 1169 | dev_err(dev, "invalid memory aperture size\n"); |
| 1212 | return -EINVAL; | 1170 | return -EINVAL; |
| 1213 | } | 1171 | } |
| 1214 | 1172 | ||
| 1173 | pcie->mem.name = "PCI MEM"; | ||
| 1174 | pci_add_resource(&pcie->resources, &pcie->mem); | ||
| 1175 | |||
| 1176 | /* Get the PCIe IO aperture */ | ||
| 1215 | mvebu_mbus_get_pcie_io_aperture(&pcie->io); | 1177 | mvebu_mbus_get_pcie_io_aperture(&pcie->io); |
| 1216 | 1178 | ||
| 1217 | if (resource_size(&pcie->io) != 0) { | 1179 | if (resource_size(&pcie->io) != 0) { |
| @@ -1220,19 +1182,38 @@ static int mvebu_pcie_probe(struct platform_device *pdev) | |||
| 1220 | pcie->realio.end = min_t(resource_size_t, | 1182 | pcie->realio.end = min_t(resource_size_t, |
| 1221 | IO_SPACE_LIMIT - SZ_64K, | 1183 | IO_SPACE_LIMIT - SZ_64K, |
| 1222 | resource_size(&pcie->io) - 1); | 1184 | resource_size(&pcie->io) - 1); |
| 1185 | pcie->realio.name = "PCI I/O"; | ||
| 1223 | 1186 | ||
| 1224 | for (i = 0; i < resource_size(&pcie->realio); i += SZ_64K) | 1187 | for (i = 0; i < resource_size(&pcie->realio); i += SZ_64K) |
| 1225 | pci_ioremap_io(i, pcie->io.start + i); | 1188 | pci_ioremap_io(i, pcie->io.start + i); |
| 1226 | } else | ||
| 1227 | pcie->realio = pcie->io; | ||
| 1228 | 1189 | ||
| 1229 | /* Get the bus range */ | 1190 | pci_add_resource(&pcie->resources, &pcie->realio); |
| 1230 | ret = of_pci_parse_bus_range(np, &pcie->busn); | ||
| 1231 | if (ret) { | ||
| 1232 | dev_err(dev, "failed to parse bus-range property: %d\n", ret); | ||
| 1233 | return ret; | ||
| 1234 | } | 1191 | } |
| 1235 | 1192 | ||
| 1193 | return devm_request_pci_bus_resources(dev, &pcie->resources); | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | static int mvebu_pcie_probe(struct platform_device *pdev) | ||
| 1197 | { | ||
| 1198 | struct device *dev = &pdev->dev; | ||
| 1199 | struct mvebu_pcie *pcie; | ||
| 1200 | struct pci_host_bridge *bridge; | ||
| 1201 | struct device_node *np = dev->of_node; | ||
| 1202 | struct device_node *child; | ||
| 1203 | int num, i, ret; | ||
| 1204 | |||
| 1205 | bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct mvebu_pcie)); | ||
| 1206 | if (!bridge) | ||
| 1207 | return -ENOMEM; | ||
| 1208 | |||
| 1209 | pcie = pci_host_bridge_priv(bridge); | ||
| 1210 | pcie->pdev = pdev; | ||
| 1211 | platform_set_drvdata(pdev, pcie); | ||
| 1212 | |||
| 1213 | ret = mvebu_pcie_parse_request_resources(pcie); | ||
| 1214 | if (ret) | ||
| 1215 | return ret; | ||
| 1216 | |||
| 1236 | num = of_get_available_child_count(np); | 1217 | num = of_get_available_child_count(np); |
| 1237 | 1218 | ||
| 1238 | pcie->ports = devm_kcalloc(dev, num, sizeof(*pcie->ports), GFP_KERNEL); | 1219 | pcie->ports = devm_kcalloc(dev, num, sizeof(*pcie->ports), GFP_KERNEL); |
| @@ -1275,15 +1256,24 @@ static int mvebu_pcie_probe(struct platform_device *pdev) | |||
| 1275 | continue; | 1256 | continue; |
| 1276 | } | 1257 | } |
| 1277 | 1258 | ||
| 1259 | mvebu_pcie_setup_hw(port); | ||
| 1278 | mvebu_pcie_set_local_dev_nr(port, 1); | 1260 | mvebu_pcie_set_local_dev_nr(port, 1); |
| 1279 | mvebu_sw_pci_bridge_init(port); | 1261 | mvebu_sw_pci_bridge_init(port); |
| 1280 | } | 1262 | } |
| 1281 | 1263 | ||
| 1282 | pcie->nports = i; | 1264 | pcie->nports = i; |
| 1283 | 1265 | ||
| 1284 | mvebu_pcie_enable(pcie); | 1266 | list_splice_init(&pcie->resources, &bridge->windows); |
| 1285 | 1267 | bridge->dev.parent = dev; | |
| 1286 | return 0; | 1268 | bridge->sysdata = pcie; |
| 1269 | bridge->busnr = 0; | ||
| 1270 | bridge->ops = &mvebu_pcie_ops; | ||
| 1271 | bridge->map_irq = of_irq_parse_and_map_pci; | ||
| 1272 | bridge->swizzle_irq = pci_common_swizzle; | ||
| 1273 | bridge->align_resource = mvebu_pcie_align_resource; | ||
| 1274 | bridge->msi = pcie->msi; | ||
| 1275 | |||
| 1276 | return pci_host_probe(bridge); | ||
| 1287 | } | 1277 | } |
| 1288 | 1278 | ||
| 1289 | static const struct of_device_id mvebu_pcie_of_match_table[] = { | 1279 | static const struct of_device_id mvebu_pcie_of_match_table[] = { |
