blob: 088bfd787e4a069e7cf05bfcde86df861c80276a [file] [log] [blame]
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +09001/*
2 * Renesas USB driver
3 *
4 * Copyright (C) 2011 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
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 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
15 *
16 */
17#include <linux/delay.h>
18#include <linux/io.h>
19#include "./common.h"
20#include "./pipe.h"
21
22/*
Kuninori Morimoto4bd04812011-06-06 14:18:07 +090023 * packet info function
24 */
Kuninori Morimoto6acb95d2011-06-06 14:18:16 +090025void usbhs_pkt_init(struct usbhs_pkt *pkt)
Kuninori Morimoto4bd04812011-06-06 14:18:07 +090026{
Kuninori Morimoto6acb95d2011-06-06 14:18:16 +090027 INIT_LIST_HEAD(&pkt->node);
28}
29
30void usbhs_pkt_update(struct usbhs_pkt *pkt, void *buf, int len)
31{
Kuninori Morimoto4bd04812011-06-06 14:18:07 +090032 pkt->buf = buf;
33 pkt->length = len;
34 pkt->actual = 0;
35 pkt->maxp = 0;
36}
37
Kuninori Morimoto6acb95d2011-06-06 14:18:16 +090038void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
39{
40 list_del_init(&pkt->node);
41 list_add_tail(&pkt->node, &pipe->list);
42
43 pkt->pipe = pipe;
44}
45
46void usbhs_pkt_pop(struct usbhs_pkt *pkt)
47{
48 list_del_init(&pkt->node);
49}
50
51struct usbhs_pkt *usbhs_pkt_get(struct usbhs_pipe *pipe)
52{
53 if (list_empty(&pipe->list))
54 return NULL;
55
56 return list_entry(pipe->list.next, struct usbhs_pkt, node);
57}
58
Kuninori Morimoto4bd04812011-06-06 14:18:07 +090059/*
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +090060 * FIFO ctrl
61 */
62static void usbhsf_send_terminator(struct usbhs_pipe *pipe)
63{
64 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
65
66 usbhs_bset(priv, CFIFOCTR, BVAL, BVAL);
67}
68
69static int usbhsf_fifo_barrier(struct usbhs_priv *priv)
70{
71 int timeout = 1024;
72
73 do {
74 /* The FIFO port is accessible */
75 if (usbhs_read(priv, CFIFOCTR) & FRDY)
76 return 0;
77
78 udelay(10);
79 } while (timeout--);
80
81 return -EBUSY;
82}
83
84static void usbhsf_fifo_clear(struct usbhs_pipe *pipe)
85{
86 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
87
88 if (!usbhs_pipe_is_dcp(pipe))
89 usbhsf_fifo_barrier(priv);
90
91 usbhs_write(priv, CFIFOCTR, BCLR);
92}
93
94static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv)
95{
96 return usbhs_read(priv, CFIFOCTR) & DTLN_MASK;
97}
98
99static int usbhsf_fifo_select(struct usbhs_pipe *pipe, int write)
100{
101 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
102 struct device *dev = usbhs_priv_to_dev(priv);
103 int timeout = 1024;
104 u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */
105 u16 base = usbhs_pipe_number(pipe); /* CURPIPE */
106
107 if (usbhs_pipe_is_dcp(pipe))
108 base |= (1 == write) << 5; /* ISEL */
109
110 /* "base" will be used below */
111 usbhs_write(priv, CFIFOSEL, base | MBW_32);
112
113 /* check ISEL and CURPIPE value */
114 while (timeout--) {
115 if (base == (mask & usbhs_read(priv, CFIFOSEL)))
116 return 0;
117 udelay(10);
118 }
119
120 dev_err(dev, "fifo select error\n");
121
122 return -EIO;
123}
124
125/*
126 * PIO fifo functions
127 */
128int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe)
129{
130 return usbhsf_fifo_select(pipe, 1);
131}
132
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900133int usbhs_fifo_write(struct usbhs_pkt *pkt)
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900134{
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900135 struct usbhs_pipe *pipe = pkt->pipe;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900136 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900137 struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900138 void __iomem *addr = priv->base + CFIFO;
139 int maxp = usbhs_pipe_get_maxpacket(pipe);
140 int total_len;
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900141 u8 *buf = pkt->buf;
142 int i, ret, len;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900143
144 ret = usbhs_pipe_is_accessible(pipe);
145 if (ret < 0)
146 return ret;
147
148 ret = usbhsf_fifo_select(pipe, 1);
149 if (ret < 0)
150 return ret;
151
152 ret = usbhsf_fifo_barrier(priv);
153 if (ret < 0)
154 return ret;
155
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900156 len = min(pkt->length, maxp);
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900157 total_len = len;
158
159 /*
160 * FIXME
161 *
162 * 32-bit access only
163 */
164 if (len >= 4 &&
165 !((unsigned long)buf & 0x03)) {
166 iowrite32_rep(addr, buf, len / 4);
167 len %= 4;
168 buf += total_len - len;
169 }
170
171 /* the rest operation */
172 for (i = 0; i < len; i++)
173 iowrite8(buf[i], addr + (0x03 - (i & 0x03)));
174
175 if (total_len < maxp)
176 usbhsf_send_terminator(pipe);
177
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900178 usbhs_pipe_enable(pipe);
179
180 /* update pkt */
181 if (info->tx_done) {
182 pkt->actual = total_len;
183 pkt->maxp = maxp;
184 info->tx_done(pkt);
185 }
186
187 return 0;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900188}
189
190int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe)
191{
192 int ret;
193
194 /*
195 * select pipe and enable it to prepare packet receive
196 */
197 ret = usbhsf_fifo_select(pipe, 0);
198 if (ret < 0)
199 return ret;
200
201 usbhs_pipe_enable(pipe);
202
203 return ret;
204}
205
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900206int usbhs_fifo_read(struct usbhs_pkt *pkt)
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900207{
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900208 struct usbhs_pipe *pipe = pkt->pipe;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900209 struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900210 struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900211 void __iomem *addr = priv->base + CFIFO;
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900212 u8 *buf = pkt->buf;
213 int rcv_len, len;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900214 int i, ret;
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900215 int total_len = 0;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900216 u32 data = 0;
217
218 ret = usbhsf_fifo_select(pipe, 0);
219 if (ret < 0)
220 return ret;
221
222 ret = usbhsf_fifo_barrier(priv);
223 if (ret < 0)
224 return ret;
225
226 rcv_len = usbhsf_fifo_rcv_len(priv);
227
228 /*
229 * Buffer clear if Zero-Length packet
230 *
231 * see
232 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
233 */
234 if (0 == rcv_len) {
235 usbhsf_fifo_clear(pipe);
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900236 goto usbhs_fifo_read_end;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900237 }
238
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900239 len = min(rcv_len, pkt->length);
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900240 total_len = len;
241
242 /*
243 * FIXME
244 *
245 * 32-bit access only
246 */
247 if (len >= 4 &&
248 !((unsigned long)buf & 0x03)) {
249 ioread32_rep(addr, buf, len / 4);
250 len %= 4;
251 buf += rcv_len - len;
252 }
253
254 /* the rest operation */
255 for (i = 0; i < len; i++) {
256 if (!(i & 0x03))
257 data = ioread32(addr);
258
259 buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
260 }
261
Kuninori Morimoto4bd04812011-06-06 14:18:07 +0900262usbhs_fifo_read_end:
263 if (info->rx_done) {
264 /* update pkt */
265 pkt->actual = total_len;
266 pkt->maxp = usbhs_pipe_get_maxpacket(pipe);
267 info->rx_done(pkt);
268 }
269
270 return 0;
Kuninori Morimotoe8d548d2011-06-06 14:18:03 +0900271}