]> rtime.felk.cvut.cz Git - mcf548x/linux.git/blob - drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c
Initial 2.6.37
[mcf548x/linux.git] / drivers / staging / westbridge / astoria / api / src / cyaslep2pep.c
1 /* Cypress West Bridge API source file (cyaslep2pep.c)
2 ## ===========================
3 ## Copyright (C) 2010  Cypress Semiconductor
4 ##
5 ## This program is free software; you can redistribute it and/or
6 ## modify it under the terms of the GNU General Public License
7 ## as published by the Free Software Foundation; either version 2
8 ## of the License, or (at your option) any later version.
9 ##
10 ## This program is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ## GNU General Public License for more details.
14 ##
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program; if not, write to the Free Software
17 ## Foundation, Inc., 51 Franklin Street, Fifth Floor
18 ## Boston, MA  02110-1301, USA.
19 ## ===========================
20 */
21
22 #include "../../include/linux/westbridge/cyashal.h"
23 #include "../../include/linux/westbridge/cyasusb.h"
24 #include "../../include/linux/westbridge/cyaserr.h"
25 #include "../../include/linux/westbridge/cyaslowlevel.h"
26 #include "../../include/linux/westbridge/cyasdma.h"
27
28 typedef enum cy_as_physical_endpoint_state {
29         cy_as_e_p_free,
30         cy_as_e_p_in,
31         cy_as_e_p_out,
32         cy_as_e_p_iso_in,
33         cy_as_e_p_iso_out
34 } cy_as_physical_endpoint_state;
35
36
37 /*
38 * This map is used to map an index between 1 and 10
39 * to a logical endpoint number.  This is used to map
40 * LEP register indexes into actual EP numbers.
41 */
42 static cy_as_end_point_number_t end_point_map[] = {
43         3, 5, 7, 9, 10, 11, 12, 13, 14, 15 };
44
45 #define CY_AS_EPCFG_1024                        (1 << 3)
46 #define CY_AS_EPCFG_DBL                  (0x02)
47 #define CY_AS_EPCFG_TRIPLE                (0x03)
48 #define CY_AS_EPCFG_QUAD                        (0x00)
49
50 /*
51  * NB: This table contains the register values for PEP1
52  * and PEP3.  PEP2 and PEP4 only have a bit to change the
53  * direction of the PEP and therefre are not represented
54  * in this table.
55  */
56 static uint8_t pep_register_values[12][4] = {
57         /* Bit 1:0 buffering, 0 = quad, 2 = double, 3 = triple */
58         /* Bit 3 size, 0 = 512, 1 = 1024 */
59         {
60                 CY_AS_EPCFG_DBL,
61                 CY_AS_EPCFG_DBL,
62         },/* Config 1  - PEP1 (2 * 512), PEP2 (2 * 512),
63            * PEP3 (2 * 512), PEP4 (2 * 512) */
64         {
65                 CY_AS_EPCFG_DBL,
66                 CY_AS_EPCFG_QUAD,
67         }, /* Config 2  - PEP1 (2 * 512), PEP2 (2 * 512),
68                 * PEP3 (4 * 512), PEP4 (N/A) */
69         {
70                 CY_AS_EPCFG_DBL,
71                 CY_AS_EPCFG_DBL | CY_AS_EPCFG_1024,
72         },/* Config 3  - PEP1 (2 * 512), PEP2 (2 * 512),
73            * PEP3 (2 * 1024), PEP4(N/A) */
74         {
75                 CY_AS_EPCFG_QUAD,
76                 CY_AS_EPCFG_DBL,
77         },/* Config 4  - PEP1 (4 * 512), PEP2 (N/A),
78            * PEP3 (2 * 512), PEP4 (2 * 512) */
79         {
80                 CY_AS_EPCFG_QUAD,
81                 CY_AS_EPCFG_QUAD,
82         },/* Config 5  - PEP1 (4 * 512), PEP2 (N/A),
83            * PEP3 (4 * 512), PEP4 (N/A) */
84         {
85                 CY_AS_EPCFG_QUAD,
86                 CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
87         },/* Config 6  - PEP1 (4 * 512), PEP2 (N/A),
88            * PEP3 (2 * 1024), PEP4 (N/A) */
89         {
90                 CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
91                 CY_AS_EPCFG_DBL,
92         },/* Config 7  - PEP1 (2 * 1024), PEP2 (N/A),
93            * PEP3 (2 * 512), PEP4 (2 * 512) */
94         {
95                 CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
96                 CY_AS_EPCFG_QUAD,
97         },/* Config 8  - PEP1 (2 * 1024), PEP2 (N/A),
98            * PEP3 (4 * 512), PEP4 (N/A) */
99         {
100                 CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
101                 CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
102         },/* Config 9  - PEP1 (2 * 1024), PEP2 (N/A),
103            * PEP3 (2 * 1024), PEP4 (N/A)*/
104         {
105                 CY_AS_EPCFG_TRIPLE,
106                 CY_AS_EPCFG_TRIPLE,
107         },/* Config 10 - PEP1 (3 * 512), PEP2 (N/A),
108            * PEP3 (3 * 512), PEP4 (2 * 512)*/
109         {
110                 CY_AS_EPCFG_TRIPLE | CY_AS_EPCFG_1024,
111                 CY_AS_EPCFG_DBL,
112         },/* Config 11 - PEP1 (3 * 1024), PEP2 (N/A),
113            * PEP3 (N/A), PEP4 (2 * 512) */
114         {
115                 CY_AS_EPCFG_QUAD | CY_AS_EPCFG_1024,
116                 CY_AS_EPCFG_DBL,
117         },/* Config 12 - PEP1 (4 * 1024), PEP2 (N/A),
118            * PEP3 (N/A), PEP4 (N/A) */
119 };
120
121 static cy_as_return_status_t
122 find_endpoint_directions(cy_as_device *dev_p,
123         cy_as_physical_endpoint_state epstate[4])
124 {
125         int i;
126         cy_as_physical_endpoint_state desired;
127
128         /*
129          * note, there is no error checking here becuase
130          * ISO error checking happens when the API is called.
131          */
132         for (i = 0; i < 10; i++) {
133                 int epno = end_point_map[i];
134                 if (dev_p->usb_config[epno].enabled) {
135                         int pep = dev_p->usb_config[epno].physical;
136                         if (dev_p->usb_config[epno].type == cy_as_usb_iso) {
137                                 /*
138                                  * marking this as an ISO endpoint, removes the
139                                  * physical EP from consideration when
140                                  * mapping the remaining E_ps.
141                                  */
142                                 if (dev_p->usb_config[epno].dir == cy_as_usb_in)
143                                         desired = cy_as_e_p_iso_in;
144                                 else
145                                         desired = cy_as_e_p_iso_out;
146                         } else {
147                                 if (dev_p->usb_config[epno].dir == cy_as_usb_in)
148                                         desired = cy_as_e_p_in;
149                                 else
150                                         desired = cy_as_e_p_out;
151                         }
152
153                         /*
154                          * NB: Note the API calls insure that an ISO endpoint
155                          * has a physical and logical EP number that are the
156                          * same, therefore this condition is not enforced here.
157                          */
158                         if (epstate[pep - 1] !=
159                                 cy_as_e_p_free && epstate[pep - 1] != desired)
160                                 return CY_AS_ERROR_INVALID_CONFIGURATION;
161
162                         epstate[pep - 1] = desired;
163                 }
164         }
165
166         /*
167          * create the EP1 config values directly.
168          * both EP1OUT and EP1IN are invalid by default.
169          */
170         dev_p->usb_ep1cfg[0] = 0;
171         dev_p->usb_ep1cfg[1] = 0;
172         if (dev_p->usb_config[1].enabled) {
173                 if ((dev_p->usb_config[1].dir == cy_as_usb_out) ||
174                         (dev_p->usb_config[1].dir == cy_as_usb_in_out)) {
175                         /* Set the valid bit and type field. */
176                         dev_p->usb_ep1cfg[0] = (1 << 7);
177                         if (dev_p->usb_config[1].type == cy_as_usb_bulk)
178                                 dev_p->usb_ep1cfg[0] |= (2 << 4);
179                         else
180                                 dev_p->usb_ep1cfg[0] |= (3 << 4);
181                 }
182
183                 if ((dev_p->usb_config[1].dir == cy_as_usb_in) ||
184                 (dev_p->usb_config[1].dir == cy_as_usb_in_out)) {
185                         /* Set the valid bit and type field. */
186                         dev_p->usb_ep1cfg[1] = (1 << 7);
187                         if (dev_p->usb_config[1].type == cy_as_usb_bulk)
188                                 dev_p->usb_ep1cfg[1] |= (2 << 4);
189                         else
190                                 dev_p->usb_ep1cfg[1] |= (3 << 4);
191                 }
192         }
193
194         return CY_AS_ERROR_SUCCESS;
195 }
196
197 static void
198 create_register_settings(cy_as_device *dev_p,
199         cy_as_physical_endpoint_state epstate[4])
200 {
201         int i;
202         uint8_t v;
203
204         for (i = 0; i < 4; i++) {
205                 if (i == 0) {
206                         /* Start with the values that specify size */
207                         dev_p->usb_pepcfg[i] =
208                                 pep_register_values
209                                         [dev_p->usb_phy_config - 1][0];
210                 } else if (i == 2) {
211                         /* Start with the values that specify size */
212                         dev_p->usb_pepcfg[i] =
213                                 pep_register_values
214                                         [dev_p->usb_phy_config - 1][1];
215                 } else
216                         dev_p->usb_pepcfg[i] = 0;
217
218                 /* Adjust direction if it is in */
219                 if (epstate[i] == cy_as_e_p_iso_in ||
220                         epstate[i] == cy_as_e_p_in)
221                         dev_p->usb_pepcfg[i] |= (1 << 6);
222         }
223
224         /* Configure the logical EP registers */
225         for (i = 0; i < 10; i++) {
226                 int val;
227                 int epnum = end_point_map[i];
228
229                 v = 0x10;         /* PEP 1, Bulk Endpoint, EP not valid */
230                 if (dev_p->usb_config[epnum].enabled) {
231                         v |= (1 << 7);   /* Enabled */
232
233                         val = dev_p->usb_config[epnum].physical - 1;
234                         cy_as_hal_assert(val >= 0 && val <= 3);
235                         v |= (val << 5);
236
237                         switch (dev_p->usb_config[epnum].type) {
238                         case cy_as_usb_bulk:
239                                 val = 2;
240                                 break;
241                         case cy_as_usb_int:
242                                 val = 3;
243                                 break;
244                         case cy_as_usb_iso:
245                                 val = 1;
246                                 break;
247                         default:
248                                 cy_as_hal_assert(cy_false);
249                                 break;
250                         }
251                         v |= (val << 3);
252                 }
253
254                 dev_p->usb_lepcfg[i] = v;
255         }
256 }
257
258
259 cy_as_return_status_t
260 cy_as_usb_map_logical2_physical(cy_as_device *dev_p)
261 {
262         cy_as_return_status_t ret;
263
264         /* Physical EPs 3 5 7 9 respectively in the array */
265         cy_as_physical_endpoint_state epstate[4] = {
266                 cy_as_e_p_free, cy_as_e_p_free,
267                         cy_as_e_p_free, cy_as_e_p_free };
268
269         /* Find the direction for the endpoints */
270         ret = find_endpoint_directions(dev_p, epstate);
271         if (ret != CY_AS_ERROR_SUCCESS)
272                 return ret;
273
274         /*
275          * now create the register settings based on the given
276          * assigned of logical E_ps to physical endpoints.
277          */
278         create_register_settings(dev_p, epstate);
279
280         return ret;
281 }
282
283 static uint16_t
284 get_max_dma_size(cy_as_device *dev_p, cy_as_end_point_number_t ep)
285 {
286         uint16_t size = dev_p->usb_config[ep].size;
287
288         if (size == 0) {
289                 switch (dev_p->usb_config[ep].type) {
290                 case cy_as_usb_control:
291                         size = 64;
292                         break;
293
294                 case cy_as_usb_bulk:
295                         size = cy_as_device_is_usb_high_speed(dev_p) ?
296                                 512 : 64;
297                         break;
298
299                 case cy_as_usb_int:
300                         size = cy_as_device_is_usb_high_speed(dev_p) ?
301                                 1024 : 64;
302                         break;
303
304                 case cy_as_usb_iso:
305                         size = cy_as_device_is_usb_high_speed(dev_p) ?
306                                 1024 : 1023;
307                         break;
308                 }
309         }
310
311         return size;
312 }
313
314 cy_as_return_status_t
315 cy_as_usb_set_dma_sizes(cy_as_device *dev_p)
316 {
317         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
318         uint32_t i;
319
320         for (i = 0; i < 10; i++) {
321                 cy_as_usb_end_point_config *config_p =
322                         &dev_p->usb_config[end_point_map[i]];
323                 if (config_p->enabled) {
324                         ret = cy_as_dma_set_max_dma_size(dev_p,
325                                 end_point_map[i],
326                                 get_max_dma_size(dev_p, end_point_map[i]));
327                         if (ret != CY_AS_ERROR_SUCCESS)
328                                 break;
329                 }
330         }
331
332         return ret;
333 }
334
335 cy_as_return_status_t
336 cy_as_usb_setup_dma(cy_as_device *dev_p)
337 {
338         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
339         uint32_t i;
340
341         for (i = 0; i < 10; i++) {
342                 cy_as_usb_end_point_config *config_p =
343                         &dev_p->usb_config[end_point_map[i]];
344                 if (config_p->enabled) {
345                         /* Map the endpoint direction to the DMA direction */
346                         cy_as_dma_direction dir = cy_as_direction_out;
347                         if (config_p->dir == cy_as_usb_in)
348                                 dir = cy_as_direction_in;
349
350                         ret = cy_as_dma_enable_end_point(dev_p,
351                                 end_point_map[i], cy_true, dir);
352                         if (ret != CY_AS_ERROR_SUCCESS)
353                                 break;
354                 }
355         }
356
357         return ret;
358 }