blob: d48a6310a17e62abbc428384b8bce54c4497cf33 [file] [log] [blame]
Shimrit Malichi7cc54ba2013-03-12 15:31:18 +02001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/usb/hbm.h>
16#include <mach/usb_bam.h>
17
18/**
19 * USB HBM Hardware registers.
20 *
21 */
22#define USB_OTG_HS_HBM_CFG (0x00000290)
23#define USB_OTG_HS_HBM_QH_MAP_PIPE(n) (0x00000294 + 4 * (n))
24#define USB_OTG_HS_HBM_PIPE_PRODUCER (0x00000314)
25#define USB_OTG_HS_HBM_PARK_MODE_DISABLE (0x00000318)
26#define USB_OTG_HS_HBM_PIPE_ZLT_DISABLE (0x0000031C)
27#define USB_OTG_HS_HBM_PIPE_EN (0x00000310)
28#define USB_OTG_HS_HBM_SW_RST (0x00000324)
29#define USB_OTG_HS_HBM_SB_SW_RST (0x00000320)
30#define USB_OTG_HS_USBCMD (0x00000140)
31#define USB_OTG_HS_USBSTS (0x00000144)
32
33/**
34 * USB HBM Hardware registers bitmask.
35 */
36#define HBM_EN 0x00000001
37#define ASE 0x20
38#define AS 0x8000
39#define PIPE_PRODUCER 1
40#define MAX_PIPE_NUM 16
41#define HBM_QH_MAP_PIPE 0xffffffc0
42
43struct hbm_msm {
44 u32 *base;
45 struct usb_hcd *hcd;
46};
47
48static struct hbm_msm *hbm_ctx;
49
50/**
51 * Read register masked field.
52 *
53 * @base - hbm base virtual address.
54 * @offset - register offset.
55 * @mask - register bitmask.
56 *
57 * @return u32
58 */
59static inline u32 hbm_msm_read_reg_field(void *base,
60 u32 offset, const u32 mask)
61{
62 u32 shift = find_first_bit((void *)&mask, 32);
63 u32 val = ioread32(base + offset);
64 val &= mask; /* clear other bits */
65 val >>= shift;
66 return val;
67}
68
69/**
70 * Write register field.
71 *
72 * @base - hbm base virtual address.
73 * @offset - register offset.
74 * @val - value to be written.
75 *
76 */
77static inline void hbm_msm_write_reg(void *base, u32 offset, u32 val)
78{
79 iowrite32(val, base + offset);
80}
81
82/**
83 * Write register masked field.
84 *
85 * @base - hbm base virtual address.
86 * @offset - register offset.
87 * @mask - register bitmask.
88 * @val - value to write.
89 *
90 */
91static inline void hbm_msm_write_reg_field(void *base, u32 offset,
92 const u32 mask, u32 val)
93{
94 u32 shift = find_first_bit((void *)&mask, 32);
95 u32 tmp = ioread32(base + offset);
96
97 tmp &= ~mask;
98 val = tmp | (val << shift);
99 iowrite32(val, base + offset);
100}
101
102/**
103 * Enable/disable park mode. Park mode enables executing up to 3 usb packets
104 * from each QH.
105 *
106 * @pipe_num - Connection index.
107 *
108 * @disable_park_mode - Enable/disable park mode.
109 *
110 */
111int set_disable_park_mode(u8 pipe_num, bool disable_park_mode)
112{
113 if (pipe_num >= MAX_PIPE_NUM) {
114 pr_err("%s: illegal pipe num %d", __func__, pipe_num);
115 return -EINVAL;
116 }
117
118 /* enable/disable park mode */
119 hbm_msm_write_reg_field(hbm_ctx->base,
120 USB_OTG_HS_HBM_PARK_MODE_DISABLE, 1 << pipe_num,
121 (disable_park_mode ? 1 : 0));
122 return 0;
123}
124
125/**
126 * Enable/disable zero length transfer.
127 *
128 * @pipe_num - Connection index.
129 *
130 * @disable_zlt - Enable/disable zlt.
131 *
132 */
133int set_disable_zlt(u8 pipe_num, bool disable_zlt)
134{
135 if (pipe_num >= MAX_PIPE_NUM) {
136 pr_err("%s: illegal pipe num %d", __func__, pipe_num);
137 return -EINVAL;
138 }
139
140 /* enable/disable zlt */
141 hbm_msm_write_reg_field(hbm_ctx->base,
142 USB_OTG_HS_HBM_PIPE_ZLT_DISABLE, 1 << pipe_num,
143 (disable_zlt ? 1 : 0));
144 return 0;
145}
146
147static void hbm_reset(bool reset)
148{
149 hbm_msm_write_reg_field(hbm_ctx->base, USB_OTG_HS_HBM_SW_RST, 1 << 0,
150 reset ? 1 : 0);
151}
152
153static void hbm_config(bool enable)
154{
155 hbm_msm_write_reg_field(hbm_ctx->base, USB_OTG_HS_HBM_CFG, HBM_EN,
156 enable ? 1 : 0);
157}
158
159int hbm_pipe_init(u32 QH_addr, u32 pipe_num, bool is_consumer)
160{
161 if (pipe_num >= MAX_PIPE_NUM) {
162 pr_err("%s: illegal pipe num %d", __func__, pipe_num);
163 return -EINVAL;
164 }
165
166 /* map QH(ep) <> pipe */
167 hbm_msm_write_reg(hbm_ctx->base,
168 USB_OTG_HS_HBM_QH_MAP_PIPE(pipe_num), QH_addr);
169
170 /* set pipe producer/consumer mode - (IN EP is producer) */
171 hbm_msm_write_reg_field(hbm_ctx->base,
172 USB_OTG_HS_HBM_PIPE_PRODUCER, 1 << pipe_num,
173 (is_consumer ? 0 : 1));
174
175 /* disable park mode as default */
176 set_disable_park_mode(pipe_num, true);
177
178 /* enable zlt as default*/
179 set_disable_zlt(pipe_num, false);
180
181 /* activate pipe */
182 hbm_msm_write_reg_field(hbm_ctx->base, USB_OTG_HS_HBM_PIPE_EN,
183 1 << pipe_num, 1);
184
185 return 0;
186}
187
188void hbm_init(struct usb_hcd *hcd)
189{
190 pr_info("%s\n", __func__);
191
192 hbm_ctx = kzalloc(sizeof(*hbm_ctx), GFP_KERNEL);
193 if (!hbm_ctx) {
194 pr_err("%s: hbm_ctx alloc failed\n", __func__);
195 return;
196 }
Shimrit Malichi7cc54ba2013-03-12 15:31:18 +0200197
198 hbm_ctx->base = hcd->regs;
199 hbm_ctx->hcd = hcd;
200
201 /* reset hbm */
202 hbm_reset(true);
203 /* delay was added to allow the reset process the end */
204 udelay(1000);
205 hbm_reset(false);
206 hbm_config(true);
207}
208
209void hbm_uninit(void)
210{
Shimrit Malichie8adf502013-03-13 18:16:30 +0200211 hbm_config(false);
Shimrit Malichi7cc54ba2013-03-12 15:31:18 +0200212 kfree(hbm_ctx);
213}
214
215static int hbm_submit_async(struct ehci_hcd *ehci, struct urb *urb,
216 struct list_head *qtd_list, gfp_t mem_flags)
217{
218 int epnum;
219 unsigned long flags;
220 struct ehci_qh *qh = NULL;
221 int rc;
222 struct usb_host_bam_type *bam =
223 (struct usb_host_bam_type *)urb->priv_data;
224
225 epnum = urb->ep->desc.bEndpointAddress;
226
227 spin_lock_irqsave(&ehci->lock, flags);
228 if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
229 rc = -ESHUTDOWN;
230 goto done;
231 }
232 rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
233 if (unlikely(rc))
234 goto done;
235
236 qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
237 if (unlikely(qh == NULL)) {
238 usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
239 rc = -ENOMEM;
240 goto done;
241 }
242
243 hbm_pipe_init(qh->qh_dma, bam->pipe_num, bam->dir);
244
245 if (likely(qh->qh_state == QH_STATE_IDLE))
246 qh_link_async(ehci, qh);
247
248done:
249 spin_unlock_irqrestore(&ehci->lock, flags);
250 if (unlikely(qh == NULL))
251 qtd_list_free(ehci, urb, qtd_list);
252 return rc;
253}
254
255int hbm_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
256 gfp_t mem_flags)
257{
258 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
259 struct list_head qtd_list;
260
261 INIT_LIST_HEAD(&qtd_list);
262
263 if (usb_pipetype(urb->pipe) != PIPE_BULK) {
264 pr_err("%s pipe type is not BULK\n", __func__);
265 return -EINVAL;
266 }
267
268 /*no sg support*/
269 urb->transfer_buffer_length = 0;
270 urb->transfer_dma = 0;
271 urb->transfer_flags |= URB_NO_INTERRUPT;
272
273 if (!qh_urb_transaction(ehci, urb, &qtd_list, mem_flags))
274 return -ENOMEM;
275 return hbm_submit_async(ehci, urb, &qtd_list, mem_flags);
276}