diff options
-rw-r--r-- | drivers/usb/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 17 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 6 | ||||
-rw-r--r-- | drivers/usb/host/fhci-dbg.c | 139 | ||||
-rw-r--r-- | drivers/usb/host/fhci-hcd.c | 836 | ||||
-rw-r--r-- | drivers/usb/host/fhci-hub.c | 345 | ||||
-rw-r--r-- | drivers/usb/host/fhci-mem.c | 113 | ||||
-rw-r--r-- | drivers/usb/host/fhci-q.c | 284 | ||||
-rw-r--r-- | drivers/usb/host/fhci-sched.c | 888 | ||||
-rw-r--r-- | drivers/usb/host/fhci-tds.c | 626 | ||||
-rw-r--r-- | drivers/usb/host/fhci.h | 607 |
11 files changed, 3862 insertions, 0 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 8b7c419b876e..8bcde8cde554 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile | |||
@@ -13,6 +13,7 @@ obj-$(CONFIG_USB_EHCI_HCD) += host/ | |||
13 | obj-$(CONFIG_USB_ISP116X_HCD) += host/ | 13 | obj-$(CONFIG_USB_ISP116X_HCD) += host/ |
14 | obj-$(CONFIG_USB_OHCI_HCD) += host/ | 14 | obj-$(CONFIG_USB_OHCI_HCD) += host/ |
15 | obj-$(CONFIG_USB_UHCI_HCD) += host/ | 15 | obj-$(CONFIG_USB_UHCI_HCD) += host/ |
16 | obj-$(CONFIG_USB_FHCI_HCD) += host/ | ||
16 | obj-$(CONFIG_USB_SL811_HCD) += host/ | 17 | obj-$(CONFIG_USB_SL811_HCD) += host/ |
17 | obj-$(CONFIG_USB_U132_HCD) += host/ | 18 | obj-$(CONFIG_USB_U132_HCD) += host/ |
18 | obj-$(CONFIG_USB_R8A66597_HCD) += host/ | 19 | obj-$(CONFIG_USB_R8A66597_HCD) += host/ |
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 5a988f4cdf87..2c63bfb1f8d9 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
@@ -239,6 +239,23 @@ config USB_UHCI_HCD | |||
239 | To compile this driver as a module, choose M here: the | 239 | To compile this driver as a module, choose M here: the |
240 | module will be called uhci-hcd. | 240 | module will be called uhci-hcd. |
241 | 241 | ||
242 | config USB_FHCI_HCD | ||
243 | tristate "Freescale QE USB Host Controller support" | ||
244 | depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE | ||
245 | select FSL_GTM | ||
246 | select QE_USB | ||
247 | help | ||
248 | This driver enables support for Freescale QE USB Host Controller | ||
249 | (as found on MPC8360 and MPC8323 processors), the driver supports | ||
250 | Full and Low Speed USB. | ||
251 | |||
252 | config FHCI_DEBUG | ||
253 | bool "Freescale QE USB Host Controller debug support" | ||
254 | depends on USB_FHCI_HCD && DEBUG_FS | ||
255 | help | ||
256 | Say "y" to see some FHCI debug information and statistics | ||
257 | throught debugfs. | ||
258 | |||
242 | config USB_U132_HCD | 259 | config USB_U132_HCD |
243 | tristate "Elan U132 Adapter Host Controller" | 260 | tristate "Elan U132 Adapter Host Controller" |
244 | depends on USB && USB_FTDI_ELAN | 261 | depends on USB && USB_FTDI_ELAN |
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index e5f3f20787e4..f163571e33d8 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
@@ -7,6 +7,11 @@ ifeq ($(CONFIG_USB_DEBUG),y) | |||
7 | endif | 7 | endif |
8 | 8 | ||
9 | isp1760-objs := isp1760-hcd.o isp1760-if.o | 9 | isp1760-objs := isp1760-hcd.o isp1760-if.o |
10 | fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \ | ||
11 | fhci-tds.o fhci-sched.o | ||
12 | ifeq ($(CONFIG_FHCI_DEBUG),y) | ||
13 | fhci-objs += fhci-dbg.o | ||
14 | endif | ||
10 | 15 | ||
11 | obj-$(CONFIG_USB_WHCI_HCD) += whci/ | 16 | obj-$(CONFIG_USB_WHCI_HCD) += whci/ |
12 | 17 | ||
@@ -17,6 +22,7 @@ obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o | |||
17 | obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o | 22 | obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o |
18 | obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o | 23 | obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o |
19 | obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o | 24 | obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o |
25 | obj-$(CONFIG_USB_FHCI_HCD) += fhci.o | ||
20 | obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o | 26 | obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o |
21 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o | 27 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o |
22 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o | 28 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o |
diff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c new file mode 100644 index 000000000000..34e14edf390b --- /dev/null +++ b/drivers/usb/host/fhci-dbg.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/debugfs.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/usb.h> | ||
23 | #include "../core/hcd.h" | ||
24 | #include "fhci.h" | ||
25 | |||
26 | void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er) | ||
27 | { | ||
28 | int i; | ||
29 | |||
30 | if (usb_er == -1) { | ||
31 | fhci->usb_irq_stat[12]++; | ||
32 | return; | ||
33 | } | ||
34 | |||
35 | for (i = 0; i < 12; ++i) { | ||
36 | if (usb_er & (1 << i)) | ||
37 | fhci->usb_irq_stat[i]++; | ||
38 | } | ||
39 | } | ||
40 | |||
41 | static int fhci_dfs_regs_show(struct seq_file *s, void *v) | ||
42 | { | ||
43 | struct fhci_hcd *fhci = s->private; | ||
44 | struct fhci_regs __iomem *regs = fhci->regs; | ||
45 | |||
46 | seq_printf(s, | ||
47 | "mode: 0x%x\n" "addr: 0x%x\n" | ||
48 | "command: 0x%x\n" "ep0: 0x%x\n" | ||
49 | "event: 0x%x\n" "mask: 0x%x\n" | ||
50 | "status: 0x%x\n" "SOF timer: %d\n" | ||
51 | "frame number: %d\n" | ||
52 | "lines status: 0x%x\n", | ||
53 | in_8(®s->usb_mod), in_8(®s->usb_addr), | ||
54 | in_8(®s->usb_comm), in_be16(®s->usb_ep[0]), | ||
55 | in_be16(®s->usb_event), in_be16(®s->usb_mask), | ||
56 | in_8(®s->usb_status), in_be16(®s->usb_sof_tmr), | ||
57 | in_be16(®s->usb_frame_num), | ||
58 | fhci_ioports_check_bus_state(fhci)); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v) | ||
64 | { | ||
65 | struct fhci_hcd *fhci = s->private; | ||
66 | int *usb_irq_stat = fhci->usb_irq_stat; | ||
67 | |||
68 | seq_printf(s, | ||
69 | "RXB: %d\n" "TXB: %d\n" "BSY: %d\n" | ||
70 | "SOF: %d\n" "TXE0: %d\n" "TXE1: %d\n" | ||
71 | "TXE2: %d\n" "TXE3: %d\n" "IDLE: %d\n" | ||
72 | "RESET: %d\n" "SFT: %d\n" "MSF: %d\n" | ||
73 | "IDLE_ONLY: %d\n", | ||
74 | usb_irq_stat[0], usb_irq_stat[1], usb_irq_stat[2], | ||
75 | usb_irq_stat[3], usb_irq_stat[4], usb_irq_stat[5], | ||
76 | usb_irq_stat[6], usb_irq_stat[7], usb_irq_stat[8], | ||
77 | usb_irq_stat[9], usb_irq_stat[10], usb_irq_stat[11], | ||
78 | usb_irq_stat[12]); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int fhci_dfs_regs_open(struct inode *inode, struct file *file) | ||
84 | { | ||
85 | return single_open(file, fhci_dfs_regs_show, inode->i_private); | ||
86 | } | ||
87 | |||
88 | static int fhci_dfs_irq_stat_open(struct inode *inode, struct file *file) | ||
89 | { | ||
90 | return single_open(file, fhci_dfs_irq_stat_show, inode->i_private); | ||
91 | } | ||
92 | |||
93 | static const struct file_operations fhci_dfs_regs_fops = { | ||
94 | .open = fhci_dfs_regs_open, | ||
95 | .read = seq_read, | ||
96 | .llseek = seq_lseek, | ||
97 | .release = single_release, | ||
98 | }; | ||
99 | |||
100 | static const struct file_operations fhci_dfs_irq_stat_fops = { | ||
101 | .open = fhci_dfs_irq_stat_open, | ||
102 | .read = seq_read, | ||
103 | .llseek = seq_lseek, | ||
104 | .release = single_release, | ||
105 | }; | ||
106 | |||
107 | void fhci_dfs_create(struct fhci_hcd *fhci) | ||
108 | { | ||
109 | struct device *dev = fhci_to_hcd(fhci)->self.controller; | ||
110 | |||
111 | fhci->dfs_root = debugfs_create_dir(dev->bus_id, NULL); | ||
112 | if (!fhci->dfs_root) { | ||
113 | WARN_ON(1); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | fhci->dfs_regs = debugfs_create_file("regs", S_IFREG | S_IRUGO, | ||
118 | fhci->dfs_root, fhci, &fhci_dfs_regs_fops); | ||
119 | |||
120 | fhci->dfs_irq_stat = debugfs_create_file("irq_stat", | ||
121 | S_IFREG | S_IRUGO, fhci->dfs_root, fhci, | ||
122 | &fhci_dfs_irq_stat_fops); | ||
123 | |||
124 | WARN_ON(!fhci->dfs_regs || !fhci->dfs_irq_stat); | ||
125 | } | ||
126 | |||
127 | void fhci_dfs_destroy(struct fhci_hcd *fhci) | ||
128 | { | ||
129 | if (!fhci->dfs_root) | ||
130 | return; | ||
131 | |||
132 | if (fhci->dfs_irq_stat) | ||
133 | debugfs_remove(fhci->dfs_irq_stat); | ||
134 | |||
135 | if (fhci->dfs_regs) | ||
136 | debugfs_remove(fhci->dfs_regs); | ||
137 | |||
138 | debugfs_remove(fhci->dfs_root); | ||
139 | } | ||
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c new file mode 100644 index 000000000000..ba622cc8a9ba --- /dev/null +++ b/drivers/usb/host/fhci-hcd.c | |||
@@ -0,0 +1,836 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/usb.h> | ||
28 | #include <linux/of_platform.h> | ||
29 | #include <linux/of_gpio.h> | ||
30 | #include <asm/qe.h> | ||
31 | #include <asm/fsl_gtm.h> | ||
32 | #include "../core/hcd.h" | ||
33 | #include "fhci.h" | ||
34 | |||
35 | void fhci_start_sof_timer(struct fhci_hcd *fhci) | ||
36 | { | ||
37 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
38 | |||
39 | /* clear frame_n */ | ||
40 | out_be16(&fhci->pram->frame_num, 0); | ||
41 | |||
42 | out_be16(&fhci->regs->usb_sof_tmr, 0); | ||
43 | setbits8(&fhci->regs->usb_mod, USB_MODE_SFTE); | ||
44 | |||
45 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
46 | } | ||
47 | |||
48 | void fhci_stop_sof_timer(struct fhci_hcd *fhci) | ||
49 | { | ||
50 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
51 | |||
52 | clrbits8(&fhci->regs->usb_mod, USB_MODE_SFTE); | ||
53 | gtm_stop_timer16(fhci->timer); | ||
54 | |||
55 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
56 | } | ||
57 | |||
58 | u16 fhci_get_sof_timer_count(struct fhci_usb *usb) | ||
59 | { | ||
60 | return be16_to_cpu(in_be16(&usb->fhci->regs->usb_sof_tmr) / 12); | ||
61 | } | ||
62 | |||
63 | /* initialize the endpoint zero */ | ||
64 | static u32 endpoint_zero_init(struct fhci_usb *usb, | ||
65 | enum fhci_mem_alloc data_mem, | ||
66 | u32 ring_len) | ||
67 | { | ||
68 | u32 rc; | ||
69 | |||
70 | rc = fhci_create_ep(usb, data_mem, ring_len); | ||
71 | if (rc) | ||
72 | return rc; | ||
73 | |||
74 | /* inilialize endpoint registers */ | ||
75 | fhci_init_ep_registers(usb, usb->ep0, data_mem); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* enable the USB interrupts */ | ||
81 | void fhci_usb_enable_interrupt(struct fhci_usb *usb) | ||
82 | { | ||
83 | struct fhci_hcd *fhci = usb->fhci; | ||
84 | |||
85 | if (usb->intr_nesting_cnt == 1) { | ||
86 | /* initialize the USB interrupt */ | ||
87 | enable_irq(fhci_to_hcd(fhci)->irq); | ||
88 | |||
89 | /* initialize the event register and mask register */ | ||
90 | out_be16(&usb->fhci->regs->usb_event, 0xffff); | ||
91 | out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); | ||
92 | |||
93 | /* enable the timer interrupts */ | ||
94 | enable_irq(fhci->timer->irq); | ||
95 | } else if (usb->intr_nesting_cnt > 1) | ||
96 | fhci_info(fhci, "unbalanced USB interrupts nesting\n"); | ||
97 | usb->intr_nesting_cnt--; | ||
98 | } | ||
99 | |||
100 | /* diable the usb interrupt */ | ||
101 | void fhci_usb_disable_interrupt(struct fhci_usb *usb) | ||
102 | { | ||
103 | struct fhci_hcd *fhci = usb->fhci; | ||
104 | |||
105 | if (usb->intr_nesting_cnt == 0) { | ||
106 | /* diable the timer interrupt */ | ||
107 | disable_irq_nosync(fhci->timer->irq); | ||
108 | |||
109 | /* disable the usb interrupt */ | ||
110 | disable_irq_nosync(fhci_to_hcd(fhci)->irq); | ||
111 | out_be16(&usb->fhci->regs->usb_mask, 0); | ||
112 | } | ||
113 | usb->intr_nesting_cnt++; | ||
114 | } | ||
115 | |||
116 | /* enable the USB controller */ | ||
117 | static u32 fhci_usb_enable(struct fhci_hcd *fhci) | ||
118 | { | ||
119 | struct fhci_usb *usb = fhci->usb_lld; | ||
120 | |||
121 | out_be16(&usb->fhci->regs->usb_event, 0xffff); | ||
122 | out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); | ||
123 | setbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN); | ||
124 | |||
125 | mdelay(100); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* disable the USB controller */ | ||
131 | static u32 fhci_usb_disable(struct fhci_hcd *fhci) | ||
132 | { | ||
133 | struct fhci_usb *usb = fhci->usb_lld; | ||
134 | |||
135 | fhci_usb_disable_interrupt(usb); | ||
136 | fhci_port_disable(fhci); | ||
137 | |||
138 | /* disable the usb controller */ | ||
139 | if (usb->port_status == FHCI_PORT_FULL || | ||
140 | usb->port_status == FHCI_PORT_LOW) | ||
141 | fhci_device_disconnected_interrupt(fhci); | ||
142 | |||
143 | clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* check the bus state by polling the QE bit on the IO ports */ | ||
149 | int fhci_ioports_check_bus_state(struct fhci_hcd *fhci) | ||
150 | { | ||
151 | u8 bits = 0; | ||
152 | |||
153 | /* check USBOE,if transmitting,exit */ | ||
154 | if (!gpio_get_value(fhci->gpios[GPIO_USBOE])) | ||
155 | return -1; | ||
156 | |||
157 | /* check USBRP */ | ||
158 | if (gpio_get_value(fhci->gpios[GPIO_USBRP])) | ||
159 | bits |= 0x2; | ||
160 | |||
161 | /* check USBRN */ | ||
162 | if (gpio_get_value(fhci->gpios[GPIO_USBRN])) | ||
163 | bits |= 0x1; | ||
164 | |||
165 | return bits; | ||
166 | } | ||
167 | |||
168 | static void fhci_mem_free(struct fhci_hcd *fhci) | ||
169 | { | ||
170 | struct ed *ed; | ||
171 | struct ed *next_ed; | ||
172 | struct td *td; | ||
173 | struct td *next_td; | ||
174 | |||
175 | list_for_each_entry_safe(ed, next_ed, &fhci->empty_eds, node) { | ||
176 | list_del(&ed->node); | ||
177 | kfree(ed); | ||
178 | } | ||
179 | |||
180 | list_for_each_entry_safe(td, next_td, &fhci->empty_tds, node) { | ||
181 | list_del(&td->node); | ||
182 | kfree(td); | ||
183 | } | ||
184 | |||
185 | kfree(fhci->vroot_hub); | ||
186 | fhci->vroot_hub = NULL; | ||
187 | |||
188 | kfree(fhci->hc_list); | ||
189 | fhci->hc_list = NULL; | ||
190 | } | ||
191 | |||
192 | static int fhci_mem_init(struct fhci_hcd *fhci) | ||
193 | { | ||
194 | int i; | ||
195 | |||
196 | fhci->hc_list = kzalloc(sizeof(*fhci->hc_list), GFP_KERNEL); | ||
197 | if (!fhci->hc_list) | ||
198 | goto err; | ||
199 | |||
200 | INIT_LIST_HEAD(&fhci->hc_list->ctrl_list); | ||
201 | INIT_LIST_HEAD(&fhci->hc_list->bulk_list); | ||
202 | INIT_LIST_HEAD(&fhci->hc_list->iso_list); | ||
203 | INIT_LIST_HEAD(&fhci->hc_list->intr_list); | ||
204 | INIT_LIST_HEAD(&fhci->hc_list->done_list); | ||
205 | |||
206 | fhci->vroot_hub = kzalloc(sizeof(*fhci->vroot_hub), GFP_KERNEL); | ||
207 | if (!fhci->vroot_hub) | ||
208 | goto err; | ||
209 | |||
210 | INIT_LIST_HEAD(&fhci->empty_eds); | ||
211 | INIT_LIST_HEAD(&fhci->empty_tds); | ||
212 | |||
213 | /* initialize work queue to handle done list */ | ||
214 | fhci_tasklet.data = (unsigned long)fhci; | ||
215 | fhci->process_done_task = &fhci_tasklet; | ||
216 | |||
217 | for (i = 0; i < MAX_TDS; i++) { | ||
218 | struct td *td; | ||
219 | |||
220 | td = kmalloc(sizeof(*td), GFP_KERNEL); | ||
221 | if (!td) | ||
222 | goto err; | ||
223 | fhci_recycle_empty_td(fhci, td); | ||
224 | } | ||
225 | for (i = 0; i < MAX_EDS; i++) { | ||
226 | struct ed *ed; | ||
227 | |||
228 | ed = kmalloc(sizeof(*ed), GFP_KERNEL); | ||
229 | if (!ed) | ||
230 | goto err; | ||
231 | fhci_recycle_empty_ed(fhci, ed); | ||
232 | } | ||
233 | |||
234 | fhci->active_urbs = 0; | ||
235 | return 0; | ||
236 | err: | ||
237 | fhci_mem_free(fhci); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | |||
241 | /* destroy the fhci_usb structure */ | ||
242 | static void fhci_usb_free(void *lld) | ||
243 | { | ||
244 | struct fhci_usb *usb = lld; | ||
245 | struct fhci_hcd *fhci = usb->fhci; | ||
246 | |||
247 | if (usb) { | ||
248 | fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); | ||
249 | fhci_ep0_free(usb); | ||
250 | kfree(usb->actual_frame); | ||
251 | kfree(usb); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | /* initialize the USB */ | ||
256 | static int fhci_usb_init(struct fhci_hcd *fhci) | ||
257 | { | ||
258 | struct fhci_usb *usb = fhci->usb_lld; | ||
259 | |||
260 | memset_io(usb->fhci->pram, 0, FHCI_PRAM_SIZE); | ||
261 | |||
262 | usb->port_status = FHCI_PORT_DISABLED; | ||
263 | usb->max_frame_usage = FRAME_TIME_USAGE; | ||
264 | usb->sw_transaction_time = SW_FIX_TIME_BETWEEN_TRANSACTION; | ||
265 | |||
266 | usb->actual_frame = kzalloc(sizeof(*usb->actual_frame), GFP_KERNEL); | ||
267 | if (!usb->actual_frame) { | ||
268 | fhci_usb_free(usb); | ||
269 | return -ENOMEM; | ||
270 | } | ||
271 | |||
272 | INIT_LIST_HEAD(&usb->actual_frame->tds_list); | ||
273 | |||
274 | /* initializing registers on chip, clear frame number */ | ||
275 | out_be16(&fhci->pram->frame_num, 0); | ||
276 | |||
277 | /* clear rx state */ | ||
278 | out_be32(&fhci->pram->rx_state, 0); | ||
279 | |||
280 | /* set mask register */ | ||
281 | usb->saved_msk = (USB_E_TXB_MASK | | ||
282 | USB_E_TXE1_MASK | | ||
283 | USB_E_IDLE_MASK | | ||
284 | USB_E_RESET_MASK | USB_E_SFT_MASK | USB_E_MSF_MASK); | ||
285 | |||
286 | out_8(&usb->fhci->regs->usb_mod, USB_MODE_HOST | USB_MODE_EN); | ||
287 | |||
288 | /* clearing the mask register */ | ||
289 | out_be16(&usb->fhci->regs->usb_mask, 0); | ||
290 | |||
291 | /* initialing the event register */ | ||
292 | out_be16(&usb->fhci->regs->usb_event, 0xffff); | ||
293 | |||
294 | if (endpoint_zero_init(usb, DEFAULT_DATA_MEM, DEFAULT_RING_LEN) != 0) { | ||
295 | fhci_usb_free(usb); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* initialize the fhci_usb struct and the corresponding data staruct */ | ||
303 | static struct fhci_usb *fhci_create_lld(struct fhci_hcd *fhci) | ||
304 | { | ||
305 | struct fhci_usb *usb; | ||
306 | |||
307 | /* allocate memory for SCC data structure */ | ||
308 | usb = kzalloc(sizeof(*usb), GFP_KERNEL); | ||
309 | if (!usb) { | ||
310 | fhci_err(fhci, "no memory for SCC data struct\n"); | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | usb->fhci = fhci; | ||
315 | usb->hc_list = fhci->hc_list; | ||
316 | usb->vroot_hub = fhci->vroot_hub; | ||
317 | |||
318 | usb->transfer_confirm = fhci_transfer_confirm_callback; | ||
319 | |||
320 | return usb; | ||
321 | } | ||
322 | |||
323 | static int fhci_start(struct usb_hcd *hcd) | ||
324 | { | ||
325 | int ret; | ||
326 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
327 | |||
328 | ret = fhci_mem_init(fhci); | ||
329 | if (ret) { | ||
330 | fhci_err(fhci, "failed to allocate memory\n"); | ||
331 | goto err; | ||
332 | } | ||
333 | |||
334 | fhci->usb_lld = fhci_create_lld(fhci); | ||
335 | if (!fhci->usb_lld) { | ||
336 | fhci_err(fhci, "low level driver config failed\n"); | ||
337 | ret = -ENOMEM; | ||
338 | goto err; | ||
339 | } | ||
340 | |||
341 | ret = fhci_usb_init(fhci); | ||
342 | if (ret) { | ||
343 | fhci_err(fhci, "low level driver initialize failed\n"); | ||
344 | goto err; | ||
345 | } | ||
346 | |||
347 | spin_lock_init(&fhci->lock); | ||
348 | |||
349 | /* connect the virtual root hub */ | ||
350 | fhci->vroot_hub->dev_num = 1; /* this field may be needed to fix */ | ||
351 | fhci->vroot_hub->hub.wHubStatus = 0; | ||
352 | fhci->vroot_hub->hub.wHubChange = 0; | ||
353 | fhci->vroot_hub->port.wPortStatus = 0; | ||
354 | fhci->vroot_hub->port.wPortChange = 0; | ||
355 | |||
356 | hcd->state = HC_STATE_RUNNING; | ||
357 | |||
358 | /* | ||
359 | * From here on, khubd concurrently accesses the root | ||
360 | * hub; drivers will be talking to enumerated devices. | ||
361 | * (On restart paths, khubd already knows about the root | ||
362 | * hub and could find work as soon as we wrote FLAG_CF.) | ||
363 | * | ||
364 | * Before this point the HC was idle/ready. After, khubd | ||
365 | * and device drivers may start it running. | ||
366 | */ | ||
367 | fhci_usb_enable(fhci); | ||
368 | return 0; | ||
369 | err: | ||
370 | fhci_mem_free(fhci); | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static void fhci_stop(struct usb_hcd *hcd) | ||
375 | { | ||
376 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
377 | |||
378 | fhci_usb_disable_interrupt(fhci->usb_lld); | ||
379 | fhci_usb_disable(fhci); | ||
380 | |||
381 | fhci_usb_free(fhci->usb_lld); | ||
382 | fhci->usb_lld = NULL; | ||
383 | fhci_mem_free(fhci); | ||
384 | } | ||
385 | |||
386 | static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, | ||
387 | gfp_t mem_flags) | ||
388 | { | ||
389 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
390 | u32 pipe = urb->pipe; | ||
391 | int ret; | ||
392 | int i; | ||
393 | int size = 0; | ||
394 | struct urb_priv *urb_priv; | ||
395 | unsigned long flags; | ||
396 | |||
397 | switch (usb_pipetype(pipe)) { | ||
398 | case PIPE_CONTROL: | ||
399 | /* 1 td fro setup,1 for ack */ | ||
400 | size = 2; | ||
401 | case PIPE_BULK: | ||
402 | /* one td for every 4096 bytes(can be upto 8k) */ | ||
403 | size += urb->transfer_buffer_length / 4096; | ||
404 | /* ...add for any remaining bytes... */ | ||
405 | if ((urb->transfer_buffer_length % 4096) != 0) | ||
406 | size++; | ||
407 | /* ..and maybe a zero length packet to wrap it up */ | ||
408 | if (size == 0) | ||
409 | size++; | ||
410 | else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 | ||
411 | && (urb->transfer_buffer_length | ||
412 | % usb_maxpacket(urb->dev, pipe, | ||
413 | usb_pipeout(pipe))) != 0) | ||
414 | size++; | ||
415 | break; | ||
416 | case PIPE_ISOCHRONOUS: | ||
417 | size = urb->number_of_packets; | ||
418 | if (size <= 0) | ||
419 | return -EINVAL; | ||
420 | for (i = 0; i < urb->number_of_packets; i++) { | ||
421 | urb->iso_frame_desc[i].actual_length = 0; | ||
422 | urb->iso_frame_desc[i].status = (u32) (-EXDEV); | ||
423 | } | ||
424 | break; | ||
425 | case PIPE_INTERRUPT: | ||
426 | size = 1; | ||
427 | } | ||
428 | |||
429 | /* allocate the private part of the URB */ | ||
430 | urb_priv = kzalloc(sizeof(*urb_priv), mem_flags); | ||
431 | if (!urb_priv) | ||
432 | return -ENOMEM; | ||
433 | |||
434 | /* allocate the private part of the URB */ | ||
435 | urb_priv->tds = kzalloc(size * sizeof(struct td), mem_flags); | ||
436 | if (!urb_priv->tds) { | ||
437 | kfree(urb_priv); | ||
438 | return -ENOMEM; | ||
439 | } | ||
440 | |||
441 | spin_lock_irqsave(&fhci->lock, flags); | ||
442 | |||
443 | ret = usb_hcd_link_urb_to_ep(hcd, urb); | ||
444 | if (ret) | ||
445 | goto err; | ||
446 | |||
447 | /* fill the private part of the URB */ | ||
448 | urb_priv->num_of_tds = size; | ||
449 | |||
450 | urb->status = -EINPROGRESS; | ||
451 | urb->actual_length = 0; | ||
452 | urb->error_count = 0; | ||
453 | urb->hcpriv = urb_priv; | ||
454 | |||
455 | fhci_queue_urb(fhci, urb); | ||
456 | err: | ||
457 | if (ret) { | ||
458 | kfree(urb_priv->tds); | ||
459 | kfree(urb_priv); | ||
460 | } | ||
461 | spin_unlock_irqrestore(&fhci->lock, flags); | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | /* dequeue FHCI URB */ | ||
466 | static int fhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | ||
467 | { | ||
468 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
469 | struct fhci_usb *usb = fhci->usb_lld; | ||
470 | int ret = -EINVAL; | ||
471 | unsigned long flags; | ||
472 | |||
473 | if (!urb || !urb->dev || !urb->dev->bus) | ||
474 | goto out; | ||
475 | |||
476 | spin_lock_irqsave(&fhci->lock, flags); | ||
477 | |||
478 | ret = usb_hcd_check_unlink_urb(hcd, urb, status); | ||
479 | if (ret) | ||
480 | goto out2; | ||
481 | |||
482 | if (usb->port_status != FHCI_PORT_DISABLED) { | ||
483 | struct urb_priv *urb_priv; | ||
484 | |||
485 | /* | ||
486 | * flag the urb's data for deletion in some upcoming | ||
487 | * SF interrupt's delete list processing | ||
488 | */ | ||
489 | urb_priv = urb->hcpriv; | ||
490 | |||
491 | if (!urb_priv || (urb_priv->state == URB_DEL)) | ||
492 | goto out2; | ||
493 | |||
494 | urb_priv->state = URB_DEL; | ||
495 | |||
496 | /* already pending? */ | ||
497 | urb_priv->ed->state = FHCI_ED_URB_DEL; | ||
498 | } else { | ||
499 | fhci_urb_complete_free(fhci, urb); | ||
500 | } | ||
501 | |||
502 | out2: | ||
503 | spin_unlock_irqrestore(&fhci->lock, flags); | ||
504 | out: | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | static void fhci_endpoint_disable(struct usb_hcd *hcd, | ||
509 | struct usb_host_endpoint *ep) | ||
510 | { | ||
511 | struct fhci_hcd *fhci; | ||
512 | struct ed *ed; | ||
513 | unsigned long flags; | ||
514 | |||
515 | fhci = hcd_to_fhci(hcd); | ||
516 | spin_lock_irqsave(&fhci->lock, flags); | ||
517 | ed = ep->hcpriv; | ||
518 | if (ed) { | ||
519 | while (ed->td_head != NULL) { | ||
520 | struct td *td = fhci_remove_td_from_ed(ed); | ||
521 | fhci_urb_complete_free(fhci, td->urb); | ||
522 | } | ||
523 | fhci_recycle_empty_ed(fhci, ed); | ||
524 | ep->hcpriv = NULL; | ||
525 | } | ||
526 | spin_unlock_irqrestore(&fhci->lock, flags); | ||
527 | } | ||
528 | |||
529 | static int fhci_get_frame_number(struct usb_hcd *hcd) | ||
530 | { | ||
531 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
532 | |||
533 | return get_frame_num(fhci); | ||
534 | } | ||
535 | |||
536 | static const struct hc_driver fhci_driver = { | ||
537 | .description = "fsl,usb-fhci", | ||
538 | .product_desc = "FHCI HOST Controller", | ||
539 | .hcd_priv_size = sizeof(struct fhci_hcd), | ||
540 | |||
541 | /* generic hardware linkage */ | ||
542 | .irq = fhci_irq, | ||
543 | .flags = HCD_USB11 | HCD_MEMORY, | ||
544 | |||
545 | /* basic lifecycle operation */ | ||
546 | .start = fhci_start, | ||
547 | .stop = fhci_stop, | ||
548 | |||
549 | /* managing i/o requests and associated device resources */ | ||
550 | .urb_enqueue = fhci_urb_enqueue, | ||
551 | .urb_dequeue = fhci_urb_dequeue, | ||
552 | .endpoint_disable = fhci_endpoint_disable, | ||
553 | |||
554 | /* scheduling support */ | ||
555 | .get_frame_number = fhci_get_frame_number, | ||
556 | |||
557 | /* root hub support */ | ||
558 | .hub_status_data = fhci_hub_status_data, | ||
559 | .hub_control = fhci_hub_control, | ||
560 | }; | ||
561 | |||
562 | static int __devinit of_fhci_probe(struct of_device *ofdev, | ||
563 | const struct of_device_id *ofid) | ||
564 | { | ||
565 | struct device *dev = &ofdev->dev; | ||
566 | struct device_node *node = ofdev->node; | ||
567 | struct usb_hcd *hcd; | ||
568 | struct fhci_hcd *fhci; | ||
569 | struct resource usb_regs; | ||
570 | unsigned long pram_addr; | ||
571 | unsigned int usb_irq; | ||
572 | const char *sprop; | ||
573 | const u32 *iprop; | ||
574 | int size; | ||
575 | int ret; | ||
576 | int i; | ||
577 | int j; | ||
578 | |||
579 | if (usb_disabled()) | ||
580 | return -ENODEV; | ||
581 | |||
582 | sprop = of_get_property(node, "mode", NULL); | ||
583 | if (sprop && strcmp(sprop, "host")) | ||
584 | return -ENODEV; | ||
585 | |||
586 | hcd = usb_create_hcd(&fhci_driver, dev, dev->bus_id); | ||
587 | if (!hcd) { | ||
588 | dev_err(dev, "could not create hcd\n"); | ||
589 | return -ENOMEM; | ||
590 | } | ||
591 | |||
592 | fhci = hcd_to_fhci(hcd); | ||
593 | hcd->self.controller = dev; | ||
594 | dev_set_drvdata(dev, hcd); | ||
595 | |||
596 | iprop = of_get_property(node, "hub-power-budget", &size); | ||
597 | if (iprop && size == sizeof(*iprop)) | ||
598 | hcd->power_budget = *iprop; | ||
599 | |||
600 | /* FHCI registers. */ | ||
601 | ret = of_address_to_resource(node, 0, &usb_regs); | ||
602 | if (ret) { | ||
603 | dev_err(dev, "could not get regs\n"); | ||
604 | goto err_regs; | ||
605 | } | ||
606 | |||
607 | hcd->regs = ioremap(usb_regs.start, usb_regs.end - usb_regs.start + 1); | ||
608 | if (!hcd->regs) { | ||
609 | dev_err(dev, "could not ioremap regs\n"); | ||
610 | ret = -ENOMEM; | ||
611 | goto err_regs; | ||
612 | } | ||
613 | fhci->regs = hcd->regs; | ||
614 | |||
615 | /* Parameter RAM. */ | ||
616 | iprop = of_get_property(node, "reg", &size); | ||
617 | if (!iprop || size < sizeof(*iprop) * 4) { | ||
618 | dev_err(dev, "can't get pram offset\n"); | ||
619 | ret = -EINVAL; | ||
620 | goto err_pram; | ||
621 | } | ||
622 | |||
623 | pram_addr = cpm_muram_alloc_fixed(iprop[2], FHCI_PRAM_SIZE); | ||
624 | if (IS_ERR_VALUE(pram_addr)) { | ||
625 | dev_err(dev, "failed to allocate usb pram\n"); | ||
626 | ret = -ENOMEM; | ||
627 | goto err_pram; | ||
628 | } | ||
629 | fhci->pram = cpm_muram_addr(pram_addr); | ||
630 | |||
631 | /* GPIOs and pins */ | ||
632 | for (i = 0; i < NUM_GPIOS; i++) { | ||
633 | int gpio; | ||
634 | enum of_gpio_flags flags; | ||
635 | |||
636 | gpio = of_get_gpio_flags(node, i, &flags); | ||
637 | fhci->gpios[i] = gpio; | ||
638 | fhci->alow_gpios[i] = flags & OF_GPIO_ACTIVE_LOW; | ||
639 | |||
640 | if (!gpio_is_valid(gpio)) { | ||
641 | if (i < GPIO_SPEED) { | ||
642 | dev_err(dev, "incorrect GPIO%d: %d\n", | ||
643 | i, gpio); | ||
644 | goto err_gpios; | ||
645 | } else { | ||
646 | dev_info(dev, "assuming board doesn't have " | ||
647 | "%s gpio\n", i == GPIO_SPEED ? | ||
648 | "speed" : "power"); | ||
649 | continue; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | ret = gpio_request(gpio, dev->bus_id); | ||
654 | if (ret) { | ||
655 | dev_err(dev, "failed to request gpio %d", i); | ||
656 | goto err_gpios; | ||
657 | } | ||
658 | |||
659 | if (i >= GPIO_SPEED) { | ||
660 | ret = gpio_direction_output(gpio, 0); | ||
661 | if (ret) { | ||
662 | dev_err(dev, "failed to set gpio %d as " | ||
663 | "an output\n", i); | ||
664 | i++; | ||
665 | goto err_gpios; | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | |||
670 | for (j = 0; j < NUM_PINS; j++) { | ||
671 | fhci->pins[j] = qe_pin_request(ofdev->node, j); | ||
672 | if (IS_ERR(fhci->pins[j])) { | ||
673 | ret = PTR_ERR(fhci->pins[j]); | ||
674 | dev_err(dev, "can't get pin %d: %d\n", j, ret); | ||
675 | goto err_pins; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | /* Frame limit timer and its interrupt. */ | ||
680 | fhci->timer = gtm_get_timer16(); | ||
681 | if (IS_ERR(fhci->timer)) { | ||
682 | ret = PTR_ERR(fhci->timer); | ||
683 | dev_err(dev, "failed to request qe timer: %i", ret); | ||
684 | goto err_get_timer; | ||
685 | } | ||
686 | |||
687 | ret = request_irq(fhci->timer->irq, fhci_frame_limit_timer_irq, | ||
688 | IRQF_DISABLED, "qe timer (usb)", hcd); | ||
689 | if (ret) { | ||
690 | dev_err(dev, "failed to request timer irq"); | ||
691 | goto err_timer_irq; | ||
692 | } | ||
693 | |||
694 | /* USB Host interrupt. */ | ||
695 | usb_irq = irq_of_parse_and_map(node, 0); | ||
696 | if (usb_irq == NO_IRQ) { | ||
697 | dev_err(dev, "could not get usb irq\n"); | ||
698 | ret = -EINVAL; | ||
699 | goto err_usb_irq; | ||
700 | } | ||
701 | |||
702 | /* Clocks. */ | ||
703 | sprop = of_get_property(node, "fsl,fullspeed-clock", NULL); | ||
704 | if (sprop) { | ||
705 | fhci->fullspeed_clk = qe_clock_source(sprop); | ||
706 | if (fhci->fullspeed_clk == QE_CLK_DUMMY) { | ||
707 | dev_err(dev, "wrong fullspeed-clock\n"); | ||
708 | ret = -EINVAL; | ||
709 | goto err_clocks; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | sprop = of_get_property(node, "fsl,lowspeed-clock", NULL); | ||
714 | if (sprop) { | ||
715 | fhci->lowspeed_clk = qe_clock_source(sprop); | ||
716 | if (fhci->lowspeed_clk == QE_CLK_DUMMY) { | ||
717 | dev_err(dev, "wrong lowspeed-clock\n"); | ||
718 | ret = -EINVAL; | ||
719 | goto err_clocks; | ||
720 | } | ||
721 | } | ||
722 | |||
723 | if (fhci->fullspeed_clk == QE_CLK_NONE && | ||
724 | fhci->lowspeed_clk == QE_CLK_NONE) { | ||
725 | dev_err(dev, "no clocks specified\n"); | ||
726 | ret = -EINVAL; | ||
727 | goto err_clocks; | ||
728 | } | ||
729 | |||
730 | dev_info(dev, "at 0x%p, irq %d\n", hcd->regs, usb_irq); | ||
731 | |||
732 | fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); | ||
733 | |||
734 | /* Start with full-speed, if possible. */ | ||
735 | if (fhci->fullspeed_clk != QE_CLK_NONE) { | ||
736 | fhci_config_transceiver(fhci, FHCI_PORT_FULL); | ||
737 | qe_usb_clock_set(fhci->fullspeed_clk, USB_CLOCK); | ||
738 | } else { | ||
739 | fhci_config_transceiver(fhci, FHCI_PORT_LOW); | ||
740 | qe_usb_clock_set(fhci->lowspeed_clk, USB_CLOCK >> 3); | ||
741 | } | ||
742 | |||
743 | /* Clear and disable any pending interrupts. */ | ||
744 | out_be16(&fhci->regs->usb_event, 0xffff); | ||
745 | out_be16(&fhci->regs->usb_mask, 0); | ||
746 | |||
747 | ret = usb_add_hcd(hcd, usb_irq, IRQF_DISABLED); | ||
748 | if (ret < 0) | ||
749 | goto err_add_hcd; | ||
750 | |||
751 | fhci_dfs_create(fhci); | ||
752 | |||
753 | return 0; | ||
754 | |||
755 | err_add_hcd: | ||
756 | err_clocks: | ||
757 | irq_dispose_mapping(usb_irq); | ||
758 | err_usb_irq: | ||
759 | free_irq(fhci->timer->irq, hcd); | ||
760 | err_timer_irq: | ||
761 | gtm_put_timer16(fhci->timer); | ||
762 | err_get_timer: | ||
763 | err_pins: | ||
764 | while (--j >= 0) | ||
765 | qe_pin_free(fhci->pins[j]); | ||
766 | err_gpios: | ||
767 | while (--i >= 0) { | ||
768 | if (gpio_is_valid(fhci->gpios[i])) | ||
769 | gpio_free(fhci->gpios[i]); | ||
770 | } | ||
771 | cpm_muram_free(pram_addr); | ||
772 | err_pram: | ||
773 | iounmap(hcd->regs); | ||
774 | err_regs: | ||
775 | usb_put_hcd(hcd); | ||
776 | return ret; | ||
777 | } | ||
778 | |||
779 | static int __devexit fhci_remove(struct device *dev) | ||
780 | { | ||
781 | struct usb_hcd *hcd = dev_get_drvdata(dev); | ||
782 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
783 | int i; | ||
784 | int j; | ||
785 | |||
786 | usb_remove_hcd(hcd); | ||
787 | free_irq(fhci->timer->irq, hcd); | ||
788 | gtm_put_timer16(fhci->timer); | ||
789 | cpm_muram_free(cpm_muram_offset(fhci->pram)); | ||
790 | for (i = 0; i < NUM_GPIOS; i++) { | ||
791 | if (!gpio_is_valid(fhci->gpios[i])) | ||
792 | continue; | ||
793 | gpio_free(fhci->gpios[i]); | ||
794 | } | ||
795 | for (j = 0; j < NUM_PINS; j++) | ||
796 | qe_pin_free(fhci->pins[j]); | ||
797 | fhci_dfs_destroy(fhci); | ||
798 | usb_put_hcd(hcd); | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static int __devexit of_fhci_remove(struct of_device *ofdev) | ||
803 | { | ||
804 | return fhci_remove(&ofdev->dev); | ||
805 | } | ||
806 | |||
807 | static struct of_device_id of_fhci_match[] = { | ||
808 | { .compatible = "fsl,mpc8323-qe-usb", }, | ||
809 | {}, | ||
810 | }; | ||
811 | MODULE_DEVICE_TABLE(of, of_fhci_match); | ||
812 | |||
813 | static struct of_platform_driver of_fhci_driver = { | ||
814 | .name = "fsl,usb-fhci", | ||
815 | .match_table = of_fhci_match, | ||
816 | .probe = of_fhci_probe, | ||
817 | .remove = __devexit_p(of_fhci_remove), | ||
818 | }; | ||
819 | |||
820 | static int __init fhci_module_init(void) | ||
821 | { | ||
822 | return of_register_platform_driver(&of_fhci_driver); | ||
823 | } | ||
824 | module_init(fhci_module_init); | ||
825 | |||
826 | static void __exit fhci_module_exit(void) | ||
827 | { | ||
828 | of_unregister_platform_driver(&of_fhci_driver); | ||
829 | } | ||
830 | module_exit(fhci_module_exit); | ||
831 | |||
832 | MODULE_DESCRIPTION("USB Freescale Host Controller Interface Driver"); | ||
833 | MODULE_AUTHOR("Shlomi Gridish <gridish@freescale.com>, " | ||
834 | "Jerry Huang <Chang-Ming.Huang@freescale.com>, " | ||
835 | "Anton Vorontsov <avorontsov@ru.mvista.com>"); | ||
836 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c new file mode 100644 index 000000000000..0cfaedc3e124 --- /dev/null +++ b/drivers/usb/host/fhci-hub.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/usb.h> | ||
25 | #include <linux/gpio.h> | ||
26 | #include <asm/qe.h> | ||
27 | #include "../core/hcd.h" | ||
28 | #include "fhci.h" | ||
29 | |||
30 | /* virtual root hub specific descriptor */ | ||
31 | static u8 root_hub_des[] = { | ||
32 | 0x09, /* blength */ | ||
33 | 0x29, /* bDescriptorType;hub-descriptor */ | ||
34 | 0x01, /* bNbrPorts */ | ||
35 | 0x00, /* wHubCharacteristics */ | ||
36 | 0x00, | ||
37 | 0x01, /* bPwrOn2pwrGood;2ms */ | ||
38 | 0x00, /* bHubContrCurrent;0mA */ | ||
39 | 0x00, /* DeviceRemoveable */ | ||
40 | 0xff, /* PortPwrCtrlMask */ | ||
41 | }; | ||
42 | |||
43 | static void fhci_gpio_set_value(struct fhci_hcd *fhci, int gpio_nr, bool on) | ||
44 | { | ||
45 | int gpio = fhci->gpios[gpio_nr]; | ||
46 | bool alow = fhci->alow_gpios[gpio_nr]; | ||
47 | |||
48 | if (!gpio_is_valid(gpio)) | ||
49 | return; | ||
50 | |||
51 | gpio_set_value(gpio, on ^ alow); | ||
52 | mdelay(5); | ||
53 | } | ||
54 | |||
55 | void fhci_config_transceiver(struct fhci_hcd *fhci, | ||
56 | enum fhci_port_status status) | ||
57 | { | ||
58 | fhci_dbg(fhci, "-> %s: %d\n", __func__, status); | ||
59 | |||
60 | switch (status) { | ||
61 | case FHCI_PORT_POWER_OFF: | ||
62 | fhci_gpio_set_value(fhci, GPIO_POWER, false); | ||
63 | break; | ||
64 | case FHCI_PORT_DISABLED: | ||
65 | case FHCI_PORT_WAITING: | ||
66 | fhci_gpio_set_value(fhci, GPIO_POWER, true); | ||
67 | break; | ||
68 | case FHCI_PORT_LOW: | ||
69 | fhci_gpio_set_value(fhci, GPIO_SPEED, false); | ||
70 | break; | ||
71 | case FHCI_PORT_FULL: | ||
72 | fhci_gpio_set_value(fhci, GPIO_SPEED, true); | ||
73 | break; | ||
74 | default: | ||
75 | WARN_ON(1); | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | fhci_dbg(fhci, "<- %s: %d\n", __func__, status); | ||
80 | } | ||
81 | |||
82 | /* disable the USB port by clearing the EN bit in the USBMOD register */ | ||
83 | void fhci_port_disable(struct fhci_hcd *fhci) | ||
84 | { | ||
85 | struct fhci_usb *usb = (struct fhci_usb *)fhci->usb_lld; | ||
86 | enum fhci_port_status port_status; | ||
87 | |||
88 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
89 | |||
90 | fhci_stop_sof_timer(fhci); | ||
91 | |||
92 | fhci_flush_all_transmissions(usb); | ||
93 | |||
94 | fhci_usb_disable_interrupt((struct fhci_usb *)fhci->usb_lld); | ||
95 | port_status = usb->port_status; | ||
96 | usb->port_status = FHCI_PORT_DISABLED; | ||
97 | |||
98 | /* Enable IDLE since we want to know if something comes along */ | ||
99 | usb->saved_msk |= USB_E_IDLE_MASK; | ||
100 | out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); | ||
101 | |||
102 | /* check if during the disconnection process attached new device */ | ||
103 | if (port_status == FHCI_PORT_WAITING) | ||
104 | fhci_device_connected_interrupt(fhci); | ||
105 | usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_ENABLE; | ||
106 | usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE; | ||
107 | fhci_usb_enable_interrupt((struct fhci_usb *)fhci->usb_lld); | ||
108 | |||
109 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
110 | } | ||
111 | |||
112 | /* enable the USB port by setting the EN bit in the USBMOD register */ | ||
113 | void fhci_port_enable(void *lld) | ||
114 | { | ||
115 | struct fhci_usb *usb = (struct fhci_usb *)lld; | ||
116 | struct fhci_hcd *fhci = usb->fhci; | ||
117 | |||
118 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
119 | |||
120 | fhci_config_transceiver(fhci, usb->port_status); | ||
121 | |||
122 | if ((usb->port_status != FHCI_PORT_FULL) && | ||
123 | (usb->port_status != FHCI_PORT_LOW)) | ||
124 | fhci_start_sof_timer(fhci); | ||
125 | |||
126 | usb->vroot_hub->port.wPortStatus |= USB_PORT_STAT_ENABLE; | ||
127 | usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE; | ||
128 | |||
129 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
130 | } | ||
131 | |||
132 | void fhci_io_port_generate_reset(struct fhci_hcd *fhci) | ||
133 | { | ||
134 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
135 | |||
136 | gpio_direction_output(fhci->gpios[GPIO_USBOE], 0); | ||
137 | gpio_direction_output(fhci->gpios[GPIO_USBTP], 0); | ||
138 | gpio_direction_output(fhci->gpios[GPIO_USBTN], 0); | ||
139 | |||
140 | mdelay(5); | ||
141 | |||
142 | qe_pin_set_dedicated(fhci->pins[PIN_USBOE]); | ||
143 | qe_pin_set_dedicated(fhci->pins[PIN_USBTP]); | ||
144 | qe_pin_set_dedicated(fhci->pins[PIN_USBTN]); | ||
145 | |||
146 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
147 | } | ||
148 | |||
149 | /* generate the RESET condition on the bus */ | ||
150 | void fhci_port_reset(void *lld) | ||
151 | { | ||
152 | struct fhci_usb *usb = (struct fhci_usb *)lld; | ||
153 | struct fhci_hcd *fhci = usb->fhci; | ||
154 | u8 mode; | ||
155 | u16 mask; | ||
156 | |||
157 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
158 | |||
159 | fhci_stop_sof_timer(fhci); | ||
160 | /* disable the USB controller */ | ||
161 | mode = in_8(&fhci->regs->usb_mod); | ||
162 | out_8(&fhci->regs->usb_mod, mode & (~USB_MODE_EN)); | ||
163 | |||
164 | /* disable idle interrupts */ | ||
165 | mask = in_be16(&fhci->regs->usb_mask); | ||
166 | out_be16(&fhci->regs->usb_mask, mask & (~USB_E_IDLE_MASK)); | ||
167 | |||
168 | fhci_io_port_generate_reset(fhci); | ||
169 | |||
170 | /* enable interrupt on this endpoint */ | ||
171 | out_be16(&fhci->regs->usb_mask, mask); | ||
172 | |||
173 | /* enable the USB controller */ | ||
174 | mode = in_8(&fhci->regs->usb_mod); | ||
175 | out_8(&fhci->regs->usb_mod, mode | USB_MODE_EN); | ||
176 | fhci_start_sof_timer(fhci); | ||
177 | |||
178 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
179 | } | ||
180 | |||
181 | int fhci_hub_status_data(struct usb_hcd *hcd, char *buf) | ||
182 | { | ||
183 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
184 | int ret = 0; | ||
185 | unsigned long flags; | ||
186 | |||
187 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
188 | |||
189 | spin_lock_irqsave(&fhci->lock, flags); | ||
190 | |||
191 | if (fhci->vroot_hub->port.wPortChange & (USB_PORT_STAT_C_CONNECTION | | ||
192 | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_SUSPEND | | ||
193 | USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_OVERCURRENT)) { | ||
194 | *buf = 1 << 1; | ||
195 | ret = 1; | ||
196 | fhci_dbg(fhci, "-- %s\n", __func__); | ||
197 | } | ||
198 | |||
199 | spin_unlock_irqrestore(&fhci->lock, flags); | ||
200 | |||
201 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
202 | |||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | ||
207 | u16 wIndex, char *buf, u16 wLength) | ||
208 | { | ||
209 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
210 | int retval = 0; | ||
211 | int len = 0; | ||
212 | struct usb_hub_status *hub_status; | ||
213 | struct usb_port_status *port_status; | ||
214 | unsigned long flags; | ||
215 | |||
216 | spin_lock_irqsave(&fhci->lock, flags); | ||
217 | |||
218 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
219 | |||
220 | switch (typeReq) { | ||
221 | case ClearHubFeature: | ||
222 | switch (wValue) { | ||
223 | case C_HUB_LOCAL_POWER: | ||
224 | case C_HUB_OVER_CURRENT: | ||
225 | break; | ||
226 | default: | ||
227 | goto error; | ||
228 | } | ||
229 | break; | ||
230 | case ClearPortFeature: | ||
231 | fhci->vroot_hub->feature &= (1 << wValue); | ||
232 | |||
233 | switch (wValue) { | ||
234 | case USB_PORT_FEAT_ENABLE: | ||
235 | fhci->vroot_hub->port.wPortStatus &= | ||
236 | ~USB_PORT_STAT_ENABLE; | ||
237 | fhci_port_disable(fhci); | ||
238 | break; | ||
239 | case USB_PORT_FEAT_C_ENABLE: | ||
240 | fhci->vroot_hub->port.wPortChange &= | ||
241 | ~USB_PORT_STAT_C_ENABLE; | ||
242 | break; | ||
243 | case USB_PORT_FEAT_SUSPEND: | ||
244 | fhci->vroot_hub->port.wPortStatus &= | ||
245 | ~USB_PORT_STAT_SUSPEND; | ||
246 | fhci_stop_sof_timer(fhci); | ||
247 | break; | ||
248 | case USB_PORT_FEAT_C_SUSPEND: | ||
249 | fhci->vroot_hub->port.wPortChange &= | ||
250 | ~USB_PORT_STAT_C_SUSPEND; | ||
251 | break; | ||
252 | case USB_PORT_FEAT_POWER: | ||
253 | fhci->vroot_hub->port.wPortStatus &= | ||
254 | ~USB_PORT_STAT_POWER; | ||
255 | fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); | ||
256 | break; | ||
257 | case USB_PORT_FEAT_C_CONNECTION: | ||
258 | fhci->vroot_hub->port.wPortChange &= | ||
259 | ~USB_PORT_STAT_C_CONNECTION; | ||
260 | break; | ||
261 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
262 | fhci->vroot_hub->port.wPortChange &= | ||
263 | ~USB_PORT_STAT_C_OVERCURRENT; | ||
264 | break; | ||
265 | case USB_PORT_FEAT_C_RESET: | ||
266 | fhci->vroot_hub->port.wPortChange &= | ||
267 | ~USB_PORT_STAT_C_RESET; | ||
268 | break; | ||
269 | default: | ||
270 | goto error; | ||
271 | } | ||
272 | break; | ||
273 | case GetHubDescriptor: | ||
274 | memcpy(buf, root_hub_des, sizeof(root_hub_des)); | ||
275 | buf[3] = 0x11; /* per-port power, no ovrcrnt */ | ||
276 | len = (buf[0] < wLength) ? buf[0] : wLength; | ||
277 | break; | ||
278 | case GetHubStatus: | ||
279 | hub_status = (struct usb_hub_status *)buf; | ||
280 | hub_status->wHubStatus = | ||
281 | cpu_to_le16(fhci->vroot_hub->hub.wHubStatus); | ||
282 | hub_status->wHubChange = | ||
283 | cpu_to_le16(fhci->vroot_hub->hub.wHubChange); | ||
284 | len = 4; | ||
285 | break; | ||
286 | case GetPortStatus: | ||
287 | port_status = (struct usb_port_status *)buf; | ||
288 | port_status->wPortStatus = | ||
289 | cpu_to_le16(fhci->vroot_hub->port.wPortStatus); | ||
290 | port_status->wPortChange = | ||
291 | cpu_to_le16(fhci->vroot_hub->port.wPortChange); | ||
292 | len = 4; | ||
293 | break; | ||
294 | case SetHubFeature: | ||
295 | switch (wValue) { | ||
296 | case C_HUB_OVER_CURRENT: | ||
297 | case C_HUB_LOCAL_POWER: | ||
298 | break; | ||
299 | default: | ||
300 | goto error; | ||
301 | } | ||
302 | break; | ||
303 | case SetPortFeature: | ||
304 | fhci->vroot_hub->feature |= (1 << wValue); | ||
305 | |||
306 | switch (wValue) { | ||
307 | case USB_PORT_FEAT_ENABLE: | ||
308 | fhci->vroot_hub->port.wPortStatus |= | ||
309 | USB_PORT_STAT_ENABLE; | ||
310 | fhci_port_enable(fhci->usb_lld); | ||
311 | break; | ||
312 | case USB_PORT_FEAT_SUSPEND: | ||
313 | fhci->vroot_hub->port.wPortStatus |= | ||
314 | USB_PORT_STAT_SUSPEND; | ||
315 | fhci_stop_sof_timer(fhci); | ||
316 | break; | ||
317 | case USB_PORT_FEAT_RESET: | ||
318 | fhci->vroot_hub->port.wPortStatus |= | ||
319 | USB_PORT_STAT_RESET; | ||
320 | fhci_port_reset(fhci->usb_lld); | ||
321 | fhci->vroot_hub->port.wPortStatus |= | ||
322 | USB_PORT_STAT_ENABLE; | ||
323 | fhci->vroot_hub->port.wPortStatus &= | ||
324 | ~USB_PORT_STAT_RESET; | ||
325 | break; | ||
326 | case USB_PORT_FEAT_POWER: | ||
327 | fhci->vroot_hub->port.wPortStatus |= | ||
328 | USB_PORT_STAT_POWER; | ||
329 | fhci_config_transceiver(fhci, FHCI_PORT_WAITING); | ||
330 | break; | ||
331 | default: | ||
332 | goto error; | ||
333 | } | ||
334 | break; | ||
335 | default: | ||
336 | error: | ||
337 | retval = -EPIPE; | ||
338 | } | ||
339 | |||
340 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
341 | |||
342 | spin_unlock_irqrestore(&fhci->lock, flags); | ||
343 | |||
344 | return retval; | ||
345 | } | ||
diff --git a/drivers/usb/host/fhci-mem.c b/drivers/usb/host/fhci-mem.c new file mode 100644 index 000000000000..2c0736c99712 --- /dev/null +++ b/drivers/usb/host/fhci-mem.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/usb.h> | ||
23 | #include "../core/hcd.h" | ||
24 | #include "fhci.h" | ||
25 | |||
26 | static void init_td(struct td *td) | ||
27 | { | ||
28 | memset(td, 0, sizeof(*td)); | ||
29 | INIT_LIST_HEAD(&td->node); | ||
30 | INIT_LIST_HEAD(&td->frame_lh); | ||
31 | } | ||
32 | |||
33 | static void init_ed(struct ed *ed) | ||
34 | { | ||
35 | memset(ed, 0, sizeof(*ed)); | ||
36 | INIT_LIST_HEAD(&ed->td_list); | ||
37 | INIT_LIST_HEAD(&ed->node); | ||
38 | } | ||
39 | |||
40 | static struct td *get_empty_td(struct fhci_hcd *fhci) | ||
41 | { | ||
42 | struct td *td; | ||
43 | |||
44 | if (!list_empty(&fhci->empty_tds)) { | ||
45 | td = list_entry(fhci->empty_tds.next, struct td, node); | ||
46 | list_del(fhci->empty_tds.next); | ||
47 | } else { | ||
48 | td = kmalloc(sizeof(*td), GFP_ATOMIC); | ||
49 | if (!td) | ||
50 | fhci_err(fhci, "No memory to allocate to TD\n"); | ||
51 | else | ||
52 | init_td(td); | ||
53 | } | ||
54 | |||
55 | return td; | ||
56 | } | ||
57 | |||
58 | void fhci_recycle_empty_td(struct fhci_hcd *fhci, struct td *td) | ||
59 | { | ||
60 | init_td(td); | ||
61 | list_add(&td->node, &fhci->empty_tds); | ||
62 | } | ||
63 | |||
64 | struct ed *fhci_get_empty_ed(struct fhci_hcd *fhci) | ||
65 | { | ||
66 | struct ed *ed; | ||
67 | |||
68 | if (!list_empty(&fhci->empty_eds)) { | ||
69 | ed = list_entry(fhci->empty_eds.next, struct ed, node); | ||
70 | list_del(fhci->empty_eds.next); | ||
71 | } else { | ||
72 | ed = kmalloc(sizeof(*ed), GFP_ATOMIC); | ||
73 | if (!ed) | ||
74 | fhci_err(fhci, "No memory to allocate to ED\n"); | ||
75 | else | ||
76 | init_ed(ed); | ||
77 | } | ||
78 | |||
79 | return ed; | ||
80 | } | ||
81 | |||
82 | void fhci_recycle_empty_ed(struct fhci_hcd *fhci, struct ed *ed) | ||
83 | { | ||
84 | init_ed(ed); | ||
85 | list_add(&ed->node, &fhci->empty_eds); | ||
86 | } | ||
87 | |||
88 | struct td *fhci_td_fill(struct fhci_hcd *fhci, struct urb *urb, | ||
89 | struct urb_priv *urb_priv, struct ed *ed, u16 index, | ||
90 | enum fhci_ta_type type, int toggle, u8 *data, u32 len, | ||
91 | u16 interval, u16 start_frame, bool ioc) | ||
92 | { | ||
93 | struct td *td = get_empty_td(fhci); | ||
94 | |||
95 | if (!td) | ||
96 | return NULL; | ||
97 | |||
98 | td->urb = urb; | ||
99 | td->ed = ed; | ||
100 | td->type = type; | ||
101 | td->toggle = toggle; | ||
102 | td->data = data; | ||
103 | td->len = len; | ||
104 | td->iso_index = index; | ||
105 | td->interval = interval; | ||
106 | td->start_frame = start_frame; | ||
107 | td->ioc = ioc; | ||
108 | td->status = USB_TD_OK; | ||
109 | |||
110 | urb_priv->tds[index] = td; | ||
111 | |||
112 | return td; | ||
113 | } | ||
diff --git a/drivers/usb/host/fhci-q.c b/drivers/usb/host/fhci-q.c new file mode 100644 index 000000000000..b0a1446ba292 --- /dev/null +++ b/drivers/usb/host/fhci-q.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/list.h> | ||
23 | #include <linux/usb.h> | ||
24 | #include "../core/hcd.h" | ||
25 | #include "fhci.h" | ||
26 | |||
27 | /* maps the hardware error code to the USB error code */ | ||
28 | static int status_to_error(u32 status) | ||
29 | { | ||
30 | if (status == USB_TD_OK) | ||
31 | return 0; | ||
32 | else if (status & USB_TD_RX_ER_CRC) | ||
33 | return -EILSEQ; | ||
34 | else if (status & USB_TD_RX_ER_NONOCT) | ||
35 | return -EPROTO; | ||
36 | else if (status & USB_TD_RX_ER_OVERUN) | ||
37 | return -ECOMM; | ||
38 | else if (status & USB_TD_RX_ER_BITSTUFF) | ||
39 | return -EPROTO; | ||
40 | else if (status & USB_TD_RX_ER_PID) | ||
41 | return -EILSEQ; | ||
42 | else if (status & (USB_TD_TX_ER_NAK | USB_TD_TX_ER_TIMEOUT)) | ||
43 | return -ETIMEDOUT; | ||
44 | else if (status & USB_TD_TX_ER_STALL) | ||
45 | return -EPIPE; | ||
46 | else if (status & USB_TD_TX_ER_UNDERUN) | ||
47 | return -ENOSR; | ||
48 | else if (status & USB_TD_RX_DATA_UNDERUN) | ||
49 | return -EREMOTEIO; | ||
50 | else if (status & USB_TD_RX_DATA_OVERUN) | ||
51 | return -EOVERFLOW; | ||
52 | else | ||
53 | return -EINVAL; | ||
54 | } | ||
55 | |||
56 | void fhci_add_td_to_frame(struct fhci_time_frame *frame, struct td *td) | ||
57 | { | ||
58 | list_add_tail(&td->frame_lh, &frame->tds_list); | ||
59 | } | ||
60 | |||
61 | void fhci_add_tds_to_ed(struct ed *ed, struct td **td_list, int number) | ||
62 | { | ||
63 | int i; | ||
64 | |||
65 | for (i = 0; i < number; i++) { | ||
66 | struct td *td = td_list[i]; | ||
67 | list_add_tail(&td->node, &ed->td_list); | ||
68 | } | ||
69 | if (ed->td_head == NULL) | ||
70 | ed->td_head = td_list[0]; | ||
71 | } | ||
72 | |||
73 | static struct td *peek_td_from_ed(struct ed *ed) | ||
74 | { | ||
75 | struct td *td; | ||
76 | |||
77 | if (!list_empty(&ed->td_list)) | ||
78 | td = list_entry(ed->td_list.next, struct td, node); | ||
79 | else | ||
80 | td = NULL; | ||
81 | |||
82 | return td; | ||
83 | } | ||
84 | |||
85 | struct td *fhci_remove_td_from_frame(struct fhci_time_frame *frame) | ||
86 | { | ||
87 | struct td *td; | ||
88 | |||
89 | if (!list_empty(&frame->tds_list)) { | ||
90 | td = list_entry(frame->tds_list.next, struct td, frame_lh); | ||
91 | list_del_init(frame->tds_list.next); | ||
92 | } else | ||
93 | td = NULL; | ||
94 | |||
95 | return td; | ||
96 | } | ||
97 | |||
98 | struct td *fhci_peek_td_from_frame(struct fhci_time_frame *frame) | ||
99 | { | ||
100 | struct td *td; | ||
101 | |||
102 | if (!list_empty(&frame->tds_list)) | ||
103 | td = list_entry(frame->tds_list.next, struct td, frame_lh); | ||
104 | else | ||
105 | td = NULL; | ||
106 | |||
107 | return td; | ||
108 | } | ||
109 | |||
110 | struct td *fhci_remove_td_from_ed(struct ed *ed) | ||
111 | { | ||
112 | struct td *td; | ||
113 | |||
114 | if (!list_empty(&ed->td_list)) { | ||
115 | td = list_entry(ed->td_list.next, struct td, node); | ||
116 | list_del_init(ed->td_list.next); | ||
117 | |||
118 | /* if this TD was the ED's head, find next TD */ | ||
119 | if (!list_empty(&ed->td_list)) | ||
120 | ed->td_head = list_entry(ed->td_list.next, struct td, | ||
121 | node); | ||
122 | else | ||
123 | ed->td_head = NULL; | ||
124 | } else | ||
125 | td = NULL; | ||
126 | |||
127 | return td; | ||
128 | } | ||
129 | |||
130 | struct td *fhci_remove_td_from_done_list(struct fhci_controller_list *p_list) | ||
131 | { | ||
132 | struct td *td; | ||
133 | |||
134 | if (!list_empty(&p_list->done_list)) { | ||
135 | td = list_entry(p_list->done_list.next, struct td, node); | ||
136 | list_del_init(p_list->done_list.next); | ||
137 | } else | ||
138 | td = NULL; | ||
139 | |||
140 | return td; | ||
141 | } | ||
142 | |||
143 | void fhci_move_td_from_ed_to_done_list(struct fhci_usb *usb, struct ed *ed) | ||
144 | { | ||
145 | struct td *td; | ||
146 | |||
147 | td = ed->td_head; | ||
148 | list_del_init(&td->node); | ||
149 | |||
150 | /* If this TD was the ED's head,find next TD */ | ||
151 | if (!list_empty(&ed->td_list)) | ||
152 | ed->td_head = list_entry(ed->td_list.next, struct td, node); | ||
153 | else { | ||
154 | ed->td_head = NULL; | ||
155 | ed->state = FHCI_ED_SKIP; | ||
156 | } | ||
157 | ed->toggle_carry = td->toggle; | ||
158 | list_add_tail(&td->node, &usb->hc_list->done_list); | ||
159 | if (td->ioc) | ||
160 | usb->transfer_confirm(usb->fhci); | ||
161 | } | ||
162 | |||
163 | /* free done FHCI URB resource such as ED and TD */ | ||
164 | static void free_urb_priv(struct fhci_hcd *fhci, struct urb *urb) | ||
165 | { | ||
166 | int i; | ||
167 | struct urb_priv *urb_priv = urb->hcpriv; | ||
168 | struct ed *ed = urb_priv->ed; | ||
169 | |||
170 | for (i = 0; i < urb_priv->num_of_tds; i++) { | ||
171 | list_del_init(&urb_priv->tds[i]->node); | ||
172 | fhci_recycle_empty_td(fhci, urb_priv->tds[i]); | ||
173 | } | ||
174 | |||
175 | /* if this TD was the ED's head,find the next TD */ | ||
176 | if (!list_empty(&ed->td_list)) | ||
177 | ed->td_head = list_entry(ed->td_list.next, struct td, node); | ||
178 | else | ||
179 | ed->td_head = NULL; | ||
180 | |||
181 | kfree(urb_priv->tds); | ||
182 | kfree(urb_priv); | ||
183 | urb->hcpriv = NULL; | ||
184 | |||
185 | /* if this TD was the ED's head,find next TD */ | ||
186 | if (ed->td_head == NULL) | ||
187 | list_del_init(&ed->node); | ||
188 | fhci->active_urbs--; | ||
189 | } | ||
190 | |||
191 | /* this routine called to complete and free done URB */ | ||
192 | void fhci_urb_complete_free(struct fhci_hcd *fhci, struct urb *urb) | ||
193 | { | ||
194 | free_urb_priv(fhci, urb); | ||
195 | |||
196 | if (urb->status == -EINPROGRESS) { | ||
197 | if (urb->actual_length != urb->transfer_buffer_length && | ||
198 | urb->transfer_flags & URB_SHORT_NOT_OK) | ||
199 | urb->status = -EREMOTEIO; | ||
200 | else | ||
201 | urb->status = 0; | ||
202 | } | ||
203 | |||
204 | usb_hcd_unlink_urb_from_ep(fhci_to_hcd(fhci), urb); | ||
205 | |||
206 | spin_unlock(&fhci->lock); | ||
207 | |||
208 | usb_hcd_giveback_urb(fhci_to_hcd(fhci), urb, urb->status); | ||
209 | |||
210 | spin_lock(&fhci->lock); | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * caculate transfer length/stats and update the urb | ||
215 | * Precondition: irqsafe(only for urb-?status locking) | ||
216 | */ | ||
217 | void fhci_done_td(struct urb *urb, struct td *td) | ||
218 | { | ||
219 | struct ed *ed = td->ed; | ||
220 | u32 cc = td->status; | ||
221 | |||
222 | /* ISO...drivers see per-TD length/status */ | ||
223 | if (ed->mode == FHCI_TF_ISO) { | ||
224 | u32 len; | ||
225 | if (!(urb->transfer_flags & URB_SHORT_NOT_OK && | ||
226 | cc == USB_TD_RX_DATA_UNDERUN)) | ||
227 | cc = USB_TD_OK; | ||
228 | |||
229 | if (usb_pipeout(urb->pipe)) | ||
230 | len = urb->iso_frame_desc[td->iso_index].length; | ||
231 | else | ||
232 | len = td->actual_len; | ||
233 | |||
234 | urb->actual_length += len; | ||
235 | urb->iso_frame_desc[td->iso_index].actual_length = len; | ||
236 | urb->iso_frame_desc[td->iso_index].status = | ||
237 | status_to_error(cc); | ||
238 | } | ||
239 | |||
240 | /* BULK,INT,CONTROL... drivers see aggregate length/status, | ||
241 | * except that "setup" bytes aren't counted and "short" transfers | ||
242 | * might not be reported as errors. | ||
243 | */ | ||
244 | else { | ||
245 | if (td->error_cnt >= 3) | ||
246 | urb->error_count = 3; | ||
247 | |||
248 | /* control endpoint only have soft stalls */ | ||
249 | |||
250 | /* update packet status if needed(short may be ok) */ | ||
251 | if (!(urb->transfer_flags & URB_SHORT_NOT_OK) && | ||
252 | cc == USB_TD_RX_DATA_UNDERUN) { | ||
253 | ed->state = FHCI_ED_OPER; | ||
254 | cc = USB_TD_OK; | ||
255 | } | ||
256 | if (cc != USB_TD_OK) { | ||
257 | if (urb->status == -EINPROGRESS) | ||
258 | urb->status = status_to_error(cc); | ||
259 | } | ||
260 | |||
261 | /* count all non-empty packets except control SETUP packet */ | ||
262 | if (td->type != FHCI_TA_SETUP || td->iso_index != 0) | ||
263 | urb->actual_length += td->actual_len; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /* there are some pedning request to unlink */ | ||
268 | void fhci_del_ed_list(struct fhci_hcd *fhci, struct ed *ed) | ||
269 | { | ||
270 | struct td *td = peek_td_from_ed(ed); | ||
271 | struct urb *urb = td->urb; | ||
272 | struct urb_priv *urb_priv = urb->hcpriv; | ||
273 | |||
274 | if (urb_priv->state == URB_DEL) { | ||
275 | td = fhci_remove_td_from_ed(ed); | ||
276 | /* HC may have partly processed this TD */ | ||
277 | if (td->status != USB_TD_INPROGRESS) | ||
278 | fhci_done_td(urb, td); | ||
279 | |||
280 | /* URB is done;clean up */ | ||
281 | if (++(urb_priv->tds_cnt) == urb_priv->num_of_tds) | ||
282 | fhci_urb_complete_free(fhci, urb); | ||
283 | } | ||
284 | } | ||
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c new file mode 100644 index 000000000000..bb63b68ddb77 --- /dev/null +++ b/drivers/usb/host/fhci-sched.c | |||
@@ -0,0 +1,888 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/usb.h> | ||
27 | #include <asm/qe.h> | ||
28 | #include <asm/fsl_gtm.h> | ||
29 | #include "../core/hcd.h" | ||
30 | #include "fhci.h" | ||
31 | |||
32 | static void recycle_frame(struct fhci_usb *usb, struct packet *pkt) | ||
33 | { | ||
34 | pkt->data = NULL; | ||
35 | pkt->len = 0; | ||
36 | pkt->status = USB_TD_OK; | ||
37 | pkt->info = 0; | ||
38 | pkt->priv_data = NULL; | ||
39 | |||
40 | cq_put(usb->ep0->empty_frame_Q, pkt); | ||
41 | } | ||
42 | |||
43 | /* confirm submitted packet */ | ||
44 | void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt) | ||
45 | { | ||
46 | struct td *td; | ||
47 | struct packet *td_pkt; | ||
48 | struct ed *ed; | ||
49 | u32 trans_len; | ||
50 | bool td_done = false; | ||
51 | |||
52 | td = fhci_remove_td_from_frame(usb->actual_frame); | ||
53 | td_pkt = td->pkt; | ||
54 | trans_len = pkt->len; | ||
55 | td->status = pkt->status; | ||
56 | if (td->type == FHCI_TA_IN && td_pkt->info & PKT_DUMMY_PACKET) { | ||
57 | if ((td->data + td->actual_len) && trans_len) | ||
58 | memcpy(td->data + td->actual_len, pkt->data, | ||
59 | trans_len); | ||
60 | cq_put(usb->ep0->dummy_packets_Q, pkt->data); | ||
61 | } | ||
62 | |||
63 | recycle_frame(usb, pkt); | ||
64 | |||
65 | ed = td->ed; | ||
66 | if (ed->mode == FHCI_TF_ISO) { | ||
67 | if (ed->td_list.next->next != &ed->td_list) { | ||
68 | struct td *td_next = | ||
69 | list_entry(ed->td_list.next->next, struct td, | ||
70 | node); | ||
71 | |||
72 | td_next->start_frame = usb->actual_frame->frame_num; | ||
73 | } | ||
74 | td->actual_len = trans_len; | ||
75 | td_done = true; | ||
76 | } else if ((td->status & USB_TD_ERROR) && | ||
77 | !(td->status & USB_TD_TX_ER_NAK)) { | ||
78 | /* | ||
79 | * There was an error on the transaction (but not NAK). | ||
80 | * If it is fatal error (data underrun, stall, bad pid or 3 | ||
81 | * errors exceeded), mark this TD as done. | ||
82 | */ | ||
83 | if ((td->status & USB_TD_RX_DATA_UNDERUN) || | ||
84 | (td->status & USB_TD_TX_ER_STALL) || | ||
85 | (td->status & USB_TD_RX_ER_PID) || | ||
86 | (++td->error_cnt >= 3)) { | ||
87 | ed->state = FHCI_ED_HALTED; | ||
88 | td_done = true; | ||
89 | |||
90 | if (td->status & USB_TD_RX_DATA_UNDERUN) { | ||
91 | fhci_dbg(usb->fhci, "td err fu\n"); | ||
92 | td->toggle = !td->toggle; | ||
93 | td->actual_len += trans_len; | ||
94 | } else { | ||
95 | fhci_dbg(usb->fhci, "td err f!u\n"); | ||
96 | } | ||
97 | } else { | ||
98 | fhci_dbg(usb->fhci, "td err !f\n"); | ||
99 | /* it is not a fatal error -retry this transaction */ | ||
100 | td->nak_cnt = 0; | ||
101 | td->error_cnt++; | ||
102 | td->status = USB_TD_OK; | ||
103 | } | ||
104 | } else if (td->status & USB_TD_TX_ER_NAK) { | ||
105 | /* there was a NAK response */ | ||
106 | fhci_vdbg(usb->fhci, "td nack\n"); | ||
107 | td->nak_cnt++; | ||
108 | td->error_cnt = 0; | ||
109 | td->status = USB_TD_OK; | ||
110 | } else { | ||
111 | /* there was no error on transaction */ | ||
112 | td->error_cnt = 0; | ||
113 | td->nak_cnt = 0; | ||
114 | td->toggle = !td->toggle; | ||
115 | td->actual_len += trans_len; | ||
116 | |||
117 | if (td->len == td->actual_len) | ||
118 | td_done = true; | ||
119 | } | ||
120 | |||
121 | if (td_done) | ||
122 | fhci_move_td_from_ed_to_done_list(usb, ed); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Flush all transmitted packets from BDs | ||
127 | * This routine is called when disabling the USB port to flush all | ||
128 | * transmissions that are allready scheduled in the BDs | ||
129 | */ | ||
130 | void fhci_flush_all_transmissions(struct fhci_usb *usb) | ||
131 | { | ||
132 | u8 mode; | ||
133 | struct td *td; | ||
134 | |||
135 | mode = in_8(&usb->fhci->regs->usb_mod); | ||
136 | clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN); | ||
137 | |||
138 | fhci_flush_bds(usb); | ||
139 | |||
140 | while ((td = fhci_peek_td_from_frame(usb->actual_frame)) != NULL) { | ||
141 | struct packet *pkt = td->pkt; | ||
142 | |||
143 | pkt->status = USB_TD_TX_ER_TIMEOUT; | ||
144 | fhci_transaction_confirm(usb, pkt); | ||
145 | } | ||
146 | |||
147 | usb->actual_frame->frame_status = FRAME_END_TRANSMISSION; | ||
148 | |||
149 | /* reset the event register */ | ||
150 | out_be16(&usb->fhci->regs->usb_event, 0xffff); | ||
151 | /* enable the USB controller */ | ||
152 | out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN); | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * This function forms the packet and transmit the packet. This function | ||
157 | * will handle all endpoint type:ISO,interrupt,control and bulk | ||
158 | */ | ||
159 | static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td) | ||
160 | { | ||
161 | u32 fw_transaction_time, len = 0; | ||
162 | struct packet *pkt; | ||
163 | u8 *data = NULL; | ||
164 | |||
165 | /* calcalate data address,len and toggle and then add the transaction */ | ||
166 | if (td->toggle == USB_TD_TOGGLE_CARRY) | ||
167 | td->toggle = ed->toggle_carry; | ||
168 | |||
169 | switch (ed->mode) { | ||
170 | case FHCI_TF_ISO: | ||
171 | len = td->len; | ||
172 | if (td->type != FHCI_TA_IN) | ||
173 | data = td->data; | ||
174 | break; | ||
175 | case FHCI_TF_CTRL: | ||
176 | case FHCI_TF_BULK: | ||
177 | len = min(td->len - td->actual_len, ed->max_pkt_size); | ||
178 | if (!((td->type == FHCI_TA_IN) && | ||
179 | ((len + td->actual_len) == td->len))) | ||
180 | data = td->data + td->actual_len; | ||
181 | break; | ||
182 | case FHCI_TF_INTR: | ||
183 | len = min(td->len, ed->max_pkt_size); | ||
184 | if (!((td->type == FHCI_TA_IN) && | ||
185 | ((td->len + CRC_SIZE) >= ed->max_pkt_size))) | ||
186 | data = td->data; | ||
187 | break; | ||
188 | default: | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | if (usb->port_status == FHCI_PORT_FULL) | ||
193 | fw_transaction_time = (((len + PROTOCOL_OVERHEAD) * 11) >> 4); | ||
194 | else | ||
195 | fw_transaction_time = ((len + PROTOCOL_OVERHEAD) * 6); | ||
196 | |||
197 | /* check if there's enough space in this frame to submit this TD */ | ||
198 | if (usb->actual_frame->total_bytes + len + PROTOCOL_OVERHEAD >= | ||
199 | usb->max_bytes_per_frame) { | ||
200 | fhci_vdbg(usb->fhci, "not enough space in this frame: " | ||
201 | "%d %d %d\n", usb->actual_frame->total_bytes, len, | ||
202 | usb->max_bytes_per_frame); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | /* check if there's enough time in this frame to submit this TD */ | ||
207 | if (usb->actual_frame->frame_status != FRAME_IS_PREPARED && | ||
208 | (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION || | ||
209 | (fw_transaction_time + usb->sw_transaction_time >= | ||
210 | 1000 - fhci_get_sof_timer_count(usb)))) { | ||
211 | fhci_dbg(usb->fhci, "not enough time in this frame\n"); | ||
212 | return -1; | ||
213 | } | ||
214 | |||
215 | /* update frame object fields before transmitting */ | ||
216 | pkt = cq_get(usb->ep0->empty_frame_Q); | ||
217 | if (!pkt) { | ||
218 | fhci_dbg(usb->fhci, "there is no empty frame\n"); | ||
219 | return -1; | ||
220 | } | ||
221 | td->pkt = pkt; | ||
222 | |||
223 | pkt->info = 0; | ||
224 | if (data == NULL) { | ||
225 | data = cq_get(usb->ep0->dummy_packets_Q); | ||
226 | BUG_ON(!data); | ||
227 | pkt->info = PKT_DUMMY_PACKET; | ||
228 | } | ||
229 | pkt->data = data; | ||
230 | pkt->len = len; | ||
231 | pkt->status = USB_TD_OK; | ||
232 | /* update TD status field before transmitting */ | ||
233 | td->status = USB_TD_INPROGRESS; | ||
234 | /* update actual frame time object with the actual transmission */ | ||
235 | usb->actual_frame->total_bytes += (len + PROTOCOL_OVERHEAD); | ||
236 | fhci_add_td_to_frame(usb->actual_frame, td); | ||
237 | |||
238 | if (usb->port_status != FHCI_PORT_FULL && | ||
239 | usb->port_status != FHCI_PORT_LOW) { | ||
240 | pkt->status = USB_TD_TX_ER_TIMEOUT; | ||
241 | pkt->len = 0; | ||
242 | fhci_transaction_confirm(usb, pkt); | ||
243 | } else if (fhci_host_transaction(usb, pkt, td->type, ed->dev_addr, | ||
244 | ed->ep_addr, ed->mode, ed->speed, td->toggle)) { | ||
245 | /* remove TD from actual frame */ | ||
246 | list_del_init(&td->frame_lh); | ||
247 | td->status = USB_TD_OK; | ||
248 | if (pkt->info & PKT_DUMMY_PACKET) | ||
249 | cq_put(usb->ep0->dummy_packets_Q, pkt->data); | ||
250 | recycle_frame(usb, pkt); | ||
251 | usb->actual_frame->total_bytes -= (len + PROTOCOL_OVERHEAD); | ||
252 | fhci_err(usb->fhci, "host transaction failed\n"); | ||
253 | return -1; | ||
254 | } | ||
255 | |||
256 | return len; | ||
257 | } | ||
258 | |||
259 | static void move_head_to_tail(struct list_head *list) | ||
260 | { | ||
261 | struct list_head *node = list->next; | ||
262 | |||
263 | if (!list_empty(list)) { | ||
264 | list_del(node); | ||
265 | list_add_tail(node, list); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * This function goes through the endpoint list and schedules the | ||
271 | * transactions within this list | ||
272 | */ | ||
273 | static int scan_ed_list(struct fhci_usb *usb, | ||
274 | struct list_head *list, enum fhci_tf_mode list_type) | ||
275 | { | ||
276 | static const int frame_part[4] = { | ||
277 | [FHCI_TF_CTRL] = MAX_BYTES_PER_FRAME, | ||
278 | [FHCI_TF_ISO] = (MAX_BYTES_PER_FRAME * | ||
279 | MAX_PERIODIC_FRAME_USAGE) / 100, | ||
280 | [FHCI_TF_BULK] = MAX_BYTES_PER_FRAME, | ||
281 | [FHCI_TF_INTR] = (MAX_BYTES_PER_FRAME * | ||
282 | MAX_PERIODIC_FRAME_USAGE) / 100 | ||
283 | }; | ||
284 | struct ed *ed; | ||
285 | struct td *td; | ||
286 | int ans = 1; | ||
287 | u32 save_transaction_time = usb->sw_transaction_time; | ||
288 | |||
289 | list_for_each_entry(ed, list, node) { | ||
290 | td = ed->td_head; | ||
291 | |||
292 | if (!td || (td && td->status == USB_TD_INPROGRESS)) | ||
293 | continue; | ||
294 | |||
295 | if (ed->state != FHCI_ED_OPER) { | ||
296 | if (ed->state == FHCI_ED_URB_DEL) { | ||
297 | td->status = USB_TD_OK; | ||
298 | fhci_move_td_from_ed_to_done_list(usb, ed); | ||
299 | ed->state = FHCI_ED_SKIP; | ||
300 | } | ||
301 | continue; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * if it isn't interrupt pipe or it is not iso pipe and the | ||
306 | * interval time passed | ||
307 | */ | ||
308 | if ((list_type == FHCI_TF_INTR || list_type == FHCI_TF_ISO) && | ||
309 | (((usb->actual_frame->frame_num - | ||
310 | td->start_frame) & 0x7ff) < td->interval)) | ||
311 | continue; | ||
312 | |||
313 | if (add_packet(usb, ed, td) < 0) | ||
314 | continue; | ||
315 | |||
316 | /* update time stamps in the TD */ | ||
317 | td->start_frame = usb->actual_frame->frame_num; | ||
318 | usb->sw_transaction_time += save_transaction_time; | ||
319 | |||
320 | if (usb->actual_frame->total_bytes >= | ||
321 | usb->max_bytes_per_frame) { | ||
322 | usb->actual_frame->frame_status = | ||
323 | FRAME_DATA_END_TRANSMISSION; | ||
324 | fhci_push_dummy_bd(usb->ep0); | ||
325 | ans = 0; | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | if (usb->actual_frame->total_bytes >= frame_part[list_type]) | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | /* be fair to each ED(move list head around) */ | ||
334 | move_head_to_tail(list); | ||
335 | usb->sw_transaction_time = save_transaction_time; | ||
336 | |||
337 | return ans; | ||
338 | } | ||
339 | |||
340 | static u32 rotate_frames(struct fhci_usb *usb) | ||
341 | { | ||
342 | struct fhci_hcd *fhci = usb->fhci; | ||
343 | |||
344 | if (!list_empty(&usb->actual_frame->tds_list)) { | ||
345 | if ((((in_be16(&fhci->pram->frame_num) & 0x07ff) - | ||
346 | usb->actual_frame->frame_num) & 0x7ff) > 5) | ||
347 | fhci_flush_actual_frame(usb); | ||
348 | else | ||
349 | return -EINVAL; | ||
350 | } | ||
351 | |||
352 | usb->actual_frame->frame_status = FRAME_IS_PREPARED; | ||
353 | usb->actual_frame->frame_num = in_be16(&fhci->pram->frame_num) & 0x7ff; | ||
354 | usb->actual_frame->total_bytes = 0; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * This function schedule the USB transaction and will process the | ||
361 | * endpoint in the following order: iso, interrupt, control and bulk. | ||
362 | */ | ||
363 | void fhci_schedule_transactions(struct fhci_usb *usb) | ||
364 | { | ||
365 | int left = 1; | ||
366 | |||
367 | if (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION) | ||
368 | if (rotate_frames(usb) != 0) | ||
369 | return; | ||
370 | |||
371 | if (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION) | ||
372 | return; | ||
373 | |||
374 | if (usb->actual_frame->total_bytes == 0) { | ||
375 | /* | ||
376 | * schedule the next available ISO transfer | ||
377 | *or next stage of the ISO transfer | ||
378 | */ | ||
379 | scan_ed_list(usb, &usb->hc_list->iso_list, FHCI_TF_ISO); | ||
380 | |||
381 | /* | ||
382 | * schedule the next available interrupt transfer or | ||
383 | * the next stage of the interrupt transfer | ||
384 | */ | ||
385 | scan_ed_list(usb, &usb->hc_list->intr_list, FHCI_TF_INTR); | ||
386 | |||
387 | /* | ||
388 | * schedule the next available control transfer | ||
389 | * or the next stage of the control transfer | ||
390 | */ | ||
391 | left = scan_ed_list(usb, &usb->hc_list->ctrl_list, | ||
392 | FHCI_TF_CTRL); | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * schedule the next available bulk transfer or the next stage of the | ||
397 | * bulk transfer | ||
398 | */ | ||
399 | if (left > 0) | ||
400 | scan_ed_list(usb, &usb->hc_list->bulk_list, FHCI_TF_BULK); | ||
401 | } | ||
402 | |||
403 | /* Handles SOF interrupt */ | ||
404 | static void sof_interrupt(struct fhci_hcd *fhci) | ||
405 | { | ||
406 | struct fhci_usb *usb = fhci->usb_lld; | ||
407 | |||
408 | if ((usb->port_status == FHCI_PORT_DISABLED) && | ||
409 | (usb->vroot_hub->port.wPortStatus & USB_PORT_STAT_CONNECTION) && | ||
410 | !(usb->vroot_hub->port.wPortChange & USB_PORT_STAT_C_CONNECTION)) { | ||
411 | if (usb->vroot_hub->port.wPortStatus & USB_PORT_STAT_LOW_SPEED) | ||
412 | usb->port_status = FHCI_PORT_LOW; | ||
413 | else | ||
414 | usb->port_status = FHCI_PORT_FULL; | ||
415 | /* Disable IDLE */ | ||
416 | usb->saved_msk &= ~USB_E_IDLE_MASK; | ||
417 | out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); | ||
418 | } | ||
419 | |||
420 | gtm_set_exact_timer16(fhci->timer, usb->max_frame_usage, false); | ||
421 | |||
422 | fhci_host_transmit_actual_frame(usb); | ||
423 | usb->actual_frame->frame_status = FRAME_IS_TRANSMITTED; | ||
424 | |||
425 | fhci_schedule_transactions(usb); | ||
426 | } | ||
427 | |||
428 | /* Handles device disconnected interrupt on port */ | ||
429 | void fhci_device_disconnected_interrupt(struct fhci_hcd *fhci) | ||
430 | { | ||
431 | struct fhci_usb *usb = fhci->usb_lld; | ||
432 | |||
433 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
434 | |||
435 | fhci_usb_disable_interrupt(usb); | ||
436 | clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS); | ||
437 | usb->port_status = FHCI_PORT_DISABLED; | ||
438 | |||
439 | fhci_stop_sof_timer(fhci); | ||
440 | |||
441 | /* Enable IDLE since we want to know if something comes along */ | ||
442 | usb->saved_msk |= USB_E_IDLE_MASK; | ||
443 | out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); | ||
444 | |||
445 | usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_CONNECTION; | ||
446 | usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_CONNECTION; | ||
447 | usb->max_bytes_per_frame = 0; | ||
448 | fhci_usb_enable_interrupt(usb); | ||
449 | |||
450 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
451 | } | ||
452 | |||
453 | /* detect a new device connected on the USB port */ | ||
454 | void fhci_device_connected_interrupt(struct fhci_hcd *fhci) | ||
455 | { | ||
456 | |||
457 | struct fhci_usb *usb = fhci->usb_lld; | ||
458 | int state; | ||
459 | int ret; | ||
460 | |||
461 | fhci_dbg(fhci, "-> %s\n", __func__); | ||
462 | |||
463 | fhci_usb_disable_interrupt(usb); | ||
464 | state = fhci_ioports_check_bus_state(fhci); | ||
465 | |||
466 | /* low-speed device was connected to the USB port */ | ||
467 | if (state == 1) { | ||
468 | ret = qe_usb_clock_set(fhci->lowspeed_clk, USB_CLOCK >> 3); | ||
469 | if (ret) { | ||
470 | fhci_warn(fhci, "Low-Speed device is not supported, " | ||
471 | "try use BRGx\n"); | ||
472 | goto out; | ||
473 | } | ||
474 | |||
475 | usb->port_status = FHCI_PORT_LOW; | ||
476 | setbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS); | ||
477 | usb->vroot_hub->port.wPortStatus |= | ||
478 | (USB_PORT_STAT_LOW_SPEED | | ||
479 | USB_PORT_STAT_CONNECTION); | ||
480 | usb->vroot_hub->port.wPortChange |= | ||
481 | USB_PORT_STAT_C_CONNECTION; | ||
482 | usb->max_bytes_per_frame = | ||
483 | (MAX_BYTES_PER_FRAME >> 3) - 7; | ||
484 | fhci_port_enable(usb); | ||
485 | } else if (state == 2) { | ||
486 | ret = qe_usb_clock_set(fhci->fullspeed_clk, USB_CLOCK); | ||
487 | if (ret) { | ||
488 | fhci_warn(fhci, "Full-Speed device is not supported, " | ||
489 | "try use CLKx\n"); | ||
490 | goto out; | ||
491 | } | ||
492 | |||
493 | usb->port_status = FHCI_PORT_FULL; | ||
494 | clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS); | ||
495 | usb->vroot_hub->port.wPortStatus &= | ||
496 | ~USB_PORT_STAT_LOW_SPEED; | ||
497 | usb->vroot_hub->port.wPortStatus |= | ||
498 | USB_PORT_STAT_CONNECTION; | ||
499 | usb->vroot_hub->port.wPortChange |= | ||
500 | USB_PORT_STAT_C_CONNECTION; | ||
501 | usb->max_bytes_per_frame = (MAX_BYTES_PER_FRAME - 15); | ||
502 | fhci_port_enable(usb); | ||
503 | } | ||
504 | out: | ||
505 | fhci_usb_enable_interrupt(usb); | ||
506 | fhci_dbg(fhci, "<- %s\n", __func__); | ||
507 | } | ||
508 | |||
509 | irqreturn_t fhci_frame_limit_timer_irq(int irq, void *_hcd) | ||
510 | { | ||
511 | struct usb_hcd *hcd = _hcd; | ||
512 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
513 | struct fhci_usb *usb = fhci->usb_lld; | ||
514 | |||
515 | spin_lock(&fhci->lock); | ||
516 | |||
517 | gtm_set_exact_timer16(fhci->timer, 1000, false); | ||
518 | |||
519 | if (usb->actual_frame->frame_status == FRAME_IS_TRANSMITTED) { | ||
520 | usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION; | ||
521 | fhci_push_dummy_bd(usb->ep0); | ||
522 | } | ||
523 | |||
524 | fhci_schedule_transactions(usb); | ||
525 | |||
526 | spin_unlock(&fhci->lock); | ||
527 | |||
528 | return IRQ_HANDLED; | ||
529 | } | ||
530 | |||
531 | /* Cancel transmission on the USB endpoint */ | ||
532 | static void abort_transmission(struct fhci_usb *usb) | ||
533 | { | ||
534 | fhci_dbg(usb->fhci, "-> %s\n", __func__); | ||
535 | /* issue stop Tx command */ | ||
536 | qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0); | ||
537 | /* flush Tx FIFOs */ | ||
538 | out_8(&usb->fhci->regs->usb_comm, USB_CMD_FLUSH_FIFO | EP_ZERO); | ||
539 | udelay(1000); | ||
540 | /* reset Tx BDs */ | ||
541 | fhci_flush_bds(usb); | ||
542 | /* issue restart Tx command */ | ||
543 | qe_issue_cmd(QE_USB_RESTART_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0); | ||
544 | fhci_dbg(usb->fhci, "<- %s\n", __func__); | ||
545 | } | ||
546 | |||
547 | irqreturn_t fhci_irq(struct usb_hcd *hcd) | ||
548 | { | ||
549 | struct fhci_hcd *fhci = hcd_to_fhci(hcd); | ||
550 | struct fhci_usb *usb; | ||
551 | u16 usb_er = 0; | ||
552 | unsigned long flags; | ||
553 | |||
554 | spin_lock_irqsave(&fhci->lock, flags); | ||
555 | |||
556 | usb = fhci->usb_lld; | ||
557 | |||
558 | usb_er |= in_be16(&usb->fhci->regs->usb_event) & | ||
559 | in_be16(&usb->fhci->regs->usb_mask); | ||
560 | |||
561 | /* clear event bits for next time */ | ||
562 | out_be16(&usb->fhci->regs->usb_event, usb_er); | ||
563 | |||
564 | fhci_dbg_isr(fhci, usb_er); | ||
565 | |||
566 | if (usb_er & USB_E_RESET_MASK) { | ||
567 | if ((usb->port_status == FHCI_PORT_FULL) || | ||
568 | (usb->port_status == FHCI_PORT_LOW)) { | ||
569 | fhci_device_disconnected_interrupt(fhci); | ||
570 | usb_er &= ~USB_E_IDLE_MASK; | ||
571 | } else if (usb->port_status == FHCI_PORT_WAITING) { | ||
572 | usb->port_status = FHCI_PORT_DISCONNECTING; | ||
573 | |||
574 | /* Turn on IDLE since we want to disconnect */ | ||
575 | usb->saved_msk |= USB_E_IDLE_MASK; | ||
576 | out_be16(&usb->fhci->regs->usb_event, | ||
577 | usb->saved_msk); | ||
578 | } else if (usb->port_status == FHCI_PORT_DISABLED) { | ||
579 | if (fhci_ioports_check_bus_state(fhci) == 1 && | ||
580 | usb->port_status != FHCI_PORT_LOW && | ||
581 | usb->port_status != FHCI_PORT_FULL) | ||
582 | fhci_device_connected_interrupt(fhci); | ||
583 | } | ||
584 | usb_er &= ~USB_E_RESET_MASK; | ||
585 | } | ||
586 | |||
587 | if (usb_er & USB_E_MSF_MASK) { | ||
588 | abort_transmission(fhci->usb_lld); | ||
589 | usb_er &= ~USB_E_MSF_MASK; | ||
590 | } | ||
591 | |||
592 | if (usb_er & (USB_E_SOF_MASK | USB_E_SFT_MASK)) { | ||
593 | sof_interrupt(fhci); | ||
594 | usb_er &= ~(USB_E_SOF_MASK | USB_E_SFT_MASK); | ||
595 | } | ||
596 | |||
597 | if (usb_er & USB_E_TXB_MASK) { | ||
598 | fhci_tx_conf_interrupt(fhci->usb_lld); | ||
599 | usb_er &= ~USB_E_TXB_MASK; | ||
600 | } | ||
601 | |||
602 | if (usb_er & USB_E_TXE1_MASK) { | ||
603 | fhci_tx_conf_interrupt(fhci->usb_lld); | ||
604 | usb_er &= ~USB_E_TXE1_MASK; | ||
605 | } | ||
606 | |||
607 | if (usb_er & USB_E_IDLE_MASK) { | ||
608 | if (usb->port_status == FHCI_PORT_DISABLED && | ||
609 | usb->port_status != FHCI_PORT_LOW && | ||
610 | usb->port_status != FHCI_PORT_FULL) { | ||
611 | usb_er &= ~USB_E_RESET_MASK; | ||
612 | fhci_device_connected_interrupt(fhci); | ||
613 | } else if (usb->port_status == | ||
614 | FHCI_PORT_DISCONNECTING) { | ||
615 | /* XXX usb->port_status = FHCI_PORT_WAITING; */ | ||
616 | /* Disable IDLE */ | ||
617 | usb->saved_msk &= ~USB_E_IDLE_MASK; | ||
618 | out_be16(&usb->fhci->regs->usb_mask, | ||
619 | usb->saved_msk); | ||
620 | } else { | ||
621 | fhci_dbg_isr(fhci, -1); | ||
622 | } | ||
623 | |||
624 | usb_er &= ~USB_E_IDLE_MASK; | ||
625 | } | ||
626 | |||
627 | spin_unlock_irqrestore(&fhci->lock, flags); | ||
628 | |||
629 | return IRQ_HANDLED; | ||
630 | } | ||
631 | |||
632 | |||
633 | /* | ||
634 | * Process normal completions(error or sucess) and clean the schedule. | ||
635 | * | ||
636 | * This is the main path for handing urbs back to drivers. The only other patth | ||
637 | * is process_del_list(),which unlinks URBs by scanning EDs,instead of scanning | ||
638 | * the (re-reversed) done list as this does. | ||
639 | */ | ||
640 | static void process_done_list(unsigned long data) | ||
641 | { | ||
642 | struct urb *urb; | ||
643 | struct ed *ed; | ||
644 | struct td *td; | ||
645 | struct urb_priv *urb_priv; | ||
646 | struct fhci_hcd *fhci = (struct fhci_hcd *)data; | ||
647 | |||
648 | disable_irq(fhci->timer->irq); | ||
649 | disable_irq(fhci_to_hcd(fhci)->irq); | ||
650 | spin_lock(&fhci->lock); | ||
651 | |||
652 | td = fhci_remove_td_from_done_list(fhci->hc_list); | ||
653 | while (td != NULL) { | ||
654 | urb = td->urb; | ||
655 | urb_priv = urb->hcpriv; | ||
656 | ed = td->ed; | ||
657 | |||
658 | /* update URB's length and status from TD */ | ||
659 | fhci_done_td(urb, td); | ||
660 | urb_priv->tds_cnt++; | ||
661 | |||
662 | /* | ||
663 | * if all this urb's TDs are done, call complete() | ||
664 | * Interrupt transfers are the onley special case: | ||
665 | * they are reissued,until "deleted" by usb_unlink_urb | ||
666 | * (real work done in a SOF intr, by process_del_list) | ||
667 | */ | ||
668 | if (urb_priv->tds_cnt == urb_priv->num_of_tds) { | ||
669 | fhci_urb_complete_free(fhci, urb); | ||
670 | } else if (urb_priv->state == URB_DEL && | ||
671 | ed->state == FHCI_ED_SKIP) { | ||
672 | fhci_del_ed_list(fhci, ed); | ||
673 | ed->state = FHCI_ED_OPER; | ||
674 | } else if (ed->state == FHCI_ED_HALTED) { | ||
675 | urb_priv->state = URB_DEL; | ||
676 | ed->state = FHCI_ED_URB_DEL; | ||
677 | fhci_del_ed_list(fhci, ed); | ||
678 | ed->state = FHCI_ED_OPER; | ||
679 | } | ||
680 | |||
681 | td = fhci_remove_td_from_done_list(fhci->hc_list); | ||
682 | } | ||
683 | |||
684 | spin_unlock(&fhci->lock); | ||
685 | enable_irq(fhci->timer->irq); | ||
686 | enable_irq(fhci_to_hcd(fhci)->irq); | ||
687 | } | ||
688 | |||
689 | DECLARE_TASKLET(fhci_tasklet, process_done_list, 0); | ||
690 | |||
691 | /* transfer complted callback */ | ||
692 | u32 fhci_transfer_confirm_callback(struct fhci_hcd *fhci) | ||
693 | { | ||
694 | if (!fhci->process_done_task->state) | ||
695 | tasklet_schedule(fhci->process_done_task); | ||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | /* | ||
700 | * adds urb to the endpoint descriptor list | ||
701 | * arguments: | ||
702 | * fhci data structure for the Low level host controller | ||
703 | * ep USB Host endpoint data structure | ||
704 | * urb USB request block data structure | ||
705 | */ | ||
706 | void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) | ||
707 | { | ||
708 | struct ed *ed = urb->ep->hcpriv; | ||
709 | struct urb_priv *urb_priv = urb->hcpriv; | ||
710 | u32 data_len = urb->transfer_buffer_length; | ||
711 | int urb_state = 0; | ||
712 | int toggle = 0; | ||
713 | struct td *td; | ||
714 | u8 *data; | ||
715 | u16 cnt = 0; | ||
716 | |||
717 | if (ed == NULL) { | ||
718 | ed = fhci_get_empty_ed(fhci); | ||
719 | ed->dev_addr = usb_pipedevice(urb->pipe); | ||
720 | ed->ep_addr = usb_pipeendpoint(urb->pipe); | ||
721 | switch (usb_pipetype(urb->pipe)) { | ||
722 | case PIPE_CONTROL: | ||
723 | ed->mode = FHCI_TF_CTRL; | ||
724 | break; | ||
725 | case PIPE_BULK: | ||
726 | ed->mode = FHCI_TF_BULK; | ||
727 | break; | ||
728 | case PIPE_INTERRUPT: | ||
729 | ed->mode = FHCI_TF_INTR; | ||
730 | break; | ||
731 | case PIPE_ISOCHRONOUS: | ||
732 | ed->mode = FHCI_TF_ISO; | ||
733 | break; | ||
734 | default: | ||
735 | break; | ||
736 | } | ||
737 | ed->speed = (urb->dev->speed == USB_SPEED_LOW) ? | ||
738 | FHCI_LOW_SPEED : FHCI_FULL_SPEED; | ||
739 | ed->max_pkt_size = usb_maxpacket(urb->dev, | ||
740 | urb->pipe, usb_pipeout(urb->pipe)); | ||
741 | urb->ep->hcpriv = ed; | ||
742 | fhci_dbg(fhci, "new ep speed=%d max_pkt_size=%d\n", | ||
743 | ed->speed, ed->max_pkt_size); | ||
744 | } | ||
745 | |||
746 | /* for ISO transfer calculate start frame index */ | ||
747 | if (ed->mode == FHCI_TF_ISO && urb->transfer_flags & URB_ISO_ASAP) | ||
748 | urb->start_frame = ed->td_head ? ed->last_iso + 1 : | ||
749 | get_frame_num(fhci); | ||
750 | |||
751 | /* | ||
752 | * OHCI handles the DATA toggle itself,we just use the USB | ||
753 | * toggle bits | ||
754 | */ | ||
755 | if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), | ||
756 | usb_pipeout(urb->pipe))) | ||
757 | toggle = USB_TD_TOGGLE_CARRY; | ||
758 | else { | ||
759 | toggle = USB_TD_TOGGLE_DATA0; | ||
760 | usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), | ||
761 | usb_pipeout(urb->pipe), 1); | ||
762 | } | ||
763 | |||
764 | urb_priv->tds_cnt = 0; | ||
765 | urb_priv->ed = ed; | ||
766 | if (data_len > 0) | ||
767 | data = urb->transfer_buffer; | ||
768 | else | ||
769 | data = NULL; | ||
770 | |||
771 | switch (ed->mode) { | ||
772 | case FHCI_TF_BULK: | ||
773 | if (urb->transfer_flags & URB_ZERO_PACKET && | ||
774 | urb->transfer_buffer_length > 0 && | ||
775 | ((urb->transfer_buffer_length % | ||
776 | usb_maxpacket(urb->dev, urb->pipe, | ||
777 | usb_pipeout(urb->pipe))) == 0)) | ||
778 | urb_state = US_BULK0; | ||
779 | while (data_len > 4096) { | ||
780 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, | ||
781 | usb_pipeout(urb->pipe) ? FHCI_TA_OUT : | ||
782 | FHCI_TA_IN, | ||
783 | cnt ? USB_TD_TOGGLE_CARRY : | ||
784 | toggle, | ||
785 | data, 4096, 0, 0, true); | ||
786 | data += 4096; | ||
787 | data_len -= 4096; | ||
788 | cnt++; | ||
789 | } | ||
790 | |||
791 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, | ||
792 | usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, | ||
793 | cnt ? USB_TD_TOGGLE_CARRY : toggle, | ||
794 | data, data_len, 0, 0, true); | ||
795 | cnt++; | ||
796 | |||
797 | if (urb->transfer_flags & URB_ZERO_PACKET && | ||
798 | cnt < urb_priv->num_of_tds) { | ||
799 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, | ||
800 | usb_pipeout(urb->pipe) ? FHCI_TA_OUT : | ||
801 | FHCI_TA_IN, | ||
802 | USB_TD_TOGGLE_CARRY, NULL, 0, 0, 0, true); | ||
803 | cnt++; | ||
804 | } | ||
805 | break; | ||
806 | case FHCI_TF_INTR: | ||
807 | urb->start_frame = get_frame_num(fhci) + 1; | ||
808 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, | ||
809 | usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, | ||
810 | USB_TD_TOGGLE_DATA0, data, data_len, | ||
811 | urb->interval, urb->start_frame, true); | ||
812 | break; | ||
813 | case FHCI_TF_CTRL: | ||
814 | ed->dev_addr = usb_pipedevice(urb->pipe); | ||
815 | ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe, | ||
816 | usb_pipeout(urb->pipe)); | ||
817 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, | ||
818 | USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true); | ||
819 | |||
820 | if (data_len > 0) { | ||
821 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, | ||
822 | usb_pipeout(urb->pipe) ? FHCI_TA_OUT : | ||
823 | FHCI_TA_IN, | ||
824 | USB_TD_TOGGLE_DATA1, data, data_len, 0, 0, | ||
825 | true); | ||
826 | } | ||
827 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, | ||
828 | usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT, | ||
829 | USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); | ||
830 | urb_state = US_CTRL_SETUP; | ||
831 | break; | ||
832 | case FHCI_TF_ISO: | ||
833 | for (cnt = 0; cnt < urb->number_of_packets; cnt++) { | ||
834 | u16 frame = urb->start_frame; | ||
835 | |||
836 | /* | ||
837 | * FIXME scheduling should handle frame counter | ||
838 | * roll-around ... exotic case (and OHCI has | ||
839 | * a 2^16 iso range, vs other HCs max of 2^10) | ||
840 | */ | ||
841 | frame += cnt * urb->interval; | ||
842 | frame &= 0x07ff; | ||
843 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, | ||
844 | usb_pipeout(urb->pipe) ? FHCI_TA_OUT : | ||
845 | FHCI_TA_IN, | ||
846 | USB_TD_TOGGLE_DATA0, | ||
847 | data + urb->iso_frame_desc[cnt].offset, | ||
848 | urb->iso_frame_desc[cnt].length, | ||
849 | urb->interval, frame, true); | ||
850 | } | ||
851 | break; | ||
852 | default: | ||
853 | break; | ||
854 | } | ||
855 | |||
856 | /* | ||
857 | * set the state of URB | ||
858 | * control pipe:3 states -- setup,data,status | ||
859 | * interrupt and bulk pipe:1 state -- data | ||
860 | */ | ||
861 | urb->pipe &= ~0x1f; | ||
862 | urb->pipe |= urb_state & 0x1f; | ||
863 | |||
864 | urb_priv->state = URB_INPROGRESS; | ||
865 | |||
866 | if (!ed->td_head) { | ||
867 | ed->state = FHCI_ED_OPER; | ||
868 | switch (ed->mode) { | ||
869 | case FHCI_TF_CTRL: | ||
870 | list_add(&ed->node, &fhci->hc_list->ctrl_list); | ||
871 | break; | ||
872 | case FHCI_TF_BULK: | ||
873 | list_add(&ed->node, &fhci->hc_list->bulk_list); | ||
874 | break; | ||
875 | case FHCI_TF_INTR: | ||
876 | list_add(&ed->node, &fhci->hc_list->intr_list); | ||
877 | break; | ||
878 | case FHCI_TF_ISO: | ||
879 | list_add(&ed->node, &fhci->hc_list->iso_list); | ||
880 | break; | ||
881 | default: | ||
882 | break; | ||
883 | } | ||
884 | } | ||
885 | |||
886 | fhci_add_tds_to_ed(ed, urb_priv->tds, urb_priv->num_of_tds); | ||
887 | fhci->active_urbs++; | ||
888 | } | ||
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c new file mode 100644 index 000000000000..b40332290319 --- /dev/null +++ b/drivers/usb/host/fhci-tds.c | |||
@@ -0,0 +1,626 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/list.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/usb.h> | ||
24 | #include "../core/hcd.h" | ||
25 | #include "fhci.h" | ||
26 | |||
27 | #define DUMMY_BD_BUFFER 0xdeadbeef | ||
28 | #define DUMMY2_BD_BUFFER 0xbaadf00d | ||
29 | |||
30 | /* Transaction Descriptors bits */ | ||
31 | #define TD_R 0x8000 /* ready bit */ | ||
32 | #define TD_W 0x2000 /* wrap bit */ | ||
33 | #define TD_I 0x1000 /* interrupt on completion */ | ||
34 | #define TD_L 0x0800 /* last */ | ||
35 | #define TD_TC 0x0400 /* transmit CRC */ | ||
36 | #define TD_CNF 0x0200 /* CNF - Must be always 1 */ | ||
37 | #define TD_LSP 0x0100 /* Low-speed transaction */ | ||
38 | #define TD_PID 0x00c0 /* packet id */ | ||
39 | #define TD_RXER 0x0020 /* Rx error or not */ | ||
40 | |||
41 | #define TD_NAK 0x0010 /* No ack. */ | ||
42 | #define TD_STAL 0x0008 /* Stall recieved */ | ||
43 | #define TD_TO 0x0004 /* time out */ | ||
44 | #define TD_UN 0x0002 /* underrun */ | ||
45 | #define TD_NO 0x0010 /* Rx Non Octet Aligned Packet */ | ||
46 | #define TD_AB 0x0008 /* Frame Aborted */ | ||
47 | #define TD_CR 0x0004 /* CRC Error */ | ||
48 | #define TD_OV 0x0002 /* Overrun */ | ||
49 | #define TD_BOV 0x0001 /* Buffer Overrun */ | ||
50 | |||
51 | #define TD_ERRORS (TD_NAK | TD_STAL | TD_TO | TD_UN | \ | ||
52 | TD_NO | TD_AB | TD_CR | TD_OV | TD_BOV) | ||
53 | |||
54 | #define TD_PID_DATA0 0x0080 /* Data 0 toggle */ | ||
55 | #define TD_PID_DATA1 0x00c0 /* Data 1 toggle */ | ||
56 | #define TD_PID_TOGGLE 0x00c0 /* Data 0/1 toggle mask */ | ||
57 | |||
58 | #define TD_TOK_SETUP 0x0000 | ||
59 | #define TD_TOK_OUT 0x4000 | ||
60 | #define TD_TOK_IN 0x8000 | ||
61 | #define TD_ISO 0x1000 | ||
62 | #define TD_ENDP 0x0780 | ||
63 | #define TD_ADDR 0x007f | ||
64 | |||
65 | #define TD_ENDP_SHIFT 7 | ||
66 | |||
67 | struct usb_td { | ||
68 | __be16 status; | ||
69 | __be16 length; | ||
70 | __be32 buf_ptr; | ||
71 | __be16 extra; | ||
72 | __be16 reserved; | ||
73 | }; | ||
74 | |||
75 | static struct usb_td __iomem *next_bd(struct usb_td __iomem *base, | ||
76 | struct usb_td __iomem *td, | ||
77 | u16 status) | ||
78 | { | ||
79 | if (status & TD_W) | ||
80 | return base; | ||
81 | else | ||
82 | return ++td; | ||
83 | } | ||
84 | |||
85 | void fhci_push_dummy_bd(struct endpoint *ep) | ||
86 | { | ||
87 | if (ep->already_pushed_dummy_bd == false) { | ||
88 | u16 td_status = in_be16(&ep->empty_td->status); | ||
89 | |||
90 | out_be32(&ep->empty_td->buf_ptr, DUMMY_BD_BUFFER); | ||
91 | /* get the next TD in the ring */ | ||
92 | ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); | ||
93 | ep->already_pushed_dummy_bd = true; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | /* destroy an USB endpoint */ | ||
98 | void fhci_ep0_free(struct fhci_usb *usb) | ||
99 | { | ||
100 | struct endpoint *ep; | ||
101 | int size; | ||
102 | |||
103 | ep = usb->ep0; | ||
104 | if (ep) { | ||
105 | if (ep->td_base) | ||
106 | cpm_muram_free(cpm_muram_offset(ep->td_base)); | ||
107 | |||
108 | if (ep->conf_frame_Q) { | ||
109 | size = cq_howmany(ep->conf_frame_Q); | ||
110 | for (; size; size--) { | ||
111 | struct packet *pkt = cq_get(ep->conf_frame_Q); | ||
112 | |||
113 | kfree(pkt); | ||
114 | } | ||
115 | cq_delete(ep->conf_frame_Q); | ||
116 | } | ||
117 | |||
118 | if (ep->empty_frame_Q) { | ||
119 | size = cq_howmany(ep->empty_frame_Q); | ||
120 | for (; size; size--) { | ||
121 | struct packet *pkt = cq_get(ep->empty_frame_Q); | ||
122 | |||
123 | kfree(pkt); | ||
124 | } | ||
125 | cq_delete(ep->empty_frame_Q); | ||
126 | } | ||
127 | |||
128 | if (ep->dummy_packets_Q) { | ||
129 | size = cq_howmany(ep->dummy_packets_Q); | ||
130 | for (; size; size--) { | ||
131 | u8 *buff = cq_get(ep->dummy_packets_Q); | ||
132 | |||
133 | kfree(buff); | ||
134 | } | ||
135 | cq_delete(ep->dummy_packets_Q); | ||
136 | } | ||
137 | |||
138 | kfree(ep); | ||
139 | usb->ep0 = NULL; | ||
140 | } | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * create the endpoint structure | ||
145 | * | ||
146 | * arguments: | ||
147 | * usb A pointer to the data structure of the USB | ||
148 | * data_mem The data memory partition(BUS) | ||
149 | * ring_len TD ring length | ||
150 | */ | ||
151 | u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, | ||
152 | u32 ring_len) | ||
153 | { | ||
154 | struct endpoint *ep; | ||
155 | struct usb_td __iomem *td; | ||
156 | unsigned long ep_offset; | ||
157 | char *err_for = "enpoint PRAM"; | ||
158 | int ep_mem_size; | ||
159 | u32 i; | ||
160 | |||
161 | /* we need at least 3 TDs in the ring */ | ||
162 | if (!(ring_len > 2)) { | ||
163 | fhci_err(usb->fhci, "illegal TD ring length parameters\n"); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | ep = kzalloc(sizeof(*ep), GFP_KERNEL); | ||
168 | if (!ep) | ||
169 | return -ENOMEM; | ||
170 | |||
171 | ep_mem_size = ring_len * sizeof(*td) + sizeof(struct fhci_ep_pram); | ||
172 | ep_offset = cpm_muram_alloc(ep_mem_size, 32); | ||
173 | if (IS_ERR_VALUE(ep_offset)) | ||
174 | goto err; | ||
175 | ep->td_base = cpm_muram_addr(ep_offset); | ||
176 | |||
177 | /* zero all queue pointers */ | ||
178 | ep->conf_frame_Q = cq_new(ring_len + 2); | ||
179 | ep->empty_frame_Q = cq_new(ring_len + 2); | ||
180 | ep->dummy_packets_Q = cq_new(ring_len + 2); | ||
181 | if (!ep->conf_frame_Q || !ep->empty_frame_Q || !ep->dummy_packets_Q) { | ||
182 | err_for = "frame_queues"; | ||
183 | goto err; | ||
184 | } | ||
185 | |||
186 | for (i = 0; i < (ring_len + 1); i++) { | ||
187 | struct packet *pkt; | ||
188 | u8 *buff; | ||
189 | |||
190 | pkt = kmalloc(sizeof(*pkt), GFP_KERNEL); | ||
191 | if (!pkt) { | ||
192 | err_for = "frame"; | ||
193 | goto err; | ||
194 | } | ||
195 | |||
196 | buff = kmalloc(1028 * sizeof(*buff), GFP_KERNEL); | ||
197 | if (!buff) { | ||
198 | kfree(pkt); | ||
199 | err_for = "buffer"; | ||
200 | goto err; | ||
201 | } | ||
202 | cq_put(ep->empty_frame_Q, pkt); | ||
203 | cq_put(ep->dummy_packets_Q, buff); | ||
204 | } | ||
205 | |||
206 | /* we put the endpoint parameter RAM right behind the TD ring */ | ||
207 | ep->ep_pram_ptr = (void __iomem *)ep->td_base + sizeof(*td) * ring_len; | ||
208 | |||
209 | ep->conf_td = ep->td_base; | ||
210 | ep->empty_td = ep->td_base; | ||
211 | |||
212 | ep->already_pushed_dummy_bd = false; | ||
213 | |||
214 | /* initialize tds */ | ||
215 | td = ep->td_base; | ||
216 | for (i = 0; i < ring_len; i++) { | ||
217 | out_be32(&td->buf_ptr, 0); | ||
218 | out_be16(&td->status, 0); | ||
219 | out_be16(&td->length, 0); | ||
220 | out_be16(&td->extra, 0); | ||
221 | td++; | ||
222 | } | ||
223 | td--; | ||
224 | out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ | ||
225 | out_be16(&td->length, 0); | ||
226 | |||
227 | /* endpoint structure has been created */ | ||
228 | usb->ep0 = ep; | ||
229 | |||
230 | return 0; | ||
231 | err: | ||
232 | fhci_ep0_free(usb); | ||
233 | kfree(ep); | ||
234 | fhci_err(usb->fhci, "no memory for the %s\n", err_for); | ||
235 | return -ENOMEM; | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * initialize the endpoint register according to the given parameters | ||
240 | * | ||
241 | * artuments: | ||
242 | * usb A pointer to the data strucutre of the USB | ||
243 | * ep A pointer to the endpoint structre | ||
244 | * data_mem The data memory partition(BUS) | ||
245 | */ | ||
246 | void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep, | ||
247 | enum fhci_mem_alloc data_mem) | ||
248 | { | ||
249 | u8 rt; | ||
250 | |||
251 | /* set the endpoint registers according to the endpoint */ | ||
252 | out_be16(&usb->fhci->regs->usb_ep[0], | ||
253 | USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE); | ||
254 | out_be16(&usb->fhci->pram->ep_ptr[0], | ||
255 | cpm_muram_offset(ep->ep_pram_ptr)); | ||
256 | |||
257 | rt = (BUS_MODE_BO_BE | BUS_MODE_GBL); | ||
258 | #ifdef MULTI_DATA_BUS | ||
259 | if (data_mem == MEM_SECONDARY) | ||
260 | rt |= BUS_MODE_DTB; | ||
261 | #endif | ||
262 | out_8(&ep->ep_pram_ptr->rx_func_code, rt); | ||
263 | out_8(&ep->ep_pram_ptr->tx_func_code, rt); | ||
264 | out_be16(&ep->ep_pram_ptr->rx_buff_len, 1028); | ||
265 | out_be16(&ep->ep_pram_ptr->rx_base, 0); | ||
266 | out_be16(&ep->ep_pram_ptr->tx_base, cpm_muram_offset(ep->td_base)); | ||
267 | out_be16(&ep->ep_pram_ptr->rx_bd_ptr, 0); | ||
268 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, cpm_muram_offset(ep->td_base)); | ||
269 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Collect the submitted frames and inform the application about them | ||
274 | * It is also prepearing the TDs for new frames. If the Tx interrupts | ||
275 | * are diabled, the application should call that routine to get | ||
276 | * confirmation about the submitted frames. Otherwise, the routine is | ||
277 | * called frome the interrupt service routine during the Tx interrupt. | ||
278 | * In that case the application is informed by calling the application | ||
279 | * specific 'fhci_transaction_confirm' routine | ||
280 | */ | ||
281 | static void fhci_td_transaction_confirm(struct fhci_usb *usb) | ||
282 | { | ||
283 | struct endpoint *ep = usb->ep0; | ||
284 | struct packet *pkt; | ||
285 | struct usb_td __iomem *td; | ||
286 | u16 extra_data; | ||
287 | u16 td_status; | ||
288 | u16 td_length; | ||
289 | u32 buf; | ||
290 | |||
291 | /* | ||
292 | * collect transmitted BDs from the chip. The routine clears all BDs | ||
293 | * with R bit = 0 and the pointer to data buffer is not NULL, that is | ||
294 | * BDs which point to the transmitted data buffer | ||
295 | */ | ||
296 | while (1) { | ||
297 | td = ep->conf_td; | ||
298 | td_status = in_be16(&td->status); | ||
299 | td_length = in_be16(&td->length); | ||
300 | buf = in_be32(&td->buf_ptr); | ||
301 | extra_data = in_be16(&td->extra); | ||
302 | |||
303 | /* check if the TD is empty */ | ||
304 | if (!(!(td_status & TD_R) && ((td_status & ~TD_W) || buf))) | ||
305 | break; | ||
306 | /* check if it is a dummy buffer */ | ||
307 | else if ((buf == DUMMY_BD_BUFFER) && !(td_status & ~TD_W)) | ||
308 | break; | ||
309 | |||
310 | /* mark TD as empty */ | ||
311 | clrbits16(&td->status, ~TD_W); | ||
312 | out_be16(&td->length, 0); | ||
313 | out_be32(&td->buf_ptr, 0); | ||
314 | out_be16(&td->extra, 0); | ||
315 | /* advance the TD pointer */ | ||
316 | ep->conf_td = next_bd(ep->td_base, ep->conf_td, td_status); | ||
317 | |||
318 | /* check if it is a dummy buffer(type2) */ | ||
319 | if ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W)) | ||
320 | continue; | ||
321 | |||
322 | pkt = cq_get(ep->conf_frame_Q); | ||
323 | if (!pkt) | ||
324 | fhci_err(usb->fhci, "no frame to confirm\n"); | ||
325 | |||
326 | if (td_status & TD_ERRORS) { | ||
327 | if (td_status & TD_RXER) { | ||
328 | if (td_status & TD_CR) | ||
329 | pkt->status = USB_TD_RX_ER_CRC; | ||
330 | else if (td_status & TD_AB) | ||
331 | pkt->status = USB_TD_RX_ER_BITSTUFF; | ||
332 | else if (td_status & TD_OV) | ||
333 | pkt->status = USB_TD_RX_ER_OVERUN; | ||
334 | else if (td_status & TD_BOV) | ||
335 | pkt->status = USB_TD_RX_DATA_OVERUN; | ||
336 | else if (td_status & TD_NO) | ||
337 | pkt->status = USB_TD_RX_ER_NONOCT; | ||
338 | else | ||
339 | fhci_err(usb->fhci, "illegal error " | ||
340 | "occured\n"); | ||
341 | } else if (td_status & TD_NAK) | ||
342 | pkt->status = USB_TD_TX_ER_NAK; | ||
343 | else if (td_status & TD_TO) | ||
344 | pkt->status = USB_TD_TX_ER_TIMEOUT; | ||
345 | else if (td_status & TD_UN) | ||
346 | pkt->status = USB_TD_TX_ER_UNDERUN; | ||
347 | else if (td_status & TD_STAL) | ||
348 | pkt->status = USB_TD_TX_ER_STALL; | ||
349 | else | ||
350 | fhci_err(usb->fhci, "illegal error occured\n"); | ||
351 | } else if ((extra_data & TD_TOK_IN) && | ||
352 | pkt->len > td_length - CRC_SIZE) { | ||
353 | pkt->status = USB_TD_RX_DATA_UNDERUN; | ||
354 | } | ||
355 | |||
356 | if (extra_data & TD_TOK_IN) | ||
357 | pkt->len = td_length - CRC_SIZE; | ||
358 | else if (pkt->info & PKT_ZLP) | ||
359 | pkt->len = 0; | ||
360 | else | ||
361 | pkt->len = td_length; | ||
362 | |||
363 | fhci_transaction_confirm(usb, pkt); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | * Submitting a data frame to a specified endpoint of a USB device | ||
369 | * The frame is put in the driver's transmit queue for this endpoint | ||
370 | * | ||
371 | * Arguments: | ||
372 | * usb A pointer to the USB structure | ||
373 | * pkt A pointer to the user frame structure | ||
374 | * trans_type Transaction tyep - IN,OUT or SETUP | ||
375 | * dest_addr Device address - 0~127 | ||
376 | * dest_ep Endpoint number of the device - 0~16 | ||
377 | * trans_mode Pipe type - ISO,Interrupt,bulk or control | ||
378 | * dest_speed USB speed - Low speed or FULL speed | ||
379 | * data_toggle Data sequence toggle - 0 or 1 | ||
380 | */ | ||
381 | u32 fhci_host_transaction(struct fhci_usb *usb, | ||
382 | struct packet *pkt, | ||
383 | enum fhci_ta_type trans_type, | ||
384 | u8 dest_addr, | ||
385 | u8 dest_ep, | ||
386 | enum fhci_tf_mode trans_mode, | ||
387 | enum fhci_speed dest_speed, u8 data_toggle) | ||
388 | { | ||
389 | struct endpoint *ep = usb->ep0; | ||
390 | struct usb_td __iomem *td; | ||
391 | u16 extra_data; | ||
392 | u16 td_status; | ||
393 | |||
394 | fhci_usb_disable_interrupt(usb); | ||
395 | /* start from the next BD that should be filled */ | ||
396 | td = ep->empty_td; | ||
397 | td_status = in_be16(&td->status); | ||
398 | |||
399 | if (td_status & TD_R && in_be16(&td->length)) { | ||
400 | /* if the TD is not free */ | ||
401 | fhci_usb_enable_interrupt(usb); | ||
402 | return -1; | ||
403 | } | ||
404 | |||
405 | /* get the next TD in the ring */ | ||
406 | ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); | ||
407 | fhci_usb_enable_interrupt(usb); | ||
408 | pkt->priv_data = td; | ||
409 | out_be32(&td->buf_ptr, virt_to_phys(pkt->data)); | ||
410 | /* sets up transaction parameters - addr,endp,dir,and type */ | ||
411 | extra_data = (dest_ep << TD_ENDP_SHIFT) | dest_addr; | ||
412 | switch (trans_type) { | ||
413 | case FHCI_TA_IN: | ||
414 | extra_data |= TD_TOK_IN; | ||
415 | break; | ||
416 | case FHCI_TA_OUT: | ||
417 | extra_data |= TD_TOK_OUT; | ||
418 | break; | ||
419 | case FHCI_TA_SETUP: | ||
420 | extra_data |= TD_TOK_SETUP; | ||
421 | break; | ||
422 | } | ||
423 | if (trans_mode == FHCI_TF_ISO) | ||
424 | extra_data |= TD_ISO; | ||
425 | out_be16(&td->extra, extra_data); | ||
426 | |||
427 | /* sets up the buffer descriptor */ | ||
428 | td_status = ((td_status & TD_W) | TD_R | TD_L | TD_I | TD_CNF); | ||
429 | if (!(pkt->info & PKT_NO_CRC)) | ||
430 | td_status |= TD_TC; | ||
431 | |||
432 | switch (trans_type) { | ||
433 | case FHCI_TA_IN: | ||
434 | if (data_toggle) | ||
435 | pkt->info |= PKT_PID_DATA1; | ||
436 | else | ||
437 | pkt->info |= PKT_PID_DATA0; | ||
438 | break; | ||
439 | default: | ||
440 | if (data_toggle) { | ||
441 | td_status |= TD_PID_DATA1; | ||
442 | pkt->info |= PKT_PID_DATA1; | ||
443 | } else { | ||
444 | td_status |= TD_PID_DATA0; | ||
445 | pkt->info |= PKT_PID_DATA0; | ||
446 | } | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | if ((dest_speed == FHCI_LOW_SPEED) && | ||
451 | (usb->port_status == FHCI_PORT_FULL)) | ||
452 | td_status |= TD_LSP; | ||
453 | |||
454 | out_be16(&td->status, td_status); | ||
455 | |||
456 | /* set up buffer length */ | ||
457 | if (trans_type == FHCI_TA_IN) | ||
458 | out_be16(&td->length, pkt->len + CRC_SIZE); | ||
459 | else | ||
460 | out_be16(&td->length, pkt->len); | ||
461 | |||
462 | /* put the frame to the confirmation queue */ | ||
463 | cq_put(ep->conf_frame_Q, pkt); | ||
464 | |||
465 | if (cq_howmany(ep->conf_frame_Q) == 1) | ||
466 | out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | /* Reset the Tx BD ring */ | ||
472 | void fhci_flush_bds(struct fhci_usb *usb) | ||
473 | { | ||
474 | u16 extra_data; | ||
475 | u16 td_status; | ||
476 | u32 buf; | ||
477 | struct usb_td __iomem *td; | ||
478 | struct endpoint *ep = usb->ep0; | ||
479 | |||
480 | td = ep->td_base; | ||
481 | while (1) { | ||
482 | td_status = in_be16(&td->status); | ||
483 | buf = in_be32(&td->buf_ptr); | ||
484 | extra_data = in_be16(&td->extra); | ||
485 | |||
486 | /* if the TD is not empty - we'll confirm it as Timeout */ | ||
487 | if (td_status & TD_R) | ||
488 | out_be16(&td->status, (td_status & ~TD_R) | TD_TO); | ||
489 | /* if this TD is dummy - let's skip this TD */ | ||
490 | else if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) | ||
491 | out_be32(&td->buf_ptr, DUMMY2_BD_BUFFER); | ||
492 | /* if this is the last TD - break */ | ||
493 | if (td_status & TD_W) | ||
494 | break; | ||
495 | |||
496 | td++; | ||
497 | } | ||
498 | |||
499 | fhci_td_transaction_confirm(usb); | ||
500 | |||
501 | td = ep->td_base; | ||
502 | do { | ||
503 | out_be16(&td->status, 0); | ||
504 | out_be16(&td->length, 0); | ||
505 | out_be32(&td->buf_ptr, 0); | ||
506 | out_be16(&td->extra, 0); | ||
507 | td++; | ||
508 | } while (!(in_be16(&td->status) & TD_W)); | ||
509 | out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ | ||
510 | out_be16(&td->length, 0); | ||
511 | out_be32(&td->buf_ptr, 0); | ||
512 | out_be16(&td->extra, 0); | ||
513 | |||
514 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, | ||
515 | in_be16(&ep->ep_pram_ptr->tx_base)); | ||
516 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | ||
517 | out_be16(&ep->ep_pram_ptr->tx_cnt, 0); | ||
518 | ep->empty_td = ep->td_base; | ||
519 | ep->conf_td = ep->td_base; | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Flush all transmitted packets from TDs in the actual frame. | ||
524 | * This routine is called when something wrong with the controller and | ||
525 | * we want to get rid of the actual frame and start again next frame | ||
526 | */ | ||
527 | void fhci_flush_actual_frame(struct fhci_usb *usb) | ||
528 | { | ||
529 | u8 mode; | ||
530 | u16 tb_ptr; | ||
531 | u16 extra_data; | ||
532 | u16 td_status; | ||
533 | u32 buf_ptr; | ||
534 | struct usb_td __iomem *td; | ||
535 | struct endpoint *ep = usb->ep0; | ||
536 | |||
537 | /* disable the USB controller */ | ||
538 | mode = in_8(&usb->fhci->regs->usb_mod); | ||
539 | out_8(&usb->fhci->regs->usb_mod, mode & ~USB_MODE_EN); | ||
540 | |||
541 | tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); | ||
542 | td = cpm_muram_addr(tb_ptr); | ||
543 | td_status = in_be16(&td->status); | ||
544 | buf_ptr = in_be32(&td->buf_ptr); | ||
545 | extra_data = in_be16(&td->extra); | ||
546 | do { | ||
547 | if (td_status & TD_R) { | ||
548 | out_be16(&td->status, (td_status & ~TD_R) | TD_TO); | ||
549 | } else { | ||
550 | out_be32(&td->buf_ptr, 0); | ||
551 | ep->already_pushed_dummy_bd = false; | ||
552 | break; | ||
553 | } | ||
554 | |||
555 | /* advance the TD pointer */ | ||
556 | td = next_bd(ep->td_base, td, td_status); | ||
557 | td_status = in_be16(&td->status); | ||
558 | buf_ptr = in_be32(&td->buf_ptr); | ||
559 | extra_data = in_be16(&td->extra); | ||
560 | } while ((td_status & TD_R) || buf_ptr); | ||
561 | |||
562 | fhci_td_transaction_confirm(usb); | ||
563 | |||
564 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, | ||
565 | in_be16(&ep->ep_pram_ptr->tx_base)); | ||
566 | out_be32(&ep->ep_pram_ptr->tx_state, 0); | ||
567 | out_be16(&ep->ep_pram_ptr->tx_cnt, 0); | ||
568 | ep->empty_td = ep->td_base; | ||
569 | ep->conf_td = ep->td_base; | ||
570 | |||
571 | usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION; | ||
572 | |||
573 | /* reset the event register */ | ||
574 | out_be16(&usb->fhci->regs->usb_event, 0xffff); | ||
575 | /* enable the USB controller */ | ||
576 | out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN); | ||
577 | } | ||
578 | |||
579 | /* handles Tx confirm and Tx error interrupt */ | ||
580 | void fhci_tx_conf_interrupt(struct fhci_usb *usb) | ||
581 | { | ||
582 | fhci_td_transaction_confirm(usb); | ||
583 | |||
584 | /* | ||
585 | * Schedule another transaction to this frame only if we have | ||
586 | * already confirmed all transaction in the frame. | ||
587 | */ | ||
588 | if (((fhci_get_sof_timer_count(usb) < usb->max_frame_usage) || | ||
589 | (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION)) && | ||
590 | (list_empty(&usb->actual_frame->tds_list))) | ||
591 | fhci_schedule_transactions(usb); | ||
592 | } | ||
593 | |||
594 | void fhci_host_transmit_actual_frame(struct fhci_usb *usb) | ||
595 | { | ||
596 | u16 tb_ptr; | ||
597 | u16 td_status; | ||
598 | struct usb_td __iomem *td; | ||
599 | struct endpoint *ep = usb->ep0; | ||
600 | |||
601 | tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); | ||
602 | td = cpm_muram_addr(tb_ptr); | ||
603 | |||
604 | if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) { | ||
605 | struct usb_td __iomem *old_td = td; | ||
606 | |||
607 | ep->already_pushed_dummy_bd = false; | ||
608 | td_status = in_be16(&td->status); | ||
609 | /* gets the next TD in the ring */ | ||
610 | td = next_bd(ep->td_base, td, td_status); | ||
611 | tb_ptr = cpm_muram_offset(td); | ||
612 | out_be16(&ep->ep_pram_ptr->tx_bd_ptr, tb_ptr); | ||
613 | |||
614 | /* start transmit only if we have something in the TDs */ | ||
615 | if (in_be16(&td->status) & TD_R) | ||
616 | out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); | ||
617 | |||
618 | if (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) { | ||
619 | out_be32(&old_td->buf_ptr, 0); | ||
620 | ep->conf_td = next_bd(ep->td_base, ep->conf_td, | ||
621 | td_status); | ||
622 | } else { | ||
623 | out_be32(&old_td->buf_ptr, DUMMY2_BD_BUFFER); | ||
624 | } | ||
625 | } | ||
626 | } | ||
diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h new file mode 100644 index 000000000000..7116284ed21a --- /dev/null +++ b/drivers/usb/host/fhci.h | |||
@@ -0,0 +1,607 @@ | |||
1 | /* | ||
2 | * Freescale QUICC Engine USB Host Controller Driver | ||
3 | * | ||
4 | * Copyright (c) Freescale Semicondutor, Inc. 2006. | ||
5 | * Shlomi Gridish <gridish@freescale.com> | ||
6 | * Jerry Huang <Chang-Ming.Huang@freescale.com> | ||
7 | * Copyright (c) Logic Product Development, Inc. 2007 | ||
8 | * Peter Barada <peterb@logicpd.com> | ||
9 | * Copyright (c) MontaVista Software, Inc. 2008. | ||
10 | * Anton Vorontsov <avorontsov@ru.mvista.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #ifndef __FHCI_H | ||
19 | #define __FHCI_H | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/kfifo.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/usb.h> | ||
28 | #include <asm/qe.h> | ||
29 | #include "../core/hcd.h" | ||
30 | |||
31 | #define USB_CLOCK 48000000 | ||
32 | |||
33 | #define FHCI_PRAM_SIZE 0x100 | ||
34 | |||
35 | #define MAX_EDS 32 | ||
36 | #define MAX_TDS 32 | ||
37 | |||
38 | |||
39 | /* CRC16 field size */ | ||
40 | #define CRC_SIZE 2 | ||
41 | |||
42 | /* USB protocol overhead for each frame transmitted from the host */ | ||
43 | #define PROTOCOL_OVERHEAD 7 | ||
44 | |||
45 | /* Packet structure, info field */ | ||
46 | #define PKT_PID_DATA0 0x80000000 /* PID - Data toggle zero */ | ||
47 | #define PKT_PID_DATA1 0x40000000 /* PID - Data toggle one */ | ||
48 | #define PKT_PID_SETUP 0x20000000 /* PID - Setup bit */ | ||
49 | #define PKT_SETUP_STATUS 0x10000000 /* Setup status bit */ | ||
50 | #define PKT_SETADDR_STATUS 0x08000000 /* Set address status bit */ | ||
51 | #define PKT_SET_HOST_LAST 0x04000000 /* Last data packet */ | ||
52 | #define PKT_HOST_DATA 0x02000000 /* Data packet */ | ||
53 | #define PKT_FIRST_IN_FRAME 0x01000000 /* First packet in the frame */ | ||
54 | #define PKT_TOKEN_FRAME 0x00800000 /* Token packet */ | ||
55 | #define PKT_ZLP 0x00400000 /* Zero length packet */ | ||
56 | #define PKT_IN_TOKEN_FRAME 0x00200000 /* IN token packet */ | ||
57 | #define PKT_OUT_TOKEN_FRAME 0x00100000 /* OUT token packet */ | ||
58 | #define PKT_SETUP_TOKEN_FRAME 0x00080000 /* SETUP token packet */ | ||
59 | #define PKT_STALL_FRAME 0x00040000 /* STALL packet */ | ||
60 | #define PKT_NACK_FRAME 0x00020000 /* NACK packet */ | ||
61 | #define PKT_NO_PID 0x00010000 /* No PID */ | ||
62 | #define PKT_NO_CRC 0x00008000 /* don't append CRC */ | ||
63 | #define PKT_HOST_COMMAND 0x00004000 /* Host command packet */ | ||
64 | #define PKT_DUMMY_PACKET 0x00002000 /* Dummy packet, used for mmm */ | ||
65 | #define PKT_LOW_SPEED_PACKET 0x00001000 /* Low-Speed packet */ | ||
66 | |||
67 | #define TRANS_OK (0) | ||
68 | #define TRANS_INPROGRESS (-1) | ||
69 | #define TRANS_DISCARD (-2) | ||
70 | #define TRANS_FAIL (-3) | ||
71 | |||
72 | #define PS_INT 0 | ||
73 | #define PS_DISCONNECTED 1 | ||
74 | #define PS_CONNECTED 2 | ||
75 | #define PS_READY 3 | ||
76 | #define PS_MISSING 4 | ||
77 | |||
78 | /* Transfer Descriptor status field */ | ||
79 | #define USB_TD_OK 0x00000000 /* TD transmited or received ok */ | ||
80 | #define USB_TD_INPROGRESS 0x80000000 /* TD is being transmitted */ | ||
81 | #define USB_TD_RX_ER_NONOCT 0x40000000 /* Tx Non Octet Aligned Packet */ | ||
82 | #define USB_TD_RX_ER_BITSTUFF 0x20000000 /* Frame Aborted-Received pkt */ | ||
83 | #define USB_TD_RX_ER_CRC 0x10000000 /* CRC error */ | ||
84 | #define USB_TD_RX_ER_OVERUN 0x08000000 /* Over - run occured */ | ||
85 | #define USB_TD_RX_ER_PID 0x04000000 /* wrong PID received */ | ||
86 | #define USB_TD_RX_DATA_UNDERUN 0x02000000 /* shorter than expected */ | ||
87 | #define USB_TD_RX_DATA_OVERUN 0x01000000 /* longer than expected */ | ||
88 | #define USB_TD_TX_ER_NAK 0x00800000 /* NAK handshake */ | ||
89 | #define USB_TD_TX_ER_STALL 0x00400000 /* STALL handshake */ | ||
90 | #define USB_TD_TX_ER_TIMEOUT 0x00200000 /* transmit time out */ | ||
91 | #define USB_TD_TX_ER_UNDERUN 0x00100000 /* transmit underrun */ | ||
92 | |||
93 | #define USB_TD_ERROR (USB_TD_RX_ER_NONOCT | USB_TD_RX_ER_BITSTUFF | \ | ||
94 | USB_TD_RX_ER_CRC | USB_TD_RX_ER_OVERUN | USB_TD_RX_ER_PID | \ | ||
95 | USB_TD_RX_DATA_UNDERUN | USB_TD_RX_DATA_OVERUN | \ | ||
96 | USB_TD_TX_ER_NAK | USB_TD_TX_ER_STALL | \ | ||
97 | USB_TD_TX_ER_TIMEOUT | USB_TD_TX_ER_UNDERUN) | ||
98 | |||
99 | /* Transfer Descriptor toggle field */ | ||
100 | #define USB_TD_TOGGLE_DATA0 0 | ||
101 | #define USB_TD_TOGGLE_DATA1 1 | ||
102 | #define USB_TD_TOGGLE_CARRY 2 | ||
103 | |||
104 | /* #define MULTI_DATA_BUS */ | ||
105 | |||
106 | /* Bus mode register RBMR/TBMR */ | ||
107 | #define BUS_MODE_GBL 0x20 /* Global snooping */ | ||
108 | #define BUS_MODE_BO 0x18 /* Byte ordering */ | ||
109 | #define BUS_MODE_BO_BE 0x10 /* Byte ordering - Big-endian */ | ||
110 | #define BUS_MODE_DTB 0x02 /* Data bus */ | ||
111 | |||
112 | /* FHCI QE USB Register Description */ | ||
113 | |||
114 | /* USB Mode Register bit define */ | ||
115 | #define USB_MODE_EN 0x01 | ||
116 | #define USB_MODE_HOST 0x02 | ||
117 | #define USB_MODE_TEST 0x04 | ||
118 | #define USB_MODE_SFTE 0x08 | ||
119 | #define USB_MODE_RESUME 0x40 | ||
120 | #define USB_MODE_LSS 0x80 | ||
121 | |||
122 | /* USB Slave Address Register Mask */ | ||
123 | #define USB_SLVADDR_MASK 0x7F | ||
124 | |||
125 | /* USB Endpoint register define */ | ||
126 | #define USB_EPNUM_MASK 0xF000 | ||
127 | #define USB_EPNUM_SHIFT 12 | ||
128 | |||
129 | #define USB_TRANS_MODE_SHIFT 8 | ||
130 | #define USB_TRANS_CTR 0x0000 | ||
131 | #define USB_TRANS_INT 0x0100 | ||
132 | #define USB_TRANS_BULK 0x0200 | ||
133 | #define USB_TRANS_ISO 0x0300 | ||
134 | |||
135 | #define USB_EP_MF 0x0020 | ||
136 | #define USB_EP_RTE 0x0010 | ||
137 | |||
138 | #define USB_THS_SHIFT 2 | ||
139 | #define USB_THS_MASK 0x000c | ||
140 | #define USB_THS_NORMAL 0x0 | ||
141 | #define USB_THS_IGNORE_IN 0x0004 | ||
142 | #define USB_THS_NACK 0x0008 | ||
143 | #define USB_THS_STALL 0x000c | ||
144 | |||
145 | #define USB_RHS_SHIFT 0 | ||
146 | #define USB_RHS_MASK 0x0003 | ||
147 | #define USB_RHS_NORMAL 0x0 | ||
148 | #define USB_RHS_IGNORE_OUT 0x0001 | ||
149 | #define USB_RHS_NACK 0x0002 | ||
150 | #define USB_RHS_STALL 0x0003 | ||
151 | |||
152 | #define USB_RTHS_MASK 0x000f | ||
153 | |||
154 | /* USB Command Register define */ | ||
155 | #define USB_CMD_STR_FIFO 0x80 | ||
156 | #define USB_CMD_FLUSH_FIFO 0x40 | ||
157 | #define USB_CMD_ISFT 0x20 | ||
158 | #define USB_CMD_DSFT 0x10 | ||
159 | #define USB_CMD_EP_MASK 0x03 | ||
160 | |||
161 | /* USB Event and Mask Register define */ | ||
162 | #define USB_E_MSF_MASK 0x0800 | ||
163 | #define USB_E_SFT_MASK 0x0400 | ||
164 | #define USB_E_RESET_MASK 0x0200 | ||
165 | #define USB_E_IDLE_MASK 0x0100 | ||
166 | #define USB_E_TXE4_MASK 0x0080 | ||
167 | #define USB_E_TXE3_MASK 0x0040 | ||
168 | #define USB_E_TXE2_MASK 0x0020 | ||
169 | #define USB_E_TXE1_MASK 0x0010 | ||
170 | #define USB_E_SOF_MASK 0x0008 | ||
171 | #define USB_E_BSY_MASK 0x0004 | ||
172 | #define USB_E_TXB_MASK 0x0002 | ||
173 | #define USB_E_RXB_MASK 0x0001 | ||
174 | |||
175 | /* Freescale USB Host controller registers */ | ||
176 | struct fhci_regs { | ||
177 | u8 usb_mod; /* mode register */ | ||
178 | u8 usb_addr; /* address register */ | ||
179 | u8 usb_comm; /* command register */ | ||
180 | u8 reserved1[1]; | ||
181 | __be16 usb_ep[4]; /* endpoint register */ | ||
182 | u8 reserved2[4]; | ||
183 | __be16 usb_event; /* event register */ | ||
184 | u8 reserved3[2]; | ||
185 | __be16 usb_mask; /* mask register */ | ||
186 | u8 reserved4[1]; | ||
187 | u8 usb_status; /* status register */ | ||
188 | __be16 usb_sof_tmr; /* Start Of Frame timer */ | ||
189 | u8 reserved5[2]; | ||
190 | __be16 usb_frame_num; /* frame number register */ | ||
191 | u8 reserved6[1]; | ||
192 | }; | ||
193 | |||
194 | /* Freescale USB HOST */ | ||
195 | struct fhci_pram { | ||
196 | __be16 ep_ptr[4]; /* Endpoint porter reg */ | ||
197 | __be32 rx_state; /* Rx internal state */ | ||
198 | __be32 rx_ptr; /* Rx internal data pointer */ | ||
199 | __be16 frame_num; /* Frame number */ | ||
200 | __be16 rx_cnt; /* Rx byte count */ | ||
201 | __be32 rx_temp; /* Rx temp */ | ||
202 | __be32 rx_data_temp; /* Rx data temp */ | ||
203 | __be16 rx_u_ptr; /* Rx microcode return address temp */ | ||
204 | u8 reserved1[2]; /* reserved area */ | ||
205 | __be32 sof_tbl; /* SOF lookup table pointer */ | ||
206 | u8 sof_u_crc_temp; /* SOF micorcode CRC5 temp reg */ | ||
207 | u8 reserved2[0xdb]; | ||
208 | }; | ||
209 | |||
210 | /* Freescale USB Endpoint*/ | ||
211 | struct fhci_ep_pram { | ||
212 | __be16 rx_base; /* Rx BD base address */ | ||
213 | __be16 tx_base; /* Tx BD base address */ | ||
214 | u8 rx_func_code; /* Rx function code */ | ||
215 | u8 tx_func_code; /* Tx function code */ | ||
216 | __be16 rx_buff_len; /* Rx buffer length */ | ||
217 | __be16 rx_bd_ptr; /* Rx BD pointer */ | ||
218 | __be16 tx_bd_ptr; /* Tx BD pointer */ | ||
219 | __be32 tx_state; /* Tx internal state */ | ||
220 | __be32 tx_ptr; /* Tx internal data pointer */ | ||
221 | __be16 tx_crc; /* temp transmit CRC */ | ||
222 | __be16 tx_cnt; /* Tx byte count */ | ||
223 | __be32 tx_temp; /* Tx temp */ | ||
224 | __be16 tx_u_ptr; /* Tx microcode return address temp */ | ||
225 | __be16 reserved; | ||
226 | }; | ||
227 | |||
228 | struct fhci_controller_list { | ||
229 | struct list_head ctrl_list; /* control endpoints */ | ||
230 | struct list_head bulk_list; /* bulk endpoints */ | ||
231 | struct list_head iso_list; /* isochronous endpoints */ | ||
232 | struct list_head intr_list; /* interruput endpoints */ | ||
233 | struct list_head done_list; /* done transfers */ | ||
234 | }; | ||
235 | |||
236 | struct virtual_root_hub { | ||
237 | int dev_num; /* USB address of the root hub */ | ||
238 | u32 feature; /* indicates what feature has been set */ | ||
239 | struct usb_hub_status hub; | ||
240 | struct usb_port_status port; | ||
241 | }; | ||
242 | |||
243 | enum fhci_gpios { | ||
244 | GPIO_USBOE = 0, | ||
245 | GPIO_USBTP, | ||
246 | GPIO_USBTN, | ||
247 | GPIO_USBRP, | ||
248 | GPIO_USBRN, | ||
249 | /* these are optional */ | ||
250 | GPIO_SPEED, | ||
251 | GPIO_POWER, | ||
252 | NUM_GPIOS, | ||
253 | }; | ||
254 | |||
255 | enum fhci_pins { | ||
256 | PIN_USBOE = 0, | ||
257 | PIN_USBTP, | ||
258 | PIN_USBTN, | ||
259 | NUM_PINS, | ||
260 | }; | ||
261 | |||
262 | struct fhci_hcd { | ||
263 | enum qe_clock fullspeed_clk; | ||
264 | enum qe_clock lowspeed_clk; | ||
265 | struct qe_pin *pins[NUM_PINS]; | ||
266 | int gpios[NUM_GPIOS]; | ||
267 | bool alow_gpios[NUM_GPIOS]; | ||
268 | |||
269 | struct fhci_regs __iomem *regs; /* I/O memory used to communicate */ | ||
270 | struct fhci_pram __iomem *pram; /* Parameter RAM */ | ||
271 | struct gtm_timer *timer; | ||
272 | |||
273 | spinlock_t lock; | ||
274 | struct fhci_usb *usb_lld; /* Low-level driver */ | ||
275 | struct virtual_root_hub *vroot_hub; /* the virtual root hub */ | ||
276 | int active_urbs; | ||
277 | struct fhci_controller_list *hc_list; | ||
278 | struct tasklet_struct *process_done_task; /* tasklet for done list */ | ||
279 | |||
280 | struct list_head empty_eds; | ||
281 | struct list_head empty_tds; | ||
282 | |||
283 | #ifdef CONFIG_FHCI_DEBUG | ||
284 | int usb_irq_stat[13]; | ||
285 | struct dentry *dfs_root; | ||
286 | struct dentry *dfs_regs; | ||
287 | struct dentry *dfs_irq_stat; | ||
288 | #endif | ||
289 | }; | ||
290 | |||
291 | #define USB_FRAME_USAGE 90 | ||
292 | #define FRAME_TIME_USAGE (USB_FRAME_USAGE*10) /* frame time usage */ | ||
293 | #define SW_FIX_TIME_BETWEEN_TRANSACTION 150 /* SW */ | ||
294 | #define MAX_BYTES_PER_FRAME (USB_FRAME_USAGE*15) | ||
295 | #define MAX_PERIODIC_FRAME_USAGE 90 | ||
296 | |||
297 | /* transaction type */ | ||
298 | enum fhci_ta_type { | ||
299 | FHCI_TA_IN = 0, /* input transaction */ | ||
300 | FHCI_TA_OUT, /* output transaction */ | ||
301 | FHCI_TA_SETUP, /* setup transaction */ | ||
302 | }; | ||
303 | |||
304 | /* transfer mode */ | ||
305 | enum fhci_tf_mode { | ||
306 | FHCI_TF_CTRL = 0, | ||
307 | FHCI_TF_ISO, | ||
308 | FHCI_TF_BULK, | ||
309 | FHCI_TF_INTR, | ||
310 | }; | ||
311 | |||
312 | enum fhci_speed { | ||
313 | FHCI_FULL_SPEED, | ||
314 | FHCI_LOW_SPEED, | ||
315 | }; | ||
316 | |||
317 | /* endpoint state */ | ||
318 | enum fhci_ed_state { | ||
319 | FHCI_ED_NEW = 0, /* pipe is new */ | ||
320 | FHCI_ED_OPER, /* pipe is operating */ | ||
321 | FHCI_ED_URB_DEL, /* pipe is in hold because urb is being deleted */ | ||
322 | FHCI_ED_SKIP, /* skip this pipe */ | ||
323 | FHCI_ED_HALTED, /* pipe is halted */ | ||
324 | }; | ||
325 | |||
326 | enum fhci_port_status { | ||
327 | FHCI_PORT_POWER_OFF = 0, | ||
328 | FHCI_PORT_DISABLED, | ||
329 | FHCI_PORT_DISCONNECTING, | ||
330 | FHCI_PORT_WAITING, /* waiting for connection */ | ||
331 | FHCI_PORT_FULL, /* full speed connected */ | ||
332 | FHCI_PORT_LOW, /* low speed connected */ | ||
333 | }; | ||
334 | |||
335 | enum fhci_mem_alloc { | ||
336 | MEM_CACHABLE_SYS = 0x00000001, /* primary DDR,cachable */ | ||
337 | MEM_NOCACHE_SYS = 0x00000004, /* primary DDR,non-cachable */ | ||
338 | MEM_SECONDARY = 0x00000002, /* either secondary DDR or SDRAM */ | ||
339 | MEM_PRAM = 0x00000008, /* multi-user RAM identifier */ | ||
340 | }; | ||
341 | |||
342 | /* USB default parameters*/ | ||
343 | #define DEFAULT_RING_LEN 8 | ||
344 | #define DEFAULT_DATA_MEM MEM_CACHABLE_SYS | ||
345 | |||
346 | struct ed { | ||
347 | u8 dev_addr; /* device address */ | ||
348 | u8 ep_addr; /* endpoint address */ | ||
349 | enum fhci_tf_mode mode; /* USB transfer mode */ | ||
350 | enum fhci_speed speed; | ||
351 | unsigned int max_pkt_size; | ||
352 | enum fhci_ed_state state; | ||
353 | struct list_head td_list; /* a list of all queued TD to this pipe */ | ||
354 | struct list_head node; | ||
355 | |||
356 | /* read only parameters, should be cleared upon initialization */ | ||
357 | u8 toggle_carry; /* toggle carry from the last TD submitted */ | ||
358 | u32 last_iso; /* time stamp of last queued ISO transfer */ | ||
359 | struct td *td_head; /* a pointer to the current TD handled */ | ||
360 | }; | ||
361 | |||
362 | struct td { | ||
363 | void *data; /* a pointer to the data buffer */ | ||
364 | unsigned int len; /* length of the data to be submitted */ | ||
365 | unsigned int actual_len; /* actual bytes transfered on this td */ | ||
366 | enum fhci_ta_type type; /* transaction type */ | ||
367 | u8 toggle; /* toggle for next trans. within this TD */ | ||
368 | u16 iso_index; /* ISO transaction index */ | ||
369 | u16 start_frame; /* start frame time stamp */ | ||
370 | u16 interval; /* interval between trans. (for ISO/Intr) */ | ||
371 | u32 status; /* status of the TD */ | ||
372 | struct ed *ed; /* a handle to the corresponding ED */ | ||
373 | struct urb *urb; /* a handle to the corresponding URB */ | ||
374 | bool ioc; /* Inform On Completion */ | ||
375 | struct list_head node; | ||
376 | |||
377 | /* read only parameters should be cleared upon initialization */ | ||
378 | struct packet *pkt; | ||
379 | int nak_cnt; | ||
380 | int error_cnt; | ||
381 | struct list_head frame_lh; | ||
382 | }; | ||
383 | |||
384 | struct packet { | ||
385 | u8 *data; /* packet data */ | ||
386 | u32 len; /* packet length */ | ||
387 | u32 status; /* status of the packet - equivalent to the status | ||
388 | * field for the corresponding structure td */ | ||
389 | u32 info; /* packet information */ | ||
390 | void __iomem *priv_data; /* private data of the driver (TDs or BDs) */ | ||
391 | }; | ||
392 | |||
393 | /* struct for each URB */ | ||
394 | #define URB_INPROGRESS 0 | ||
395 | #define URB_DEL 1 | ||
396 | |||
397 | /* URB states (state field) */ | ||
398 | #define US_BULK 0 | ||
399 | #define US_BULK0 1 | ||
400 | |||
401 | /* three setup states */ | ||
402 | #define US_CTRL_SETUP 2 | ||
403 | #define US_CTRL_DATA 1 | ||
404 | #define US_CTRL_ACK 0 | ||
405 | |||
406 | #define EP_ZERO 0 | ||
407 | |||
408 | struct urb_priv { | ||
409 | int num_of_tds; | ||
410 | int tds_cnt; | ||
411 | int state; | ||
412 | |||
413 | struct td **tds; | ||
414 | struct ed *ed; | ||
415 | struct timer_list time_out; | ||
416 | }; | ||
417 | |||
418 | struct endpoint { | ||
419 | /* Pointer to ep parameter RAM */ | ||
420 | struct fhci_ep_pram __iomem *ep_pram_ptr; | ||
421 | |||
422 | /* Host transactions */ | ||
423 | struct usb_td __iomem *td_base; /* first TD in the ring */ | ||
424 | struct usb_td __iomem *conf_td; /* next TD for confirm after transac */ | ||
425 | struct usb_td __iomem *empty_td;/* next TD for new transaction req. */ | ||
426 | struct kfifo *empty_frame_Q; /* Empty frames list to use */ | ||
427 | struct kfifo *conf_frame_Q; /* frames passed to TDs,waiting for tx */ | ||
428 | struct kfifo *dummy_packets_Q;/* dummy packets for the CRC overun */ | ||
429 | |||
430 | bool already_pushed_dummy_bd; | ||
431 | }; | ||
432 | |||
433 | /* struct for each 1mSec frame time */ | ||
434 | #define FRAME_IS_TRANSMITTED 0x00 | ||
435 | #define FRAME_TIMER_END_TRANSMISSION 0x01 | ||
436 | #define FRAME_DATA_END_TRANSMISSION 0x02 | ||
437 | #define FRAME_END_TRANSMISSION 0x03 | ||
438 | #define FRAME_IS_PREPARED 0x04 | ||
439 | |||
440 | struct fhci_time_frame { | ||
441 | u16 frame_num; /* frame number */ | ||
442 | u16 total_bytes; /* total bytes submitted within this frame */ | ||
443 | u8 frame_status; /* flag that indicates to stop fill this frame */ | ||
444 | struct list_head tds_list; /* all tds of this frame */ | ||
445 | }; | ||
446 | |||
447 | /* internal driver structure*/ | ||
448 | struct fhci_usb { | ||
449 | u16 saved_msk; /* saving of the USB mask register */ | ||
450 | struct endpoint *ep0; /* pointer for endpoint0 structure */ | ||
451 | int intr_nesting_cnt; /* interrupt nesting counter */ | ||
452 | u16 max_frame_usage; /* max frame time usage,in micro-sec */ | ||
453 | u16 max_bytes_per_frame; /* max byte can be tx in one time frame */ | ||
454 | u32 sw_transaction_time; /* sw complete trans time,in micro-sec */ | ||
455 | struct fhci_time_frame *actual_frame; | ||
456 | struct fhci_controller_list *hc_list; /* main structure for hc */ | ||
457 | struct virtual_root_hub *vroot_hub; | ||
458 | enum fhci_port_status port_status; /* v_rh port status */ | ||
459 | |||
460 | u32 (*transfer_confirm)(struct fhci_hcd *fhci); | ||
461 | |||
462 | struct fhci_hcd *fhci; | ||
463 | }; | ||
464 | |||
465 | /* | ||
466 | * Various helpers and prototypes below. | ||
467 | */ | ||
468 | |||
469 | static inline u16 get_frame_num(struct fhci_hcd *fhci) | ||
470 | { | ||
471 | return in_be16(&fhci->pram->frame_num) & 0x07ff; | ||
472 | } | ||
473 | |||
474 | #define fhci_dbg(fhci, fmt, args...) \ | ||
475 | dev_dbg(fhci_to_hcd(fhci)->self.controller, fmt, ##args) | ||
476 | #define fhci_vdbg(fhci, fmt, args...) \ | ||
477 | dev_vdbg(fhci_to_hcd(fhci)->self.controller, fmt, ##args) | ||
478 | #define fhci_err(fhci, fmt, args...) \ | ||
479 | dev_err(fhci_to_hcd(fhci)->self.controller, fmt, ##args) | ||
480 | #define fhci_info(fhci, fmt, args...) \ | ||
481 | dev_info(fhci_to_hcd(fhci)->self.controller, fmt, ##args) | ||
482 | #define fhci_warn(fhci, fmt, args...) \ | ||
483 | dev_warn(fhci_to_hcd(fhci)->self.controller, fmt, ##args) | ||
484 | |||
485 | static inline struct fhci_hcd *hcd_to_fhci(struct usb_hcd *hcd) | ||
486 | { | ||
487 | return (struct fhci_hcd *)hcd->hcd_priv; | ||
488 | } | ||
489 | |||
490 | static inline struct usb_hcd *fhci_to_hcd(struct fhci_hcd *fhci) | ||
491 | { | ||
492 | return container_of((void *)fhci, struct usb_hcd, hcd_priv); | ||
493 | } | ||
494 | |||
495 | /* fifo of pointers */ | ||
496 | static inline struct kfifo *cq_new(int size) | ||
497 | { | ||
498 | return kfifo_alloc(size * sizeof(void *), GFP_KERNEL, NULL); | ||
499 | } | ||
500 | |||
501 | static inline void cq_delete(struct kfifo *kfifo) | ||
502 | { | ||
503 | kfifo_free(kfifo); | ||
504 | } | ||
505 | |||
506 | static inline unsigned int cq_howmany(struct kfifo *kfifo) | ||
507 | { | ||
508 | return __kfifo_len(kfifo) / sizeof(void *); | ||
509 | } | ||
510 | |||
511 | static inline int cq_put(struct kfifo *kfifo, void *p) | ||
512 | { | ||
513 | return __kfifo_put(kfifo, (void *)&p, sizeof(p)); | ||
514 | } | ||
515 | |||
516 | static inline void *cq_get(struct kfifo *kfifo) | ||
517 | { | ||
518 | void *p = NULL; | ||
519 | |||
520 | __kfifo_get(kfifo, (void *)&p, sizeof(p)); | ||
521 | return p; | ||
522 | } | ||
523 | |||
524 | /* fhci-hcd.c */ | ||
525 | void fhci_start_sof_timer(struct fhci_hcd *fhci); | ||
526 | void fhci_stop_sof_timer(struct fhci_hcd *fhci); | ||
527 | u16 fhci_get_sof_timer_count(struct fhci_usb *usb); | ||
528 | void fhci_usb_enable_interrupt(struct fhci_usb *usb); | ||
529 | void fhci_usb_disable_interrupt(struct fhci_usb *usb); | ||
530 | int fhci_ioports_check_bus_state(struct fhci_hcd *fhci); | ||
531 | |||
532 | /* fhci-mem.c */ | ||
533 | void fhci_recycle_empty_td(struct fhci_hcd *fhci, struct td *td); | ||
534 | void fhci_recycle_empty_ed(struct fhci_hcd *fhci, struct ed *ed); | ||
535 | struct ed *fhci_get_empty_ed(struct fhci_hcd *fhci); | ||
536 | struct td *fhci_td_fill(struct fhci_hcd *fhci, struct urb *urb, | ||
537 | struct urb_priv *urb_priv, struct ed *ed, u16 index, | ||
538 | enum fhci_ta_type type, int toggle, u8 *data, u32 len, | ||
539 | u16 interval, u16 start_frame, bool ioc); | ||
540 | void fhci_add_tds_to_ed(struct ed *ed, struct td **td_list, int number); | ||
541 | |||
542 | /* fhci-hub.c */ | ||
543 | void fhci_config_transceiver(struct fhci_hcd *fhci, | ||
544 | enum fhci_port_status status); | ||
545 | void fhci_port_disable(struct fhci_hcd *fhci); | ||
546 | void fhci_port_enable(void *lld); | ||
547 | void fhci_io_port_generate_reset(struct fhci_hcd *fhci); | ||
548 | void fhci_port_reset(void *lld); | ||
549 | int fhci_hub_status_data(struct usb_hcd *hcd, char *buf); | ||
550 | int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | ||
551 | u16 wIndex, char *buf, u16 wLength); | ||
552 | |||
553 | /* fhci-tds.c */ | ||
554 | void fhci_flush_bds(struct fhci_usb *usb); | ||
555 | void fhci_flush_actual_frame(struct fhci_usb *usb); | ||
556 | u32 fhci_host_transaction(struct fhci_usb *usb, struct packet *pkt, | ||
557 | enum fhci_ta_type trans_type, u8 dest_addr, | ||
558 | u8 dest_ep, enum fhci_tf_mode trans_mode, | ||
559 | enum fhci_speed dest_speed, u8 data_toggle); | ||
560 | void fhci_host_transmit_actual_frame(struct fhci_usb *usb); | ||
561 | void fhci_tx_conf_interrupt(struct fhci_usb *usb); | ||
562 | void fhci_push_dummy_bd(struct endpoint *ep); | ||
563 | u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, | ||
564 | u32 ring_len); | ||
565 | void fhci_init_ep_registers(struct fhci_usb *usb, | ||
566 | struct endpoint *ep, | ||
567 | enum fhci_mem_alloc data_mem); | ||
568 | void fhci_ep0_free(struct fhci_usb *usb); | ||
569 | |||
570 | /* fhci-sched.c */ | ||
571 | extern struct tasklet_struct fhci_tasklet; | ||
572 | void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt); | ||
573 | void fhci_flush_all_transmissions(struct fhci_usb *usb); | ||
574 | void fhci_schedule_transactions(struct fhci_usb *usb); | ||
575 | void fhci_device_connected_interrupt(struct fhci_hcd *fhci); | ||
576 | void fhci_device_disconnected_interrupt(struct fhci_hcd *fhci); | ||
577 | void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb); | ||
578 | u32 fhci_transfer_confirm_callback(struct fhci_hcd *fhci); | ||
579 | irqreturn_t fhci_irq(struct usb_hcd *hcd); | ||
580 | irqreturn_t fhci_frame_limit_timer_irq(int irq, void *_hcd); | ||
581 | |||
582 | /* fhci-q.h */ | ||
583 | void fhci_urb_complete_free(struct fhci_hcd *fhci, struct urb *urb); | ||
584 | struct td *fhci_remove_td_from_ed(struct ed *ed); | ||
585 | struct td *fhci_remove_td_from_frame(struct fhci_time_frame *frame); | ||
586 | void fhci_move_td_from_ed_to_done_list(struct fhci_usb *usb, struct ed *ed); | ||
587 | struct td *fhci_peek_td_from_frame(struct fhci_time_frame *frame); | ||
588 | void fhci_add_td_to_frame(struct fhci_time_frame *frame, struct td *td); | ||
589 | struct td *fhci_remove_td_from_done_list(struct fhci_controller_list *p_list); | ||
590 | void fhci_done_td(struct urb *urb, struct td *td); | ||
591 | void fhci_del_ed_list(struct fhci_hcd *fhci, struct ed *ed); | ||
592 | |||
593 | #ifdef CONFIG_FHCI_DEBUG | ||
594 | |||
595 | void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er); | ||
596 | void fhci_dfs_destroy(struct fhci_hcd *fhci); | ||
597 | void fhci_dfs_create(struct fhci_hcd *fhci); | ||
598 | |||
599 | #else | ||
600 | |||
601 | static inline void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er) {} | ||
602 | static inline void fhci_dfs_destroy(struct fhci_hcd *fhci) {} | ||
603 | static inline void fhci_dfs_create(struct fhci_hcd *fhci) {} | ||
604 | |||
605 | #endif /* CONFIG_FHCI_DEBUG */ | ||
606 | |||
607 | #endif /* __FHCI_H */ | ||