2 * EHCI HCD glue for Cavium Octeon II SOCs.
4 * Loosely based on ehci-au1xxx.c
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
10 * Copyright (C) 2010 Cavium Networks
14 #include <linux/platform_device.h>
16 #include <asm/octeon/octeon.h>
17 #include <asm/octeon/cvmx-uctlx-defs.h>
19 #define OCTEON_EHCI_HCD_NAME "octeon-ehci"
21 /* Common clock init code. */
22 void octeon2_usb_clocks_start(void);
23 void octeon2_usb_clocks_stop(void);
25 static void ehci_octeon_start(void)
27 union cvmx_uctlx_ehci_ctl ehci_ctl
;
29 octeon2_usb_clocks_start();
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
);
40 static void ehci_octeon_stop(void)
42 octeon2_usb_clocks_stop();
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
),
51 * generic hardware linkage
54 .flags
= HCD_MEMORY
| HCD_USB2
,
57 * basic lifecycle operations
62 .shutdown
= ehci_shutdown
,
65 * managing i/o requests and associated device resources
67 .urb_enqueue
= ehci_urb_enqueue
,
68 .urb_dequeue
= ehci_urb_dequeue
,
69 .endpoint_disable
= ehci_endpoint_disable
,
70 .endpoint_reset
= ehci_endpoint_reset
,
75 .get_frame_number
= ehci_get_frame
,
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
,
87 .clear_tt_buffer_complete
= ehci_clear_tt_buffer_complete
,
90 static u64 ehci_octeon_dma_mask
= DMA_BIT_MASK(64);
92 static int ehci_octeon_drv_probe(struct platform_device
*pdev
)
95 struct ehci_hcd
*ehci
;
96 struct resource
*res_mem
;
103 irq
= platform_get_irq(pdev
, 0);
105 dev_err(&pdev
->dev
, "No irq assigned\n");
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");
116 * We can DMA from anywhere. But the descriptors must be in
119 pdev
->dev
.coherent_dma_mask
= DMA_BIT_MASK(32);
120 pdev
->dev
.dma_mask
= &ehci_octeon_dma_mask
;
122 hcd
= usb_create_hcd(&ehci_octeon_hc_driver
, &pdev
->dev
, "octeon");
126 hcd
->rsrc_start
= res_mem
->start
;
127 hcd
->rsrc_len
= resource_size(res_mem
);
129 if (!request_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
,
130 OCTEON_EHCI_HCD_NAME
)) {
131 dev_err(&pdev
->dev
, "request_mem_region failed\n");
136 hcd
->regs
= ioremap(hcd
->rsrc_start
, hcd
->rsrc_len
);
138 dev_err(&pdev
->dev
, "ioremap failed\n");
145 ehci
= hcd_to_ehci(hcd
);
147 /* Octeon EHCI matches CPU endianness. */
149 ehci
->big_endian_mmio
= 1;
152 ehci
->caps
= hcd
->regs
;
153 ehci
->regs
= hcd
->regs
+
154 HC_LENGTH(ehci
, ehci_readl(ehci
, &ehci
->caps
->hc_capbase
));
155 /* cache this readonly data; minimize chip reads */
156 ehci
->hcs_params
= ehci_readl(ehci
, &ehci
->caps
->hcs_params
);
160 ret
= usb_add_hcd(hcd
, irq
, IRQF_SHARED
);
162 dev_dbg(&pdev
->dev
, "failed to add hcd with err %d\n", ret
);
166 platform_set_drvdata(pdev
, hcd
);
168 /* root ports should always stay powered */
169 ehci_port_power(ehci
, 1);
177 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
183 static int ehci_octeon_drv_remove(struct platform_device
*pdev
)
185 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
191 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
194 platform_set_drvdata(pdev
, NULL
);
199 static struct platform_driver ehci_octeon_driver
= {
200 .probe
= ehci_octeon_drv_probe
,
201 .remove
= ehci_octeon_drv_remove
,
202 .shutdown
= usb_hcd_platform_shutdown
,
204 .name
= OCTEON_EHCI_HCD_NAME
,
205 .owner
= THIS_MODULE
,
209 MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME
);