Commit 404fd02e96d33840f58f83f88815e2a259cdc532
1 parent
53118db42d
Exists in
smarc-imx-l5.0.0_1.0.0-ga
ENGR00326277-1: imx6: ldo_bypass: fix VDDARM voltage setting violate datasheet
Current only set VDDARM_IN@1.175V/VDDSOC_IN@1.175V before ldo bypass switch. So untile ldo bypass switch happened, these voltage setting is set in ldo-enable mode. But in datasheet, we need 1.15V + 125mV = 1.275V for VDDARM_IN. We need to downgrade cpufreq to 400Mhz and restore after ldo bypass mode switch. Signed-off-by: Robin Gong <b38343@freescale.com>
Showing 4 changed files with 145 additions and 11 deletions Side-by-side Diff
arch/arm/cpu/armv7/mx6/soc.c
... | ... | @@ -835,15 +835,58 @@ |
835 | 835 | return result; |
836 | 836 | } |
837 | 837 | |
838 | -void set_anatop_bypass(void) | |
838 | +static int arm_orig_podf; | |
839 | +void set_arm_freq_400M(bool is_400M) | |
839 | 840 | { |
841 | + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; | |
842 | + | |
843 | + if (is_400M) | |
844 | + writel(0x1, &mxc_ccm->cacrr); | |
845 | + else | |
846 | + writel(arm_orig_podf, &mxc_ccm->cacrr); | |
847 | +} | |
848 | + | |
849 | +void prep_anatop_bypass(void) | |
850 | +{ | |
851 | + struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; | |
852 | + | |
853 | + arm_orig_podf = readl(&mxc_ccm->cacrr); | |
854 | + /* | |
855 | + * Downgrade ARM speed to 400Mhz as half of boot 800Mhz before ldo | |
856 | + * bypassed, also downgrade internal vddarm ldo to 0.975V. | |
857 | + * VDDARM_IN 0.975V + 125mV = 1.1V < Max(1.3V) | |
858 | + * otherwise at 800Mhz(i.mx6dl): | |
859 | + * VDDARM_IN 1.175V + 125mV = 1.3V = Max(1.3V) | |
860 | + * We need provide enough gap in this case. | |
861 | + * skip if boot from 400M. | |
862 | + */ | |
863 | + if (!arm_orig_podf) | |
864 | + set_arm_freq_400M(true); | |
865 | +#ifndef CONFIG_MX6DL | |
866 | + set_ldo_voltage(LDO_ARM, 975); | |
867 | +#else | |
868 | + set_ldo_voltage(LDO_ARM, 1150); | |
869 | +#endif | |
870 | +} | |
871 | + | |
872 | +int set_anatop_bypass(void) | |
873 | +{ | |
840 | 874 | struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; |
841 | 875 | u32 reg = readl(&anatop->reg_core); |
842 | 876 | |
843 | 877 | /* bypass VDDARM/VDDSOC */ |
844 | 878 | reg = reg | (0x1F << 18) | 0x1F; |
845 | 879 | writel(reg, &anatop->reg_core); |
880 | + | |
881 | + return arm_orig_podf; | |
846 | 882 | } |
883 | + | |
884 | +void finish_anatop_bypass(void) | |
885 | +{ | |
886 | + if (!arm_orig_podf) | |
887 | + set_arm_freq_400M(false); | |
888 | +} | |
889 | + | |
847 | 890 | #endif |
848 | 891 | |
849 | 892 | #ifdef CONFIG_IMX_HDMI |
arch/arm/include/asm/arch-mx6/sys_proto.h
... | ... | @@ -26,8 +26,10 @@ |
26 | 26 | #ifdef CONFIG_LDO_BYPASS_CHECK |
27 | 27 | int check_ldo_bypass(void); |
28 | 28 | int check_1_2G(void); |
29 | -void set_anatop_bypass(void); | |
29 | +int set_anatop_bypass(void); | |
30 | 30 | void ldo_mode_set(int ldo_bypass); |
31 | +void prep_anatop_bypass(void); | |
32 | +void finish_anatop_bypass(void); | |
31 | 33 | #endif |
32 | 34 | |
33 | 35 | #ifdef CONFIG_MX6SX |
board/freescale/mx6sabresd/mx6sabresd.c
... | ... | @@ -387,6 +387,9 @@ |
387 | 387 | void ldo_mode_set(int ldo_bypass) |
388 | 388 | { |
389 | 389 | unsigned char value; |
390 | + int is_400M; | |
391 | + unsigned char vddarm; | |
392 | + | |
390 | 393 | /* increase VDDARM/VDDSOC to support 1.2G chip */ |
391 | 394 | if (check_1_2G()) { |
392 | 395 | ldo_bypass = 0; /* ldo_enable on 1.2G chip */ |
393 | 396 | |
394 | 397 | |
395 | 398 | |
396 | 399 | |
... | ... | @@ -416,30 +419,80 @@ |
416 | 419 | } |
417 | 420 | /* switch to ldo_bypass mode , boot on 800Mhz */ |
418 | 421 | if (ldo_bypass) { |
419 | - /* decrease VDDARM to 1.175V */ | |
422 | + prep_anatop_bypass(); | |
423 | + | |
424 | + /* decrease VDDARM for 400Mhz DQ:1.1V, DL:1.275V */ | |
420 | 425 | if (i2c_read(0x8, 0x20, 1, &value, 1)) { |
421 | 426 | printf("Read SW1AB error!\n"); |
422 | 427 | return; |
423 | 428 | } |
424 | 429 | value &= ~0x3f; |
425 | - value |= 0x23; | |
430 | +#if defined(CONFIG_MX6DL) | |
431 | + value |= 0x27; | |
432 | +#else | |
433 | + value |= 0x20; | |
434 | +#endif | |
426 | 435 | if (i2c_write(0x8, 0x20, 1, &value, 1)) { |
427 | 436 | printf("Set SW1AB error!\n"); |
428 | 437 | return; |
429 | 438 | } |
430 | - /* increase VDDSOC to 1.175V */ | |
439 | + /* increase VDDSOC to 1.3V */ | |
431 | 440 | if (i2c_read(0x8, 0x2e, 1, &value, 1)) { |
432 | 441 | printf("Read SW1C error!\n"); |
433 | 442 | return; |
434 | 443 | } |
435 | 444 | value &= ~0x3f; |
445 | + value |= 0x28; | |
446 | + if (i2c_write(0x8, 0x2e, 1, &value, 1)) { | |
447 | + printf("Set SW1C error!\n"); | |
448 | + return; | |
449 | + } | |
450 | + | |
451 | + /* | |
452 | + * MX6Q: | |
453 | + * VDDARM:1.15V@800M; VDDSOC:1.175V@800M | |
454 | + * VDDARM:0.975V@400M; VDDSOC:1.175V@400M | |
455 | + * MX6DL: | |
456 | + * VDDARM:1.175V@800M; VDDSOC:1.175V@800M | |
457 | + * VDDARM:1.075V@400M; VDDSOC:1.175V@400M | |
458 | + */ | |
459 | + is_400M = set_anatop_bypass(); | |
460 | + if (is_400M) | |
461 | +#if defined(CONFIG_MX6DL) | |
462 | + vddarm = 0x1f; | |
463 | +#else | |
464 | + vddarm = 0x1b; | |
465 | +#endif | |
466 | + else | |
467 | +#if defined(CONFIG_MX6DL) | |
468 | + vddarm = 0x23; | |
469 | +#else | |
470 | + vddarm = 0x22; | |
471 | +#endif | |
472 | + if (i2c_read(0x8, 0x20, 1, &value, 1)) { | |
473 | + printf("Read SW1AB error!\n"); | |
474 | + return; | |
475 | + } | |
476 | + value &= ~0x3f; | |
477 | + value |= vddarm; | |
478 | + if (i2c_write(0x8, 0x20, 1, &value, 1)) { | |
479 | + printf("Set SW1AB error!\n"); | |
480 | + return; | |
481 | + } | |
482 | + | |
483 | + /* decrease VDDSOC to 1.175V */ | |
484 | + if (i2c_read(0x8, 0x2e, 1, &value, 1)) { | |
485 | + printf("Read SW1C error!\n"); | |
486 | + return; | |
487 | + } | |
488 | + value &= ~0x3f; | |
436 | 489 | value |= 0x23; |
437 | 490 | if (i2c_write(0x8, 0x2e, 1, &value, 1)) { |
438 | 491 | printf("Set SW1C error!\n"); |
439 | 492 | return; |
440 | 493 | } |
441 | 494 | |
442 | - set_anatop_bypass(); | |
495 | + finish_anatop_bypass(); | |
443 | 496 | printf("switch to ldo_bypass mode!\n"); |
444 | 497 | } |
445 | 498 | } |
board/freescale/mx6slevk/mx6slevk.c
... | ... | @@ -758,32 +758,68 @@ |
758 | 758 | void ldo_mode_set(int ldo_bypass) |
759 | 759 | { |
760 | 760 | unsigned char value; |
761 | + int is_400M; | |
762 | + | |
761 | 763 | /* swith to ldo_bypass mode */ |
762 | 764 | if (ldo_bypass) { |
763 | - /* decrease VDDARM to 1.15V */ | |
765 | + prep_anatop_bypass(); | |
766 | + | |
767 | + /* decrease VDDARM to 1.1V */ | |
764 | 768 | if (i2c_read(0x8, 0x20, 1, &value, 1)) { |
765 | 769 | printf("Read SW1AB error!\n"); |
766 | 770 | return; |
767 | 771 | } |
768 | 772 | value &= ~0x3f; |
769 | - value |= 0x22; | |
773 | + value |= 0x20; | |
770 | 774 | if (i2c_write(0x8, 0x20, 1, &value, 1)) { |
771 | 775 | printf("Set SW1AB error!\n"); |
772 | 776 | return; |
773 | 777 | } |
774 | - /* increase VDDSOC to 1.15V */ | |
778 | + /* increase VDDSOC to 1.3V */ | |
775 | 779 | if (i2c_read(0x8, 0x2e, 1, &value, 1)) { |
776 | 780 | printf("Read SW1C error!\n"); |
777 | 781 | return; |
778 | 782 | } |
779 | 783 | value &= ~0x3f; |
780 | - value |= 0x22; | |
784 | + value |= 0x28; | |
781 | 785 | if (i2c_write(0x8, 0x2e, 1, &value, 1)) { |
782 | 786 | printf("Set SW1C error!\n"); |
783 | 787 | return; |
784 | 788 | } |
785 | 789 | |
786 | - set_anatop_bypass(); | |
790 | + is_400M = set_anatop_bypass(); | |
791 | + | |
792 | + /* | |
793 | + * MX6SL: VDDARM:1.175V@800M; VDDSOC:1.175V@800M | |
794 | + * VDDARM:0.975V@400M; VDDSOC:1.175V@400M | |
795 | + */ | |
796 | + if (i2c_read(0x8, 0x20, 1, &value, 1)) { | |
797 | + printf("Read SW1AB error!\n"); | |
798 | + return; | |
799 | + } | |
800 | + value &= ~0x3f; | |
801 | + if (is_400M) | |
802 | + value |= 0x1b; | |
803 | + else | |
804 | + value |= 0x23; | |
805 | + if (i2c_write(0x8, 0x20, 1, &value, 1)) { | |
806 | + printf("Set SW1AB error!\n"); | |
807 | + return; | |
808 | + } | |
809 | + | |
810 | + /* decrease VDDSOC to 1.175V */ | |
811 | + if (i2c_read(0x8, 0x2e, 1, &value, 1)) { | |
812 | + printf("Read SW1C error!\n"); | |
813 | + return; | |
814 | + } | |
815 | + value &= ~0x3f; | |
816 | + value |= 0x23; | |
817 | + if (i2c_write(0x8, 0x2e, 1, &value, 1)) { | |
818 | + printf("Set SW1C error!\n"); | |
819 | + return; | |
820 | + } | |
821 | + | |
822 | + finish_anatop_bypass(); | |
787 | 823 | printf("switch to ldo_bypass mode!\n"); |
788 | 824 | } |
789 | 825 |