diff options
| -rw-r--r-- | drivers/pci/host/pci-mvebu.c | 128 |
1 files changed, 69 insertions, 59 deletions
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 77f8a7c58597..80b2250ea19a 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c | |||
| @@ -120,7 +120,6 @@ struct mvebu_pcie_port { | |||
| 120 | char *name; | 120 | char *name; |
| 121 | void __iomem *base; | 121 | void __iomem *base; |
| 122 | spinlock_t conf_lock; | 122 | spinlock_t conf_lock; |
| 123 | int haslink; | ||
| 124 | u32 port; | 123 | u32 port; |
| 125 | u32 lane; | 124 | u32 lane; |
| 126 | int devfn; | 125 | int devfn; |
| @@ -141,29 +140,39 @@ struct mvebu_pcie_port { | |||
| 141 | size_t iowin_size; | 140 | size_t iowin_size; |
| 142 | }; | 141 | }; |
| 143 | 142 | ||
| 143 | static inline void mvebu_writel(struct mvebu_pcie_port *port, u32 val, u32 reg) | ||
| 144 | { | ||
| 145 | writel(val, port->base + reg); | ||
| 146 | } | ||
| 147 | |||
| 148 | static inline u32 mvebu_readl(struct mvebu_pcie_port *port, u32 reg) | ||
| 149 | { | ||
| 150 | return readl(port->base + reg); | ||
| 151 | } | ||
| 152 | |||
| 144 | static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port) | 153 | static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port) |
| 145 | { | 154 | { |
| 146 | return !(readl(port->base + PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); | 155 | return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); |
| 147 | } | 156 | } |
| 148 | 157 | ||
| 149 | static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr) | 158 | static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie_port *port, int nr) |
| 150 | { | 159 | { |
| 151 | u32 stat; | 160 | u32 stat; |
| 152 | 161 | ||
| 153 | stat = readl(port->base + PCIE_STAT_OFF); | 162 | stat = mvebu_readl(port, PCIE_STAT_OFF); |
| 154 | stat &= ~PCIE_STAT_BUS; | 163 | stat &= ~PCIE_STAT_BUS; |
| 155 | stat |= nr << 8; | 164 | stat |= nr << 8; |
| 156 | writel(stat, port->base + PCIE_STAT_OFF); | 165 | mvebu_writel(port, stat, PCIE_STAT_OFF); |
| 157 | } | 166 | } |
| 158 | 167 | ||
| 159 | static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr) | 168 | static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie_port *port, int nr) |
| 160 | { | 169 | { |
| 161 | u32 stat; | 170 | u32 stat; |
| 162 | 171 | ||
| 163 | stat = readl(port->base + PCIE_STAT_OFF); | 172 | stat = mvebu_readl(port, PCIE_STAT_OFF); |
| 164 | stat &= ~PCIE_STAT_DEV; | 173 | stat &= ~PCIE_STAT_DEV; |
| 165 | stat |= nr << 16; | 174 | stat |= nr << 16; |
| 166 | writel(stat, port->base + PCIE_STAT_OFF); | 175 | mvebu_writel(port, stat, PCIE_STAT_OFF); |
| 167 | } | 176 | } |
| 168 | 177 | ||
| 169 | /* | 178 | /* |
| @@ -181,33 +190,34 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port) | |||
| 181 | 190 | ||
| 182 | /* First, disable and clear BARs and windows. */ | 191 | /* First, disable and clear BARs and windows. */ |
| 183 | for (i = 1; i < 3; i++) { | 192 | for (i = 1; i < 3; i++) { |
| 184 | writel(0, port->base + PCIE_BAR_CTRL_OFF(i)); | 193 | mvebu_writel(port, 0, PCIE_BAR_CTRL_OFF(i)); |
| 185 | writel(0, port->base + PCIE_BAR_LO_OFF(i)); | 194 | mvebu_writel(port, 0, PCIE_BAR_LO_OFF(i)); |
| 186 | writel(0, port->base + PCIE_BAR_HI_OFF(i)); | 195 | mvebu_writel(port, 0, PCIE_BAR_HI_OFF(i)); |
| 187 | } | 196 | } |
| 188 | 197 | ||
| 189 | for (i = 0; i < 5; i++) { | 198 | for (i = 0; i < 5; i++) { |
| 190 | writel(0, port->base + PCIE_WIN04_CTRL_OFF(i)); | 199 | mvebu_writel(port, 0, PCIE_WIN04_CTRL_OFF(i)); |
| 191 | writel(0, port->base + PCIE_WIN04_BASE_OFF(i)); | 200 | mvebu_writel(port, 0, PCIE_WIN04_BASE_OFF(i)); |
| 192 | writel(0, port->base + PCIE_WIN04_REMAP_OFF(i)); | 201 | mvebu_writel(port, 0, PCIE_WIN04_REMAP_OFF(i)); |
| 193 | } | 202 | } |
| 194 | 203 | ||
| 195 | writel(0, port->base + PCIE_WIN5_CTRL_OFF); | 204 | mvebu_writel(port, 0, PCIE_WIN5_CTRL_OFF); |
| 196 | writel(0, port->base + PCIE_WIN5_BASE_OFF); | 205 | mvebu_writel(port, 0, PCIE_WIN5_BASE_OFF); |
| 197 | writel(0, port->base + PCIE_WIN5_REMAP_OFF); | 206 | mvebu_writel(port, 0, PCIE_WIN5_REMAP_OFF); |
| 198 | 207 | ||
| 199 | /* Setup windows for DDR banks. Count total DDR size on the fly. */ | 208 | /* Setup windows for DDR banks. Count total DDR size on the fly. */ |
| 200 | size = 0; | 209 | size = 0; |
| 201 | for (i = 0; i < dram->num_cs; i++) { | 210 | for (i = 0; i < dram->num_cs; i++) { |
| 202 | const struct mbus_dram_window *cs = dram->cs + i; | 211 | const struct mbus_dram_window *cs = dram->cs + i; |
| 203 | 212 | ||
| 204 | writel(cs->base & 0xffff0000, | 213 | mvebu_writel(port, cs->base & 0xffff0000, |
| 205 | port->base + PCIE_WIN04_BASE_OFF(i)); | 214 | PCIE_WIN04_BASE_OFF(i)); |
| 206 | writel(0, port->base + PCIE_WIN04_REMAP_OFF(i)); | 215 | mvebu_writel(port, 0, PCIE_WIN04_REMAP_OFF(i)); |
| 207 | writel(((cs->size - 1) & 0xffff0000) | | 216 | mvebu_writel(port, |
| 208 | (cs->mbus_attr << 8) | | 217 | ((cs->size - 1) & 0xffff0000) | |
| 209 | (dram->mbus_dram_target_id << 4) | 1, | 218 | (cs->mbus_attr << 8) | |
| 210 | port->base + PCIE_WIN04_CTRL_OFF(i)); | 219 | (dram->mbus_dram_target_id << 4) | 1, |
| 220 | PCIE_WIN04_CTRL_OFF(i)); | ||
| 211 | 221 | ||
| 212 | size += cs->size; | 222 | size += cs->size; |
| 213 | } | 223 | } |
| @@ -217,41 +227,40 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port) | |||
| 217 | size = 1 << fls(size); | 227 | size = 1 << fls(size); |
| 218 | 228 | ||
| 219 | /* Setup BAR[1] to all DRAM banks. */ | 229 | /* Setup BAR[1] to all DRAM banks. */ |
| 220 | writel(dram->cs[0].base, port->base + PCIE_BAR_LO_OFF(1)); | 230 | mvebu_writel(port, dram->cs[0].base, PCIE_BAR_LO_OFF(1)); |
| 221 | writel(0, port->base + PCIE_BAR_HI_OFF(1)); | 231 | mvebu_writel(port, 0, PCIE_BAR_HI_OFF(1)); |
| 222 | writel(((size - 1) & 0xffff0000) | 1, | 232 | mvebu_writel(port, ((size - 1) & 0xffff0000) | 1, |
| 223 | port->base + PCIE_BAR_CTRL_OFF(1)); | 233 | PCIE_BAR_CTRL_OFF(1)); |
| 224 | } | 234 | } |
| 225 | 235 | ||
| 226 | static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port) | 236 | static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port) |
| 227 | { | 237 | { |
| 228 | u16 cmd; | 238 | u32 cmd, mask; |
| 229 | u32 mask; | ||
| 230 | 239 | ||
| 231 | /* Point PCIe unit MBUS decode windows to DRAM space. */ | 240 | /* Point PCIe unit MBUS decode windows to DRAM space. */ |
| 232 | mvebu_pcie_setup_wins(port); | 241 | mvebu_pcie_setup_wins(port); |
| 233 | 242 | ||
| 234 | /* Master + slave enable. */ | 243 | /* Master + slave enable. */ |
| 235 | cmd = readw(port->base + PCIE_CMD_OFF); | 244 | cmd = mvebu_readl(port, PCIE_CMD_OFF); |
| 236 | cmd |= PCI_COMMAND_IO; | 245 | cmd |= PCI_COMMAND_IO; |
| 237 | cmd |= PCI_COMMAND_MEMORY; | 246 | cmd |= PCI_COMMAND_MEMORY; |
| 238 | cmd |= PCI_COMMAND_MASTER; | 247 | cmd |= PCI_COMMAND_MASTER; |
| 239 | writew(cmd, port->base + PCIE_CMD_OFF); | 248 | mvebu_writel(port, cmd, PCIE_CMD_OFF); |
| 240 | 249 | ||
| 241 | /* Enable interrupt lines A-D. */ | 250 | /* Enable interrupt lines A-D. */ |
| 242 | mask = readl(port->base + PCIE_MASK_OFF); | 251 | mask = mvebu_readl(port, PCIE_MASK_OFF); |
| 243 | mask |= PCIE_MASK_ENABLE_INTS; | 252 | mask |= PCIE_MASK_ENABLE_INTS; |
| 244 | writel(mask, port->base + PCIE_MASK_OFF); | 253 | mvebu_writel(port, mask, PCIE_MASK_OFF); |
| 245 | } | 254 | } |
| 246 | 255 | ||
| 247 | static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port, | 256 | static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port, |
| 248 | struct pci_bus *bus, | 257 | struct pci_bus *bus, |
| 249 | u32 devfn, int where, int size, u32 *val) | 258 | u32 devfn, int where, int size, u32 *val) |
| 250 | { | 259 | { |
| 251 | writel(PCIE_CONF_ADDR(bus->number, devfn, where), | 260 | mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where), |
| 252 | port->base + PCIE_CONF_ADDR_OFF); | 261 | PCIE_CONF_ADDR_OFF); |
| 253 | 262 | ||
| 254 | *val = readl(port->base + PCIE_CONF_DATA_OFF); | 263 | *val = mvebu_readl(port, PCIE_CONF_DATA_OFF); |
| 255 | 264 | ||
| 256 | if (size == 1) | 265 | if (size == 1) |
| 257 | *val = (*val >> (8 * (where & 3))) & 0xff; | 266 | *val = (*val >> (8 * (where & 3))) & 0xff; |
| @@ -265,21 +274,24 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port, | |||
| 265 | struct pci_bus *bus, | 274 | struct pci_bus *bus, |
| 266 | u32 devfn, int where, int size, u32 val) | 275 | u32 devfn, int where, int size, u32 val) |
| 267 | { | 276 | { |
| 268 | int ret = PCIBIOS_SUCCESSFUL; | 277 | u32 _val, shift = 8 * (where & 3); |
| 269 | 278 | ||
| 270 | writel(PCIE_CONF_ADDR(bus->number, devfn, where), | 279 | mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where), |
| 271 | port->base + PCIE_CONF_ADDR_OFF); | 280 | PCIE_CONF_ADDR_OFF); |
| 281 | _val = mvebu_readl(port, PCIE_CONF_DATA_OFF); | ||
| 272 | 282 | ||
| 273 | if (size == 4) | 283 | if (size == 4) |
| 274 | writel(val, port->base + PCIE_CONF_DATA_OFF); | 284 | _val = val; |
| 275 | else if (size == 2) | 285 | else if (size == 2) |
| 276 | writew(val, port->base + PCIE_CONF_DATA_OFF + (where & 3)); | 286 | _val = (_val & ~(0xffff << shift)) | ((val & 0xffff) << shift); |
| 277 | else if (size == 1) | 287 | else if (size == 1) |
| 278 | writeb(val, port->base + PCIE_CONF_DATA_OFF + (where & 3)); | 288 | _val = (_val & ~(0xff << shift)) | ((val & 0xff) << shift); |
| 279 | else | 289 | else |
| 280 | ret = PCIBIOS_BAD_REGISTER_NUMBER; | 290 | return PCIBIOS_BAD_REGISTER_NUMBER; |
| 281 | 291 | ||
| 282 | return ret; | 292 | mvebu_writel(port, _val, PCIE_CONF_DATA_OFF); |
| 293 | |||
| 294 | return PCIBIOS_SUCCESSFUL; | ||
| 283 | } | 295 | } |
| 284 | 296 | ||
| 285 | static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) | 297 | static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port) |
| @@ -560,7 +572,7 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, | |||
| 560 | if (bus->number == 0) | 572 | if (bus->number == 0) |
| 561 | return mvebu_sw_pci_bridge_write(port, where, size, val); | 573 | return mvebu_sw_pci_bridge_write(port, where, size, val); |
| 562 | 574 | ||
| 563 | if (!port->haslink) | 575 | if (!mvebu_pcie_link_up(port)) |
| 564 | return PCIBIOS_DEVICE_NOT_FOUND; | 576 | return PCIBIOS_DEVICE_NOT_FOUND; |
| 565 | 577 | ||
| 566 | /* | 578 | /* |
| @@ -602,7 +614,7 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | |||
| 602 | if (bus->number == 0) | 614 | if (bus->number == 0) |
| 603 | return mvebu_sw_pci_bridge_read(port, where, size, val); | 615 | return mvebu_sw_pci_bridge_read(port, where, size, val); |
| 604 | 616 | ||
| 605 | if (!port->haslink) { | 617 | if (!mvebu_pcie_link_up(port)) { |
| 606 | *val = 0xffffffff; | 618 | *val = 0xffffffff; |
| 607 | return PCIBIOS_DEVICE_NOT_FOUND; | 619 | return PCIBIOS_DEVICE_NOT_FOUND; |
| 608 | } | 620 | } |
| @@ -681,17 +693,17 @@ static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys) | |||
| 681 | return bus; | 693 | return bus; |
| 682 | } | 694 | } |
| 683 | 695 | ||
| 684 | void mvebu_pcie_add_bus(struct pci_bus *bus) | 696 | static void mvebu_pcie_add_bus(struct pci_bus *bus) |
| 685 | { | 697 | { |
| 686 | struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); | 698 | struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata); |
| 687 | bus->msi = pcie->msi; | 699 | bus->msi = pcie->msi; |
| 688 | } | 700 | } |
| 689 | 701 | ||
| 690 | resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, | 702 | static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev, |
| 691 | const struct resource *res, | 703 | const struct resource *res, |
| 692 | resource_size_t start, | 704 | resource_size_t start, |
| 693 | resource_size_t size, | 705 | resource_size_t size, |
| 694 | resource_size_t align) | 706 | resource_size_t align) |
| 695 | { | 707 | { |
| 696 | if (dev->bus->number != 0) | 708 | if (dev->bus->number != 0) |
| 697 | return start; | 709 | return start; |
| @@ -950,14 +962,12 @@ static int mvebu_pcie_probe(struct platform_device *pdev) | |||
| 950 | 962 | ||
| 951 | mvebu_pcie_set_local_dev_nr(port, 1); | 963 | mvebu_pcie_set_local_dev_nr(port, 1); |
| 952 | 964 | ||
| 953 | if (mvebu_pcie_link_up(port)) { | 965 | port->clk = of_clk_get_by_name(child, NULL); |
| 954 | port->haslink = 1; | 966 | if (IS_ERR(port->clk)) { |
| 955 | dev_info(&pdev->dev, "PCIe%d.%d: link up\n", | 967 | dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n", |
| 956 | port->port, port->lane); | 968 | port->port, port->lane); |
| 957 | } else { | 969 | iounmap(port->base); |
| 958 | port->haslink = 0; | 970 | continue; |
| 959 | dev_info(&pdev->dev, "PCIe%d.%d: link down\n", | ||
| 960 | port->port, port->lane); | ||
| 961 | } | 971 | } |
| 962 | 972 | ||
| 963 | port->dn = child; | 973 | port->dn = child; |
