iBoot/drivers/apple/anc/anc_bootrom.c

529 lines
19 KiB
C

/*
* 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]);
}
}