Branch data Line data Source code
1 : : /* ==========================================================================
2 : : * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_adp.c $
3 : : * $Revision: #12 $
4 : : * $Date: 2011/10/26 $
5 : : * $Change: 1873028 $
6 : : *
7 : : * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
8 : : * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
9 : : * otherwise expressly agreed to in writing between Synopsys and you.
10 : : *
11 : : * The Software IS NOT an item of Licensed Software or Licensed Product under
12 : : * any End User Software License Agreement or Agreement for Licensed Product
13 : : * with Synopsys or any supplement thereto. You are permitted to use and
14 : : * redistribute this Software in source and binary forms, with or without
15 : : * modification, provided that redistributions of source code must retain this
16 : : * notice. You may not view, use, disclose, copy or distribute this file or
17 : : * any information contained herein except pursuant to this license grant from
18 : : * Synopsys. If you do not agree with this notice, including the disclaimer
19 : : * below, then you are not authorized to use the Software.
20 : : *
21 : : * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
22 : : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : : * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
25 : : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 : : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 : : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 : : * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 : : * DAMAGE.
32 : : * ========================================================================== */
33 : :
34 : : #include "dwc_os.h"
35 : : #include "dwc_otg_regs.h"
36 : : #include "dwc_otg_cil.h"
37 : : #include "dwc_otg_adp.h"
38 : :
39 : : /** @file
40 : : *
41 : : * This file contains the most of the Attach Detect Protocol implementation for
42 : : * the driver to support OTG Rev2.0.
43 : : *
44 : : */
45 : :
46 : 0 : void dwc_otg_adp_write_reg(dwc_otg_core_if_t * core_if, uint32_t value)
47 : : {
48 : : adpctl_data_t adpctl;
49 : :
50 : 0 : adpctl.d32 = value;
51 : 0 : adpctl.b.ar = 0x2;
52 : :
53 : 0 : DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
54 : :
55 [ # # ]: 0 : while (adpctl.b.ar) {
56 : 0 : adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
57 : : }
58 : :
59 : 0 : }
60 : :
61 : : /**
62 : : * Function is called to read ADP registers
63 : : */
64 : 0 : uint32_t dwc_otg_adp_read_reg(dwc_otg_core_if_t * core_if)
65 : : {
66 : : adpctl_data_t adpctl;
67 : :
68 : 0 : adpctl.d32 = 0;
69 : 0 : adpctl.b.ar = 0x1;
70 : :
71 : 0 : DWC_WRITE_REG32(&core_if->core_global_regs->adpctl, adpctl.d32);
72 : :
73 [ # # ]: 0 : while (adpctl.b.ar) {
74 : 0 : adpctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->adpctl);
75 : : }
76 : :
77 : 0 : return adpctl.d32;
78 : : }
79 : :
80 : : /**
81 : : * Function is called to read ADPCTL register and filter Write-clear bits
82 : : */
83 : 0 : uint32_t dwc_otg_adp_read_reg_filter(dwc_otg_core_if_t * core_if)
84 : : {
85 : : adpctl_data_t adpctl;
86 : :
87 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
88 : 0 : adpctl.b.adp_tmout_int = 0;
89 : 0 : adpctl.b.adp_prb_int = 0;
90 : : adpctl.b.adp_tmout_int = 0;
91 : :
92 : 0 : return adpctl.d32;
93 : : }
94 : :
95 : : /**
96 : : * Function is called to write ADP registers
97 : : */
98 : 0 : void dwc_otg_adp_modify_reg(dwc_otg_core_if_t * core_if, uint32_t clr,
99 : : uint32_t set)
100 : : {
101 : 0 : dwc_otg_adp_write_reg(core_if,
102 : 0 : (dwc_otg_adp_read_reg(core_if) & (~clr)) | set);
103 : 0 : }
104 : :
105 : 0 : static void adp_sense_timeout(void *ptr)
106 : : {
107 : : dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
108 : 0 : core_if->adp.sense_timer_started = 0;
109 : 0 : DWC_PRINTF("ADP SENSE TIMEOUT\n");
110 [ # # ]: 0 : if (core_if->adp_enable) {
111 : 0 : dwc_otg_adp_sense_stop(core_if);
112 : 0 : dwc_otg_adp_probe_start(core_if);
113 : : }
114 : 0 : }
115 : :
116 : : /**
117 : : * This function is called when the ADP vbus timer expires. Timeout is 1.1s.
118 : : */
119 : 0 : static void adp_vbuson_timeout(void *ptr)
120 : : {
121 : : gpwrdn_data_t gpwrdn;
122 : : dwc_otg_core_if_t *core_if = (dwc_otg_core_if_t *) ptr;
123 : 0 : hprt0_data_t hprt0 = {.d32 = 0 };
124 : 0 : pcgcctl_data_t pcgcctl = {.d32 = 0 };
125 : 0 : DWC_PRINTF("%s: 1.1 seconds expire after turning on VBUS\n",__FUNCTION__);
126 [ # # ]: 0 : if (core_if) {
127 : 0 : core_if->adp.vbuson_timer_started = 0;
128 : : /* Turn off vbus */
129 : 0 : hprt0.b.prtpwr = 1;
130 : 0 : DWC_MODIFY_REG32(core_if->host_if->hprt0, hprt0.d32, 0);
131 : 0 : gpwrdn.d32 = 0;
132 : :
133 : : /* Power off the core */
134 [ # # ]: 0 : if (core_if->power_down == 2) {
135 : : /* Enable Wakeup Logic */
136 : : // gpwrdn.b.wkupactiv = 1;
137 : 0 : gpwrdn.b.pmuactv = 0;
138 : 0 : gpwrdn.b.pwrdnrstn = 1;
139 : 0 : gpwrdn.b.pwrdnclmp = 1;
140 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
141 : : gpwrdn.d32);
142 : :
143 : : /* Suspend the Phy Clock */
144 : 0 : pcgcctl.b.stoppclk = 1;
145 : 0 : DWC_MODIFY_REG32(core_if->pcgcctl, 0, pcgcctl.d32);
146 : :
147 : : /* Switch on VDD */
148 : : // gpwrdn.b.wkupactiv = 1;
149 : 0 : gpwrdn.b.pmuactv = 1;
150 : : gpwrdn.b.pwrdnrstn = 1;
151 : : gpwrdn.b.pwrdnclmp = 1;
152 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
153 : : gpwrdn.d32);
154 : : } else {
155 : : /* Enable Power Down Logic */
156 : 0 : gpwrdn.b.pmuintsel = 1;
157 : 0 : gpwrdn.b.pmuactv = 1;
158 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
159 : : }
160 : :
161 : : /* Power off the core */
162 [ # # ]: 0 : if (core_if->power_down == 2) {
163 : 0 : gpwrdn.d32 = 0;
164 : 0 : gpwrdn.b.pwrdnswtch = 1;
165 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn,
166 : : gpwrdn.d32, 0);
167 : : }
168 : :
169 : : /* Unmask SRP detected interrupt from Power Down Logic */
170 : 0 : gpwrdn.d32 = 0;
171 : 0 : gpwrdn.b.srp_det_msk = 1;
172 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
173 : :
174 : 0 : dwc_otg_adp_probe_start(core_if);
175 : 0 : dwc_otg_dump_global_registers(core_if);
176 : 0 : dwc_otg_dump_host_registers(core_if);
177 : : }
178 : :
179 : 0 : }
180 : :
181 : : /**
182 : : * Start the ADP Initial Probe timer to detect if Port Connected interrupt is
183 : : * not asserted within 1.1 seconds.
184 : : *
185 : : * @param core_if the pointer to core_if strucure.
186 : : */
187 : 0 : void dwc_otg_adp_vbuson_timer_start(dwc_otg_core_if_t * core_if)
188 : : {
189 : 0 : core_if->adp.vbuson_timer_started = 1;
190 [ # # ]: 0 : if (core_if->adp.vbuson_timer)
191 : : {
192 : 0 : DWC_PRINTF("SCHEDULING VBUSON TIMER\n");
193 : : /* 1.1 secs + 60ms necessary for cil_hcd_start*/
194 : 0 : DWC_TIMER_SCHEDULE(core_if->adp.vbuson_timer, 1160);
195 : : } else {
196 : 0 : DWC_WARN("VBUSON_TIMER = %p\n",core_if->adp.vbuson_timer);
197 : : }
198 : 0 : }
199 : :
200 : : #if 0
201 : : /**
202 : : * Masks all DWC OTG core interrupts
203 : : *
204 : : */
205 : : static void mask_all_interrupts(dwc_otg_core_if_t * core_if)
206 : : {
207 : : int i;
208 : : gahbcfg_data_t ahbcfg = {.d32 = 0 };
209 : :
210 : : /* Mask Host Interrupts */
211 : :
212 : : /* Clear and disable HCINTs */
213 : : for (i = 0; i < core_if->core_params->host_channels; i++) {
214 : : DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcintmsk, 0);
215 : : DWC_WRITE_REG32(&core_if->host_if->hc_regs[i]->hcint, 0xFFFFFFFF);
216 : :
217 : : }
218 : :
219 : : /* Clear and disable HAINT */
220 : : DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haintmsk, 0x0000);
221 : : DWC_WRITE_REG32(&core_if->host_if->host_global_regs->haint, 0xFFFFFFFF);
222 : :
223 : : /* Mask Device Interrupts */
224 : : if (!core_if->multiproc_int_enable) {
225 : : /* Clear and disable IN Endpoint interrupts */
226 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->diepmsk, 0);
227 : : for (i = 0; i <= core_if->dev_if->num_in_eps; i++) {
228 : : DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
229 : : diepint, 0xFFFFFFFF);
230 : : }
231 : :
232 : : /* Clear and disable OUT Endpoint interrupts */
233 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->doepmsk, 0);
234 : : for (i = 0; i <= core_if->dev_if->num_out_eps; i++) {
235 : : DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
236 : : doepint, 0xFFFFFFFF);
237 : : }
238 : :
239 : : /* Clear and disable DAINT */
240 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daint,
241 : : 0xFFFFFFFF);
242 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->daintmsk, 0);
243 : : } else {
244 : : for (i = 0; i < core_if->dev_if->num_in_eps; ++i) {
245 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
246 : : diepeachintmsk[i], 0);
247 : : DWC_WRITE_REG32(&core_if->dev_if->in_ep_regs[i]->
248 : : diepint, 0xFFFFFFFF);
249 : : }
250 : :
251 : : for (i = 0; i < core_if->dev_if->num_out_eps; ++i) {
252 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->
253 : : doepeachintmsk[i], 0);
254 : : DWC_WRITE_REG32(&core_if->dev_if->out_ep_regs[i]->
255 : : doepint, 0xFFFFFFFF);
256 : : }
257 : :
258 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachintmsk,
259 : : 0);
260 : : DWC_WRITE_REG32(&core_if->dev_if->dev_global_regs->deachint,
261 : : 0xFFFFFFFF);
262 : :
263 : : }
264 : :
265 : : /* Disable interrupts */
266 : : ahbcfg.b.glblintrmsk = 1;
267 : : DWC_MODIFY_REG32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
268 : :
269 : : /* Disable all interrupts. */
270 : : DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, 0);
271 : :
272 : : /* Clear any pending interrupts */
273 : : DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
274 : :
275 : : /* Clear any pending OTG Interrupts */
276 : : DWC_WRITE_REG32(&core_if->core_global_regs->gotgint, 0xFFFFFFFF);
277 : : }
278 : :
279 : : /**
280 : : * Unmask Port Connection Detected interrupt
281 : : *
282 : : */
283 : : static void unmask_conn_det_intr(dwc_otg_core_if_t * core_if)
284 : : {
285 : : gintmsk_data_t gintmsk = {.d32 = 0,.b.portintr = 1 };
286 : :
287 : : DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk.d32);
288 : : }
289 : : #endif
290 : :
291 : : /**
292 : : * Starts the ADP Probing
293 : : *
294 : : * @param core_if the pointer to core_if structure.
295 : : */
296 : 0 : uint32_t dwc_otg_adp_probe_start(dwc_otg_core_if_t * core_if)
297 : : {
298 : :
299 : 0 : adpctl_data_t adpctl = {.d32 = 0};
300 : : gpwrdn_data_t gpwrdn;
301 : : #if 0
302 : : adpctl_data_t adpctl_int = {.d32 = 0, .b.adp_prb_int = 1,
303 : : .b.adp_sns_int = 1, b.adp_tmout_int};
304 : : #endif
305 : 0 : dwc_otg_disable_global_interrupts(core_if);
306 : 0 : DWC_PRINTF("ADP Probe Start\n");
307 : 0 : core_if->adp.probe_enabled = 1;
308 : :
309 : 0 : adpctl.b.adpres = 1;
310 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
311 : :
312 [ # # ]: 0 : while (adpctl.b.adpres) {
313 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
314 : : }
315 : :
316 : 0 : adpctl.d32 = 0;
317 : 0 : gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
318 : :
319 : : /* In Host mode unmask SRP detected interrupt */
320 : 0 : gpwrdn.d32 = 0;
321 : 0 : gpwrdn.b.sts_chngint_msk = 1;
322 [ # # ]: 0 : if (!gpwrdn.b.idsts) {
323 : 0 : gpwrdn.b.srp_det_msk = 1;
324 : : }
325 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
326 : :
327 : 0 : adpctl.b.adp_tmout_int_msk = 1;
328 : 0 : adpctl.b.adp_prb_int_msk = 1;
329 : 0 : adpctl.b.prb_dschg = 1;
330 : 0 : adpctl.b.prb_delta = 1;
331 : 0 : adpctl.b.prb_per = 1;
332 : 0 : adpctl.b.adpen = 1;
333 : 0 : adpctl.b.enaprb = 1;
334 : :
335 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
336 : 0 : DWC_PRINTF("ADP Probe Finish\n");
337 : 0 : return 0;
338 : : }
339 : :
340 : : /**
341 : : * Starts the ADP Sense timer to detect if ADP Sense interrupt is not asserted
342 : : * within 3 seconds.
343 : : *
344 : : * @param core_if the pointer to core_if strucure.
345 : : */
346 : 0 : void dwc_otg_adp_sense_timer_start(dwc_otg_core_if_t * core_if)
347 : : {
348 : 0 : core_if->adp.sense_timer_started = 1;
349 : 0 : DWC_TIMER_SCHEDULE(core_if->adp.sense_timer, 3000 /* 3 secs */ );
350 : 0 : }
351 : :
352 : : /**
353 : : * Starts the ADP Sense
354 : : *
355 : : * @param core_if the pointer to core_if strucure.
356 : : */
357 : 0 : uint32_t dwc_otg_adp_sense_start(dwc_otg_core_if_t * core_if)
358 : : {
359 : : adpctl_data_t adpctl;
360 : :
361 : 0 : DWC_PRINTF("ADP Sense Start\n");
362 : :
363 : : /* Unmask ADP sense interrupt and mask all other from the core */
364 : 0 : adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
365 : 0 : adpctl.b.adp_sns_int_msk = 1;
366 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
367 : 0 : dwc_otg_disable_global_interrupts(core_if); // vahrama
368 : :
369 : : /* Set ADP reset bit*/
370 : 0 : adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
371 : 0 : adpctl.b.adpres = 1;
372 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
373 : :
374 [ # # ]: 0 : while (adpctl.b.adpres) {
375 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
376 : : }
377 : :
378 : 0 : adpctl.b.adpres = 0;
379 : 0 : adpctl.b.adpen = 1;
380 : 0 : adpctl.b.enasns = 1;
381 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
382 : :
383 : : dwc_otg_adp_sense_timer_start(core_if);
384 : :
385 : 0 : return 0;
386 : : }
387 : :
388 : : /**
389 : : * Stops the ADP Probing
390 : : *
391 : : * @param core_if the pointer to core_if strucure.
392 : : */
393 : 0 : uint32_t dwc_otg_adp_probe_stop(dwc_otg_core_if_t * core_if)
394 : : {
395 : :
396 : : adpctl_data_t adpctl;
397 : 0 : DWC_PRINTF("Stop ADP probe\n");
398 : 0 : core_if->adp.probe_enabled = 0;
399 : 0 : core_if->adp.probe_counter = 0;
400 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
401 : :
402 : 0 : adpctl.b.adpen = 0;
403 : 0 : adpctl.b.adp_prb_int = 1;
404 : 0 : adpctl.b.adp_tmout_int = 1;
405 : 0 : adpctl.b.adp_sns_int = 1;
406 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
407 : :
408 : 0 : return 0;
409 : : }
410 : :
411 : : /**
412 : : * Stops the ADP Sensing
413 : : *
414 : : * @param core_if the pointer to core_if strucure.
415 : : */
416 : 0 : uint32_t dwc_otg_adp_sense_stop(dwc_otg_core_if_t * core_if)
417 : : {
418 : : adpctl_data_t adpctl;
419 : :
420 : 0 : core_if->adp.sense_enabled = 0;
421 : :
422 : 0 : adpctl.d32 = dwc_otg_adp_read_reg_filter(core_if);
423 : 0 : adpctl.b.enasns = 0;
424 : 0 : adpctl.b.adp_sns_int = 1;
425 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
426 : :
427 : 0 : return 0;
428 : : }
429 : :
430 : : /**
431 : : * Called to turn on the VBUS after initial ADP probe in host mode.
432 : : * If port power was already enabled in cil_hcd_start function then
433 : : * only schedule a timer.
434 : : *
435 : : * @param core_if the pointer to core_if structure.
436 : : */
437 : 0 : void dwc_otg_adp_turnon_vbus(dwc_otg_core_if_t * core_if)
438 : : {
439 : : hprt0_data_t hprt0 = {.d32 = 0 };
440 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
441 : 0 : DWC_PRINTF("Turn on VBUS for 1.1s, port power is %d\n", hprt0.b.prtpwr);
442 : :
443 : : if (hprt0.b.prtpwr == 0) {
444 : : hprt0.b.prtpwr = 1;
445 : : //DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
446 : : }
447 : :
448 : 0 : dwc_otg_adp_vbuson_timer_start(core_if);
449 : 0 : }
450 : :
451 : : /**
452 : : * Called right after driver is loaded
453 : : * to perform initial actions for ADP
454 : : *
455 : : * @param core_if the pointer to core_if structure.
456 : : * @param is_host - flag for current mode of operation either from GINTSTS or GPWRDN
457 : : */
458 : 0 : void dwc_otg_adp_start(dwc_otg_core_if_t * core_if, uint8_t is_host)
459 : : {
460 : : gpwrdn_data_t gpwrdn;
461 : :
462 : 0 : DWC_PRINTF("ADP Initial Start\n");
463 : 0 : core_if->adp.adp_started = 1;
464 : :
465 : 0 : DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
466 : 0 : dwc_otg_disable_global_interrupts(core_if);
467 [ # # ]: 0 : if (is_host) {
468 : 0 : DWC_PRINTF("HOST MODE\n");
469 : : /* Enable Power Down Logic Interrupt*/
470 : 0 : gpwrdn.d32 = 0;
471 : 0 : gpwrdn.b.pmuintsel = 1;
472 : 0 : gpwrdn.b.pmuactv = 1;
473 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
474 : : /* Initialize first ADP probe to obtain Ramp Time value */
475 : 0 : core_if->adp.initial_probe = 1;
476 : 0 : dwc_otg_adp_probe_start(core_if);
477 : : } else {
478 : : gotgctl_data_t gotgctl;
479 : 0 : gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
480 : 0 : DWC_PRINTF("DEVICE MODE\n");
481 [ # # ]: 0 : if (gotgctl.b.bsesvld == 0) {
482 : : /* Enable Power Down Logic Interrupt*/
483 : 0 : gpwrdn.d32 = 0;
484 : 0 : DWC_PRINTF("VBUS is not valid - start ADP probe\n");
485 : 0 : gpwrdn.b.pmuintsel = 1;
486 : 0 : gpwrdn.b.pmuactv = 1;
487 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0, gpwrdn.d32);
488 : 0 : core_if->adp.initial_probe = 1;
489 : 0 : dwc_otg_adp_probe_start(core_if);
490 : : } else {
491 : 0 : DWC_PRINTF("VBUS is valid - initialize core as a Device\n");
492 : 0 : core_if->op_state = B_PERIPHERAL;
493 : 0 : dwc_otg_core_init(core_if);
494 : 0 : dwc_otg_enable_global_interrupts(core_if);
495 : : cil_pcd_start(core_if);
496 : 0 : dwc_otg_dump_global_registers(core_if);
497 : 0 : dwc_otg_dump_dev_registers(core_if);
498 : : }
499 : : }
500 : 0 : }
501 : :
502 : 207 : void dwc_otg_adp_init(dwc_otg_core_if_t * core_if)
503 : : {
504 : 207 : core_if->adp.adp_started = 0;
505 : 207 : core_if->adp.initial_probe = 0;
506 : 207 : core_if->adp.probe_timer_values[0] = -1;
507 : 207 : core_if->adp.probe_timer_values[1] = -1;
508 : 207 : core_if->adp.probe_enabled = 0;
509 : 207 : core_if->adp.sense_enabled = 0;
510 : 207 : core_if->adp.sense_timer_started = 0;
511 : 207 : core_if->adp.vbuson_timer_started = 0;
512 : 207 : core_if->adp.probe_counter = 0;
513 : 207 : core_if->adp.gpwrdn = 0;
514 : 207 : core_if->adp.attached = DWC_OTG_ADP_UNKOWN;
515 : : /* Initialize timers */
516 : 207 : core_if->adp.sense_timer =
517 : 207 : DWC_TIMER_ALLOC("ADP SENSE TIMER", adp_sense_timeout, core_if);
518 : 207 : core_if->adp.vbuson_timer =
519 : 207 : DWC_TIMER_ALLOC("ADP VBUS ON TIMER", adp_vbuson_timeout, core_if);
520 [ + - - + ]: 207 : if (!core_if->adp.sense_timer || !core_if->adp.vbuson_timer)
521 : : {
522 : 0 : DWC_ERROR("Could not allocate memory for ADP timers\n");
523 : : }
524 : 207 : }
525 : :
526 : 0 : void dwc_otg_adp_remove(dwc_otg_core_if_t * core_if)
527 : : {
528 : 0 : gpwrdn_data_t gpwrdn = { .d32 = 0 };
529 : 0 : gpwrdn.b.pmuintsel = 1;
530 : 0 : gpwrdn.b.pmuactv = 1;
531 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
532 : :
533 [ # # ]: 0 : if (core_if->adp.probe_enabled)
534 : 0 : dwc_otg_adp_probe_stop(core_if);
535 [ # # ]: 0 : if (core_if->adp.sense_enabled)
536 : 0 : dwc_otg_adp_sense_stop(core_if);
537 [ # # ]: 0 : if (core_if->adp.sense_timer_started)
538 : 0 : DWC_TIMER_CANCEL(core_if->adp.sense_timer);
539 [ # # ]: 0 : if (core_if->adp.vbuson_timer_started)
540 : 0 : DWC_TIMER_CANCEL(core_if->adp.vbuson_timer);
541 : 0 : DWC_TIMER_FREE(core_if->adp.sense_timer);
542 : 0 : DWC_TIMER_FREE(core_if->adp.vbuson_timer);
543 : 0 : }
544 : :
545 : : /////////////////////////////////////////////////////////////////////
546 : : ////////////// ADP Interrupt Handlers ///////////////////////////////
547 : : /////////////////////////////////////////////////////////////////////
548 : : /**
549 : : * This function sets Ramp Timer values
550 : : */
551 : : static uint32_t set_timer_value(dwc_otg_core_if_t * core_if, uint32_t val)
552 : : {
553 [ # # # # ]: 0 : if (core_if->adp.probe_timer_values[0] == -1) {
554 : 0 : core_if->adp.probe_timer_values[0] = val;
555 : 0 : core_if->adp.probe_timer_values[1] = -1;
556 : : return 1;
557 : : } else {
558 : 0 : core_if->adp.probe_timer_values[1] =
559 : : core_if->adp.probe_timer_values[0];
560 : 0 : core_if->adp.probe_timer_values[0] = val;
561 : : return 0;
562 : : }
563 : : }
564 : :
565 : : /**
566 : : * This function compares Ramp Timer values
567 : : */
568 : : static uint32_t compare_timer_values(dwc_otg_core_if_t * core_if)
569 : : {
570 : : uint32_t diff;
571 [ # # ]: 0 : if (core_if->adp.probe_timer_values[0]>=core_if->adp.probe_timer_values[1])
572 : 0 : diff = core_if->adp.probe_timer_values[0]-core_if->adp.probe_timer_values[1];
573 : : else
574 : 0 : diff = core_if->adp.probe_timer_values[1]-core_if->adp.probe_timer_values[0];
575 [ # # ]: 0 : if(diff < 2) {
576 : : return 0;
577 : : } else {
578 : : return 1;
579 : : }
580 : : }
581 : :
582 : : /**
583 : : * This function handles ADP Probe Interrupts
584 : : */
585 : 0 : static int32_t dwc_otg_adp_handle_prb_intr(dwc_otg_core_if_t * core_if,
586 : : uint32_t val)
587 : : {
588 : : adpctl_data_t adpctl = {.d32 = 0 };
589 : : gpwrdn_data_t gpwrdn, temp;
590 : 0 : adpctl.d32 = val;
591 : :
592 : 0 : temp.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
593 : 0 : core_if->adp.probe_counter++;
594 : 0 : core_if->adp.gpwrdn = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
595 [ # # # # ]: 0 : if (adpctl.b.rtim == 0 && !temp.b.idsts){
596 : 0 : DWC_PRINTF("RTIM value is 0\n");
597 : 0 : goto exit;
598 : : }
599 [ # # # # ]: 0 : if (set_timer_value(core_if, adpctl.b.rtim) &&
600 : 0 : core_if->adp.initial_probe) {
601 : 0 : core_if->adp.initial_probe = 0;
602 : 0 : dwc_otg_adp_probe_stop(core_if);
603 : 0 : gpwrdn.d32 = 0;
604 : 0 : gpwrdn.b.pmuactv = 1;
605 : 0 : gpwrdn.b.pmuintsel = 1;
606 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
607 : 0 : DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, 0xFFFFFFFF);
608 : :
609 : : /* check which value is for device mode and which for Host mode */
610 [ # # ]: 0 : if (!temp.b.idsts) { /* considered host mode value is 0 */
611 : : /*
612 : : * Turn on VBUS after initial ADP probe.
613 : : */
614 : 0 : core_if->op_state = A_HOST;
615 : 0 : dwc_otg_enable_global_interrupts(core_if);
616 : 0 : DWC_SPINUNLOCK(core_if->lock);
617 : : cil_hcd_start(core_if);
618 : 0 : dwc_otg_adp_turnon_vbus(core_if);
619 : 0 : DWC_SPINLOCK(core_if->lock);
620 : : } else {
621 : : /*
622 : : * Initiate SRP after initial ADP probe.
623 : : */
624 : 0 : dwc_otg_enable_global_interrupts(core_if);
625 : 0 : dwc_otg_initiate_srp(core_if);
626 : : }
627 [ # # ]: 0 : } else if (core_if->adp.probe_counter > 2){
628 : 0 : gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
629 [ # # ]: 0 : if (compare_timer_values(core_if)) {
630 : 0 : DWC_PRINTF("Difference in timer values !!! \n");
631 : : // core_if->adp.attached = DWC_OTG_ADP_ATTACHED;
632 : 0 : dwc_otg_adp_probe_stop(core_if);
633 : :
634 : : /* Power on the core */
635 [ # # ]: 0 : if (core_if->power_down == 2) {
636 : 0 : gpwrdn.b.pwrdnswtch = 1;
637 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
638 : : gpwrdn, 0, gpwrdn.d32);
639 : : }
640 : :
641 : : /* check which value is for device mode and which for Host mode */
642 [ # # ]: 0 : if (!temp.b.idsts) { /* considered host mode value is 0 */
643 : : /* Disable Interrupt from Power Down Logic */
644 : 0 : gpwrdn.d32 = 0;
645 : 0 : gpwrdn.b.pmuintsel = 1;
646 : 0 : gpwrdn.b.pmuactv = 1;
647 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
648 : : gpwrdn, gpwrdn.d32, 0);
649 : :
650 : : /*
651 : : * Initialize the Core for Host mode.
652 : : */
653 : 0 : core_if->op_state = A_HOST;
654 : 0 : dwc_otg_core_init(core_if);
655 : 0 : dwc_otg_enable_global_interrupts(core_if);
656 : : cil_hcd_start(core_if);
657 : : } else {
658 : : gotgctl_data_t gotgctl;
659 : : /* Mask SRP detected interrupt from Power Down Logic */
660 : 0 : gpwrdn.d32 = 0;
661 : 0 : gpwrdn.b.srp_det_msk = 1;
662 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
663 : : gpwrdn, gpwrdn.d32, 0);
664 : :
665 : : /* Disable Power Down Logic */
666 : 0 : gpwrdn.d32 = 0;
667 : 0 : gpwrdn.b.pmuintsel = 1;
668 : 0 : gpwrdn.b.pmuactv = 1;
669 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
670 : : gpwrdn, gpwrdn.d32, 0);
671 : :
672 : : /*
673 : : * Initialize the Core for Device mode.
674 : : */
675 : 0 : core_if->op_state = B_PERIPHERAL;
676 : 0 : dwc_otg_core_init(core_if);
677 : 0 : dwc_otg_enable_global_interrupts(core_if);
678 : : cil_pcd_start(core_if);
679 : :
680 : 0 : gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
681 [ # # ]: 0 : if (!gotgctl.b.bsesvld) {
682 : 0 : dwc_otg_initiate_srp(core_if);
683 : : }
684 : : }
685 : : }
686 [ # # ]: 0 : if (core_if->power_down == 2) {
687 [ # # ]: 0 : if (gpwrdn.b.bsessvld) {
688 : : /* Mask SRP detected interrupt from Power Down Logic */
689 : 0 : gpwrdn.d32 = 0;
690 : 0 : gpwrdn.b.srp_det_msk = 1;
691 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
692 : :
693 : : /* Disable Power Down Logic */
694 : 0 : gpwrdn.d32 = 0;
695 : 0 : gpwrdn.b.pmuactv = 1;
696 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, gpwrdn.d32, 0);
697 : :
698 : : /*
699 : : * Initialize the Core for Device mode.
700 : : */
701 : 0 : core_if->op_state = B_PERIPHERAL;
702 : 0 : dwc_otg_core_init(core_if);
703 : 0 : dwc_otg_enable_global_interrupts(core_if);
704 : : cil_pcd_start(core_if);
705 : : }
706 : : }
707 : : }
708 : : exit:
709 : : /* Clear interrupt */
710 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
711 : 0 : adpctl.b.adp_prb_int = 1;
712 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
713 : :
714 : 0 : return 0;
715 : : }
716 : :
717 : : /**
718 : : * This function hadles ADP Sense Interrupt
719 : : */
720 : 0 : static int32_t dwc_otg_adp_handle_sns_intr(dwc_otg_core_if_t * core_if)
721 : : {
722 : : adpctl_data_t adpctl;
723 : : /* Stop ADP Sense timer */
724 : 0 : DWC_TIMER_CANCEL(core_if->adp.sense_timer);
725 : :
726 : : /* Restart ADP Sense timer */
727 : : dwc_otg_adp_sense_timer_start(core_if);
728 : :
729 : : /* Clear interrupt */
730 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
731 : 0 : adpctl.b.adp_sns_int = 1;
732 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
733 : :
734 : 0 : return 0;
735 : : }
736 : :
737 : : /**
738 : : * This function handles ADP Probe Interrupts
739 : : */
740 : 0 : static int32_t dwc_otg_adp_handle_prb_tmout_intr(dwc_otg_core_if_t * core_if,
741 : : uint32_t val)
742 : : {
743 : : adpctl_data_t adpctl = {.d32 = 0 };
744 : 0 : adpctl.d32 = val;
745 : 0 : set_timer_value(core_if, adpctl.b.rtim);
746 : :
747 : : /* Clear interrupt */
748 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
749 : 0 : adpctl.b.adp_tmout_int = 1;
750 : 0 : dwc_otg_adp_write_reg(core_if, adpctl.d32);
751 : :
752 : 0 : return 0;
753 : : }
754 : :
755 : : /**
756 : : * ADP Interrupt handler.
757 : : *
758 : : */
759 : 0 : int32_t dwc_otg_adp_handle_intr(dwc_otg_core_if_t * core_if)
760 : : {
761 : : int retval = 0;
762 : : adpctl_data_t adpctl = {.d32 = 0};
763 : :
764 : 0 : adpctl.d32 = dwc_otg_adp_read_reg(core_if);
765 : 0 : DWC_PRINTF("ADPCTL = %08x\n",adpctl.d32);
766 : :
767 [ # # ]: 0 : if (adpctl.b.adp_sns_int & adpctl.b.adp_sns_int_msk) {
768 : 0 : DWC_PRINTF("ADP Sense interrupt\n");
769 : 0 : retval |= dwc_otg_adp_handle_sns_intr(core_if);
770 : : }
771 [ # # ]: 0 : if (adpctl.b.adp_tmout_int & adpctl.b.adp_tmout_int_msk) {
772 : 0 : DWC_PRINTF("ADP timeout interrupt\n");
773 : 0 : retval |= dwc_otg_adp_handle_prb_tmout_intr(core_if, adpctl.d32);
774 : : }
775 [ # # ]: 0 : if (adpctl.b.adp_prb_int & adpctl.b.adp_prb_int_msk) {
776 : 0 : DWC_PRINTF("ADP Probe interrupt\n");
777 : 0 : adpctl.b.adp_prb_int = 1;
778 : 0 : retval |= dwc_otg_adp_handle_prb_intr(core_if, adpctl.d32);
779 : : }
780 : :
781 : : // dwc_otg_adp_modify_reg(core_if, adpctl.d32, 0);
782 : : //dwc_otg_adp_write_reg(core_if, adpctl.d32);
783 : 0 : DWC_PRINTF("RETURN FROM ADP ISR\n");
784 : :
785 : 0 : return retval;
786 : : }
787 : :
788 : : /**
789 : : *
790 : : * @param core_if Programming view of DWC_otg controller.
791 : : */
792 : 0 : int32_t dwc_otg_adp_handle_srp_intr(dwc_otg_core_if_t * core_if)
793 : : {
794 : :
795 : : #ifndef DWC_HOST_ONLY
796 : : hprt0_data_t hprt0;
797 : : gpwrdn_data_t gpwrdn;
798 : : DWC_DEBUGPL(DBG_ANY, "++ Power Down Logic Session Request Interrupt++\n");
799 : :
800 : 0 : gpwrdn.d32 = DWC_READ_REG32(&core_if->core_global_regs->gpwrdn);
801 : : /* check which value is for device mode and which for Host mode */
802 [ # # ]: 0 : if (!gpwrdn.b.idsts) { /* considered host mode value is 0 */
803 : 0 : DWC_PRINTF("SRP: Host mode\n");
804 : :
805 [ # # ]: 0 : if (core_if->adp_enable) {
806 : 0 : dwc_otg_adp_probe_stop(core_if);
807 : :
808 : : /* Power on the core */
809 [ # # ]: 0 : if (core_if->power_down == 2) {
810 : 0 : gpwrdn.b.pwrdnswtch = 1;
811 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
812 : : gpwrdn, 0, gpwrdn.d32);
813 : : }
814 : :
815 : 0 : core_if->op_state = A_HOST;
816 : 0 : dwc_otg_core_init(core_if);
817 : 0 : dwc_otg_enable_global_interrupts(core_if);
818 : : cil_hcd_start(core_if);
819 : : }
820 : :
821 : : /* Turn on the port power bit. */
822 : 0 : hprt0.d32 = dwc_otg_read_hprt0(core_if);
823 : 0 : hprt0.b.prtpwr = 1;
824 : 0 : DWC_WRITE_REG32(core_if->host_if->hprt0, hprt0.d32);
825 : :
826 : : /* Start the Connection timer. So a message can be displayed
827 : : * if connect does not occur within 10 seconds. */
828 : : cil_hcd_session_start(core_if);
829 : : } else {
830 : 0 : DWC_PRINTF("SRP: Device mode %s\n", __FUNCTION__);
831 [ # # ]: 0 : if (core_if->adp_enable) {
832 : 0 : dwc_otg_adp_probe_stop(core_if);
833 : :
834 : : /* Power on the core */
835 [ # # ]: 0 : if (core_if->power_down == 2) {
836 : 0 : gpwrdn.b.pwrdnswtch = 1;
837 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->
838 : : gpwrdn, 0, gpwrdn.d32);
839 : : }
840 : :
841 : 0 : gpwrdn.d32 = 0;
842 : 0 : gpwrdn.b.pmuactv = 0;
843 : 0 : DWC_MODIFY_REG32(&core_if->core_global_regs->gpwrdn, 0,
844 : : gpwrdn.d32);
845 : :
846 : 0 : core_if->op_state = B_PERIPHERAL;
847 : 0 : dwc_otg_core_init(core_if);
848 : 0 : dwc_otg_enable_global_interrupts(core_if);
849 : : cil_pcd_start(core_if);
850 : : }
851 : : }
852 : : #endif
853 : 0 : return 1;
854 : : }
|