iBoot/target/ipod6/init_product.c

1262 lines
34 KiB
C

/*
* Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <drivers/display.h>
#if WITH_HW_DISPLAY_PMU
#include <drivers/display_pmu.h>
#endif
#if WITH_HW_DOCKFIFO_UART || WITH_HW_DOCKFIFO_BULK
#include <drivers/dockfifo/dockfifo.h>
#endif
#include <drivers/flash_nor.h>
#include <drivers/iic.h>
#include <drivers/power.h>
#include <lib/devicetree.h>
#include <lib/env.h>
#include <lib/mib.h>
#include <lib/paint.h>
#include <lib/syscfg.h>
#include <platform.h>
#include <platform/chipid.h>
#include <platform/gpio.h>
#include <platform/gpiodef.h>
#include <platform/memmap.h>
#include <platform/soc/hwregbase.h>
#include <platform/soc/chipid.h>
#include <platform/soc/pmgr.h>
#include <platform/dmin.h>
#include <sys.h>
#include <sys/boot.h>
#include <sys/menu.h>
#include <sys/task.h>
#include <target.h>
#include <target/cjay.h>
#define BOARD_TYPE_N27_AP (0xA)
#define BOARD_TYPE_N28_AP (0xC)
#define BOARD_TYPE_N27A_AP (0x2)
#define BOARD_TYPE_N28A_AP (0x4)
#define BOARD_TYPE_N27_DEV (0xB)
#define BOARD_TYPE_N28_DEV (0xD)
#define BOARD_TYPE_N27A_DEV (0x3)
#define BOARD_TYPE_N28A_DEV (0x5)
// Display panel type
typedef enum {
DISPLAY_PANEL_TYPE_UNKNOWN = 0,
DISPLAY_PANEL_TYPE_C1_DC,
DISPLAY_PANEL_TYPE_SLTSID,
DISPLAY_PANEL_TYPE_CRADLE,
DISPLAY_PANEL_TYPE_ALT_DISP_POC1,
DISPLAY_PANEL_TYPE_POR_DISP_S,
DISPLAY_PANEL_TYPE_POR_DISP_B,
DISPLAY_PANEL_TYPE_ALT_DISP_N31,
DISPLAY_PANEL_TYPE_POR_DISP_B_VID,
// Metadata
DISPLAY_PANEL_TYPE_COUNT
} display_panel_type;
static const char *display_panel_types[] = {
"UNKNOWN",
"C1",
"C1",
"C1",
"C1",
"POR_DISP_S",
"POR_DISP_B",
"ALT_DISP_N31",
"POR_DISP_B_VID"
};
typedef enum {
DISPLAY_TOUCH_TYPE_UNKNOWN = 0,
DISPLAY_TOUCH_TYPE_T126_SALTYSID,
DISPLAY_TOUCH_TYPE_A1N27A_1_POC1,
DISPLAY_TOUCH_TYPE_A1N27A_1_PROTO2,
DISPLAY_TOUCH_TYPE_A1N28A_1_PROTO2,
// Metadata
DISPLAY_TOUCH_TYPE_COUNT
} display_touch_type;
static const char *display_touch_types[] = {
"UNKNOWN",
"multi-touch,t126-saltysid",
"A1N27A,1-POC1",
"A1N27A,1-Proto2",
"A1N28A,1-Proto2"
};
// Display panel id sense pins
#define DISPLAY_TO_AP_ID0 GPIO( 17, 1) // RMII_CRSDV
#define DISPLAY_TO_AP_ID1 GPIO( 16, 7) // RMII_RXD_0
#define DISPLAY_TO_AP_ID2 GPIO( 17, 0) // RMII_RXD_1
#define DISPLAY_TO_AP_ID3 GPIO( 16, 4) // RMII_CLK
static bool gpio_board_rev_valid;
static uint32_t gpio_board_rev;
static bool gpio_display_id_valid;
static display_panel_type display_panel;
static display_touch_type display_touch;
static uint32_t display_config;
uint32_t ipod6_get_board_rev(void)
{
if (!gpio_board_rev_valid) {
gpio_configure(GPIO_BOARD_REV0, GPIO_CFG_IN);
gpio_configure(GPIO_BOARD_REV1, GPIO_CFG_IN);
gpio_configure(GPIO_BOARD_REV2, GPIO_CFG_IN);
gpio_configure(GPIO_BOARD_REV3, GPIO_CFG_IN);
gpio_configure_pupdn(GPIO_BOARD_REV0, GPIO_PDN);
gpio_configure_pupdn(GPIO_BOARD_REV1, GPIO_PDN);
gpio_configure_pupdn(GPIO_BOARD_REV2, GPIO_PDN);
gpio_configure_pupdn(GPIO_BOARD_REV3, GPIO_PDN);
spin(100); // Wait 100us
gpio_board_rev =
(gpio_read(GPIO_BOARD_REV3) << 3) |
(gpio_read(GPIO_BOARD_REV2) << 2) |
(gpio_read(GPIO_BOARD_REV1) << 1) |
(gpio_read(GPIO_BOARD_REV0) << 0);
gpio_configure(GPIO_BOARD_REV0, GPIO_CFG_DFLT);
gpio_configure(GPIO_BOARD_REV1, GPIO_CFG_DFLT);
gpio_configure(GPIO_BOARD_REV2, GPIO_CFG_DFLT);
gpio_configure(GPIO_BOARD_REV3, GPIO_CFG_DFLT);
gpio_board_rev_valid = true;
}
return gpio_board_rev;
}
bool ipod6_is_beryllium_supported()
{
bool result = true;
// On M7 DEV board configs, read ALT_BOOST_ID pin to check if Beryllium daughter card exists.
// DEV config: board-id == 1
if (((rPMGR_SCRATCH0 >> 16) & 0xf) == 1)
result = gpio_read(GPIO_ALT_BOOST_ID);
return result;
}
static void ipod6_power_display(bool enable)
{
#ifdef GPIO_PMU_LCD_PWR_EN
power_set_gpio(GPIO_PMU_LCD_PWR_EN, 1, 1);
#endif
#ifdef PMU_LCD_PWR_DVDD
#ifdef PMU_LCD_PWR_VCI
power_enable_ldo(PMU_LCD_PWR_DVDD, enable);
power_enable_ldo(PMU_LCD_PWR_VCI, enable);
#endif // PMU_LCD_PWR_VCI
#endif // PMU_LCD_PWR_DVDD
#ifdef GPIO_LCD_PWR_EN
gpio_write(GPIO_LCD_PWR_EN, enable);
#endif
}
// The panel id pin mappings are desribed by the following id pin states:
// ID0 ID1 ID2 ID3 Panel TOUCH
// ---- ---- ---- ---- ----- ------
// PD PU PU X C1_DC
// PU PD PD X SLTSID
// PU PD PU X CRADLE
// PU PU PD PD ALT_DISP_POC1
// PU PU PD PU POR_DISP_S
// PU PU PU PD POR_DISP_B
// PU PU PU PU ALT_DISP_N31
// PD PU PU PD POR_DISP_B_VID
static void ipod6_get_display_info(void)
{
const char *id0;
const char *id1;
const char *id2;
const char *id3;
if (target_config_ap()) {
switch (platform_get_board_id()) {
case BOARD_TYPE_N27_AP:
case BOARD_TYPE_N27A_AP:
display_panel = DISPLAY_PANEL_TYPE_POR_DISP_S;
display_touch = DISPLAY_TOUCH_TYPE_A1N27A_1_PROTO2;
return;
case BOARD_TYPE_N28_AP:
case BOARD_TYPE_N28A_AP:
// Special case Cardinal BOARD_REV's display.
if ((ipod6_get_board_rev() == BOARD_REV_PROTO2X_CARDINAL) ||
(ipod6_get_board_rev() == BOARD_REV_DVTb_CARDINAL))
display_panel = DISPLAY_PANEL_TYPE_POR_DISP_B_VID;
else
display_panel = DISPLAY_PANEL_TYPE_POR_DISP_B;
display_touch = DISPLAY_TOUCH_TYPE_A1N28A_1_PROTO2;
return;
}
}
gpio_configure(DISPLAY_TO_AP_ID0, GPIO_CFG_IN);
gpio_configure(DISPLAY_TO_AP_ID1, GPIO_CFG_IN);
gpio_configure(DISPLAY_TO_AP_ID2, GPIO_CFG_IN);
gpio_configure(DISPLAY_TO_AP_ID3, GPIO_CFG_IN);
gpio_configure_pupdn(DISPLAY_TO_AP_ID0, GPIO_PDN);
gpio_configure_pupdn(DISPLAY_TO_AP_ID1, GPIO_PDN);
gpio_configure_pupdn(DISPLAY_TO_AP_ID2, GPIO_PDN);
gpio_configure_pupdn(DISPLAY_TO_AP_ID3, GPIO_PDN);
spin(100); // Wait 100us
if (!gpio_read(DISPLAY_TO_AP_ID0)) {
id0 = "pd";
if (gpio_read(DISPLAY_TO_AP_ID1)) {
id1 = "pu";
if (gpio_read(DISPLAY_TO_AP_ID2)) {
id2 = "pu";
if (!gpio_read(DISPLAY_TO_AP_ID3)) {
id3 = "pd";
display_panel = DISPLAY_PANEL_TYPE_POR_DISP_B_VID;
display_touch = DISPLAY_TOUCH_TYPE_A1N28A_1_PROTO2;
gpio_display_id_valid = true;
} else {
id3 = "pu";
}
} else {
id2 = "pd";
id3 = "not read";
}
} else {
id1 = "pu";
id2 = "not read";
id3 = "not read";
display_panel = DISPLAY_PANEL_TYPE_C1_DC;
display_touch = DISPLAY_TOUCH_TYPE_UNKNOWN;
gpio_display_id_valid = true;
}
} else {
id0 = "pu";
if (!gpio_read(DISPLAY_TO_AP_ID1)) {
id1 = "pd";
id3 = "not read";
if (!gpio_read(DISPLAY_TO_AP_ID2)) {
id2 = "pd";
display_panel = DISPLAY_PANEL_TYPE_SLTSID;
display_touch = DISPLAY_TOUCH_TYPE_T126_SALTYSID;
gpio_display_id_valid = true;
} else {
id2 = "pu";
display_panel = DISPLAY_PANEL_TYPE_CRADLE;
display_touch = DISPLAY_TOUCH_TYPE_T126_SALTYSID;
gpio_display_id_valid = true;
}
} else {
id1 = "pu";
if (!gpio_read(DISPLAY_TO_AP_ID2)) {
id2 = "pd";
if (!gpio_read(DISPLAY_TO_AP_ID3)) {
id3 = "pd";
display_panel = DISPLAY_PANEL_TYPE_ALT_DISP_POC1;
display_touch = DISPLAY_TOUCH_TYPE_A1N27A_1_POC1;
gpio_display_id_valid = true;
} else {
id3 = "pu";
display_panel = DISPLAY_PANEL_TYPE_POR_DISP_S;
display_touch = DISPLAY_TOUCH_TYPE_A1N27A_1_PROTO2;
gpio_display_id_valid = true;
}
} else {
id2 = "pu";
if (!gpio_read(DISPLAY_TO_AP_ID3)) {
id3 = "pd";
display_panel = DISPLAY_PANEL_TYPE_POR_DISP_B;
display_touch = DISPLAY_TOUCH_TYPE_A1N28A_1_PROTO2;
gpio_display_id_valid = true;
} else {
id3 = "pu";
display_panel = DISPLAY_PANEL_TYPE_ALT_DISP_N31;
display_touch = DISPLAY_TOUCH_TYPE_UNKNOWN;
gpio_display_id_valid = true;
}
}
}
}
dprintf(DEBUG_INFO, "%s panel id pin state: id0=%s, id1=%s, id2=%s, id3=%s\n",
gpio_display_id_valid ? "" : "Unknown", id0, id1, id2, id3);
ASSERT(display_panel < DISPLAY_PANEL_TYPE_COUNT);
ASSERT(display_touch < DISPLAY_TOUCH_TYPE_COUNT);
dprintf(DEBUG_INFO, "Display panel = %s\nDisplay switch = %s\n",
display_panel_types[display_panel],
display_touch_types[display_touch]);
gpio_configure(DISPLAY_TO_AP_ID0, GPIO_CFG_DFLT);
gpio_configure(DISPLAY_TO_AP_ID1, GPIO_CFG_DFLT);
gpio_configure(DISPLAY_TO_AP_ID2, GPIO_CFG_DFLT);
gpio_configure(DISPLAY_TO_AP_ID3, GPIO_CFG_DFLT);
}
uint32_t target_get_display_panel_type(void)
{
if (!gpio_display_id_valid) {
ipod6_get_display_info();
}
return display_panel;
}
uint32_t target_get_display_touch_type(void)
{
if (!gpio_display_id_valid) {
ipod6_get_display_info();
}
return display_touch;
}
#if WITH_HW_POWER
int pmu_set_data(int dev, uint16_t reg, uint8_t byte, bool do_confirm);
int pmu_get_data(int dev, uint16_t reg, uint8_t *byte);
static int product_pmu_gpiocfg(int gpiono, uint8_t conf1, uint8_t conf2)
{
const uint16_t base=0x0400+(gpiono-1)*2;
int rc=pmu_set_data( 0, base, conf1, 0 );
if ( rc==0 ) rc=pmu_set_data( 0, base+1, conf2, 0 );
return rc;
}
#endif
void product_target_early_init(void)
{
// Get the display panel type.
//The display IDs need the display's rails to be turned on
ipod6_power_display(true);
ipod6_get_display_info();
#if WITH_HW_POWER
// <rdar://problem/16862108> M7: Configure binned voltages for M7 A1 parts
const uint32_t frev=chipid_get_fuse_revision();
const uint32_t crev=chipid_get_chip_revision();
if ( crev>=0x01 && frev>=0x03 ) {
uint8_t vsel=0;
// bin is at bits 37-43 in fuse (or 7 bits in rCFG_FUSE1[5-11] )
uint8_t bin=(rCFG_FUSE1>>5)&0x7f;
switch ( bin ) {
case 0x34: vsel=0x54; break; // bin1
case 0x2f: vsel=0x4c; break; // bin2
case 0x2a: vsel=0x44; break; // bin3
default: /* warn? maybe... */ break;
}
if ( vsel ) {
int rc=pmu_set_data( 0, 0x100, vsel, 1); // buck0_vsel
if ( rc==0 ) rc=pmu_set_data( 0, 0x101, vsel-0x10, 1); // buck0_vsel_alt, vsel-50mV
if ( rc<0 ) dprintf(DEBUG_CRITICAL, "PMU: cannot change buck0_vsel* (%d)\n", rc);
}
}
#endif
}
#define ENVAR_PWR_PATH "pwr-path"
void product_target_late_init(void)
{
#if WITH_HW_POWER
const uint32_t rev=ipod6_get_board_rev();
// <rdar://problem/16720846> Change behavior of PMU GPIO 13 (GPIO_DISABLE_PWR_PATH)
if ( rev<=BOARD_REV_PROTO2A ) {
uint8_t level=0;
#if RELEASE_BUILD && PRODUCT_IBOOT
level=1; // disable debug power on customer builds by default
#endif
#if WITH_ENV && PRODUCT_IBOOT
const char *boot_args = env_get("boot-args");
if ( boot_args != NULL ) {
char *arg_str = strstr(boot_args, ENVAR_PWR_PATH"=");
if ( arg_str != NULL ) {
level = ( arg_str[strlen(ENVAR_PWR_PATH"=")] == '1' );
}
}
// override with nvram environment variable (if it exists)
level = env_get_bool(ENVAR_PWR_PATH, level);
dprintf(DEBUG_CRITICAL, "PMU: pwr-path=%d\n", level);
#endif
int rc=product_pmu_gpiocfg(13, ( level<<1 ) | 0x1, 0x2 );
if ( rc<0 ) dprintf(DEBUG_CRITICAL, "PMU: pwr_path failed (%d)\n", rc);
}
// PCVB syscfg key (radar 18950042)
// bytes 0-3 : Version number = 3
// bytes 4-7 : CV offset in Volts, 4 byte fixed point decimal
// bytes 8-11 : buck0 offset in Volts, 4 byte fixed point decimal
// bytes 12-15 : buck1 offset in Volts, 4 byte fixed point decimal
SInt32 cal_data[4] = {0};
syscfgCopyDataForTag('PCVB', (void*)&cal_data, 4*sizeof(SInt32));
// Check key version
if (cal_data[0] >= 3) {
uint8_t data = 0;
SInt32 offset = 0;
// "CHG_CTRL_E = CHG_TRIM2 - ceiling[CV_offset*160]"
if (cal_data[1] > 0 && pmu_get_data(0, 0x4cb, &data) == 0) {
offset = cal_data[1] * 160;
data = (offset & 0xFFFF) ? data-(offset>>16)-1 : data-(offset>>16);
int rc=pmu_set_data(0, 0x4c4, data, 1);
if ( rc<0 ) dprintf(DEBUG_CRITICAL, "PMU: cannot change chg_ctrl_e (%d)\n", rc);
}
// "BUCK0_VSEL = BUCK0_VSEL + ceiling[Buck0_offset*320]"
if (cal_data[2] > 0 && pmu_get_data(0, 0x100, &data) == 0) {
offset = cal_data[2] * 320;
data = (offset & 0xFFFF) ? data+(offset>>16)+1 : data+(offset>>16);
int rc=pmu_set_data(0, 0x100, data, 1);
if ( rc==0 ) rc=pmu_set_data( 0, 0x101, data-0x10, 1); // buck0_vsel_alt, vsel-50mV
if ( rc<0 ) dprintf(DEBUG_CRITICAL, "PMU: cannot change buck0_vsel (%d)\n", rc);
}
// "BUCK1_VSEL = BUCK1_VSEL + ceiling[Buck1_offset*320]"
if (cal_data[3] > 0 && pmu_get_data(0, 0x120, &data) == 0) {
offset = cal_data[3] * 320;
data = (offset & 0xFFFF) ? data+(offset>>16)+1 : data+(offset>>16);
int rc=pmu_set_data(0, 0x120, data, 1);
if ( rc<0 ) dprintf(DEBUG_CRITICAL, "PMU: cannot change buck1_vsel (%d)\n", rc);
}
}
// <rdar://problem/19050193> iBoot: need to dynamicall change UART2_BERMUDA_TO_AP_CTS_L from pulldown to pullup
// toggle VDD_MAIN_SW4 for bermuda,
if ( target_config_ap() && ( rev<=BOARD_REV_EVT ) ) {
int rc;
uint8_t data=0x7f;
rc=pmu_set_data(0, 0x0085, data, 1);
if ( rc<0 ) {
dprintf(DEBUG_CRITICAL, "PMU: cannot enable VDD_MAIN_SW4 (%d)\n", rc);
} else {
task_sleep( 2 * 1000 ); // settle time
data=0x3f;
rc=pmu_set_data(0, 0x0085, data, 1);
if ( rc<0 ) dprintf(DEBUG_CRITICAL, "PMU: cannot disable VDD_MAIN_SW4 (%d)\n", rc);
gpio_configure_pupdn(GPIO_BERMUDA_TO_AP_CTS, GPIO_PUP);
}
}
#endif
// Turn on DockFIFO clock gating
for(int i = 0; i < 8; i++)
{
dockfifo_enable_clock_gating(i);
}
target_init_boot_manifest();
// Cache Dali info into NVRAM
// platform_late_init() only occurs if we didn't chargetrap, so by this point
// we know for sure we have ASP NVRAM.
extern void target_init_fast_dali();
target_init_fast_dali();
}
bool product_target_should_recover(void)
{
return platform_get_request_dfu2() && power_has_usb();
}
bool product_target_should_poweron(bool *cold_button_boot)
{
#if WITH_HW_POWER
int result;
uint8_t error_stage;
// in special case of rebooting from Dali, ignore button press
result = power_get_nvram(kPowerNVRAMiBootErrorStageKey, &error_stage);
if (result == 0 && error_stage == kPowerNVRAMiBootStagePrechargeReboot) {
boot_clear_error_count(); // don't generate a crash log for this
return true;
}
if (power_get_boot_flag() == kPowerBootFlagColdButton) *cold_button_boot = true;
#else
*cold_button_boot = false;
#endif // WITH_HW_POWER
return !*cold_button_boot || platform_get_request_dfu1();
}
bool product_target_should_poweroff(bool at_boot)
{
static bool was_precharge_reboot = false;
#if WITH_HW_POWER
// <rdar://problem/22369404>
//
// If rebooting out of Dali mode, the user could've initiated this action by holding down the power button.
// We do not want an extra-long hold of the power button to result in the device turning off.
int result;
uint8_t error_stage;
result = power_get_nvram(kPowerNVRAMiBootErrorStageKey, &error_stage);
if (was_precharge_reboot || (result == 0 && error_stage == kPowerNVRAMiBootStagePrechargeReboot)) {
boot_clear_error_count(); // don't generate a crash log for this
#if PRODUCT_IBOOT || PRODUCT_IBEC
// The error stage needs to be cleared because precharge reboot really isn't an error,
// but since this is called in a loop by the idleoff_task we need to remember that we are
// rebooting from Dali.
//
// Only clear the key in iBoot. In LLB, we need to preserve the error stage key as-is for the next stage.
was_precharge_reboot = true;
power_set_nvram(kPowerNVRAMiBootErrorStageKey, kPowerNVRAMiBootStageOff);
#endif
return false;
}
#endif
return platform_get_request_dfu1() && (!at_boot || !power_has_usb());
}
void * target_get_display_configuration(void)
{
switch(target_get_display_panel_type()){
case DISPLAY_PANEL_TYPE_C1_DC:
case DISPLAY_PANEL_TYPE_SLTSID:
case DISPLAY_PANEL_TYPE_CRADLE:
case DISPLAY_PANEL_TYPE_ALT_DISP_POC1:
display_config = 0x00000971;
break;
case DISPLAY_PANEL_TYPE_POR_DISP_S:
case DISPLAY_PANEL_TYPE_POR_DISP_B:
case DISPLAY_PANEL_TYPE_POR_DISP_B_VID:
display_config = 0x00000951;
break;
}
return ((void *)(&display_config));
}
#if WITH_ENV
void product_target_setup_default_environment(void)
{
uint32_t panel_type_index;
env_set("boot-device", "asp_nand", 0);
env_set("display-color-space","RGB888", 0);
panel_type_index = target_get_display_panel_type();
env_set("display-timing", display_panel_types[panel_type_index], 0);
#if !RELEASE_BUILD
env_set("diags-path", "/AppleInternal/Diags/bin/diag.img4", 0);
env_set("diags-vendor-path", "/AppleInternal/Diags/bin/diag-vendor.img4", 0);
#endif // !RELEASE_BUILD
}
#endif // WITH_ENV
bool product_target_is_display_in_video_mode(void)
{
switch(target_get_display_panel_type()){
case DISPLAY_PANEL_TYPE_C1_DC:
case DISPLAY_PANEL_TYPE_SLTSID:
case DISPLAY_PANEL_TYPE_CRADLE:
case DISPLAY_PANEL_TYPE_ALT_DISP_POC1:
case DISPLAY_PANEL_TYPE_POR_DISP_B_VID:
return true;
case DISPLAY_PANEL_TYPE_POR_DISP_S:
case DISPLAY_PANEL_TYPE_POR_DISP_B:
case DISPLAY_PANEL_TYPE_ALT_DISP_N31:
return false;
}
return false;
}
bool product_target_no_burst_mode(void)
{
switch(target_get_display_panel_type()){
case DISPLAY_PANEL_TYPE_POR_DISP_B_VID:
return true;
}
return false;
}
//The following 3 fuctions uses the values as defined in https://seg-docs.ecs.apple.com/projects/m7//release/specs/Apple/Top/M7_display_timing.xls
//“M7 Command Mode Timing”
//
uint32_t product_target_get_ulps_in_delay(void)
{
switch(target_get_display_panel_type()){
case DISPLAY_PANEL_TYPE_C1_DC:
case DISPLAY_PANEL_TYPE_SLTSID:
case DISPLAY_PANEL_TYPE_CRADLE:
case DISPLAY_PANEL_TYPE_ALT_DISP_POC1:
case DISPLAY_PANEL_TYPE_POR_DISP_B_VID:
return 0;
case DISPLAY_PANEL_TYPE_POR_DISP_S:
return 13056;
case DISPLAY_PANEL_TYPE_POR_DISP_B:
return 14976;
case DISPLAY_PANEL_TYPE_ALT_DISP_N31:
return 19680;
}
return false;
}
uint32_t product_target_get_ulps_end_delay(void)
{
switch(target_get_display_panel_type()){
case DISPLAY_PANEL_TYPE_C1_DC:
case DISPLAY_PANEL_TYPE_SLTSID:
case DISPLAY_PANEL_TYPE_CRADLE:
case DISPLAY_PANEL_TYPE_ALT_DISP_POC1:
case DISPLAY_PANEL_TYPE_POR_DISP_B_VID:
return 0;
case DISPLAY_PANEL_TYPE_POR_DISP_S:
return 722538;
case DISPLAY_PANEL_TYPE_POR_DISP_B:
return 637035;
case DISPLAY_PANEL_TYPE_ALT_DISP_N31:
return 584135;
}
return false;
}
uint32_t product_target_get_ulps_out_delay(void)
{
switch(target_get_display_panel_type()){
case DISPLAY_PANEL_TYPE_C1_DC:
case DISPLAY_PANEL_TYPE_SLTSID:
case DISPLAY_PANEL_TYPE_CRADLE:
case DISPLAY_PANEL_TYPE_ALT_DISP_POC1:
case DISPLAY_PANEL_TYPE_POR_DISP_B_VID:
return 0;
case DISPLAY_PANEL_TYPE_POR_DISP_S:
return 655913;
case DISPLAY_PANEL_TYPE_POR_DISP_B:
return 570410;
case DISPLAY_PANEL_TYPE_ALT_DISP_N31:
return 517510;
}
return false;
}
#if WITH_DEVICETREE
void display_update_device_tree()
{
#if WITH_HW_DISPLAY_PMU
display_pmu_update_device_tree("arm-io/i2c1/display-pmu");
#endif
DTNode *disp0_node;
DTNode *node;
char *propName;
uint32_t propSize;
void *propData;
bool video_mode;
video_mode = product_target_is_display_in_video_mode();
// Find the DISP0 (display-subsystem 0) node
if (FindNode(0, "arm-io/disp0", &disp0_node)) {
propName = "video-mode";
if (FindProperty(disp0_node, &propName, &propData, &propSize)) {
*((bool*)propData) = video_mode;
}
propName = "esd-workaround";
if (FindProperty(disp0_node, &propName, &propData, &propSize)) {
bool enable_esd_workaround = (target_config_ap() && ipod6_get_board_rev() <= BOARD_REV_EVT);
*((uint32_t*)propData) = enable_esd_workaround;
}
}
if (video_mode) {
if (FindNode(0, "arm-io/mipi-dsim", &node)) {
propName = "supports-auto-ulps";
//Do not turn on Auto ULPS on when on video mode
if (FindProperty(node, &propName, &propData, &propSize)) {
*((bool*)propData) = false;
}
}
}
#if WITH_HW_DISPLAY_SUMMIT
DTNode *backlight_node;
if (FindNode(0, "arm-io/mipi-dsim/lcd", &node)) {
extern int summit_update_device_tree(DTNode *summit_node, DTNode *clcd_node, DTNode *backlight_node);
FindNode(0, "backlight", &backlight_node);
summit_update_device_tree(node, disp0_node, backlight_node);
}
#endif //WITH_HW_DISPLAY_SUMMIT
}
void hid_update_device_tree()
{
DTNode *node;
char *propName;
uint32_t propSize;
void *propData;
if (FindNode(0, MULTITOUCH_DTPATH, &node)) {
propName = "hid-fw-personality";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
strlcpy(propData, display_touch_types[display_touch], propSize);
}
propName = "orb-f-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('OFCl', propData, propSize);
}
propName = "orb-o-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('OOCl', propData, propSize);
}
propName = "orb-i-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('OICo', propData, propSize);
}
}
}
static void spu_update_device_tree(void)
{
const char* accel_path = "arm-io/spu/iop-spu-nub/accel";
const char* gyro_path = "arm-io/spu/iop-spu-nub/gyro";
const char* als_path = "arm-io/spu/iop-spu-nub/als";
DTNode *node;
char *propName;
uint32_t propSize;
void *propData;
/* Accel Calibration */
if (FindNode(0, accel_path, &node)) {
propName = "accel-interrupt-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('AICl', propData, propSize);
}
propName = "accel-sensitivity-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('ASCl', propData, propSize);
}
propName = "accel-orientation";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('ARot', propData, propSize);
}
propName = "low-temp-accel-offset";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('LTAO', propData, propSize);
}
}
/* Gyro Calibration */
if (FindNode(0, gyro_path, &node)) {
propName = "gyro-interrupt-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('GICl', propData, propSize);
}
propName = "gyro-sensitivity-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('GSCl', propData, propSize);
}
propName = "gyro-orientation";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('GRot', propData, propSize);
}
propName = "gyro-temp-table";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('GYTT', propData, propSize);
}
propName = "gyro-trim-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('GTCl', propData, propSize);
}
}
/* ALS Calibration */
if (FindNode(0, als_path, &node)) {
propName = "alsCalibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('LSCI', propData, propSize);
}
}
}
static void opal_update_device_tree(void)
{
const char* opal_path = "arm-io/opal";
DTNode *node;
char *propName;
uint32_t propSize;
void *propData;
if (FindNode(0, opal_path, &node)) {
propName = "li-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('LiCl', propData, propSize);
}
propName = "pt-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('PlCl', propData, propSize);
}
propName = "device-board-revision";
if (FindProperty(node, &propName, &propData, &propSize)) {
*(uint32_t*)(propData) = ipod6_get_board_rev();
}
}
}
static void audio_update_device_tree(const char* dtpath)
{
DTNode *node;
char *propName;
uint32_t propSize;
void *propData;
if (FindNode(0, dtpath, &node)) {
propName = "actuator-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('TCal', propData, propSize);
}
propName = "codec-calibration";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
syscfgCopyDataForTag('CCal', propData, propSize);
}
}
}
static void charger_update_device_tree(void)
{
DTNode *node;
char *propName;
uint32_t propSize;
void *propData;
if (FindNode(0, "arm-io/i2c0/ext-charger", &node)) {
// Cjay syscfg key (radar 18717802)
SeajayCal calData = { {0,0,0,0,0},{0,0,0,0,0} };
syscfgCopyDataForTag('Cjay', (void*)&calData, sizeof(SeajayCal));
// Check key version
if (calData.Hdr.Version >= SEAJAY_CAL_VERSION && calData.Hdr.Magic == SEAJAY_CAL_MAGIC && calData.Hdr.IsNotCalibrated == 0) {
if (calData.Item.Status & kCalStatus_Offset) {
propName = "vrect-calibrate-offset";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
*((uint32_t*)propData) = calData.Item.Offset;
}
}
if (calData.Item.Status & kCalStatus_Gain) {
propName = "vrect-calibrate-gain";
if (FindProperty(node, &propName, &propData, &propSize)) {
memset(propData, 0, propSize);
*((uint32_t*)propData) = calData.Item.Gain;
}
}
}
}
}
static void device_material_update_device_tree(void)
{
DTNode *node;
char *propName;
uint32_t propSize;
void *propData;
DMin_t Dmin;
bzero(&Dmin, sizeof(Dmin));
// Look up the 'DMin' tag from syscfg.
//
// Determining which DMin to use: Pre-Monarch companion SW can't handle
// the N2xB configurations, so we had to "lie" in syscfg about the enclosure material
//
// On such configurations, the factory has put the true color in a DMin Override key 'DMnO'.
// If this key is present, we should use it instead of DMin.
int result = -1;
result = syscfgCopyDataForTag('DMnO', (uint8_t*)&Dmin, sizeof(Dmin));
if (result > 0) {
// If we copied more than 0 bytes, DMnO was present. We should use it
dprintf(DEBUG_INFO, "DMin override key 'DMnO' found. Using it instead of DMin\n");
} else {
result = syscfgCopyDataForTag('DMin', (uint8_t*)&Dmin, sizeof(Dmin));
if (result < 0) {
dprintf(DEBUG_CRITICAL, "Unable to find DMin key in syscfg.\n");
return;
}
}
if (Dmin.version != DMIN_VERSION_2) {
dprintf(DEBUG_CRITICAL, "DMin version %u is unspported.\n", (unsigned int)Dmin.version);
return;
}
if (FindNode(0, MULTITOUCH_DTPATH, &node)) {
/**
* DT property dmin key
*
* enc-top-type topEnclosure
* enc-bot-type botEnclosure
* fcm-type fcmType
* fcm-arcoated-type fcmARCoated
* fcm-inkcolor-type fcmInkColor
**/
propName = "enc-top-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.topEnclosure;
}
propName = "enc-bot-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.botEnclosure;
}
propName = "fcm-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.fcmType;
}
propName = "fcm-arcoated-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.fcmARCoated;
}
propName = "fcm-inkcolor-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.fcmInkColor;
}
}
const char* opal_path = "arm-io/opal";
if (FindNode(0, opal_path, &node)) {
/**
* Device Tree Key DMin Field
enc-top-type topEnclosure
enc-bot-type botEnclosure
bcm-window-type bcmWindow
bcm-lens-type bcmLens
pt-sensor-type bcmPTSensorType
pt-led-type bcmPTLEDType
lisa-opamp-type lisaOAType
lisa-sensor-ic lisaSensorIC
lisa-encoder-wheel lisaEncoderWheel
lisa-knurl lisaKnurl
**/
propName = "enc-top-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.topEnclosure;
}
propName = "enc-bot-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.botEnclosure;
}
propName = "bcm-window-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.bcmWindow;
}
propName = "bcm-lens-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.bcmLens;
}
propName = "pt-sensor-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.bcmPTSensorType;
}
propName = "pt-led-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.bcmPTLEDType;
}
propName = "lisa-opamp-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.lisaOAType;
}
propName = "lisa-sensor-ic";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.lisaSensorIC;
}
propName = "lisa-encoder-wheel";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.lisaEncoderWheel;
}
propName = "lisa-knurl";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.lisaKnurl;
}
}
const char* spu_path = "arm-io/spu";
if (FindNode(0, spu_path, &node)) {
propName = "pt-led-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.bcmPTLEDType;
}
}
if (FindNode(0, WIFI_DTPATH, &node)) {
/**
* DT property dmin key
*
* enc-top-type topEnclosure
* enc-bot-type botEnclosure
* fcm-type fcmType
**/
propName = "enc-top-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.topEnclosure;
}
propName = "enc-bot-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.botEnclosure;
}
propName = "fcm-type";
if (FindProperty(node, &propName, &propData, &propSize)) {
*((uint32_t*)propData) = Dmin.v2.fcmType;
}
}
}
static void aggd_update_device_tree(void)
{
// <rdar://problem/18615376> Add HW config info to allow for better data analysis
//
// We want carry aggd data correlated with hardware revision
// If we are building DEBUG/DEVELOPMENT, populate the DT with this info.
DTNodePtr chosen;
uint32_t propSize;
char *propName;
void *propData;
if (FindNode(0, "chosen", &chosen)) {
propName = "debug-board-revision";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
#if !RELEASE_BUILD
*((uint32_t*)(propData)) = ipod6_get_board_rev();
#else
propName[0] = '~';
#endif
}
}
}
static void stockholm_update_device_tree(void)
{
DTNodePtr node;
uint32_t propSize;
char *propName;
void *propData;
// Stockholm calibration
if (FindNode(0, "arm-io/uart2/stockholm", &node)) {
propName = "calibration";
if (FindProperty(node, &propName, &propData, &propSize))
syscfgCopyDataForTag('NFCl', propData, propSize);
}
// Bermuda dynamic CTS doesn't apply to DEV boards or pre-EVT devices. We will delete
// the dynamic pin assignment in that case.
if (!target_config_ap() || ipod6_get_board_rev() > BOARD_REV_EVT) {
if (FindNode(0, "arm-io/uart2", &node)) {
propName = "function-cts";
if (FindProperty(node, &propName, &propData, &propSize))
propName[0] = '~';
}
}
}
static void asp_update_device_tree(void)
{
// <rdar://problem/19298429> hung writing large images to ASP boot block
DTNodePtr chosen;
uint32_t propSize;
char *propName;
void *propData;
if (FindNode(0, "defaults", &chosen)) {
propName = "llb-num-blks";
if (FindProperty(chosen, &propName, &propData, &propSize)) {
*((uint32_t*)(propData)) = ASP_LLB_OVERRIDE_NUM_BLKS;
}
}
}
int product_target_update_device_tree(void)
{
display_update_device_tree();
hid_update_device_tree();
opal_update_device_tree();
spu_update_device_tree();
charger_update_device_tree();
audio_update_device_tree("arm-io/mca0/audio-actuator0");
device_material_update_device_tree();
aggd_update_device_tree();
stockholm_update_device_tree();
asp_update_device_tree();
return target_pass_boot_manifest();
}
#endif // WITH_DEVICETREE
bool target_needs_chargetrap(void)
{
// Dali powertrap should only be considered in iBoot
return power_needs_precharge() || power_needs_thermal_trap();
}
bool target_do_chargetrap(void)
{
#if APPLICATION_IBOOT && PRODUCT_IBOOT
// Dali powertrap should only be considered in iBoot
if (target_needs_chargetrap()) {
dprintf(DEBUG_INFO, "Charge trap requested");
// Currently, Dali expects us to initialize the display.
// This requires two consecutive calls, just like in the main.c boot path.
platform_init_display();
platform_init_display();
int boot_dali_flash(void);
if (boot_dali_flash() < 0)
{
panic("Failed to boot dali but chargetrap was requested\n");
}
return true;
}
#endif
return false;
}
#if !WITH_HW_POWER
bool power_needs_precharge(void)
{
return false;
}
void power_cancel_buttonwait(void)
{
}
bool power_do_chargetrap(void)
{
return false;
}
bool power_is_suspended(void)
{
return false;
}
void power_will_resume(void)
{
}
bool power_has_usb(void)
{
return false;
}
int power_read_dock_id(unsigned *id)
{
return -1;
}
bool power_get_diags_dock(void)
{
return false;
}
u_int32_t power_get_boot_battery_level(void)
{
return 0;
}
int power_get_nvram(u_int8_t key, u_int8_t *data)
{
return -1;
}
int power_set_nvram(u_int8_t key, u_int8_t data)
{
return -1;
}
int power_set_soc_voltage(unsigned mv, int override)
{
return -1;
}
bool force_usb_power = false;
void power_set_usb_state(bool configured, bool suspended)
{
}
int power_backlight_enable(u_int32_t backlight_level)
{
return 0;
}
#endif /* ! WITH_HW_POWER */