common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / usb / host / ehci-faraday.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Faraday USB 2.0 EHCI Controller
4  *
5  * (C) Copyright 2010 Faraday Technology
6  * Dante Su <dantesu@faraday-tech.com>
7  */
8
9 #include <common.h>
10 #include <log.h>
11 #include <asm/io.h>
12 #include <usb.h>
13 #include <linux/delay.h>
14 #include <usb/fusbh200.h>
15 #include <usb/fotg210.h>
16
17 #include "ehci.h"
18
19 #ifndef CONFIG_USB_EHCI_BASE_LIST
20 #define CONFIG_USB_EHCI_BASE_LIST       { CONFIG_USB_EHCI_BASE }
21 #endif
22
23 union ehci_faraday_regs {
24         struct fusbh200_regs usb;
25         struct fotg210_regs  otg;
26 };
27
28 static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
29 {
30         return !readl(&regs->usb.easstr);
31 }
32
33 void faraday_ehci_set_usbmode(struct ehci_ctrl *ctrl)
34 {
35         /* nothing needs to be done */
36 }
37
38 int faraday_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
39 {
40         int spd, ret = PORTSC_PSPD_HS;
41         union ehci_faraday_regs *regs;
42
43         ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
44         if (ehci_is_fotg2xx(regs))
45                 spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
46         else
47                 spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
48
49         switch (spd) {
50         case 0:    /* full speed */
51                 ret = PORTSC_PSPD_FS;
52                 break;
53         case 1:    /* low  speed */
54                 ret = PORTSC_PSPD_LS;
55                 break;
56         case 2:    /* high speed */
57                 ret = PORTSC_PSPD_HS;
58                 break;
59         default:
60                 printf("ehci-faraday: invalid device speed\n");
61                 break;
62         }
63
64         return ret;
65 }
66
67 uint32_t *faraday_ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
68 {
69         /* Faraday EHCI has one and only one portsc register */
70         if (port) {
71                 /* Printing the message would cause a scan failure! */
72                 debug("The request port(%d) is not configured\n", port);
73                 return NULL;
74         }
75
76         /* Faraday EHCI PORTSC register offset is 0x20 from hcor */
77         return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
78 }
79
80 static const struct ehci_ops faraday_ehci_ops = {
81         .set_usb_mode           = faraday_ehci_set_usbmode,
82         .get_port_speed         = faraday_ehci_get_port_speed,
83         .get_portsc_register    = faraday_ehci_get_portsc_register,
84 };
85
86 /*
87  * Create the appropriate control structures to manage
88  * a new EHCI host controller.
89  */
90 int ehci_hcd_init(int index, enum usb_init_type init,
91                 struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor)
92 {
93         struct ehci_hccr *hccr;
94         struct ehci_hcor *hcor;
95         union ehci_faraday_regs *regs;
96         uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
97
98         if (index < 0 || index >= ARRAY_SIZE(base_list))
99                 return -1;
100         ehci_set_controller_priv(index, NULL, &faraday_ehci_ops);
101         regs = (void __iomem *)base_list[index];
102         hccr = (struct ehci_hccr *)&regs->usb.hccr;
103         hcor = (struct ehci_hcor *)&regs->usb.hcor;
104
105         if (ehci_is_fotg2xx(regs)) {
106                 /* A-device bus reset */
107                 /* ... Power off A-device */
108                 setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
109                 /* ... Drop vbus and bus traffic */
110                 clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
111                 mdelay(1);
112                 /* ... Power on A-device */
113                 clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
114                 /* ... Drive vbus and bus traffic */
115                 setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
116                 mdelay(1);
117                 /* Disable OTG & DEV interrupts, triggered at level-high */
118                 writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
119                 /* Clear all interrupt status */
120                 writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
121         } else {
122                 /* Interrupt=level-high */
123                 setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
124                 /* VBUS on */
125                 clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
126                 /* Disable all interrupts */
127                 writel(0x00, &regs->usb.bmier);
128                 writel(0x1f, &regs->usb.bmisr);
129         }
130
131         *ret_hccr = hccr;
132         *ret_hcor = hcor;
133
134         return 0;
135 }
136
137 /*
138  * Destroy the appropriate control structures corresponding
139  * the the EHCI host controller.
140  */
141 int ehci_hcd_stop(int index)
142 {
143         return 0;
144 }