.. | .. |
---|
66 | 66 | void ast_vhub_nuke(struct ast_vhub_ep *ep, int status) |
---|
67 | 67 | { |
---|
68 | 68 | struct ast_vhub_req *req; |
---|
69 | | - |
---|
70 | | - EPDBG(ep, "Nuking\n"); |
---|
| 69 | + int count = 0; |
---|
71 | 70 | |
---|
72 | 71 | /* Beware, lock will be dropped & req-acquired by done() */ |
---|
73 | 72 | while (!list_empty(&ep->queue)) { |
---|
74 | 73 | req = list_first_entry(&ep->queue, struct ast_vhub_req, queue); |
---|
75 | 74 | ast_vhub_done(ep, req, status); |
---|
| 75 | + count++; |
---|
76 | 76 | } |
---|
| 77 | + if (count) |
---|
| 78 | + EPDBG(ep, "Nuked %d request(s)\n", count); |
---|
77 | 79 | } |
---|
78 | 80 | |
---|
79 | 81 | struct usb_request *ast_vhub_alloc_request(struct usb_ep *u_ep, |
---|
.. | .. |
---|
98 | 100 | { |
---|
99 | 101 | struct ast_vhub *vhub = data; |
---|
100 | 102 | irqreturn_t iret = IRQ_NONE; |
---|
101 | | - u32 istat; |
---|
| 103 | + u32 i, istat; |
---|
102 | 104 | |
---|
103 | 105 | /* Stale interrupt while tearing down */ |
---|
104 | 106 | if (!vhub->ep0_bufs) |
---|
.. | .. |
---|
120 | 122 | |
---|
121 | 123 | /* Handle generic EPs first */ |
---|
122 | 124 | if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) { |
---|
123 | | - u32 i, ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR); |
---|
| 125 | + u32 ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR); |
---|
124 | 126 | writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR); |
---|
125 | 127 | |
---|
126 | | - for (i = 0; ep_acks && i < AST_VHUB_NUM_GEN_EPs; i++) { |
---|
| 128 | + for (i = 0; ep_acks && i < vhub->max_epns; i++) { |
---|
127 | 129 | u32 mask = VHUB_EP_IRQ(i); |
---|
128 | 130 | if (ep_acks & mask) { |
---|
129 | 131 | ast_vhub_epn_ack_irq(&vhub->epns[i]); |
---|
.. | .. |
---|
133 | 135 | } |
---|
134 | 136 | |
---|
135 | 137 | /* Handle device interrupts */ |
---|
136 | | - if (istat & (VHUB_IRQ_DEVICE1 | |
---|
137 | | - VHUB_IRQ_DEVICE2 | |
---|
138 | | - VHUB_IRQ_DEVICE3 | |
---|
139 | | - VHUB_IRQ_DEVICE4 | |
---|
140 | | - VHUB_IRQ_DEVICE5)) { |
---|
141 | | - if (istat & VHUB_IRQ_DEVICE1) |
---|
142 | | - ast_vhub_dev_irq(&vhub->ports[0].dev); |
---|
143 | | - if (istat & VHUB_IRQ_DEVICE2) |
---|
144 | | - ast_vhub_dev_irq(&vhub->ports[1].dev); |
---|
145 | | - if (istat & VHUB_IRQ_DEVICE3) |
---|
146 | | - ast_vhub_dev_irq(&vhub->ports[2].dev); |
---|
147 | | - if (istat & VHUB_IRQ_DEVICE4) |
---|
148 | | - ast_vhub_dev_irq(&vhub->ports[3].dev); |
---|
149 | | - if (istat & VHUB_IRQ_DEVICE5) |
---|
150 | | - ast_vhub_dev_irq(&vhub->ports[4].dev); |
---|
| 138 | + if (istat & vhub->port_irq_mask) { |
---|
| 139 | + for (i = 0; i < vhub->max_ports; i++) { |
---|
| 140 | + if (istat & VHUB_DEV_IRQ(i)) |
---|
| 141 | + ast_vhub_dev_irq(&vhub->ports[i].dev); |
---|
| 142 | + } |
---|
151 | 143 | } |
---|
152 | 144 | |
---|
153 | 145 | /* Handle top-level vHub EP0 interrupts */ |
---|
.. | .. |
---|
181 | 173 | |
---|
182 | 174 | void ast_vhub_init_hw(struct ast_vhub *vhub) |
---|
183 | 175 | { |
---|
184 | | - u32 ctrl; |
---|
| 176 | + u32 ctrl, port_mask, epn_mask; |
---|
185 | 177 | |
---|
186 | 178 | UDCDBG(vhub,"(Re)Starting HW ...\n"); |
---|
187 | 179 | |
---|
.. | .. |
---|
221 | 213 | } |
---|
222 | 214 | |
---|
223 | 215 | /* Reset all devices */ |
---|
224 | | - writel(VHUB_SW_RESET_ALL, vhub->regs + AST_VHUB_SW_RESET); |
---|
| 216 | + port_mask = GENMASK(vhub->max_ports, 1); |
---|
| 217 | + writel(VHUB_SW_RESET_ROOT_HUB | |
---|
| 218 | + VHUB_SW_RESET_DMA_CONTROLLER | |
---|
| 219 | + VHUB_SW_RESET_EP_POOL | |
---|
| 220 | + port_mask, vhub->regs + AST_VHUB_SW_RESET); |
---|
225 | 221 | udelay(1); |
---|
226 | 222 | writel(0, vhub->regs + AST_VHUB_SW_RESET); |
---|
227 | 223 | |
---|
228 | 224 | /* Disable and cleanup EP ACK/NACK interrupts */ |
---|
| 225 | + epn_mask = GENMASK(vhub->max_epns - 1, 0); |
---|
229 | 226 | writel(0, vhub->regs + AST_VHUB_EP_ACK_IER); |
---|
230 | 227 | writel(0, vhub->regs + AST_VHUB_EP_NACK_IER); |
---|
231 | | - writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_ACK_ISR); |
---|
232 | | - writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_NACK_ISR); |
---|
| 228 | + writel(epn_mask, vhub->regs + AST_VHUB_EP_ACK_ISR); |
---|
| 229 | + writel(epn_mask, vhub->regs + AST_VHUB_EP_NACK_ISR); |
---|
233 | 230 | |
---|
234 | 231 | /* Default settings for EP0, enable HW hub EP1 */ |
---|
235 | 232 | writel(0, vhub->regs + AST_VHUB_EP0_CTRL); |
---|
.. | .. |
---|
272 | 269 | return 0; |
---|
273 | 270 | |
---|
274 | 271 | /* Remove devices */ |
---|
275 | | - for (i = 0; i < AST_VHUB_NUM_PORTS; i++) |
---|
| 272 | + for (i = 0; i < vhub->max_ports; i++) |
---|
276 | 273 | ast_vhub_del_dev(&vhub->ports[i].dev); |
---|
277 | 274 | |
---|
278 | 275 | spin_lock_irqsave(&vhub->lock, flags); |
---|
.. | .. |
---|
294 | 291 | if (vhub->ep0_bufs) |
---|
295 | 292 | dma_free_coherent(&pdev->dev, |
---|
296 | 293 | AST_VHUB_EP0_MAX_PACKET * |
---|
297 | | - (AST_VHUB_NUM_PORTS + 1), |
---|
| 294 | + (vhub->max_ports + 1), |
---|
298 | 295 | vhub->ep0_bufs, |
---|
299 | 296 | vhub->ep0_bufs_dma); |
---|
300 | 297 | vhub->ep0_bufs = NULL; |
---|
.. | .. |
---|
308 | 305 | struct ast_vhub *vhub; |
---|
309 | 306 | struct resource *res; |
---|
310 | 307 | int i, rc = 0; |
---|
| 308 | + const struct device_node *np = pdev->dev.of_node; |
---|
311 | 309 | |
---|
312 | 310 | vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL); |
---|
313 | 311 | if (!vhub) |
---|
314 | 312 | return -ENOMEM; |
---|
315 | 313 | |
---|
| 314 | + rc = of_property_read_u32(np, "aspeed,vhub-downstream-ports", |
---|
| 315 | + &vhub->max_ports); |
---|
| 316 | + if (rc < 0) |
---|
| 317 | + vhub->max_ports = AST_VHUB_NUM_PORTS; |
---|
| 318 | + |
---|
| 319 | + vhub->ports = devm_kcalloc(&pdev->dev, vhub->max_ports, |
---|
| 320 | + sizeof(*vhub->ports), GFP_KERNEL); |
---|
| 321 | + if (!vhub->ports) |
---|
| 322 | + return -ENOMEM; |
---|
| 323 | + |
---|
| 324 | + rc = of_property_read_u32(np, "aspeed,vhub-generic-endpoints", |
---|
| 325 | + &vhub->max_epns); |
---|
| 326 | + if (rc < 0) |
---|
| 327 | + vhub->max_epns = AST_VHUB_NUM_GEN_EPs; |
---|
| 328 | + |
---|
| 329 | + vhub->epns = devm_kcalloc(&pdev->dev, vhub->max_epns, |
---|
| 330 | + sizeof(*vhub->epns), GFP_KERNEL); |
---|
| 331 | + if (!vhub->epns) |
---|
| 332 | + return -ENOMEM; |
---|
| 333 | + |
---|
316 | 334 | spin_lock_init(&vhub->lock); |
---|
317 | 335 | vhub->pdev = pdev; |
---|
| 336 | + vhub->port_irq_mask = GENMASK(VHUB_IRQ_DEV1_BIT + vhub->max_ports - 1, |
---|
| 337 | + VHUB_IRQ_DEV1_BIT); |
---|
318 | 338 | |
---|
319 | 339 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
320 | 340 | vhub->regs = devm_ioremap_resource(&pdev->dev, res); |
---|
.. | .. |
---|
349 | 369 | /* Find interrupt and install handler */ |
---|
350 | 370 | vhub->irq = platform_get_irq(pdev, 0); |
---|
351 | 371 | if (vhub->irq < 0) { |
---|
352 | | - dev_err(&pdev->dev, "Failed to get interrupt\n"); |
---|
353 | 372 | rc = vhub->irq; |
---|
354 | 373 | goto err; |
---|
355 | 374 | } |
---|
.. | .. |
---|
366 | 385 | */ |
---|
367 | 386 | vhub->ep0_bufs = dma_alloc_coherent(&pdev->dev, |
---|
368 | 387 | AST_VHUB_EP0_MAX_PACKET * |
---|
369 | | - (AST_VHUB_NUM_PORTS + 1), |
---|
| 388 | + (vhub->max_ports + 1), |
---|
370 | 389 | &vhub->ep0_bufs_dma, GFP_KERNEL); |
---|
371 | 390 | if (!vhub->ep0_bufs) { |
---|
372 | 391 | dev_err(&pdev->dev, "Failed to allocate EP0 DMA buffers\n"); |
---|
.. | .. |
---|
380 | 399 | ast_vhub_init_ep0(vhub, &vhub->ep0, NULL); |
---|
381 | 400 | |
---|
382 | 401 | /* Init devices */ |
---|
383 | | - for (i = 0; i < AST_VHUB_NUM_PORTS && rc == 0; i++) |
---|
| 402 | + for (i = 0; i < vhub->max_ports && rc == 0; i++) |
---|
384 | 403 | rc = ast_vhub_init_dev(vhub, i); |
---|
385 | 404 | if (rc) |
---|
386 | 405 | goto err; |
---|
387 | 406 | |
---|
388 | 407 | /* Init hub emulation */ |
---|
389 | | - ast_vhub_init_hub(vhub); |
---|
| 408 | + rc = ast_vhub_init_hub(vhub); |
---|
| 409 | + if (rc) |
---|
| 410 | + goto err; |
---|
390 | 411 | |
---|
391 | 412 | /* Initialize HW */ |
---|
392 | 413 | ast_vhub_init_hw(vhub); |
---|
.. | .. |
---|
407 | 428 | { |
---|
408 | 429 | .compatible = "aspeed,ast2500-usb-vhub", |
---|
409 | 430 | }, |
---|
| 431 | + { |
---|
| 432 | + .compatible = "aspeed,ast2600-usb-vhub", |
---|
| 433 | + }, |
---|
410 | 434 | { } |
---|
411 | 435 | }; |
---|
412 | 436 | MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids); |
---|