|
@@ -26,6 +26,8 @@ static void mxs_power_clock2xtal(void)
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
|
|
+ debug("SPL: Switching CPU clock to 24MHz XTAL\n");
|
|
|
+
|
|
|
/* Set XTAL as CPU reference clock */
|
|
|
writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
|
|
|
&clkctrl_regs->hw_clkctrl_clkseq_set);
|
|
@@ -43,9 +45,23 @@ static void mxs_power_clock2pll(void)
|
|
|
struct mxs_clkctrl_regs *clkctrl_regs =
|
|
|
(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
|
|
|
|
|
|
+ debug("SPL: Switching CPU core clock source to PLL\n");
|
|
|
+
|
|
|
+ /*
|
|
|
+ * TODO: Are we really? It looks like we turn on PLL0, but we then
|
|
|
+ * set the CLKCTRL_CLKSEQ_BYPASS_CPU bit of the (which was already
|
|
|
+ * set by mxs_power_clock2xtal()). Clearing this bit here seems to
|
|
|
+ * introduce some instability (causing the CPU core to hang). Maybe
|
|
|
+ * we aren't giving PLL0 enough time to stabilise?
|
|
|
+ */
|
|
|
setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0,
|
|
|
CLKCTRL_PLL0CTRL0_POWER);
|
|
|
early_delay(100);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * TODO: Should the PLL0 FORCE_LOCK bit be set here followed be a
|
|
|
+ * wait on the PLL0 LOCK bit?
|
|
|
+ */
|
|
|
setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq,
|
|
|
CLKCTRL_CLKSEQ_BYPASS_CPU);
|
|
|
}
|
|
@@ -62,6 +78,8 @@ static void mxs_power_set_auto_restart(void)
|
|
|
struct mxs_rtc_regs *rtc_regs =
|
|
|
(struct mxs_rtc_regs *)MXS_RTC_BASE;
|
|
|
|
|
|
+ debug("SPL: Setting auto-restart bit\n");
|
|
|
+
|
|
|
writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr);
|
|
|
while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST)
|
|
|
;
|
|
@@ -101,14 +119,17 @@ static void mxs_power_set_linreg(void)
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
/* Set linear regulator 25mV below switching converter */
|
|
|
+ debug("SPL: Setting VDDD 25mV below DC-DC converters\n");
|
|
|
clrsetbits_le32(&power_regs->hw_power_vdddctrl,
|
|
|
POWER_VDDDCTRL_LINREG_OFFSET_MASK,
|
|
|
POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
|
|
|
|
|
|
+ debug("SPL: Setting VDDA 25mV below DC-DC converters\n");
|
|
|
clrsetbits_le32(&power_regs->hw_power_vddactrl,
|
|
|
POWER_VDDACTRL_LINREG_OFFSET_MASK,
|
|
|
POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW);
|
|
|
|
|
|
+ debug("SPL: Setting VDDIO 25mV below DC-DC converters\n");
|
|
|
clrsetbits_le32(&power_regs->hw_power_vddioctrl,
|
|
|
POWER_VDDIOCTRL_LINREG_OFFSET_MASK,
|
|
|
POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW);
|
|
@@ -127,6 +148,8 @@ static int mxs_get_batt_volt(void)
|
|
|
volt &= POWER_BATTMONITOR_BATT_VAL_MASK;
|
|
|
volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET;
|
|
|
volt *= 8;
|
|
|
+
|
|
|
+ debug("SPL: Battery Voltage = %dmV\n", volt);
|
|
|
return volt;
|
|
|
}
|
|
|
|
|
@@ -154,8 +177,10 @@ static int mxs_is_batt_good(void)
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
uint32_t volt = mxs_get_batt_volt();
|
|
|
|
|
|
- if ((volt >= 2400) && (volt <= 4300))
|
|
|
+ if ((volt >= 2400) && (volt <= 4300)) {
|
|
|
+ debug("SPL: Battery is good\n");
|
|
|
return 1;
|
|
|
+ }
|
|
|
|
|
|
clrsetbits_le32(&power_regs->hw_power_5vctrl,
|
|
|
POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK,
|
|
@@ -175,16 +200,21 @@ static int mxs_is_batt_good(void)
|
|
|
|
|
|
volt = mxs_get_batt_volt();
|
|
|
|
|
|
- if (volt >= 3500)
|
|
|
+ if (volt >= 3500) {
|
|
|
+ debug("SPL: Battery Voltage too high\n");
|
|
|
return 0;
|
|
|
+ }
|
|
|
|
|
|
- if (volt >= 2400)
|
|
|
+ if (volt >= 2400) {
|
|
|
+ debug("SPL: Battery is good\n");
|
|
|
return 1;
|
|
|
+ }
|
|
|
|
|
|
writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK,
|
|
|
&power_regs->hw_power_charge_clr);
|
|
|
writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set);
|
|
|
|
|
|
+ debug("SPL: Battery Voltage too low\n");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -203,6 +233,7 @@ static void mxs_power_setup_5v_detect(void)
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
/* Start 5V detection */
|
|
|
+ debug("SPL: Starting 5V input detection comparator\n");
|
|
|
clrsetbits_le32(&power_regs->hw_power_5vctrl,
|
|
|
POWER_5VCTRL_VBUSVALID_TRSH_MASK,
|
|
|
POWER_5VCTRL_VBUSVALID_TRSH_4V4 |
|
|
@@ -220,6 +251,8 @@ static void mxs_src_power_init(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Pre-Configuring power block\n");
|
|
|
+
|
|
|
/* Improve efficieny and reduce transient ripple */
|
|
|
writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST |
|
|
|
POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set);
|
|
@@ -257,6 +290,8 @@ static void mxs_power_init_4p2_params(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Configuring common 4P2 regulator params\n");
|
|
|
+
|
|
|
/* Setup 4P2 parameters */
|
|
|
clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
|
|
|
POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK,
|
|
@@ -289,6 +324,8 @@ static void mxs_enable_4p2_dcdc_input(int xfer)
|
|
|
uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo;
|
|
|
uint32_t prev_5v_brnout, prev_5v_droop;
|
|
|
|
|
|
+ debug("SPL: %s 4P2 DC-DC Input\n", xfer ? "Enabling" : "Disabling");
|
|
|
+
|
|
|
prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) &
|
|
|
POWER_5VCTRL_PWDN_5VBRNOUT;
|
|
|
prev_5v_droop = readl(&power_regs->hw_power_ctrl) &
|
|
@@ -390,6 +427,8 @@ static void mxs_power_init_4p2_regulator(void)
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
uint32_t tmp, tmp2;
|
|
|
|
|
|
+ debug("SPL: Enabling 4P2 regulator\n");
|
|
|
+
|
|
|
setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2);
|
|
|
|
|
|
writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set);
|
|
@@ -407,6 +446,7 @@ static void mxs_power_init_4p2_regulator(void)
|
|
|
* gradually to avoid large inrush current from the 5V cable which can
|
|
|
* cause transients/problems
|
|
|
*/
|
|
|
+ debug("SPL: Charging 4P2 capacitor\n");
|
|
|
mxs_enable_4p2_dcdc_input(0);
|
|
|
|
|
|
if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) {
|
|
@@ -420,6 +460,8 @@ static void mxs_power_init_4p2_regulator(void)
|
|
|
POWER_DCDC4P2_ENABLE_DCDC);
|
|
|
writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK,
|
|
|
&power_regs->hw_power_5vctrl_set);
|
|
|
+
|
|
|
+ debug("SPL: Unable to recover from mx23 errata 5837\n");
|
|
|
hang();
|
|
|
}
|
|
|
|
|
@@ -433,6 +475,7 @@ static void mxs_power_init_4p2_regulator(void)
|
|
|
* current limit until the brownout status is false or until we've
|
|
|
* reached our maximum defined 4p2 current limit.
|
|
|
*/
|
|
|
+ debug("SPL: Setting 4P2 brownout level\n");
|
|
|
clrsetbits_le32(&power_regs->hw_power_dcdc4p2,
|
|
|
POWER_DCDC4P2_BO_MASK,
|
|
|
22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */
|
|
@@ -479,8 +522,11 @@ static void mxs_power_init_dcdc_4p2_source(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Switching DC-DC converters to 4P2\n");
|
|
|
+
|
|
|
if (!(readl(&power_regs->hw_power_dcdc4p2) &
|
|
|
POWER_DCDC4P2_ENABLE_DCDC)) {
|
|
|
+ debug("SPL: Already switched - aborting\n");
|
|
|
hang();
|
|
|
}
|
|
|
|
|
@@ -509,6 +555,8 @@ static void mxs_power_enable_4p2(void)
|
|
|
uint32_t vdddctrl, vddactrl, vddioctrl;
|
|
|
uint32_t tmp;
|
|
|
|
|
|
+ debug("SPL: Powering up 4P2 regulator\n");
|
|
|
+
|
|
|
vdddctrl = readl(&power_regs->hw_power_vdddctrl);
|
|
|
vddactrl = readl(&power_regs->hw_power_vddactrl);
|
|
|
vddioctrl = readl(&power_regs->hw_power_vddioctrl);
|
|
@@ -559,6 +607,8 @@ static void mxs_power_enable_4p2(void)
|
|
|
if (tmp)
|
|
|
writel(POWER_CHARGE_ENABLE_LOAD,
|
|
|
&power_regs->hw_power_charge_clr);
|
|
|
+
|
|
|
+ debug("SPL: 4P2 regulator powered-up\n");
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -574,6 +624,8 @@ static void mxs_boot_valid_5v(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Booting from 5V supply\n");
|
|
|
+
|
|
|
/*
|
|
|
* Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V
|
|
|
* disconnect event. FIXME
|
|
@@ -601,6 +653,9 @@ static void mxs_powerdown(void)
|
|
|
{
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
+
|
|
|
+ debug("Powering Down\n");
|
|
|
+
|
|
|
writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset);
|
|
|
writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF,
|
|
|
&power_regs->hw_power_reset);
|
|
@@ -617,6 +672,8 @@ static void mxs_batt_boot(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Configuring power block to boot from battery\n");
|
|
|
+
|
|
|
clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT);
|
|
|
clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC);
|
|
|
|
|
@@ -672,6 +729,8 @@ static void mxs_handle_5v_conflict(void)
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
uint32_t tmp;
|
|
|
|
|
|
+ debug("SPL: Resolving 5V conflict\n");
|
|
|
+
|
|
|
setbits_le32(&power_regs->hw_power_vddioctrl,
|
|
|
POWER_VDDIOCTRL_BO_OFFSET_MASK);
|
|
|
|
|
@@ -683,19 +742,27 @@ static void mxs_handle_5v_conflict(void)
|
|
|
* VDDIO has a brownout, then the VDD5V_GT_VDDIO becomes
|
|
|
* unreliable
|
|
|
*/
|
|
|
+ debug("SPL: VDDIO has a brownout\n");
|
|
|
mxs_powerdown();
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (tmp & POWER_STS_VDD5V_GT_VDDIO) {
|
|
|
+ debug("SPL: POWER_STS_VDD5V_GT_VDDIO is set\n");
|
|
|
mxs_boot_valid_5v();
|
|
|
break;
|
|
|
} else {
|
|
|
+ debug("SPL: POWER_STS_VDD5V_GT_VDDIO is not set\n");
|
|
|
mxs_powerdown();
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * TODO: I can't see this being reached. We'll either
|
|
|
+ * powerdown or boot from a stable 5V supply.
|
|
|
+ */
|
|
|
if (tmp & POWER_STS_PSWITCH_MASK) {
|
|
|
+ debug("SPL: POWER_STS_PSWITCH_MASK is set\n");
|
|
|
mxs_batt_boot();
|
|
|
break;
|
|
|
}
|
|
@@ -713,21 +780,26 @@ static void mxs_5v_boot(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Configuring power block to boot from 5V input\n");
|
|
|
+
|
|
|
/*
|
|
|
* NOTE: In original IMX-Bootlets, this also checks for VBUSVALID,
|
|
|
* but their implementation always returns 1 so we omit it here.
|
|
|
*/
|
|
|
if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
|
|
|
+ debug("SPL: 5V VDD good\n");
|
|
|
mxs_boot_valid_5v();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
early_delay(1000);
|
|
|
if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
|
|
|
+ debug("SPL: 5V VDD good (after delay)\n");
|
|
|
mxs_boot_valid_5v();
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ debug("SPL: 5V VDD not good\n");
|
|
|
mxs_handle_5v_conflict();
|
|
|
}
|
|
|
|
|
@@ -742,6 +814,8 @@ static void mxs_init_batt_bo(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Initialising battery brown-out level to 3.0V\n");
|
|
|
+
|
|
|
/* Brownout at 3V */
|
|
|
clrsetbits_le32(&power_regs->hw_power_battmonitor,
|
|
|
POWER_BATTMONITOR_BRWNOUT_LVL_MASK,
|
|
@@ -762,6 +836,8 @@ static void mxs_switch_vddd_to_dcdc_source(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Switching VDDD to DC-DC converters\n");
|
|
|
+
|
|
|
clrsetbits_le32(&power_regs->hw_power_vdddctrl,
|
|
|
POWER_VDDDCTRL_LINREG_OFFSET_MASK,
|
|
|
POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW);
|
|
@@ -788,6 +864,8 @@ static void mxs_power_configure_power_source(void)
|
|
|
struct mxs_lradc_regs *lradc_regs =
|
|
|
(struct mxs_lradc_regs *)MXS_LRADC_BASE;
|
|
|
|
|
|
+ debug("SPL: Configuring power source\n");
|
|
|
+
|
|
|
mxs_src_power_init();
|
|
|
|
|
|
if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) {
|
|
@@ -811,6 +889,10 @@ static void mxs_power_configure_power_source(void)
|
|
|
mxs_batt_boot();
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * TODO: Do not switch CPU clock to PLL if we are VDD5V is sourced
|
|
|
+ * from USB VBUS
|
|
|
+ */
|
|
|
mxs_power_clock2pll();
|
|
|
|
|
|
mxs_init_batt_bo();
|
|
@@ -819,6 +901,7 @@ static void mxs_power_configure_power_source(void)
|
|
|
|
|
|
#ifdef CONFIG_MX23
|
|
|
/* Fire up the VDDMEM LinReg now that we're all set. */
|
|
|
+ debug("SPL: Enabling mx23 VDDMEM linear regulator\n");
|
|
|
writel(POWER_VDDMEMCTRL_ENABLE_LINREG | POWER_VDDMEMCTRL_ENABLE_ILIMIT,
|
|
|
&power_regs->hw_power_vddmemctrl);
|
|
|
#endif
|
|
@@ -838,6 +921,8 @@ static void mxs_enable_output_rail_protection(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Enabling output rail protection\n");
|
|
|
+
|
|
|
writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
|
|
|
POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr);
|
|
|
|
|
@@ -1077,6 +1162,8 @@ static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg,
|
|
|
*/
|
|
|
static void mxs_setup_batt_detect(void)
|
|
|
{
|
|
|
+ debug("SPL: Starting battery voltage measurement logic\n");
|
|
|
+
|
|
|
mxs_lradc_init();
|
|
|
mxs_lradc_enable_batt_measurement();
|
|
|
early_delay(10);
|
|
@@ -1111,6 +1198,8 @@ void mxs_power_init(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Initialising Power Block\n");
|
|
|
+
|
|
|
mxs_ungate_power();
|
|
|
|
|
|
mxs_power_clock2xtal();
|
|
@@ -1123,9 +1212,13 @@ void mxs_power_init(void)
|
|
|
mxs_power_configure_power_source();
|
|
|
mxs_enable_output_rail_protection();
|
|
|
|
|
|
+ debug("SPL: Setting VDDIO to 3V3 (brownout @ 3v15)\n");
|
|
|
mxs_power_set_vddx(&mxs_vddio_cfg, 3300, 3150);
|
|
|
+
|
|
|
+ debug("SPL: Setting VDDD to 1V5 (brownout @ 1v0)\n");
|
|
|
mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1000);
|
|
|
#ifdef CONFIG_MX23
|
|
|
+ debug("SPL: Setting mx23 VDDMEM to 2V5 (brownout @ 1v7)\n");
|
|
|
mxs_power_set_vddx(&mxs_vddmem_cfg, 2500, 1700);
|
|
|
#endif
|
|
|
writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ |
|
|
@@ -1150,6 +1243,7 @@ void mxs_power_wait_pswitch(void)
|
|
|
struct mxs_power_regs *power_regs =
|
|
|
(struct mxs_power_regs *)MXS_POWER_BASE;
|
|
|
|
|
|
+ debug("SPL: Waiting for power switch input\n");
|
|
|
while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK))
|
|
|
;
|
|
|
}
|