diff options
Diffstat (limited to 'firmware/target/arm/imx31/dvfs_dptc-imx31.c')
-rw-r--r-- | firmware/target/arm/imx31/dvfs_dptc-imx31.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/firmware/target/arm/imx31/dvfs_dptc-imx31.c b/firmware/target/arm/imx31/dvfs_dptc-imx31.c index 680b015c81..cae9a384c9 100644 --- a/firmware/target/arm/imx31/dvfs_dptc-imx31.c +++ b/firmware/target/arm/imx31/dvfs_dptc-imx31.c | |||
@@ -72,6 +72,7 @@ static bool dvfs_running = false; /* Has driver enabled DVFS? */ | |||
72 | unsigned int dvfs_nr_dn = 0; | 72 | unsigned int dvfs_nr_dn = 0; |
73 | unsigned int dvfs_nr_up = 0; | 73 | 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 | 76 | ||
76 | static void dvfs_stop(void); | 77 | static void dvfs_stop(void); |
77 | 78 | ||
@@ -83,7 +84,7 @@ static inline void wait_for_dvfs_update_en(void) | |||
83 | } | 84 | } |
84 | 85 | ||
85 | 86 | ||
86 | static void do_dvfs_update(unsigned int level) | 87 | static void do_dvfs_update(unsigned int level, bool in_isr) |
87 | { | 88 | { |
88 | const struct dvfs_clock_table_entry *setting = &dvfs_clock_table[level]; | 89 | const struct dvfs_clock_table_entry *setting = &dvfs_clock_table[level]; |
89 | unsigned long pmcr0 = CCM_PMCR0; | 90 | unsigned long pmcr0 = CCM_PMCR0; |
@@ -96,7 +97,7 @@ static void do_dvfs_update(unsigned int level) | |||
96 | 97 | ||
97 | pmcr0 &= ~CCM_PMCR0_VSCNT; | 98 | pmcr0 &= ~CCM_PMCR0_VSCNT; |
98 | 99 | ||
99 | if (level > ((pmcr0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS)) | 100 | if (level < ((pmcr0 & CCM_PMCR0_DVSUP) >> CCM_PMCR0_DVSUP_POS)) |
100 | { | 101 | { |
101 | pmcr0 |= CCM_PMCR0_UDSC; /* Up scaling, increase */ | 102 | pmcr0 |= CCM_PMCR0_UDSC; /* Up scaling, increase */ |
102 | pmcr0 |= setting->vscnt << CCM_PMCR0_VSCNT_POS; | 103 | pmcr0 |= setting->vscnt << CCM_PMCR0_VSCNT_POS; |
@@ -126,7 +127,15 @@ static void do_dvfs_update(unsigned int level) | |||
126 | } | 127 | } |
127 | 128 | ||
128 | CCM_PMCR0 = pmcr0; | 129 | CCM_PMCR0 = pmcr0; |
130 | /* Note: changes to frequency with ints unmaked seem to cause spurious | ||
131 | * DVFS interrupts with value CCM_PMCR0_FSVAI_NO_INT. These aren't | ||
132 | * supposed to happen. Only do the lengthy delay with them enabled iff | ||
133 | * called from the IRQ handler. */ | ||
134 | if (in_isr) | ||
135 | enable_irq(); | ||
129 | udelay(100); /* Software wait for voltage ramp-up */ | 136 | udelay(100); /* Software wait for voltage ramp-up */ |
137 | if (in_isr) | ||
138 | disable_irq(); | ||
130 | CCM_PDR0 = setting->pdr_val; | 139 | CCM_PDR0 = setting->pdr_val; |
131 | 140 | ||
132 | if (!(pmcr0 & CCM_PMCR0_DFSUP_POST_DIVIDERS)) | 141 | if (!(pmcr0 & CCM_PMCR0_DFSUP_POST_DIVIDERS)) |
@@ -160,7 +169,7 @@ static void set_current_dvfs_level(unsigned int level) | |||
160 | 169 | ||
161 | wait_for_dvfs_update_en(); | 170 | wait_for_dvfs_update_en(); |
162 | 171 | ||
163 | do_dvfs_update(level); | 172 | do_dvfs_update(level, false); |
164 | 173 | ||
165 | wait_for_dvfs_update_en(); | 174 | wait_for_dvfs_update_en(); |
166 | 175 | ||
@@ -191,7 +200,8 @@ static void __attribute__((used)) dvfs_int(void) | |||
191 | 200 | ||
192 | /* Upon the DECREASE event, the frequency will be changed to the next | 201 | /* Upon the DECREASE event, the frequency will be changed to the next |
193 | * higher state index. */ | 202 | * higher state index. */ |
194 | level++; | 203 | while (((1u << ++level) & DVFS_LEVEL_MASK) == 0); |
204 | |||
195 | dvfs_nr_dn++; | 205 | dvfs_nr_dn++; |
196 | break; | 206 | break; |
197 | 207 | ||
@@ -202,7 +212,8 @@ static void __attribute__((used)) dvfs_int(void) | |||
202 | 212 | ||
203 | /* Upon the INCREASE event, the frequency will be changed to the next | 213 | /* Upon the INCREASE event, the frequency will be changed to the next |
204 | * lower state index. */ | 214 | * lower state index. */ |
205 | level--; | 215 | while (((1u << --level) & DVFS_LEVEL_MASK) == 0); |
216 | |||
206 | dvfs_nr_up++; | 217 | dvfs_nr_up++; |
207 | break; | 218 | break; |
208 | 219 | ||
@@ -218,11 +229,11 @@ static void __attribute__((used)) dvfs_int(void) | |||
218 | break; | 229 | break; |
219 | 230 | ||
220 | case CCM_PMCR0_FSVAI_NO_INT: | 231 | case CCM_PMCR0_FSVAI_NO_INT: |
221 | default: | 232 | dvfs_nr_no++; |
222 | return; /* Do nothing. Freq change is not required */ | 233 | return; /* Do nothing. Freq change is not required */ |
223 | } /* end switch */ | 234 | } /* end switch */ |
224 | 235 | ||
225 | do_dvfs_update(level); | 236 | do_dvfs_update(level, true); |
226 | } | 237 | } |
227 | 238 | ||
228 | 239 | ||
@@ -230,9 +241,9 @@ static void __attribute__((used)) dvfs_int(void) | |||
230 | static __attribute__((naked, interrupt("IRQ"))) void CCM_DVFS_HANDLER(void) | 241 | static __attribute__((naked, interrupt("IRQ"))) void CCM_DVFS_HANDLER(void) |
231 | { | 242 | { |
232 | /* Audio can glitch with the long udelay if nested IRQ isn't allowed. */ | 243 | /* Audio can glitch with the long udelay if nested IRQ isn't allowed. */ |
233 | AVIC_NESTED_NI_CALL_PROLOGUE(INT_PRIO_DVFS); | 244 | AVIC_NESTED_NI_CALL_PROLOGUE(INT_PRIO_DVFS, 32*4); |
234 | asm volatile ("bl dvfs_int"); | 245 | asm volatile ("bl dvfs_int"); |
235 | AVIC_NESTED_NI_CALL_EPILOGUE(); | 246 | AVIC_NESTED_NI_CALL_EPILOGUE(32*4); |
236 | } | 247 | } |
237 | 248 | ||
238 | 249 | ||
@@ -281,7 +292,7 @@ static void dvfs_init(void) | |||
281 | imx31_regmod32(&CCM_LTR0, | 292 | imx31_regmod32(&CCM_LTR0, |
282 | DVFS_UPTHR << CCM_LTR0_UPTHR_POS | | 293 | DVFS_UPTHR << CCM_LTR0_UPTHR_POS | |
283 | DVFS_DNTHR << CCM_LTR0_DNTHR_POS | | 294 | DVFS_DNTHR << CCM_LTR0_DNTHR_POS | |
284 | DVFS_DIV3CK, | 295 | DVFS_DIV3CK << CCM_LTR0_DIV3CK_POS, |
285 | CCM_LTR0_UPTHR | CCM_LTR0_DNTHR | CCM_LTR0_DIV3CK); | 296 | CCM_LTR0_UPTHR | CCM_LTR0_DNTHR | CCM_LTR0_DIV3CK); |
286 | 297 | ||
287 | /* Set up LTR1. */ | 298 | /* Set up LTR1. */ |
@@ -356,7 +367,7 @@ static void dvfs_stop(void) | |||
356 | { | 367 | { |
357 | /* Set default frequency level */ | 368 | /* Set default frequency level */ |
358 | wait_for_dvfs_update_en(); | 369 | wait_for_dvfs_update_en(); |
359 | do_dvfs_update(DVFS_LEVEL_DEFAULT); | 370 | do_dvfs_update(DVFS_LEVEL_DEFAULT, false); |
360 | wait_for_dvfs_update_en(); | 371 | wait_for_dvfs_update_en(); |
361 | } | 372 | } |
362 | 373 | ||
@@ -379,6 +390,7 @@ static bool dptc_running = false; /* Has driver enabled DPTC? */ | |||
379 | unsigned int dptc_nr_dn = 0; | 390 | unsigned int dptc_nr_dn = 0; |
380 | unsigned int dptc_nr_up = 0; | 391 | unsigned int dptc_nr_up = 0; |
381 | unsigned int dptc_nr_pnc = 0; | 392 | unsigned int dptc_nr_pnc = 0; |
393 | unsigned int dptc_nr_no = 0; | ||
382 | 394 | ||
383 | static struct spi_transfer_desc dptc_pmic_xfer; /* Transfer descriptor */ | 395 | static struct spi_transfer_desc dptc_pmic_xfer; /* Transfer descriptor */ |
384 | static const unsigned char dptc_pmic_regs[2] = /* Register subaddresses */ | 396 | static const unsigned char dptc_pmic_regs[2] = /* Register subaddresses */ |
@@ -492,7 +504,12 @@ static void dptc_new_wp(unsigned int wp) | |||
492 | /* Interrupt vector for DPTC */ | 504 | /* Interrupt vector for DPTC */ |
493 | static __attribute__((interrupt("IRQ"))) void CCM_CLK_HANDLER(void) | 505 | static __attribute__((interrupt("IRQ"))) void CCM_CLK_HANDLER(void) |
494 | { | 506 | { |
495 | dptc_int(CCM_PMCR0); | 507 | unsigned long pmcr0 = CCM_PMCR0; |
508 | |||
509 | if ((pmcr0 & CCM_PMCR0_PTVAI) == CCM_PMCR0_PTVAI_NO_INT) | ||
510 | dptc_nr_no++; | ||
511 | |||
512 | dptc_int(pmcr0); | ||
496 | } | 513 | } |
497 | 514 | ||
498 | 515 | ||