diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2010-04-23 15:32:50 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2010-04-23 15:32:50 +0000 |
commit | 11cca264ff57ad0b234bd1cd2c9a2366b967feb7 (patch) | |
tree | 7693e7150d5abc9687966cc248bfbd550d356964 /firmware/target/arm/imx31 | |
parent | 6cee7579dbdc4d41c4df08c9395cf96c952ebab1 (diff) | |
download | rockbox-11cca264ff57ad0b234bd1cd2c9a2366b967feb7.tar.gz rockbox-11cca264ff57ad0b234bd1cd2c9a2366b967feb7.zip |
i.MX31/Gigabeat S: Implement frequency and voltage scaling-- 1.6V for 528MHz, and 1.35V for 264MHz and 132MHz. Keep DPTC overdrive ( > 400MHz) voltage scaling off for now because of uncertainties. Simplify the (working) mess later.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25699 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm/imx31')
-rw-r--r-- | firmware/target/arm/imx31/avic-imx31.c | 7 | ||||
-rw-r--r-- | firmware/target/arm/imx31/avic-imx31.h | 37 | ||||
-rw-r--r-- | firmware/target/arm/imx31/ccm-imx31.c | 62 | ||||
-rw-r--r-- | firmware/target/arm/imx31/ccm-imx31.h | 17 | ||||
-rw-r--r-- | firmware/target/arm/imx31/debug-imx31.c | 33 | ||||
-rw-r--r-- | firmware/target/arm/imx31/dvfs_dptc-imx31.c | 712 | ||||
-rw-r--r-- | firmware/target/arm/imx31/dvfs_dptc-imx31.h | 99 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h | 279 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c | 7 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c | 8 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c | 43 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/system-target.h | 15 | ||||
-rw-r--r-- | firmware/target/arm/imx31/mc13783-imx31.c | 21 | ||||
-rw-r--r-- | firmware/target/arm/imx31/rolo_restart_firmware.S (renamed from firmware/target/arm/imx31/rolo_restart.S) | 10 | ||||
-rw-r--r-- | firmware/target/arm/imx31/sdma-imx31.c | 2 |
15 files changed, 1274 insertions, 78 deletions
diff --git a/firmware/target/arm/imx31/avic-imx31.c b/firmware/target/arm/imx31/avic-imx31.c index 4ba7da4be0..c8bf419bcd 100644 --- a/firmware/target/arm/imx31/avic-imx31.c +++ b/firmware/target/arm/imx31/avic-imx31.c | |||
@@ -128,7 +128,7 @@ void avic_init(void) | |||
128 | : : : "r0"); | 128 | : : : "r0"); |
129 | 129 | ||
130 | /* Enable normal interrupts at all priorities */ | 130 | /* Enable normal interrupts at all priorities */ |
131 | avic->nimask = 0x1f; | 131 | avic->nimask = AVIC_NIL_ENABLE; |
132 | } | 132 | } |
133 | 133 | ||
134 | void avic_set_int_priority(enum IMX31_INT_LIST ints, | 134 | void avic_set_int_priority(enum IMX31_INT_LIST ints, |
@@ -210,3 +210,8 @@ void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype) | |||
210 | 210 | ||
211 | restore_interrupt(oldstatus); | 211 | restore_interrupt(oldstatus); |
212 | } | 212 | } |
213 | |||
214 | void avic_set_ni_level(unsigned int level) | ||
215 | { | ||
216 | AVIC_NIMASK = level > 0x1f ? 0x1f : level; | ||
217 | } | ||
diff --git a/firmware/target/arm/imx31/avic-imx31.h b/firmware/target/arm/imx31/avic-imx31.h index a049713600..ba8f91cc1a 100644 --- a/firmware/target/arm/imx31/avic-imx31.h +++ b/firmware/target/arm/imx31/avic-imx31.h | |||
@@ -172,7 +172,11 @@ struct avic_map | |||
172 | }; | 172 | }; |
173 | }; | 173 | }; |
174 | 174 | ||
175 | /* #define IRQ priorities for different modules (0-15) */ | ||
175 | #define INT_PRIO_DEFAULT 7 | 176 | #define INT_PRIO_DEFAULT 7 |
177 | #define INT_PRIO_DVFS (INT_PRIO_DEFAULT+1) | ||
178 | #define INT_PRIO_DPTC (INT_PRIO_DEFAULT+1) | ||
179 | #define INT_PRIO_SDMA (INT_PRIO_DEFAULT+2) | ||
176 | 180 | ||
177 | enum INT_TYPE | 181 | enum INT_TYPE |
178 | { | 182 | { |
@@ -210,4 +214,37 @@ void avic_set_int_priority(enum IMX31_INT_LIST ints, | |||
210 | void avic_disable_int(enum IMX31_INT_LIST ints); | 214 | void avic_disable_int(enum IMX31_INT_LIST ints); |
211 | void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype); | 215 | void avic_set_int_type(enum IMX31_INT_LIST ints, enum INT_TYPE intstype); |
212 | 216 | ||
217 | #define AVIC_NIL_DISABLE 0xf | ||
218 | #define AVIC_NIL_ENABLE 0x1f | ||
219 | void avic_set_ni_level(unsigned int level); | ||
220 | |||
221 | /* Call a service routine while allowing preemption by interrupts of higher | ||
222 | * priority. r4-r7 must be preserved for epilogue code to restore context. */ | ||
223 | #define AVIC_NESTED_NI_CALL_PROLOGUE() \ | ||
224 | ({ asm volatile ( \ | ||
225 | "sub lr, lr, #4 \n" /* prepare return address */ \ | ||
226 | "stmfd sp!, { r0-r7, r12, lr } \n" /* preserve return context */ \ | ||
227 | "mov r0, #0x68000000 \n" /* AVIC_BASE_ADDR */ \ | ||
228 | "mrs r4, spsr \n" /* save SPSR_irq */ \ | ||
229 | "ldr r5, [r0, #0x04] \n" /* save NIMASK */ \ | ||
230 | "ldr r1, [r0, #0x40] \n" /* load NIVECSR */ \ | ||
231 | "mov r2, sp \n" /* remember IRQ stack to use in call */ \ | ||
232 | "str r1, [r0, #0x04] \n" /* copy NIVECSR to NIMASK */ \ | ||
233 | "cps #0x13 \n" /* switch to SVC mode (+ unmask IRQ) */ \ | ||
234 | "mov r6, sp \n" /* save SP_svc */ \ | ||
235 | "mov r7, lr \n" /* save LR_svc */ \ | ||
236 | "mov sp, r2 \n" /* switch to SP_irq */ \ | ||
237 | ); }) | ||
238 | |||
239 | #define AVIC_NESTED_NI_CALL_EPILOGUE() \ | ||
240 | ({ asm volatile ( \ | ||
241 | "mov sp, r6 \n" /* restore SP_svc */ \ | ||
242 | "mov lr, r7 \n" /* restore LR_svc */ \ | ||
243 | "cps #0x12 \n" /* return to IRQ mode (+ mask IRQ) */ \ | ||
244 | "mov r0, #0x68000000 \n" /* AVIC BASE ADDR */ \ | ||
245 | "msr spsr_cxsf, r4 \n" /* restore SPSR_irq */ \ | ||
246 | "str r5, [r0, #0x04] \n" /* restore NIMASK */ \ | ||
247 | "ldmfd sp!, { r0-r7, r12, pc }^ \n" /* reload context and return */ \ | ||
248 | ); }) | ||
249 | |||
213 | #endif /* AVIC_IMX31_H */ | 250 | #endif /* AVIC_IMX31_H */ |
diff --git a/firmware/target/arm/imx31/ccm-imx31.c b/firmware/target/arm/imx31/ccm-imx31.c index 0d166e5dbf..2cf2080cf1 100644 --- a/firmware/target/arm/imx31/ccm-imx31.c +++ b/firmware/target/arm/imx31/ccm-imx31.c | |||
@@ -24,7 +24,8 @@ | |||
24 | #include "cpu.h" | 24 | #include "cpu.h" |
25 | #include "ccm-imx31.h" | 25 | #include "ccm-imx31.h" |
26 | 26 | ||
27 | unsigned int ccm_get_src_pll(void) | 27 | /* Return the current source pll for MCU */ |
28 | enum IMX31_PLLS ccm_get_src_pll(void) | ||
28 | { | 29 | { |
29 | return (CCM_PMCR0 & 0xC0000000) == 0 ? PLL_SERIAL : PLL_MCU; | 30 | return (CCM_PMCR0 & 0xC0000000) == 0 ? PLL_SERIAL : PLL_MCU; |
30 | } | 31 | } |
@@ -45,8 +46,21 @@ void ccm_module_clock_gating(enum IMX31_CG_LIST cg, enum IMX31_CG_MODES mode) | |||
45 | imx31_regmod32(reg, mode << shift, mask); | 46 | imx31_regmod32(reg, mode << shift, mask); |
46 | } | 47 | } |
47 | 48 | ||
49 | /* Decode PLL output frequency from register value */ | ||
50 | unsigned int ccm_calc_pll_rate(unsigned int infreq, unsigned long regval) | ||
51 | { | ||
52 | uint32_t mfn = regval & 0x3ff; | ||
53 | uint32_t pd = ((regval >> 26) & 0xf) + 1; | ||
54 | uint32_t mfd = ((regval >> 16) & 0x3ff) + 1; | ||
55 | uint32_t mfi = (regval >> 10) & 0xf; | ||
56 | |||
57 | mfi = mfi <= 5 ? 5 : mfi; | ||
58 | |||
59 | return 2ull*infreq*(mfi * mfd + mfn) / (mfd * pd); | ||
60 | } | ||
61 | |||
48 | /* Get the PLL reference clock frequency in HZ */ | 62 | /* Get the PLL reference clock frequency in HZ */ |
49 | unsigned int ccm_get_pll_ref_clk(void) | 63 | unsigned int ccm_get_pll_ref_clk_rate(void) |
50 | { | 64 | { |
51 | if ((CCM_CCMR & (3 << 1)) == (1 << 1)) | 65 | if ((CCM_CCMR & (3 << 1)) == (1 << 1)) |
52 | return CONFIG_CKIL_FREQ * 1024; | 66 | return CONFIG_CKIL_FREQ * 1024; |
@@ -55,41 +69,59 @@ unsigned int ccm_get_pll_ref_clk(void) | |||
55 | } | 69 | } |
56 | 70 | ||
57 | /* Return PLL frequency in HZ */ | 71 | /* Return PLL frequency in HZ */ |
58 | unsigned int ccm_get_pll(enum IMX31_PLLS pll) | 72 | unsigned int ccm_get_pll_rate(enum IMX31_PLLS pll) |
59 | { | 73 | { |
60 | uint32_t infreq = ccm_get_pll_ref_clk(); | 74 | return ccm_calc_pll_rate(ccm_get_pll_ref_clk_rate(), (&CCM_MPCTL)[pll]); |
61 | uint32_t reg = (&CCM_MPCTL)[pll]; | 75 | } |
62 | uint32_t mfn = reg & 0x3ff; | ||
63 | uint32_t pd = ((reg >> 26) & 0xf) + 1; | ||
64 | uint64_t mfd = ((reg >> 16) & 0x3ff) + 1; | ||
65 | uint32_t mfi = (reg >> 10) & 0xf; | ||
66 | 76 | ||
67 | mfi = mfi <= 5 ? 5 : mfi; | 77 | unsigned int ccm_get_mcu_clk(void) |
78 | { | ||
79 | unsigned int pllnum = ccm_get_src_pll(); | ||
80 | unsigned int fpll = ccm_get_pll_rate(pllnum); | ||
81 | unsigned int mcu_podf = (CCM_PDR0 & 0x7) + 1; | ||
68 | 82 | ||
69 | return 2*infreq*(mfi * mfd + mfn) / (mfd * pd); | 83 | return fpll / mcu_podf; |
70 | } | 84 | } |
71 | 85 | ||
72 | unsigned int ccm_get_ipg_clk(void) | 86 | unsigned int ccm_get_ipg_clk(void) |
73 | { | 87 | { |
74 | unsigned int pllnum = ccm_get_src_pll(); | 88 | unsigned int pllnum = ccm_get_src_pll(); |
75 | unsigned int pll = ccm_get_pll(pllnum); | 89 | unsigned int fpll = ccm_get_pll_rate(pllnum); |
76 | uint32_t reg = CCM_PDR0; | 90 | uint32_t reg = CCM_PDR0; |
77 | unsigned int max_pdf = ((reg >> 3) & 0x7) + 1; | 91 | unsigned int max_pdf = ((reg >> 3) & 0x7) + 1; |
78 | unsigned int ipg_pdf = ((reg >> 6) & 0x3) + 1; | 92 | unsigned int ipg_pdf = ((reg >> 6) & 0x3) + 1; |
79 | 93 | ||
80 | return pll / (max_pdf * ipg_pdf); | 94 | return fpll / (max_pdf * ipg_pdf); |
81 | } | 95 | } |
82 | 96 | ||
83 | unsigned int ccm_get_ahb_clk(void) | 97 | unsigned int ccm_get_ahb_clk(void) |
84 | { | 98 | { |
85 | unsigned int pllnum = ccm_get_src_pll(); | 99 | unsigned int pllnum = ccm_get_src_pll(); |
86 | unsigned int pll = ccm_get_pll(pllnum); | 100 | unsigned int fpll = ccm_get_pll_rate(pllnum); |
87 | unsigned int max_pdf = ((CCM_PDR0 >> 3) & 0x7) + 1; | 101 | unsigned int max_pdf = ((CCM_PDR0 >> 3) & 0x7) + 1; |
88 | 102 | ||
89 | return pll / max_pdf; | 103 | return fpll / max_pdf; |
90 | } | 104 | } |
91 | 105 | ||
92 | unsigned int ccm_get_ata_clk(void) | 106 | unsigned int ccm_get_ata_clk(void) |
93 | { | 107 | { |
94 | return ccm_get_ipg_clk(); | 108 | return ccm_get_ipg_clk(); |
95 | } | 109 | } |
110 | |||
111 | /* Write new values to the current PLL and post-dividers */ | ||
112 | void ccm_set_mcupll_and_pdr(unsigned long pllctl, unsigned long pdr) | ||
113 | { | ||
114 | unsigned int pll = ccm_get_src_pll(); | ||
115 | volatile unsigned long *pllreg = &(&CCM_MPCTL)[pll]; | ||
116 | unsigned long fref = ccm_get_pll_ref_clk_rate(); | ||
117 | unsigned long curfreq = ccm_calc_pll_rate(fref, *pllreg); | ||
118 | unsigned long newfreq = ccm_calc_pll_rate(fref, pllctl); | ||
119 | |||
120 | if (newfreq > curfreq) | ||
121 | CCM_PDR0 = pdr; | ||
122 | |||
123 | *pllreg = pllctl; | ||
124 | |||
125 | if (newfreq <= curfreq) | ||
126 | CCM_PDR0 = pdr; | ||
127 | } | ||
diff --git a/firmware/target/arm/imx31/ccm-imx31.h b/firmware/target/arm/imx31/ccm-imx31.h index e95891255d..400f6cad5d 100644 --- a/firmware/target/arm/imx31/ccm-imx31.h +++ b/firmware/target/arm/imx31/ccm-imx31.h | |||
@@ -93,11 +93,21 @@ enum IMX31_PLLS | |||
93 | NUM_PLLS, | 93 | NUM_PLLS, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | |||
97 | /* Return the current source pll for MCU */ | ||
98 | enum IMX31_PLLS ccm_get_src_pll(void); | ||
99 | |||
100 | /* Decode PLL output frequency from register value */ | ||
101 | unsigned int ccm_calc_pll_rate(unsigned int infreq, unsigned long regval); | ||
102 | |||
96 | /* Get the PLL reference clock frequency in HZ */ | 103 | /* Get the PLL reference clock frequency in HZ */ |
97 | unsigned int ccm_get_pll_ref_clk(void); | 104 | unsigned int ccm_get_pll_ref_clk_rate(void); |
98 | 105 | ||
99 | /* Return PLL frequency in HZ */ | 106 | /* Return PLL frequency in HZ */ |
100 | unsigned int ccm_get_pll(enum IMX31_PLLS pll); | 107 | unsigned int ccm_get_pll_rate(enum IMX31_PLLS pll); |
108 | |||
109 | /* Return MCU frequency in HZ */ | ||
110 | unsigned int ccm_get_mcu_clk(void); | ||
101 | 111 | ||
102 | /* Return ipg_clk in HZ */ | 112 | /* Return ipg_clk in HZ */ |
103 | unsigned int ccm_get_ipg_clk(void); | 113 | unsigned int ccm_get_ipg_clk(void); |
@@ -108,4 +118,7 @@ unsigned int ccm_get_ahb_clk(void); | |||
108 | /* Return the ATA frequency in HZ */ | 118 | /* Return the ATA frequency in HZ */ |
109 | unsigned int ccm_get_ata_clk(void); | 119 | unsigned int ccm_get_ata_clk(void); |
110 | 120 | ||
121 | /* Write new values to the current PLL and post-dividers */ | ||
122 | void ccm_set_mcupll_and_pdr(unsigned long pllctl, unsigned long pdr); | ||
123 | |||
111 | #endif /* _CCM_IMX31_H_ */ | 124 | #endif /* _CCM_IMX31_H_ */ |
diff --git a/firmware/target/arm/imx31/debug-imx31.c b/firmware/target/arm/imx31/debug-imx31.c index dc3c293495..d854c9bc36 100644 --- a/firmware/target/arm/imx31/debug-imx31.c +++ b/firmware/target/arm/imx31/debug-imx31.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "mc13783.h" | 29 | #include "mc13783.h" |
30 | #include "adc.h" | 30 | #include "adc.h" |
31 | #include "ccm-imx31.h" | 31 | #include "ccm-imx31.h" |
32 | #include "dvfs_dptc-imx31.h" | ||
32 | 33 | ||
33 | bool __dbg_hw_info(void) | 34 | bool __dbg_hw_info(void) |
34 | { | 35 | { |
@@ -39,6 +40,9 @@ bool __dbg_hw_info(void) | |||
39 | unsigned int freq; | 40 | unsigned int freq; |
40 | uint32_t regval; | 41 | uint32_t regval; |
41 | 42 | ||
43 | extern volatile unsigned int dvfs_nr_dn, dvfs_nr_up, dvfs_nr_pnc; | ||
44 | extern volatile unsigned int dptc_nr_dn, dptc_nr_up, dptc_nr_pnc; | ||
45 | |||
42 | lcd_clear_display(); | 46 | lcd_clear_display(); |
43 | lcd_setfont(FONT_SYSFIXED); | 47 | lcd_setfont(FONT_SYSFIXED); |
44 | 48 | ||
@@ -52,11 +56,11 @@ bool __dbg_hw_info(void) | |||
52 | spctl = CCM_SPCTL; | 56 | spctl = CCM_SPCTL; |
53 | upctl = CCM_UPCTL; | 57 | upctl = CCM_UPCTL; |
54 | 58 | ||
55 | pllref = ccm_get_pll_ref_clk(); | 59 | pllref = ccm_get_pll_ref_clk_rate(); |
56 | 60 | ||
57 | mcu_pllfreq = ccm_get_pll(PLL_MCU); | 61 | mcu_pllfreq = ccm_calc_pll_rate(pllref, mpctl); |
58 | ser_pllfreq = ccm_get_pll(PLL_SERIAL); | 62 | ser_pllfreq = ccm_calc_pll_rate(pllref, spctl); |
59 | usb_pllfreq = ccm_get_pll(PLL_USB); | 63 | usb_pllfreq = ccm_calc_pll_rate(pllref, upctl); |
60 | 64 | ||
61 | lcd_putsf(0, line++, "pll_ref_clk: %u", pllref); | 65 | lcd_putsf(0, line++, "pll_ref_clk: %u", pllref); |
62 | line++; | 66 | line++; |
@@ -107,10 +111,29 @@ bool __dbg_hw_info(void) | |||
107 | 111 | ||
108 | freq = usb_pllfreq / (((CCM_PDR0 >> 16) & 0x1f) + 1); | 112 | freq = usb_pllfreq / (((CCM_PDR0 >> 16) & 0x1f) + 1); |
109 | lcd_putsf(0, line++, " ipg_per_baud: %u", freq); | 113 | lcd_putsf(0, line++, " ipg_per_baud: %u", freq); |
114 | |||
115 | line++; | ||
116 | lcd_putsf(0, line++, "PMCR0: %08lX", CCM_PMCR0); | ||
117 | |||
118 | line++; | ||
119 | lcd_putsf(0, line++, "cpu_frequency: %ld Hz", cpu_frequency); | ||
120 | |||
121 | lcd_putsf(0, line++, "dvfs_level: %u", dvfs_get_level()); | ||
122 | lcd_putsf(0, line++, "dvfs d|u|p: %u %u %u", dvfs_nr_dn, dvfs_nr_up, dvfs_nr_pnc); | ||
123 | regval = dvfs_dptc_get_voltage(); | ||
124 | lcd_putsf(0, line++, "cpu_voltage: %d.%03d V", regval / 1000, | ||
125 | regval % 1000); | ||
126 | |||
127 | lcd_putsf(0, line++, "dptc_wp: %u", dptc_get_wp()); | ||
128 | lcd_putsf(0, line++, "dptc d|u|p: %u %u %u", dptc_nr_dn, dptc_nr_up, dptc_nr_pnc); | ||
129 | lcd_putsf(0, line++, "DVCR0,1: %08lX %08lX", CCM_DCVR0, CCM_DCVR1); | ||
130 | lcd_putsf(0, line++, "DVCR2,3: %08lX %08lX", CCM_DCVR2, CCM_DCVR3); | ||
131 | lcd_putsf(0, line++, "SWITCHERS0: %08lX", mc13783_read(MC13783_SWITCHERS0)); | ||
132 | lcd_putsf(0, line++, "SWITCHERS1: %08lX", mc13783_read(MC13783_SWITCHERS1)); | ||
110 | 133 | ||
111 | lcd_update(); | 134 | lcd_update(); |
112 | 135 | ||
113 | if (button_get(true) == (DEBUG_CANCEL|BUTTON_REL)) | 136 | if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL)) |
114 | return false; | 137 | return false; |
115 | } | 138 | } |
116 | } | 139 | } |
diff --git a/firmware/target/arm/imx31/dvfs_dptc-imx31.c b/firmware/target/arm/imx31/dvfs_dptc-imx31.c index 8f32fd0fba..6e177ba6bd 100644 --- a/firmware/target/arm/imx31/dvfs_dptc-imx31.c +++ b/firmware/target/arm/imx31/dvfs_dptc-imx31.c | |||
@@ -22,27 +22,721 @@ | |||
22 | ****************************************************************************/ | 22 | ****************************************************************************/ |
23 | #include "config.h" | 23 | #include "config.h" |
24 | #include "system.h" | 24 | #include "system.h" |
25 | #include "ccm-imx31.h" | 25 | #include "logf.h" |
26 | #include "mc13783.h" | 26 | #include "mc13783.h" |
27 | #include "iomuxc-imx31.h" | ||
28 | #include "ccm-imx31.h" | ||
29 | #include "avic-imx31.h" | ||
30 | #include "dvfs_dptc-imx31.h" | ||
31 | #include "dvfs_dptc_tables-target.h" | ||
27 | 32 | ||
28 | /* Most of the code in here is based upon the Linux BSP provided by Freescale | 33 | /* Most of the code in here is based upon the Linux BSP provided by Freescale |
29 | * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. */ | 34 | * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved. */ |
30 | 35 | ||
31 | void dvfs_dptc_start(void) | 36 | /* The current DVFS index level */ |
37 | static volatile unsigned int dvfs_level = DVFS_LEVEL_DEFAULT; | ||
38 | /* The current DPTC working point */ | ||
39 | static volatile unsigned int dptc_wp = DPTC_WP_DEFAULT; | ||
40 | |||
41 | |||
42 | static void update_dptc_counts(unsigned int level, unsigned int wp) | ||
43 | { | ||
44 | int oldlevel = disable_irq_save(); | ||
45 | const struct dptc_dcvr_table_entry *entry = &dptc_dcvr_table[level][wp]; | ||
46 | |||
47 | CCM_DCVR0 = entry->dcvr0; | ||
48 | CCM_DCVR1 = entry->dcvr1; | ||
49 | CCM_DCVR2 = entry->dcvr2; | ||
50 | CCM_DCVR3 = entry->dcvr3; | ||
51 | |||
52 | restore_irq(oldlevel); | ||
53 | } | ||
54 | |||
55 | |||
56 | static inline uint32_t check_regulator_setting(uint32_t setting) | ||
57 | { | ||
58 | /* Simply a safety check *in case* table gets scrambled */ | ||
59 | if (setting < VOLTAGE_SETTING_MIN) | ||
60 | setting = VOLTAGE_SETTING_MIN; | ||
61 | else if (setting > VOLTAGE_SETTING_MAX) | ||
62 | setting = VOLTAGE_SETTING_MAX; | ||
63 | |||
64 | return setting; | ||
65 | } | ||
66 | |||
67 | |||
68 | /** DVFS **/ | ||
69 | static bool dvfs_running = false; /* Has driver enabled DVFS? */ | ||
70 | |||
71 | /* Request tracking since boot */ | ||
72 | unsigned int dvfs_nr_dn = 0; | ||
73 | unsigned int dvfs_nr_up = 0; | ||
74 | unsigned int dvfs_nr_pnc = 0; | ||
75 | |||
76 | static void dvfs_stop(void); | ||
77 | |||
78 | |||
79 | /* Wait for the UPDTEN flag to be set so that all bits may be written */ | ||
80 | static inline void wait_for_dvfs_update_en(void) | ||
81 | { | ||
82 | while (!(CCM_PMCR0 & CCM_PMCR0_UPDTEN)); | ||
83 | } | ||
84 | |||
85 | |||
86 | static void do_dvfs_update(unsigned int level) | ||
87 | { | ||
88 | const struct dvfs_clock_table_entry *setting = &dvfs_clock_table[level]; | ||
89 | unsigned long pmcr0 = CCM_PMCR0; | ||
90 | |||
91 | if (pmcr0 & CCM_PMCR0_DPTEN) | ||
92 | { | ||
93 | /* Ignore voltage change request from DPTC. Voltage is *not* valid. */ | ||
94 | pmcr0 &= ~CCM_PMCR0_DPVCR; | ||
95 | } | ||
96 | |||
97 | pmcr0 &= ~CCM_PMCR0_VSCNT; | ||
98 | |||
99 | if (level > ((pmcr0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS)) | ||
100 | { | ||
101 | pmcr0 |= CCM_PMCR0_UDSC; /* Up scaling, increase */ | ||
102 | pmcr0 |= setting->vscnt << CCM_PMCR0_VSCNT_POS; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | pmcr0 &= ~CCM_PMCR0_UDSC; /* Down scaling, decrease */ | ||
107 | pmcr0 |= 0x1 << CCM_PMCR0_VSCNT_POS; | ||
108 | } | ||
109 | |||
110 | /* DVSUP (new frequency index) setup */ | ||
111 | pmcr0 = (pmcr0 & ~CCM_PMCR0_DVSUP) | (level << CCM_PMCR0_DVSUP_POS); | ||
112 | |||
113 | dvfs_level = level; | ||
114 | |||
115 | if ((setting->pll_num << CCM_PMCR0_DFSUP_MCUPLL_POS) ^ | ||
116 | (pmcr0 & CCM_PMCR0_DFSUP_MCUPLL)) | ||
117 | { | ||
118 | /* Update pll and post-dividers. */ | ||
119 | pmcr0 ^= CCM_PMCR0_DFSUP_MCUPLL; | ||
120 | pmcr0 &= ~CCM_PMCR0_DFSUP_POST_DIVIDERS; | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | /* Post-dividers update only */ | ||
125 | pmcr0 |= CCM_PMCR0_DFSUP_POST_DIVIDERS; | ||
126 | } | ||
127 | |||
128 | CCM_PMCR0 = pmcr0; | ||
129 | udelay(100); /* Software wait for voltage ramp-up */ | ||
130 | CCM_PDR0 = setting->pdr_val; | ||
131 | |||
132 | if (!(pmcr0 & CCM_PMCR0_DFSUP_POST_DIVIDERS)) | ||
133 | { | ||
134 | /* Update the PLL settings */ | ||
135 | if (pmcr0 & CCM_PMCR0_DFSUP_MCUPLL) | ||
136 | CCM_MPCTL = setting->pll_val; | ||
137 | else | ||
138 | CCM_SPCTL = setting->pll_val; | ||
139 | } | ||
140 | |||
141 | cpu_frequency = ccm_get_mcu_clk(); | ||
142 | |||
143 | if (pmcr0 & CCM_PMCR0_DPTEN) | ||
144 | { | ||
145 | update_dptc_counts(level, dptc_wp); | ||
146 | /* Enable DPTC to request voltage changes. Voltage is valid. */ | ||
147 | CCM_PMCR0 |= CCM_PMCR0_DPVCR; | ||
148 | udelay(2); | ||
149 | CCM_PMCR0 |= CCM_PMCR0_DPVV; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | |||
154 | /* Start DVFS, change the set point and stop it */ | ||
155 | static void set_current_dvfs_level(unsigned int level) | ||
156 | { | ||
157 | int oldlevel = disable_irq_save(); | ||
158 | |||
159 | CCM_PMCR0 |= CCM_PMCR0_DVFEN; | ||
160 | |||
161 | wait_for_dvfs_update_en(); | ||
162 | |||
163 | do_dvfs_update(level); | ||
164 | |||
165 | wait_for_dvfs_update_en(); | ||
166 | |||
167 | CCM_PMCR0 &= ~CCM_PMCR0_DVFEN; | ||
168 | |||
169 | restore_irq(oldlevel); | ||
170 | } | ||
171 | |||
172 | |||
173 | /* DVFS Interrupt handler */ | ||
174 | static void __attribute__((used)) dvfs_int(void) | ||
175 | { | ||
176 | unsigned long pmcr0 = CCM_PMCR0; | ||
177 | unsigned long fsvai = pmcr0 & CCM_PMCR0_FSVAI; | ||
178 | unsigned int level = (pmcr0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS; | ||
179 | |||
180 | if (pmcr0 & CCM_PMCR0_FSVAIM) | ||
181 | return; /* Do nothing. DVFS interrupt is masked. */ | ||
182 | |||
183 | if (!(pmcr0 & CCM_PMCR0_UPDTEN)) | ||
184 | return; /* Do nothing. DVFS didn't finish previous flow update. */ | ||
185 | |||
186 | switch (fsvai) | ||
187 | { | ||
188 | case CCM_PMCR0_FSVAI_DECREASE: | ||
189 | if (level >= DVFS_NUM_LEVELS - 1) | ||
190 | return; /* DVFS already at lowest level */ | ||
191 | |||
192 | /* Upon the DECREASE event, the frequency will be changed to the next | ||
193 | * higher state index. */ | ||
194 | level++; | ||
195 | dvfs_nr_dn++; | ||
196 | break; | ||
197 | |||
198 | /* Single-step frequency increase */ | ||
199 | case CCM_PMCR0_FSVAI_INCREASE: | ||
200 | if (level == 0) | ||
201 | return; /* DVFS already at highest level */ | ||
202 | |||
203 | /* Upon the INCREASE event, the frequency will be changed to the next | ||
204 | * lower state index. */ | ||
205 | level--; | ||
206 | dvfs_nr_up++; | ||
207 | break; | ||
208 | |||
209 | /* Right to highest if panic */ | ||
210 | case CCM_PMCR0_FSVAI_INCREASE_NOW: | ||
211 | if (level == 0) | ||
212 | return; /* DVFS already at highest level */ | ||
213 | |||
214 | /* Upon the INCREASE_NOW event, the frequency will be increased to | ||
215 | * the maximum (index 0). */ | ||
216 | level = 0; | ||
217 | dvfs_nr_pnc++; | ||
218 | break; | ||
219 | |||
220 | case CCM_PMCR0_FSVAI_NO_INT: | ||
221 | default: | ||
222 | return; /* Do nothing. Freq change is not required */ | ||
223 | } /* end switch */ | ||
224 | |||
225 | do_dvfs_update(level); | ||
226 | } | ||
227 | |||
228 | |||
229 | /* Interrupt vector for DVFS */ | ||
230 | static __attribute__((naked, interrupt("IRQ"))) void CCM_DVFS_HANDLER(void) | ||
231 | { | ||
232 | /* Audio can glitch with the long udelay if nested IRQ isn't allowed. */ | ||
233 | AVIC_NESTED_NI_CALL_PROLOGUE(); | ||
234 | asm volatile ("bl dvfs_int"); | ||
235 | AVIC_NESTED_NI_CALL_EPILOGUE(); | ||
236 | } | ||
237 | |||
238 | |||
239 | /* Initialize the DVFS hardware */ | ||
240 | static void dvfs_init(void) | ||
241 | { | ||
242 | if (CCM_PMCR0 & CCM_PMCR0_DVFEN) | ||
243 | { | ||
244 | /* Turn it off first. Really, shouldn't happen though. */ | ||
245 | dvfs_running = true; | ||
246 | dvfs_stop(); | ||
247 | } | ||
248 | |||
249 | /* Combine SW1A and SW1B DVS pins for a possible five DVS levels | ||
250 | * per working point. Four, MAXIMUM, are actually used, one for each | ||
251 | * frequency. */ | ||
252 | mc13783_set(MC13783_ARBITRATION_SWITCHERS, MC13783_SW1ABDVS); | ||
253 | |||
254 | /* Set DVS speed to 25mV every 4us. */ | ||
255 | mc13783_write_masked(MC13783_SWITCHERS4, MC13783_SW1ADVSSPEED_4US, | ||
256 | MC13783_SW1ADVSSPEED); | ||
257 | |||
258 | /* Set DVFS pins to functional outputs. Input mode and pad setting is | ||
259 | * fixed in hardware. */ | ||
260 | iomuxc_set_pin_mux(IOMUXC_DVFS0, | ||
261 | IOMUXC_MUX_OUT_FUNCTIONAL | IOMUXC_MUX_IN_NONE); | ||
262 | iomuxc_set_pin_mux(IOMUXC_DVFS1, | ||
263 | IOMUXC_MUX_OUT_FUNCTIONAL | IOMUXC_MUX_IN_NONE); | ||
264 | |||
265 | #ifndef DVFS_NO_PWRRDY | ||
266 | /* Configure PWRRDY signal pin. */ | ||
267 | imx31_regclr32(&GPIO1_GDIR, (1 << 5)); | ||
268 | iomuxc_set_pin_mux(IOMUXC_GPIO1_5, | ||
269 | IOMUXC_MUX_OUT_FUNCTIONAL | IOMUXC_MUX_IN_FUNCTIONAL); | ||
270 | #endif | ||
271 | |||
272 | /* Initialize DVFS signal weights and detection modes. */ | ||
273 | int i; | ||
274 | for (i = 0; i < 16; i++) | ||
275 | { | ||
276 | dvfs_set_lt_weight(i, lt_signals[i].weight); | ||
277 | dvfs_set_lt_detect(i, lt_signals[i].detect); | ||
278 | } | ||
279 | |||
280 | /* Set up LTR0. */ | ||
281 | imx31_regmod32(&CCM_LTR0, | ||
282 | DVFS_UPTHR << CCM_LTR0_UPTHR_POS | | ||
283 | DVFS_DNTHR << CCM_LTR0_DNTHR_POS | | ||
284 | DVFS_DIV3CK, | ||
285 | CCM_LTR0_UPTHR | CCM_LTR0_DNTHR | CCM_LTR0_DIV3CK); | ||
286 | |||
287 | /* Set up LTR1. */ | ||
288 | imx31_regmod32(&CCM_LTR1, | ||
289 | DVFS_DNCNT << CCM_LTR1_DNCNT_POS | | ||
290 | DVFS_UPCNT << CCM_LTR1_UPCNT_POS | | ||
291 | DVFS_PNCTHR << CCM_LTR1_PNCTHR_POS | | ||
292 | CCM_LTR1_LTBRSR, | ||
293 | CCM_LTR1_DNCNT | CCM_LTR1_UPCNT | | ||
294 | CCM_LTR1_PNCTHR | CCM_LTR1_LTBRSR); | ||
295 | |||
296 | /* Set up LTR2-- EMA configuration. */ | ||
297 | imx31_regmod32(&CCM_LTR2, DVFS_EMAC << CCM_LTR2_EMAC_POS, | ||
298 | CCM_LTR2_EMAC); | ||
299 | |||
300 | /* DVFS interrupt goes to MCU. Mask load buffer full interrupt. */ | ||
301 | imx31_regset32(&CCM_PMCR0, CCM_PMCR0_DVFIS | CCM_PMCR0_LBMI); | ||
302 | |||
303 | /* Initialize current core PLL and dividers for default level. Assumes | ||
304 | * clocking scheme has been set up appropriately in other init code. */ | ||
305 | ccm_set_mcupll_and_pdr(dvfs_clock_table[DVFS_LEVEL_DEFAULT].pll_val, | ||
306 | dvfs_clock_table[DVFS_LEVEL_DEFAULT].pdr_val); | ||
307 | |||
308 | /* Set initial level and working point. */ | ||
309 | set_current_dvfs_level(DVFS_LEVEL_DEFAULT); | ||
310 | |||
311 | logf("DVFS: Initialized"); | ||
312 | } | ||
313 | |||
314 | |||
315 | /* Start the DVFS hardware */ | ||
316 | static void dvfs_start(void) | ||
317 | { | ||
318 | int oldlevel; | ||
319 | |||
320 | /* Have to wait at least 3 div3 clocks before enabling after being | ||
321 | * stopped. */ | ||
322 | udelay(1500); | ||
323 | |||
324 | oldlevel = disable_irq_save(); | ||
325 | |||
326 | if (!dvfs_running) | ||
327 | { | ||
328 | dvfs_running = true; | ||
329 | |||
330 | /* Unmask DVFS interrupt source and enable DVFS. */ | ||
331 | avic_enable_int(INT_CCM_DVFS, INT_TYPE_IRQ, INT_PRIO_DVFS, | ||
332 | CCM_DVFS_HANDLER); | ||
333 | |||
334 | CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_FSVAIM) | CCM_PMCR0_DVFEN; | ||
335 | } | ||
336 | |||
337 | restore_irq(oldlevel); | ||
338 | |||
339 | logf("DVFS: started"); | ||
340 | } | ||
341 | |||
342 | |||
343 | /* Stop the DVFS hardware and return to default frequency */ | ||
344 | static void dvfs_stop(void) | ||
32 | { | 345 | { |
33 | /* For now, just set the regulator voltage off of overdrive mode */ | 346 | int oldlevel = disable_irq_save(); |
34 | /* For 264 MHz, DPTC is not needed and lower V can be used */ | 347 | |
348 | if (dvfs_running) | ||
349 | { | ||
350 | /* Mask DVFS interrupts. */ | ||
351 | CCM_PMCR0 |= CCM_PMCR0_FSVAIM | CCM_PMCR0_LBMI; | ||
352 | avic_disable_int(INT_CCM_DVFS); | ||
353 | |||
354 | if (((CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS) != | ||
355 | DVFS_LEVEL_DEFAULT) | ||
356 | { | ||
357 | /* Set default frequency level */ | ||
358 | wait_for_dvfs_update_en(); | ||
359 | do_dvfs_update(DVFS_LEVEL_DEFAULT); | ||
360 | wait_for_dvfs_update_en(); | ||
361 | } | ||
362 | |||
363 | /* Disable DVFS. */ | ||
364 | CCM_PMCR0 &= ~CCM_PMCR0_DVFEN; | ||
365 | dvfs_running = false; | ||
366 | } | ||
367 | |||
368 | restore_irq(oldlevel); | ||
369 | |||
370 | logf("DVFS: stopped"); | ||
371 | } | ||
372 | |||
373 | |||
374 | /** DPTC **/ | ||
375 | |||
376 | /* Request tracking since boot */ | ||
377 | unsigned int dptc_nr_dn = 0; | ||
378 | unsigned int dptc_nr_up = 0; | ||
379 | unsigned int dptc_nr_pnc = 0; | ||
380 | |||
381 | |||
382 | /* Enable DPTC and unmask interrupt. */ | ||
383 | static void enable_dptc(void) | ||
384 | { | ||
385 | int oldlevel = disable_irq_save(); | ||
386 | |||
387 | /* Enable DPTC, assert voltage change request. */ | ||
388 | CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_PTVAIM) | CCM_PMCR0_DPTEN | | ||
389 | CCM_PMCR0_DPVCR; | ||
390 | |||
391 | udelay(2); | ||
392 | |||
393 | /* Set voltage valid *after* setting change request */ | ||
394 | CCM_PMCR0 |= CCM_PMCR0_DPVV; | ||
395 | |||
396 | restore_irq(oldlevel); | ||
397 | } | ||
398 | |||
399 | |||
400 | static void dptc_new_wp(unsigned int wp) | ||
401 | { | ||
402 | unsigned int level = dvfs_level; | ||
403 | const union dvfs_dptc_voltage_table_entry *entry = &dvfs_dptc_voltage_table[wp]; | ||
404 | |||
405 | uint32_t sw1a = check_regulator_setting(entry->sw1a); | ||
406 | uint32_t sw1advs = check_regulator_setting(entry->sw1advs); | ||
407 | uint32_t sw1bdvs = check_regulator_setting(entry->sw1bdvs); | ||
408 | uint32_t sw1bstby = check_regulator_setting(entry->sw1bstby); | ||
409 | |||
410 | dptc_wp = wp; | ||
35 | 411 | ||
36 | mc13783_write_masked(MC13783_SWITCHERS0, | 412 | mc13783_write_masked(MC13783_SWITCHERS0, |
37 | MC13783_SW_1_350 << MC13783_SW1A_POS, | 413 | sw1a << MC13783_SW1A_POS | /* SW1A */ |
38 | MC13783_SW1A); | 414 | sw1advs << MC13783_SW1ADVS_POS, /* SW1ADVS */ |
39 | imx31_regmod32(&CCM_PMCR0, CCM_PMCR0_DVS1_0_DVS0_0, | 415 | MC13783_SW1A | MC13783_SW1ADVS); |
40 | CCM_PMCR0_DVSUP_DVS); | 416 | |
417 | mc13783_write_masked(MC13783_SWITCHERS1, | ||
418 | sw1bdvs << MC13783_SW1BDVS_POS | /* SW1BDVS */ | ||
419 | sw1bstby << MC13783_SW1BSTBY_POS, /* SW1BSTBY */ | ||
420 | MC13783_SW1BDVS | MC13783_SW1BSTBY); | ||
421 | |||
422 | |||
423 | udelay(100); /* Wait to settle */ | ||
424 | |||
425 | update_dptc_counts(level, wp); | ||
426 | } | ||
427 | |||
428 | |||
429 | /* DPTC service thread */ | ||
430 | #ifdef ROCKBOX_HAS_LOGF | ||
431 | #define DPTC_STACK_SIZE DEFAULT_STACK_SIZE | ||
432 | #else | ||
433 | #define DPTC_STACK_SIZE 160 | ||
434 | #endif | ||
435 | static int dptc_thread_stack[DPTC_STACK_SIZE/sizeof(int)]; | ||
436 | static const char * const dptc_thread_name = "dptc"; | ||
437 | static struct wakeup dptc_wakeup; /* Object to signal upon DPTC event */ | ||
438 | static struct mutex dptc_mutex; /* Avoid mutually disrupting voltage updates */ | ||
439 | static unsigned long dptc_int_data; /* Data passed to thread for each event */ | ||
440 | static bool dptc_running = false; /* Has driver enabled DPTC? */ | ||
441 | |||
442 | |||
443 | static void dptc_interrupt_thread(void) | ||
444 | { | ||
445 | int wp; | ||
446 | |||
447 | mutex_lock(&dptc_mutex); | ||
448 | |||
449 | while (1) | ||
450 | { | ||
451 | mutex_unlock(&dptc_mutex); | ||
452 | |||
453 | wakeup_wait(&dptc_wakeup, TIMEOUT_BLOCK); | ||
454 | |||
455 | mutex_lock(&dptc_mutex); | ||
456 | |||
457 | if (!dptc_running) | ||
458 | continue; | ||
459 | |||
460 | wp = dptc_wp; | ||
461 | |||
462 | switch (dptc_int_data & CCM_PMCR0_PTVAI) | ||
463 | { | ||
464 | case CCM_PMCR0_PTVAI_DECREASE: | ||
465 | wp++; | ||
466 | dptc_nr_dn++; | ||
467 | break; | ||
468 | |||
469 | case CCM_PMCR0_PTVAI_INCREASE: | ||
470 | wp--; | ||
471 | dptc_nr_up++; | ||
472 | break; | ||
473 | |||
474 | case CCM_PMCR0_PTVAI_INCREASE_NOW: | ||
475 | wp = DPTC_WP_PANIC; | ||
476 | dptc_nr_pnc++; | ||
477 | break; | ||
478 | |||
479 | case CCM_PMCR0_PTVAI_NO_INT: | ||
480 | logf("DPTC: unexpected INT"); | ||
481 | continue; | ||
482 | } | ||
483 | |||
484 | if (wp < 0) | ||
485 | { | ||
486 | wp = 0; | ||
487 | logf("DPTC: already @ highest (%d)", wp); | ||
488 | } | ||
489 | else if (wp >= DPTC_NUM_WP) | ||
490 | { | ||
491 | wp = DPTC_NUM_WP - 1; | ||
492 | logf("DPTC: already @ lowest (%d)", wp); | ||
493 | } | ||
494 | else | ||
495 | { | ||
496 | logf("DPTC: new wp (%d)", wp); | ||
497 | } | ||
498 | |||
499 | dptc_new_wp(wp); | ||
500 | enable_dptc(); | ||
501 | } | ||
502 | } | ||
503 | |||
504 | |||
505 | /* Interrupt vector for DPTC */ | ||
506 | static __attribute__((interrupt("IRQ"))) void CCM_CLK_HANDLER(void) | ||
507 | { | ||
508 | /* Snapshot the interrupt cause */ | ||
509 | unsigned long pmcr0 = CCM_PMCR0; | ||
510 | dptc_int_data = pmcr0; | ||
511 | |||
512 | /* Mask DPTC interrupt and disable DPTC until the change request is | ||
513 | * serviced. */ | ||
514 | CCM_PMCR0 = (pmcr0 & ~CCM_PMCR0_DPTEN) | CCM_PMCR0_PTVAIM; | ||
515 | |||
516 | wakeup_signal(&dptc_wakeup); | ||
517 | } | ||
518 | |||
519 | |||
520 | /* Initialize the DPTC hardware */ | ||
521 | static void dptc_init(void) | ||
522 | { | ||
523 | /* Force DPTC off if running for some reason. */ | ||
524 | imx31_regmod32(&CCM_PMCR0, CCM_PMCR0_PTVAIM, | ||
525 | CCM_PMCR0_PTVAIM | CCM_PMCR0_DPTEN); | ||
526 | |||
527 | /* Set default, safe working point. */ | ||
528 | dptc_new_wp(DPTC_WP_DEFAULT); | ||
529 | |||
530 | /* Interrupt goes to MCU, specified reference circuits enabled when | ||
531 | * DPTC is active. */ | ||
532 | imx31_regset32(&CCM_PMCR0, CCM_PMCR0_PTVIS | DPTC_DRCE_MASK); | ||
533 | |||
534 | /* DPTC counting range = 256 system clocks */ | ||
535 | imx31_regclr32(&CCM_PMCR0, CCM_PMCR0_DCR); | ||
536 | |||
537 | /* Create PMIC regulator service. */ | ||
538 | wakeup_init(&dptc_wakeup); | ||
539 | mutex_init(&dptc_mutex); | ||
540 | create_thread(dptc_interrupt_thread, | ||
541 | dptc_thread_stack, sizeof(dptc_thread_stack), 0, | ||
542 | dptc_thread_name IF_PRIO(, PRIORITY_REALTIME_1) IF_COP(, CPU)); | ||
543 | |||
544 | logf("DPTC: Initialized"); | ||
41 | } | 545 | } |
42 | 546 | ||
43 | 547 | ||
548 | /* Start DPTC module */ | ||
549 | static void dptc_start(void) | ||
550 | { | ||
551 | int oldstate; | ||
552 | |||
553 | mutex_lock(&dptc_mutex); | ||
554 | |||
555 | oldstate = disable_irq_save(); | ||
556 | |||
557 | if (!dptc_running) | ||
558 | { | ||
559 | dptc_running = true; | ||
560 | |||
561 | /* Enable DPTC and unmask interrupt. */ | ||
562 | avic_enable_int(INT_CCM_CLK, INT_TYPE_IRQ, INT_PRIO_DPTC, | ||
563 | CCM_CLK_HANDLER); | ||
564 | |||
565 | update_dptc_counts(dvfs_level, dptc_wp); | ||
566 | enable_dptc(); | ||
567 | } | ||
568 | |||
569 | restore_irq(oldstate); | ||
570 | |||
571 | mutex_unlock(&dptc_mutex); | ||
572 | |||
573 | logf("DPTC: started"); | ||
574 | } | ||
575 | |||
576 | |||
577 | /* Stop the DPTC hardware if running and go back to default working point */ | ||
578 | static void dptc_stop(void) | ||
579 | { | ||
580 | int oldlevel; | ||
581 | |||
582 | mutex_lock(&dptc_mutex); | ||
583 | |||
584 | oldlevel = disable_irq_save(); | ||
585 | |||
586 | if (dptc_running) | ||
587 | { | ||
588 | /* Disable DPTC and mask interrupt. */ | ||
589 | CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_DPTEN) | CCM_PMCR0_PTVAIM; | ||
590 | avic_disable_int(INT_CCM_CLK); | ||
591 | dptc_int_data = 0; | ||
592 | |||
593 | dptc_running = false; | ||
594 | } | ||
595 | |||
596 | restore_irq(oldlevel); | ||
597 | |||
598 | /* Go back to default working point. */ | ||
599 | dptc_new_wp(DPTC_WP_DEFAULT); | ||
600 | |||
601 | mutex_unlock(&dptc_mutex); | ||
602 | |||
603 | logf("DPTC: stopped"); | ||
604 | } | ||
605 | |||
606 | |||
607 | /** Main module interface **/ | ||
608 | |||
609 | /* Initialize DVFS and DPTC */ | ||
610 | void dvfs_dptc_init(void) | ||
611 | { | ||
612 | dptc_init(); | ||
613 | dvfs_init(); | ||
614 | } | ||
615 | |||
616 | |||
617 | /* Start DVFS and DPTC */ | ||
618 | void dvfs_dptc_start(void) | ||
619 | { | ||
620 | dvfs_start(); | ||
621 | if (0) /* Hold off for now */ | ||
622 | { | ||
623 | dptc_start(); | ||
624 | } | ||
625 | } | ||
626 | |||
627 | |||
628 | /* Stop DVFS and DPTC */ | ||
44 | void dvfs_dptc_stop(void) | 629 | void dvfs_dptc_stop(void) |
45 | { | 630 | { |
46 | /* Nothing for now */ | 631 | dptc_stop(); |
632 | dvfs_stop(); | ||
47 | } | 633 | } |
48 | 634 | ||
635 | |||
636 | /* Set a signal load tracking weight */ | ||
637 | void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value) | ||
638 | { | ||
639 | volatile unsigned long *reg_p = &CCM_LTR2; | ||
640 | unsigned int shift = 3 * index; | ||
641 | |||
642 | if (index < 9) | ||
643 | { | ||
644 | reg_p = &CCM_LTR3; | ||
645 | shift += 5; /* Bits 7:5, 10:8 ... 31:29 */ | ||
646 | } | ||
647 | else if (index < 16) | ||
648 | { | ||
649 | shift -= 16; /* Bits 13:11, 16:14 ... 31:29 */ | ||
650 | } | ||
651 | |||
652 | imx31_regmod32(reg_p, value << shift, 0x7 << shift); | ||
653 | } | ||
654 | |||
655 | |||
656 | /* Set a signal load detection mode */ | ||
657 | void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge) | ||
658 | { | ||
659 | unsigned long bit = 0; | ||
660 | |||
661 | if ((unsigned)index < 13) | ||
662 | bit = 1ul << (index + 3); | ||
663 | else if ((unsigned)index < 16) | ||
664 | bit = 1ul << (index + 29); | ||
665 | |||
666 | imx31_regmod32(&CCM_LTR0, edge ? bit : 0, bit); | ||
667 | } | ||
668 | |||
669 | |||
670 | void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert) | ||
671 | { | ||
672 | if ((unsigned)dvgp <= 3) | ||
673 | { | ||
674 | unsigned long bit = 1ul << dvgp; | ||
675 | imx31_regmod32(&CCM_PMCR1, assert ? bit : 0, bit); | ||
676 | } | ||
677 | } | ||
678 | |||
679 | |||
680 | /* Turn the wait-for-interrupt monitoring on or off */ | ||
681 | void dvfs_wfi_monitor(bool on) | ||
682 | { | ||
683 | imx31_regmod32(&CCM_PMCR0, on ? 0 : CCM_PMCR0_WFIM, | ||
684 | CCM_PMCR0_WFIM); | ||
685 | } | ||
686 | |||
687 | |||
688 | /* Obtain the current core voltage setting, in millivolts 8-) */ | ||
689 | unsigned int dvfs_dptc_get_voltage(void) | ||
690 | { | ||
691 | unsigned int v; | ||
692 | |||
693 | int oldlevel = disable_irq_save(); | ||
694 | v = dvfs_dptc_voltage_table[dptc_wp].sw[dvfs_level]; | ||
695 | restore_irq(oldlevel); | ||
696 | |||
697 | /* 25mV steps from 0.900V to 1.675V */ | ||
698 | return v * 25 + 900; | ||
699 | } | ||
700 | |||
701 | |||
702 | /* Get the current DVFS level */ | ||
703 | unsigned int dvfs_get_level(void) | ||
704 | { | ||
705 | return dvfs_level; | ||
706 | } | ||
707 | |||
708 | |||
709 | /* If DVFS is disabled, set the level explicitly */ | ||
710 | void dvfs_set_level(unsigned int level) | ||
711 | { | ||
712 | int oldlevel = disable_irq_save(); | ||
713 | |||
714 | unsigned int currlevel = | ||
715 | (CCM_PMCR0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS; | ||
716 | |||
717 | if (!dvfs_running && level < DVFS_NUM_LEVELS && level != currlevel) | ||
718 | set_current_dvfs_level(level); | ||
719 | |||
720 | restore_irq(oldlevel); | ||
721 | } | ||
722 | |||
723 | |||
724 | /* Get the current DPTC working point */ | ||
725 | unsigned int dptc_get_wp(void) | ||
726 | { | ||
727 | return dptc_wp; | ||
728 | } | ||
729 | |||
730 | |||
731 | /* If DPTC is not running, set the working point explicitly */ | ||
732 | void dptc_set_wp(unsigned int wp) | ||
733 | { | ||
734 | mutex_lock(&dptc_mutex); | ||
735 | |||
736 | if (!dptc_running && wp < DPTC_NUM_WP) | ||
737 | { | ||
738 | dptc_new_wp(wp); | ||
739 | } | ||
740 | |||
741 | mutex_unlock(&dptc_mutex); | ||
742 | } | ||
diff --git a/firmware/target/arm/imx31/dvfs_dptc-imx31.h b/firmware/target/arm/imx31/dvfs_dptc-imx31.h index 8f6f5da98d..2bf6114a11 100644 --- a/firmware/target/arm/imx31/dvfs_dptc-imx31.h +++ b/firmware/target/arm/imx31/dvfs_dptc-imx31.h | |||
@@ -24,7 +24,106 @@ | |||
24 | #ifndef _DVFS_DPTC_IMX31_H_ | 24 | #ifndef _DVFS_DPTC_IMX31_H_ |
25 | #define _DVFS_DPTC_IMX31_H_ | 25 | #define _DVFS_DPTC_IMX31_H_ |
26 | 26 | ||
27 | /* DVFS load tracking signals */ | ||
28 | enum DVFS_LT_SIGS | ||
29 | { | ||
30 | DVFS_LT_SIG_M3IF_M0_BUF = 0, /* Hready signal of M3IF's master #0 | ||
31 | (L2 Cache) */ | ||
32 | DVFS_LT_SIG_M3IF_M1 = 1, /* Hready signal of M3IF's master #1 | ||
33 | (L2 Cache) */ | ||
34 | DVFS_LT_SIG_MBX_MBXCLKGATE = 2, /* Hready signal of M3IF's master #2 | ||
35 | (MBX) */ | ||
36 | DVFS_LT_SIG_M3IF_M3 = 3, /* Hready signal of M3IF's master #3 | ||
37 | (MAX) */ | ||
38 | DVFS_LT_SIG_M3IF_M4 = 4, /* Hready signal of M3IF's master #4 | ||
39 | (SDMA) */ | ||
40 | DVFS_LT_SIG_M3IF_M5 = 5, /* Hready signal of M3IF's master #5 | ||
41 | (mpeg4_vga_encoder) */ | ||
42 | DVFS_LT_SIG_M3IF_M6 = 6, /* Hready signal of M3IF's master #6 | ||
43 | (IPU) */ | ||
44 | DVFS_LT_SIG_M3IF_M7 = 7, /* Hready signal of M3IF's master #7 | ||
45 | (IPU) */ | ||
46 | DVFS_LT_SIG_ARM11_P_IRQ_B_RBT_GATE = 8, /* ARM normal interrupt */ | ||
47 | DVFS_LT_SIG_ARM11_P_FIQ_B_RBT_GATE = 9, /* ARM fast interrupt */ | ||
48 | DVFS_LT_SIG_IPI_GPIO1_INT0 = 10, /* Interrupt line from GPIO */ | ||
49 | DVFS_LT_SIG_IPI_INT_IPU_FUNC = 11, /* Interrupt line from IPU */ | ||
50 | DVFS_LT_SIG_DVGP0 = 12, /* Software-controllable general-purpose | ||
51 | bits from the CCM */ | ||
52 | DVFS_LT_SIG_DVGP1 = 13, /* Software-controllable general-purpose | ||
53 | bits from the CCM */ | ||
54 | DVFS_LT_SIG_DVGP2 = 14, /* Software-controllable general-purpose | ||
55 | bits from the CCM */ | ||
56 | DVFS_LT_SIG_DVGP3 = 15, /* Software-controllable general-purpose | ||
57 | bits from the CCM */ | ||
58 | }; | ||
59 | |||
60 | |||
61 | enum DVFS_DVGPS | ||
62 | { | ||
63 | DVFS_DVGP_0 = 0, | ||
64 | DVFS_DVGP_1, | ||
65 | DVFS_DVGP_2, | ||
66 | DVFS_DVGP_3, | ||
67 | }; | ||
68 | |||
69 | union dvfs_dptc_voltage_table_entry | ||
70 | { | ||
71 | uint8_t sw[4]; /* Access as array */ | ||
72 | |||
73 | struct | ||
74 | { | ||
75 | /* Chosen by PMIC pin states */ | ||
76 | /* when SWxABDVS bit is 1: */ | ||
77 | /* DVSSWxA DVSSWxB */ | ||
78 | uint8_t sw1a; /* 0 0 */ | ||
79 | uint8_t sw1advs; /* 1 0 */ | ||
80 | uint8_t sw1bdvs; /* 0 1 */ | ||
81 | uint8_t sw1bstby; /* 1 1 */ | ||
82 | }; | ||
83 | }; | ||
84 | |||
85 | |||
86 | struct dptc_dcvr_table_entry | ||
87 | { | ||
88 | uint32_t dcvr0; /* DCVR register values for working point */ | ||
89 | uint32_t dcvr1; | ||
90 | uint32_t dcvr2; | ||
91 | uint32_t dcvr3; | ||
92 | }; | ||
93 | |||
94 | |||
95 | struct dvfs_clock_table_entry | ||
96 | { | ||
97 | uint32_t pll_val; /* Setting for target PLL */ | ||
98 | uint32_t pdr_val; /* Post-divider for target setting */ | ||
99 | uint32_t pll_num : 1; /* 1 = MCU PLL, 0 = Serial PLL */ | ||
100 | uint32_t vscnt : 3; /* Voltage scaling counter, CKIL delay */ | ||
101 | }; | ||
102 | |||
103 | |||
104 | struct dvfs_lt_signal_descriptor | ||
105 | { | ||
106 | uint8_t weight : 3; /* Signal weight = 0-7 */ | ||
107 | uint8_t detect : 1; /* 1 = edge-detected */ | ||
108 | }; | ||
109 | |||
110 | |||
111 | extern long cpu_voltage_setting; | ||
112 | |||
113 | void dvfs_dptc_init(void); | ||
27 | void dvfs_dptc_start(void); | 114 | void dvfs_dptc_start(void); |
28 | void dvfs_dptc_stop(void); | 115 | void dvfs_dptc_stop(void); |
29 | 116 | ||
117 | void dvfs_wfi_monitor(bool on); | ||
118 | void dvfs_set_lt_weight(enum DVFS_LT_SIGS index, unsigned long value); | ||
119 | void dvfs_set_lt_detect(enum DVFS_LT_SIGS index, bool edge); | ||
120 | void dvfs_set_gp_bit(enum DVFS_DVGPS dvgp, bool assert); | ||
121 | |||
122 | unsigned int dvfs_dptc_get_voltage(void); | ||
123 | unsigned int dvfs_get_level(void); | ||
124 | void dvfs_set_level(unsigned int level); | ||
125 | |||
126 | unsigned int dptc_get_wp(void); | ||
127 | void dptc_set_wp(unsigned int wp); | ||
128 | |||
30 | #endif /* _DVFS_DPTC_IMX31_H_ */ | 129 | #endif /* _DVFS_DPTC_IMX31_H_ */ |
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 new file mode 100644 index 0000000000..2356e23252 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/dvfs_dptc_tables-target.h | |||
@@ -0,0 +1,279 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 by Michael Sevakis | ||
11 | * | ||
12 | * Target-specific i.MX31 DVFS and DPTC driver declarations | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #ifndef _DVFS_DPTC_TARGET_H_ | ||
24 | #define _DVFS_DPTC_TARGET_H_ | ||
25 | |||
26 | #define DVFS_LEVEL_DEFAULT 1 /* 264 MHz - safe frequency for 1.35V */ | ||
27 | #define DVFS_NUM_LEVELS 3 /* 528 MHz, 264 MHz, 132 MHz */ | ||
28 | #define DVFS_NO_PWRRDY /* PWRRDY is connected to different SoC port */ | ||
29 | |||
30 | #define DPTC_WP_DEFAULT 1 /* 1.600, 1.350, 1.350 */ | ||
31 | #define DPTC_WP_PANIC 3 /* Up to minimum for > 400 MHz */ | ||
32 | #define DPTC_NUM_WP 17 | ||
33 | |||
34 | #define VOLTAGE_SETTING_MIN MC13783_SW_1_350 | ||
35 | #define VOLTAGE_SETTING_MAX MC13783_SW_1_625 | ||
36 | |||
37 | /* Frequency increase threshold. Increase frequency change request | ||
38 | * will be sent if DVFS counter value will be more than this value. */ | ||
39 | #define DVFS_UPTHR 30 | ||
40 | |||
41 | /* Frequency decrease threshold. Decrease frequency change request | ||
42 | * will be sent if DVFS counter value will be less than this value. */ | ||
43 | #define DVFS_DNTHR 18 | ||
44 | |||
45 | /* Panic threshold. Panic frequency change request | ||
46 | * will be sent if DVFS counter value will be more than this value. */ | ||
47 | #define DVFS_PNCTHR 63 | ||
48 | |||
49 | /* With the ARM clocked at 532, this setting yields a DIV_3_CLK of 2.03 kHz. | ||
50 | * | ||
51 | * Note: To get said clock, the divider would have to be 262144. The values | ||
52 | * and their meanings are not published in the reference manual for i.MX31 | ||
53 | * but show up in the i.MX35 reference manual. Either that chip is different | ||
54 | * and the values have an additional division or the comments in the BSP are | ||
55 | * incorrect. | ||
56 | */ | ||
57 | #define DVFS_DIV3CK CCM_LTR0_DIV3CK_131072 | ||
58 | |||
59 | /* UPCNT defines the amount of times the up threshold should be exceeded | ||
60 | * before DVFS will trigger frequency increase request. */ | ||
61 | |||
62 | #if 0 | ||
63 | /* Freescale BSP value: a bit too agressive IMHO */ | ||
64 | #define DVFS_UPCNT 0x33 | ||
65 | #endif | ||
66 | #define DVFS_UPCNT 0x48 | ||
67 | |||
68 | /* DNCNT defines the amount of times the down threshold should be undershot | ||
69 | * before DVFS will trigger frequency decrease request. */ | ||
70 | #define DVFS_DNCNT 0x33 | ||
71 | |||
72 | /* EMAC defines how many samples are included in EMA calculation */ | ||
73 | #define DVFS_EMAC 0x20 | ||
74 | |||
75 | /* Define mask of which reference circuits are employed for DPTC */ | ||
76 | #define DPTC_DRCE_MASK (CCM_PMCR0_DRCE1 | CCM_PMCR0_DRCE3) | ||
77 | |||
78 | /* When panicing, this working point is used */ | ||
79 | #define DPTC_PANIC_WP | ||
80 | |||
81 | /* Due to a hardware bug in chip revisions < 2.0, when switching between | ||
82 | * Serial and MCU PLLs, DVFS forces the target PLL to go into reset and | ||
83 | * relock, only post divider frequency scaling is possible. | ||
84 | */ | ||
85 | |||
86 | static const union dvfs_dptc_voltage_table_entry | ||
87 | dvfs_dptc_voltage_table[DPTC_NUM_WP] = | ||
88 | { | ||
89 | /* For each working point, there are four DVFS settings, chosen by the | ||
90 | * DVS pin states on the PMIC set by the DVFS routines. Pins are reversed | ||
91 | * and actual order as used by PMIC for DVSUP values of 00, 01, 10 and 11 | ||
92 | * is below. | ||
93 | * | ||
94 | * SW1A SW1ADVS SW1BDVS SW1BSTBY | ||
95 | * 0 2 1 3 */ | ||
96 | { { MC13783_SW_1_625, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
97 | { { MC13783_SW_1_600, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
98 | { { MC13783_SW_1_575, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
99 | { { MC13783_SW_1_550, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
100 | { { MC13783_SW_1_525, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
101 | { { MC13783_SW_1_500, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
102 | { { MC13783_SW_1_475, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
103 | { { MC13783_SW_1_450, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
104 | { { MC13783_SW_1_425, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
105 | { { MC13783_SW_1_400, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
106 | { { MC13783_SW_1_375, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
107 | { { MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
108 | { { MC13783_SW_1_325, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
109 | { { MC13783_SW_1_300, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
110 | { { MC13783_SW_1_275, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
111 | { { MC13783_SW_1_250, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
112 | { { MC13783_SW_1_225, MC13783_SW_1_350, MC13783_SW_1_350, MC13783_SW_1_350 } }, | ||
113 | }; | ||
114 | |||
115 | #if 1 | ||
116 | /* For 27 MHz PLL reference clock */ | ||
117 | static const struct dptc_dcvr_table_entry | ||
118 | dptc_dcvr_table[DVFS_NUM_LEVELS][DPTC_NUM_WP] = | ||
119 | { | ||
120 | /* DCVR0 DCVR1 DCVR2 DCVR3 */ | ||
121 | { /* 528 MHz */ | ||
122 | { 0xffc00000, 0x90400000, 0xffc00000, 0xdd000000 }, | ||
123 | { 0xffc00000, 0x90629890, 0xffc00000, 0xdd34ed20 }, | ||
124 | { 0xffc00000, 0x90629890, 0xffc00000, 0xdd34ed20 }, | ||
125 | { 0xffc00000, 0x90629894, 0xffc00000, 0xdd74fd24 }, | ||
126 | { 0xffc00000, 0x90a2a894, 0xffc00000, 0xddb50d28 }, | ||
127 | { 0xffc00000, 0x90e2b89c, 0xffc00000, 0xde352d30 }, | ||
128 | { 0xffc00000, 0x9162d8a0, 0xffc00000, 0xdef55d38 }, | ||
129 | { 0xffc00000, 0x91e2f8a8, 0xffc00000, 0xdfb58d44 }, | ||
130 | { 0xffc00000, 0x926308b0, 0xffc00000, 0xe0b5cd54 }, | ||
131 | { 0xffc00000, 0x92e328bc, 0xffc00000, 0xe1f60d64 }, | ||
132 | { 0xffc00000, 0x93a358c0, 0xffc00000, 0xe3365d74 }, | ||
133 | { 0xffc00000, 0xf66388cc, 0xffc00000, 0xf6768d84 }, | ||
134 | { 0xffc00000, 0xf663b8d4, 0xffc00000, 0xf676dd98 }, | ||
135 | { 0xffc00000, 0xf663e8e0, 0xffc00000, 0xf6773da4 }, | ||
136 | { 0xffc00000, 0xf66418ec, 0xffc00000, 0xf6778dbc }, | ||
137 | { 0xffc00000, 0xf66458fc, 0xffc00000, 0xf677edd0 }, | ||
138 | { 0xffc00000, 0xf6648908, 0xffc00000, 0xf6783de8 }, | ||
139 | |||
140 | }, | ||
141 | { /* 264 MHz */ | ||
142 | { 0xffc00000, 0x90400000, 0xffc00000, 0xdd000000 }, | ||
143 | { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 }, | ||
144 | { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 }, | ||
145 | { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd4d4348 }, | ||
146 | { 0xffc00000, 0x9088b228, 0xffc00000, 0xdd8d434c }, | ||
147 | { 0xffc00000, 0x90c8b228, 0xffc00000, 0xde0d534c }, | ||
148 | { 0xffc00000, 0x9148b228, 0xffc00000, 0xdecd5350 }, | ||
149 | { 0xffc00000, 0x91c8c22c, 0xffc00000, 0xdf8d6354 }, | ||
150 | { 0xffc00000, 0x9248d22c, 0xffc00000, 0xe08d7354 }, | ||
151 | { 0xffc00000, 0x92c8d230, 0xffc00000, 0xe1cd8358 }, | ||
152 | { 0xffc00000, 0x9388e234, 0xffc00000, 0xe30d935c }, | ||
153 | { 0xffc00000, 0xf648e234, 0xffc00000, 0xf64db364 }, | ||
154 | { 0xffc00000, 0xf648f238, 0xffc00000, 0xf64dc368 }, | ||
155 | { 0xffc00000, 0xf648f23c, 0xffc00000, 0xf64dd36c }, | ||
156 | { 0xffc00000, 0xf649023c, 0xffc00000, 0xf64de370 }, | ||
157 | { 0xffc00000, 0xf649123c, 0xffc00000, 0xf64df374 }, | ||
158 | { 0xffc00000, 0xf6492240, 0xffc00000, 0xf64e1378 }, | ||
159 | |||
160 | }, | ||
161 | { /* 132 MHz */ | ||
162 | { 0xffc00000, 0x90400000, 0xffc00000, 0xdd000000 }, | ||
163 | { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 }, | ||
164 | { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd0d4348 }, | ||
165 | { 0xffc00000, 0x9048a224, 0xffc00000, 0xdd4d4348 }, | ||
166 | { 0xffc00000, 0x9088b228, 0xffc00000, 0xdd8d434c }, | ||
167 | { 0xffc00000, 0x90c8b228, 0xffc00000, 0xde0d534c }, | ||
168 | { 0xffc00000, 0x9148b228, 0xffc00000, 0xdecd5350 }, | ||
169 | { 0xffc00000, 0x91c8c22c, 0xffc00000, 0xdf8d6354 }, | ||
170 | { 0xffc00000, 0x9248d22c, 0xffc00000, 0xe08d7354 }, | ||
171 | { 0xffc00000, 0x92c8d230, 0xffc00000, 0xe1cd8358 }, | ||
172 | { 0xffc00000, 0x9388e234, 0xffc00000, 0xe30d935c }, | ||
173 | { 0xffc00000, 0xf648e234, 0xffc00000, 0xf64db364 }, | ||
174 | { 0xffc00000, 0xf648f238, 0xffc00000, 0xf64dc368 }, | ||
175 | { 0xffc00000, 0xf648f23c, 0xffc00000, 0xf64dd36c }, | ||
176 | { 0xffc00000, 0xf649023c, 0xffc00000, 0xf64de370 }, | ||
177 | { 0xffc00000, 0xf649123c, 0xffc00000, 0xf64df374 }, | ||
178 | { 0xffc00000, 0xf6492240, 0xffc00000, 0xf64e1378 }, | ||
179 | }, | ||
180 | }; | ||
181 | #else/* For 26 MHz PLL reference clock */ | ||
182 | static const struct dptc_dcvr_table_entry | ||
183 | dptc_dcvr_table[DVFS_NUM_LEVELS][DPTC_NUM_WP] = | ||
184 | { | ||
185 | /* DCVR0 DCVR1 DCVR2 DCVR3 */ | ||
186 | { /* 528 MHz */ | ||
187 | { 0xffc00000, 0x95c00000, 0xffc00000, 0xe5800000 }, | ||
188 | { 0xffc00000, 0x95e3e8e4, 0xffc00000, 0xe5b6fda0 }, | ||
189 | { 0xffc00000, 0x95e3e8e4, 0xffc00000, 0xe5b6fda0 }, | ||
190 | { 0xffc00000, 0x95e3e8e8, 0xffc00000, 0xe5f70da4 }, | ||
191 | { 0xffc00000, 0x9623f8e8, 0xffc00000, 0xe6371da8 }, | ||
192 | { 0xffc00000, 0x966408f0, 0xffc00000, 0xe6b73db0 }, | ||
193 | { 0xffc00000, 0x96e428f4, 0xffc00000, 0xe7776dbc }, | ||
194 | { 0xffc00000, 0x976448fc, 0xffc00000, 0xe8379dc8 }, | ||
195 | { 0xffc00000, 0x97e46904, 0xffc00000, 0xe977ddd8 }, | ||
196 | { 0xffc00000, 0x98a48910, 0xffc00000, 0xeab81de8 }, | ||
197 | { 0xffc00000, 0x9964b918, 0xffc00000, 0xebf86df8 }, | ||
198 | { 0xffc00000, 0xffe4e924, 0xffc00000, 0xfff8ae08 }, | ||
199 | { 0xffc00000, 0xffe5192c, 0xffc00000, 0xfff8fe1c }, | ||
200 | { 0xffc00000, 0xffe54938, 0xffc00000, 0xfff95e2c }, | ||
201 | { 0xffc00000, 0xffe57944, 0xffc00000, 0xfff9ae44 }, | ||
202 | { 0xffc00000, 0xffe5b954, 0xffc00000, 0xfffa0e58 }, | ||
203 | { 0xffc00000, 0xffe5e960, 0xffc00000, 0xfffa6e70 }, | ||
204 | }, | ||
205 | { /* 264 MHz */ | ||
206 | { 0xffc00000, 0x95c00000, 0xffc00000, 0xe5800000 }, | ||
207 | { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 }, | ||
208 | { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 }, | ||
209 | { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe5cdc368 }, | ||
210 | { 0xffc00000, 0x9609023c, 0xffc00000, 0xe60dc36c }, | ||
211 | { 0xffc00000, 0x9649023c, 0xffc00000, 0xe68dd36c }, | ||
212 | { 0xffc00000, 0x96c9023c, 0xffc00000, 0xe74dd370 }, | ||
213 | { 0xffc00000, 0x97491240, 0xffc00000, 0xe80de374 }, | ||
214 | { 0xffc00000, 0x97c92240, 0xffc00000, 0xe94df374 }, | ||
215 | { 0xffc00000, 0x98892244, 0xffc00000, 0xea8e0378 }, | ||
216 | { 0xffc00000, 0x99493248, 0xffc00000, 0xebce137c }, | ||
217 | { 0xffc00000, 0xffc93248, 0xffc00000, 0xffce3384 }, | ||
218 | { 0xffc00000, 0xffc9424c, 0xffc00000, 0xffce4388 }, | ||
219 | { 0xffc00000, 0xffc95250, 0xffc00000, 0xffce538c }, | ||
220 | { 0xffc00000, 0xffc96250, 0xffc00000, 0xffce7390 }, | ||
221 | { 0xffc00000, 0xffc97254, 0xffc00000, 0xffce8394 }, | ||
222 | { 0xffc00000, 0xffc98258, 0xffc00000, 0xffcea39c }, | ||
223 | }, | ||
224 | { /* 132 MHz */ | ||
225 | { 0xffc00000, 0x95c00000, 0xffc00000, 0xe5800000 }, | ||
226 | { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 }, | ||
227 | { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe58dc368 }, | ||
228 | { 0xffc00000, 0x95c8f238, 0xffc00000, 0xe5cdc368 }, | ||
229 | { 0xffc00000, 0x9609023c, 0xffc00000, 0xe60dc36c }, | ||
230 | { 0xffc00000, 0x9649023c, 0xffc00000, 0xe68dd36c }, | ||
231 | { 0xffc00000, 0x96c9023c, 0xffc00000, 0xe74dd370 }, | ||
232 | { 0xffc00000, 0x97491240, 0xffc00000, 0xe80de374 }, | ||
233 | { 0xffc00000, 0x97c92240, 0xffc00000, 0xe94df374 }, | ||
234 | { 0xffc00000, 0x98892244, 0xffc00000, 0xea8e0378 }, | ||
235 | { 0xffc00000, 0x99493248, 0xffc00000, 0xebce137c }, | ||
236 | { 0xffc00000, 0xffc93248, 0xffc00000, 0xffce3384 }, | ||
237 | { 0xffc00000, 0xffc9424c, 0xffc00000, 0xffce4388 }, | ||
238 | { 0xffc00000, 0xffc95250, 0xffc00000, 0xffce538c }, | ||
239 | { 0xffc00000, 0xffc96250, 0xffc00000, 0xffce7390 }, | ||
240 | { 0xffc00000, 0xffc97254, 0xffc00000, 0xffce8394 }, | ||
241 | { 0xffc00000, 0xffc98258, 0xffc00000, 0xffcea39c }, | ||
242 | }, | ||
243 | }; | ||
244 | #endif | ||
245 | |||
246 | |||
247 | /* For 27 MHz PLL reference clock */ | ||
248 | static const struct dvfs_clock_table_entry | ||
249 | dvfs_clock_table[DVFS_NUM_LEVELS] = | ||
250 | { | ||
251 | /* PLL val PDR0 val PLL VSCNT */ | ||
252 | { 0x00082407, 0xff841e58, 1, 7 }, /* MCUPLL, 528 MHz, /1 = 528 MHz */ | ||
253 | { 0x00082407, 0xff841e59, 1, 7 }, /* MCUPLL, 528 MHz, /2 = 264 MHz */ | ||
254 | { 0x00082407, 0xff841e5b, 1, 7 }, /* MCUPLL, 528 MHz, /4 = 132 MHz */ | ||
255 | }; | ||
256 | |||
257 | |||
258 | /* DVFS load-tracking signal weights and detect modes */ | ||
259 | static const struct dvfs_lt_signal_descriptor lt_signals[16] = | ||
260 | { | ||
261 | { 0, 0 }, /* DVFS_LT_SIG_M3IF_M0_BUF */ | ||
262 | { 0, 0 }, /* DVFS_LT_SIG_M3IF_M1 */ | ||
263 | { 0, 0 }, /* DVFS_LT_SIG_MBX_MBXCLKGATE */ | ||
264 | { 0, 0 }, /* DVFS_LT_SIG_M3IF_M3 */ | ||
265 | { 0, 0 }, /* DVFS_LT_SIG_M3IF_M4 */ | ||
266 | { 0, 0 }, /* DVFS_LT_SIG_M3IF_M5 */ | ||
267 | { 0, 0 }, /* DVFS_LT_SIG_M3IF_M6 */ | ||
268 | { 0, 0 }, /* DVFS_LT_SIG_M3IF_M7 */ | ||
269 | { 0, 0 }, /* DVFS_LT_SIG_ARM11_P_IRQ_B_RBT_GATE */ | ||
270 | { 0, 0 }, /* DVFS_LT_SIG_ARM11_P_FIQ_B_RBT_GATE */ | ||
271 | { 0, 0 }, /* DVFS_LT_SIG_IPI_GPIO1_INT0 */ | ||
272 | { 0, 0 }, /* DVFS_LT_SIG_IPI_INT_IPU_FUNC */ | ||
273 | { 7, 0 }, /* DVFS_LT_SIG_DVGP0 */ | ||
274 | { 7, 0 }, /* DVFS_LT_SIG_DVGP1 */ | ||
275 | { 7, 0 }, /* DVFS_LT_SIG_DVGP2 */ | ||
276 | { 7, 0 }, /* DVFS_LT_SIG_DVGP3 */ | ||
277 | }; | ||
278 | |||
279 | #endif /* _DVFS_DPTC_TARGET_H_ */ | ||
diff --git a/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c index 8e81447bd3..894aea4fd3 100644 --- a/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/kernel-gigabeat-s.c | |||
@@ -70,10 +70,11 @@ void kernel_device_init(void) | |||
70 | sdma_init(); | 70 | sdma_init(); |
71 | spi_init(); | 71 | spi_init(); |
72 | mc13783_init(); | 72 | mc13783_init(); |
73 | dvfs_dptc_start(); | 73 | dvfs_dptc_init(); |
74 | dvfs_wfi_monitor(true); /* Monitor the WFI signal */ | ||
75 | dvfs_dptc_start(); /* Should be ok to start even so early */ | ||
74 | } | 76 | } |
75 | 77 | ||
76 | #ifdef BOOTLOADER | ||
77 | void tick_stop(void) | 78 | void tick_stop(void) |
78 | { | 79 | { |
79 | avic_disable_int(INT_EPIT1); /* Disable insterrupt */ | 80 | avic_disable_int(INT_EPIT1); /* Disable insterrupt */ |
@@ -81,4 +82,4 @@ void tick_stop(void) | |||
81 | EPITSR1 = EPITSR_OCIF; /* Clear pending */ | 82 | EPITSR1 = EPITSR_OCIF; /* Clear pending */ |
82 | ccm_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */ | 83 | ccm_module_clock_gating(CG_EPIT1, CGM_OFF); /* Turn off module clock */ |
83 | } | 84 | } |
84 | #endif | 85 | |
diff --git a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c index 7e3b39dba8..d7fe87f168 100644 --- a/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/power-gigabeat-s.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "backlight-target.h" | 28 | #include "backlight-target.h" |
29 | #include "avic-imx31.h" | 29 | #include "avic-imx31.h" |
30 | #include "mc13783.h" | 30 | #include "mc13783.h" |
31 | #include "dvfs_dptc-imx31.h" | ||
31 | #if CONFIG_TUNER | 32 | #if CONFIG_TUNER |
32 | #include "fmradio_i2c.h" | 33 | #include "fmradio_i2c.h" |
33 | #endif | 34 | #endif |
@@ -121,6 +122,9 @@ bool tuner_powered(void) | |||
121 | 122 | ||
122 | void power_off(void) | 123 | void power_off(void) |
123 | { | 124 | { |
125 | /* Turn off voltage and frequency scaling */ | ||
126 | dvfs_dptc_stop(); | ||
127 | |||
124 | /* Cut backlight */ | 128 | /* Cut backlight */ |
125 | _backlight_off(); | 129 | _backlight_off(); |
126 | 130 | ||
@@ -131,9 +135,7 @@ void power_off(void) | |||
131 | mc13783_set(MC13783_POWER_CONTROL0, MC13783_USEROFFSPI); | 135 | mc13783_set(MC13783_POWER_CONTROL0, MC13783_USEROFFSPI); |
132 | 136 | ||
133 | /* Wait for power cut */ | 137 | /* Wait for power cut */ |
134 | disable_interrupt(IRQ_FIQ_STATUS); | 138 | system_halt(); |
135 | |||
136 | while (1); | ||
137 | } | 139 | } |
138 | 140 | ||
139 | void power_init(void) | 141 | void power_init(void) |
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c index cd684e77ac..7c0d30c783 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "gpio-imx31.h" | 26 | #include "gpio-imx31.h" |
27 | #include "mmu-imx31.h" | 27 | #include "mmu-imx31.h" |
28 | #include "system-target.h" | 28 | #include "system-target.h" |
29 | #include "powermgmt-target.h" | ||
29 | #include "lcd.h" | 30 | #include "lcd.h" |
30 | #include "serial-imx31.h" | 31 | #include "serial-imx31.h" |
31 | #include "debug.h" | 32 | #include "debug.h" |
@@ -115,18 +116,24 @@ int system_memory_guard(int newmode) | |||
115 | return 0; | 116 | return 0; |
116 | } | 117 | } |
117 | 118 | ||
119 | void system_halt(void) | ||
120 | { | ||
121 | disable_interrupt(IRQ_FIQ_STATUS); | ||
122 | avic_set_ni_level(AVIC_NIL_DISABLE); | ||
123 | while (1) | ||
124 | core_idle(); | ||
125 | } | ||
126 | |||
118 | void system_reboot(void) | 127 | void system_reboot(void) |
119 | { | 128 | { |
120 | /* Multi-context so no SPI available (WDT?) */ | 129 | /* Multi-context so no SPI available (WDT?) */ |
121 | while (1); | 130 | system_halt(); |
122 | } | 131 | } |
123 | 132 | ||
124 | void system_exception_wait(void) | 133 | void system_exception_wait(void) |
125 | { | 134 | { |
126 | /* Called in many contexts so button reading may be a chore */ | 135 | /* Called in many contexts so button reading may be a chore */ |
127 | avic_disable_int(INT_ALL); | 136 | system_halt(); |
128 | core_idle(); | ||
129 | while (1); | ||
130 | } | 137 | } |
131 | 138 | ||
132 | void system_init(void) | 139 | void system_init(void) |
@@ -175,6 +182,9 @@ void system_init(void) | |||
175 | 182 | ||
176 | unsigned int i; | 183 | unsigned int i; |
177 | 184 | ||
185 | /* Initialize frequency with current */ | ||
186 | cpu_frequency = ccm_get_mcu_clk(); | ||
187 | |||
178 | /* MCR WFI enables wait mode (CCM_CCMR_LPM_WAIT_MODE = 0) */ | 188 | /* MCR WFI enables wait mode (CCM_CCMR_LPM_WAIT_MODE = 0) */ |
179 | imx31_regclr32(&CCM_CCMR, CCM_CCMR_LPM); | 189 | imx31_regclr32(&CCM_CCMR, CCM_CCMR_LPM); |
180 | 190 | ||
@@ -239,16 +249,33 @@ void __attribute__((naked)) imx31_regclr32(volatile uint32_t *reg_p, | |||
239 | (void)reg_p; (void)mask; | 249 | (void)reg_p; (void)mask; |
240 | } | 250 | } |
241 | 251 | ||
242 | #ifdef BOOTLOADER | 252 | |
243 | void system_prepare_fw_start(void) | 253 | void system_prepare_fw_start(void) |
244 | { | 254 | { |
245 | dvfs_dptc_stop(); | 255 | dvfs_dptc_stop(); |
246 | disable_interrupt(IRQ_FIQ_STATUS); | ||
247 | avic_disable_int(INT_ALL); | ||
248 | mc13783_close(); | 256 | mc13783_close(); |
249 | tick_stop(); | 257 | tick_stop(); |
258 | disable_interrupt(IRQ_FIQ_STATUS); | ||
259 | avic_set_ni_level(AVIC_NIL_DISABLE); | ||
250 | } | 260 | } |
251 | #endif | 261 | |
262 | |||
263 | #ifndef BOOTLOADER | ||
264 | void rolo_restart_firmware(const unsigned char *source, unsigned char *dest, | ||
265 | int length) __attribute__((noreturn)); | ||
266 | |||
267 | void __attribute__((noreturn)) | ||
268 | rolo_restart(const unsigned char *source, unsigned char *dest, int length) | ||
269 | { | ||
270 | /* Some housekeeping tasks must be performed for a safe changeover */ | ||
271 | charging_algorithm_close(); | ||
272 | system_prepare_fw_start(); | ||
273 | |||
274 | /* Copying routine where new image is run */ | ||
275 | rolo_restart_firmware(source, dest, length); | ||
276 | } | ||
277 | #endif /* BOOTLOADER */ | ||
278 | |||
252 | 279 | ||
253 | inline void dumpregs(void) | 280 | inline void dumpregs(void) |
254 | { | 281 | { |
diff --git a/firmware/target/arm/imx31/gigabeat-s/system-target.h b/firmware/target/arm/imx31/gigabeat-s/system-target.h index b859093c58..af95471db6 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/system-target.h | |||
@@ -24,12 +24,12 @@ | |||
24 | #include "system-arm.h" | 24 | #include "system-arm.h" |
25 | #include "mmu-arm.h" | 25 | #include "mmu-arm.h" |
26 | 26 | ||
27 | #ifndef HAVE_ADJUSTABLE_CPU_FREQ | 27 | /* High enough for most tasks but low enough for reduced voltage */ |
28 | /* TODO: implement CPU frequency scaling */ | 28 | #define CPUFREQ_DEFAULT 264000000 |
29 | #define CPUFREQ_DEFAULT CPU_FREQ | 29 | /* Still quite powerful, minimum possible frequency */ |
30 | #define CPUFREQ_NORMAL CPU_FREQ | 30 | #define CPUFREQ_NORMAL 132000000 |
31 | #define CPUFREQ_MAX CPU_FREQ | 31 | /* Overdrive mode */ |
32 | #endif | 32 | #define CPUFREQ_MAX 528000000 |
33 | 33 | ||
34 | static inline void udelay(unsigned int usecs) | 34 | static inline void udelay(unsigned int usecs) |
35 | { | 35 | { |
@@ -45,10 +45,11 @@ void gpt_stop(void); | |||
45 | 45 | ||
46 | unsigned int iim_system_rev(void); | 46 | unsigned int iim_system_rev(void); |
47 | 47 | ||
48 | /* Prepare for transition to firmware */ | 48 | /* Prepare for transition to (new) firmware */ |
49 | void system_prepare_fw_start(void); | 49 | void system_prepare_fw_start(void); |
50 | void tick_stop(void); | 50 | void tick_stop(void); |
51 | void kernel_device_init(void); | 51 | void kernel_device_init(void); |
52 | void system_halt(void); | ||
52 | 53 | ||
53 | void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value, | 54 | void imx31_regmod32(volatile uint32_t *reg_p, uint32_t value, |
54 | uint32_t mask); | 55 | uint32_t mask); |
diff --git a/firmware/target/arm/imx31/mc13783-imx31.c b/firmware/target/arm/imx31/mc13783-imx31.c index 1c43b3b6fa..a083614488 100644 --- a/firmware/target/arm/imx31/mc13783-imx31.c +++ b/firmware/target/arm/imx31/mc13783-imx31.c | |||
@@ -26,10 +26,6 @@ | |||
26 | #include "debug.h" | 26 | #include "debug.h" |
27 | #include "kernel.h" | 27 | #include "kernel.h" |
28 | 28 | ||
29 | #ifdef BOOTLOADER | ||
30 | #define PMIC_DRIVER_CLOSE | ||
31 | #endif | ||
32 | |||
33 | extern const struct mc13783_event_list mc13783_event_list; | 29 | extern const struct mc13783_event_list mc13783_event_list; |
34 | extern struct spi_node mc13783_spi; | 30 | extern struct spi_node mc13783_spi; |
35 | 31 | ||
@@ -47,10 +43,7 @@ static const unsigned char pmic_intm_regs[2] = | |||
47 | static const unsigned char pmic_ints_regs[2] = | 43 | static const unsigned char pmic_ints_regs[2] = |
48 | { MC13783_INTERRUPT_STATUS0, MC13783_INTERRUPT_STATUS1 }; | 44 | { MC13783_INTERRUPT_STATUS0, MC13783_INTERRUPT_STATUS1 }; |
49 | 45 | ||
50 | #ifdef PMIC_DRIVER_CLOSE | 46 | static volatile unsigned int mc13783_thread_id = 0; |
51 | static bool pmic_close = false; | ||
52 | static unsigned int mc13783_thread_id = 0; | ||
53 | #endif | ||
54 | 47 | ||
55 | static void mc13783_interrupt_thread(void) | 48 | static void mc13783_interrupt_thread(void) |
56 | { | 49 | { |
@@ -65,10 +58,8 @@ static void mc13783_interrupt_thread(void) | |||
65 | 58 | ||
66 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); | 59 | wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); |
67 | 60 | ||
68 | #ifdef PMIC_DRIVER_CLOSE | 61 | if (mc13783_thread_id == 0) |
69 | if (pmic_close) | ||
70 | break; | 62 | break; |
71 | #endif | ||
72 | 63 | ||
73 | mc13783_read_regset(pmic_ints_regs, pending, 2); | 64 | mc13783_read_regset(pmic_ints_regs, pending, 2); |
74 | 65 | ||
@@ -107,9 +98,7 @@ static void mc13783_interrupt_thread(void) | |||
107 | while (++event < event_last); | 98 | while (++event < event_last); |
108 | } | 99 | } |
109 | 100 | ||
110 | #ifdef PMIC_DRIVER_CLOSE | ||
111 | gpio_disable_event(MC13783_EVENT_ID); | 101 | gpio_disable_event(MC13783_EVENT_ID); |
112 | #endif | ||
113 | } | 102 | } |
114 | 103 | ||
115 | /* GPIO interrupt handler for mc13783 */ | 104 | /* GPIO interrupt handler for mc13783 */ |
@@ -136,15 +125,12 @@ void mc13783_init(void) | |||
136 | 125 | ||
137 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); | 126 | MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); |
138 | 127 | ||
139 | #ifdef PMIC_DRIVER_CLOSE | ||
140 | mc13783_thread_id = | 128 | mc13783_thread_id = |
141 | #endif | ||
142 | create_thread(mc13783_interrupt_thread, | 129 | create_thread(mc13783_interrupt_thread, |
143 | mc13783_thread_stack, sizeof(mc13783_thread_stack), 0, | 130 | mc13783_thread_stack, sizeof(mc13783_thread_stack), 0, |
144 | mc13783_thread_name IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); | 131 | mc13783_thread_name IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); |
145 | } | 132 | } |
146 | 133 | ||
147 | #ifdef PMIC_DRIVER_CLOSE | ||
148 | void mc13783_close(void) | 134 | void mc13783_close(void) |
149 | { | 135 | { |
150 | unsigned int thread_id = mc13783_thread_id; | 136 | unsigned int thread_id = mc13783_thread_id; |
@@ -153,12 +139,9 @@ void mc13783_close(void) | |||
153 | return; | 139 | return; |
154 | 140 | ||
155 | mc13783_thread_id = 0; | 141 | mc13783_thread_id = 0; |
156 | |||
157 | pmic_close = true; | ||
158 | wakeup_signal(&mc13783_wake); | 142 | wakeup_signal(&mc13783_wake); |
159 | thread_wait(thread_id); | 143 | thread_wait(thread_id); |
160 | } | 144 | } |
161 | #endif /* PMIC_DRIVER_CLOSE */ | ||
162 | 145 | ||
163 | bool mc13783_enable_event(enum mc13783_event_ids id) | 146 | bool mc13783_enable_event(enum mc13783_event_ids id) |
164 | { | 147 | { |
diff --git a/firmware/target/arm/imx31/rolo_restart.S b/firmware/target/arm/imx31/rolo_restart_firmware.S index 902f513f62..5f24f653e0 100644 --- a/firmware/target/arm/imx31/rolo_restart.S +++ b/firmware/target/arm/imx31/rolo_restart_firmware.S | |||
@@ -9,7 +9,7 @@ | |||
9 | * | 9 | * |
10 | * Copyright (C) 2008 by Michael Sevakis | 10 | * Copyright (C) 2008 by Michael Sevakis |
11 | * | 11 | * |
12 | * RoLo restart code for IMX31 | 12 | * RoLo firmware restart code for IMX31 |
13 | * | 13 | * |
14 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
15 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
@@ -24,13 +24,13 @@ | |||
24 | #include "cpu.h" | 24 | #include "cpu.h" |
25 | 25 | ||
26 | /**************************************************************************** | 26 | /**************************************************************************** |
27 | * void rolo_restart(const unsigned char* source, unsigned char* dest, | 27 | * void rolo_restart_firmware(const unsigned char* source, unsigned char* dest, |
28 | * int length) __attribute__((noreturn)); | 28 | * int length) __attribute__((noreturn)); |
29 | */ | 29 | */ |
30 | .section .text, "ax", %progbits | 30 | .section .text, "ax", %progbits |
31 | .align 2 | 31 | .align 2 |
32 | .global rolo_restart | 32 | .global rolo_restart_firmware |
33 | rolo_restart: | 33 | rolo_restart_firmware: |
34 | adr r4, restart_copy_start | 34 | adr r4, restart_copy_start |
35 | adr r5, restart_copy_end | 35 | adr r5, restart_copy_end |
36 | ldr r6, =IRAM_BASE_ADDR | 36 | ldr r6, =IRAM_BASE_ADDR |
diff --git a/firmware/target/arm/imx31/sdma-imx31.c b/firmware/target/arm/imx31/sdma-imx31.c index 6f715ebb3f..40a43f8121 100644 --- a/firmware/target/arm/imx31/sdma-imx31.c +++ b/firmware/target/arm/imx31/sdma-imx31.c | |||
@@ -533,7 +533,7 @@ void sdma_init(void) | |||
533 | /* 32-word channel contexts, use default bootscript address */ | 533 | /* 32-word channel contexts, use default bootscript address */ |
534 | SDMA_CHN0ADDR = SDMA_CHN0ADDR_SMSZ | 0x0050; | 534 | SDMA_CHN0ADDR = SDMA_CHN0ADDR_SMSZ | 0x0050; |
535 | 535 | ||
536 | avic_enable_int(INT_SDMA, INT_TYPE_IRQ, INT_PRIO_DEFAULT+1, SDMA_HANDLER); | 536 | avic_enable_int(INT_SDMA, INT_TYPE_IRQ, INT_PRIO_SDMA, SDMA_HANDLER); |
537 | 537 | ||
538 | /* SDMA core must run at the proper frequency based upon the AHB/IPG | 538 | /* SDMA core must run at the proper frequency based upon the AHB/IPG |
539 | * ratio */ | 539 | * ratio */ |