diff options
Diffstat (limited to 'drivers/pci/dwc/pcie-designware.c')
-rw-r--r-- | drivers/pci/dwc/pcie-designware.c | 258 |
1 files changed, 210 insertions, 48 deletions
diff --git a/drivers/pci/dwc/pcie-designware.c b/drivers/pci/dwc/pcie-designware.c index 7e1fb7d6643c..0e03af279259 100644 --- a/drivers/pci/dwc/pcie-designware.c +++ b/drivers/pci/dwc/pcie-designware.c | |||
@@ -61,91 +61,253 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val) | |||
61 | return PCIBIOS_SUCCESSFUL; | 61 | return PCIBIOS_SUCCESSFUL; |
62 | } | 62 | } |
63 | 63 | ||
64 | u32 dw_pcie_readl_dbi(struct dw_pcie *pci, u32 reg) | 64 | u32 __dw_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, |
65 | size_t size) | ||
65 | { | 66 | { |
66 | if (pci->ops->readl_dbi) | 67 | int ret; |
67 | return pci->ops->readl_dbi(pci, reg); | 68 | u32 val; |
68 | 69 | ||
69 | return readl(pci->dbi_base + reg); | 70 | if (pci->ops->read_dbi) |
71 | return pci->ops->read_dbi(pci, base, reg, size); | ||
72 | |||
73 | ret = dw_pcie_read(base + reg, size, &val); | ||
74 | if (ret) | ||
75 | dev_err(pci->dev, "read DBI address failed\n"); | ||
76 | |||
77 | return val; | ||
70 | } | 78 | } |
71 | 79 | ||
72 | void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val) | 80 | void __dw_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base, u32 reg, |
81 | size_t size, u32 val) | ||
73 | { | 82 | { |
74 | if (pci->ops->writel_dbi) | 83 | int ret; |
75 | pci->ops->writel_dbi(pci, reg, val); | 84 | |
76 | else | 85 | if (pci->ops->write_dbi) { |
77 | writel(val, pci->dbi_base + reg); | 86 | pci->ops->write_dbi(pci, base, reg, size, val); |
87 | return; | ||
88 | } | ||
89 | |||
90 | ret = dw_pcie_write(base + reg, size, val); | ||
91 | if (ret) | ||
92 | dev_err(pci->dev, "write DBI address failed\n"); | ||
78 | } | 93 | } |
79 | 94 | ||
80 | static u32 dw_pcie_readl_unroll(struct dw_pcie *pci, u32 index, u32 reg) | 95 | static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg) |
81 | { | 96 | { |
82 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); | 97 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); |
83 | 98 | ||
84 | return dw_pcie_readl_dbi(pci, offset + reg); | 99 | return dw_pcie_readl_dbi(pci, offset + reg); |
85 | } | 100 | } |
86 | 101 | ||
87 | static void dw_pcie_writel_unroll(struct dw_pcie *pci, u32 index, u32 reg, | 102 | static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg, |
88 | u32 val) | 103 | u32 val) |
89 | { | 104 | { |
90 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); | 105 | u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); |
91 | 106 | ||
92 | dw_pcie_writel_dbi(pci, offset + reg, val); | 107 | dw_pcie_writel_dbi(pci, offset + reg, val); |
93 | } | 108 | } |
94 | 109 | ||
110 | void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, int type, | ||
111 | u64 cpu_addr, u64 pci_addr, u32 size) | ||
112 | { | ||
113 | u32 retries, val; | ||
114 | |||
115 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, | ||
116 | lower_32_bits(cpu_addr)); | ||
117 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, | ||
118 | upper_32_bits(cpu_addr)); | ||
119 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT, | ||
120 | lower_32_bits(cpu_addr + size - 1)); | ||
121 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, | ||
122 | lower_32_bits(pci_addr)); | ||
123 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, | ||
124 | upper_32_bits(pci_addr)); | ||
125 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, | ||
126 | type); | ||
127 | dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, | ||
128 | PCIE_ATU_ENABLE); | ||
129 | |||
130 | /* | ||
131 | * Make sure ATU enable takes effect before any subsequent config | ||
132 | * and I/O accesses. | ||
133 | */ | ||
134 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | ||
135 | val = dw_pcie_readl_ob_unroll(pci, index, | ||
136 | PCIE_ATU_UNR_REGION_CTRL2); | ||
137 | if (val & PCIE_ATU_ENABLE) | ||
138 | return; | ||
139 | |||
140 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | ||
141 | } | ||
142 | dev_err(pci->dev, "outbound iATU is not being enabled\n"); | ||
143 | } | ||
144 | |||
95 | void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, | 145 | void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, |
96 | u64 cpu_addr, u64 pci_addr, u32 size) | 146 | u64 cpu_addr, u64 pci_addr, u32 size) |
97 | { | 147 | { |
98 | u32 retries, val; | 148 | u32 retries, val; |
99 | 149 | ||
150 | if (pci->ops->cpu_addr_fixup) | ||
151 | cpu_addr = pci->ops->cpu_addr_fixup(cpu_addr); | ||
152 | |||
100 | if (pci->iatu_unroll_enabled) { | 153 | if (pci->iatu_unroll_enabled) { |
101 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, | 154 | dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr, |
102 | lower_32_bits(cpu_addr)); | 155 | pci_addr, size); |
103 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, | 156 | return; |
104 | upper_32_bits(cpu_addr)); | ||
105 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_LIMIT, | ||
106 | lower_32_bits(cpu_addr + size - 1)); | ||
107 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, | ||
108 | lower_32_bits(pci_addr)); | ||
109 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, | ||
110 | upper_32_bits(pci_addr)); | ||
111 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, | ||
112 | type); | ||
113 | dw_pcie_writel_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, | ||
114 | PCIE_ATU_ENABLE); | ||
115 | } else { | ||
116 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, | ||
117 | PCIE_ATU_REGION_OUTBOUND | index); | ||
118 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, | ||
119 | lower_32_bits(cpu_addr)); | ||
120 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, | ||
121 | upper_32_bits(cpu_addr)); | ||
122 | dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, | ||
123 | lower_32_bits(cpu_addr + size - 1)); | ||
124 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, | ||
125 | lower_32_bits(pci_addr)); | ||
126 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, | ||
127 | upper_32_bits(pci_addr)); | ||
128 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); | ||
129 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); | ||
130 | } | 157 | } |
131 | 158 | ||
159 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, | ||
160 | PCIE_ATU_REGION_OUTBOUND | index); | ||
161 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, | ||
162 | lower_32_bits(cpu_addr)); | ||
163 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, | ||
164 | upper_32_bits(cpu_addr)); | ||
165 | dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, | ||
166 | lower_32_bits(cpu_addr + size - 1)); | ||
167 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, | ||
168 | lower_32_bits(pci_addr)); | ||
169 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, | ||
170 | upper_32_bits(pci_addr)); | ||
171 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); | ||
172 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); | ||
173 | |||
132 | /* | 174 | /* |
133 | * Make sure ATU enable takes effect before any subsequent config | 175 | * Make sure ATU enable takes effect before any subsequent config |
134 | * and I/O accesses. | 176 | * and I/O accesses. |
135 | */ | 177 | */ |
136 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | 178 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { |
137 | if (pci->iatu_unroll_enabled) | 179 | val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); |
138 | val = dw_pcie_readl_unroll(pci, index, | ||
139 | PCIE_ATU_UNR_REGION_CTRL2); | ||
140 | else | ||
141 | val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); | ||
142 | |||
143 | if (val == PCIE_ATU_ENABLE) | 180 | if (val == PCIE_ATU_ENABLE) |
144 | return; | 181 | return; |
145 | 182 | ||
146 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | 183 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); |
147 | } | 184 | } |
148 | dev_err(pci->dev, "iATU is not being enabled\n"); | 185 | dev_err(pci->dev, "outbound iATU is not being enabled\n"); |
186 | } | ||
187 | |||
188 | static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg) | ||
189 | { | ||
190 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); | ||
191 | |||
192 | return dw_pcie_readl_dbi(pci, offset + reg); | ||
193 | } | ||
194 | |||
195 | static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, | ||
196 | u32 val) | ||
197 | { | ||
198 | u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index); | ||
199 | |||
200 | dw_pcie_writel_dbi(pci, offset + reg, val); | ||
201 | } | ||
202 | |||
203 | int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index, int bar, | ||
204 | u64 cpu_addr, enum dw_pcie_as_type as_type) | ||
205 | { | ||
206 | int type; | ||
207 | u32 retries, val; | ||
208 | |||
209 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, | ||
210 | lower_32_bits(cpu_addr)); | ||
211 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, | ||
212 | upper_32_bits(cpu_addr)); | ||
213 | |||
214 | switch (as_type) { | ||
215 | case DW_PCIE_AS_MEM: | ||
216 | type = PCIE_ATU_TYPE_MEM; | ||
217 | break; | ||
218 | case DW_PCIE_AS_IO: | ||
219 | type = PCIE_ATU_TYPE_IO; | ||
220 | break; | ||
221 | default: | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type); | ||
226 | dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, | ||
227 | PCIE_ATU_ENABLE | | ||
228 | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); | ||
229 | |||
230 | /* | ||
231 | * Make sure ATU enable takes effect before any subsequent config | ||
232 | * and I/O accesses. | ||
233 | */ | ||
234 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | ||
235 | val = dw_pcie_readl_ib_unroll(pci, index, | ||
236 | PCIE_ATU_UNR_REGION_CTRL2); | ||
237 | if (val & PCIE_ATU_ENABLE) | ||
238 | return 0; | ||
239 | |||
240 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | ||
241 | } | ||
242 | dev_err(pci->dev, "inbound iATU is not being enabled\n"); | ||
243 | |||
244 | return -EBUSY; | ||
245 | } | ||
246 | |||
247 | int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar, | ||
248 | u64 cpu_addr, enum dw_pcie_as_type as_type) | ||
249 | { | ||
250 | int type; | ||
251 | u32 retries, val; | ||
252 | |||
253 | if (pci->iatu_unroll_enabled) | ||
254 | return dw_pcie_prog_inbound_atu_unroll(pci, index, bar, | ||
255 | cpu_addr, as_type); | ||
256 | |||
257 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | | ||
258 | index); | ||
259 | dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr)); | ||
260 | dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr)); | ||
261 | |||
262 | switch (as_type) { | ||
263 | case DW_PCIE_AS_MEM: | ||
264 | type = PCIE_ATU_TYPE_MEM; | ||
265 | break; | ||
266 | case DW_PCIE_AS_IO: | ||
267 | type = PCIE_ATU_TYPE_IO; | ||
268 | break; | ||
269 | default: | ||
270 | return -EINVAL; | ||
271 | } | ||
272 | |||
273 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type); | ||
274 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE | ||
275 | | PCIE_ATU_BAR_MODE_ENABLE | (bar << 8)); | ||
276 | |||
277 | /* | ||
278 | * Make sure ATU enable takes effect before any subsequent config | ||
279 | * and I/O accesses. | ||
280 | */ | ||
281 | for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { | ||
282 | val = dw_pcie_readl_dbi(pci, PCIE_ATU_CR2); | ||
283 | if (val & PCIE_ATU_ENABLE) | ||
284 | return 0; | ||
285 | |||
286 | usleep_range(LINK_WAIT_IATU_MIN, LINK_WAIT_IATU_MAX); | ||
287 | } | ||
288 | dev_err(pci->dev, "inbound iATU is not being enabled\n"); | ||
289 | |||
290 | return -EBUSY; | ||
291 | } | ||
292 | |||
293 | void dw_pcie_disable_atu(struct dw_pcie *pci, int index, | ||
294 | enum dw_pcie_region_type type) | ||
295 | { | ||
296 | int region; | ||
297 | |||
298 | switch (type) { | ||
299 | case DW_PCIE_REGION_INBOUND: | ||
300 | region = PCIE_ATU_REGION_INBOUND; | ||
301 | break; | ||
302 | case DW_PCIE_REGION_OUTBOUND: | ||
303 | region = PCIE_ATU_REGION_OUTBOUND; | ||
304 | break; | ||
305 | default: | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index); | ||
310 | dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~PCIE_ATU_ENABLE); | ||
149 | } | 311 | } |
150 | 312 | ||
151 | int dw_pcie_wait_for_link(struct dw_pcie *pci) | 313 | int dw_pcie_wait_for_link(struct dw_pcie *pci) |