struct imx233_dcp_info_t imx233_dcp_get_info(unsigned flags) { struct imx233_dcp_info_t info; memset(&info, 0, sizeof(info)); if(flags & DCP_INFO_CAPABILITIES) { info.has_crypto = HW_DCP_CTRL & HW_DCP_CTRL__PRESENT_CRYPTO; info.has_csc = HW_DCP_CTRL & HW_DCP_CTRL__PRESENT_CSC; info.num_keys = __XTRACT(HW_DCP_CAPABILITY0, NUM_KEYS); info.num_channels = __XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS); info.ciphers = __XTRACT(HW_DCP_CAPABILITY1, CIPHER_ALGORITHMS); info.hashs = __XTRACT(HW_DCP_CAPABILITY1, HASH_ALGORITHMS); } if(flags & DCP_INFO_GLOBAL_STATE) { info.otp_key_ready = HW_DCP_STAT & HW_DCP_STAT__OTP_KEY_READY; info.context_switching = HW_DCP_CTRL & HW_DCP_CTRL__ENABLE_CONTEXT_SWITCHING; info.context_caching = HW_DCP_CTRL & HW_DCP_CTRL__ENABLE_CONTEXT_CACHING; info.gather_writes = HW_DCP_CTRL & HW_DCP_CTRL__GATHER_RESIDUAL_WRITES; info.ch0_merged = HW_DCP_CHANNELCTRL & HW_DCP_CHANNELCTRL__CH0_IRQ_MERGED; } if(flags & DCP_INFO_CHANNELS) { for(int i = 0; i < HW_DCP_NUM_CHANNELS; i++) { info.channel[i].irq_en = HW_DCP_CTRL & HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(i); info.channel[i].irq = HW_DCP_STAT & HW_DCP_STAT__IRQ(i); info.channel[i].ready = HW_DCP_STAT & HW_DCP_STAT__READY_CHANNELS(i); info.channel[i].high_priority = HW_DCP_CHANNELCTRL & HW_DCP_CHANNELCTRL__HIGH_PRIORITY_CHANNEL(i); info.channel[i].enable = HW_DCP_CHANNELCTRL & HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(i); info.channel[i].sema = __XTRACT_EX(HW_DCP_CHxSEMA(i), HW_DCP_CHxSEMA__VALUE); info.channel[i].cmdptr = HW_DCP_CHxCMDPTR(i); info.channel[i].acquired = arbiter_acquired(&channel_arbiter, i); } } if(flags & DCP_INFO_CSC) { info.csc.irq_en = HW_DCP_CTRL & HW_DCP_CTRL__CSC_INTERRUPT_ENABLE; info.csc.irq = HW_DCP_STAT & HW_DCP_STAT__CSCIRQ; info.csc.priority = __XTRACT(HW_DCP_CHANNELCTRL, CSC_PRIORITY); info.csc.enable = HW_DCP_CSCCTRL0 & HW_DCP_CSCCTRL0__ENABLE; } return info; }
void imx233_dcp_init(void) { /* Reset block */ imx233_reset_block(&HW_DCP_CTRL); /* Setup contexte pointer */ HW_DCP_CONTEXT = (uint32_t)PHYSICAL_ADDR(&dcp_context); /* Enable context switching and caching */ __REG_SET(HW_DCP_CTRL) = HW_DCP_CTRL__ENABLE_CONTEXT_CACHING | HW_DCP_CTRL__ENABLE_CONTEXT_SWITCHING; /* Check that there are sufficiently many channels */ if(__XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS) != HW_DCP_NUM_CHANNELS) panicf("DCP has %lu channels but was configured to use %d !", __XTRACT(HW_DCP_CAPABILITY0, NUM_CHANNELS), HW_DCP_NUM_CHANNELS); /* Setup channel arbiter to use */ arbiter_init(&channel_arbiter, HW_DCP_NUM_CHANNELS); /* Merge channel0 interrupt */ __REG_SET(HW_DCP_CHANNELCTRL) = HW_DCP_CHANNELCTRL__CH0_IRQ_MERGED; /* setup semaphores */ for(int i = 0; i< HW_DCP_NUM_CHANNELS; i++) semaphore_init(&channel_sema[i], 1, 0); }
unsigned imx233_lcdif_enable_irqs(unsigned irq_bm) { unsigned old_msk = __XTRACT(HW_LCDIF_CTRL1, IRQ_EN); /* clear irq status */ __REG_CLR(HW_LCDIF_CTRL1) = irq_bm << HW_LCDIF_CTRL1__IRQ_BP; /* disable irqs */ __REG_CLR(HW_LCDIF_CTRL1) = HW_LCDIF_CTRL1__IRQ_EN_BM; /* enable irqs */ __REG_SET(HW_LCDIF_CTRL1) = irq_bm << HW_LCDIF_CTRL1__IRQ_EN_BP; return old_msk; }
int imx233_lradc_read_battery_voltage(void) { return __XTRACT(HW_LRADC_CONVERSION, SCALED_BATT_VOLTAGE); }
void charging_algorithm_step(void) { bool is_5v_present = usb_detect() == USB_INSERTED; /* initial state & 5v -> battery transition */ if(!is_5v_present && charge_state != DISCHARGING) { logf("pwrmgmt: * -> discharging"); logf("pwrmgmt: disable charger and 4p2"); /* 5V has been lost: disable 4p2 power rail */ __REG_SET(HW_POWER_CHARGE) = HW_POWER_CHARGE__PWD_BATTCHRG; __REG_CLR(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_DCDC | HW_POWER_DCDC4P2__ENABLE_4P2; __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2; charge_state = DISCHARGING; } /* battery -> 5v transition */ else if(is_5v_present && charge_state == DISCHARGING) { logf("pwrmgmt: discharging -> trickle"); logf("pwrmgmt: begin charging 4p2"); /* 5V has been detected: prepare 4.2V power rail for activation */ __REG_SET(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_4P2; __REG_SET(HW_POWER_CHARGE) = HW_POWER_CHARGE__ENABLE_LOAD; __FIELD_SET(HW_POWER_5VCTRL, CHARGE_4P2_ILIMIT, 1); __REG_CLR(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2;// FIXME: manual error ? __REG_SET(HW_POWER_DCDC4P2) = HW_POWER_DCDC4P2__ENABLE_DCDC; timeout_4p2_ilimit_increase = current_tick + HZ / 100; charge_state = TRICKLE; } else if(charge_state == TRICKLE && TIME_AFTER(current_tick, timeout_4p2_ilimit_increase)) { /* if 4.2V current limit has not reached 780mA, increase it slowly to * charge the 4.2V capacitance */ if(__XTRACT(HW_POWER_5VCTRL, CHARGE_4P2_ILIMIT) != 0x3f) { //logf("pwrmgmt: incr 4.2 ilimit"); HW_POWER_5VCTRL += 1 << HW_POWER_5VCTRL__CHARGE_4P2_ILIMIT_BP; timeout_4p2_ilimit_increase = current_tick + HZ / 100; } /* we've reached the maximum, take action */ else { logf("pwrmgmt: enable dcdc and charger"); logf("pwrmgmt: trickle -> charging"); /* adjust arbitration between 4.2 and battery */ __FIELD_SET(HW_POWER_DCDC4P2, CMPTRIP, 0); /* 85% */ __FIELD_SET(HW_POWER_DCDC4P2, DROPOUT_CTRL, 0xe); /* select greater, 200 mV drop */ __REG_CLR(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__DCDC_XFER; __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__ENABLE_DCDC; /* enable battery charging */ __REG_CLR(HW_POWER_CHARGE) = HW_POWER_CHARGE__PWD_BATTCHRG; charge_state = CHARGING; timeout_charging = current_tick + IMX233_CHARGING_TIMEOUT; } } else if(charge_state == CHARGING && TIME_AFTER(current_tick, timeout_charging)) { /* we have charged for a too long time, declare charger broken */ logf("pwrmgmt: charging timeout exceeded!"); logf("pwrmgmt: charging -> error"); /* stop charging */ __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2; /* goto error state */ charge_state = CHARGE_STATE_ERROR; } else if(charge_state == CHARGING && !(HW_POWER_STS & HW_POWER_STS__CHRGSTS)) { logf("pwrmgmt: topping off"); logf("pwrmgmt: charging -> topoff"); charge_state = TOPOFF; timeout_topping_off = current_tick + IMX233_TOPOFF_TIMEOUT; } else if(charge_state == TOPOFF && TIME_AFTER(current_tick, timeout_topping_off)) { logf("pwrmgmt: charging finished"); logf("pwrmgmt: topoff -> disabled"); /* stop charging */ __REG_SET(HW_POWER_5VCTRL) = HW_POWER_5VCTRL__PWD_CHARGE_4P2; charge_state = CHARGE_STATE_DISABLED; } }
/* Returns battery voltage from ADC [millivolts] */ int _battery_voltage(void) { /* battery value is in 8mV LSB */ return __XTRACT(HW_POWER_BATTMONITOR, BATT_VAL) * 8; }