diff options
Diffstat (limited to 'firmware/target/arm/imx31')
-rw-r--r-- | firmware/target/arm/imx31/debug-imx31.c | 147 | ||||
-rw-r--r-- | firmware/target/arm/imx31/debug-target.h | 1 | ||||
-rw-r--r-- | firmware/target/arm/imx31/dvfs_dptc-imx31.c | 355 | ||||
-rw-r--r-- | firmware/target/arm/imx31/dvfs_dptc-imx31.h | 12 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h | 8 |
5 files changed, 407 insertions, 116 deletions
diff --git a/firmware/target/arm/imx31/debug-imx31.c b/firmware/target/arm/imx31/debug-imx31.c index 1239c7cae7..f8dacbedd5 100644 --- a/firmware/target/arm/imx31/debug-imx31.c +++ b/firmware/target/arm/imx31/debug-imx31.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "adc.h" | 29 | #include "adc.h" |
30 | #include "ccm-imx31.h" | 30 | #include "ccm-imx31.h" |
31 | #include "dvfs_dptc-imx31.h" | 31 | #include "dvfs_dptc-imx31.h" |
32 | #include <stdio.h> | ||
32 | 33 | ||
33 | bool __dbg_hw_info(void) | 34 | bool __dbg_hw_info(void) |
34 | { | 35 | { |
@@ -242,4 +243,148 @@ bool dbg_ports(void) | |||
242 | if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL)) | 243 | if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL)) |
243 | return false; | 244 | return false; |
244 | } | 245 | } |
245 | } | 246 | } |
247 | |||
248 | |||
249 | bool __dbg_dvfs_dptc(void) | ||
250 | { | ||
251 | int ltwlevel; | ||
252 | unsigned long ltdetect; | ||
253 | int dvfs_wp, dvfs_mask; | ||
254 | bool dptc_on; | ||
255 | int i; | ||
256 | char buf[32]; | ||
257 | unsigned long ltw[4]; | ||
258 | bool ltwassert[4]; | ||
259 | |||
260 | lcd_clear_display(); | ||
261 | lcd_setfont(FONT_SYSFIXED); | ||
262 | |||
263 | dvfs_mask = dvfs_level_mask(); | ||
264 | |||
265 | dvfs_wp = dvfs_enabled() ? -1 : (int)dvfs_get_level(); | ||
266 | dptc_on = dptc_enabled(); | ||
267 | dvfs_get_gp_sense(<wlevel, <detect); | ||
268 | |||
269 | while (1) | ||
270 | { | ||
271 | int line = 0; | ||
272 | |||
273 | int button = button_get_w_tmo(HZ/10); | ||
274 | |||
275 | if (dvfs_wp < 0) | ||
276 | strcpy(buf, "Auto"); | ||
277 | else | ||
278 | snprintf(buf, sizeof(buf), "%d", dvfs_wp); | ||
279 | |||
280 | lcd_puts(0, line, "[DVFS/DPTC]"); | ||
281 | line += 2; | ||
282 | lcd_putsf(0, line, "CPU freq. point (Up/Dn) : %s", buf); | ||
283 | line += 2; | ||
284 | lcd_putsf(0, line, "DPTC volt. scale (Play) : %s", | ||
285 | dptc_on ? "Enabled" : "Disabled"); | ||
286 | line += 2; | ||
287 | lcd_putsf(0, line, "GP load level (Vol +/-) : %d", ltwlevel); | ||
288 | line += 2; | ||
289 | lcd_puts(0, line, "----------------------------------------"); | ||
290 | line += 2; | ||
291 | lcd_putsf(0, line++, "Frequency: %dHz", cpu_frequency); | ||
292 | i = dvfs_dptc_get_voltage(); | ||
293 | lcd_putsf(0, line++, "Voltage : %d.%03d V", i / 1000, i % 1000); | ||
294 | |||
295 | for (i = 0; i <= 3; i++) | ||
296 | { | ||
297 | ltw[i] = dvfs_get_lt_weight(i + DVFS_LT_SIG_DVGP0); | ||
298 | ltwassert[i] = dvfs_get_gp_bit(i + DVFS_DVGP_0); | ||
299 | } | ||
300 | |||
301 | lcd_putsf(0, line++, "GPW (3-0): %lu%lu%lu%lu %c%c%c%c", | ||
302 | ltw[3], ltw[2], ltw[1], ltw[0], | ||
303 | ltwassert[3] ? 'y' : 'n', | ||
304 | ltwassert[2] ? 'y' : 'n', | ||
305 | ltwassert[1] ? 'y' : 'n', | ||
306 | ltwassert[0] ? 'y' : 'n'); | ||
307 | |||
308 | line += 2; | ||
309 | lcd_puts(8, line, "(Press SELECT to revert)"); | ||
310 | |||
311 | switch (button) | ||
312 | { | ||
313 | case DEBUG_CANCEL|BUTTON_REL: | ||
314 | return false; | ||
315 | |||
316 | /* CPU frequency */ | ||
317 | case BUTTON_UP: | ||
318 | if (++dvfs_wp >= DVFS_NUM_LEVELS) | ||
319 | { | ||
320 | /* Going back to automatic */ | ||
321 | dvfs_wp = -1; | ||
322 | dvfs_start(); | ||
323 | } | ||
324 | else | ||
325 | { | ||
326 | if (dvfs_wp == 0) | ||
327 | { | ||
328 | /* Going to manual setting */ | ||
329 | dvfs_stop(); | ||
330 | } | ||
331 | |||
332 | /* Skip gaps in mask */ | ||
333 | while (((1 << dvfs_wp) & dvfs_mask) == 0) dvfs_wp++; | ||
334 | dvfs_set_level(dvfs_wp); | ||
335 | } | ||
336 | |||
337 | break; | ||
338 | |||
339 | case BUTTON_DOWN: | ||
340 | if (--dvfs_wp == -1) | ||
341 | { | ||
342 | /* Going back to automatic */ | ||
343 | dvfs_start(); | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | if (dvfs_wp <= -2) | ||
348 | { | ||
349 | /* Going to manual setting */ | ||
350 | dvfs_stop(); | ||
351 | dvfs_wp = DVFS_NUM_LEVELS - 1; | ||
352 | } | ||
353 | |||
354 | /* Skip gaps in mask */ | ||
355 | while (((1 << dvfs_wp) & dvfs_mask) == 0) dvfs_wp--; | ||
356 | dvfs_set_level(dvfs_wp); | ||
357 | } | ||
358 | break; | ||
359 | |||
360 | /* GP Load tracking */ | ||
361 | case BUTTON_VOL_UP: | ||
362 | if (ltwlevel < 28) | ||
363 | dvfs_set_gp_sense(++ltwlevel, ltdetect); | ||
364 | break; | ||
365 | |||
366 | case BUTTON_VOL_DOWN: | ||
367 | if (ltwlevel > 0) | ||
368 | dvfs_set_gp_sense(--ltwlevel, ltdetect); | ||
369 | break; | ||
370 | |||
371 | case BUTTON_PLAY: | ||
372 | dptc_on = !dptc_enabled(); | ||
373 | dptc_on ? dptc_start() : dptc_stop(); | ||
374 | break; | ||
375 | |||
376 | case BUTTON_SELECT: | ||
377 | dvfs_start(); | ||
378 | dptc_start(); | ||
379 | dvfs_set_gp_sense(-1, 0); | ||
380 | |||
381 | dvfs_wp = dvfs_enabled() ? -1 : (int)dvfs_get_level(); | ||
382 | dptc_on = dptc_enabled(); | ||
383 | dvfs_get_gp_sense(<wlevel, <detect); | ||
384 | break; | ||
385 | } | ||
386 | |||
387 | lcd_update(); | ||
388 | yield(); | ||
389 | } | ||
390 | } | ||
diff --git a/firmware/target/arm/imx31/debug-target.h b/firmware/target/arm/imx31/debug-target.h index 06baee5ea0..ca02ab84de 100644 --- a/firmware/target/arm/imx31/debug-target.h +++ b/firmware/target/arm/imx31/debug-target.h | |||
@@ -24,5 +24,6 @@ | |||
24 | #define DEBUG_CANCEL BUTTON_BACK | 24 | #define DEBUG_CANCEL BUTTON_BACK |
25 | bool __dbg_hw_info(void); | 25 | bool __dbg_hw_info(void); |
26 | bool dbg_ports(void); | 26 | bool dbg_ports(void); |
27 | bool __dbg_dvfs_dptc(void); | ||
27 | 28 | ||
28 | #endif /* DEBUG_TARGET_H */ | 29 | #endif /* DEBUG_TARGET_H */ |
diff --git a/firmware/target/arm/imx31/dvfs_dptc-imx31.c b/firmware/target/arm/imx31/dvfs_dptc-imx31.c index 555e030af5..b78a995f87 100644 --- a/firmware/target/arm/imx31/dvfs_dptc-imx31.c +++ b/firmware/target/arm/imx31/dvfs_dptc-imx31.c | |||
@@ -74,8 +74,6 @@ unsigned int dvfs_nr_up = 0; | |||
74 | unsigned int dvfs_nr_pnc = 0; | 74 | unsigned int dvfs_nr_pnc = 0; |
75 | unsigned int dvfs_nr_no = 0; | 75 | unsigned int dvfs_nr_no = 0; |
76 | 76 | ||
77 | static void dvfs_stop(void); | ||
78 | |||
79 | 77 | ||
80 | /* Wait for the UPDTEN flag to be set so that all bits may be written */ | 78 | /* Wait for the UPDTEN flag to be set so that all bits may be written */ |
81 | static inline void wait_for_dvfs_update_en(void) | 79 | static inline void wait_for_dvfs_update_en(void) |
@@ -279,6 +277,9 @@ static void INIT_ATTR dvfs_init(void) | |||
279 | iomuxc_set_pin_mux(IOMUXC_GPIO1_5, | 277 | iomuxc_set_pin_mux(IOMUXC_GPIO1_5, |
280 | IOMUXC_MUX_OUT_FUNCTIONAL | IOMUXC_MUX_IN_FUNCTIONAL); | 278 | IOMUXC_MUX_OUT_FUNCTIONAL | IOMUXC_MUX_IN_FUNCTIONAL); |
281 | #endif | 279 | #endif |
280 | |||
281 | /* GP load bits disabled */ | ||
282 | bitclr32(&CCM_PMCR1, 0xf); | ||
282 | 283 | ||
283 | /* Initialize DVFS signal weights and detection modes. */ | 284 | /* Initialize DVFS signal weights and detection modes. */ |
284 | int i; | 285 | int i; |
@@ -321,66 +322,6 @@ static void INIT_ATTR dvfs_init(void) | |||
321 | logf("DVFS: Initialized"); | 322 | logf("DVFS: Initialized"); |
322 | } | 323 | } |
323 | 324 | ||
324 | |||
325 | /* Start the DVFS hardware */ | ||
326 | static void dvfs_start(void) | ||
327 | { | ||
328 | int oldlevel; | ||
329 | |||
330 | /* Have to wait at least 3 div3 clocks before enabling after being | ||
331 | * stopped. */ | ||
332 | udelay(1500); | ||
333 | |||
334 | oldlevel = disable_irq_save(); | ||
335 | |||
336 | if (!dvfs_running) | ||
337 | { | ||
338 | dvfs_running = true; | ||
339 | |||
340 | /* Unmask DVFS interrupt source and enable DVFS. */ | ||
341 | avic_enable_int(INT_CCM_DVFS, INT_TYPE_IRQ, INT_PRIO_DVFS, | ||
342 | CCM_DVFS_HANDLER); | ||
343 | |||
344 | CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_FSVAIM) | CCM_PMCR0_DVFEN; | ||
345 | } | ||
346 | |||
347 | restore_irq(oldlevel); | ||
348 | |||
349 | logf("DVFS: started"); | ||
350 | } | ||
351 | |||
352 | |||
353 | /* Stop the DVFS hardware and return to default frequency */ | ||
354 | static void dvfs_stop(void) | ||
355 | { | ||
356 | int oldlevel = disable_irq_save(); | ||
357 | |||
358 | if (dvfs_running) | ||
359 | { | ||
360 | /* Mask DVFS interrupts. */ | ||
361 | CCM_PMCR0 |= CCM_PMCR0_FSVAIM | CCM_PMCR0_LBMI; | ||
362 | avic_disable_int(INT_CCM_DVFS); | ||
363 | |||
364 | if (((CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS) != | ||
365 | DVFS_LEVEL_DEFAULT) | ||
366 | { | ||
367 | /* Set default frequency level */ | ||
368 | wait_for_dvfs_update_en(); | ||
369 | do_dvfs_update(DVFS_LEVEL_DEFAULT, false); | ||
370 | wait_for_dvfs_update_en(); | ||
371 | } | ||
372 | |||
373 | /* Disable DVFS. */ | ||
374 | CCM_PMCR0 &= ~CCM_PMCR0_DVFEN; | ||
375 | dvfs_running = false; | ||
376 | } | ||
377 | |||
378 | restore_irq(oldlevel); | ||
379 | |||
380 | logf("DVFS: stopped"); | ||
381 | } | ||
382 | |||
383 | |||
384 | /** DPTC **/ | 325 | /** DPTC **/ |
385 | 326 | ||
386 | /* Request tracking since boot */ | 327 | /* Request tracking since boot */ |
@@ -540,75 +481,87 @@ static void INIT_ATTR dptc_init(void) | |||
540 | } | 481 | } |
541 | 482 | ||
542 | 483 | ||
543 | /* Start DPTC module */ | 484 | /** Main module interface **/ |
544 | static void dptc_start(void) | ||
545 | { | ||
546 | int oldlevel = disable_irq_save(); | ||
547 | 485 | ||
548 | if (!dptc_running) | 486 | /* Initialize DVFS and DPTC */ |
549 | { | 487 | void INIT_ATTR dvfs_dptc_init(void) |
550 | dptc_running = true; | 488 | { |
489 | dptc_init(); | ||
490 | dvfs_init(); | ||
491 | } | ||
551 | 492 | ||
552 | /* Enable DPTC and unmask interrupt. */ | ||
553 | avic_enable_int(INT_CCM_CLK, INT_TYPE_IRQ, INT_PRIO_DPTC, | ||
554 | CCM_CLK_HANDLER); | ||
555 | 493 | ||
556 | update_dptc_counts(dvfs_level, dptc_wp); | 494 | /* Start DVFS and DPTC */ |
557 | enable_dptc(); | 495 | void dvfs_dptc_start(void) |
558 | } | 496 | { |
497 | dvfs_start(); | ||
498 | dptc_start(); | ||
499 | } | ||
559 | 500 | ||
560 | restore_irq(oldlevel); | ||
561 | 501 | ||
562 | logf("DPTC: started"); | 502 | /* Stop DVFS and DPTC */ |
503 | void dvfs_dptc_stop(void) | ||
504 | { | ||
505 | dptc_stop(); | ||
506 | dvfs_stop(); | ||
563 | } | 507 | } |
564 | 508 | ||
565 | 509 | /* Start the DVFS hardware */ | |
566 | /* Stop the DPTC hardware if running and go back to default working point */ | 510 | void dvfs_start(void) |
567 | static void dptc_stop(void) | ||
568 | { | 511 | { |
569 | int oldlevel = disable_irq_save(); | 512 | int oldlevel; |
570 | 513 | ||
571 | if (dptc_running) | 514 | /* Have to wait at least 3 div3 clocks before enabling after being |
515 | * stopped. */ | ||
516 | udelay(1500); | ||
517 | |||
518 | oldlevel = disable_irq_save(); | ||
519 | |||
520 | if (!dvfs_running) | ||
572 | { | 521 | { |
573 | dptc_running = false; | 522 | dvfs_running = true; |
574 | 523 | ||
575 | /* Disable DPTC and mask interrupt. */ | 524 | /* Unmask DVFS interrupt source and enable DVFS. */ |
576 | CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_DPTEN) | CCM_PMCR0_PTVAIM; | 525 | avic_enable_int(INT_CCM_DVFS, INT_TYPE_IRQ, INT_PRIO_DVFS, |
577 | avic_disable_int(INT_CCM_CLK); | 526 | CCM_DVFS_HANDLER); |
578 | 527 | ||
579 | /* Go back to default working point. */ | 528 | CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_FSVAIM) | CCM_PMCR0_DVFEN; |
580 | dptc_new_wp(DPTC_WP_DEFAULT); | ||
581 | } | 529 | } |
582 | 530 | ||
583 | restore_irq(oldlevel); | 531 | restore_irq(oldlevel); |
584 | 532 | ||
585 | logf("DPTC: stopped"); | 533 | logf("DVFS: started"); |
586 | } | 534 | } |
587 | 535 | ||
588 | 536 | ||
589 | /** Main module interface **/ | 537 | /* Stop the DVFS hardware and return to default frequency */ |
590 | 538 | void dvfs_stop(void) | |
591 | /* Initialize DVFS and DPTC */ | ||
592 | void INIT_ATTR dvfs_dptc_init(void) | ||
593 | { | 539 | { |
594 | dptc_init(); | 540 | int oldlevel = disable_irq_save(); |
595 | dvfs_init(); | ||
596 | } | ||
597 | 541 | ||
542 | if (dvfs_running) | ||
543 | { | ||
544 | /* Mask DVFS interrupts. */ | ||
545 | CCM_PMCR0 |= CCM_PMCR0_FSVAIM | CCM_PMCR0_LBMI; | ||
546 | avic_disable_int(INT_CCM_DVFS); | ||
598 | 547 | ||
599 | /* Start DVFS and DPTC */ | 548 | if (((CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS) != |
600 | void dvfs_dptc_start(void) | 549 | DVFS_LEVEL_DEFAULT) |
601 | { | 550 | { |
602 | dvfs_start(); | 551 | /* Set default frequency level */ |
603 | dptc_start(); | 552 | wait_for_dvfs_update_en(); |
604 | } | 553 | do_dvfs_update(DVFS_LEVEL_DEFAULT, false); |
554 | wait_for_dvfs_update_en(); | ||
555 | } | ||
605 | 556 | ||
557 | /* Disable DVFS. */ | ||
558 | CCM_PMCR0 &= ~CCM_PMCR0_DVFEN; | ||
559 | dvfs_running = false; | ||
560 | } | ||
606 | 561 | ||
607 | /* Stop DVFS and DPTC */ | 562 | restore_irq(oldlevel); |
608 | void dvfs_dptc_stop(void) | 563 | |
609 | { | 564 | logf("DVFS: stopped"); |
610 | dptc_stop(); | ||
611 | dvfs_stop(); | ||
612 | } | 565 | } |
613 | 566 | ||
614 | 567 | ||
@@ -648,6 +601,26 @@ void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value) | |||
648 | } | 601 | } |
649 | 602 | ||
650 | 603 | ||
604 | /* Return a signal load tracking weight */ | ||
605 | unsigned long dvfs_get_lt_weight(enum DVFS_LT_SIGS index) | ||
606 | { | ||
607 | volatile unsigned long *reg_p = &CCM_LTR2; | ||
608 | unsigned int shift = 3 * index; | ||
609 | |||
610 | if (index < 9) | ||
611 | { | ||
612 | reg_p = &CCM_LTR3; | ||
613 | shift += 5; /* Bits 7:5, 10:8 ... 31:29 */ | ||
614 | } | ||
615 | else if (index < 16) | ||
616 | { | ||
617 | shift -= 16; /* Bits 13:11, 16:14 ... 31:29 */ | ||
618 | } | ||
619 | |||
620 | return (*reg_p & (0x7 << shift)) >> shift; | ||
621 | } | ||
622 | |||
623 | |||
651 | /* Set a signal load detection mode */ | 624 | /* Set a signal load detection mode */ |
652 | void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge) | 625 | void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge) |
653 | { | 626 | { |
@@ -662,6 +635,21 @@ void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge) | |||
662 | } | 635 | } |
663 | 636 | ||
664 | 637 | ||
638 | /* Returns a signal load detection mode */ | ||
639 | bool dvfs_get_lt_detect(enum DVFS_LT_SIGS index) | ||
640 | { | ||
641 | unsigned int shift = 32; | ||
642 | |||
643 | if ((unsigned)index < 13) | ||
644 | shift = index + 3; | ||
645 | else if ((unsigned)index < 16) | ||
646 | shift = index + 29; | ||
647 | |||
648 | return !!((CCM_LTR0 & (1ul << shift)) >> shift); | ||
649 | } | ||
650 | |||
651 | |||
652 | /* Set/clear the general-purpose load tracking bit */ | ||
665 | void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert) | 653 | void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert) |
666 | { | 654 | { |
667 | if ((unsigned)dvgp <= 3) | 655 | if ((unsigned)dvgp <= 3) |
@@ -672,6 +660,82 @@ void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert) | |||
672 | } | 660 | } |
673 | 661 | ||
674 | 662 | ||
663 | /* Return the general-purpose load tracking bit */ | ||
664 | bool dvfs_get_gp_bit(enum DVFS_DVGPS dvgp) | ||
665 | { | ||
666 | if ((unsigned)dvgp <= 3) | ||
667 | return (CCM_PMCR1 & (1ul << dvgp)) != 0; | ||
668 | return false; | ||
669 | } | ||
670 | |||
671 | |||
672 | /* Set GP load tracking by code. | ||
673 | * level_code: | ||
674 | * lt 0 =defaults | ||
675 | * 0 =all off -> | ||
676 | * 28 =highest load | ||
677 | * gte 28=highest load | ||
678 | * detect_mask bits: | ||
679 | * b[3:0]: 1=LTn edge detect, 0=LTn level detect | ||
680 | */ | ||
681 | void dvfs_set_gp_sense(int level_code, unsigned long detect_mask) | ||
682 | { | ||
683 | int i; | ||
684 | |||
685 | for (i = 0; i <= 3; i++) | ||
686 | { | ||
687 | int ltsig_num = DVFS_LT_SIG_DVGP0 + i; | ||
688 | int gpw_num = DVFS_DVGP_0 + i; | ||
689 | unsigned long weight; | ||
690 | bool edge; | ||
691 | bool assert; | ||
692 | |||
693 | if (level_code < 0) | ||
694 | { | ||
695 | /* defaults */ | ||
696 | detect_mask = 0; | ||
697 | assert = 0; | ||
698 | weight = lt_signals[ltsig_num].weight; | ||
699 | edge = lt_signals[ltsig_num].detect != 0; | ||
700 | } | ||
701 | else | ||
702 | { | ||
703 | weight = MIN(level_code, 7); | ||
704 | edge = !!(detect_mask & 1); | ||
705 | assert = weight > 0; | ||
706 | detect_mask >>= 1; | ||
707 | level_code -= 7; | ||
708 | if (level_code < 0) | ||
709 | level_code = 0; | ||
710 | } | ||
711 | |||
712 | dvfs_set_lt_weight(ltsig_num, weight); /* set weight */ | ||
713 | dvfs_set_lt_detect(ltsig_num, edge); /* set detect mode */ | ||
714 | dvfs_set_gp_bit(gpw_num, assert); /* set activity */ | ||
715 | } | ||
716 | } | ||
717 | |||
718 | /* Return GP weight settings */ | ||
719 | void dvfs_get_gp_sense(int *level_code, unsigned long *detect_mask) | ||
720 | { | ||
721 | int i; | ||
722 | int code = 0; | ||
723 | unsigned long mask = 0; | ||
724 | |||
725 | for (i = DVFS_LT_SIG_DVGP0; i <= DVFS_LT_SIG_DVGP3; i++) | ||
726 | { | ||
727 | code += dvfs_get_lt_weight(i); | ||
728 | mask = (mask << 1) | (dvfs_get_lt_detect(i) ? 1 : 0); | ||
729 | } | ||
730 | |||
731 | if (level_code) | ||
732 | *level_code = code; | ||
733 | |||
734 | if (detect_mask) | ||
735 | *detect_mask = mask; | ||
736 | } | ||
737 | |||
738 | |||
675 | /* Turn the wait-for-interrupt monitoring on or off */ | 739 | /* Turn the wait-for-interrupt monitoring on or off */ |
676 | void dvfs_wfi_monitor(bool on) | 740 | void dvfs_wfi_monitor(bool on) |
677 | { | 741 | { |
@@ -700,18 +764,80 @@ unsigned int dvfs_get_level(void) | |||
700 | } | 764 | } |
701 | 765 | ||
702 | 766 | ||
767 | /* Is DVFS enabled? */ | ||
768 | bool dvfs_enabled(void) | ||
769 | { | ||
770 | return dvfs_running; | ||
771 | } | ||
772 | |||
773 | |||
774 | /* Get bitmask of levels supported */ | ||
775 | unsigned int dvfs_level_mask(void) | ||
776 | { | ||
777 | return DVFS_LEVEL_MASK; | ||
778 | } | ||
779 | |||
780 | |||
703 | /* If DVFS is disabled, set the level explicitly */ | 781 | /* If DVFS is disabled, set the level explicitly */ |
704 | void dvfs_set_level(unsigned int level) | 782 | void dvfs_set_level(unsigned int level) |
705 | { | 783 | { |
706 | int oldlevel = disable_irq_save(); | 784 | int oldlevel = disable_irq_save(); |
707 | 785 | ||
708 | unsigned int currlevel = | 786 | if (!dvfs_running && level < DVFS_NUM_LEVELS) |
709 | (CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS; | 787 | { |
788 | unsigned int currlevel = | ||
789 | (CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS; | ||
790 | if (level != currlevel && ((1 << level) & DVFS_LEVEL_MASK)) | ||
791 | set_current_dvfs_level(level); | ||
792 | } | ||
710 | 793 | ||
711 | if (!dvfs_running && level < DVFS_NUM_LEVELS && level != currlevel) | 794 | restore_irq(oldlevel); |
712 | set_current_dvfs_level(level); | 795 | } |
796 | |||
797 | |||
798 | /* Start DPTC module */ | ||
799 | void dptc_start(void) | ||
800 | { | ||
801 | int oldlevel = disable_irq_save(); | ||
802 | |||
803 | if (!dptc_running) | ||
804 | { | ||
805 | dptc_running = true; | ||
806 | |||
807 | /* Enable DPTC and unmask interrupt. */ | ||
808 | avic_enable_int(INT_CCM_CLK, INT_TYPE_IRQ, INT_PRIO_DPTC, | ||
809 | CCM_CLK_HANDLER); | ||
810 | |||
811 | update_dptc_counts(dvfs_level, dptc_wp); | ||
812 | enable_dptc(); | ||
813 | } | ||
713 | 814 | ||
714 | restore_irq(oldlevel); | 815 | restore_irq(oldlevel); |
816 | |||
817 | logf("DPTC: started"); | ||
818 | } | ||
819 | |||
820 | |||
821 | /* Stop the DPTC hardware if running and go back to default working point */ | ||
822 | void dptc_stop(void) | ||
823 | { | ||
824 | int oldlevel = disable_irq_save(); | ||
825 | |||
826 | if (dptc_running) | ||
827 | { | ||
828 | dptc_running = false; | ||
829 | |||
830 | /* Disable DPTC and mask interrupt. */ | ||
831 | CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_DPTEN) | CCM_PMCR0_PTVAIM; | ||
832 | avic_disable_int(INT_CCM_CLK); | ||
833 | |||
834 | /* Go back to default working point. */ | ||
835 | dptc_new_wp(DPTC_WP_DEFAULT); | ||
836 | } | ||
837 | |||
838 | restore_irq(oldlevel); | ||
839 | |||
840 | logf("DPTC: stopped"); | ||
715 | } | 841 | } |
716 | 842 | ||
717 | 843 | ||
@@ -722,6 +848,13 @@ unsigned int dptc_get_wp(void) | |||
722 | } | 848 | } |
723 | 849 | ||
724 | 850 | ||
851 | /* Is DPTC enabled? */ | ||
852 | bool dptc_enabled(void) | ||
853 | { | ||
854 | return dptc_running; | ||
855 | } | ||
856 | |||
857 | |||
725 | /* If DPTC is not running, set the working point explicitly */ | 858 | /* If DPTC is not running, set the working point explicitly */ |
726 | void dptc_set_wp(unsigned int wp) | 859 | void dptc_set_wp(unsigned int wp) |
727 | { | 860 | { |
diff --git a/firmware/target/arm/imx31/dvfs_dptc-imx31.h b/firmware/target/arm/imx31/dvfs_dptc-imx31.h index 6b59bffae6..1f3f1ab20d 100644 --- a/firmware/target/arm/imx31/dvfs_dptc-imx31.h +++ b/firmware/target/arm/imx31/dvfs_dptc-imx31.h | |||
@@ -124,16 +124,28 @@ void dvfs_dptc_init(void); | |||
124 | void dvfs_dptc_start(void); | 124 | void dvfs_dptc_start(void); |
125 | void dvfs_dptc_stop(void); | 125 | void dvfs_dptc_stop(void); |
126 | 126 | ||
127 | void dvfs_start(void); | ||
128 | void dvfs_stop(void); | ||
129 | bool dvfs_enabled(void); | ||
127 | void dvfs_wfi_monitor(bool on); | 130 | void dvfs_wfi_monitor(bool on); |
128 | void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value); | 131 | void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value); |
132 | unsigned long dvfs_get_lt_weight(enum DVFS_LT_SIGS index); | ||
129 | void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge); | 133 | void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge); |
134 | bool dvfs_get_lt_detect(enum DVFS_LT_SIGS index); | ||
130 | void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert); | 135 | void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert); |
136 | bool dvfs_get_gp_bit(enum DVFS_DVGPS dvgp); | ||
131 | void dvfs_int_mask(bool mask); | 137 | void dvfs_int_mask(bool mask); |
138 | void dvfs_set_gp_sense(int level_code, unsigned long detect_mask); | ||
139 | void dvfs_get_gp_sense(int *level_code, unsigned long *detect_mask); | ||
140 | unsigned int dvfs_level_mask(void); | ||
132 | 141 | ||
133 | unsigned int dvfs_dptc_get_voltage(void); | 142 | unsigned int dvfs_dptc_get_voltage(void); |
134 | unsigned int dvfs_get_level(void); | 143 | unsigned int dvfs_get_level(void); |
135 | void dvfs_set_level(unsigned int level); | 144 | void dvfs_set_level(unsigned int level); |
136 | 145 | ||
146 | void dptc_start(void); | ||
147 | void dptc_stop(void); | ||
148 | bool dptc_enabled(void); | ||
137 | unsigned int dptc_get_wp(void); | 149 | unsigned int dptc_get_wp(void); |
138 | void dptc_set_wp(unsigned int wp); | 150 | void dptc_set_wp(unsigned int wp); |
139 | 151 | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h b/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h index 89edf09675..f81ef83ac7 100644 --- a/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h | |||
@@ -241,10 +241,10 @@ static const struct dvfs_lt_signal_descriptor lt_signals[16] = | |||
241 | { 0, 0 }, /* DVFS_LT_SIG_ARM11_P_FIQ_B_RBT_GATE */ | 241 | { 0, 0 }, /* DVFS_LT_SIG_ARM11_P_FIQ_B_RBT_GATE */ |
242 | { 0, 0 }, /* DVFS_LT_SIG_IPI_GPIO1_INT0 */ | 242 | { 0, 0 }, /* DVFS_LT_SIG_IPI_GPIO1_INT0 */ |
243 | { 0, 0 }, /* DVFS_LT_SIG_IPI_INT_IPU_FUNC */ | 243 | { 0, 0 }, /* DVFS_LT_SIG_IPI_INT_IPU_FUNC */ |
244 | { 7, 0 }, /* DVFS_LT_SIG_DVGP0 */ | 244 | { 0, 0 }, /* DVFS_LT_SIG_DVGP0 */ |
245 | { 7, 0 }, /* DVFS_LT_SIG_DVGP1 */ | 245 | { 0, 0 }, /* DVFS_LT_SIG_DVGP1 */ |
246 | { 7, 0 }, /* DVFS_LT_SIG_DVGP2 */ | 246 | { 0, 0 }, /* DVFS_LT_SIG_DVGP2 */ |
247 | { 7, 0 }, /* DVFS_LT_SIG_DVGP3 */ | 247 | { 0, 0 }, /* DVFS_LT_SIG_DVGP3 */ |
248 | }; | 248 | }; |
249 | 249 | ||
250 | #endif /* _DVFS_DPTC_TARGET_H_ */ | 250 | #endif /* _DVFS_DPTC_TARGET_H_ */ |