diff --git a/bootloader/gfx/logos.h b/bootloader/gfx/logos.h index 24a8e93..ec00fc6 100644 --- a/bootloader/gfx/logos.h +++ b/bootloader/gfx/logos.h @@ -477,4 +477,61 @@ static u8 BOOTLOGO_BLZ[SZ_BOOTLOGO_BLZ] = { 0x6C, 0x23, 0x00, 0x00 }; +// 21 x 50 @8bpp RGB. +#define X_BATTERY_EMPTY 21 +#define Y_BATTERY_EMPTY_BATT 38 +#define Y_BATTERY_EMPTY_CHRG 12 +#define SZ_BATTERY_EMPTY 3150 +#define SZ_BATTERY_EMPTY_BLZ 740 +static u8 BATTERY_EMPTY_BLZ[SZ_BATTERY_EMPTY_BLZ] = +{ + 0x17, 0xC0, 0x5D, 0x51, 0x79, 0x12, 0x79, 0x48, 0x69, 0x00, 0x0D, 0x46, 0xE3, 0x0F, 0xF0, 0x20, + 0xF0, 0x35, 0x2E, 0x38, 0x3F, 0x40, 0xEF, 0xCF, 0x00, 0x89, 0x77, 0x00, 0x17, 0x01, 0x14, 0x09, + 0x90, 0x36, 0xF0, 0xA4, 0xF1, 0x62, 0x01, 0x38, 0xA1, 0x99, 0x84, 0x3E, 0x00, 0x23, 0x1F, 0x04, + 0x40, 0x3B, 0xF0, 0x5B, 0x4F, 0x00, 0x18, 0x25, 0x20, 0x24, 0x90, 0x57, 0x00, 0x3C, 0xC0, 0x7B, + 0x00, 0x63, 0x10, 0x31, 0x7C, 0x2B, 0x03, 0x30, 0x3C, 0xF0, 0xA2, 0x00, 0xCE, 0x11, 0x0F, 0x0D, + 0x21, 0x00, 0x9E, 0xDE, 0x00, 0x06, 0x40, 0x60, 0xF0, 0xB9, 0xA0, 0xEA, 0x70, 0x3C, 0xF0, 0xF5, + 0x67, 0xD4, 0x3E, 0x01, 0x54, 0x00, 0x00, 0x00, 0x57, 0x70, 0xCD, 0xB1, 0x00, 0x1E, 0xFB, 0xD9, + 0x15, 0xA0, 0xC9, 0xAE, 0x69, 0x30, 0x3C, 0xD0, 0x30, 0xF0, 0xE4, 0xC1, 0xA7, 0x18, 0x10, 0x0D, + 0x0C, 0x00, 0x49, 0x3F, 0x04, 0x00, 0x87, 0x75, 0x00, 0xC5, 0xAA, 0x2A, 0x00, 0x09, 0x40, 0xC0, + 0xD7, 0xBA, 0x24, 0x00, 0x0C, 0xA0, 0x33, 0xF0, 0xF7, 0xD6, 0x0C, 0x00, 0x9C, 0x3C, 0xA0, 0x07, + 0x06, 0x2A, 0x10, 0x7D, 0x6C, 0x00, 0xBB, 0x09, 0xA2, 0x00, 0xF3, 0xD2, 0x00, 0xE3, 0xC4, 0x0C, + 0xA0, 0x80, 0x3C, 0xF0, 0x41, 0x38, 0x05, 0x50, 0x3E, 0xF1, 0x03, 0x00, 0x01, 0x19, 0x01, 0x00, + 0x33, 0x2C, 0x00, 0x71, 0x62, 0x00, 0x00, 0xAF, 0x97, 0x00, 0xEB, 0xCB, 0x03, 0x30, 0x03, 0x30, + 0x3C, 0x40, 0xE0, 0x81, 0x70, 0x04, 0x40, 0x0F, 0xF0, 0x23, 0xF0, 0x2D, 0x27, 0x00, 0x1C, 0x6B, + 0x5D, 0x00, 0xA9, 0x92, 0x00, 0xE7, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xDC, 0x00, 0xBF, 0xA5, + 0x0E, 0xE0, 0x81, 0x0F, 0xF0, 0x19, 0xF0, 0xA5, 0x00, 0x22, 0x00, 0x65, 0x58, 0x00, 0x07, 0x67, + 0x59, 0x07, 0x70, 0x0F, 0xF0, 0x2A, 0xF0, 0x06, 0x09, 0x45, 0x10, 0x3C, 0x0A, 0x00, 0x00, 0x03, + 0x30, 0x00, 0x00, 0x49, 0x11, 0x0B, 0x47, 0x0E, 0x10, 0x0B, 0x1B, 0x06, 0x04, 0x3F, 0xF0, 0xD2, + 0xF0, 0xCD, 0x38, 0xE0, 0x85, 0xF8, 0xF7, 0x3A, 0x26, 0x75, 0x00, 0xD2, 0xF0, 0x33, 0x00, 0x27, + 0x71, 0x09, 0x06, 0x24, 0x30, 0xBD, 0x2C, 0x1D, 0x15, 0x00, 0xDB, 0x44, 0x33, 0x22, 0x00, 0x00, + 0x03, 0x30, 0x00, 0x00, 0x57, 0x00, 0x5D, 0x00, 0x18, 0x00, 0xFC, 0xC7, 0x2E, 0x1F, 0x00, 0x00, + 0x45, 0x00, 0x29, 0x09, 0x06, 0x18, 0x89, 0x30, 0x2F, 0x0B, 0x07, 0xDF, 0x34, 0x23, 0x21, 0xC0, + 0x81, 0x59, 0x15, 0x0E, 0x3C, 0xC0, 0x2A, 0x00, 0xF5, 0xC7, 0xE1, 0x34, 0x38, 0x23, 0x31, 0x0B, + 0x07, 0xC9, 0x2F, 0x1F, 0x33, 0x00, 0x80, 0x2D, 0x00, 0x1E, 0x90, 0x4D, 0x12, 0x0C, 0x2D, 0xC0, + 0x41, 0x0F, 0x23, 0x0A, 0x03, 0x30, 0x00, 0x00, 0xD9, 0x33, 0x22, 0xE7, 0x36, 0x06, 0x24, 0x06, + 0x00, 0xCB, 0x2F, 0x1F, 0x39, 0x30, 0x15, 0x05, 0x22, 0x03, 0x06, 0x60, 0x0F, 0xF0, 0x21, 0xF0, + 0x0F, 0x03, 0x02, 0x03, 0x00, 0x8E, 0xF9, 0x3A, 0x3C, 0xA0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, + 0x3C, 0xF0, 0x30, 0xF0, 0xFC, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, + 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, + 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, + 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, + 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, + 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, + 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, + 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0xFF, 0x3C, 0xF0, 0x3C, 0xF0, + 0x0F, 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0xFF, 0x3C, 0xF0, 0x0F, + 0xF0, 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0xFF, 0x0F, 0xF0, + 0x27, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0xFF, 0x27, + 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x0F, 0xF0, 0x27, 0xF0, 0xFF, + 0x3C, 0xF0, 0x3C, 0xF0, 0x30, 0xF0, 0x3C, 0xF0, 0x84, 0x90, 0x3F, 0x00, 0x00, 0x00, 0x0F, 0xF0, + 0xFF, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x07, 0x01, 0xB1, 0x40, + 0x81, 0x20, 0x33, 0x0C, 0x08, 0x00, 0x00, 0x0F, 0xF0, 0xC6, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, + 0x0D, 0x03, 0x02, 0x2D, 0x0A, 0x07, 0x07, 0x75, 0x30, 0x39, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F, + 0xF0, 0x1B, 0xF0, 0x03, 0x00, 0xFE, 0x39, 0x00, 0xB1, 0x29, 0x1B, 0xF3, 0x39, 0x26, 0x00, 0x00, + 0x81, 0x0F, 0xF0, 0x09, 0x90, 0x03, 0x30, 0x00, 0x00, 0xFE, 0x3B, 0x27, 0xF5, 0x0F, 0x39, 0x26, + 0xB3, 0x2A, 0x1C, 0x17, 0x05, 0x03, 0x00, 0xFF, 0xE4, 0x02, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, + 0x6A, 0x09, 0x00, 0x00 +}; + #endif diff --git a/bootloader/main.c b/bootloader/main.c index db982bb..5751881 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -35,7 +35,10 @@ #include "mem/heap.h" #include "mem/minerva.h" #include "mem/sdram.h" +#include "power/bq24193.h" +#include "power/max17050.h" #include "power/max77620.h" +#include "power/max7762x.h" #include "rtc/max77620-rtc.h" #include "soc/bpmp.h" #include "soc/fuse.h" @@ -1147,6 +1150,111 @@ static void _show_errors() } } +static void _check_low_battery() +{ + int enough_battery; + int batt_volt = 3200; + int charge_status = 0; + + bq24193_get_property(BQ24193_ChargeStatus, &charge_status); + max17050_get_property(MAX17050_AvgVCELL, &batt_volt); + + enough_battery = charge_status ? 3250 : 3000; + + if (batt_volt > enough_battery) + return; + + // Prepare battery icon resources. + u8 *battery_res = malloc(ALIGN(SZ_BATTERY_EMPTY, 0x1000)); + blz_uncompress_srcdest(BATTERY_EMPTY_BLZ, SZ_BATTERY_EMPTY_BLZ, battery_res, SZ_BATTERY_EMPTY); + + u8 *battery_icon = malloc(0x95A); // 21x38x3 + u8 *charging_icon = malloc(0x2F4); // 21x12x3 + u8 *no_charging_icon = calloc(0x2F4, 1); + + memcpy(charging_icon, battery_res, 0x2F4); + memcpy(battery_icon, battery_res + 0x2F4, 0x95A); + + u32 battery_icon_y_pos = 1280 - 16 - Y_BATTERY_EMPTY_BATT; + u32 charging_icon_y_pos = 1280 - 16 - Y_BATTERY_EMPTY_BATT - 12 - Y_BATTERY_EMPTY_CHRG; + free(battery_res); + + charge_status = !charge_status; + + u32 timer = 0; + bool screen_on = false; + while (true) + { + bpmp_msleep(250); + + // Refresh battery stats. + int current_charge_status = 0; + bq24193_get_property(BQ24193_ChargeStatus, ¤t_charge_status); + max17050_get_property(MAX17050_AvgVCELL, &batt_volt); + enough_battery = current_charge_status ? 3250 : 3000; + + if (batt_volt > enough_battery) + break; + + // Refresh charging icon. + if (screen_on && (charge_status != current_charge_status)) + { + if (current_charge_status) + gfx_set_rect_rgb(charging_icon, X_BATTERY_EMPTY, Y_BATTERY_EMPTY_CHRG, 16, charging_icon_y_pos); + else + gfx_set_rect_rgb(no_charging_icon, X_BATTERY_EMPTY, Y_BATTERY_EMPTY_CHRG, 16, charging_icon_y_pos); + } + + // Check if it's time to turn off display. + if (screen_on && timer < get_tmr_ms()) + { + if (!current_charge_status) + { + max77620_low_battery_monitor_config(true); + power_off(); + } + + display_end(); + screen_on = false; + } + + // Check if charging status changed or Power button was pressed. + if (((charge_status != current_charge_status) || (btn_wait_timeout(0, BTN_POWER) & BTN_POWER))) + { + if (!screen_on) + { + display_init(); + u32 *fb = display_init_framebuffer(); + gfx_init_ctxt(fb, 720, 1280, 720); + + gfx_set_rect_rgb(battery_icon, X_BATTERY_EMPTY, Y_BATTERY_EMPTY_BATT, 16, battery_icon_y_pos); + if (current_charge_status) + gfx_set_rect_rgb(charging_icon, X_BATTERY_EMPTY, Y_BATTERY_EMPTY_CHRG, 16, charging_icon_y_pos); + else + gfx_set_rect_rgb(no_charging_icon, X_BATTERY_EMPTY, Y_BATTERY_EMPTY_CHRG, 16, charging_icon_y_pos); + + display_backlight_pwm_init(); + display_backlight_brightness(100, 1000); + + screen_on = true; + } + + timer = get_tmr_ms() + 15000; + } + + charge_status = current_charge_status; + } + + display_end(); + + free(battery_icon); + free(charging_icon); + free(no_charging_icon); + + // Re enable Low Battery Monitor shutdown. + max77620_low_battery_monitor_config(true); +} + static void _about() { static const char credits[] = @@ -1318,6 +1426,9 @@ void ipl_main() uart_wait_idle(DEBUG_UART_PORT, UART_TX_IDLE); #endif + // Check if battery is enough. + _check_low_battery(); + // Set bootloader's default configuration. set_default_configuration(); diff --git a/bootloader/power/max7762x.c b/bootloader/power/max7762x.c index 6dfd6c6..ce07cbe 100644 --- a/bootloader/power/max7762x.c +++ b/bootloader/power/max7762x.c @@ -169,9 +169,9 @@ void max77620_config_default() _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); } -void max77620_low_battery_monitor_config() +void max77620_low_battery_monitor_config(bool enable) { _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | + MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/bootloader/power/max7762x.h b/bootloader/power/max7762x.h index 8b0feb9..8a11a9f 100644 --- a/bootloader/power/max7762x.h +++ b/bootloader/power/max7762x.h @@ -113,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv); int max77620_regulator_enable(u32 id, int enable); int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); void max77620_config_default(); -void max77620_low_battery_monitor_config(); +void max77620_low_battery_monitor_config(bool enable); #endif diff --git a/bootloader/soc/hw_init.c b/bootloader/soc/hw_init.c index bb4c0d3..58b4e0b 100644 --- a/bootloader/soc/hw_init.c +++ b/bootloader/soc/hw_init.c @@ -222,6 +222,9 @@ void _config_se_brom() void _config_regulators() { + // Disable low battery shutdown monitor. + max77620_low_battery_monitor_config(false); + // Disable SDMMC1 IO power. gpio_output_enable(GPIO_PORT_E, GPIO_PIN_4, GPIO_OUTPUT_DISABLE); max77620_regulator_enable(REGULATOR_LDO2, 0); @@ -267,9 +270,6 @@ void _config_regulators() i2c_send_byte(I2C_5, MAX77621_GPU_I2C_ADDR, MAX77621_CONTROL2_REG, MAX77621_T_JUNCTION_120 | MAX77621_FT_ENABLE | MAX77621_CKKADV_TRIP_75mV_PER_US_HIST_DIS | MAX77621_CKKADV_TRIP_150mV_PER_US | MAX77621_INDUCTOR_NOMINAL); - - // Enable low battery shutdown monitor for < 2800mV. - max77620_low_battery_monitor_config(); } void config_hw() diff --git a/nyx/nyx_gui/power/max7762x.c b/nyx/nyx_gui/power/max7762x.c index 0e7a6b5..ce07cbe 100644 --- a/nyx/nyx_gui/power/max7762x.c +++ b/nyx/nyx_gui/power/max7762x.c @@ -137,6 +137,7 @@ int max77620_regulator_enable(u32 id, int enable) return 1; } +// LDO only. int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags) { if (id > REGULATOR_MAX) @@ -168,9 +169,9 @@ void max77620_config_default() _max77620_try_set_reg(MAX77620_REG_SD_CFG2, 4); } -void max77620_low_battery_monitor_config() +void max77620_low_battery_monitor_config(bool enable) { _max77620_try_set_reg(MAX77620_REG_CNFGGLBL1, - MAX77620_CNFGGLBL1_LBDAC_EN | MAX77620_CNFGGLBL1_MPPLD | + MAX77620_CNFGGLBL1_LBDAC_EN | (enable ? MAX77620_CNFGGLBL1_MPPLD : 0) | MAX77620_CNFGGLBL1_LBHYST_200 | MAX77620_CNFGGLBL1_LBDAC_2800); } diff --git a/nyx/nyx_gui/power/max7762x.h b/nyx/nyx_gui/power/max7762x.h index 3a0afe3..8a11a9f 100644 --- a/nyx/nyx_gui/power/max7762x.h +++ b/nyx/nyx_gui/power/max7762x.h @@ -33,7 +33,7 @@ * ldo2 | SDMMC1 | 50000 | 800000 | 1800000 | 3300000 | * ldo3 | GC ASIC | 50000 | 800000 | 3100000 | 3100000 | 3.1V (pcv) * ldo4 | RTC | 12500 | 800000 | 850000 | 850000 | -* ldo5 | GC ASIC | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) +* ldo5 | GC Card | 50000 | 800000 | 1800000 | 1800000 | 1.8V (pcv) * ldo6 | Touch, ALS | 50000 | 800000 | 2900000 | 2900000 | 2.9V * ldo7 | XUSB | 50000 | 800000 | 1050000 | 1050000 | * ldo8 | XUSB, DC | 50000 | 800000 | 1050000 | 1050000 | @@ -113,6 +113,6 @@ int max77620_regulator_set_voltage(u32 id, u32 mv); int max77620_regulator_enable(u32 id, int enable); int max77620_regulator_set_volt_and_flags(u32 id, u32 mv, u8 flags); void max77620_config_default(); -void max77620_low_battery_monitor_config(); +void max77620_low_battery_monitor_config(bool enable); #endif