first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2013 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys.h>
|
||||
#include <sys/task.h>
|
||||
#include <platform.h>
|
||||
#include <platform/soc/hwclocks.h>
|
||||
#include <platform/soc/hwregbase.h>
|
||||
#include <drivers/anc_boot.h>
|
||||
#include "anc_bootrom.h"
|
||||
#include "anc_bootrom_private.h"
|
||||
|
||||
#define NAND_BOOTBLOCK_OFFSET 2
|
||||
|
||||
#define NAND_BOOT_MIN_WRITE_CYCLE_NANOS 50
|
||||
#define NAND_BOOT_MIN_READ_CYCLE_NANOS 50
|
||||
#define NAND_BOOT_MIN_CA_CYCLE_NANOS 50
|
||||
#define NAND_BOOT_MIN_WRITE_SETUP_NANOS 20
|
||||
#define NAND_BOOT_MIN_WRITE_HOLD_NANOS 20
|
||||
#define NAND_BOOT_MIN_READ_SETUP_NANOS 20
|
||||
#define NAND_BOOT_MIN_READ_HOLD_NANOS 20
|
||||
#define NAND_BOOT_MIN_CA_SETUP_NANOS 20
|
||||
#define NAND_BOOT_MIN_CA_HOLD_NANOS 20
|
||||
|
||||
#define T_CERDY_CYCLES 2675 // 50us @ 53.5MHz
|
||||
|
||||
#define ANC_TIMEOUT_MICROS 1000000UL // Applies to reg status waits - not tRST timeout
|
||||
#define T_PURST_USEC (10 * 1000) // 10ms
|
||||
|
||||
anc_t g_boot_anc[ANC_BOOT_CONTROLLERS];
|
||||
|
||||
static bool anc_boot_init_minimal(anc_t *anc, uint32_t interface);
|
||||
static void anc_configure_pins(void);
|
||||
static void anc_boot_reset(anc_t *anc);
|
||||
static bool anc_boot_nand_reset(int busesToReset);
|
||||
static int anc_boot_read_boot_pages(uint32_t valid_controllers, void *data, size_t *size);
|
||||
static void anc_boot_set_init_timings(anc_t *anc);
|
||||
|
||||
int anc_bootrom_init(bool reset_devices, int resetMode)
|
||||
{
|
||||
int i;
|
||||
int busesToReset;
|
||||
|
||||
if (resetMode == ANC_BOOT_MODE_RESET_ALL_CONTROLLERS) {
|
||||
busesToReset = ANC_BOOT_CONTROLLERS;
|
||||
} else if (resetMode == ANC_BOOT_MODE_RESET_ONE_CONTROLLER) {
|
||||
busesToReset = 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
anc_configure_pins();
|
||||
|
||||
for (i = 0; i < ANC_BOOT_CONTROLLERS; i++)
|
||||
{
|
||||
if (!anc_boot_init_minimal(&g_boot_anc[i], i))
|
||||
{
|
||||
dprintf(DEBUG_INFO, "failed: unable to initialize ANC%d\n", i);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (reset_devices && !anc_boot_nand_reset(busesToReset))
|
||||
{
|
||||
dprintf(DEBUG_INFO, "failed: unable to reset NAND devices\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void anc_configure_pins()
|
||||
{
|
||||
uint32_t *npl = (uint32_t *)ANS_PPN_N_PL_BASE_ADDR;
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_CLE, M_PPNNPL_PPN0_CLE_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_ALE, M_PPNNPL_PPN0_ALE_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_REN, M_PPNNPL_PPN0_REN_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_WEN, M_PPNNPL_PPN0_WEN_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_CEN, M_PPNNPL_PPN0_CEN_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_IO, (V_PPNNPL_PPN0_IO_INPUT_ENABLE(0xFF) |
|
||||
V_PPNNPL_PPN0_IO_PULL_ENABLE(0xFF)));
|
||||
#if ANC_TOGGLE_SUPPORTED == 1
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_DQS, (M_PPNNPL_PPN0_DQS_INPUT_ENABLE |
|
||||
M_PPNNPL_PPN0_DQS_PULL_ENABLE));
|
||||
#endif
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_DS, V_PPNNPL_PPN0_DS_DRIVE_STRENGTH(ANC_PPNNPL_DS_DRIVE_STRENGTH));
|
||||
anc_npl_wr(npl, R_PPNNPL_CONFIG, M_PPNNPL_CONFIG_AUTO_DISABLE_IO_PULLDOWN);
|
||||
#if APPLICATION_SECUREROM && defined(ANC_PPNNPL_INPUT_SELECT_SCHMITT)
|
||||
// <rdar://problem/15132151> N56, High power on 1V8_H7P_IO - rail - PPN_INPUT_SELECT
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN0_INPUT_SELECT, M_PPNNPL_PPN0_INPUT_SELECT_INPUT_SELECT |
|
||||
M_PPNNPL_PPN0_INPUT_SELECT_INPUT_SELECT_SCHMITT);
|
||||
#endif
|
||||
|
||||
#if ANC_BOOT_CONTROLLERS > 1
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_CLE, M_PPNNPL_PPN1_CLE_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_ALE, M_PPNNPL_PPN1_ALE_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_REN, M_PPNNPL_PPN1_REN_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_WEN, M_PPNNPL_PPN1_WEN_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_CEN, M_PPNNPL_PPN1_CEN_OUTPUT_ENABLE);
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_IO, (V_PPNNPL_PPN1_IO_INPUT_ENABLE(0xFF) |
|
||||
V_PPNNPL_PPN1_IO_PULL_ENABLE(0xFF)));
|
||||
#if ANC_TOGGLE_SUPPORTED == 1
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_DQS, (M_PPNNPL_PPN1_DQS_INPUT_ENABLE |
|
||||
M_PPNNPL_PPN1_DQS_PULL_ENABLE));
|
||||
#endif
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_DS, V_PPNNPL_PPN1_DS_DRIVE_STRENGTH(ANC_PPNNPL_DS_DRIVE_STRENGTH));
|
||||
#if APPLICATION_SECUREROM && defined(ANC_PPNNPL_INPUT_SELECT_SCHMITT)
|
||||
// <rdar://problem/15132151> N56, High power on 1V8_H7P_IO - rail - PPN_INPUT_SELECT
|
||||
anc_npl_wr(npl, R_PPNNPL_PPN1_INPUT_SELECT, M_PPNNPL_PPN1_INPUT_SELECT_INPUT_SELECT |
|
||||
M_PPNNPL_PPN1_INPUT_SELECT_INPUT_SELECT_SCHMITT);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool anc_boot_init_minimal(anc_t *anc, uint32_t interface)
|
||||
{
|
||||
#if ANC_BOOT_CONTROLLERS > 1
|
||||
anc->regs = (uint32_t *)((interface == 0) ? ANS_ANC_0_BASE_ADDR : ANS_ANC_1_BASE_ADDR);
|
||||
#else
|
||||
anc->regs = (uint32_t *)ANS_ANC_BASE_ADDR;
|
||||
if (interface > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (interface == 0)
|
||||
{
|
||||
clock_gate(CLK_ANS, true);
|
||||
#ifdef WITH_ANS_DLL
|
||||
clock_gate(CLK_ANS_DLL, true);
|
||||
#endif
|
||||
}
|
||||
anc_boot_reset(anc);
|
||||
anc_boot_set_init_timings(anc);
|
||||
|
||||
anc->bus_id = interface;
|
||||
anc->initialized = true;
|
||||
anc->pages_per_block = NAND_BOOT_PAGES_PER_BLOCK;
|
||||
anc->bytes_per_meta = NAND_BOOT_BYTES_PER_META;
|
||||
anc->meta_words = NAND_BOOT_BYTES_PER_META / sizeof(uint32_t);
|
||||
anc->bytes_per_page = NAND_BOOT_BYTES_PER_PAGE;
|
||||
anc->logical_page_size = NAND_BOOT_LOGICAL_PAGE_SIZE;
|
||||
anc->lbas_per_page = NAND_BOOT_BYTES_PER_PAGE / NAND_BOOT_LOGICAL_PAGE_SIZE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void anc_boot_reset(anc_t *anc)
|
||||
{
|
||||
anc_wr(anc, R_ANC_LINK_CONFIG, (V_ANC_LINK_CONFIG_ENABLE_CRC(0) |
|
||||
V_ANC_LINK_CONFIG_DDR_MODE(0)));
|
||||
anc_wr(anc, R_ANC_LINK_CMD_TIMEOUT, (V_ANC_LINK_CMD_TIMEOUT_VALUE(60 * 1000 * 1000) |
|
||||
V_ANC_LINK_CMD_TIMEOUT_ENABLE(1)));
|
||||
anc_wr(anc, R_ANC_DMA_CONTROL, V_ANC_DMA_CONTROL_START(1));
|
||||
anc_wr(anc, R_ANC_LINK_CONTROL, V_ANC_LINK_CONTROL_START(1));
|
||||
}
|
||||
|
||||
static void anc_boot_set_init_timings(anc_t *anc)
|
||||
{
|
||||
// All timings are fixed and recommend by DV: <rdar://problem/11051297>
|
||||
anc_wr(anc, R_ANC_LINK_SDR_DATA_TIMING, (V_ANC_LINK_SDR_DATA_TIMING_REN_HOLD_TIME(ANC_LINK_SDR_REN_HOLD_TIME) |
|
||||
V_ANC_LINK_SDR_DATA_TIMING_REN_SETUP_TIME(ANC_LINK_SDR_REN_SETUP_TIME) |
|
||||
V_ANC_LINK_SDR_DATA_TIMING_WEN_HOLD_TIME(ANC_LINK_SDR_WEN_HOLD_TIME) |
|
||||
V_ANC_LINK_SDR_DATA_TIMING_WEN_SETUP_TIME(ANC_LINK_SDR_REN_SETUP_TIME)));
|
||||
anc_wr(anc, R_ANC_LINK_COMMAND_ADDRESS_PULSE_TIMING,
|
||||
(V_ANC_LINK_COMMAND_ADDRESS_PULSE_TIMING_CA_HOLD_TIME(ANC_LINK_CMD_ADDR_PULSE_TIMING_CA_HOLD_TIME) |
|
||||
V_ANC_LINK_COMMAND_ADDRESS_PULSE_TIMING_CA_SETUP_TIME(ANC_LINK_CMD_ADDR_PULSE_TIMING_CA_SETUP_TIME)));
|
||||
anc_wr(anc, R_ANC_LINK_READ_STATUS_CONFIG, (V_ANC_LINK_READ_STATUS_CONFIG_POSITION(0x40) |
|
||||
V_ANC_LINK_READ_STATUS_CONFIG_POLARITY(0x40) |
|
||||
V_ANC_LINK_READ_STATUS_CONFIG_STATUS_CAPTURE_DELAY(10) |
|
||||
V_ANC_LINK_READ_STATUS_CONFIG_READY_SAMPLE_DELAY(8)));
|
||||
|
||||
anc_wr(anc, R_ANC_LINK_SDR_TIMING,
|
||||
(V_ANC_LINK_SDR_TIMING_DATA_CAPTURE_DELAY(ANC_LINK_SDR_DATA_CAPTURE_DELAY) |
|
||||
V_ANC_LINK_SDR_TIMING_CLE_ALE_SETUP_TIME(ANC_LINK_SDR_CLE_ALE_SETUP_TIME) |
|
||||
V_ANC_LINK_SDR_TIMING_CLE_ALE_HOLD_TIME(0)));
|
||||
}
|
||||
|
||||
static bool anc_boot_nand_reset(int busesToReset)
|
||||
{
|
||||
bool ret;
|
||||
int controller;
|
||||
anc_t *anc;
|
||||
const uint32_t int_mask = (M_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG |
|
||||
M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE |
|
||||
M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT);
|
||||
uint32_t int_status;
|
||||
utime_t current_time;
|
||||
|
||||
// Wait 10ms after SoC reset to ensure we don't violate tPURST
|
||||
current_time = system_time();
|
||||
if (current_time < T_PURST_USEC)
|
||||
{
|
||||
task_sleep(T_PURST_USEC - current_time);
|
||||
}
|
||||
|
||||
// First, issue a reset on all CEs attached to each bus
|
||||
for (controller = 0; controller < busesToReset; controller++)
|
||||
{
|
||||
anc = &g_boot_anc[controller];
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(T_CERDY_CYCLES));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__RESET));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(0));
|
||||
}
|
||||
|
||||
// Wait for bus 0, ce 0 to complete
|
||||
anc = &g_boot_anc[0];
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__LOW_POWER_READ_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_STATUS(0, PPN_LOW_POWER_STATUS__READY, PPN_LOW_POWER_STATUS__READY));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__SEND_INTERRUPT(0, 0));
|
||||
|
||||
int_status = anc_boot_wait_interrupt(anc, int_mask);
|
||||
if (!int_status)
|
||||
{
|
||||
// Timeout waiting for any status bits (including timeout bit - if we hit this, the ANC hw timeout
|
||||
// parts aren't working right
|
||||
dprintf(DEBUG_INFO, "Timeout waiting for CHAN_INT_STATUS != 0 - this should never happen\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (G_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG(int_status))
|
||||
{
|
||||
// Successful status read
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Timeout or invalid status
|
||||
dprintf(DEBUG_INFO, "Unexpected status 0x%08X\n", int_status);
|
||||
dprintf(DEBUG_INFO, "NAND Status: 0x%02X\n", anc_rd(anc, R_ANC_LINK_NAND_STATUS));
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool anc_bootrom_read_phys_page(uint32_t band,
|
||||
uint32_t dip,
|
||||
uint32_t page,
|
||||
uint32_t num_lbas,
|
||||
void *data,
|
||||
uint32_t *meta)
|
||||
{
|
||||
anc_t *anc = &g_boot_anc[0];
|
||||
const uint32_t intmask = (M_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG |
|
||||
M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT |
|
||||
M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE);
|
||||
uint32_t intstatus;
|
||||
unsigned int lba;
|
||||
addr_t paddr;
|
||||
bool ret = true;
|
||||
|
||||
paddr = mem_static_map_physical((addr_t)data);
|
||||
if (!paddr)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "No buffer\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((paddr & (16 - 1)) != 0)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "ANC buffers must be 16 byte aligned\n");
|
||||
return false;
|
||||
}
|
||||
if (!meta)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "No meta buffer\n");
|
||||
return false;
|
||||
}
|
||||
if (num_lbas == 0)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Invalid num_lbas %d\n", num_lbas);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, data, NAND_BOOT_LOGICAL_PAGE_SIZE * num_lbas);
|
||||
#endif
|
||||
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_CONFIG(DMA_DIRECTION_N2M, false));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__READ));
|
||||
|
||||
// Can't use LINK_CMD_ADDR6: rdar://problem/10941493
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__OPCODE(LINK_CMD_OP_ADDR6) | ((page & 0xFF) << 16));
|
||||
anc_boot_put_link_command(anc, page >> 8);
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD2(NAND_CMD__READ_CONFIRM, NAND_CMD__READ_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_STATUS(0x00,
|
||||
(PPN_LOW_POWER_STATUS__READY |
|
||||
PPN_LOW_POWER_STATUS__FAIL),
|
||||
PPN_LOW_POWER_STATUS__READY));
|
||||
|
||||
// Wait 27 clocks for RW turnaround
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__OPCODE(LINK_CMD_OP_WAIT_TIME) | 0x1b);
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__READ));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__OPCODE(LINK_CMD_OP_WAIT_TIME) | 0x1b);
|
||||
for (lba = 0; lba < num_lbas; lba++)
|
||||
{
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_PIO(NAND_BOOT_BYTES_PER_META, false, false));
|
||||
if (lba == (num_lbas - 1))
|
||||
{
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__SEND_INTERRUPT(0, 0));
|
||||
}
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_DMA(NAND_BOOT_LOGICAL_PAGE_SIZE, false, false));
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_BUFDESC(NAND_BOOT_LOGICAL_PAGE_SIZE,
|
||||
(uint64_t)paddr + lba * NAND_BOOT_LOGICAL_PAGE_SIZE));
|
||||
}
|
||||
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_FLAG(0, 0));
|
||||
|
||||
intstatus = anc_boot_wait_interrupt(anc, intmask);
|
||||
if (!intstatus)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Timeout waiting for CHAN_INT_STATUS != 0 - this should never happen\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// We've either timed out or gotten our status by now
|
||||
if (intstatus & M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT)
|
||||
{
|
||||
// Timeout waiting for status: flush LINK CmdQ and return error
|
||||
dprintf(DEBUG_INFO, "Timeout waiting for NAND status\n");
|
||||
anc_wr(anc, R_ANC_LINK_CONTROL, M_ANC_LINK_CONTROL_RESET_CMDQ);
|
||||
return false;
|
||||
}
|
||||
else if (intstatus & M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE)
|
||||
{
|
||||
// Invalid status (probably has error bit set). Reset CmdQ and return error
|
||||
dprintf(DEBUG_INFO, "Invalid NAND status 0x%02X\n", anc_rd(anc, R_ANC_LINK_NAND_STATUS));
|
||||
anc_wr(anc, R_ANC_LINK_CONTROL, M_ANC_LINK_CONTROL_RESET_CMDQ);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We've got a good status and metadata should be available now.
|
||||
|
||||
for (lba = 0; lba < num_lbas; lba++)
|
||||
{
|
||||
uint32_t meta_index;
|
||||
for (meta_index = 0; meta_index < (NAND_BOOT_BYTES_PER_META/ sizeof(uint32_t)); meta_index++)
|
||||
{
|
||||
uint32_t meta_word = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
if ((meta_index == 0) && (meta_word != meta[0]))
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Invalid meta: expected 0x%08X got 0x%08X\n", meta[0], meta_word);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if APPLICATION_SECUREROM
|
||||
if (!anc_boot_wait_reg(anc, R_ANC_CHAN_INT_STATUS,
|
||||
M_ANC_CHAN_INT_STATUS_DMA_CMD_FLAG,
|
||||
M_ANC_CHAN_INT_STATUS_DMA_CMD_FLAG))
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Timeout waiting for DMA to complete\n");
|
||||
return false;
|
||||
}
|
||||
#else // APPLICATION_SECUREROM
|
||||
intstatus = anc_boot_wait_interrupt(anc, M_ANC_CHAN_INT_STATUS_DMA_CMD_FLAG | M_ANC_CHAN_INT_STATUS_DMA_CMD_TIMEOUT);
|
||||
if (!intstatus || (intstatus & M_ANC_CHAN_INT_STATUS_DMA_CMD_TIMEOUT))
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Timeout waiting for DMA to complete - 0x%08x\n", intstatus);
|
||||
return false;
|
||||
}
|
||||
#endif // APPLICATION_SECUREROM
|
||||
|
||||
anc_wr(anc, R_ANC_CHAN_INT_STATUS, M_ANC_CHAN_INT_STATUS_DMA_CMD_FLAG);
|
||||
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
platform_cache_operation(CACHE_INVALIDATE, data, NAND_BOOT_LOGICAL_PAGE_SIZE * num_lbas);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void anc_boot_put_link_command(anc_t *anc, uint32_t value)
|
||||
{
|
||||
#if APPLICATION_SECUREROM
|
||||
anc_boot_wait_reg(anc, R_ANC_CHAN_LINK_CMDQ_FIFO_STATUS, M_ANC_CHAN_LINK_CMDQ_FIFO_STATUS_FULL, 0);
|
||||
anc_wr(anc, R_ANC_CHAN_LINK_CMDQ_FIFO, value);
|
||||
#else // APPLICATION_SECUREROM
|
||||
if (anc_boot_wait_reg_int_timeout(anc, R_ANC_CHAN_LINK_CMDQ_FIFO_STATUS, M_ANC_CHAN_LINK_CMDQ_FIFO_STATUS_FULL, 0, M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT))
|
||||
{
|
||||
anc_wr(anc, R_ANC_CHAN_LINK_CMDQ_FIFO, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Timeout waiting for room in link command FIFO\n");
|
||||
}
|
||||
#endif // APPLICATION_SECUREROM
|
||||
}
|
||||
|
||||
void anc_boot_put_dma_command(anc_t *anc, uint64_t value)
|
||||
{
|
||||
#if APPLICATION_SECUREROM
|
||||
anc_boot_wait_reg(anc, R_ANC_CHAN_LINK_CMDQ_FIFO_STATUS, M_ANC_CHAN_DMA_CMDQ_FIFO_STATUS_FULL, 0);
|
||||
anc_wr(anc, R_ANC_CHAN_DMA_CMDQ_FIFO, value & 0xFFFFFFFFUL);
|
||||
anc_wr(anc, R_ANC_CHAN_DMA_CMDQ_FIFO, (value >> 32UL));
|
||||
#else // APPLICATION_SECUREROM
|
||||
if (anc_boot_wait_reg_int_timeout(anc, R_ANC_CHAN_LINK_CMDQ_FIFO_STATUS, M_ANC_CHAN_DMA_CMDQ_FIFO_STATUS_FULL, 0, M_ANC_CHAN_INT_STATUS_DMA_CMD_TIMEOUT))
|
||||
{
|
||||
anc_wr(anc, R_ANC_CHAN_DMA_CMDQ_FIFO, value & 0xFFFFFFFFUL);
|
||||
anc_wr(anc, R_ANC_CHAN_DMA_CMDQ_FIFO, (value >> 32UL));
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Timeout waiting for room in DMA command FIFO\n");
|
||||
}
|
||||
#endif // APPLICATION_SECUREROM
|
||||
}
|
||||
|
||||
// Wait up to ANC_TIMEOUT_MICROS for ((reg & mask) == value)
|
||||
bool anc_boot_wait_reg(anc_t *anc, uint32_t reg, uint32_t mask, uint32_t value)
|
||||
{
|
||||
utime_t start_time = system_time();
|
||||
uint32_t regval;
|
||||
|
||||
do
|
||||
{
|
||||
regval = anc_rd(anc, reg);
|
||||
if ((regval & mask) == value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} while (!time_has_elapsed(start_time, ANC_TIMEOUT_MICROS));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !APPLICATION_SECUREROM
|
||||
// Like anc_boot_wait_reg, but waits until (R_ANC_CHAN_INT_MASK & tomask) to determine the timeout instead of using ANC_TIMEOUT_MICROS. Only used by LLB.
|
||||
bool anc_boot_wait_reg_int_timeout(anc_t *anc, uint32_t reg, uint32_t mask, uint32_t value, uint32_t tomask)
|
||||
{
|
||||
uint32_t regval, intval;
|
||||
|
||||
do
|
||||
{
|
||||
regval = anc_rd(anc, reg);
|
||||
if ((regval & mask) == value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
intval = anc_rd(anc, R_ANC_CHAN_INT_STATUS);
|
||||
} while (!(intval & tomask));
|
||||
|
||||
anc_wr(anc, R_ANC_CHAN_INT_STATUS, (intval & tomask));
|
||||
|
||||
regval = anc_rd(anc, reg);
|
||||
if ((regval & mask) == value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif // !APPLICATION_SECUREROM
|
||||
|
||||
uint32_t anc_boot_wait_interrupt(anc_t *anc, uint32_t mask)
|
||||
{
|
||||
#if APPLICATION_SECUREROM
|
||||
utime_t start_time = system_time();
|
||||
#endif // APPLICATION_SECUREROM
|
||||
uint32_t regval;
|
||||
|
||||
do
|
||||
{
|
||||
regval = anc_rd(anc, R_ANC_CHAN_INT_STATUS);
|
||||
if (regval & mask)
|
||||
{
|
||||
// Only clear the bits we're looking for
|
||||
anc_wr(anc, R_ANC_CHAN_INT_STATUS, (regval & mask));
|
||||
return regval;
|
||||
}
|
||||
#if APPLICATION_SECUREROM
|
||||
} while (!time_has_elapsed(start_time, ANC_TIMEOUT_MICROS));
|
||||
#else // APPLICATION_SECUREROM
|
||||
} while (1);
|
||||
#endif // APPLICATION_SECUREROM
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void anc_disable_uid(anc_t *anc)
|
||||
{
|
||||
// The DISABLE_UID bit doesn't work unless AES is enabled. Force a DMA_CONFIG to enable it
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_CONFIG(DMA_DIRECTION_N2M, true));
|
||||
|
||||
// Wait for AES to become enabled
|
||||
anc_boot_wait_reg(anc, R_ANC_DMA_STATUS, M_ANC_DMA_STATUS_AES_ENABLED, M_ANC_DMA_STATUS_AES_ENABLED);
|
||||
#ifdef M_ANC_DMA_UID_CONFIG_DISABLE_UID
|
||||
// Disable UID1 (doesn't exist on M7)
|
||||
anc_wr(anc, R_ANC_DMA_UID_CONFIG, M_ANC_DMA_UID_CONFIG_DISABLE_UID);
|
||||
#endif
|
||||
}
|
||||
|
||||
void anc_disable_uid_key(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!g_boot_anc[0].initialized)
|
||||
{
|
||||
// If we came in here through the DFU path, ANC isn't configured.
|
||||
anc_bootrom_init(false, ANC_BOOT_MODE_RESET_ALL_CONTROLLERS);
|
||||
}
|
||||
|
||||
for (i = 0; i < ANC_BOOT_CONTROLLERS; i++)
|
||||
{
|
||||
anc_disable_uid(&g_boot_anc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.
|
||||
*/
|
||||
|
||||
#ifndef _ANC_BOOTROM_H_
|
||||
#define _ANC_BOOTROM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int anc_bootrom_init(bool reset, int resetMode);
|
||||
bool anc_bootrom_read_phys_page(uint32_t band,
|
||||
uint32_t dip,
|
||||
uint32_t page,
|
||||
uint32_t num_lbas,
|
||||
void *data,
|
||||
uint32_t *meta);
|
||||
#endif // _ANC_BOOTROM_H_
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
#ifndef _ANC_CMDS_H_
|
||||
#define _ANC_CMDS_H_
|
||||
|
||||
#define LINK_CMDQ_SIZE 128
|
||||
#define DMA_CMDQ_SIZE 64 // 64b words, not 32b
|
||||
#define LINK_PIO_READ_FIFO_SIZE 64
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// DMA Command Definitions
|
||||
#define DMA_COMMAND__OPCODE(n) (((n) & 0x7FULL) << 60)
|
||||
#define DMA_COMMAND__OPCODE__CONFIG (0)
|
||||
#define DMA_COMMAND__OPCODE__BUFDESC (1)
|
||||
#define DMA_COMMAND__OPCODE__AES_KEY_IV (2)
|
||||
#define DMA_COMMAND__OPCODE__AES_UID1_IV (3)
|
||||
#define DMA_COMMAND__OPCODE__AES_IV (4)
|
||||
#define DMA_COMMAND__OPCODE__FLAG (5)
|
||||
|
||||
#define DMA_COMMAND_CONFIG__DMA_DIRECTION(n) (((n) & 0x1ULL) << 53)
|
||||
#define DMA_DIRECTION_M2N (0)
|
||||
#define DMA_DIRECTION_N2M (1)
|
||||
#define DMA_COMMAND_CONFIG__PROC_ENABLE_AES(n) (((n) & 0x1ULL) << 54)
|
||||
|
||||
#define DMA_COMMAND_BUFDESC__LENGTH(n) (((n) & 0x1FFFULL) << 40)
|
||||
#define DMA_COMMAND_BUFDESC__ADDRESS(n) (((n) & 0xFFFFFFFFFFULL) << 0)
|
||||
|
||||
#define DMA_COMMAND_AESKEY__UNWRAP(n) (((n) & 0x1ULL) << 2)
|
||||
#define DMA_COMMAND_AESKEY__KEY_LEN(n) (((n) & 0x3ULL) << 0)
|
||||
#define DMA_COMMAND_AESKEY_128_BITS (0)
|
||||
#define DMA_COMMAND_AESKEY_192_BITS (1)
|
||||
#define DMA_COMMAND_AESKEY_256_BITS (2)
|
||||
|
||||
#define DMA_COMMAND_FLAG__PAUSE(n) (((n) & 0x1ULL) << 16)
|
||||
#define DMA_COMMAND_FLAG__CODE(n) (((n) & 0xFFFFULL) << 0)
|
||||
|
||||
#define DMA_COMMAND_CONFIG(dir,aes) \
|
||||
(DMA_COMMAND__OPCODE(DMA_COMMAND__OPCODE__CONFIG) | \
|
||||
DMA_COMMAND_CONFIG__DMA_DIRECTION(dir) | \
|
||||
DMA_COMMAND_CONFIG__PROC_ENABLE_AES(aes))
|
||||
#define DMA_COMMAND_BUFDESC(data_bytes,address) \
|
||||
(DMA_COMMAND__OPCODE(DMA_COMMAND__OPCODE__BUFDESC) | \
|
||||
DMA_COMMAND_BUFDESC__LENGTH(data_bytes) | \
|
||||
DMA_COMMAND_BUFDESC__ADDRESS(address))
|
||||
#define DMA_COMMAND_AES_KEY_IV(key_len, unwrap_en) \
|
||||
(DMA_COMMAND__OPCODE(DMA_COMMAND__OPCODE__AES_KEY_IV) | \
|
||||
DMA_COMMAND_AESKEY__KEY_LEN(key_len) | \
|
||||
DMA_COMMAND_AESKEY__UNWRAP(unwrap_en))
|
||||
#define DMA_COMMAND_FLAG(code,pause) \
|
||||
(DMA_COMMAND__OPCODE(DMA_COMMAND__OPCODE__FLAG) | \
|
||||
DMA_COMMAND_FLAG__PAUSE(pause) | \
|
||||
DMA_COMMAND_FLAG__CODE(code))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Link Command Definitions
|
||||
#define LINK_COMMAND__YIELD (1UL << 31)
|
||||
#define LINK_COMMAND__OPCODE(n) (((n) & 0x3FUL) << 24)
|
||||
|
||||
#define LINK_CMD_OP_DEBUG_DLL 0x00
|
||||
#define LINK_CMD_OP_CMD0 0x01
|
||||
#define LINK_CMD_OP_CMD1 0x02
|
||||
#define LINK_CMD_OP_CMD1_OP 0x03
|
||||
#define LINK_CMD_OP_CMD2 0x04
|
||||
#define LINK_CMD_OP_CMD2_OP 0x05
|
||||
#define LINK_CMD_OP_CMD3 0x06
|
||||
#define LINK_CMD_OP_CMD3_OP 0x07
|
||||
#define LINK_CMD_OP_CMD4 0x08
|
||||
#define LINK_CMD_OP_CMD4_OP 0x09
|
||||
#define LINK_CMD_OP_CMD5 0x0A
|
||||
#define LINK_CMD_OP_CMD5_OP 0x0B
|
||||
#define LINK_CMD_OP_CMD6 0x0C
|
||||
#define LINK_CMD_OP_CMD6_OP 0x0D
|
||||
#define LINK_CMD_OP_CMD7 0x0E
|
||||
#define LINK_CMD_OP_CMD7_OP 0x0F
|
||||
#define LINK_CMD_OP_CMD8_OP 0x10
|
||||
#define LINK_CMD_OP_ADDR1 0x12
|
||||
#define LINK_CMD_OP_ADDR1_OP 0x13
|
||||
#define LINK_CMD_OP_ADDR2 0x14
|
||||
#define LINK_CMD_OP_ADDR2_OP 0x15
|
||||
#define LINK_CMD_OP_ADDR3 0x16
|
||||
#define LINK_CMD_OP_ADDR3_OP 0x17
|
||||
#define LINK_CMD_OP_ADDR4 0x18
|
||||
#define LINK_CMD_OP_ADDR4_OP 0x19
|
||||
#define LINK_CMD_OP_ADDR5 0x1A
|
||||
#define LINK_CMD_OP_ADDR5_OP 0x1B
|
||||
#define LINK_CMD_OP_ADDR6 0x1C
|
||||
#define LINK_CMD_OP_ADDR6_OP 0x1D
|
||||
#define LINK_CMD_OP_ADDR7 0x1E
|
||||
#define LINK_CMD_OP_ADDR7_OP 0x1F
|
||||
#define LINK_CMD_OP_ADDR8_OP 0x20
|
||||
#define LINK_CMD_OP_READ_RELEASE 0x21
|
||||
#define LINK_CMD_OP_CE 0x22
|
||||
#define LINK_CMD_OP_CE_OP 0x23
|
||||
#define LINK_CMD_OP_READ_DMA 0x24
|
||||
#define LINK_CMD_OP_READ_DMA_OP 0x25
|
||||
#define LINK_CMD_OP_READ_PIO 0x26
|
||||
#define LINK_CMD_OP_READ_PIO_OP 0x27
|
||||
#define LINK_CMD_OP_READ_NUL 0x28
|
||||
#define LINK_CMD_OP_READ_NUL_OP 0x29
|
||||
#define LINK_CMD_OP_READ_STATUS 0x2A
|
||||
#define LINK_CMD_OP_READ_STATUS_ABORT_ENABLED 0x2B
|
||||
#define LINK_CMD_OP_WRITE_DMA 0x2C
|
||||
#define LINK_CMD_OP_WRITE_DMA_OP 0x2D
|
||||
#define LINK_CMD_OP_WRITE_PIO 0x2E
|
||||
#define LINK_CMD_OP_WRITE_PIO_OP 0x2F
|
||||
#define LINK_CMD_OP_WRITE_PIO_IMM 0x30
|
||||
#define LINK_CMD_OP_WRITE_PAD 0x32
|
||||
#define LINK_CMD_OP_WRITE_PAD_OP 0x33
|
||||
#define LINK_CMD_OP_READ_REGISTER 0x34
|
||||
#define LINK_CMD_OP_WRITE_REGISTER 0x35
|
||||
#define LINK_CMD_OP_POLL_REGISTER 0x36
|
||||
#define LINK_CMD_OP_POLL_REGISTER_ABORT_ENABLED 0x37
|
||||
#define LINK_CMD_OP_WAIT_TIME 0x38
|
||||
#define LINK_CMD_OP_WAIT_TIME_ABORT_ENABLED 0x39
|
||||
#define LINK_CMD_OP_WAIT_FOR_INTERRUPT 0x3A
|
||||
#define LINK_CMD_OP_WAIT_FOR_INTERRUPT_ABORT_ENABLED 0x3B
|
||||
#define LINK_CMD_OP_SEND_INTERRUPT 0x3C
|
||||
#define LINK_CMD_OP_MACRO 0x3D
|
||||
#define LINK_CMD_OP_DPI_OUT 0x3E
|
||||
#define LINK_CMD_OP_DPI_IN 0x3F
|
||||
|
||||
#define LINK_COMMAND__CE__CE(ce) (((ce) & 0xFFUL) << 0)
|
||||
#define LINK_COMMAND__CE(ce) (LINK_COMMAND__OPCODE(LINK_CMD_OP_CE) | LINK_COMMAND__CE__CE(ce))
|
||||
|
||||
#define LINK_COMMAND__CMD__CMD2(n) (((n) & 0xFFUL) << 16)
|
||||
#define LINK_COMMAND__CMD__CMD1(n) (((n) & 0xFFUL) << 8)
|
||||
#define LINK_COMMAND__CMD__CMD0(n) (((n) & 0xFFUL) << 0)
|
||||
|
||||
#define LINK_COMMAND__CMD1(cmd1) (LINK_COMMAND__OPCODE(LINK_CMD_OP_CMD1) | LINK_COMMAND__CMD__CMD0(cmd1))
|
||||
#define LINK_COMMAND__CMD2(cmd1,cmd2) (LINK_COMMAND__OPCODE(LINK_CMD_OP_CMD2) | \
|
||||
LINK_COMMAND__CMD__CMD0(cmd1) | \
|
||||
LINK_COMMAND__CMD__CMD1(cmd2))
|
||||
#define LINK_COMMAND__CMD3(cmd1,cmd2,cmd3) (LINK_COMMAND__OPCODE(LINK_CMD_OP_CMD3) | \
|
||||
LINK_COMMAND__CMD__CMD0(cmd1) | \
|
||||
LINK_COMMAND__CMD__CMD1(cmd2) | \
|
||||
LINK_COMMAND__CMD__CMD2(cmd3))
|
||||
|
||||
|
||||
#define LINK_COMMAND__ADDR__ADDR2(n) (((n) & 0xFFUL) << 16)
|
||||
#define LINK_COMMAND__ADDR__ADDR1(n) (((n) & 0xFFUL) << 8)
|
||||
#define LINK_COMMAND__ADDR__ADDR0(n) (((n) & 0xFFUL) << 0)
|
||||
#define LINK_COMMAND__ADDR1(addr0) (LINK_COMMAND__OPCODE(LINK_CMD_OP_ADDR1) | \
|
||||
LINK_COMMAND__ADDR__ADDR0(addr0))
|
||||
#define LINK_COMMAND__ADDR2(addr0,addr1) (LINK_COMMAND__OPCODE(LINK_CMD_OP_ADDR2) | \
|
||||
LINK_COMMAND__ADDR__ADDR0(addr0) | \
|
||||
LINK_COMMAND__ADDR__ADDR1(addr1))
|
||||
#define LINK_COMMAND__ADDR3(addr0,addr1,addr2) (LINK_COMMAND__OPCODE(LINK_CMD_OP_ADDR3) | \
|
||||
LINK_COMMAND__ADDR__ADDR0(addr0) | \
|
||||
LINK_COMMAND__ADDR__ADDR1(addr1) | \
|
||||
LINK_COMMAND__ADDR__ADDR2(addr2))
|
||||
|
||||
#define LINK_COMMAND__WRITE_DMA__LEN(n) (((n) & 0x7FFFUL) << 0)
|
||||
#define LINK_COMMAND__WRITE_DMA__CRC_START(n) (((n) & 0x1UL) << 22)
|
||||
#define LINK_COMMAND__WRITE_DMA__CRC_STOP(n) (((n) & 0x1UL) << 23)
|
||||
#define LINK_COMMAND__WRITE_DMA(len, crc_start, crc_stop) (LINK_COMMAND__OPCODE(LINK_CMD_OP_WRITE_DMA) | \
|
||||
LINK_COMMAND__WRITE_DMA__LEN(len) | \
|
||||
LINK_COMMAND__WRITE_DMA__CRC_START(crc_start) | \
|
||||
LINK_COMMAND__WRITE_DMA__CRC_STOP(crc_stop))
|
||||
|
||||
#define LINK_COMMAND__WRITE_PIO__LEN(n) (((n) & 0x7FFFUL) << 0)
|
||||
#define LINK_COMMAND__WRITE_PIO__CRC_START(n) (((n) & 0x1UL) << 22)
|
||||
#define LINK_COMMAND__WRITE_PIO__CRC_STOP(n) (((n) & 0x1UL) << 23)
|
||||
#define LINK_COMMAND__WRITE_PIO(len, crc_start, crc_stop) (LINK_COMMAND__OPCODE(LINK_CMD_OP_WRITE_PIO) | \
|
||||
LINK_COMMAND__WRITE_PIO__LEN(len) | \
|
||||
LINK_COMMAND__WRITE_PIO__CRC_START(crc_start) | \
|
||||
LINK_COMMAND__WRITE_PIO__CRC_STOP(crc_stop))
|
||||
|
||||
#define LINK_COMMAND__READ_DMA__LEN(n) (((n) & 0x7FFFUL) << 0)
|
||||
#define LINK_COMMAND__READ_DMA__CRC_START(n) (((n) & 0x1UL) << 22)
|
||||
#define LINK_COMMAND__READ_DMA__CRC_STOP(n) (((n) & 0x1UL) << 23)
|
||||
#define LINK_COMMAND__READ_DMA(len, crc_start, crc_stop) (LINK_COMMAND__OPCODE(LINK_CMD_OP_READ_DMA) | \
|
||||
LINK_COMMAND__READ_DMA__LEN(len) | \
|
||||
LINK_COMMAND__READ_DMA__CRC_START(crc_start) | \
|
||||
LINK_COMMAND__READ_DMA__CRC_STOP(crc_stop))
|
||||
|
||||
#define LINK_COMMAND__READ_PIO__LEN(n) (((n) & 0x7FFFUL) << 0)
|
||||
#define LINK_COMMAND__READ_PIO__CRC_START(n) (((n) & 0x1UL) << 22)
|
||||
#define LINK_COMMAND__READ_PIO__CRC_STOP(n) (((n) & 0x1UL) << 23)
|
||||
#define LINK_COMMAND__READ_PIO(len, crc_start, crc_stop) (LINK_COMMAND__OPCODE(LINK_CMD_OP_READ_PIO) | \
|
||||
LINK_COMMAND__READ_PIO__LEN(len) | \
|
||||
LINK_COMMAND__READ_PIO__CRC_START(crc_start) | \
|
||||
LINK_COMMAND__READ_PIO__CRC_STOP(crc_stop))
|
||||
|
||||
#define LINK_COMMAND__READ_STATUS__CODE(n) (((n) & 0xFFUL) << 16)
|
||||
#define LINK_COMMAND__READ_STATUS__MASK(n) (((n) & 0xFFUL) << 8)
|
||||
#define LINK_COMMAND__READ_STATUS__COND(n) (((n) & 0xFFUL) << 0)
|
||||
#define LINK_COMMAND__READ_STATUS(code,mask,cond) (LINK_COMMAND__OPCODE(LINK_CMD_OP_READ_STATUS) | \
|
||||
LINK_COMMAND__READ_STATUS__CODE(code) | \
|
||||
LINK_COMMAND__READ_STATUS__MASK(mask) | \
|
||||
LINK_COMMAND__READ_STATUS__COND(cond))
|
||||
|
||||
#define LINK_COMMAND__SEND_INTERRUPT__PAUSE(n) (((n) & 0x1UL) << 23)
|
||||
#define LINK_COMMAND__SEND_INTERRUPT__CODE(n) (((n) & 0xFFFFUL) << 0)
|
||||
#define LINK_COMMAND__SEND_INTERRUPT(pause,code) (LINK_COMMAND__OPCODE(LINK_CMD_OP_SEND_INTERRUPT) | \
|
||||
LINK_COMMAND__SEND_INTERRUPT__PAUSE(pause) | \
|
||||
LINK_COMMAND__SEND_INTERRUPT__CODE(code))
|
||||
|
||||
#define LINK_COMMAND__READ_REGISTER__ADDR(n) (((n) & 0xFFFFFFUL) << 0)
|
||||
#define LINK_COMMAND__READ_REGISTER(addr) (LINK_COMMAND__OPCODE(LINK_CMD_OP_READ_REGISTER) | \
|
||||
LINK_COMMAND__READ_REGISTER__ADDR(addr))
|
||||
|
||||
#define LINK_COMMAND__WRITE_REGISTER__ADDR(n) (((n) & 0xFFFFFFUL) << 0)
|
||||
#define LINK_COMMAND__WRITE_REGISTER(addr) (LINK_COMMAND__OPCODE(LINK_CMD_OP_WRITE_REGISTER) | \
|
||||
LINK_COMMAND__WRITE_REGISTER__ADDR(addr))
|
||||
|
||||
#define LINK_COMMAND__WAIT_TIME__CYCLES(n) (((n) & 0xFFFFUL) << 0)
|
||||
#define LINK_COMMAND__WAIT_TIME(link_cycles) (LINK_COMMAND__OPCODE(LINK_CMD_OP_WAIT_TIME) | \
|
||||
LINK_COMMAND__WAIT_TIME__CYCLES((link_cycles)))
|
||||
|
||||
#define LINK_COMMAND__MACRO__LENGTH(n) (((n) & 0xFFUL) << 0)
|
||||
#define LINK_COMMAND__MACRO__ADDR(n) (((n) & 0xFFUL) << 8)
|
||||
#define LINK_COMMAND__MACRO__REPEAT(n) (((n) & 0xFFUL) << 16)
|
||||
#define LINK_COMMAND__MACRO(addr,length,repeat) (LINK_COMMAND__OPCODE(LINK_CMD_OP_MACRO) | \
|
||||
LINK_COMMAND__MACRO__LENGTH(length-1) | \
|
||||
LINK_COMMAND__MACRO__ADDR(addr) | \
|
||||
LINK_COMMAND__MACRO__REPEAT(repeat))
|
||||
|
||||
#endif // _ANC_CMDS_H_
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.
|
||||
*/
|
||||
#ifndef _ANC_BOOTROM_PRIVATE_H_
|
||||
#define _ANC_BOOTROM_PRIVATE_H_
|
||||
|
||||
#if SUB_PLATFORM_S7002
|
||||
# include "anc_bootrom_regs_m7.h"
|
||||
#else
|
||||
# include "anc_bootrom_regs.h"
|
||||
#endif
|
||||
#include "ppn_npl_regs.h"
|
||||
#include "anc_bootrom_cmds.h"
|
||||
|
||||
#define ANC_MAX_CES_PER_BUS (1)
|
||||
#define ANC_NAND_ID_SIZE (6)
|
||||
|
||||
#define NAND_BOOT_PAGES_PER_BLOCK 128
|
||||
#define NAND_BOOT_BYTES_PER_META 16
|
||||
#define NAND_BOOT_BYTES_PER_PAGE 8192
|
||||
#define NAND_BOOT_LOGICAL_PAGE_SIZE 4096
|
||||
|
||||
// NAND Commands
|
||||
#define NAND_CMD__RESET ((uint8_t)0xFF)
|
||||
#define NAND_CMD__READ_ID ((uint8_t)0x90)
|
||||
#define NAND_CMD__READ_STATUS ((uint8_t)0x70)
|
||||
#define NAND_CMD__READ ((uint8_t)0x00)
|
||||
#define NAND_CMD__READ_CONFIRM ((uint8_t)0x30)
|
||||
|
||||
#define NAND_CMD__MULTIPAGE_READ ((uint8_t)0x07)
|
||||
#define NAND_CMD__MULTIPAGE_READ_LAST ((uint8_t)0x0A)
|
||||
#define NAND_CMD__MULTIPAGE_READ_CONFIRM ((uint8_t)0x37)
|
||||
#define NAND_CMD__MULTIPAGE_PROGRAM ((uint8_t)0x87)
|
||||
#define NAND_CMD__MULTIPAGE_PROGRAM_LAST ((uint8_t)0x8A)
|
||||
#define NAND_CMD__MULTIPAGE_PROGRAM_CONFIRM ((uint8_t)0x17)
|
||||
#define NAND_CMD__MULTIPAGE_PREP ((uint8_t)0xB0)
|
||||
#define NAND_CMD__MULTIPAGE_PREP__CONFIRM ((uint8_t)0xB8)
|
||||
#define NAND_CMD__MULTIBLOCK_ERASE ((uint8_t)0x67)
|
||||
#define NAND_CMD__MULTIBLOCK_ERASE_LAST ((uint8_t)0x6A)
|
||||
#define NAND_CMD__MULTIBLOCK_ERASE_CONFIRM ((uint8_t)0xD7)
|
||||
#define NAND_CMD__LOW_POWER_READ_STATUS ((uint8_t)0x70)
|
||||
#define NAND_CMD__GET_NEXT_OPERATION_STATUS ((uint8_t)0x77)
|
||||
#define NAND_CMD__OPERATION_STATUS ((uint8_t)0x7D)
|
||||
#define NAND_CMD__READ_SERIAL_OUTPUT ((uint8_t)0x7A)
|
||||
#define NAND_CMD__CONTROLLER_STATUS ((uint8_t)0x79)
|
||||
#define NAND_CMD__READ_DEVICE_PARAMETERS ((uint8_t)0x92)
|
||||
#define NAND_CMD__READ_DEVICE_PARAMETERS_CONFIRM ((uint8_t)0x97)
|
||||
#define NAND_CMD__SET_FEATURES ((uint8_t)0xEF)
|
||||
#define NAND_CMD__GET_FEATURES ((uint8_t)0xEE)
|
||||
#define NAND_CMD__SET_GET_FEATURES_CONFIRM ((uint8_t)0xE7)
|
||||
#define NAND_CMD__SET_DEBUG_DATA ((uint8_t)0xE9)
|
||||
#define NAND_CMD__GET_DEBUG_DATA ((uint8_t)0xE8)
|
||||
#define NAND_CMD__UPDATE_FW ((uint8_t)0xED)
|
||||
#define NAND_CMD__PPN_STATUS_CONFIRM ((uint8_t)0xED)
|
||||
|
||||
#define PPN_LOW_POWER_STATUS__FAIL (1 << 0)
|
||||
#define PPN_LOW_POWER_STATUS__READY (1 << 6)
|
||||
#define PPN_LOW_POWER_STATUS__WRITE_PROTECT_BAR (1 << 7)
|
||||
|
||||
#define PPN_FEATURE__POWER_STATE ((uint16_t)0x0180)
|
||||
|
||||
#define PPN_FEATURE__POWER_STATE__LOW_POWER 0x1
|
||||
#define PPN_FEATURE__POWER_STATE__NORMAL_ASYNC 0x2
|
||||
#define PPN_FEATURE__POWER_STATE__NORMAL_DDR 0xA
|
||||
#define PPN_FEATURE__POWER_STATE__STANDBY 0x4
|
||||
|
||||
#define CHIPID_ADDR (0x00)
|
||||
|
||||
#define PPN_BLOCK_PAIRING__NO_PAIRING (0x00)
|
||||
#define PPN_BLOCK_PAIRING__EVEN_ODD (0x10)
|
||||
#define PPN_BLOCK_PAIRING__FOUR_PLANE (0x20)
|
||||
|
||||
#define ROUNDUPTO(num, gran) ((((num) + (gran) - 1) / (gran)) * (gran))
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define ANC_BOOT_MAX_TIMING_REG_VALUE (M_ANC_LINK_SDR_DATA_TIMING_REN_SETUP_TIME >> S_ANC_LINK_SDR_DATA_TIMING_REN_SETUP_TIME)
|
||||
|
||||
typedef uint8_t anc_chip_id_t[ANC_NAND_ID_SIZE];
|
||||
|
||||
typedef struct anc_t
|
||||
{
|
||||
uint32_t bus_id;
|
||||
bool initialized;
|
||||
uint32_t *regs;
|
||||
|
||||
uint32_t pages_per_block;
|
||||
uint32_t bytes_per_meta;
|
||||
uint32_t meta_words;
|
||||
uint32_t bytes_per_page;
|
||||
uint32_t logical_page_size;
|
||||
uint32_t lbas_per_page;
|
||||
|
||||
anc_chip_id_t chip_id;
|
||||
|
||||
} anc_t;
|
||||
|
||||
extern anc_t g_boot_anc[ANC_BOOT_CONTROLLERS];
|
||||
|
||||
#define anc_wr(anc, reg, val) (*((anc)->regs + ((reg) >> 2)) = (val))
|
||||
#define anc_wr64(anc, reg, val) anc_store64((volatile uint64_t *)((anc)->regs + ((reg) >> 2)), (val))
|
||||
#define anc_rd(anc, reg) (*(volatile uint32_t *)((uint8_t *)((anc)->regs) + (reg)))
|
||||
#define anc_npl_wr(npl, reg, val) (*(npl + ((reg) >> 2)) = (val))
|
||||
|
||||
void anc_boot_put_link_command(anc_t *anc, uint32_t value);
|
||||
void anc_boot_put_dma_command(anc_t *anc, uint64_t value);
|
||||
uint32_t anc_boot_wait_interrupt(anc_t *anc, uint32_t mask);
|
||||
bool anc_boot_wait_reg(anc_t *anc, uint32_t reg, uint32_t mask, uint32_t value);
|
||||
#if !APPLICATION_SECUREROM
|
||||
bool anc_boot_wait_reg_int_timeout(anc_t *anc, uint32_t reg, uint32_t mask, uint32_t value, uint32_t tomask);
|
||||
#endif // !APPLICATION_SECUREROM
|
||||
|
||||
#endif // _ANC_BOOTROM_PRIVATE_H_
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,659 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 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/anc_boot.h>
|
||||
#include <platform.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys.h>
|
||||
#include "anc_bootrom.h"
|
||||
#include "anc_llb.h"
|
||||
#include "anc_bootrom_private.h"
|
||||
#include "util_boot.h"
|
||||
|
||||
anc_ppn_device_params_t *anc_geom;
|
||||
|
||||
#define NUM_DIP 256UL
|
||||
#define NUM_BUS 2UL
|
||||
|
||||
dip_info_t dip_info[NUM_DIP];
|
||||
int anc_num_channel; // number of populated channels
|
||||
|
||||
static bool anc_llb_set_normal_mode(void);
|
||||
static bool anc_llb_set_feature(anc_t *anc, uint16_t feature, const uint8_t *data, uint32_t len);
|
||||
static bool anc_llb_get_geometry(void);
|
||||
static bool anc_llb_read_chip_ids(void);
|
||||
static bool anc_llb_read_chip_id(anc_t *anc, anc_chip_id_t *chip_id);
|
||||
static bool anc_llb_read_device_parameters(anc_t *anc,
|
||||
anc_ppn_device_params_t *params);
|
||||
static void anc_llb_handle_geb(anc_t *anc);
|
||||
|
||||
int anc_llb_init(void)
|
||||
{
|
||||
unsigned int dip;
|
||||
unsigned int die;
|
||||
unsigned int plane;
|
||||
unsigned int bus;
|
||||
unsigned int cau_per_die;
|
||||
unsigned int numDip;
|
||||
unsigned int numPlane;
|
||||
unsigned int die_per_channel;
|
||||
|
||||
anc_geom = memalign(NUM_BUS * sizeof(anc_ppn_device_params_t), CPU_CACHELINE_SIZE);
|
||||
if (!anc_geom) panic("Unable to allocate anc_geom");
|
||||
|
||||
// Initialize ANC, but don't reset the NANDs - they're already good to go
|
||||
// in low-power mode coming out of SecureROM.
|
||||
if (anc_bootrom_init(false, ANC_BOOT_MODE_RESET_ALL_CONTROLLERS) != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Failed to init ANC");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!anc_llb_read_chip_ids())
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Failed to read chip IDs");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!anc_llb_set_normal_mode())
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Failed to enter normal mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!anc_llb_get_geometry())
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Failed to get geometry");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (anc_geom[0].caus_per_channel > (NUM_DIP / NUM_BUS))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "caus_per_channel out of range: %d max %ld\n", anc_geom[0].caus_per_channel, NUM_DIP / NUM_BUS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
die_per_channel = anc_geom[0].dies_per_channel;
|
||||
cau_per_die = (anc_geom[0].caus_per_channel / die_per_channel);
|
||||
dip = 0;
|
||||
die = 0;
|
||||
bus = 0;
|
||||
plane = 0;
|
||||
|
||||
// PAIRING_SCHEME_TWO_BY_TWO_PAIRING
|
||||
if (4 == cau_per_die && PPN_BLOCK_PAIRING__FOUR_PLANE == anc_geom[0].block_pairing_scheme) {
|
||||
numDip = (anc_geom[0].caus_per_channel * anc_num_channel) / 2;
|
||||
numPlane = cau_per_die / 2;
|
||||
} else { // PAIRING_SCHEME_ODD_EVEN_PAIRING, PAIRING_SCHEME_NO_PAIRING
|
||||
numDip = anc_geom[0].caus_per_channel * anc_num_channel;
|
||||
numPlane = cau_per_die;
|
||||
}
|
||||
|
||||
while (dip < numDip) {
|
||||
dip_info[dip].cau = plane + (die * cau_per_die);
|
||||
dip_info[dip].bus = bus;
|
||||
dip++;
|
||||
|
||||
plane++;
|
||||
|
||||
if (plane >= numPlane) {
|
||||
plane = 0;
|
||||
bus++;
|
||||
|
||||
if ((int) bus >= anc_num_channel) {
|
||||
bus = 0;
|
||||
die++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (4 == cau_per_die && PPN_BLOCK_PAIRING__FOUR_PLANE == anc_geom[0].block_pairing_scheme) {
|
||||
die = 0;
|
||||
bus = 0;
|
||||
plane = 2;
|
||||
numDip = anc_geom[0].caus_per_channel * anc_num_channel;
|
||||
numPlane = cau_per_die;
|
||||
|
||||
while (dip < numDip) {
|
||||
dip_info[dip].cau = plane + (die * cau_per_die);
|
||||
dip_info[dip].bus = bus;
|
||||
dip++;
|
||||
|
||||
plane++;
|
||||
|
||||
if (plane >= numPlane) {
|
||||
plane = 2;
|
||||
bus++;
|
||||
|
||||
if ((int) bus >= anc_num_channel) {
|
||||
bus = 0;
|
||||
die++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t anc_get_dip(uint32_t bus, uint32_t cau) {
|
||||
uint32_t dip;
|
||||
uint32_t num_dip;
|
||||
|
||||
num_dip = anc_geom[0].caus_per_channel * anc_num_channel;
|
||||
|
||||
for (dip = 0; dip < num_dip; dip++) {
|
||||
if (cau == dip_info[dip].cau && bus == dip_info[dip].bus) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dip;
|
||||
}
|
||||
|
||||
uint32_t anc_get_dies_per_channel() {
|
||||
return anc_geom[0].dies_per_channel;
|
||||
}
|
||||
|
||||
static bool anc_llb_set_normal_mode(void)
|
||||
{
|
||||
int channel;
|
||||
|
||||
for (channel = 0; channel < anc_num_channel; channel++)
|
||||
{
|
||||
anc_t *anc = &g_boot_anc[channel];
|
||||
uint32_t power_state = PPN_FEATURE__POWER_STATE__NORMAL_ASYNC;
|
||||
|
||||
if (!anc_llb_set_feature(anc,
|
||||
PPN_FEATURE__POWER_STATE,
|
||||
(const uint8_t *)&power_state,
|
||||
sizeof(uint32_t)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
anc_wr(anc, R_ANC_LINK_SDR_DATA_TIMING, 0x04040404);
|
||||
anc_wr(anc, R_ANC_LINK_SDR_TIMING, 0x00000F0F);
|
||||
anc_wr(anc, R_ANC_LINK_COMMAND_ADDRESS_PULSE_TIMING, 0x00000302);
|
||||
anc_wr(anc, R_ANC_LINK_READ_STATUS_CONFIG, 0x00F04040);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool anc_llb_get_geometry(void)
|
||||
{
|
||||
int channel;
|
||||
|
||||
for (channel = 0; channel < anc_num_channel; channel++)
|
||||
{
|
||||
anc_t *anc = &g_boot_anc[channel];
|
||||
|
||||
if (!anc_llb_read_device_parameters(anc, &anc_geom[channel]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool anc_llb_read_chip_ids(void)
|
||||
{
|
||||
int channel;
|
||||
|
||||
anc_num_channel=0;
|
||||
for (channel = 0; channel < ANC_BOOT_CONTROLLERS; channel++)
|
||||
{
|
||||
anc_t *anc = &g_boot_anc[channel];
|
||||
|
||||
if (!anc_llb_read_chip_id(anc, &anc->chip_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (anc->chip_id[0]=='P' && anc->chip_id[1]=='P' && anc->chip_id[2]=='N')
|
||||
{
|
||||
anc_num_channel++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool anc_llb_read_chip_id(anc_t *anc, anc_chip_id_t *chip_id)
|
||||
{
|
||||
bool ret = false;
|
||||
const uint32_t int_mask = (M_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG |
|
||||
M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT);
|
||||
uint32_t int_status;
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__READ_ID));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__ADDR1(CHIPID_ADDR));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_PIO(ANC_NAND_ID_SIZE, false, false));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__SEND_INTERRUPT(0, 0));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(0));
|
||||
|
||||
int_status = anc_boot_wait_interrupt(anc, int_mask);
|
||||
if (!int_status || (int_status & M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Timeout waiting for CHAN_INT_STATUS - 0x%08x\n", int_status);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (G_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG(int_status))
|
||||
{
|
||||
uint32_t id_word;
|
||||
uint8_t *ptr = (uint8_t *)chip_id;
|
||||
|
||||
// Chip ID is now available in Link PIO Read FIFO
|
||||
id_word = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
ptr[0] = (id_word >> 0) & 0xFF;
|
||||
ptr[1] = (id_word >> 8) & 0xFF;
|
||||
ptr[2] = (id_word >> 16) & 0xFF;
|
||||
ptr[3] = (id_word >> 24) & 0xFF;
|
||||
id_word = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
ptr[4] = (id_word >> 0) & 0xFF;
|
||||
ptr[5] = (id_word >> 8) & 0xFF;
|
||||
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool anc_llb_set_feature(anc_t *anc,
|
||||
uint16_t feature,
|
||||
const uint8_t *data,
|
||||
uint32_t len)
|
||||
{
|
||||
bool ret;
|
||||
uint32_t i;
|
||||
const uint32_t int_mask = (M_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG |
|
||||
M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE |
|
||||
M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT);
|
||||
uint32_t int_status;
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__SET_FEATURES));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__ADDR2(feature & 0xFF,
|
||||
(feature & 0xFF00) >> 8));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WRITE_PIO(len, false, false));
|
||||
for (i = 0; i < len / sizeof(uint32_t); i++)
|
||||
{
|
||||
anc_boot_put_link_command(anc, data[i]);
|
||||
}
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD3(NAND_CMD__SET_GET_FEATURES_CONFIRM,
|
||||
NAND_CMD__GET_NEXT_OPERATION_STATUS,
|
||||
NAND_CMD__OPERATION_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(32));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_STATUS(0, 0x40, 0x40));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__SEND_INTERRUPT(0, 0));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(32));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__GET_NEXT_OPERATION_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(0));
|
||||
|
||||
int_status = anc_boot_wait_interrupt(anc, int_mask);
|
||||
if (!int_status || (int_status & M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT))
|
||||
{
|
||||
panic("Timeout waiting for CHAN_INT_STATUS - 0x%08x\n", int_status);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (G_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG(int_status))
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool anc_llb_read_device_parameters(anc_t *anc,
|
||||
anc_ppn_device_params_t *params)
|
||||
{
|
||||
const uint32_t intmask = (M_ANC_CHAN_INT_STATUS_DMA_CMD_FLAG |
|
||||
M_ANC_CHAN_INT_STATUS_DMA_CMD_TIMEOUT |
|
||||
M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT |
|
||||
M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE);
|
||||
uint32_t intstatus;
|
||||
bool ret;
|
||||
uint64_t paddr = mem_static_map_physical((uintptr_t)params);
|
||||
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_CONFIG(DMA_DIRECTION_N2M, false));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__READ_DEVICE_PARAMETERS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__ADDR1(0x00));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD3(NAND_CMD__READ_DEVICE_PARAMETERS_CONFIRM,
|
||||
NAND_CMD__GET_NEXT_OPERATION_STATUS,
|
||||
NAND_CMD__OPERATION_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(32));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_STATUS(0, 0x40, 0x40));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__READ_SERIAL_OUTPUT));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(32));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_DMA(sizeof(anc_ppn_device_params_t), false, false));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__GET_NEXT_OPERATION_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(0));
|
||||
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
platform_cache_operation(CACHE_CLEAN, params, sizeof(anc_ppn_device_params_t));
|
||||
#endif
|
||||
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_BUFDESC(sizeof(anc_ppn_device_params_t),
|
||||
paddr));
|
||||
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_FLAG(0, 0));
|
||||
|
||||
intstatus = anc_boot_wait_interrupt(anc, intmask);
|
||||
if (!intstatus || (intstatus & M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT))
|
||||
{
|
||||
panic("Timeout waiting for CHAN_INT_STATUS - 0x%08x\n", intstatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intstatus & M_ANC_CHAN_INT_STATUS_DMA_CMD_TIMEOUT)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Timeout waiting for DMA to complete");
|
||||
ret = false;
|
||||
}
|
||||
else if (intstatus & M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Unexpected NAND status\n");
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
platform_cache_operation(CACHE_INVALIDATE, params, sizeof(anc_ppn_device_params_t));
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t make_physical_page(uint32_t dip, uint32_t band, uint16_t page)
|
||||
{
|
||||
const unsigned int block_bits = anc_geom[0].block_bits;
|
||||
const unsigned int page_bits = anc_geom[0].page_address_bits;
|
||||
const unsigned int cau_bits = anc_geom[0].cau_bits;
|
||||
unsigned int mode;
|
||||
|
||||
if((dip_info[dip].cau == 0) && (band == 0)) {
|
||||
mode = 0;
|
||||
} else {
|
||||
if (anc_geom[0].address_bits_bits_per_cell > 1) {
|
||||
// Device supports high-endurance SLC
|
||||
mode = 3;
|
||||
} else {
|
||||
// Device only supports regular SLC/MLC modes. Treat this high-endurance
|
||||
// work as regular SLC
|
||||
mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// LLB will always use SLC (but the PPN spec requires we not set the mode bit on CAU 0, block 0)
|
||||
return (page |
|
||||
(band << page_bits) |
|
||||
(dip_info[dip].cau << (page_bits + block_bits)) |
|
||||
(mode << (page_bits + block_bits + cau_bits)));
|
||||
}
|
||||
|
||||
|
||||
uint32_t anc_llb_read_phys_page(uint32_t band, // returns # of valid pages
|
||||
uint32_t dip,
|
||||
uint32_t page,
|
||||
uint32_t num_lbas,
|
||||
void *data,
|
||||
uint32_t *meta)
|
||||
{
|
||||
anc_t *anc = &g_boot_anc[dip_info[dip].bus];
|
||||
const uint32_t intmask = (M_ANC_CHAN_INT_STATUS_LINK_CMD_FLAG |
|
||||
M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT |
|
||||
M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE);
|
||||
uint32_t intstatus;
|
||||
unsigned int lba;
|
||||
addr_t paddr;
|
||||
uint32_t ret = num_lbas;
|
||||
uint32_t ppage = make_physical_page(dip, band, page);
|
||||
bool encrypted = false;
|
||||
uint8_t nand_status;
|
||||
|
||||
paddr = mem_static_map_physical((addr_t)data);
|
||||
if (!paddr)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "No buffer\n");
|
||||
return 0;
|
||||
}
|
||||
if (!meta)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "No meta buffer\n");
|
||||
return 0;
|
||||
}
|
||||
if (num_lbas == 0)
|
||||
{
|
||||
dprintf(DEBUG_INFO, "Invalid num_lbas %d\n", num_lbas);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((platform_get_chip_id() == 0x8960) && (platform_get_chip_revision() == 0))
|
||||
{
|
||||
// On Alcatraz A0, we encrypt everything but dip 0, block 0 (due to rdar://problem/11247422)
|
||||
if ((dip == 0) && (band == 0))
|
||||
{
|
||||
encrypted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
encrypted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encrypted = false;
|
||||
}
|
||||
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, data, num_lbas * NAND_BOOT_LOGICAL_PAGE_SIZE);
|
||||
#endif
|
||||
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_CONFIG(DMA_DIRECTION_N2M, encrypted));
|
||||
if (encrypted)
|
||||
{
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_AES_KEY_IV(DMA_COMMAND_AESKEY_256_BITS, false));
|
||||
// Key of all zeroes
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
// IV of all zeroes
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
}
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__MULTIPAGE_READ_LAST));
|
||||
|
||||
if (anc_geom[dip_info[dip].bus].bytes_per_row_address != 4)
|
||||
{
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__OPCODE(LINK_CMD_OP_ADDR3_OP) | (page & 0xFFFFFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__OPCODE(LINK_CMD_OP_ADDR4) | (ppage & 0xFFFFFF));
|
||||
anc_boot_put_link_command(anc, (ppage & 0xFF000000) >> 24);
|
||||
}
|
||||
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD3(NAND_CMD__MULTIPAGE_READ_CONFIRM,
|
||||
NAND_CMD__GET_NEXT_OPERATION_STATUS,
|
||||
NAND_CMD__OPERATION_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(32));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_STATUS(0x00,
|
||||
0x50,
|
||||
0x40));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_REGISTER(R_ANC_LINK_NAND_STATUS - A_ANC_LINK_BASE));
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__READ_SERIAL_OUTPUT));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(32));
|
||||
for (lba = 0; lba < num_lbas; lba++)
|
||||
{
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_PIO(NAND_BOOT_BYTES_PER_META, false, false));
|
||||
if (lba == (num_lbas - 1))
|
||||
{
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__SEND_INTERRUPT(0, 0));
|
||||
}
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_DMA(NAND_BOOT_LOGICAL_PAGE_SIZE, false, false));
|
||||
if (encrypted && (lba != 0))
|
||||
{
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND__OPCODE(DMA_COMMAND__OPCODE__AES_IV));
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
anc_boot_put_dma_command(anc, 0x0000000000000000ULL);
|
||||
}
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_BUFDESC(NAND_BOOT_LOGICAL_PAGE_SIZE,
|
||||
(uint64_t)paddr + lba * NAND_BOOT_LOGICAL_PAGE_SIZE));
|
||||
}
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(32));
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__GET_NEXT_OPERATION_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(0));
|
||||
|
||||
anc_boot_put_dma_command(anc, DMA_COMMAND_FLAG(0, 0));
|
||||
|
||||
intstatus = anc_boot_wait_interrupt(anc, intmask);
|
||||
if (!intstatus)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Timeout waiting for CHAN_INT_STATUS != 0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We've either timed out or gotten our status by now
|
||||
if (intstatus & M_ANC_CHAN_INT_STATUS_LINK_CMD_TIMEOUT)
|
||||
{
|
||||
// Timeout waiting for status: flush LINK CmdQ and return error
|
||||
dprintf(DEBUG_CRITICAL, "Timeout waiting for NAND status\n");
|
||||
anc_wr(anc, R_ANC_LINK_CONTROL, M_ANC_LINK_CONTROL_RESET_CMDQ);
|
||||
return 0;
|
||||
}
|
||||
else if (intstatus & M_ANC_CHAN_INT_STATUS_READ_STATUS_ERR_RESPONSE)
|
||||
{
|
||||
uint8_t status = anc_rd(anc, R_ANC_LINK_NAND_STATUS);
|
||||
// Invalid status (probably has error bit set due to a clean or uncorrectable page)
|
||||
if (BOOT_LBA_TOKEN_UNKNOWN != meta[0]) // scanning blocks - may be clean or uecc
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Invalid NAND status 0x%02X\n", status);
|
||||
}
|
||||
anc_wr(anc, R_ANC_LINK_CONTROL, M_ANC_LINK_CONTROL_START);
|
||||
ret = 0;
|
||||
meta[0] = BOOT_ERR_BLANK;
|
||||
}
|
||||
|
||||
nand_status = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
if (nand_status != 0x40)
|
||||
{
|
||||
if (BOOT_LBA_TOKEN_UNKNOWN != meta[0]) // scanning blocks - may be clean or uecc
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Invalid NAND status: 0x%02X\n", nand_status);
|
||||
}
|
||||
ret = 0;
|
||||
meta[0] = BOOT_ERR_BLANK;
|
||||
}
|
||||
|
||||
for (lba = 0; lba < num_lbas; lba++)
|
||||
{
|
||||
uint32_t meta_index;
|
||||
for (meta_index = 0; meta_index < (NAND_BOOT_BYTES_PER_META / sizeof(uint32_t)); meta_index++)
|
||||
{
|
||||
uint32_t meta_word = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
if ((meta_index == 0) && (meta_word != meta[0]))
|
||||
{
|
||||
if (BOOT_LBA_TOKEN_UNKNOWN == meta[0])
|
||||
{
|
||||
meta[0] = meta_word;
|
||||
}
|
||||
else if (BOOT_ERR_BLANK != meta[0])
|
||||
{
|
||||
if (lba==0) {
|
||||
dprintf(DEBUG_CRITICAL, "Invalid meta: expected 0x%08X got 0x%08x\n", meta[0], meta_word);
|
||||
}
|
||||
ret = lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intstatus = anc_boot_wait_interrupt(anc, M_ANC_CHAN_INT_STATUS_DMA_CMD_FLAG | M_ANC_CHAN_INT_STATUS_DMA_CMD_TIMEOUT);
|
||||
if (!intstatus || (intstatus & M_ANC_CHAN_INT_STATUS_DMA_CMD_TIMEOUT))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Timeout waiting for DMA to complete - 0x%08x\n", intstatus);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
anc_wr(anc, R_ANC_CHAN_INT_STATUS, M_ANC_CHAN_INT_STATUS_DMA_CMD_FLAG);
|
||||
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
platform_cache_operation(CACHE_INVALIDATE, data, num_lbas * NAND_BOOT_LOGICAL_PAGE_SIZE);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t failure_type;
|
||||
uint32_t start_page;
|
||||
uint8_t page_len[3];
|
||||
uint8_t checksum;
|
||||
} anc_ppn_failure_info_t;
|
||||
|
||||
|
||||
static void anc_llb_handle_geb(anc_t *anc)
|
||||
{
|
||||
uint32_t buffer[3];
|
||||
dprintf(DEBUG_CRITICAL, "General Error Dected on Bus %d, attempting to pull failure info", anc->bus_id);
|
||||
|
||||
anc_wr(anc, R_ANC_CHAN_INT_ENABLE, 0);
|
||||
anc_wr(anc, R_ANC_DMA_CONTROL, V_ANC_DMA_CONTROL_RESET(1) | V_ANC_DMA_CONTROL_START(1));
|
||||
anc_wr(anc, R_ANC_LINK_CONTROL, (V_ANC_LINK_CONTROL_RESET_CMDQ(1) |
|
||||
V_ANC_LINK_CONTROL_RESET_PIO_READ(1) |
|
||||
V_ANC_LINK_CONTROL_START(1)));
|
||||
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__GET_DEBUG_DATA));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__ADDR3(0xFF, 0xFF, 0xFF));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__SET_GET_FEATURES_CONFIRM));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(129000));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__OPERATION_STATUS));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_STATUS(0, 0x40, 0x40));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CMD1(NAND_CMD__READ_SERIAL_OUTPUT));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__WAIT_TIME(1));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__READ_PIO(10, false, false));
|
||||
anc_boot_put_link_command(anc, LINK_COMMAND__CE(0));
|
||||
|
||||
while (G_ANC_CHAN_LINK_PIO_READ_FIFO_STATUS_LEVEL(anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO_STATUS)) < 3)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
buffer[0] = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
buffer[1] = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
buffer[2] = anc_rd(anc, R_ANC_CHAN_LINK_PIO_READ_FIFO);
|
||||
|
||||
panic("GEB detected failure type 0x%04X start page 0x%08X",
|
||||
((anc_ppn_failure_info_t *)buffer)->failure_type, ((anc_ppn_failure_info_t *)buffer)->start_page);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef ANC_LLB_H
|
||||
#define ANC_LLB_H
|
||||
|
||||
typedef struct dip_info_t
|
||||
{
|
||||
uint32_t cau;
|
||||
uint32_t bus;
|
||||
} dip_info_t;
|
||||
|
||||
typedef struct _anc_ppn_device_params_t
|
||||
{
|
||||
char header[16];
|
||||
uint32_t caus_per_channel;
|
||||
uint32_t cau_bits;
|
||||
uint32_t blocks_per_cau;
|
||||
uint32_t block_bits;
|
||||
uint32_t pages_per_block;
|
||||
uint32_t pages_per_block_slc;
|
||||
uint32_t page_address_bits;
|
||||
uint32_t address_bits_bits_per_cell;
|
||||
uint32_t default_bits_per_cell;
|
||||
uint32_t page_size;
|
||||
uint32_t dies_per_channel;
|
||||
uint32_t block_pairing_scheme;
|
||||
uint32_t bytes_per_row_address;
|
||||
uint8_t reserved[92];
|
||||
uint8_t tRC;
|
||||
uint8_t tREA;
|
||||
uint8_t tREH;
|
||||
uint8_t tRHOH;
|
||||
uint8_t tRHZ;
|
||||
uint8_t tRLOH;
|
||||
uint8_t tRP;
|
||||
uint8_t reserved2;
|
||||
uint8_t tWC;
|
||||
uint8_t tWH;
|
||||
uint8_t tWP;
|
||||
uint8_t reserved3[53];
|
||||
uint32_t read_queue_size;
|
||||
uint32_t program_queue_size;
|
||||
uint32_t erase_queue_size;
|
||||
uint32_t prep_function_buffer_size;
|
||||
uint32_t tRST;
|
||||
uint32_t tPURST;
|
||||
uint32_t tSCE;
|
||||
uint32_t tCERDY;
|
||||
uint8_t reserved4[256];
|
||||
} anc_ppn_device_params_t;
|
||||
|
||||
int anc_llb_init(void);
|
||||
uint32_t anc_get_dip(uint32_t bus, uint32_t cau);
|
||||
uint32_t anc_get_dies_per_channel();
|
||||
uint32_t anc_llb_read_phys_page(uint32_t band,
|
||||
uint32_t dip,
|
||||
uint32_t page,
|
||||
uint32_t num_lbas,
|
||||
void *data,
|
||||
uint32_t *meta);
|
||||
|
||||
|
||||
#endif // ANC_LLB_H
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,46 @@
|
||||
# Copyright (C) 2011-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.
|
||||
#
|
||||
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
GLOBAL_INCLUDES += $(LOCAL_DIR)
|
||||
|
||||
ifeq ($(PRODUCT),LLB)
|
||||
OPTIONS += WITH_ANC_FIRMWARE=1
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/anc_bootrom.o \
|
||||
$(LOCAL_DIR)/anc_llb.o \
|
||||
$(LOCAL_DIR)/util_boot.o
|
||||
endif
|
||||
|
||||
ifeq ($(IBOOT_ANC_NVRAM), true)
|
||||
ifeq ($(PRODUCT),iBoot)
|
||||
|
||||
# Some targets like M7 can boot into chargetrap faster
|
||||
# by skipping ANS in iBoot and instead relying on ANC
|
||||
# for firmware and NVRAM access. These targets set
|
||||
# IBOOT_ANC_NVRAM to true and ANC support is only conditionally
|
||||
# active in iBoot.
|
||||
|
||||
OPTIONS += WITH_ANC_FIRMWARE=1
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/anc_bootrom.o \
|
||||
$(LOCAL_DIR)/anc_llb.o \
|
||||
$(LOCAL_DIR)/util_boot.o
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(APPLICATION),SecureROM)
|
||||
OPTIONS += WITH_ANC_BOOT=1
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/anc_bootrom.o \
|
||||
$(LOCAL_DIR)/util_boot.o
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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/anc_boot.h>
|
||||
#include <lib/blockdev.h>
|
||||
#include <platform/memmap.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util_boot.h"
|
||||
#include "anc_bootrom.h"
|
||||
#include "anc_llb.h"
|
||||
|
||||
|
||||
#define BOOT_NUM_ELEMENT (12)
|
||||
#define BOOT_NUM_PSLOTS (32)
|
||||
typedef struct {
|
||||
uint32_t page : 8;
|
||||
uint32_t slot : 8;
|
||||
uint32_t pslot : 8;
|
||||
uint32_t RFU : 8;
|
||||
} UtilBoot_location_t;
|
||||
|
||||
typedef struct {
|
||||
UtilBoot_location_t location[UTIL_NUM_ELEMENT];
|
||||
uint32_t prevUtilDMversion;
|
||||
uint32_t prevUtilDMslot;
|
||||
bool BCopyPresent;
|
||||
uint8_t minorVersion;
|
||||
} UtilBoot_t;
|
||||
|
||||
typedef struct {
|
||||
UtilBootDM_t s;
|
||||
uint32_t version;
|
||||
uint32_t RFU; // was used by mxcfg
|
||||
uint16_t erases[UTIL_NUM_PSLOTS];
|
||||
uint8_t clogMajor;
|
||||
uint8_t clogMinor;
|
||||
uint8_t pendDefect; // defect pending (shuffle in progress).
|
||||
uint8_t pad[4096 - sizeof(UtilBootDM_t) - 11 - UTIL_NUM_PSLOTS*2];
|
||||
}UtilDM_t;
|
||||
|
||||
extern anc_ppn_device_params_t *anc_geom;
|
||||
#define CASSERT(x, name) typedef char __ASP_CASSERT_##name[(x) ? 1 : -1]
|
||||
|
||||
CASSERT(sizeof(UtilDM_t)==4096, sizeUtilDMcorrect);
|
||||
|
||||
extern int anc_num_channel;
|
||||
|
||||
#define quantup(num, gran) (((num) + (gran) - 1) / (gran))
|
||||
#define ROUNDUPTO(num, gran) ((((num) + (gran) - 1) / (gran)) * (gran))
|
||||
|
||||
static UtilDM_t* UtilDM;
|
||||
static UtilDM_t* UtilDM_backup;
|
||||
|
||||
static UtilBoot_t Util;
|
||||
|
||||
#define META_LBA_INDEX 0
|
||||
static uint32_t meta[4];
|
||||
|
||||
// prototypes
|
||||
uint32_t Boot_Slip (uint32_t slot);
|
||||
void Boot_BandDip (uint32_t pslot, uint32_t* band, uint32_t* dip);
|
||||
static int anc_read_fw_block (struct blockdev *_dev, void *data, block_addr req_offset, uint32_t max_size);
|
||||
bool Boot_PostProcessDM(UtilDM_t *p, uint32_t slot, uint32_t page, uint32_t *meta);
|
||||
#if WITH_LLB_NVRAM
|
||||
bool Boot_Read(void *buffer, uint32_t page, uint32_t slot, uint32_t *meta);
|
||||
uint32_t Boot_Find_Fast_Scan(void *buffer, uint32_t page, uint32_t slot);
|
||||
void Boot_Find_Fast(void *buffer);
|
||||
void Boot_Find_UtilDM(void *buffer);
|
||||
static int anc_read_nvram_block (struct blockdev *_dev, void *data, block_addr req_offset, uint32_t max_size);
|
||||
#endif
|
||||
#if WITH_LLB_BLKDEV
|
||||
static int anc_read_llb_block (struct blockdev *_dev, void *data, block_addr req_offset, uint32_t max_size);
|
||||
#endif
|
||||
|
||||
// POR equivalent. Resets the Nand but does not do discovery. Zeros out the UtilDM->s.utilMajor to indicate UtilDM not loaded.
|
||||
bool anc_reset(int resetMode) {
|
||||
bool err;
|
||||
|
||||
UtilDM->s.utilMajor = 0; // indicate UtilDM not loaded.
|
||||
meta[1]=0;
|
||||
meta[2]=0;
|
||||
meta[3]=0;
|
||||
err = anc_bootrom_init(true, resetMode);
|
||||
if (err != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Entry point from LLB
|
||||
bool anc_firmware_init(void)
|
||||
{
|
||||
bool err;
|
||||
struct blockdev *bdev;
|
||||
#if WITH_LLB_NVRAM
|
||||
struct blockdev *nv_bdev;
|
||||
#endif
|
||||
#if WITH_LLB_BLKDEV
|
||||
struct blockdev *llb_bdev;
|
||||
#endif
|
||||
|
||||
|
||||
UtilDM = memalign(sizeof(UtilDM_t), CPU_CACHELINE_SIZE);
|
||||
UtilDM_backup = memalign(sizeof(UtilDM_t), CPU_CACHELINE_SIZE);
|
||||
|
||||
if (!UtilDM) {
|
||||
dprintf(DEBUG_CRITICAL, "Failed to malloc UtilDM\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!UtilDM_backup) {
|
||||
dprintf(DEBUG_CRITICAL, "Failed to malloc UtilDM_backup\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bzero(UtilDM, sizeof(UtilDM_t));
|
||||
bzero(UtilDM_backup, sizeof(UtilDM_t));
|
||||
|
||||
uint32_t block_size;
|
||||
uint32_t size;
|
||||
|
||||
err = anc_llb_init();
|
||||
if (err != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to reset ANC\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load UtilDM
|
||||
meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_UTILDM;
|
||||
if (anc_llb_read_phys_page(BOOT_BAND_UTILDM, BOOT_DIP_UTILDM, BOOT_PAGE_UTILDM, BOOT_SIZE_UTILDM, UtilDM_backup, &meta[0])!=BOOT_SIZE_UTILDM) {
|
||||
UtilDM->s.utilMajor = 0;
|
||||
return(false);
|
||||
}
|
||||
|
||||
Boot_PostProcessDM(UtilDM_backup,0,0,meta);
|
||||
dprintf(DEBUG_CRITICAL,"Loaded UtilDM revision = %2d.%2d\n",UtilDM->s.utilMajor, UtilDM->s.utilMinor);
|
||||
|
||||
if (UtilDM->s.eSize[BOOT_ELEMENT_FW] == 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"No firmware region programmed; not creating block device\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bdev = malloc(sizeof(struct blockdev));
|
||||
if (!bdev)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to allocate blockdev\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
block_size = BOOT_BYTES_PER_SEC * UtilDM->s.secPerPage;
|
||||
size = ROUNDUPTO(UtilDM->s.eSize[BOOT_ELEMENT_FW] * BOOT_BYTES_PER_SEC, block_size);
|
||||
|
||||
if (construct_blockdev(bdev,
|
||||
"anc_firmware",
|
||||
size,
|
||||
block_size) != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to construct block device\n");
|
||||
free(bdev);
|
||||
return false;
|
||||
}
|
||||
|
||||
bdev->read_block_hook = &anc_read_fw_block;
|
||||
if (register_blockdev(bdev) != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to register bdev\n");
|
||||
free(bdev);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ANC DMA has a minimum 16byte alignment requirement
|
||||
// But if the CPU isn't coherent with ANC, we need to increase the alignment requirement
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
blockdev_set_buffer_alignment(bdev, __max(ANC_MIN_ALIGNMENT, CPU_CACHELINE_SIZE));
|
||||
#else
|
||||
blockdev_set_buffer_alignment(bdev, ANC_MIN_ALIGNMENT);
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
uint32_t *buf;
|
||||
uint32_t i;
|
||||
buf = (uint32_t *)INSECURE_MEMORY_BASE;
|
||||
dprintf(DEBUG_CRITICAL,"Starting test at %p\n", buf);
|
||||
memset(buf, 0, 520192);
|
||||
anc_read_fw_block(NULL, buf, 0, 127);
|
||||
for (i = 0; i < 520192 / 4; i++)
|
||||
{
|
||||
if (buf[i] != i)
|
||||
{
|
||||
panic("Miscompare at 0x%08X got 0x%08X", i, buf[i]);
|
||||
}
|
||||
}
|
||||
dprintf(DEBUG_CRITICAL,"compare passed\n");
|
||||
|
||||
anc_read_fw_block(NULL, buf, 126, 1);
|
||||
i = 126 * 1024;
|
||||
uint32_t j;
|
||||
for (j = 0; j < 1024; j++, i++)
|
||||
{
|
||||
if (buf[j] != i)
|
||||
{
|
||||
panic("Miscompare expected 0x%08X got 0x%08X", i, buf[j]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_LLB_NVRAM
|
||||
// keep trying to find the latest
|
||||
Boot_Find_UtilDM(UtilDM_backup);
|
||||
Boot_Find_Fast(UtilDM_backup);
|
||||
nv_bdev = malloc(sizeof(struct blockdev));
|
||||
if (!nv_bdev)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to allocate nvram blockdev\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (construct_blockdev(nv_bdev,
|
||||
"nvram",
|
||||
8192,
|
||||
8192) != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to construct block device\n");
|
||||
free(nv_bdev);
|
||||
return false;
|
||||
}
|
||||
|
||||
nv_bdev->read_block_hook = &anc_read_nvram_block;
|
||||
if (register_blockdev(nv_bdev) != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to register bdev\n");
|
||||
free(nv_bdev);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#if WITH_LLB_BLKDEV
|
||||
llb_bdev = malloc(sizeof(struct blockdev));
|
||||
if (!llb_bdev)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to allocate LLB blockdev\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
block_size = BOOT_BYTES_PER_SEC * UtilDM->s.secPerPage;
|
||||
size = ROUNDUPTO(UtilDM->s.eSize[BOOT_ELEMENT_LLB] * BOOT_BYTES_PER_SEC, block_size);
|
||||
|
||||
if (construct_blockdev(llb_bdev,
|
||||
"anc_llb",
|
||||
size,
|
||||
block_size) != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to construct block device\n");
|
||||
free(llb_bdev);
|
||||
return false;
|
||||
}
|
||||
|
||||
llb_bdev->read_block_hook = &anc_read_llb_block;
|
||||
|
||||
// ANC DMA has a minimum 16byte alignment requirement
|
||||
// But if the CPU isn't coherent with ANC, we need to increase the alignment requirement
|
||||
#if WITH_NON_COHERENT_DMA
|
||||
blockdev_set_buffer_alignment(llb_bdev, __max(ANC_MIN_ALIGNMENT, CPU_CACHELINE_SIZE));
|
||||
#else
|
||||
blockdev_set_buffer_alignment(llb_bdev, ANC_MIN_ALIGNMENT);
|
||||
#endif
|
||||
|
||||
|
||||
if (register_blockdev(llb_bdev) != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL,"Failed to register bdev\n");
|
||||
free(llb_bdev);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// LLB loader. Will load UtilDM on first read request which will reset the UtilDM->s.utilMajor to be current.
|
||||
size_t anc_read_llb(void* data, size_t max_size) {
|
||||
uint32_t page;
|
||||
uint32_t size, thisSize;
|
||||
uint32_t secPerPage;
|
||||
bool err;
|
||||
|
||||
if(0 == UtilDM->s.utilMajor) {
|
||||
err = anc_bootrom_init(false, 0); // do discovery
|
||||
if(err) {
|
||||
return(0);
|
||||
}
|
||||
meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_UTILDM;
|
||||
if (!anc_bootrom_read_phys_page(BOOT_BAND_UTILDM, BOOT_DIP_UTILDM, BOOT_PAGE_UTILDM, BOOT_SIZE_UTILDM, UtilDM, &meta[0])) {
|
||||
UtilDM->s.utilMajor = 0;
|
||||
return(false);
|
||||
}
|
||||
dprintf(DEBUG_CRITICAL,"Loaded UtilDM revision = %2d.%2d\n",UtilDM->s.utilMajor, UtilDM->s.utilMinor);
|
||||
}
|
||||
|
||||
|
||||
meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_LLB;
|
||||
secPerPage = UtilDM->s.secPerPage;
|
||||
page = BOOT_PAGE_LLB; // LLB doesn't start at page=0
|
||||
|
||||
size = (uint32_t) max_size / BOOT_BYTES_PER_SEC;
|
||||
dprintf(DEBUG_CRITICAL,"Reading LLB for size=%d\n", size);
|
||||
if(size > UtilDM->s.eSize[BOOT_ELEMENT_LLB]) {
|
||||
size = UtilDM->s.eSize[BOOT_ELEMENT_LLB];
|
||||
dprintf(DEBUG_CRITICAL,"Trimmed size to written size of %5d\n", size);
|
||||
}
|
||||
|
||||
max_size = size; // record for result to caller
|
||||
|
||||
while(size) {
|
||||
if(size > secPerPage) {
|
||||
thisSize = secPerPage;
|
||||
} else {
|
||||
thisSize = size;
|
||||
}
|
||||
|
||||
if(!anc_bootrom_read_phys_page(BOOT_BAND_LLB, BOOT_DIP_LLB, page, thisSize, data, &meta[0])) {
|
||||
break;
|
||||
}
|
||||
size -= thisSize;
|
||||
page++;
|
||||
data += thisSize * BOOT_BYTES_PER_SEC;
|
||||
}
|
||||
|
||||
return( (max_size - size) * BOOT_BYTES_PER_SEC );
|
||||
}
|
||||
|
||||
|
||||
// the code below this comment is required for loading the FW element.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// clone of UtilDM_Slip from product code
|
||||
uint32_t Boot_Slip(uint32_t pslot) {
|
||||
uint32_t i;
|
||||
|
||||
i = 0;
|
||||
while(i < UtilDM->s.numDefects && (pslot >= UtilDM->s.defects[i]) ) {
|
||||
pslot++;
|
||||
i++;
|
||||
}
|
||||
return(pslot);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// clone of UtilDM_BandDip
|
||||
// Converts the physical slot to a band,dip that is consistent with Nand engine's usage. returns dip and writes band to bandPtr
|
||||
void Boot_BandDip(uint32_t pslot, uint32_t* bandPtr, uint32_t* dipPtr) {
|
||||
uint32_t bus;
|
||||
uint32_t die;
|
||||
uint32_t plane;
|
||||
uint32_t cau;
|
||||
|
||||
uint32_t slot_itr;
|
||||
uint32_t band;
|
||||
uint32_t num_bus;
|
||||
uint32_t die_per_bus;
|
||||
uint32_t cau_per_die;
|
||||
|
||||
if (anc_get_dies_per_channel() * anc_num_channel == UtilDM->s.numDie) {
|
||||
num_bus = anc_num_channel;
|
||||
} else {
|
||||
// geom_num_bus is incorrect because a bus didn't come up.
|
||||
num_bus = UtilDM->s.numDie / anc_get_dies_per_channel();
|
||||
}
|
||||
die_per_bus = UtilDM->s.numDie / anc_num_channel;
|
||||
cau_per_die = UtilDM->s.numPlanes;
|
||||
|
||||
bus = 0;
|
||||
die = 0;
|
||||
plane = 0;
|
||||
band = 0;
|
||||
for (slot_itr = 0; slot_itr < pslot; slot_itr++) {
|
||||
bus++;
|
||||
|
||||
if(bus >= num_bus) {
|
||||
bus = 0;
|
||||
die++;
|
||||
|
||||
if (die >= die_per_bus){
|
||||
die = 0;
|
||||
plane++;
|
||||
|
||||
if (plane >= cau_per_die) {
|
||||
plane=0;
|
||||
band++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cau = (die * cau_per_die) + plane;
|
||||
|
||||
*bandPtr = band;
|
||||
*dipPtr = anc_get_dip(bus, cau);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// leveraged core UtilDM_PostProcess
|
||||
bool Boot_PostProcessDM(UtilDM_t *p, uint32_t page, uint32_t slot, uint32_t *meta)
|
||||
{
|
||||
uint32_t wasGrownDef;
|
||||
uint32_t newV;
|
||||
uint32_t currV;
|
||||
bool result = false;
|
||||
|
||||
if (meta[0] == BOOT_ERR_BLANK) {
|
||||
dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] BLANK! \n", slot, page);
|
||||
}
|
||||
else if (p->s.utilMajor != BOOT_UTIL_MAJOR) {
|
||||
dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] !!!!! Found UtilDM with different major version =0x%08x ", slot, page,
|
||||
p->s.utilMajor);
|
||||
return false;
|
||||
} else if (p->s.utilMinor < Util.minorVersion) {
|
||||
dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] !!!!! Found UtilDM with major version 0x%08x but minor version 0x%08x (less than minimum 0x%08x)",
|
||||
slot, page, p->s.utilMajor, p->s.utilMinor, Util.minorVersion);
|
||||
return false;
|
||||
} else {
|
||||
newV = p->version;
|
||||
currV = UtilDM->version;
|
||||
|
||||
if (newV >= currV) {
|
||||
Util.prevUtilDMversion = currV;
|
||||
Util.prevUtilDMslot = Util.location[BOOT_ELEMENT_UTILDM].slot;
|
||||
Util.location[BOOT_ELEMENT_UTILDM].slot = slot;
|
||||
Util.location[BOOT_ELEMENT_UTILDM].page = page;
|
||||
|
||||
dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] Adopting version=0x%08x numDefects=%2d numSlots=%2d\n", slot,
|
||||
page, newV, p->s.numDefects,
|
||||
p->s.numSlots);
|
||||
wasGrownDef = UtilDM->s.numDefects;
|
||||
memcpy(UtilDM, p, sizeof(UtilDM_t));
|
||||
|
||||
if (wasGrownDef != UtilDM->s.numDefects) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (slot == BOOT_SLOT_FAST_B) {
|
||||
Util.BCopyPresent = true;
|
||||
} else {
|
||||
Util.BCopyPresent = false; // Always expect a B copy on the right of A
|
||||
}
|
||||
} else if (!Util.BCopyPresent && (slot == BOOT_SLOT_FAST_B) && ((currV == (newV + 1)))) {
|
||||
|
||||
// This is the case where we have a newer copy on the left of the older copy <rdar://problem/15261567>
|
||||
// accept B copy if it's version is 1 less than A copy, consider B slot, the previous slot
|
||||
Util.prevUtilDMversion = newV;
|
||||
Util.prevUtilDMslot = slot;
|
||||
|
||||
dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] Adopting B copy version=0x%08x numDefects=%2d numSlots=%2d", slot,
|
||||
page, newV, p->s.numDefects,
|
||||
p->s.numSlots);
|
||||
Util.BCopyPresent = true;
|
||||
|
||||
} else {
|
||||
dprintf(DEBUG_INFO,"UTIL - [%2d,%2d] Ignoring version=0x%08x numDefects=%2d numSlots=%2d", slot,
|
||||
page, newV, p->s.numDefects,
|
||||
p->s.numSlots);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int anc_read_fw_block (struct blockdev *_dev, void *data, block_addr offset, uint32_t sectors) {
|
||||
|
||||
uint32_t slot;
|
||||
uint32_t slotB; // offset for the B copy of FW. 0 indicates not doing retry
|
||||
uint32_t pslot;
|
||||
uint32_t page;
|
||||
uint32_t band;
|
||||
uint32_t dip;
|
||||
uint32_t thisSize;
|
||||
uint32_t secPerPage;
|
||||
uint32_t pagePerSlot;
|
||||
uint32_t err;
|
||||
uint32_t max_size;
|
||||
|
||||
// Incoming sectors are in terms of page size (to prevent the client from
|
||||
// attempting a sub-page read).
|
||||
sectors *= UtilDM->s.secPerPage;
|
||||
offset *= UtilDM->s.secPerPage;
|
||||
|
||||
dprintf(DEBUG_INFO,"Reading sectors from FW element from offset=%4d for a size=%4d\n", offset, sectors);;
|
||||
|
||||
if(BOOT_UTIL_MAJOR != UtilDM->s.utilMajor) {
|
||||
dprintf(DEBUG_CRITICAL,"Exiting anc_read_fw because UtilDM->s.utilMajor is incorrect\n");
|
||||
return(0);
|
||||
}
|
||||
if(offset > UtilDM->s.eSize[BOOT_ELEMENT_FW]) {
|
||||
dprintf(DEBUG_CRITICAL,"Requested offset exceeds size of firmware\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(sectors + offset > UtilDM->s.eSize[BOOT_ELEMENT_FW]) {
|
||||
dprintf(DEBUG_CRITICAL,"Attempt to read past end of firmware\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_FW;
|
||||
secPerPage = UtilDM->s.secPerPage;
|
||||
pagePerSlot = UtilDM->s.numPages;
|
||||
|
||||
page = BOOT_PAGE_FW; // starting location for FW in [slot,page]
|
||||
slot = BOOT_SLOT_FW;
|
||||
|
||||
while(offset >= secPerPage) {
|
||||
offset -= secPerPage;
|
||||
page++;
|
||||
if(page >= pagePerSlot) {
|
||||
page = 0;
|
||||
slot++;
|
||||
}
|
||||
}
|
||||
// lba now converted to page/slot
|
||||
|
||||
err = 0;
|
||||
slotB = 0;
|
||||
|
||||
max_size = sectors; // save for result
|
||||
while(sectors) {
|
||||
pslot = Boot_Slip(slot+slotB);
|
||||
Boot_BandDip(pslot, &band, &dip);
|
||||
|
||||
thisSize = sectors;
|
||||
if(thisSize > secPerPage) {
|
||||
thisSize = secPerPage;
|
||||
}
|
||||
|
||||
if (anc_llb_read_phys_page(band, dip, page, thisSize, data, &meta[0])!=secPerPage) {
|
||||
dprintf(DEBUG_CRITICAL,"Failed to read page\n");
|
||||
if(!slotB) {
|
||||
slotB = UtilDM->s.sizeFWslots;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
slotB = 0;
|
||||
sectors -= thisSize;
|
||||
data += thisSize * BOOT_BYTES_PER_SEC;
|
||||
page++;
|
||||
if(page >= pagePerSlot) {
|
||||
page = 0;
|
||||
slot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(err) {
|
||||
dprintf(DEBUG_CRITICAL,"Encountered error = %d\n", err);
|
||||
}
|
||||
|
||||
return (max_size - sectors) / secPerPage;
|
||||
}
|
||||
|
||||
#if WITH_LLB_BLKDEV
|
||||
// LLB loader. Will load UtilDM on first read request which will reset the UtilDM->s.utilMajor to be current.
|
||||
static int anc_read_llb_block (struct blockdev *_dev, void *data, block_addr offset, uint32_t sectors) {
|
||||
uint32_t page;
|
||||
uint32_t size, thisSize, max_size, secRead;
|
||||
uint32_t secPerPage;
|
||||
bool err;
|
||||
|
||||
if(0 == UtilDM->s.utilMajor) {
|
||||
err = anc_bootrom_init(false, 0); // do discovery
|
||||
if(err) {
|
||||
return(0);
|
||||
}
|
||||
meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_UTILDM;
|
||||
if (anc_llb_read_phys_page(BOOT_BAND_UTILDM, BOOT_DIP_UTILDM, BOOT_PAGE_UTILDM, BOOT_SIZE_UTILDM, UtilDM, &meta[0])!=BOOT_SIZE_UTILDM) {
|
||||
UtilDM->s.utilMajor = 0;
|
||||
return(false);
|
||||
}
|
||||
dprintf(DEBUG_CRITICAL,"Loaded UtilDM revision = %2d.%2d\n",UtilDM->s.utilMajor, UtilDM->s.utilMinor);
|
||||
}
|
||||
|
||||
|
||||
meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_LLB;
|
||||
secPerPage = UtilDM->s.secPerPage;
|
||||
page = BOOT_PAGE_LLB + offset;
|
||||
|
||||
size = sectors * secPerPage;
|
||||
dprintf(DEBUG_SPEW,"Reading LLB for size=%d, page=%u\n", sectors, (unsigned int)page);
|
||||
if(size > UtilDM->s.eSize[BOOT_ELEMENT_LLB]) {
|
||||
size = UtilDM->s.eSize[BOOT_ELEMENT_LLB];
|
||||
dprintf(DEBUG_CRITICAL,"Trimmed size to written size of %5d\n", size);
|
||||
}
|
||||
|
||||
max_size = size; // record for result to caller
|
||||
|
||||
while(size) {
|
||||
if(size > secPerPage) {
|
||||
thisSize = secPerPage;
|
||||
} else {
|
||||
thisSize = size;
|
||||
}
|
||||
|
||||
secRead = anc_llb_read_phys_page(BOOT_BAND_LLB, BOOT_DIP_LLB, page, thisSize, data, &meta[0]);
|
||||
if ((secRead == 0) || (secRead<thisSize && size>secPerPage)) { // only allow partial NAND page at the end of read
|
||||
break;
|
||||
}
|
||||
size -= thisSize;
|
||||
page++;
|
||||
data += thisSize * BOOT_BYTES_PER_SEC;
|
||||
}
|
||||
|
||||
return( (max_size - size) / secPerPage );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_LLB_NVRAM
|
||||
static int anc_read_nvram_block (struct blockdev *_dev, void *data, block_addr offset, uint32_t sectors) {
|
||||
|
||||
uint32_t slot;
|
||||
uint32_t slotB; // offset for the B copy of FW. 0 indicates not doing retry
|
||||
uint32_t pslot;
|
||||
uint32_t page;
|
||||
uint32_t band;
|
||||
uint32_t dip;
|
||||
uint32_t thisSize;
|
||||
uint32_t secPerPage;
|
||||
uint32_t pagePerSlot;
|
||||
uint32_t err;
|
||||
uint32_t max_size;
|
||||
|
||||
// Incoming sectors are in terms of page size (to prevent the client from
|
||||
// attempting a sub-page read).
|
||||
sectors *= 2; // blocksize is 8k not 4k
|
||||
|
||||
dprintf(DEBUG_INFO,"Reading sectors from NVRAM element from offset=%4d for a size=%4d\n", offset, sectors);
|
||||
|
||||
if(BOOT_UTIL_MAJOR != UtilDM->s.utilMajor) {
|
||||
dprintf(DEBUG_CRITICAL,"Exiting anc_read_fw because UtilDM->s.utilMajor is incorrect\n");
|
||||
return(0);
|
||||
}
|
||||
if(offset > 0) {
|
||||
dprintf(DEBUG_CRITICAL,"Requested offset exceeds size of nvram\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
if(sectors + offset > UtilDM->s.eSize[BOOT_ELEMENT_NVRAM]) {
|
||||
dprintf(DEBUG_CRITICAL,"Attempt to read past end of nvram\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
meta[META_LBA_INDEX] = BOOT_LBA_TOKEN_NVRAM;
|
||||
secPerPage = UtilDM->s.secPerPage;
|
||||
pagePerSlot = UtilDM->s.numPages;
|
||||
|
||||
page = Util.location[BOOT_ELEMENT_NVRAM].page; // starting location for NVRAM in [slot,page]
|
||||
slot = Util.location[BOOT_ELEMENT_NVRAM].slot;
|
||||
|
||||
err = 0;
|
||||
slotB = 0;
|
||||
|
||||
max_size = sectors; // save for result
|
||||
if (page==0 && slot==0) {// NVRAM not populated
|
||||
sectors=0;
|
||||
}
|
||||
while(sectors) {
|
||||
pslot = Boot_Slip(slot+slotB);
|
||||
Boot_BandDip(pslot, &band, &dip);
|
||||
|
||||
thisSize = sectors;
|
||||
if(thisSize > secPerPage) {
|
||||
thisSize = secPerPage;
|
||||
}
|
||||
|
||||
if(!anc_llb_read_phys_page(band, dip, page, thisSize, data, &meta[0])) {
|
||||
dprintf(DEBUG_CRITICAL,"Failed to read page\n");
|
||||
if(!slotB) {
|
||||
slotB = 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
slotB = 0;
|
||||
sectors -= thisSize;
|
||||
|
||||
data += thisSize * BOOT_BYTES_PER_SEC;
|
||||
page++;
|
||||
if(page >= pagePerSlot) {
|
||||
page=0;
|
||||
slot++;
|
||||
if (sectors) { // still more to read?
|
||||
err=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(err) {
|
||||
dprintf(DEBUG_CRITICAL,"Encountered error = %d\n", err);
|
||||
}
|
||||
|
||||
return (max_size - sectors) / 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uint32_t Boot_Find_Fast_Scan(void *buffer, uint32_t page, uint32_t slot) {
|
||||
uint32_t element;
|
||||
uint32_t ElementSizePages;
|
||||
|
||||
if (0 == page) {
|
||||
UtilDM->version = 1;
|
||||
}
|
||||
|
||||
for (; page < UtilDM->s.numPages;) {
|
||||
meta[0] = BOOT_LBA_TOKEN_UNKNOWN;
|
||||
if (Boot_Read(buffer,page,slot,meta)) {
|
||||
if ((meta[0] >= BOOT_LBA_TOKEN_FAST_FIRST) && (meta[0] <= BOOT_LBA_TOKEN_FAST_LAST)) {
|
||||
|
||||
element = meta[0] - BOOT_LBA_TOKEN_ELEMENTS;
|
||||
dprintf(DEBUG_INFO,"UTIL_MINOR - [%2d,%2d] Found %d\n", slot, page, element);
|
||||
|
||||
if (0 == UtilDM->s.eSize[element]) {
|
||||
dprintf(DEBUG_CRITICAL,"UTIL - Element of unknown size!!! \n");
|
||||
page++;
|
||||
} else {
|
||||
if (element == BOOT_ELEMENT_UTILDM) {
|
||||
Boot_PostProcessDM(buffer,page,slot,meta);
|
||||
} else {
|
||||
Util.location[element].slot = slot;
|
||||
Util.location[element].page = page;
|
||||
dprintf(DEBUG_INFO,"UTIL_MINOR - Found location [%2d,%2d] for element %d\n", Util.location[element].slot,
|
||||
Util.location[element].page,element);
|
||||
}
|
||||
|
||||
page += quantup(UtilDM->s.eSize[element], UtilDM->s.secPerPage);
|
||||
}
|
||||
} else if (!((meta[0] >= BOOT_LBA_TOKEN_FAST_FIRST) && (meta[0] <= BOOT_LBA_TOKEN_FAST_LAST)) && (meta[0] < BOOT_LBA_TOKEN_UNKNOWN)) {
|
||||
element = meta[0] - BOOT_LBA_TOKEN_ELEMENTS;
|
||||
ElementSizePages = 0;
|
||||
|
||||
if (element < UTIL_NUM_ELEMENT) {
|
||||
ElementSizePages = quantup(UtilDM->s.eSize[element], UtilDM->s.secPerPage);
|
||||
}
|
||||
|
||||
if ((ElementSizePages == 0) || ((page + ElementSizePages) > UtilDM->s.numPages)) {
|
||||
dprintf(DEBUG_CRITICAL,"UTIL - [%2d,%2d] Something Broken, UtilDM->s.eSize[%d]=%d!!\n", slot, page, element,
|
||||
ElementSizePages);
|
||||
page = 0;
|
||||
break;
|
||||
|
||||
} else {
|
||||
dprintf(DEBUG_CRITICAL,"Skipping unknown element %d\n", element);
|
||||
}
|
||||
|
||||
page += ElementSizePages;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( BOOT_ERR_BLANK != meta[0]) { // something ugly ?, either unknown LBA value or unc
|
||||
dprintf(DEBUG_CRITICAL,"UTIL - [%2d,%2d] Something Broken !! meta=%x\n", slot, page, meta[0]);
|
||||
page = 0;
|
||||
} else {
|
||||
dprintf(DEBUG_INFO,"UTIL_MINOR - [%2d,%2d] Blank !!\n", slot, page);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
|
||||
// passed in a single sector seg with buffer allocated
|
||||
void Boot_Find_Fast(void *buffer) {
|
||||
uint32_t page;
|
||||
uint32_t slot, tmpslot;
|
||||
uint32_t element;
|
||||
|
||||
tmpslot = slot = Util.location[BOOT_ELEMENT_UTILDM].slot;// slot with the highest version UtilDM
|
||||
if ((BOOT_SLOT_FAST_B == slot) && (BOOT_SLOT_FAST_A == Util.prevUtilDMslot) && (Util.prevUtilDMversion == UtilDM->version)) { // NORMAL state
|
||||
slot = BOOT_SLOT_FAST_A;
|
||||
page = Boot_Find_Fast_Scan(buffer, 1, slot);
|
||||
|
||||
if (page) {
|
||||
slot = BOOT_SLOT_FAST_B; // read copy B
|
||||
meta[0] = BOOT_LBA_TOKEN_UNKNOWN;
|
||||
|
||||
if (!Boot_Read(buffer,page-1,slot,meta)) {
|
||||
dprintf(DEBUG_INFO,"UTIL - Fast Copy B last page broken!\n");
|
||||
page = 0;
|
||||
} else if (page < UtilDM->s.numPages) { // last written page of B is ok, check next page is blank
|
||||
slot = BOOT_SLOT_FAST_B;
|
||||
meta[0] = BOOT_LBA_TOKEN_UNKNOWN;
|
||||
if (!Boot_Read(buffer,page,slot,meta) && meta[0]!=BOOT_ERR_BLANK) {
|
||||
dprintf(DEBUG_CRITICAL,"UTIL - Fast Copy B next location not Blank!!\n");
|
||||
page = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// spew enough data to know why we failed the IF term.
|
||||
dprintf(DEBUG_CRITICAL,"UTIL - FastA:%2d slot:%2d prevSlot:%2d prevV:%08x currV:%08x\n",
|
||||
BOOT_SLOT_FAST_A, slot, Util.prevUtilDMslot,
|
||||
Util.prevUtilDMversion, UtilDM->version);
|
||||
|
||||
|
||||
if ((BOOT_SLOT_LLB != Util.prevUtilDMslot) && !(!Util.BCopyPresent && (BOOT_SLOT_FAST_B == Util.prevUtilDMslot))) {
|
||||
/*Scan the older copy first*/
|
||||
slot = Util.prevUtilDMslot;
|
||||
Boot_Find_Fast_Scan(buffer, 0, slot);
|
||||
}
|
||||
|
||||
slot = tmpslot;
|
||||
Boot_Find_Fast_Scan(buffer, 0, slot);
|
||||
page = 0;
|
||||
}
|
||||
|
||||
for (element = BOOT_ELEMENT_FAST_FIRST; element <= BOOT_ELEMENT_FAST_LAST; element++) {
|
||||
dprintf(DEBUG_INFO,"UTIL - Location [%2d,%2d] for element %d\n", Util.location[element].slot, Util.location[element].page,
|
||||
element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Boot_Read(void *buffer, uint32_t page, uint32_t slot, uint32_t *meta)
|
||||
{
|
||||
uint32_t band, dip;
|
||||
uint32_t pslot = Boot_Slip(slot);//+slotB);
|
||||
Boot_BandDip(pslot, &band, &dip);
|
||||
|
||||
return (anc_llb_read_phys_page(band, dip, page, 1, buffer, &meta[0]));
|
||||
}
|
||||
|
||||
void Boot_Find_UtilDM(void *buffer)
|
||||
{
|
||||
|
||||
uint32_t firstSlot = Util.location[BOOT_ELEMENT_UTILDM].slot;
|
||||
uint32_t slot, page;
|
||||
|
||||
UtilDM->s.numSlots = 32; //UTIL_BLIND_SEARCH;
|
||||
page=0;
|
||||
|
||||
for (slot = BOOT_SLOT_FAST_A; slot < UtilDM->s.numSlots;) {
|
||||
|
||||
if (slot == UtilDM->pendDefect) {
|
||||
slot++;
|
||||
continue;
|
||||
}
|
||||
meta[0]=BOOT_LBA_TOKEN_UNKNOWN;
|
||||
Boot_Read(buffer,page,slot,meta);
|
||||
|
||||
if (Boot_PostProcessDM(buffer,page,slot,meta)) {
|
||||
dprintf(DEBUG_INFO,"UTIL - defect growth\n"); // don't assume that we're aligned.
|
||||
slot = BOOT_SLOT_FAST_A; // start over
|
||||
Util.location[BOOT_ELEMENT_UTILDM].slot = firstSlot; // and assimlate again.
|
||||
} else {
|
||||
slot++;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == UtilDM->version) { // found nothing?
|
||||
dprintf(DEBUG_CRITICAL,"UTIL - Found no UtilDM!!! Nand should be blank\n");
|
||||
UtilDM->s.numSlots = 0; // then reset numSlots
|
||||
UtilDM->s.numDefects = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#ifndef ASPsim_utilBoot_h
|
||||
#define ASPsim_utilBoot_h
|
||||
|
||||
|
||||
|
||||
#define UTIL_NUM_ELEMENT (12)
|
||||
#define UTIL_NUM_PSLOTS (128)
|
||||
#define UTIL_NO_DEFECT (0xff)
|
||||
typedef struct {
|
||||
uint8_t utilMajor;
|
||||
uint8_t utilMinor;
|
||||
uint16_t eSize[UTIL_NUM_ELEMENT]; // element size in sectors, 0 if never written.
|
||||
uint8_t defects[UTIL_NUM_PSLOTS];
|
||||
uint16_t numDefects;
|
||||
uint16_t numPages;
|
||||
uint8_t secPerPage;
|
||||
uint8_t numPlanes;
|
||||
uint8_t numDie;
|
||||
uint8_t numSlots;
|
||||
uint8_t sizeFWslots; // size of the firmware element in slot granularity
|
||||
uint8_t RFU[8]; // reserved for future use
|
||||
}UtilBootDM_t;
|
||||
|
||||
#define BOOT_NO_DEFECT (0xff)
|
||||
|
||||
#define BOOT_LBA_TOKEN_BASE 0xFF00000
|
||||
#define BOOT_LBA_TOKEN_UTILNOP (BOOT_LBA_TOKEN_BASE + 1)
|
||||
#define BOOT_LBA_TOKEN_ELEMENTS (BOOT_LBA_TOKEN_BASE + 2)
|
||||
#define BOOT_LBA_TOKEN_LLB (BOOT_LBA_TOKEN_BASE + 2)
|
||||
#define BOOT_LBA_TOKEN_FW (BOOT_LBA_TOKEN_BASE + 3)
|
||||
#define BOOT_LBA_TOKEN_UTILDM (BOOT_LBA_TOKEN_BASE + 4)
|
||||
#define BOOT_LBA_TOKEN_DM (BOOT_LBA_TOKEN_BASE + 0x05)
|
||||
#define BOOT_LBA_TOKEN_CTRLBITS (BOOT_LBA_TOKEN_BASE + 0x06)
|
||||
#define BOOT_LBA_TOKEN_EFFACEABLE (BOOT_LBA_TOKEN_BASE + 0x07)
|
||||
#define BOOT_LBA_TOKEN_NVRAM (BOOT_LBA_TOKEN_BASE + 0x08)
|
||||
#define BOOT_LBA_TOKEN_SYSCFG (BOOT_LBA_TOKEN_BASE + 0x09)
|
||||
#define BOOT_LBA_TOKEN_PANICLOG (BOOT_LBA_TOKEN_BASE + 0x0A)
|
||||
#define BOOT_LBA_TOKEN_UNKNOWN (BOOT_LBA_TOKEN_BASE + 0x10)
|
||||
|
||||
#define BOOT_LBA_TOKEN_FAST_FIRST BOOT_LBA_TOKEN_UTILDM
|
||||
#define BOOT_LBA_TOKEN_FAST_LAST BOOT_LBA_TOKEN_PANICLOG
|
||||
|
||||
|
||||
#define BOOT_ELEMENT_UTILDM (2)
|
||||
#define BOOT_BAND_UTILDM (0)
|
||||
#define BOOT_DIP_UTILDM (0)
|
||||
#define BOOT_PAGE_UTILDM (0)
|
||||
#define BOOT_SIZE_UTILDM (1)
|
||||
|
||||
#define BOOT_ELEMENT_LLB (0)
|
||||
#define BOOT_BAND_LLB (0)
|
||||
#define BOOT_DIP_LLB (0)
|
||||
#define BOOT_PAGE_LLB (1)
|
||||
#define BOOT_SIZE_LLB (UtilDM->s.eSize[BOOT_ELEMENT_LLB])
|
||||
|
||||
#define BOOT_ELEMENT_FW (1)
|
||||
#define BOOT_SLOT_FW (1)
|
||||
#define BOOT_PAGE_FW (0)
|
||||
#define BOOT_SIZE_FW (UtilDM->s.eSize[BOOT_ELEMENT_FW])
|
||||
|
||||
#define BOOT_ELEMENT_NVRAM (6)
|
||||
#define BOOT_BYTES_PER_SEC (4096)
|
||||
|
||||
#define BOOT_NO_ERROR (0)
|
||||
#define BOOT_ERR_ABORT (10)
|
||||
#define BOOT_UTIL_MAJOR (8) // MUST match AppleStorageProcessor/src/aspcore/core/format.h
|
||||
|
||||
#define BOOT_ELEMENT_FAST_FIRST BOOT_ELEMENT_UTILDM
|
||||
#define BOOT_ELEMENT_FAST_LAST BOOT_ELEMENT_NVRAM
|
||||
|
||||
#define BOOT_SLOT_LLB 0
|
||||
|
||||
#define BOOT_SLOT_FW_A_FIRST 1
|
||||
#define BOOT_SLOT_FW_A_LAST (BOOT_SLOT_FW_A_FIRST + (1 * UtilDM->s.sizeFWslots) - 1)
|
||||
#define BOOT_SLOT_FW_B_LAST (BOOT_SLOT_FW_A_FIRST + (2 * UtilDM->s.sizeFWslots) - 1)
|
||||
|
||||
|
||||
#define BOOT_SLOT_SYSCFG_A (BOOT_SLOT_FW_B_LAST + 1)
|
||||
#define BOOT_SLOT_SYSCFG_B (BOOT_SLOT_SYSCFG_A + 1)
|
||||
|
||||
#define BOOT_SLOT_FAST_A (BOOT_SLOT_SYSCFG_B + 1)
|
||||
#define BOOT_SLOT_FAST_B (BOOT_SLOT_FAST_A + 1)
|
||||
|
||||
#define BOOT_SLOT_PANICLOG (BOOT_SLOT_FAST_B + 1)
|
||||
|
||||
#define BOOT_ERR_BLANK 0xffffffff
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user