00001
00041 #include <assert.h>
00042 #include <interrupt.h>
00043 #include <io.h>
00044 #include <status-codes.h>
00045 #include <timeout.h>
00046 #include <chip/clk.h>
00047
00048 #ifndef CONFIG_PLL_STARTUP_CYCLES
00049 # define CONFIG_PLL_STARTUP_CYCLES 63
00050 #endif
00051
00052 #define PLL_TIMEOUT_MS \
00053 div_ceil(1000 * (CONFIG_PLL_STARTUP_CYCLES * 2), \
00054 PM_RCOSC_MIN_RATE)
00055
00056 static int8_t osc_count[PM_NR_OSCS];
00057 static int8_t pll_count[PM_NR_PLLS];
00058
00059 #if !defined(CONFIG_CLK_OSC0_MAIN)
00060 unsigned long main_clock_rate = BOARD_OSC0_HZ;
00061
00066 void pm_priv_set_main_clock(enum pm_mainclk_src source,
00067 unsigned long rate)
00068 {
00069 uint32_t mcctrl;
00070 unsigned long iflags;
00071
00072 assert(!(PM_MCCTRL_MCSEL(source) & ~PM_MCCTRL_MCSEL_MASK));
00073
00074 iflags = cpu_irq_save();
00075 mcctrl = pm_read_reg(MCCTRL);
00076 mcctrl &= ~PM_MCCTRL_MCSEL_MASK;
00077 mcctrl |= PM_MCCTRL_MCSEL(source);
00078 pm_write_reg(MCCTRL, mcctrl);
00079 pm_read_reg(MCCTRL);
00080
00081 main_clock_rate = rate;
00082 cpu_irq_restore(iflags);
00083 }
00084 #endif
00085
00086 int pm_enable_pll_sync(unsigned int id)
00087 {
00088 struct timeout timeout;
00089
00090 assert(id < ARRAY_LEN(pll_count));
00091 assert(cpu_irq_is_enabled());
00092
00093
00094 cpu_irq_disable();
00095 assert(pll_count[id] >= 0);
00096 if (pll_count[id]++ == 0) {
00097 uint32_t pllctrl;
00098
00099 pllctrl = pm_read_reg(PLL(id));
00100 pllctrl |= PM_PLL_PLLEN;
00101 pm_write_reg(PLL(id), pllctrl);
00102 }
00103 cpu_irq_enable();
00104
00105
00106 if (pm_read_reg(POSCSR) & PM_LOCK(id))
00107 return STATUS_OK;
00108
00109
00110 timeout_init_ms(&timeout, PLL_TIMEOUT_MS);
00111 do {
00112 if (pm_read_reg(POSCSR) & PM_LOCK(id))
00113 return STATUS_OK;
00114 } while (!timeout_has_expired(&timeout));
00115
00116 return -STATUS_TIMEOUT;
00117 }
00118
00119 unsigned long pm_init_pll(unsigned int id, enum pm_pll_src source,
00120 unsigned int div, unsigned int mul,
00121 unsigned long flags)
00122 {
00123 uint32_t pllctrl;
00124 unsigned long rate;
00125
00126
00127 assert(id < PM_NR_PLLS);
00128 assert(source < 2);
00129 assert(div > 0 && div < 256);
00130 assert(mul > 1 && mul < 256);
00131 assert(!(pm_read_reg(PLL(id)) & PM_PLL_PLLEN));
00132
00133
00134 rate = (pm_priv_get_pll_src_rate(source) + div / 2) / div;
00135 rate *= mul;
00136
00137
00138 pllctrl = PM_PLL_PLLOSC(source);
00139 pllctrl |= flags;
00140 if (PM_VERSION < PM_MKVERSION(3, 0, 0))
00141 mul--;
00142 if (PM_VERSION < PM_MKVERSION(2, 0, 0))
00143 div--;
00144
00145 pllctrl |= PM_PLL_PLLDIV(div);
00146 pllctrl |= PM_PLL_PLLMUL(mul);
00147 pllctrl |= PM_PLL_PLLCOUNT(CONFIG_PLL_STARTUP_CYCLES);
00148 pllctrl |= pm_priv_pll_rate_opt(rate);
00149 pm_write_reg(PLL(id), pllctrl);
00150
00151 if (flags & PM_PLL_OUTPUT_DIV_BY_2)
00152 rate = (rate + 1) / 2;
00153
00154 return rate;
00155 }
00156
00157 unsigned long pm_get_pll_rate(unsigned int id)
00158 {
00159 uint32_t pllctrl;
00160 unsigned long rate;
00161 unsigned int source;
00162 unsigned int mul;
00163 unsigned int div;
00164
00165 pllctrl = pm_read_reg(PLL(id));
00166 if (!(pllctrl & PM_PLL_PLLEN))
00167 return 0;
00168
00169 source = PM_PLL_GET_PLLOSC(pllctrl);
00170 mul = PM_PLL_GET_PLLMUL(pllctrl);
00171 div = PM_PLL_GET_PLLDIV(pllctrl);
00172
00173 if (PM_VERSION < PM_MKVERSION(2, 0, 0))
00174 div++;
00175 if (PM_VERSION < PM_MKVERSION(3, 0, 0))
00176 mul++;
00177
00178 rate = (pm_priv_get_pll_src_rate(source) + div / 2) / div;
00179 rate *= mul;
00180 if (pllctrl & PM_PLL_OUTPUT_DIV_BY_2)
00181 rate = (rate + 1) / 2;
00182
00183 return rate;
00184 }
00185
00186 int pm_priv_enable_osc_sync(unsigned int index, unsigned long startup_us)
00187 {
00188 struct timeout timeout;
00189
00190 assert(index < ARRAY_LEN(osc_count));
00191 assert(cpu_irq_is_enabled());
00192
00193
00194 cpu_irq_disable();
00195 assert(osc_count[index] >= 0);
00196 if (osc_count[index]++ == 0) {
00197 uint32_t mcctrl;
00198
00199 mcctrl = pm_read_reg(MCCTRL);
00200 mcctrl |= PM_MCCTRL_OSCEN(index);
00201 pm_write_reg(MCCTRL, mcctrl);
00202 }
00203 cpu_irq_enable();
00204
00205
00206 if (pm_read_reg(POSCSR) & PM_OSCRDY(index))
00207 return STATUS_OK;
00208
00209
00210 timeout_init_us(&timeout, startup_us * 2 + 100);
00211 do {
00212 if (pm_read_reg(POSCSR) & PM_OSCRDY(index))
00213 return STATUS_OK;
00214 } while (!timeout_has_expired(&timeout));
00215
00216 return -STATUS_TIMEOUT;
00217 }