1 /* Cypress West Bridge API source file (cyaslep2pep.c)
2 ## ===========================
3 ## Copyright (C) 2010 Cypress Semiconductor
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.
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.
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 ## ===========================
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"
28 typedef enum cy_as_physical_endpoint_state
{
34 } cy_as_physical_endpoint_state
;
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.
42 static cy_as_end_point_number_t end_point_map
[] = {
43 3, 5, 7, 9, 10, 11, 12, 13, 14, 15 };
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)
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
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 */
62 },/* Config 1 - PEP1 (2 * 512), PEP2 (2 * 512),
63 * PEP3 (2 * 512), PEP4 (2 * 512) */
67 }, /* Config 2 - PEP1 (2 * 512), PEP2 (2 * 512),
68 * PEP3 (4 * 512), PEP4 (N/A) */
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) */
77 },/* Config 4 - PEP1 (4 * 512), PEP2 (N/A),
78 * PEP3 (2 * 512), PEP4 (2 * 512) */
82 },/* Config 5 - PEP1 (4 * 512), PEP2 (N/A),
83 * PEP3 (4 * 512), PEP4 (N/A) */
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) */
90 CY_AS_EPCFG_1024
| CY_AS_EPCFG_DBL
,
92 },/* Config 7 - PEP1 (2 * 1024), PEP2 (N/A),
93 * PEP3 (2 * 512), PEP4 (2 * 512) */
95 CY_AS_EPCFG_1024
| CY_AS_EPCFG_DBL
,
97 },/* Config 8 - PEP1 (2 * 1024), PEP2 (N/A),
98 * PEP3 (4 * 512), PEP4 (N/A) */
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)*/
107 },/* Config 10 - PEP1 (3 * 512), PEP2 (N/A),
108 * PEP3 (3 * 512), PEP4 (2 * 512)*/
110 CY_AS_EPCFG_TRIPLE
| CY_AS_EPCFG_1024
,
112 },/* Config 11 - PEP1 (3 * 1024), PEP2 (N/A),
113 * PEP3 (N/A), PEP4 (2 * 512) */
115 CY_AS_EPCFG_QUAD
| CY_AS_EPCFG_1024
,
117 },/* Config 12 - PEP1 (4 * 1024), PEP2 (N/A),
118 * PEP3 (N/A), PEP4 (N/A) */
121 static cy_as_return_status_t
122 find_endpoint_directions(cy_as_device
*dev_p
,
123 cy_as_physical_endpoint_state epstate
[4])
126 cy_as_physical_endpoint_state desired
;
129 * note, there is no error checking here because
130 * ISO error checking happens when the API is called.
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
) {
138 * marking this as an ISO endpoint, removes the
139 * physical EP from consideration when
140 * mapping the remaining E_ps.
142 if (dev_p
->usb_config
[epno
].dir
== cy_as_usb_in
)
143 desired
= cy_as_e_p_iso_in
;
145 desired
= cy_as_e_p_iso_out
;
147 if (dev_p
->usb_config
[epno
].dir
== cy_as_usb_in
)
148 desired
= cy_as_e_p_in
;
150 desired
= cy_as_e_p_out
;
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.
158 if (epstate
[pep
- 1] !=
159 cy_as_e_p_free
&& epstate
[pep
- 1] != desired
)
160 return CY_AS_ERROR_INVALID_CONFIGURATION
;
162 epstate
[pep
- 1] = desired
;
167 * create the EP1 config values directly.
168 * both EP1OUT and EP1IN are invalid by default.
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);
180 dev_p
->usb_ep1cfg
[0] |= (3 << 4);
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);
190 dev_p
->usb_ep1cfg
[1] |= (3 << 4);
194 return CY_AS_ERROR_SUCCESS
;
198 create_register_settings(cy_as_device
*dev_p
,
199 cy_as_physical_endpoint_state epstate
[4])
204 for (i
= 0; i
< 4; i
++) {
206 /* Start with the values that specify size */
207 dev_p
->usb_pepcfg
[i
] =
209 [dev_p
->usb_phy_config
- 1][0];
211 /* Start with the values that specify size */
212 dev_p
->usb_pepcfg
[i
] =
214 [dev_p
->usb_phy_config
- 1][1];
216 dev_p
->usb_pepcfg
[i
] = 0;
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);
224 /* Configure the logical EP registers */
225 for (i
= 0; i
< 10; i
++) {
227 int epnum
= end_point_map
[i
];
229 v
= 0x10; /* PEP 1, Bulk Endpoint, EP not valid */
230 if (dev_p
->usb_config
[epnum
].enabled
) {
231 v
|= (1 << 7); /* Enabled */
233 val
= dev_p
->usb_config
[epnum
].physical
- 1;
234 cy_as_hal_assert(val
>= 0 && val
<= 3);
237 switch (dev_p
->usb_config
[epnum
].type
) {
248 cy_as_hal_assert(cy_false
);
254 dev_p
->usb_lepcfg
[i
] = v
;
259 cy_as_return_status_t
260 cy_as_usb_map_logical2_physical(cy_as_device
*dev_p
)
262 cy_as_return_status_t ret
;
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
};
269 /* Find the direction for the endpoints */
270 ret
= find_endpoint_directions(dev_p
, epstate
);
271 if (ret
!= CY_AS_ERROR_SUCCESS
)
275 * now create the register settings based on the given
276 * assigned of logical E_ps to physical endpoints.
278 create_register_settings(dev_p
, epstate
);
284 get_max_dma_size(cy_as_device
*dev_p
, cy_as_end_point_number_t ep
)
286 uint16_t size
= dev_p
->usb_config
[ep
].size
;
289 switch (dev_p
->usb_config
[ep
].type
) {
290 case cy_as_usb_control
:
295 size
= cy_as_device_is_usb_high_speed(dev_p
) ?
300 size
= cy_as_device_is_usb_high_speed(dev_p
) ?
305 size
= cy_as_device_is_usb_high_speed(dev_p
) ?
314 cy_as_return_status_t
315 cy_as_usb_set_dma_sizes(cy_as_device
*dev_p
)
317 cy_as_return_status_t ret
= CY_AS_ERROR_SUCCESS
;
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
,
326 get_max_dma_size(dev_p
, end_point_map
[i
]));
327 if (ret
!= CY_AS_ERROR_SUCCESS
)
335 cy_as_return_status_t
336 cy_as_usb_setup_dma(cy_as_device
*dev_p
)
338 cy_as_return_status_t ret
= CY_AS_ERROR_SUCCESS
;
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
;
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
)