summaryrefslogtreecommitdiff
path: root/firmware/target/arm/imx31/dvfs_dptc-imx31.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/imx31/dvfs_dptc-imx31.c')
-rw-r--r--firmware/target/arm/imx31/dvfs_dptc-imx31.c41
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? */
72unsigned int dvfs_nr_dn = 0; 72unsigned int dvfs_nr_dn = 0;
73unsigned int dvfs_nr_up = 0; 73unsigned int dvfs_nr_up = 0;
74unsigned int dvfs_nr_pnc = 0; 74unsigned int dvfs_nr_pnc = 0;
75unsigned int dvfs_nr_no = 0;
75 76
76static void dvfs_stop(void); 77static 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
86static void do_dvfs_update(unsigned int level) 87static 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)
230static __attribute__((naked, interrupt("IRQ"))) void CCM_DVFS_HANDLER(void) 241static __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? */
379unsigned int dptc_nr_dn = 0; 390unsigned int dptc_nr_dn = 0;
380unsigned int dptc_nr_up = 0; 391unsigned int dptc_nr_up = 0;
381unsigned int dptc_nr_pnc = 0; 392unsigned int dptc_nr_pnc = 0;
393unsigned int dptc_nr_no = 0;
382 394
383static struct spi_transfer_desc dptc_pmic_xfer; /* Transfer descriptor */ 395static struct spi_transfer_desc dptc_pmic_xfer; /* Transfer descriptor */
384static const unsigned char dptc_pmic_regs[2] = /* Register subaddresses */ 396static 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 */
493static __attribute__((interrupt("IRQ"))) void CCM_CLK_HANDLER(void) 505static __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