GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / usb / gadget / udc / aspeed-vhub / core.c
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         struct ast_vhub *vhub = ep->vhub;
40
41         EPVDBG(ep, "completing request @%p, status %d\n", req, status);
42
43         list_del_init(&req->queue);
44
45         if (req->req.status == -EINPROGRESS)
46                 req->req.status = status;
47
48         if (req->req.dma) {
49                 if (!WARN_ON(!ep->dev))
50                         usb_gadget_unmap_request_by_dev(&vhub->pdev->dev,
51                                                  &req->req, ep->epn.is_in);
52                 req->req.dma = 0;
53         }
54
55         /*
56          * If this isn't an internal EP0 request, call the core
57          * to call the gadget completion.
58          */
59         if (!internal) {
60                 spin_unlock(&ep->vhub->lock);
61                 usb_gadget_giveback_request(&ep->ep, &req->req);
62                 spin_lock(&ep->vhub->lock);
63         }
64 }
65
66 void ast_vhub_nuke(struct ast_vhub_ep *ep, int status)
67 {
68         struct ast_vhub_req *req;
69
70         EPDBG(ep, "Nuking\n");
71
72         /* Beware, lock will be dropped & req-acquired by done() */
73         while (!list_empty(&ep->queue)) {
74                 req = list_first_entry(&ep->queue, struct ast_vhub_req, queue);
75                 ast_vhub_done(ep, req, status);
76         }
77 }
78
79 struct usb_request *ast_vhub_alloc_request(struct usb_ep *u_ep,
80                                            gfp_t gfp_flags)
81 {
82         struct ast_vhub_req *req;
83
84         req = kzalloc(sizeof(*req), gfp_flags);
85         if (!req)
86                 return NULL;
87         return &req->req;
88 }
89
90 void ast_vhub_free_request(struct usb_ep *u_ep, struct usb_request *u_req)
91 {
92         struct ast_vhub_req *req = to_ast_req(u_req);
93
94         kfree(req);
95 }
96
97 static irqreturn_t ast_vhub_irq(int irq, void *data)
98 {
99         struct ast_vhub *vhub = data;
100         irqreturn_t iret = IRQ_NONE;
101         u32 istat;
102
103         /* Stale interrupt while tearing down */
104         if (!vhub->ep0_bufs)
105                 return IRQ_NONE;
106
107         spin_lock(&vhub->lock);
108
109         /* Read and ACK interrupts */
110         istat = readl(vhub->regs + AST_VHUB_ISR);
111         if (!istat)
112                 goto bail;
113         writel(istat, vhub->regs + AST_VHUB_ISR);
114         iret = IRQ_HANDLED;
115
116         UDCVDBG(vhub, "irq status=%08x, ep_acks=%08x ep_nacks=%08x\n",
117                istat,
118                readl(vhub->regs + AST_VHUB_EP_ACK_ISR),
119                readl(vhub->regs + AST_VHUB_EP_NACK_ISR));
120
121         /* Handle generic EPs first */
122         if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) {
123                 u32 i, ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR);
124                 writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR);
125
126                 for (i = 0; ep_acks && i < AST_VHUB_NUM_GEN_EPs; i++) {
127                         u32 mask = VHUB_EP_IRQ(i);
128                         if (ep_acks & mask) {
129                                 ast_vhub_epn_ack_irq(&vhub->epns[i]);
130                                 ep_acks &= ~mask;
131                         }
132                 }
133         }
134
135         /* 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);
151         }
152
153         /* Handle top-level vHub EP0 interrupts */
154         if (istat & (VHUB_IRQ_HUB_EP0_OUT_ACK_STALL |
155                      VHUB_IRQ_HUB_EP0_IN_ACK_STALL |
156                      VHUB_IRQ_HUB_EP0_SETUP)) {
157                 if (istat & VHUB_IRQ_HUB_EP0_IN_ACK_STALL)
158                         ast_vhub_ep0_handle_ack(&vhub->ep0, true);
159                 if (istat & VHUB_IRQ_HUB_EP0_OUT_ACK_STALL)
160                         ast_vhub_ep0_handle_ack(&vhub->ep0, false);
161                 if (istat & VHUB_IRQ_HUB_EP0_SETUP)
162                         ast_vhub_ep0_handle_setup(&vhub->ep0);
163         }
164
165         /* Various top level bus events */
166         if (istat & (VHUB_IRQ_BUS_RESUME |
167                      VHUB_IRQ_BUS_SUSPEND |
168                      VHUB_IRQ_BUS_RESET)) {
169                 if (istat & VHUB_IRQ_BUS_RESUME)
170                         ast_vhub_hub_resume(vhub);
171                 if (istat & VHUB_IRQ_BUS_SUSPEND)
172                         ast_vhub_hub_suspend(vhub);
173                 if (istat & VHUB_IRQ_BUS_RESET)
174                         ast_vhub_hub_reset(vhub);
175         }
176
177  bail:
178         spin_unlock(&vhub->lock);
179         return iret;
180 }
181
182 void ast_vhub_init_hw(struct ast_vhub *vhub)
183 {
184         u32 ctrl;
185
186         UDCDBG(vhub,"(Re)Starting HW ...\n");
187
188         /* Enable PHY */
189         ctrl = VHUB_CTRL_PHY_CLK |
190                 VHUB_CTRL_PHY_RESET_DIS;
191
192        /*
193         * We do *NOT* set the VHUB_CTRL_CLK_STOP_SUSPEND bit
194         * to stop the logic clock during suspend because
195         * it causes the registers to become inaccessible and
196         * we haven't yet figured out a good wayt to bring the
197         * controller back into life to issue a wakeup.
198         */
199
200         /*
201          * Set some ISO & split control bits according to Aspeed
202          * recommendation
203          *
204          * VHUB_CTRL_ISO_RSP_CTRL: When set tells the HW to respond
205          * with 0 bytes data packet to ISO IN endpoints when no data
206          * is available.
207          *
208          * VHUB_CTRL_SPLIT_IN: This makes a SOF complete a split IN
209          * transaction.
210          */
211         ctrl |= VHUB_CTRL_ISO_RSP_CTRL | VHUB_CTRL_SPLIT_IN;
212         writel(ctrl, vhub->regs + AST_VHUB_CTRL);
213         udelay(1);
214
215         /* Set descriptor ring size */
216         if (AST_VHUB_DESCS_COUNT == 256) {
217                 ctrl |= VHUB_CTRL_LONG_DESC;
218                 writel(ctrl, vhub->regs + AST_VHUB_CTRL);
219         } else {
220                 BUILD_BUG_ON(AST_VHUB_DESCS_COUNT != 32);
221         }
222
223         /* Reset all devices */
224         writel(VHUB_SW_RESET_ALL, vhub->regs + AST_VHUB_SW_RESET);
225         udelay(1);
226         writel(0, vhub->regs + AST_VHUB_SW_RESET);
227
228         /* Disable and cleanup EP ACK/NACK interrupts */
229         writel(0, vhub->regs + AST_VHUB_EP_ACK_IER);
230         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);
233
234         /* Default settings for EP0, enable HW hub EP1 */
235         writel(0, vhub->regs + AST_VHUB_EP0_CTRL);
236         writel(VHUB_EP1_CTRL_RESET_TOGGLE |
237                VHUB_EP1_CTRL_ENABLE,
238                vhub->regs + AST_VHUB_EP1_CTRL);
239         writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG);
240
241         /* Configure EP0 DMA buffer */
242         writel(vhub->ep0.buf_dma, vhub->regs + AST_VHUB_EP0_DATA);
243
244         /* Clear address */
245         writel(0, vhub->regs + AST_VHUB_CONF);
246
247         /* Pullup hub (activate on host) */
248         if (vhub->force_usb1)
249                 ctrl |= VHUB_CTRL_FULL_SPEED_ONLY;
250
251         ctrl |= VHUB_CTRL_UPSTREAM_CONNECT;
252         writel(ctrl, vhub->regs + AST_VHUB_CTRL);
253
254         /* Enable some interrupts */
255         writel(VHUB_IRQ_HUB_EP0_IN_ACK_STALL |
256                VHUB_IRQ_HUB_EP0_OUT_ACK_STALL |
257                VHUB_IRQ_HUB_EP0_SETUP |
258                VHUB_IRQ_EP_POOL_ACK_STALL |
259                VHUB_IRQ_BUS_RESUME |
260                VHUB_IRQ_BUS_SUSPEND |
261                VHUB_IRQ_BUS_RESET,
262                vhub->regs + AST_VHUB_IER);
263 }
264
265 static int ast_vhub_remove(struct platform_device *pdev)
266 {
267         struct ast_vhub *vhub = platform_get_drvdata(pdev);
268         unsigned long flags;
269         int i;
270
271         if (!vhub || !vhub->regs)
272                 return 0;
273
274         /* Remove devices */
275         for (i = 0; i < AST_VHUB_NUM_PORTS; i++)
276                 ast_vhub_del_dev(&vhub->ports[i].dev);
277
278         spin_lock_irqsave(&vhub->lock, flags);
279
280         /* Mask & ack all interrupts  */
281         writel(0, vhub->regs + AST_VHUB_IER);
282         writel(VHUB_IRQ_ACK_ALL, vhub->regs + AST_VHUB_ISR);
283
284         /* Pull device, leave PHY enabled */
285         writel(VHUB_CTRL_PHY_CLK |
286                VHUB_CTRL_PHY_RESET_DIS,
287                vhub->regs + AST_VHUB_CTRL);
288
289         if (vhub->clk)
290                 clk_disable_unprepare(vhub->clk);
291
292         spin_unlock_irqrestore(&vhub->lock, flags);
293
294         if (vhub->ep0_bufs)
295                 dma_free_coherent(&pdev->dev,
296                                   AST_VHUB_EP0_MAX_PACKET *
297                                   (AST_VHUB_NUM_PORTS + 1),
298                                   vhub->ep0_bufs,
299                                   vhub->ep0_bufs_dma);
300         vhub->ep0_bufs = NULL;
301
302         return 0;
303 }
304
305 static int ast_vhub_probe(struct platform_device *pdev)
306 {
307         enum usb_device_speed max_speed;
308         struct ast_vhub *vhub;
309         struct resource *res;
310         int i, rc = 0;
311
312         vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL);
313         if (!vhub)
314                 return -ENOMEM;
315
316         spin_lock_init(&vhub->lock);
317         vhub->pdev = pdev;
318
319         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
320         vhub->regs = devm_ioremap_resource(&pdev->dev, res);
321         if (IS_ERR(vhub->regs)) {
322                 dev_err(&pdev->dev, "Failed to map resources\n");
323                 return PTR_ERR(vhub->regs);
324         }
325         UDCDBG(vhub, "vHub@%pR mapped @%p\n", res, vhub->regs);
326
327         platform_set_drvdata(pdev, vhub);
328
329         vhub->clk = devm_clk_get(&pdev->dev, NULL);
330         if (IS_ERR(vhub->clk)) {
331                 rc = PTR_ERR(vhub->clk);
332                 goto err;
333         }
334         rc = clk_prepare_enable(vhub->clk);
335         if (rc) {
336                 dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", rc);
337                 goto err;
338         }
339
340         /* Check if we need to limit the HW to USB1 */
341         max_speed = usb_get_maximum_speed(&pdev->dev);
342         if (max_speed != USB_SPEED_UNKNOWN && max_speed < USB_SPEED_HIGH)
343                 vhub->force_usb1 = true;
344
345         /* Mask & ack all interrupts before installing the handler */
346         writel(0, vhub->regs + AST_VHUB_IER);
347         writel(VHUB_IRQ_ACK_ALL, vhub->regs + AST_VHUB_ISR);
348
349         /* Find interrupt and install handler */
350         vhub->irq = platform_get_irq(pdev, 0);
351         if (vhub->irq < 0) {
352                 dev_err(&pdev->dev, "Failed to get interrupt\n");
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");