diff options
author | Kevin Hilman <khilman@linaro.org> | 2013-10-17 17:54:09 -0400 |
---|---|---|
committer | Kevin Hilman <khilman@linaro.org> | 2013-10-17 17:54:27 -0400 |
commit | f2c4e82e350dab489ae0d8fcd84b780de508ab64 (patch) | |
tree | 298b1db346ca882ebfe03f650478d7001b0a490f /drivers/pci | |
parent | e85923acb94b518c3b7bfad407cf93ee964ba27f (diff) | |
parent | f5072dfbac053200c8865c4fb15e4f020b7b5d1d (diff) |
Merge tag 'drivers-3.13-2' of git://git.infradead.org/linux-mvebu into next/drivers
From Jason Cooper:
mvebu driver changes for v3.13 (round 2)
- mvebu
- pcie
- dynamic link up detection
- add IO wrappers
- declare some local functions static
* tag 'drivers-3.13-2' of git://git.infradead.org/linux-mvebu:
PCI: mvebu: make local functions static
PCI: mvebu: add I/O access wrappers
PCI: mvebu: Dynamically detect if the PEX link is up to enable hot plug
Signed-off-by: Kevin Hilman <khilman@linaro.org>
Diffstat (limited to 'drivers/pci')
-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; |