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.c32
1 files changed, 18 insertions, 14 deletions
diff --git a/firmware/target/arm/imx31/dvfs_dptc-imx31.c b/firmware/target/arm/imx31/dvfs_dptc-imx31.c
index b78a995f87..1c4e3a923f 100644
--- a/firmware/target/arm/imx31/dvfs_dptc-imx31.c
+++ b/firmware/target/arm/imx31/dvfs_dptc-imx31.c
@@ -81,16 +81,19 @@ static inline void wait_for_dvfs_update_en(void)
81 while (!(CCM_PMCR0 & CCM_PMCR0_UPDTEN)); 81 while (!(CCM_PMCR0 & CCM_PMCR0_UPDTEN));
82} 82}
83 83
84 84/* Do the actual frequency and DVFS pin change - always call with IRQ masked */
85static void do_dvfs_update(unsigned int level, bool in_isr) 85static void do_dvfs_update(unsigned int level)
86{ 86{
87 const struct dvfs_clock_table_entry *setting = &dvfs_clock_table[level]; 87 const struct dvfs_clock_table_entry *setting = &dvfs_clock_table[level];
88 unsigned long pmcr0 = CCM_PMCR0; 88 unsigned long pmcr0 = CCM_PMCR0;
89 int oldlevel;
89 90
90 if (pmcr0 & CCM_PMCR0_DPTEN) 91 if (pmcr0 & CCM_PMCR0_DPTEN)
91 { 92 {
92 /* Ignore voltage change request from DPTC. Voltage is *not* valid. */ 93 /* Ignore voltage change request from DPTC. Voltage is *not* valid. */
93 pmcr0 &= ~CCM_PMCR0_DPVCR; 94 pmcr0 &= ~CCM_PMCR0_DPVCR;
95 /* Mask DPTC interrupt for when called in thread context */
96 pmcr0 |= CCM_PMCR0_PTVAIM;
94 } 97 }
95 98
96 pmcr0 &= ~CCM_PMCR0_VSCNT; 99 pmcr0 &= ~CCM_PMCR0_VSCNT;
@@ -127,13 +130,10 @@ static void do_dvfs_update(unsigned int level, bool in_isr)
127 CCM_PMCR0 = pmcr0; 130 CCM_PMCR0 = pmcr0;
128 /* Note: changes to frequency with ints unmaked seem to cause spurious 131 /* Note: changes to frequency with ints unmaked seem to cause spurious
129 * DVFS interrupts with value CCM_PMCR0_FSVAI_NO_INT. These aren't 132 * DVFS interrupts with value CCM_PMCR0_FSVAI_NO_INT. These aren't
130 * supposed to happen. Only do the lengthy delay with them enabled iff 133 * supposed to happen. Only do the lengthy delay with them enabled. */
131 * called from the IRQ handler. */ 134 enable_irq();
132 if (in_isr)
133 enable_irq();
134 udelay(100); /* Software wait for voltage ramp-up */ 135 udelay(100); /* Software wait for voltage ramp-up */
135 if (in_isr) 136 disable_irq();
136 disable_irq();
137 CCM_PDR0 = setting->pdr_val; 137 CCM_PDR0 = setting->pdr_val;
138 138
139 if (!(pmcr0 & CCM_PMCR0_DFSUP_POST_DIVIDERS)) 139 if (!(pmcr0 & CCM_PMCR0_DFSUP_POST_DIVIDERS))
@@ -150,9 +150,10 @@ static void do_dvfs_update(unsigned int level, bool in_isr)
150 if (pmcr0 & CCM_PMCR0_DPTEN) 150 if (pmcr0 & CCM_PMCR0_DPTEN)
151 { 151 {
152 update_dptc_counts(level, dptc_wp); 152 update_dptc_counts(level, dptc_wp);
153 /* Enable DPTC to request voltage changes. Voltage is valid. */ 153 /* Enable DPTC to request voltage changes, unmask interrupt. */
154 CCM_PMCR0 |= CCM_PMCR0_DPVCR; 154 CCM_PMCR0 = (CCM_PMCR0 & ~CCM_PMCR0_PTVAIM) | CCM_PMCR0_DPVCR;
155 udelay(2); 155 udelay(2);
156 /* Voltage is valid. */
156 CCM_PMCR0 |= CCM_PMCR0_DPVV; 157 CCM_PMCR0 |= CCM_PMCR0_DPVV;
157 } 158 }
158} 159}
@@ -167,7 +168,7 @@ static void set_current_dvfs_level(unsigned int level)
167 168
168 wait_for_dvfs_update_en(); 169 wait_for_dvfs_update_en();
169 170
170 do_dvfs_update(level, false); 171 do_dvfs_update(level);
171 172
172 wait_for_dvfs_update_en(); 173 wait_for_dvfs_update_en();
173 174
@@ -231,7 +232,7 @@ static void __attribute__((used)) dvfs_int(void)
231 return; /* Do nothing. Freq change is not required */ 232 return; /* Do nothing. Freq change is not required */
232 } /* end switch */ 233 } /* end switch */
233 234
234 do_dvfs_update(level, true); 235 do_dvfs_update(level);
235} 236}
236 237
237 238
@@ -370,7 +371,8 @@ static void dptc_transfer_done_callback(struct spi_transfer_desc *xfer)
370} 371}
371 372
372 373
373/* Handle the DPTC interrupt and sometimes the manual setting */ 374/* Handle the DPTC interrupt and sometimes the manual setting - always call
375 * with IRQ masked. */
374static void dptc_int(unsigned long pmcr0) 376static void dptc_int(unsigned long pmcr0)
375{ 377{
376 const union dvfs_dptc_voltage_table_entry *entry; 378 const union dvfs_dptc_voltage_table_entry *entry;
@@ -433,6 +435,8 @@ static void dptc_int(unsigned long pmcr0)
433} 435}
434 436
435 437
438/* Handle setting the working point explicitly - always call with IRQ
439 * masked */
436static void dptc_new_wp(unsigned int wp) 440static void dptc_new_wp(unsigned int wp)
437{ 441{
438 dptc_wp = wp; 442 dptc_wp = wp;
@@ -550,7 +554,7 @@ void dvfs_stop(void)
550 { 554 {
551 /* Set default frequency level */ 555 /* Set default frequency level */
552 wait_for_dvfs_update_en(); 556 wait_for_dvfs_update_en();
553 do_dvfs_update(DVFS_LEVEL_DEFAULT, false); 557 do_dvfs_update(DVFS_LEVEL_DEFAULT);
554 wait_for_dvfs_update_en(); 558 wait_for_dvfs_update_en();
555 } 559 }
556 560