]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/usb/host/ehci-octeon.c
DMA-API: usb: use dma_set_coherent_mask()
[karo-tx-linux.git] / drivers / usb / host / ehci-octeon.c
1 /*
2  * EHCI HCD glue for Cavium Octeon II SOCs.
3  *
4  * Loosely based on ehci-au1xxx.c
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  *
10  * Copyright (C) 2010 Cavium Networks
11  *
12  */
13
14 #include <linux/platform_device.h>
15
16 #include <asm/octeon/octeon.h>
17 #include <asm/octeon/cvmx-uctlx-defs.h>
18
19 #define OCTEON_EHCI_HCD_NAME "octeon-ehci"
20
21 /* Common clock init code.  */
22 void octeon2_usb_clocks_start(void);
23 void octeon2_usb_clocks_stop(void);
24
25 static void ehci_octeon_start(void)
26 {
27         union cvmx_uctlx_ehci_ctl ehci_ctl;
28
29         octeon2_usb_clocks_start();
30
31         ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0));
32         /* Use 64-bit addressing. */
33         ehci_ctl.s.ehci_64b_addr_en = 1;
34         ehci_ctl.s.l2c_addr_msb = 0;
35         ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
36         ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
37         cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64);
38 }
39
40 static void ehci_octeon_stop(void)
41 {
42         octeon2_usb_clocks_stop();
43 }
44
45 static const struct hc_driver ehci_octeon_hc_driver = {
46         .description            = hcd_name,
47         .product_desc           = "Octeon EHCI",
48         .hcd_priv_size          = sizeof(struct ehci_hcd),
49
50         /*
51          * generic hardware linkage
52          */
53         .irq                    = ehci_irq,
54         .flags                  = HCD_MEMORY | HCD_USB2 | HCD_BH,
55
56         /*
57          * basic lifecycle operations
58          */
59         .reset                  = ehci_setup,
60         .start                  = ehci_run,
61         .stop                   = ehci_stop,
62         .shutdown               = ehci_shutdown,
63
64         /*
65          * managing i/o requests and associated device resources
66          */
67         .urb_enqueue            = ehci_urb_enqueue,
68         .urb_dequeue            = ehci_urb_dequeue,
69         .endpoint_disable       = ehci_endpoint_disable,
70         .endpoint_reset         = ehci_endpoint_reset,
71
72         /*
73          * scheduling support
74          */
75         .get_frame_number       = ehci_get_frame,
76
77         /*
78          * root hub support
79          */
80         .hub_status_data        = ehci_hub_status_data,
81         .hub_control            = ehci_hub_control,
82         .bus_suspend            = ehci_bus_suspend,
83         .bus_resume             = ehci_bus_resume,
84         .relinquish_port        = ehci_relinquish_port,
85         .port_handed_over       = ehci_port_handed_over,
86
87         .clear_tt_buffer_complete       = ehci_clear_tt_buffer_complete,
88 };
89
90 static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64);
91
92 static int ehci_octeon_drv_probe(struct platform_device *pdev)
93 {
94         struct usb_hcd *hcd;
95         struct ehci_hcd *ehci;
96         struct resource *res_mem;
97         int irq;
98         int ret;
99
100         if (usb_disabled())
101                 return -ENODEV;
102
103         irq = platform_get_irq(pdev, 0);
104         if (irq < 0) {
105                 dev_err(&pdev->dev, "No irq assigned\n");
106                 return -ENODEV;
107         }
108
109         res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
110         if (res_mem == NULL) {
111                 dev_err(&pdev->dev, "No register space assigned\n");
112                 return -ENODEV;
113         }
114
115         /*
116          * We can DMA from anywhere. But the descriptors must be in
117          * the lower 4GB.
118          */
119         pdev->dev.dma_mask = &ehci_octeon_dma_mask;
120         ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
121         if (ret)
122                 return ret;
123
124         hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon");
125         if (!hcd)
126                 return -ENOMEM;
127
128         hcd->rsrc_start = res_mem->start;
129         hcd->rsrc_len = resource_size(res_mem);
130
131         if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
132                                 OCTEON_EHCI_HCD_NAME)) {
133                 dev_err(&pdev->dev, "request_mem_region failed\n");
134                 ret = -EBUSY;
135                 goto err1;
136         }
137
138         hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
139         if (!hcd->regs) {
140                 dev_err(&pdev->dev, "ioremap failed\n");
141                 ret = -ENOMEM;
142                 goto err2;
143         }
144
145         ehci_octeon_start();
146
147         ehci = hcd_to_ehci(hcd);
148
149         /* Octeon EHCI matches CPU endianness. */
150 #ifdef __BIG_ENDIAN
151         ehci->big_endian_mmio = 1;
152 #endif
153
154         ehci->caps = hcd->regs;
155
156         ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
157         if (ret) {
158                 dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
159                 goto err3;
160         }
161
162         platform_set_drvdata(pdev, hcd);
163
164         return 0;
165 err3:
166         ehci_octeon_stop();
167
168         iounmap(hcd->regs);
169 err2:
170         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
171 err1:
172         usb_put_hcd(hcd);
173         return ret;
174 }
175
176 static int ehci_octeon_drv_remove(struct platform_device *pdev)
177 {
178         struct usb_hcd *hcd = platform_get_drvdata(pdev);
179
180         usb_remove_hcd(hcd);
181
182         ehci_octeon_stop();
183         iounmap(hcd->regs);
184         release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
185         usb_put_hcd(hcd);
186
187         return 0;
188 }
189
190 static struct platform_driver ehci_octeon_driver = {
191         .probe          = ehci_octeon_drv_probe,
192         .remove         = ehci_octeon_drv_remove,
193         .shutdown       = usb_hcd_platform_shutdown,
194         .driver = {
195                 .name   = OCTEON_EHCI_HCD_NAME,
196                 .owner  = THIS_MODULE,
197         }
198 };
199
200 MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME);