1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * aspeed-vhub -- Driver for Aspeed SoC "vHub" USB gadget 4 * 5 * core.c - Top level support 6 * 7 * Copyright 2017 IBM Corporation 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 */ 14 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/platform_device.h> 18 #include <linux/delay.h> 19 #include <linux/ioport.h> 20 #include <linux/slab.h> 21 #include <linux/errno.h> 22 #include <linux/list.h> 23 #include <linux/interrupt.h> 24 #include <linux/proc_fs.h> 25 #include <linux/prefetch.h> 26 #include <linux/clk.h> 27 #include <linux/usb/gadget.h> 28 #include <linux/of.h> 29 #include <linux/of_gpio.h> 30 #include <linux/regmap.h> 31 #include <linux/dma-mapping.h> 32 33 #include "vhub.h" 34 35 void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req, 36 int status) 37 { 38 bool internal = req->internal; 39 40 EPVDBG(ep, "completing request @%p, status %d\n", req, status); 41 42 list_del_init(&req->queue); 43 44 if (req->req.status == -EINPROGRESS) 45 req->req.status = status; 46 47 if (req->req.dma) { 48 if (!WARN_ON(!ep->dev)) 49 usb_gadget_unmap_request(&ep->dev->gadget, 50 &req->req, ep->epn.is_in); 51 req->req.dma = 0; 52 } 53 54 /* 55 * If this isn't an internal EP0 request, call the core 56 * to call the gadget completion. 57 */ 58 if (!internal) { 59 spin_unlock(&ep->vhub->lock); 60 usb_gadget_giveback_request(&ep->ep, &req->req); 61 spin_lock(&ep->vhub->lock); 62 } 63 } 64 65 void ast_vhub_nuke(struct ast_vhub_ep *ep, int status) 66 { 67 struct ast_vhub_req *req; 68 int count = 0; 69 70 /* Beware, lock will be dropped & req-acquired by done() */ 71 while (!list_empty(&ep->queue)) { 72 req = list_first_entry(&ep->queue, struct ast_vhub_req, queue); 73 ast_vhub_done(ep, req, status); 74 count++; 75 } 76 if (count) 77 EPDBG(ep, "Nuked %d request(s)\n", count); 78 } 79 80 struct usb_request *ast_vhub_alloc_request(struct usb_ep *u_ep, 81 gfp_t gfp_flags) 82 { 83 struct ast_vhub_req *req; 84 85 req = kzalloc(sizeof(*req), gfp_flags); 86 if (!req) 87 return NULL; 88 return &req->req; 89 } 90 91 void ast_vhub_free_request(struct usb_ep *u_ep, struct usb_request *u_req) 92 { 93 struct ast_vhub_req *req = to_ast_req(u_req); 94 95 kfree(req); 96 } 97 98 static irqreturn_t ast_vhub_irq(int irq, void *data) 99 { 100 struct ast_vhub *vhub = data; 101 irqreturn_t iret = IRQ_NONE; 102 u32 istat; 103 104 /* Stale interrupt while tearing down */ 105 if (!vhub->ep0_bufs) 106 return IRQ_NONE; 107 108 spin_lock(&vhub->lock); 109 110 /* Read and ACK interrupts */ 111 istat = readl(vhub->regs + AST_VHUB_ISR); 112 if (!istat) 113 goto bail; 114 writel(istat, vhub->regs + AST_VHUB_ISR); 115 iret = IRQ_HANDLED; 116 117 UDCVDBG(vhub, "irq status=%08x, ep_acks=%08x ep_nacks=%08x\n", 118 istat, 119 readl(vhub->regs + AST_VHUB_EP_ACK_ISR), 120 readl(vhub->regs + AST_VHUB_EP_NACK_ISR)); 121 122 /* Handle generic EPs first */ 123 if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) { 124 u32 i, ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR); 125 writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR); 126 127 for (i = 0; ep_acks && i < AST_VHUB_NUM_GEN_EPs; i++) { 128 u32 mask = VHUB_EP_IRQ(i); 129 if (ep_acks & mask) { 130 ast_vhub_epn_ack_irq(&vhub->epns[i]); 131 ep_acks &= ~mask; 132 } 133 } 134 } 135 136 /* Handle device interrupts */ 137 if (istat & (VHUB_IRQ_DEVICE1 | 138 VHUB_IRQ_DEVICE2 | 139 VHUB_IRQ_DEVICE3 | 140 VHUB_IRQ_DEVICE4 | 141 VHUB_IRQ_DEVICE5)) { 142 if (istat & VHUB_IRQ_DEVICE1) 143 ast_vhub_dev_irq(&vhub->ports[0].dev); 144 if (istat & VHUB_IRQ_DEVICE2) 145 ast_vhub_dev_irq(&vhub->ports[1].dev); 146 if (istat & VHUB_IRQ_DEVICE3) 147 ast_vhub_dev_irq(&vhub->ports[2].dev); 148 if (istat & VHUB_IRQ_DEVICE4) 149 ast_vhub_dev_irq(&vhub->ports[3].dev); 150 if (istat & VHUB_IRQ_DEVICE5) 151 ast_vhub_dev_irq(&vhub->ports[4].dev); 152 } 153 154 /* Handle top-level vHub EP0 interrupts */ 155 if (istat & (VHUB_IRQ_HUB_EP0_OUT_ACK_STALL | 156 VHUB_IRQ_HUB_EP0_IN_ACK_STALL | 157 VHUB_IRQ_HUB_EP0_SETUP)) { 158 if (istat & VHUB_IRQ_HUB_EP0_IN_ACK_STALL) 159 ast_vhub_ep0_handle_ack(&vhub->ep0, true); 160 if (istat & VHUB_IRQ_HUB_EP0_OUT_ACK_STALL) 161 ast_vhub_ep0_handle_ack(&vhub->ep0, false); 162 if (istat & VHUB_IRQ_HUB_EP0_SETUP) 163 ast_vhub_ep0_handle_setup(&vhub->ep0); 164 } 165 166 /* Various top level bus events */ 167 if (istat & (VHUB_IRQ_BUS_RESUME | 168 VHUB_IRQ_BUS_SUSPEND | 169 VHUB_IRQ_BUS_RESET)) { 170 if (istat & VHUB_IRQ_BUS_RESUME) 171 ast_vhub_hub_resume(vhub); 172 if (istat & VHUB_IRQ_BUS_SUSPEND) 173 ast_vhub_hub_suspend(vhub); 174 if (istat & VHUB_IRQ_BUS_RESET) 175 ast_vhub_hub_reset(vhub); 176 } 177 178 bail: 179 spin_unlock(&vhub->lock); 180 return iret; 181 } 182 183 void ast_vhub_init_hw(struct ast_vhub *vhub) 184 { 185 u32 ctrl; 186 187 UDCDBG(vhub,"(Re)Starting HW ...\n"); 188 189 /* Enable PHY */ 190 ctrl = VHUB_CTRL_PHY_CLK | 191 VHUB_CTRL_PHY_RESET_DIS; 192 193 /* 194 * We do *NOT* set the VHUB_CTRL_CLK_STOP_SUSPEND bit 195 * to stop the logic clock during suspend because 196 * it causes the registers to become inaccessible and 197 * we haven't yet figured out a good wayt to bring the 198 * controller back into life to issue a wakeup. 199 */ 200 201 /* 202 * Set some ISO & split control bits according to Aspeed 203 * recommendation 204 * 205 * VHUB_CTRL_ISO_RSP_CTRL: When set tells the HW to respond 206 * with 0 bytes data packet to ISO IN endpoints when no data 207 * is available. 208 * 209 * VHUB_CTRL_SPLIT_IN: This makes a SOF complete a split IN 210 * transaction. 211 */ 212 ctrl |= VHUB_CTRL_ISO_RSP_CTRL | VHUB_CTRL_SPLIT_IN; 213 writel(ctrl, vhub->regs + AST_VHUB_CTRL); 214 udelay(1); 215 216 /* Set descriptor ring size */ 217 if (AST_VHUB_DESCS_COUNT == 256) { 218 ctrl |= VHUB_CTRL_LONG_DESC; 219 writel(ctrl, vhub->regs + AST_VHUB_CTRL); 220 } else { 221 BUILD_BUG_ON(AST_VHUB_DESCS_COUNT != 32); 222 } 223 224 /* Reset all devices */ 225 writel(VHUB_SW_RESET_ALL, vhub->regs + AST_VHUB_SW_RESET); 226 udelay(1); 227 writel(0, vhub->regs + AST_VHUB_SW_RESET); 228 229 /* Disable and cleanup EP ACK/NACK interrupts */ 230 writel(0, vhub->regs + AST_VHUB_EP_ACK_IER); 231 writel(0, vhub->regs + AST_VHUB_EP_NACK_IER); 232 writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_ACK_ISR); 233 writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_NACK_ISR); 234 235 /* Default settings for EP0, enable HW hub EP1 */ 236 writel(0, vhub->regs + AST_VHUB_EP0_CTRL); 237 writel(VHUB_EP1_CTRL_RESET_TOGGLE | 238 VHUB_EP1_CTRL_ENABLE, 239 vhub->regs + AST_VHUB_EP1_CTRL); 240 writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG); 241 242 /* Configure EP0 DMA buffer */ 243 writel(vhub->ep0.buf_dma, vhub->regs + AST_VHUB_EP0_DATA); 244 245 /* Clear address */ 246 writel(0, vhub->regs + AST_VHUB_CONF); 247 248 /* Pullup hub (activate on host) */ 249 if (vhub->force_usb1) 250 ctrl |= VHUB_CTRL_FULL_SPEED_ONLY; 251 252 ctrl |= VHUB_CTRL_UPSTREAM_CONNECT; 253 writel(ctrl, vhub->regs + AST_VHUB_CTRL); 254 255 /* Enable some interrupts */ 256 writel(VHUB_IRQ_HUB_EP0_IN_ACK_STALL | 257 VHUB_IRQ_HUB_EP0_OUT_ACK_STALL | 258 VHUB_IRQ_HUB_EP0_SETUP | 259 VHUB_IRQ_EP_POOL_ACK_STALL | 260 VHUB_IRQ_BUS_RESUME | 261 VHUB_IRQ_BUS_SUSPEND | 262 VHUB_IRQ_BUS_RESET, 263 vhub->regs + AST_VHUB_IER); 264 } 265 266 static int ast_vhub_remove(struct platform_device *pdev) 267 { 268 struct ast_vhub *vhub = platform_get_drvdata(pdev); 269 unsigned long flags; 270 int i; 271 272 if (!vhub || !vhub->regs) 273 return 0; 274 275 /* Remove devices */ 276 for (i = 0; i < AST_VHUB_NUM_PORTS; i++) 277 ast_vhub_del_dev(&vhub->ports[i].dev); 278 279 spin_lock_irqsave(&vhub->lock, flags); 280 281 /* Mask & ack all interrupts */ 282 writel(0, vhub->regs + AST_VHUB_IER); 283 writel(VHUB_IRQ_ACK_ALL, vhub->regs + AST_VHUB_ISR); 284 285 /* Pull device, leave PHY enabled */ 286 writel(VHUB_CTRL_PHY_CLK | 287 VHUB_CTRL_PHY_RESET_DIS, 288 vhub->regs + AST_VHUB_CTRL); 289 290 if (vhub->clk) 291 clk_disable_unprepare(vhub->clk); 292 293 spin_unlock_irqrestore(&vhub->lock, flags); 294 295 if (vhub->ep0_bufs) 296 dma_free_coherent(&pdev->dev, 297 AST_VHUB_EP0_MAX_PACKET * 298 (AST_VHUB_NUM_PORTS + 1), 299 vhub->ep0_bufs, 300 vhub->ep0_bufs_dma); 301 vhub->ep0_bufs = NULL; 302 303 return 0; 304 } 305 306 static int ast_vhub_probe(struct platform_device *pdev) 307 { 308 enum usb_device_speed max_speed; 309 struct ast_vhub *vhub; 310 struct resource *res; 311 int i, rc = 0; 312 313 vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL); 314 if (!vhub) 315 return -ENOMEM; 316 317 spin_lock_init(&vhub->lock); 318 vhub->pdev = pdev; 319 320 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 321 vhub->regs = devm_ioremap_resource(&pdev->dev, res); 322 if (IS_ERR(vhub->regs)) { 323 dev_err(&pdev->dev, "Failed to map resources\n"); 324 return PTR_ERR(vhub->regs); 325 } 326 UDCDBG(vhub, "vHub@%pR mapped @%p\n", res, vhub->regs); 327 328 platform_set_drvdata(pdev, vhub); 329 330 vhub->clk = devm_clk_get(&pdev->dev, NULL); 331 if (IS_ERR(vhub->clk)) { 332 rc = PTR_ERR(vhub->clk); 333 goto err; 334 } 335 rc = clk_prepare_enable(vhub->clk); 336 if (rc) { 337 dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", rc); 338 goto err; 339 } 340 341 /* Check if we need to limit the HW to USB1 */ 342 max_speed = usb_get_maximum_speed(&pdev->dev); 343 if (max_speed != USB_SPEED_UNKNOWN && max_speed < USB_SPEED_HIGH) 344 vhub->force_usb1 = true; 345 346 /* Mask & ack all interrupts before installing the handler */ 347 writel(0, vhub->regs + AST_VHUB_IER); 348 writel(VHUB_IRQ_ACK_ALL, vhub->regs + AST_VHUB_ISR); 349 350 /* Find interrupt and install handler */ 351 vhub->irq = platform_get_irq(pdev, 0); 352 if (vhub->irq < 0) { 353 rc = vhub->irq; 354 goto err; 355 } 356 rc = devm_request_irq(&pdev->dev, vhub->irq, ast_vhub_irq, 0, 357 KBUILD_MODNAME, vhub); 358 if (rc) { 359 dev_err(&pdev->dev, "Failed to request interrupt\n"); 360 goto err; 361 } 362 363 /* 364 * Allocate DMA buffers for all EP0s in one chunk, 365 * one per port and one for the vHub itself 366 */ 367 vhub->ep0_bufs = dma_alloc_coherent(&pdev->dev, 368 AST_VHUB_EP0_MAX_PACKET * 369 (AST_VHUB_NUM_PORTS + 1), 370 &vhub->ep0_bufs_dma, GFP_KERNEL); 371 if (!vhub->ep0_bufs) { 372 dev_err(&pdev->dev, "Failed to allocate EP0 DMA buffers\n"); 373 rc = -ENOMEM; 374 goto err; 375 } 376 UDCVDBG(vhub, "EP0 DMA buffers @%p (DMA 0x%08x)\n", 377 vhub->ep0_bufs, (u32)vhub->ep0_bufs_dma); 378 379 /* Init vHub EP0 */ 380 ast_vhub_init_ep0(vhub, &vhub->ep0, NULL); 381 382 /* Init devices */ 383 for (i = 0; i < AST_VHUB_NUM_PORTS && rc == 0; i++) 384 rc = ast_vhub_init_dev(vhub, i); 385 if (rc) 386 goto err; 387 388 /* Init hub emulation */ 389 ast_vhub_init_hub(vhub); 390 391 /* Initialize HW */ 392 ast_vhub_init_hw(vhub); 393 394 dev_info(&pdev->dev, "Initialized virtual hub in USB%d mode\n", 395 vhub->force_usb1 ? 1 : 2); 396 397 return 0; 398 err: 399 ast_vhub_remove(pdev); 400 return rc; 401 } 402 403 static const struct of_device_id ast_vhub_dt_ids[] = { 404 { 405 .compatible = "aspeed,ast2400-usb-vhub", 406 }, 407 { 408 .compatible = "aspeed,ast2500-usb-vhub", 409 }, 410 { } 411 }; 412 MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids); 413 414 static struct platform_driver ast_vhub_driver = { 415 .probe = ast_vhub_probe, 416 .remove = ast_vhub_remove, 417 .driver = { 418 .name = KBUILD_MODNAME, 419 .of_match_table = ast_vhub_dt_ids, 420 }, 421 }; 422 module_platform_driver(ast_vhub_driver); 423 424 MODULE_DESCRIPTION("Aspeed vHub udc driver"); 425 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 426 MODULE_LICENSE("GPL"); 427