first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+246
View File
@@ -0,0 +1,246 @@
/*
* Copyright (C) 2009-2010 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 <arch.h>
#include <arch/arm/arm.h>
#include <debug.h>
#include <drivers/a5iop/a5iop.h>
#include <platform.h>
#include <platform/int.h>
#include <platform/timer.h>
#include <sys/callout.h>
#include <sys/task.h>
/*
* Cache control
*/
void
a5iop_cache_operation(int operation, void *address, u_int32_t length)
{
uint32_t actual_base, lines, extra;
if (unlikely(length == 0)) {
enter_critical_section();
if (operation & CACHE_CLEAN)
arm_clean_dcache();
if (operation & CACHE_INVALIDATE)
arm_invalidate_dcache();
exit_critical_section();
/* on the panic path, disable the cache? XXX */
if (operation & CACHE_PANIC) { }
} else {
actual_base = (uint32_t)address;
ASSERT((actual_base & ~(CPU_CACHELINE_SIZE-1)) == actual_base);
ASSERT((length % CPU_CACHELINE_SIZE) == 0);
lines = length >> CPU_CACHELINE_SHIFT;
ASSERT(lines > 0);
extra = lines & 7;
lines -= extra;
/* perform loop unrolling to optimize multi-line operations rdar://problem/6722268 */
if (operation & (CACHE_CLEAN | CACHE_INVALIDATE)) {
switch (extra) {
case 0:
break;
case 1:
arm_clean_invalidate_dcache_line(actual_base);
break;
case 2:
arm_clean_invalidate_dcache_line_2(actual_base);
break;
case 3:
arm_clean_invalidate_dcache_line_3(actual_base);
break;
case 4:
arm_clean_invalidate_dcache_line_4(actual_base);
break;
case 5:
arm_clean_invalidate_dcache_line_5(actual_base);
break;
case 6:
arm_clean_invalidate_dcache_line_6(actual_base);
break;
case 7:
arm_clean_invalidate_dcache_line_7(actual_base);
break;
}
actual_base += CPU_CACHELINE_SIZE * extra;
while (lines) {
arm_clean_invalidate_dcache_line_8(actual_base);
lines -= 8;
actual_base += CPU_CACHELINE_SIZE * 8;
}
} else if (operation & CACHE_CLEAN) {
switch (extra) {
case 0:
break;
case 1:
arm_clean_dcache_line(actual_base);
break;
case 2:
arm_clean_dcache_line_2(actual_base);
break;
case 3:
arm_clean_dcache_line_3(actual_base);
break;
case 4:
arm_clean_dcache_line_4(actual_base);
break;
case 5:
arm_clean_dcache_line_5(actual_base);
break;
case 6:
arm_clean_dcache_line_6(actual_base);
break;
case 7:
arm_clean_dcache_line_7(actual_base);
break;
}
actual_base += CPU_CACHELINE_SIZE * extra;
while (lines) {
arm_clean_dcache_line_8(actual_base);
lines -= 8;
actual_base += CPU_CACHELINE_SIZE * 8;
}
} else {// operation & CACHE_INVALIDATE
switch (extra) {
case 0:
break;
case 1:
arm_invalidate_dcache_line(actual_base);
break;
case 2:
arm_invalidate_dcache_line_2(actual_base);
break;
case 3:
arm_invalidate_dcache_line_3(actual_base);
break;
case 4:
arm_invalidate_dcache_line_4(actual_base);
break;
case 5:
arm_invalidate_dcache_line_5(actual_base);
break;
case 6:
arm_invalidate_dcache_line_6(actual_base);
break;
case 7:
arm_invalidate_dcache_line_7(actual_base);
break;
}
actual_base += CPU_CACHELINE_SIZE * extra;
while (lines) {
arm_invalidate_dcache_line_8(actual_base);
lines -= 8;
actual_base += CPU_CACHELINE_SIZE * 8;
}
}
}
}
#if SUPPORT_SLEEP
static struct task *sleeping_task;
static u_int32_t idle_sleep;
static u_int32_t powergate_cnt, powerwake_cnt, powerfall_cnt;
static u_int32_t suspend_cnt, wake_cnt;
static u_int64_t sleep_stamp, wake_stamp;
extern u_int32_t arch_sleep_magic;
void
a5iop_sleep(u_int32_t going_idle)
{
idle_sleep = going_idle;
if (idle_sleep)
powergate_cnt++;
else
suspend_cnt++;
/* disable interrupts; this is matched in the wake path */
enter_critical_section();
/* we are the sleeping task */
sleeping_task = task_get_current_task();
sleep_stamp = timer_get_ticks();
/* fool the upcoming test on the sleep path */
arch_sleep_magic = SLEEP_MAGIC_NOT_ASLEEP;
/* save our current context - on wake we will return from this call */
arch_task_context_switch(&sleeping_task->arch, &sleeping_task->arch);
/* if we are on the wake path, go back */
if (SLEEP_MAGIC_WAKEY_WAKEY == arch_sleep_magic) {
RELEASE_ASSERT(powergate_cnt == powerfall_cnt + powerwake_cnt);
RELEASE_ASSERT(suspend_cnt == wake_cnt);
return;
}
/* flip the switch and wait for us to go to sleep */
arch_sleep_magic = SLEEP_MAGIC_WAKEY_WAKEY;
/* Flush and invalidate the the entire dcache
* Don't call a5iop_cache_operation directly because the
* irq_disable count won't get flushed */
arm_clean_dcache();
/* Use WFI to fully quiesce */
arch_halt();
if (idle_sleep) {
/* It's possible to fall through the WFI without
* power-gating, so carry on in that case. */
powerfall_cnt++;
exit_critical_section();
} else {
/* On the sleep/suspend path, it's not acceptible to
* return from this routine. We don't expect to fall
* through the WFI but better safe than sorry. */
while (1) arch_halt();
}
}
void
platform_wakeup(void)
{
/* Reestablish the correct CPU configuration */
arch_cpu_init(true);
wake_stamp = timer_get_ticks();
if (idle_sleep) {
/* Waking from idle power-gating; timer and interrupt
* state is intact; we just need to pop a level of IRQ
* disable and start running. */
powerwake_cnt++;
exit_critical_section();
} else {
wake_cnt++;
platform_early_init();
}
/* There should be a better abstracted way to enable NMI <rdar://problem/8269765> */
arm_enable_fiqs();
/* kick the callout system to re-evaluate deadlines */
callout_reset_deadline();
/* and switch back to the context that went to sleep */
arch_task_context_restore(&sleeping_task->arch);
panic("arch_task_context_restore didn't");
}
#endif /* SUPPORT_SLEEP */
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2010 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 __A5IOP_H
#define __A5IOP_H
#include <sys/types.h>
__BEGIN_DECLS
extern void a5iop_init(void);
extern void a5iop_cache_operation(int operation, void *address, u_int32_t length);
extern void a5iop_sleep(u_int32_t going_idle);
__END_DECLS
#endif
+14
View File
@@ -0,0 +1,14 @@
# Copyright (C) 2010 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)
ALL_OBJS += $(LOCAL_DIR)/a5iop.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+425
View File
@@ -0,0 +1,425 @@
/*
* Copyright (C) 2011-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/a7iop/a7iop.h>
#include <platform/int.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwisr.h>
#include <platform/soc/hwregbase.h>
#include <sys.h>
#include <sys/task.h>
#include <platform/timer.h>
#define low_bits(x) ((x) & 0x00000000ffffffffULL)
#define high_bits(x) (((x) & 0xffffffff00000000ULL) >> 32)
#define MAX_CLOCKS (2)
static int32_t _akf_init(const KFWRAPPER_TYPE_T kfw_type);
static void _akf_recv_mbox_nonempty_int_handler(void *arg);
static void _akf_send_mbox_empty_int_handler(void *arg);
static void _akf_set_timebase(addr_t regs_base);
// KFWrappers are indexed by types defined in enum table
static struct akf_wrapper {
uint64_t base;
uint32_t clock_idx[MAX_CLOCKS];
uint32_t inbox_int;
uint32_t outbox_int;
struct task_event recv_mbox_wait_event;
struct task_event send_mbox_wait_event;
bool set_iop_timebase;
} _akf_wrappers[] = {
#ifdef ANS_AKF_BASE_ADDR
#ifdef WITH_ANS_DLL
[KFW_ANS] = { .base = ANS_AKF_BASE_ADDR,
.clock_idx = { CLK_ANS, CLK_ANS_DLL },
.inbox_int = INT_ANS_KF_INBOX_EMPTY,
.outbox_int = INT_ANS_KF_OUTBOX_NOTEMPTY,
.set_iop_timebase = true
},
#else
[KFW_ANS] = { .base = ANS_AKF_BASE_ADDR,
.clock_idx = { CLK_ANS, UINT32_MAX },
.inbox_int = INT_ANS_KF_INBOX_EMPTY,
.outbox_int = INT_ANS_KF_OUTBOX_NOTEMPTY,
.set_iop_timebase = true
},
#endif
#else
[KFW_ANS] = { .base = UINT64_MAX,
.clock_idx = { UINT32_MAX },
.inbox_int = UINT32_MAX,
.outbox_int = UINT32_MAX,
.set_iop_timebase = false
},
#endif
#ifdef ASIO_AKF_BASE_ADDR
[KFW_SIO] = { .base = ASIO_AKF_BASE_ADDR,
.clock_idx = { CLK_SIO, CLK_SIO_P },
.inbox_int = INT_SIO_KF_INBOX_EMPTY,
.outbox_int = INT_SIO_KF_OUTBOX_NOTEMPTY,
.set_iop_timebase = false
},
#else
[KFW_SIO] = { .base = UINT64_MAX,
.clock_idx = { UINT32_MAX },
.inbox_int = UINT32_MAX,
.outbox_int = UINT32_MAX,
.set_iop_timebase = false
},
#endif
#ifdef ASEP_AKF_BASE_ADDR
[KFW_SEP] = { .base = ASEP_AKF_BASE_ADDR,
.clock_idx = { UINT32_MAX, UINT32_MAX },
.inbox_int = INT_SEP_KF_INBOX_EMPTY,
.outbox_int = INT_SEP_KF_OUTBOX_NOTEMPTY
},
#else
[KFW_SEP] = { .base = UINT64_MAX,
.clock_idx = { UINT32_MAX },
.inbox_int = UINT32_MAX,
.outbox_int = UINT32_MAX,
.set_iop_timebase = false
},
#endif
};
/*
* akf_start
*
* Initialize KFWrapper (clocks, interrupts), sets up remap window,
* Enable FIFOs, and boot KF core.
* It assumes firmware address is aligned, and memory allocated is contiguous.
*
*/
int32_t akf_start(const KFWRAPPER_TYPE_T kfw_type, const addr_t firmware_address, const uint64_t firmware_size)
{
addr_t fw_phy_addr;
addr_t akf_base;
uint32_t i;
akf_base = _akf_wrappers[kfw_type].base;
ASSERT(akf_base != 0);
// register for interrupts
install_int_handler(_akf_wrappers[kfw_type].outbox_int, _akf_recv_mbox_nonempty_int_handler, (void *)kfw_type);
install_int_handler(_akf_wrappers[kfw_type].inbox_int, _akf_send_mbox_empty_int_handler, (void *)kfw_type);
// initialize wait events
event_init(&_akf_wrappers[kfw_type].recv_mbox_wait_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
event_init(&_akf_wrappers[kfw_type].send_mbox_wait_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
// enable clock and power
for (i = 0; i < MAX_CLOCKS; i++) {
if (_akf_wrappers[kfw_type].clock_idx[i] == UINT32_MAX)
break;
clock_gate(_akf_wrappers[kfw_type].clock_idx[i], true);
}
// mask all the interrupts
rAKF_AP_MAILBOX_SET(akf_base) = AKF_MAILBOX_O_NONEMPTY_MSK | AKF_MAILBOX_O_EMPTY_MSK |
AKF_MAILBOX_I_NONEMPTY_MSK | AKF_MAILBOX_I_EMPTY_MSK;
// setup remap
rAKF_AXI_START(akf_base) = 0;
rAKF_AXI_START_EXT(akf_base) = 0;
rAKF_AXI_END(akf_base) = (uint32_t)(low_bits(firmware_size));
rAKF_AXI_END_EXT(akf_base) = (uint32_t)(high_bits(firmware_size));
fw_phy_addr = mem_static_map_physical(firmware_address);
rAKF_AXI_BASE(akf_base) = (uint32_t)(low_bits(fw_phy_addr));
rAKF_AXI_BASE_EXT(akf_base) = (uint32_t)(high_bits(fw_phy_addr));
// enable FIFOs
rAKF_AP_INBOX_CTRL(akf_base) |= AKF_AP_INBOX_CTRL_ENABLE;
rAKF_AP_OUTBOX_CTRL(akf_base) |= AKF_AP_OUTBOX_CTRL_ENABLE;
#if AKF_VERSION == 2
rAKF_KIC_MAILBOX_EXT_CLR(akf_base) = 0x1111;
#endif
// if appropriate, set IOP timebase to be close to and in sync with local timebase (from aic),
if (_akf_wrappers[kfw_type].set_iop_timebase) {
_akf_set_timebase(akf_base);
}
// set run bit
rAKF_CPU_CTRL(akf_base) = AKF_CPU_CTRL_RUN;
// let interrupt flow
unmask_int(_akf_wrappers[kfw_type].outbox_int);
unmask_int(_akf_wrappers[kfw_type].inbox_int);
return 0;
}
/*
* akf_start_sep
*
* SEP needs special handling.
* Register and enables interrupts, enable fifos
*
*/
int32_t akf_start_sep(void)
{
// register for interrupts
install_int_handler(_akf_wrappers[KFW_SEP].outbox_int, _akf_recv_mbox_nonempty_int_handler, (void *)KFW_SEP);
install_int_handler(_akf_wrappers[KFW_SEP].inbox_int, _akf_send_mbox_empty_int_handler, (void *)KFW_SEP);
// initialize wait events
event_init(&_akf_wrappers[KFW_SEP].recv_mbox_wait_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
event_init(&_akf_wrappers[KFW_SEP].send_mbox_wait_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
// mask all the interrupts
rAKF_AP_MAILBOX_SET(_akf_wrappers[KFW_SEP].base) = AKF_MAILBOX_O_NONEMPTY_MSK | AKF_MAILBOX_O_EMPTY_MSK |
AKF_MAILBOX_I_NONEMPTY_MSK | AKF_MAILBOX_I_EMPTY_MSK;
// enable FIFOs
rAKF_AP_INBOX_CTRL(_akf_wrappers[KFW_SEP].base) |= AKF_AP_INBOX_CTRL_ENABLE;
rAKF_AP_OUTBOX_CTRL(_akf_wrappers[KFW_SEP].base) |= AKF_AP_OUTBOX_CTRL_ENABLE;
// let interrupt flow
unmask_int(_akf_wrappers[KFW_SEP].outbox_int);
unmask_int(_akf_wrappers[KFW_SEP].inbox_int);
return 0;
}
/*
* akf_recv_mbox
*
* Fetch a message from outbound mailbox.
* If there are no messages in outbox, outbox-non-empty interrupt will be enabled.
* If wait_timeout is UINT32_MAX, driver will wait for ever for a message
* 0: success, -1: outbox empty, -2: timed out
*
*/
int32_t akf_recv_mbox(const KFWRAPPER_TYPE_T kfw_type, uint64_t *msg, uint32_t wait_timeout)
{
int32_t ret;
addr_t akf_base;
akf_base = _akf_wrappers[kfw_type].base;
ASSERT(akf_base != 0);
ret = 0;
enter_critical_section();
while (rAKF_AP_OUTBOX_CTRL(akf_base) & AKF_AP_OUTBOX_CTRL_EMPTY) {
if (!wait_timeout) {
ret = -1;
goto exit;
}
rAKF_AP_MAILBOX_CLR(akf_base) = AKF_MAILBOX_O_NONEMPTY_MSK;
if (wait_timeout == UINT32_MAX) {
event_wait(&_akf_wrappers[kfw_type].recv_mbox_wait_event);
}
else {
// XXX recompute wait timeout here?
if (event_wait_timeout(&_akf_wrappers[kfw_type].recv_mbox_wait_event, wait_timeout) == false) {
ret = -2;
goto exit;
}
}
}
// assert for over-flow and under-flow errors
RELEASE_ASSERT((rAKF_AP_OUTBOX_CTRL(akf_base) & (AKF_AP_OUTBOX_CTRL_UDFL | AKF_AP_OUTBOX_CTRL_OVFL)) == 0);
*msg = akf_read_ap_outbox(akf_base);
exit:
exit_critical_section();
return ret;
}
/*
* akf_send_mbox
*
* Send a message to inbound mailbox.
* If there is no space in the inbox, inbox-empty interrupt will be enabled.
* If wait_timeout is UINT32_MAX, driver will wait for ever for space in the mailbox to stuff a new message.
* 0: success, -1: inbox full, -2: timed out
*
*/
int32_t akf_send_mbox(const KFWRAPPER_TYPE_T kfw_type, const uint64_t msg, uint32_t wait_timeout)
{
int32_t ret;
addr_t akf_base;
akf_base = _akf_wrappers[kfw_type].base;
ASSERT(akf_base != 0);
ret = 0;
enter_critical_section();
while (rAKF_AP_INBOX_CTRL(akf_base) & AKF_AP_INBOX_CTRL_FULL) {
if (!wait_timeout) {
ret = -1;
goto exit;
}
rAKF_AP_MAILBOX_CLR(akf_base) = AKF_MAILBOX_I_EMPTY_MSK;
if (wait_timeout == UINT32_MAX) {
event_wait(&_akf_wrappers[kfw_type].send_mbox_wait_event);
}
else {
// XXX recompute wait timeout here?
if (event_wait_timeout(&_akf_wrappers[kfw_type].send_mbox_wait_event, wait_timeout) == false) {
ret = -2;
goto exit;
}
}
}
// assert for over-flow and under-flow errors
RELEASE_ASSERT((rAKF_AP_INBOX_CTRL(akf_base) & (AKF_AP_INBOX_CTRL_UDFL | AKF_AP_INBOX_CTRL_OVFL)) == 0);
akf_write_ap_inbox(akf_base, msg);
exit:
exit_critical_section();
return ret;
}
/*
* akf_send_nmi
*
* Sends NMI to the KF core.
* KF Timer1 is used for generating FIQ NMI. It setups up FIQ Software source.
*
*/
int32_t akf_send_nmi(const KFWRAPPER_TYPE_T kfw_type)
{
addr_t akf_base;
akf_base = _akf_wrappers[kfw_type].base;
ASSERT(akf_base != 0);
if ((rAKF_KIC_TMR_CFG1(akf_base) & AKF_KIC_TMR_CFG_NMI) == 0) {
dprintf(DEBUG_INFO, "akf_send_nmi: KIC_TMR_CFG1 not configured for NMI\n");
return -1;
}
rAKF_KIC_TMR_STATE_SET1(akf_base) = AKF_KIC_TMR_STATE_SET_SGT;
return 0;
}
/*
* akf_stop
*
* Stops the KF core, mask all FIFO interrupts
* Book-keeping related to shutdown (quiesce clocks, uninstall interrupt handler, clears remap window)
*
*/
int32_t akf_stop(const KFWRAPPER_TYPE_T kfw_type)
{
addr_t akf_base;
uint32_t i;
akf_base = _akf_wrappers[kfw_type].base;
ASSERT(akf_base != 0);
enter_critical_section();
// mask interrupts
mask_int(_akf_wrappers[kfw_type].outbox_int);
mask_int(_akf_wrappers[kfw_type].inbox_int);
// XXX clear any pending interrupts?
// disable FIFOs
rAKF_AP_INBOX_CTRL(akf_base) = (rAKF_AP_INBOX_CTRL(akf_base) & ~AKF_AP_INBOX_CTRL_ENABLE);
rAKF_AP_OUTBOX_CTRL(akf_base) = (rAKF_AP_OUTBOX_CTRL(akf_base) & ~AKF_AP_OUTBOX_CTRL_ENABLE);
// SEP: special handling, clean local states
if (kfw_type == KFW_SEP)
goto done;
// at this time, KF should be idle (not generating any transactions to fabric)
// stop KF and keep it in reset
rAKF_CPU_CTRL(akf_base) = (rAKF_CPU_CTRL(akf_base) & ~AKF_CPU_CTRL_RUN);
// clear remap registers
rAKF_AXI_START(akf_base) = 0;
rAKF_AXI_START_EXT(akf_base) = 0;
rAKF_AXI_END(akf_base) = 0;
rAKF_AXI_END_EXT(akf_base) = 0;
rAKF_AXI_BASE(akf_base) = 0;
rAKF_AXI_BASE_EXT(akf_base) = 0;
// disable clock and power, clock_gate calls takes care of both
for (i = 0; i < MAX_CLOCKS; i++) {
if (_akf_wrappers[kfw_type].clock_idx[i] == UINT32_MAX)
break;
clock_gate(_akf_wrappers[kfw_type].clock_idx[i], false);
}
done:
exit_critical_section();
return 0;
}
static void _akf_recv_mbox_nonempty_int_handler(void *arg)
{
KFWRAPPER_TYPE_T kfw_type = (KFWRAPPER_TYPE_T)arg;
RELEASE_ASSERT(kfw_type < KFW_TYPE_MAX);
ASSERT(_akf_wrappers[kfw_type].base != 0);
rAKF_AP_MAILBOX_SET(_akf_wrappers[kfw_type].base) = AKF_MAILBOX_O_NONEMPTY_MSK;
// NOTE: this akf reg access will ensure that interrupt mask operation above
// will complete before exiting interrupt handling - the read result is unimportant
(void)rAKF_AP_INBOX_CTRL(_akf_wrappers[kfw_type].base);
event_signal(&_akf_wrappers[kfw_type].recv_mbox_wait_event);
}
static void _akf_send_mbox_empty_int_handler(void *arg)
{
KFWRAPPER_TYPE_T kfw_type = (KFWRAPPER_TYPE_T)arg;
RELEASE_ASSERT(kfw_type < KFW_TYPE_MAX);
ASSERT(_akf_wrappers[kfw_type].base != 0);
rAKF_AP_MAILBOX_SET(_akf_wrappers[kfw_type].base) = AKF_MAILBOX_I_EMPTY_MSK;
// NOTE: this akf reg access will ensure that interrupt mask operation above
// will complete before exiting interrupt handling - the read result is unimportant
(void)rAKF_AP_INBOX_CTRL(_akf_wrappers[kfw_type].base);
event_signal(&_akf_wrappers[kfw_type].send_mbox_wait_event);
}
static void _akf_set_timebase(addr_t regs_base)
{
uint32_t reg_value;
uint64_t now;
reg_value = rAKF_KIC_GLB_CFG(regs_base);
enter_critical_section();
rAKF_KIC_GLB_CFG(regs_base) = (reg_value & ~AKF_KIC_GLB_CFG_TEN);
now = timer_get_ticks();
rAKF_KIC_GLB_TIME_BASE_LO(regs_base) = (uint32_t)now;
rAKF_KIC_GLB_TIME_BASE_HI(regs_base) = (uint32_t)(now>>32);
rAKF_KIC_GLB_CFG(regs_base) = (reg_value | AKF_KIC_GLB_CFG_TEN);
exit_critical_section();
}
+84
View File
@@ -0,0 +1,84 @@
/*
* 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/a7iop/a7iop.h>
#include <platform/memmap.h>
#include <sys.h>
#include <sys/menu.h>
#include <sys/task.h>
#if defined(WITH_MENU) && WITH_MENU
static int _a7iop_debug_main(int argc, struct cmd_arg *args);
static int _a7iop_debug_start_kf(KFWRAPPER_TYPE_T type);
static int _a7iop_debug_stop_kf(KFWRAPPER_TYPE_T type);
MENU_COMMAND_DEBUG(a7iop_test, _a7iop_debug_main, "Test A7IOP interface", NULL);
static int _a7iop_debug_main(int argc, struct cmd_arg *args) {
const char *s;
KFWRAPPER_TYPE_T type;
if (argc < 3) {
goto print_usage;
}
s = args[1].str;
if (strcmp(s, "ans") == 0) {
type = KFW_ANS;
}
else if (strcmp(s, "sio") == 0) {
type = KFW_SIO;
}
else if (strcmp(s, "sep") == 0) {
type = KFW_SEP;
} else {
goto print_usage;
}
s = args[2].str;
if (strcmp(s, "start") == 0) {
return _a7iop_debug_start_kf(type);
}
else if (strcmp(s, "stop") == 0) {
return _a7iop_debug_stop_kf(type);
} else {
goto print_usage;
}
print_usage:
printf("Usage: ");
printf("a7iop_test [ans/sio/sep] [start/stop]\n");
return -1;
}
static int _a7iop_debug_start_kf(KFWRAPPER_TYPE_T type)
{
addr_t fw_base;
uint32_t code[] = { 0xe3a00000, 0xe3a01001, 0xe3a02002, 0xe3a03003, 0xe3a04004, 0xe320f003 };
fw_base = (addr_t)DEFAULT_LOAD_ADDRESS;
bcopy((void *)code, (void *)fw_base, sizeof(code));
akf_start(type, fw_base, sizeof(code));
return 0;
}
static int _a7iop_debug_stop_kf(KFWRAPPER_TYPE_T type)
{
akf_stop(type);
return 0;
}
#endif // defined(WITH_MENU) && WITH_MENU
@@ -0,0 +1,196 @@
/*
* Copyright (C) 2011-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 _APPLE_A7IOP_H
#define _APPLE_A7IOP_H
#include <sys/types.h>
#include <platform/soc/hwregbase.h>
/*******************************************
* KFWrappers
*
********************************************/
typedef enum {
KFW_ANS = 0,
KFW_SIO,
KFW_SEP,
KFW_TYPE_MAX,
} KFWRAPPER_TYPE_T;
#define A7IOP_WAIT_FOREVER (UINT32_MAX)
#define A7IOP_NO_WAIT (0)
/*******************************************
* A7IOP interface
*
********************************************/
int32_t akf_start(const KFWRAPPER_TYPE_T kfw_type, const addr_t firmware_address, const uint64_t firmware_size);
int32_t akf_start_sep(void);
int32_t akf_send_mbox(const KFWRAPPER_TYPE_T kfw_type, const uint64_t msg, uint32_t wait_timeout) __attribute__((warn_unused_result));
int32_t akf_recv_mbox(const KFWRAPPER_TYPE_T kfw_type, uint64_t *msg, uint32_t wait_timeout) __attribute__((warn_unused_result));
int32_t akf_send_nmi(const KFWRAPPER_TYPE_T kfw_type);
int32_t akf_stop(const KFWRAPPER_TYPE_T kfw_type);
/*******************************************
* KFWrapper registers
*
* Below are offsets, and bit definitions
*
********************************************/
#if AKF_VERSION == 1
#define AKF_STRIDE (0x1000)
#define rAKF_AXI_BASE(_b) (*(volatile uint32_t *)((_b) + 0x0008))
#define rAKF_AXI_BASE_EXT(_b) (*(volatile uint32_t *)((_b) + 0x000C))
#define rAKF_AXI_START(_b) (*(volatile uint32_t *)((_b) + 0x0010))
#define rAKF_AXI_START_EXT(_b) (*(volatile uint32_t *)((_b) + 0x0014))
#define rAKF_AXI_END(_b) (*(volatile uint32_t *)((_b) + 0x0018))
#define rAKF_AXI_END_EXT(_b) (*(volatile uint32_t *)((_b) + 0x001C))
#define rAKF_CPU_CTRL(_b) (*(volatile uint32_t *)((_b) + 0x0028))
#define rAKF_KIC_GLB_TIME_BASE_LO(_b) (*(volatile uint32_t *)((_b) + 0x0810))
#define rAKF_KIC_GLB_TIME_BASE_HI(_b) (*(volatile uint32_t *)((_b) + 0x0818))
#define rAKF_KIC_TMR_CFG1(_b) (*(volatile uint32_t *)((_b) + 0x0884))
#define rAKF_KIC_TMR_STATE_SET1(_b) (*(volatile uint32_t *)((_b) + 0x08A4))
#elif AKF_VERSION == 2
#define AKF_STRIDE (0x4000)
#define rAKF_AXI_BASE(_b) (*(volatile uint32_t *)((_b) + 0x0008))
#define rAKF_AXI_BASE_EXT(_b) (*(volatile uint32_t *)((_b) + 0x0010))
#define rAKF_AXI_START(_b) (*(volatile uint32_t *)((_b) + 0x0018))
#define rAKF_AXI_START_EXT(_b) (*(volatile uint32_t *)((_b) + 0x0020))
#define rAKF_AXI_END(_b) (*(volatile uint32_t *)((_b) + 0x0028))
#define rAKF_AXI_END_EXT(_b) (*(volatile uint32_t *)((_b) + 0x0030))
#define rAKF_CPU_CTRL(_b) (*(volatile uint32_t *)((_b) + 0x0044))
#define rAKF_KIC_MAILBOX_EXT_SET(_b) (*(volatile uint32_t *)((_b) + 0x0c00))
#define rAKF_KIC_MAILBOX_EXT_CLR(_b) (*(volatile uint32_t *)((_b) + 0x0c04))
#define rAKF_KIC_GLB_TIME_BASE_LO(_b) (*(volatile uint32_t *)((_b) + 0xc030))
#define rAKF_KIC_GLB_TIME_BASE_HI(_b) (*(volatile uint32_t *)((_b) + 0xc038))
#define rAKF_KIC_TMR_CFG1(_b) (*(volatile uint32_t *)((_b) + 0xc000))
#define rAKF_KIC_TMR_STATE_SET1(_b) (*(volatile uint32_t *)((_b) + 0xc020))
#else
#error "Invalid or no AKF_VERSION"
// shut up additional errors
#define AKF_STRIDE (0)
#endif
#define AKF_CPU_CTRL_RUN (1<<4)
#define rAKF_KIC_GLB_CFG(_b) (*(volatile uint32_t *)((_b) + 0x080c))
#define AKF_KIC_GLB_CFG_TEN (1<<1)
#define AKF_KIC_TMR_CFG_FSL_TIMER (0 << 4)
#define AKF_KIC_TMR_CFG_FSL_SW (1 << 4)
#define AKF_KIC_TMR_CFG_FSL_EXTERNAL (2 << 4)
#define AKF_KIC_TMR_CFG_SMD_FIQ (0<<3)
#define AKF_KIC_TMR_CFG_SMD_IRQ (1<<3)
#define AKF_KIC_TMR_CFG_EMD_IRQ (1<<2)
#define AKF_KIC_TMR_CFG_IMD_FIQ (0<<1)
#define AKF_KIC_TMR_CFG_IMD_IRQ (1<<1)
#define AKF_KIC_TMR_CFG_EN (1<<0)
#define AKF_KIC_TMR_CFG_NMI (AKF_KIC_TMR_CFG_FSL_SW | AKF_KIC_TMR_CFG_SMD_FIQ | AKF_KIC_TMR_CFG_IMD_FIQ | AKF_KIC_TMR_CFG_EN)
#define AKF_KIC_TMR_STATE_SET_SGT (1<<0)
#define rAKF_AP_MAILBOX_SET(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x000))
#define rAKF_AP_MAILBOX_CLR(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x004))
#define AKF_MAILBOX_O_NONEMPTY_MSK (1<<12)
#define AKF_MAILBOX_O_EMPTY_MSK (1<<8)
#define AKF_MAILBOX_I_NONEMPTY_MSK (1<<4)
#define AKF_MAILBOX_I_EMPTY_MSK (1<<0)
#define rAKF_AP_INBOX_CTRL(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x008))
#define AKF_AP_INBOX_CTRL_UDFL (1<<19)
#define AKF_AP_INBOX_CTRL_OVFL (1<<18)
#define AKF_AP_INBOX_CTRL_EMPTY (1<<17)
#define AKF_AP_INBOX_CTRL_FULL (1<<16)
#define AKF_AP_INBOX_CTRL_ENABLE (1<<0)
// AKF "64-bit" register helpers.
__attribute__((always_inline)) inline void _akf_write_reg_64(addr_t low_addr, uint64_t value)
{
#if defined(__arm64__)
(*(volatile uint64_t *)(low_addr)) = value;
#else
uint32_t low = (uint32_t)(value & 0xFFFFFFFF);
uint32_t high = (uint32_t)((value >> 32) & 0xFFFFFFFF);
__asm__ __volatile__("strd %0, %1, [%2]" : : "r"(low), "r"(high) , "r"(low_addr));
#endif
}
__attribute__((always_inline)) inline uint64_t _akf_read_reg_64(addr_t low_addr)
{
#if defined(__arm64__)
return (*(volatile uint64_t *)(low_addr));
#else
uint32_t low, high;
__asm__ __volatile__ ("ldrd %0, %1, [%2]" : "=r"(low), "=r"(high) : "r"(low_addr));
return ((uint64_t)high << 32) | low;
#endif
}
__attribute__((always_inline)) inline void akf_write_ap_inbox(addr_t akf_base, uint64_t value)
{
_akf_write_reg_64(akf_base + AKF_STRIDE + 0x010, value);
}
#define rAKF_AP_INBOX_WR_L(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x010))
#define rAKF_AP_INBOX_WR_H(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x014))
__attribute__((always_inline)) inline uint64_t akf_read_ap_inbox(addr_t akf_base)
{
return _akf_read_reg_64(akf_base + AKF_STRIDE + 0x018);
}
#define rAKF_AP_INBOX_RD(_b) (*(volatile uint64_t *)((_b) + AKF_STRIDE + 0x018))
#define rAKF_AP_INBOX_RD_L(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x018))
#define rAKF_AP_INBOX_RD_H(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x01C))
#define rAKF_AP_OUTBOX_CTRL(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x020))
#define AKF_AP_OUTBOX_CTRL_UDFL (1<<19)
#define AKF_AP_OUTBOX_CTRL_OVFL (1<<18)
#define AKF_AP_OUTBOX_CTRL_EMPTY (1<<17)
#define AKF_AP_OUTBOX_CTRL_FULL (1<<16)
#define AKF_AP_OUTBOX_CTRL_ENABLE (1<<0)
__attribute__((always_inline)) inline void akf_write_ap_outbox(addr_t akf_base, uint64_t value)
{
_akf_write_reg_64(akf_base + AKF_STRIDE + 0x030, value);
}
#define rAKF_AP_OUTBOX_WR_L(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x030))
#define rAKF_AP_OUTBOX_WR_H(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x034))
__attribute__((always_inline)) inline uint64_t akf_read_ap_outbox(addr_t akf_base)
{
return _akf_read_reg_64(akf_base + AKF_STRIDE + 0x038);
}
#define rAKF_AP_OUTBOX_RD_L(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x038))
#define rAKF_AP_OUTBOX_RD_H(_b) (*(volatile uint32_t *)((_b) + AKF_STRIDE + 0x03C))
#endif /* _APPLE_A7IOP_H */
+16
View File
@@ -0,0 +1,16 @@
# 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
ALL_OBJS += \
$(LOCAL_DIR)/a7iop.o \
$(LOCAL_DIR)/a7iop_debug.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <drivers/display.h>
#include <platform/gpiodef.h>
#include <lib/syscfg.h>
#include <platform.h>
#include <platform/soc/chipid.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwregbase.h>
#include <drivers/dither.h>
#include <drivers/dpb.h>
#include <drivers/wpc.h>
#include <drivers/prc.h>
#include <drivers/adbe/adbe.h>
void adbe_enable_clocks(bool enable)
{
int device;
if (ADBE_DISPLAYPIPE_BASE_ADDR == DISP0_BASE_ADDR)
device = CLK_DISP0;
#ifdef DISP1_BASE_ADDR
else
device = CLK_DISP1;
#endif //DISP1_BASE_ADDR
if (enable)
clock_gate(device, true);
else
clock_gate(device, false);
}
void adbe_install_gamma_table(u_int32_t *red_lut, u_int32_t *green_lut, u_int32_t *blue_lut, struct syscfg_wpcl *wpcl)
{
RELEASE_ASSERT(red_lut != NULL);
RELEASE_ASSERT(green_lut != NULL);
RELEASE_ASSERT(blue_lut != NULL);
RELEASE_ASSERT(wpcl != NULL);
#ifdef WITH_DPB
//gamma correction is done in the dpb block
dpb_install_gamma_table(red_lut, green_lut, blue_lut, wpcl);
#endif
#ifdef WITH_WPC
//gamma correction is done in the wpc block
wpc_install_gamma_table(red_lut, green_lut, blue_lut, wpcl);
#endif
#ifdef WITH_PRC
//gamma correction is done in the prc block
prc_install_gamma_table(red_lut, green_lut, blue_lut, wpcl);
#endif
}
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2012-2014 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 __ADBE_REGS_H
#define __ADBE_REGS_H
#include <platform/soc/hwregbase.h>
#define rDBEMODECNTL (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x4))
#define DBEMODECNTL_ENABLE (1 << 31)
#define DBEMODECNTL_PRE_CSC_LUT_ENABLE (1 << 30)
#define DBEMODECNTL_CSC_ENABLE (1 << 29)
#define DBEMODECNTL_POST_CSC_LUT_ENABLE (1 << 28)
#define DBEMODECNTL_AAP_ENABLE (1 << 27)
#define DBEMODECNTL_DPB_ENABLE (1 << 26)
#define DBEMODECNTL_BN_DITHER_ENABLE (1 << 25)
#define DBEMODECNTL_ST_DITHER_ENABLE (1 << 24)
#define DBEMODECNTL_DYN_CLK_GATE_ENABLE (1 << 23)
#define DBEMODECNTL_AFC_TEARDOWN_ENABLE (1 << 22)
#define DBEMODECNTL_PMGR_CLK_GATE_ENABL (1 << 21)
#define DBEMODECNTL_BLK_CLK_GATE_ENABLE (1 << 20)
#define DBEMODECNTL_VSYNC_POLARITY (1 << 19)
#define DBEMODECNTL_HSYNC_POLARITY (1 << 18)
#define DBEMODECNTL_I_P_SELECT(x) (x << 16)
#define DBEMODECNTL_UPDATE_ENABLE_TIMING (1 << 15)
#define DBEMODECNTL_UPDATE_REQ_TIMING (1 << 14)
#define DBEMODECNTL_CH2_SEL(x) (x << 12)
#define DBEMODECNTL_CH1_SEL(x) (x << 10)
#define DBEMODECNTL_CH0_SEL(x) (x << 8)
#define DBEMODECNTL_CRC_ENABLE (1 << 7)
#define DBEMODECNTL_CRC_MULTIFRAME_ENABLE (1 << 6)
#define DBEMODECNTL_CRC_WINDOW_ENABLE (1 << 5)
#define DBEMODECNTL_CRC_VALID (1 << 4)
#define DBEMODECNTL_VFTG_STATUS (1 << 0)
#define rDBECONSTCOLOR (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x8))
#define rDBESCRNSZ (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0xC))
#define rDBEFRONTPORCH (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x10))
#define rDBESYNCPULSE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x14))
#define rDBEBACKPORCH (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x18))
#define rDBEVBLANKPOS (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x1C))
#define rDBEVBLANKCLKGATE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x20))
#define rDBEVBLANKIDLE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x24))
#define rDBECRCWINDOW (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x28))
#define rDBECRCRESULT (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x2C))
//Only Alcatraz has the color manager on the back end. No need to generated a new driver just for it.
#define rCM_DEGAMMA_RED(n) (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x0400 + ((n) * 4)))
#define rCM_DEGAMMA_GREEN(n) (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x0800 + ((n) * 4)))
#define rCM_DEGAMMA_BLUE(n) (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x0c00 + ((n) * 4)))
#define rCM_CSC_00 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1000)
#define rCM_MATRIX_BASE(n) (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1000 + ((n) * 4)))
#define rCM_CSC_01 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1004))
#define rCM_CSC_02 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1008))
#define rCM_CSC_C0 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x100c))
#define rCM_CSC_CI0 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1010))
#define rCM_CSC_10 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1014))
#define rCM_CSC_11 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1018))
#define rCM_CSC_12 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x101c))
#define rCM_CSC_C1 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1020))
#define rCM_CSC_CI1 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1024))
#define rCM_CSC_20 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1028))
#define rCM_CSC_21 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1020))
#define rCM_CSC_22 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1030))
#define rCM_CSC_C2 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1034))
#define rCM_CSC_CI2 (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1038))
#define rCM_LUT_CTL (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x103c))
#define CM_LUT_CTL (DISP_CM_BASE_ADDR + 0x103c)
#define CM_LUT_CTL_UPDATE_ENABLE_ENG_BLUE (1 << 23)
#define CM_LUT_CTL_UPDATE_REQ_ENG_BLUE (1 << 22)
#define CM_LUT_CTL_BYPASS_ENG_BLUE (1 << 21)
#define CM_LUT_CTL_UPDATE_ENABLE_DEG_BLUE (1 << 19)
#define CM_LUT_CTL_UPDATE_REQ_DEG_BLUE (1 << 18)
#define CM_LUT_CTL_BYPASS_DEG_BLUE (1 << 17)
#define CM_LUT_CTL_UPDATE_ENABLE_ENG_GREEN (1 << 15)
#define CM_LUT_CTL_UPDATE_REQ_ENG_GREEN (1 << 14)
#define CM_LUT_CTL_BYPASS_ENG_GREEN (1 << 13)
#define CM_LUT_CTL_UPDATE_ENABLE_DEG_GREEN (1 << 11)
#define CM_LUT_CTL_UPDATE_REQ_DEG_GREEN (1 << 10)
#define CM_LUT_CTL_BYPASS_DEG_GREEN (1 << 9)
#define CM_LUT_CTL_UPDATE_ENABLE_ENG_RED (1 << 7)
#define CM_LUT_CTL_UPDATE_REQ_ENG_RED (1 << 6)
#define CM_LUT_CTL_BYPASS_ENG_RED (1 << 5)
#define CM_LUT_CTL_UPDATE_ENABLE_DEG_RED (1 << 3)
#define CM_LUT_CTL_UPDATE_REQ_DEG_RED (1 << 2)
#define CM_LUT_CTL_BYPASS_DEG_RED (1 << 1)
#define rCM_ENGAMMA_RED(n) (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x1200 + ((n) * 4)))
#define rCM_ENGAMMA_GREEN(n) (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x2200 + ((n) * 4)))
#define rCM_ENGAMMA_BLUE(n) (*(volatile u_int32_t *)(DISP_CM_BASE_ADDR + 0x3200 + ((n) * 4)))
#endif /* __ADBE_REGS_H */
+89
View File
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2012-2014 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 __ADBE_REGS_H
#define __ADBE_REGS_H
#include <platform/soc/hwregbase.h>
#define rDBEMODECNTL (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x4))
#define DBEMODECNTL_AAP_ENABLE (1 << 31)
#define DBEMODECNTL_DPB_ENABLE (1 << 30)
#define DBEMODECNTL_BN_DITHER_ENABLE (1 << 29)
#define DBEMODECNTL_ST_DITHER_ENABLE (1 << 28)
#define DBEMODECNTL_DPB_BUSY_MASK (1 << 23)
#define DBEMODECNTL_PMGR_CLK_GATE_ENABLE (1 << 22)
#define DBEMODECNTL_DYN_CLK_GATE_ENABLE (1 << 21)
#define DBEMODECNTL_BLK_CLK_GATE_ENABLE (1 << 20)
#define DBEMODECNTL_DITHER_ENABLE (1 << 28)
#define DBEMODECNTL_PRC_ENABLE (1 << 27)
#define DBEMODECNTL_WPC_ENABLE (1 << 26)
#define rDBEVFTGCTL (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x8))
#define DBEVFTGCT_VFTG_ENABLE (1 << 31)
#define DBEVFTGCT_VFTG_STATUS (1 << 30)
#define DBEVFTGCT_FRAME_COUNT_ENABLE (1 << 29)
#define DBEVFTGCT_FRAME_COUNT_RESET (1 << 28)
#define DBEVFTGCT_IDLE_FRAME_VBLANK_ENABLE (1 << 24)
#define DBEVFTGCT_VSYNC_POLARITY(n) ((n) << 19)
#define DBEVFTGCT_HSYNC_POLARITY(n) ((n) << 18)
#define DBEVFTGCT_SCAN_SELECT(n) ((n) << 16)
#define DBEVFTGCT_UPDATE_ENABLE_TIMING (1 << 15)
#define DBEVFTGCT_UPDATE_REQ_TIMING (1 << 14)
#define DBEVFTGCT_CH2_SEL(n) ((n) << 12)
#define DBEVFTGCT_CH1_SEL(n) ((n) << 10)
#define DBEVFTGCT_CH0_SEL(n) ((n) << 8)
#define DBEVFTGCT_VERTICAL_STATUS(n) ((n) << 4)
#define DBEVFTGCT_HORIZONTAL_STATUS(n) ((n) << 0)
#define rDBESCRNSZ (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0xC))
#define rDBEFRONTPORCH (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x10))
#define rDBESYNCPULSE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x14))
#define rDBEBACKPORCH (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x18))
#define rDBECOUNTER_STATUS (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x1C))
#define rDBECOUNTER_POSITION (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x20))
#define rDBEVBLANK_POSITION (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x24))
#define rDBEVBLANKCLKGATE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x28))
#define rDBEVBLANKBUSY (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x2C))
#define rDBEISR (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x30))
#define rDBECONST_COLOR (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x34))
#define rDBECRC_CTL (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x38))
#define rDBECRCWINDOW (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x3C))
#define rDBECRCRESULT (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x40))
#define rDBEFIFO_CONFIG (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x44))
#define rDBEFIFO_STATUS (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x48))
#define rDBESPARE_CONFIG0 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x4C))
#define rDBESPARE_CONFIG1 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x50))
#define rDBESPARE_CONFIG2 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x54))
#define rDBESPARE_CONFIG3 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x58))
#define rDBESPARE_STATUS0 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x5C))
#define rDBESPARE_STATUS1 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x60))
#define rDBESPARE_STATUS2 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x64))
#define rDBESPARE_STATUS3 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x68))
#define rAAP_FORMAT_CONTROL_REG0 (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x0))
#define rAAP_FORMAT_CONTROL_REG1 (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x4))
#define AAP_FORMAT_CONTROL_REG1_AUTOSIZE (1 << 7)
#define AAP_FORMAT_CONTROL_REG1_AUTOPOS (1 << 6)
#define AAP_FORMAT_CONTROL_REG1_FCMODE(n) ((n & 0x3) << 4)
#define AAP_FORMAT_CONTROL_REG1_RSVD(n) ((n & 0xf) << 2)
#define AAP_FORMAT_CONTROL_REG1_VS_POL (1 << 1)
#define AAP_FORMAT_CONTROL_REG1_HS_POL (1 << 0)
#define rAAP_FORMAT_HS_POS_LSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x8))
#define rAAP_FORMAT_HS_POS_MSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0xC))
#define rAAP_FORMAT_FRAME_WIDTH_LSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x10))
#define rAAP_FORMAT_FRAME_WIDTH_MSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x14))
#define rAAP_FORMAT_FRAME_HEIGHT_LSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x18))
#define rAAP_FORMAT_FRAME_HEIGHT_MSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x1C))
#define rAAP_FORMAT_VS_POS_LSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x20))
#define rAAP_FORMAT_VS_POS_MSB (*(volatile u_int32_t *)(DISP0_AAP_BASE_ADDR + 0x24))
#endif /* __ADBE_REGS_H */
+153
View File
@@ -0,0 +1,153 @@
/*
* Copyright (C) 2014 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 __ADBE_REGS_V3_H
#define __ADBE_REGS_V3_H
#define rADBE_VERSION (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0000))
#define rADBE_NRT_CTL (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0004))
#define ADBE_NRT_CTL_VFTG_MODE_COMMAND (1 << 25)
#define ADBE_NRT_CTL_TE_ENABLE_SEL_SW (1 << 24)
#define ADBE_NRT_CTL_TE_MODE_MASK (3 << 22)
#define ADBE_NRT_CTL_TE_MODE_IDLE (0 << 22)
#define ADBE_NRT_CTL_TE_MODE_POS (1 << 22)
#define ADBE_NRT_CTL_TE_MODE_NEG (2 << 22)
#define ADBE_NRT_CTL_TE_MODE_TOGGLE (3 << 22)
#define ADBE_NRT_CTL_AAP_ENABLE (1 << 21)
#define ADBE_NRT_CTL_BN_DITHER_ENABLE (1 << 20)
#define ADBE_NRT_CTL_ST_DITHER_ENABLE (1 << 19)
#define ADBE_NRT_CTL_ADISP_CLK_GATE_ENABLE (1 << 18)
#define ADBE_NRT_CTL_ADBE_CLK_GATE_ENABLE (1 << 17)
#define ADBE_NRT_CTL_BLK_CLK_GATE_ENABLE (1 << 16)
#define ADBE_NRT_CTL_VSYNC_POLARITY(n) ((n) << 9)
#define ADBE_NRT_CTL_HSYNC_POLARITY(n) ((n) << 8)
#define ADBE_NRT_CTL_SCAN_SELECT_PROG_NOCHG (0 << 6)
#define ADBE_NRT_CTL_SCAN_SELECT_INT_ODD (1 << 6)
#define ADBE_NRT_CTL_SCAN_SELECT_PROG_CHG (2 << 6)
#define ADBE_NRT_CTL_SCAN_SELECT_INT_EVEN (3 << 6)
#define ADBE_NRT_CTL_CH2_SEL_RED (0 << 4)
#define ADBE_NRT_CTL_CH2_SEL_GREEN (1 << 4)
#define ADBE_NRT_CTL_CH2_SEL_BLUE (2 << 4)
#define ADBE_NRT_CTL_CH2_SEL_CONST (3 << 4)
#define ADBE_NRT_CTL_CH1_SEL_RED (0 << 2)
#define ADBE_NRT_CTL_CH1_SEL_GREEN (1 << 2)
#define ADBE_NRT_CTL_CH1_SEL_BLUE (2 << 2)
#define ADBE_NRT_CTL_CH1_SEL_CONST (3 << 2)
#define ADBE_NRT_CTL_CH0_SEL_RED (0 << 0)
#define ADBE_NRT_CTL_CH0_SEL_GREEN (1 << 0)
#define ADBE_NRT_CTL_CH0_SEL_BLUE (2 << 0)
#define ADBE_NRT_CTL_CH0_SEL_CONST (3 << 0)
#define rADBE_RT_CTL (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0008))
#define ADBE_RT_CTL_VFTG_STATUS_EN (1 << 16)
#define ADBE_RT_CTL_VERTICAL_STATUS_IDLE (0 << 12)
#define ADBE_RT_CTL_VERTICAL_STATUS_ACTIVE (8 << 12)
#define ADBE_RT_CTL_VERTICAL_STATUS_FRONT (4 << 12)
#define ADBE_RT_CTL_VERTICAL_STATUS_SYNC (2 << 12)
#define ADBE_RT_CTL_VERTICAL_STATUS_BACK (1 << 12)
#define ADBE_RT_CTL_HORIZONTAL_STATUS_IDLE (0 << 8)
#define ADBE_RT_CTL_HORIZONTAL_STATUS_ACTIVE (8 << 8)
#define ADBE_RT_CTL_HORIZONTAL_STATUS_FRONT (4 << 8)
#define ADBE_RT_CTL_HORIZONTAL_STATUS_SYNC (2 << 8)
#define ADBE_RT_CTL_HORIZONTAL_STATUS_BACK (1 << 8)
#define ADBE_RT_CTL_VFTG_ENABLE_CMD_EN (1 << 5)
#define ADBE_RT_CTL_VFTG_ENABLE_VID_EN (1 << 4)
#define ADBE_RT_CTL_UPDATE_ENABLE_TIMING_READY (1 << 3)
#define ADBE_RT_CTL_UPDATE_REQ_TIMING_NOSYNC (1 << 2)
#define ADBE_RT_CTL_FRAME_COUNT_ENABLE (1 << 1)
#define ADBE_RT_CTL_FRAME_COUNT_RESET_EN (1 << 0)
#define rADBE_ACTIVE_SIZE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x000c))
#define ADBE_ACTIVE_SIZE_VERTICAL(n) ((n) << 16)
#define ADBE_ACTIVE_SIZE_HORIZONTAL(n) ((n) << 0)
#define rADBE_FRONT_PORCH (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0010))
#define ADBE_FRONT_PORCH_VERTICAL(n) ((n) << 16)
#define ADBE_FRONT_PORCH_HORIZONTAL(n) ((n) << 0)
#define rADBE_SYNC_PULSE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0014))
#define ADBE_SYNC_PULSE_VERTICAL(n) ((n) << 16)
#define ADBE_SYNC_PULSE_HORIZONTAL(n) ((n) << 0)
#define rADBE_BACK_PORCH (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0018))
#define ADBE_BACK_PORCH_VERTICAL(n) ((n) << 16)
#define ADBE_BACK_PORCH_HORIZONTAL(n) ((n) << 0)
#define rADBE_COUNTER_STATUS (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x001c))
#define ADBE_COUNTER_STATUS_FRAME_COUNTER(n) ((n) << 16)
#define ADBE_COUNTER_STATUS_LINE_COUNTER(n) ((n) << 0)
#define rADBE_COUNTER_POSITION (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0020))
#define ADBE_COUNTER_POSITION_FRAME_COUNTER(n) ((n) << 16)
#define ADBE_COUNTER_POSITION_LINE_COUNTER(n) ((n) << 0)
#define rADBE_VBLANK_POSITION (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0024))
#define ADBE_VBLANK_POSITION_FIELD_OUT(n) ((n) << 16)
#define ADBE_VBLANK_POSITION_VBI_PULSE(n) ((n) << 0)
#define rADBE_VBLANK_CLK_GATE (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0028))
#define ADBE_VBLANK_CLK_GATE_WAKEUP(n) ((n) << 16)
#define ADBE_VBLANK_CLK_GATE_IDLE(n) ((n) << 0)
#define rADBE_VBLANK_BUSY (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x002c))
#define ADBE_VBLANK_BUSY_FINISH(n) ((n) << 16)
#define ADBE_VBLANK_BUSY_START(n) ((n) << 0)
#define rADBE_INTERRUPT (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0030))
#define ADBE_INTERRUPT_COUNTER_MASK (1 << 18)
#define ADBE_INTERRUPT_VFTG_DOWN_MASK (1 << 17)
#define ADBE_INTERRUPT_VBI_TE_MASK (1 << 16)
#define ADBE_INTERRUPT_COUNTER_STATUS (1 << 2)
#define ADBE_INTERRUPT_VFTG_DOWN_STATUS (1 << 1)
#define ADBE_INTERRUPT_VBI_TE_STATUS (1 << 0 )
#define rADBE_CONST_COLOR (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0034))
#define ADBE_CONST_COLOR_VALUE_CH2(n) ((n) << 20)
#define ADBE_CONST_COLOR_VALUE_CH1(n) ((n) << 10)
#define ADBE_CONST_COLOR_VALUE_CH0(n) ((n) << 0)
#define rADBE_CRC_CTL (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0038))
#define ADBE_CRC_CTL_ENABLE (1 << 3)
#define ADBE_CRC_CTL_MULTIFRAME_ENABLE (1 << 2)
#define ADBE_CRC_CTL_WINDOW_ENABLE (1 << 1)
#define ADBE_CRC_CTL_VALID (1 << 0)
#define rADBE_CRC_WINDOW (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x003c))
#define ADBE_CRC_WINDOW_RIGHT ((n) << 16)
#define ADBE_CRC_WINDOW_LEFT ((n) << 0)
#define rADBE_CRC_RESULT (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0040))
#define rADBE_FIFO_CONFIG (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0044))
#define ADBE_FIFO_CONFIG_UNDERRUN_MODE_DEFAULT (0 << 30)
#define ADBE_FIFO_CONFIG_UNDERRUN_MODE_NORMAL (1 << 30)
#define ADBE_FIFO_CONFIG_UNDERRUN_MODE_FRAME (2 << 30)
#define ADBE_FIFO_CONFIG_UNDERRUN_MODE_STICKY (3 << 30)
#define ADBE_FIFO_CONFIG_UNDERRUN_CH2(n) ((n) << 20)
#define ADBE_FIFO_CONFIG_UNDERRUN_CH1(n) ((n) << 10)
#define ADBE_FIFO_CONFIG_UNDERRUN_CH0(n) ((n) << 0)
#define rADBE_FIFO_STATUS (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0048))
#define ADBE_FIFO_STATUS_FULL (1 << 25)
#define ADBE_FIFO_STATUS_EMPTY (1 << 24)
#define ADBE_FIFO_STATUS_PUSH_COUNT_GRAY(n) ((n) << 12)
#define ADBE_FIFO_STATUS_POP_COUNT_GRAY(n) ((n) << 0)
#define rADBE_SPARE_CONFIG0 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x004c))
#define rADBE_SPARE_CONFIG1 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0050))
#define rADBE_SPARE_CONFIG2 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0054))
#define rADBE_SPARE_CONFIG3 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0058))
#define rADBE_SPARE_STATUS0 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x005c))
#define rADBE_SPARE_STATUS1 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0060))
#define rADBE_SPARE_STATUS2 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0064))
#define rADBE_SPARE_STATUS3 (*(volatile u_int32_t *)(DISP0_ADBE_BASE_ADDR + 0x0068))
#endif // __ADBE_REGS_V3_H
+185
View File
@@ -0,0 +1,185 @@
/*
* Copyright (C) 2012-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include "adbe_regs_v1.h"
#include <debug.h>
#include <drivers/display.h>
#include <lib/paint.h>
#include <platform/gpiodef.h>
#include <lib/syscfg.h>
#include <platform.h>
#include <platform/soc/chipid.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwregbase.h>
#include <drivers/dither.h>
#include <drivers/dpb.h>
#include <drivers/adbe/adbe.h>
#include <lib/mib.h>
struct adbe_v1_tuneable {
char *name;
uint32_t adbe0_tunable_mode_ctrl;
uint32_t adbe0_vblank_pos_vbi_pulse;
uint32_t adbe0_vblank_clk_gate_wakeup;
uint32_t adbe0_vblank_clk_gate_idle;
uint32_t adbe0_vblank_blk_idle_dpb;
uint32_t adbe0_vblank_blk_idle_aap;
uint32_t adbe0_aap_support;
};
#include <target/adbe_settings.h>
static struct adbe_v1_tuneable *adbe_tuneables_info;
static const int32_t adbe_tuneables_list_size = sizeof(adbe_tuneables) / sizeof(struct adbe_v1_tuneable);
static void adbe_program_color_manager()
{
uint32_t i;
uint32_t engamma_table_count = mib_get_u32(kMIBTargetDisplayCMEngammaTableCount);
uint32_t degamma_table_count = mib_get_u32(kMIBTargetDisplayCMDegammaTableCount);
uint32_t matrix_table_count = mib_get_u32(kMIBTargetDisplayCMMatrixTableCount);
if (engamma_table_count != 0 && degamma_table_count != 0 && matrix_table_count != 0) {
const uint32_t * engamma_table_base = (const uint32_t *)mib_get_ptr(kMIBTargetDisplayCMEngammaTablePtr);
const uint32_t * degamma_table_base = (const uint32_t *)mib_get_ptr(kMIBTargetDisplayCMDegammaTablePtr);
const uint32_t * matrix_table_base = (const uint32_t *)mib_get_ptr(kMIBTargetDisplayCMMatrixTablePtr);
for (i = 0; i < degamma_table_count; i++) {
rCM_DEGAMMA_RED(i) = degamma_table_base[i];
rCM_DEGAMMA_GREEN(i) = degamma_table_base[i];
rCM_DEGAMMA_BLUE(i) = degamma_table_base[i];
}
for (i = 0; i < matrix_table_count; i++) {
rCM_MATRIX_BASE(i) = matrix_table_base[i];
}
for (i = 0; i < engamma_table_count; i++) {
rCM_ENGAMMA_RED(i) = engamma_table_base[i];
rCM_ENGAMMA_GREEN(i) = engamma_table_base[i];
rCM_ENGAMMA_BLUE(i) = engamma_table_base[i];
}
//enabe LUTs in the lut register
rCM_LUT_CTL = CM_LUT_CTL_UPDATE_ENABLE_ENG_BLUE |
CM_LUT_CTL_UPDATE_REQ_ENG_BLUE |
CM_LUT_CTL_UPDATE_ENABLE_DEG_BLUE |
CM_LUT_CTL_UPDATE_REQ_DEG_BLUE |
CM_LUT_CTL_UPDATE_ENABLE_ENG_GREEN |
CM_LUT_CTL_UPDATE_REQ_ENG_GREEN |
CM_LUT_CTL_UPDATE_ENABLE_DEG_GREEN |
CM_LUT_CTL_UPDATE_REQ_DEG_GREEN |
CM_LUT_CTL_UPDATE_ENABLE_ENG_RED |
CM_LUT_CTL_UPDATE_REQ_ENG_RED |
CM_LUT_CTL_UPDATE_ENABLE_DEG_RED |
CM_LUT_CTL_UPDATE_REQ_DEG_RED;
}
}
void adbe_init(struct display_timing *timing)
{
const char *env;
int32_t cnt;
env = env_get("adbe-tunable");
if (env == 0) env = "default";
for (cnt = 0; cnt < adbe_tuneables_list_size; cnt++) {
if (strcmp(env, adbe_tuneables[cnt].name)) continue;
adbe_tuneables_info = adbe_tuneables + cnt;
}
if (adbe_tuneables_info == 0) {
dprintf(DEBUG_INFO, "Failed to find adbe tunables info, bailing adbe_init()\n");
return;
}
rDBESCRNSZ = (timing->v_active << 16) | (timing->h_active << 0);
rDBEFRONTPORCH = (timing->v_front_porch << 16) | (timing->h_front_porch << 0);
rDBESYNCPULSE = (timing->v_pulse_width << 16) | (timing->h_pulse_width << 0);
rDBEBACKPORCH = (timing->v_back_porch << 16) | (timing->h_back_porch << 0);
rDBEVBLANKPOS = adbe_tuneables_info->adbe0_vblank_pos_vbi_pulse;
#ifdef TARGET_ADBE0_VBLANK_POSITION
rDBEVBLANKPOS |= TARGET_ADBE0_VBLANK_POSITION;
#endif
adbe_tuneables_info->adbe0_vblank_clk_gate_wakeup = timing->v_back_porch + timing->v_front_porch + timing->v_pulse_width - 5;
rDBEVBLANKCLKGATE = ((adbe_tuneables_info->adbe0_vblank_clk_gate_wakeup << 16) | adbe_tuneables_info->adbe0_vblank_clk_gate_idle);
rDBEVBLANKIDLE = ((adbe_tuneables_info->adbe0_vblank_blk_idle_dpb << 16) | adbe_tuneables_info->adbe0_vblank_blk_idle_aap);
//csc lut programming should occur here
//Set AAP
rDBEMODECNTL |= (adbe_tuneables_info->adbe0_aap_support) ? DBEMODECNTL_AAP_ENABLE: 0;
#ifdef WITH_DPB
// Need to enable block first in order to access its registers
rDBEMODECNTL |= DBEMODECNTL_DPB_ENABLE;
dpb_init();
#endif
// Dither
#ifdef WITH_HW_DITHER
//Currently, no product uses BN on H6.
uint8_t dither_type = DITHER_SPATIO_TEMPORAL;
#ifdef TARGET_DITHER_TYPE
dither_type = TARGET_DITHER_TYPE;
#endif //TARGET_DITHER_TYPE
//Dithering gets enabled in this block, no need to call into dithering to enable
//We need to enable to block to access their corresponding registers
switch(dither_type) {
case DITHER_SPATIO_TEMPORAL:
rDBEMODECNTL |= DBEMODECNTL_ST_DITHER_ENABLE;
break;
case DITHER_BLUE_NOISE:
rDBEMODECNTL |= DBEMODECNTL_BN_DITHER_ENABLE;
break;
case DITHER_NONE:
default:
rDBEMODECNTL &= ~(DBEMODECNTL_ST_DITHER_ENABLE | DBEMODECNTL_BN_DITHER_ENABLE);
break;
}
dither_init(timing->display_depth);
#endif
#ifdef TARGET_ENABLE_CM
rDBEMODECNTL |= (DBEMODECNTL_PRE_CSC_LUT_ENABLE | DBEMODECNTL_CSC_ENABLE | DBEMODECNTL_POST_CSC_LUT_ENABLE);
adbe_program_color_manager();
#endif
rDBEMODECNTL |= adbe_tuneables_info->adbe0_tunable_mode_ctrl;
// Radar <rdar://problem/13402498> J72dev2 - Innsbruck11A289 | Playing a video in full screen causes the screen to go blank
// need to force an update to the timing before enabling the timing generator
rDBEMODECNTL |= (DBEMODECNTL_UPDATE_ENABLE_TIMING | DBEMODECNTL_UPDATE_REQ_TIMING);
}
void adbe_enable_timing_generator(bool enable)
{
if (enable) {
rDBEMODECNTL |= DBEMODECNTL_ENABLE; // Enable VFTG
while ((rDBEMODECNTL & DBEMODECNTL_VFTG_STATUS) == 0); // Wait for it to be enabled
}
else {
rDBEMODECNTL &= ~DBEMODECNTL_ENABLE; // Enable VFTG
while ((rDBEMODECNTL & DBEMODECNTL_VFTG_STATUS) == 1); // Wait for it to be disabled
}
}
bool adbe_get_enable_timing_generator(void)
{
return ((rDBEMODECNTL & DBEMODECNTL_ENABLE) == (uint32_t)DBEMODECNTL_ENABLE);
}
+166
View File
@@ -0,0 +1,166 @@
/*
* Copyright (C) 2012-2014 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 "adbe_regs_v2.h"
#include <debug.h>
#include <drivers/display.h>
#include <lib/paint.h>
#include <platform/gpiodef.h>
#include <lib/syscfg.h>
#include <platform.h>
#include <platform/soc/chipid.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwregbase.h>
#include <drivers/dither.h>
#include <drivers/dpb.h>
#include <drivers/wpc.h>
#include <drivers/prc.h>
#include <drivers/adbe/adbe.h>
struct adbe_v2_tuneable {
char *name;
uint32_t adbe0_tunable_mode_ctrl;
uint32_t adbe0_vftgctl_idle_frame_vblank_enable;
uint32_t adbe0_vblank_pos_vbi_pulse;
uint32_t adbe0_vblank_clk_gate_wakeup;
uint32_t adbe0_vblank_clk_gate_idle;
uint32_t adbe0_vblank_busy_finish;
uint32_t adbe0_aap_support;
uint32_t adbe0_aap_format_control_reg1;
};
#include <target/adbe_settings.h>
static struct adbe_v2_tuneable *adbe_tuneables_info;
static const int32_t adbe_tuneables_list_size = sizeof(adbe_tuneables) / sizeof(struct adbe_v2_tuneable);
void adbe_init(struct display_timing *timing)
{
const char *env;
int32_t cnt;
env = env_get("adbe-tunables");
if (env == 0) env = "default";
for (cnt = 0; cnt < adbe_tuneables_list_size; cnt++) {
if (strcmp(env, adbe_tuneables[cnt].name)) continue;
adbe_tuneables_info = adbe_tuneables + cnt;
}
if (adbe_tuneables_info == 0) {
dprintf(DEBUG_INFO, "Failed to find adbe tunables info, bailing adbe_init()\n");
return;
}
rDBESCRNSZ = (timing->v_active << 16) | (timing->h_active << 0);
rDBEFRONTPORCH = (timing->v_front_porch << 16) | (timing->h_front_porch << 0);
rDBESYNCPULSE = (timing->v_pulse_width << 16) | (timing->h_pulse_width << 0);
rDBEBACKPORCH = (timing->v_back_porch << 16) | (timing->h_back_porch << 0);
rDBEVFTGCTL |= (DBEVFTGCT_VSYNC_POLARITY(timing->neg_vsync) | DBEVFTGCT_HSYNC_POLARITY(timing->neg_hsync));
rDBEVFTGCTL |= DBEVFTGCT_FRAME_COUNT_ENABLE | DBEVFTGCT_SCAN_SELECT(0x2);
rDBEVFTGCTL |= adbe_tuneables_info->adbe0_vftgctl_idle_frame_vblank_enable ? DBEVFTGCT_IDLE_FRAME_VBLANK_ENABLE : 0 ;
rDBEVBLANK_POSITION = (rDBEVBLANK_POSITION & ~0xFFFF) | adbe_tuneables_info->adbe0_vblank_pos_vbi_pulse;
rDBEVBLANKCLKGATE = ((adbe_tuneables_info->adbe0_vblank_clk_gate_wakeup << 16) | adbe_tuneables_info->adbe0_vblank_clk_gate_idle);
rDBEVBLANKBUSY = (adbe_tuneables_info->adbe0_vblank_busy_finish << 16);
//csc lut programming should occur here
rAAP_FORMAT_CONTROL_REG1 = adbe_tuneables_info->adbe0_aap_format_control_reg1;
//Set AAP
rDBEMODECNTL |= (adbe_tuneables_info->adbe0_aap_support) ? DBEMODECNTL_AAP_ENABLE: 0;
#ifdef WITH_DPB
// Need to enable block first in order to access its registers
rDBEMODECNTL |= DBEMODECNTL_DPB_ENABLE;
#if DPB_VERSION < 2
dpb_init();
#else
dpb_init(timing->h_active, timing->v_active);
#endif
#endif
#ifdef WITH_WPC
// Need to enable block first in order to access its registers
rDBEMODECNTL |= DBEMODECNTL_WPC_ENABLE;
wpc_init(timing->h_active, timing->v_active);
#endif
#ifdef WITH_PRC
// Need to enable block first in order to access its registers
rDBEMODECNTL |= DBEMODECNTL_PRC_ENABLE;
prc_init(timing->h_active, timing->v_active);
#endif
// Dither
#if DITHER_VERSION < 4
#ifdef WITH_HW_DITHER
//Currently, no product uses BN on H6.
uint8_t dither_type = DITHER_SPATIO_TEMPORAL;
#ifdef TARGET_DITHER_TYPE
dither_type = TARGET_DITHER_TYPE;
#endif //TARGET_DITHER_TYPE
//Dithering gets enabled in this block, no need to call into dithering to enable
//We need to enable to block to access their corresponding registers
switch(dither_type) {
case DITHER_SPATIO_TEMPORAL:
rDBEMODECNTL |= DBEMODECNTL_ST_DITHER_ENABLE;
break;
case DITHER_BLUE_NOISE:
rDBEMODECNTL |= DBEMODECNTL_BN_DITHER_ENABLE;
break;
case DITHER_NONE:
default:
rDBEMODECNTL &= ~(DBEMODECNTL_ST_DITHER_ENABLE | DBEMODECNTL_BN_DITHER_ENABLE);
break;
}
dither_init(timing->display_depth);
#endif
#else // DITHER_VERSION >= 4
#ifdef WITH_HW_DITHER
// Enable Dither Block
rDBEMODECNTL |= DBEMODECNTL_DITHER_ENABLE;
dither_init(timing->h_active, timing->v_active, timing->display_depth);
#endif
#endif
rDBEMODECNTL |= adbe_tuneables_info->adbe0_tunable_mode_ctrl;
rDBEFIFO_CONFIG = 0x400003ff;
//disable interrupts
rDBEISR = ((1 << 18) | (1 << 17) | (1 << 16));
rDBEVFTGCTL |= (DBEVFTGCT_UPDATE_ENABLE_TIMING | DBEVFTGCT_UPDATE_REQ_TIMING);
}
void adbe_enable_timing_generator(bool enable)
{
if (enable) {
rDBEVFTGCTL |= DBEVFTGCT_VFTG_ENABLE; // Enable VFTG
while ((rDBEVFTGCTL & DBEVFTGCT_VFTG_STATUS) == 0); // Wait for it to be enabled
} else {
rDBEVFTGCTL &= ~DBEVFTGCT_VFTG_ENABLE; // Disable VFTG
while ((rDBEVFTGCTL & DBEVFTGCT_VFTG_STATUS) == DBEVFTGCT_VFTG_STATUS); // Wait for it to be disabled
}
}
bool adbe_get_enable_timing_generator(void)
{
return ((rDBEVFTGCTL & DBEVFTGCT_VFTG_ENABLE) == (uint32_t)DBEVFTGCT_VFTG_ENABLE);
}
+163
View File
@@ -0,0 +1,163 @@
/*
* Copyright (C) 2012-2014 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 "adbe_regs_v3.h"
#include <debug.h>
#include <drivers/display.h>
#include <lib/paint.h>
#include <platform/gpiodef.h>
#include <lib/syscfg.h>
#include <platform.h>
#include <platform/soc/chipid.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwregbase.h>
#include <drivers/dither.h>
#include <drivers/dpb.h>
#include <drivers/adbe/adbe.h>
struct adbe_v3_tuneable {
char *name;
uint32_t adbe0_vblank_clk_gate_wakeup;
uint32_t adbe0_vblank_clk_gate_idle;
uint32_t adbe0_tunable_nrt_ctl;
uint32_t adbe0_aap_support;
};
#include <target/adbe_settings.h>
static bool is_video_mode = true;
static struct adbe_v3_tuneable *adbe_tuneables_info;
static const int32_t adbe_tuneables_list_size = sizeof(adbe_tuneables) / sizeof(struct adbe_v3_tuneable);
void adbe_init(struct display_timing *timing)
{
const char *env;
int32_t cnt;
env = env_get("adbe-tunable");
if (env == 0) env = "default";
for (cnt = 0; cnt < adbe_tuneables_list_size; cnt++) {
if (strcmp(env, adbe_tuneables[cnt].name)) continue;
adbe_tuneables_info = adbe_tuneables + cnt;
}
if (adbe_tuneables_info == 0) {
dprintf(DEBUG_INFO, "Failed to find adbe tunables info, bailing adbe_init()\n");
return;
}
rADBE_ACTIVE_SIZE = ADBE_ACTIVE_SIZE_VERTICAL(timing->v_active) | ADBE_ACTIVE_SIZE_HORIZONTAL(timing->h_active);
rADBE_FRONT_PORCH = ADBE_FRONT_PORCH_VERTICAL(timing->v_front_porch) | ADBE_FRONT_PORCH_HORIZONTAL(timing->h_front_porch );
rADBE_SYNC_PULSE = ADBE_SYNC_PULSE_VERTICAL(timing->v_pulse_width) | ADBE_SYNC_PULSE_HORIZONTAL(timing->h_pulse_width);
rADBE_BACK_PORCH = ADBE_BACK_PORCH_VERTICAL(timing->v_back_porch) | ADBE_BACK_PORCH_HORIZONTAL(timing->h_back_porch);
//rdar://16085315 Errata Samsung’s DSIM_MDRESOL.MainStandby register field description.
rADBE_NRT_CTL &= ~ADBE_NRT_CTL_TE_MODE_MASK;
rADBE_NRT_CTL |= (ADBE_NRT_CTL_VSYNC_POLARITY(timing->neg_vsync) | ADBE_NRT_CTL_HSYNC_POLARITY(timing->neg_hsync));
rADBE_RT_CTL |= ADBE_RT_CTL_FRAME_COUNT_ENABLE;
rADBE_NRT_CTL |= ADBE_NRT_CTL_SCAN_SELECT_PROG_CHG;
#ifdef TARGET_ADBE0_VBLANK_POSITION
rADBE_VBLANK_POSITION = TARGET_ADBE0_VBLANK_POSITION;
#endif
adbe_tuneables_info->adbe0_vblank_clk_gate_wakeup = timing->v_back_porch + timing->v_front_porch + timing->v_pulse_width - 5;
rADBE_VBLANK_CLK_GATE =
(ADBE_VBLANK_CLK_GATE_WAKEUP(adbe_tuneables_info->adbe0_vblank_clk_gate_wakeup) |
adbe_tuneables_info->adbe0_vblank_clk_gate_idle);
//Set AAP
rADBE_NRT_CTL |= (adbe_tuneables_info->adbe0_aap_support) ? ADBE_NRT_CTL_AAP_ENABLE: 0;
// Dither
#ifdef WITH_HW_DITHER
uint8_t dither_type = DITHER_SPATIO_TEMPORAL;
#ifdef TARGET_DITHER_TYPE
dither_type = TARGET_DITHER_TYPE;
#endif //TARGET_DITHER_TYPE
//Dithering gets enabled in this block, no need to call into dithering to enable
//We need to enable to block to access their corresponding registers
switch(dither_type) {
case DITHER_SPATIO_TEMPORAL:
rADBE_NRT_CTL |= ADBE_NRT_CTL_ST_DITHER_ENABLE;
break;
case DITHER_BLUE_NOISE:
rADBE_NRT_CTL |= ADBE_NRT_CTL_BN_DITHER_ENABLE;
break;
case DITHER_NONE:
default:
rADBE_NRT_CTL &= ~(ADBE_NRT_CTL_ST_DITHER_ENABLE | ADBE_NRT_CTL_BN_DITHER_ENABLE);
break;
}
dither_init(timing->display_depth);
#endif
rADBE_NRT_CTL |= adbe_tuneables_info->adbe0_tunable_nrt_ctl;
//Underrun setup
rADBE_FIFO_CONFIG = ADBE_FIFO_CONFIG_UNDERRUN_MODE_STICKY | ADBE_FIFO_CONFIG_UNDERRUN_CH0(0x3FF);
}
static void adbe_enable_timing_generator_v3_video_mode(bool enable)
{
if (enable) {
rADBE_RT_CTL |= ADBE_RT_CTL_VFTG_ENABLE_VID_EN; // Enable VFTG
while ((rADBE_RT_CTL & ADBE_RT_CTL_VFTG_STATUS_EN) == 0); // Wait for it to be enabled
} else {
rADBE_RT_CTL &= ~ADBE_RT_CTL_VFTG_ENABLE_VID_EN; // Disable VFTG
while ((rADBE_RT_CTL & ADBE_RT_CTL_VFTG_STATUS_EN) == ADBE_RT_CTL_VFTG_STATUS_EN); // Wait for it to be disabled
}
}
static void adbe_enable_timing_generator_v3_command_mode(bool enable)
{
if (enable) {
rADBE_RT_CTL |= ADBE_RT_CTL_VFTG_ENABLE_CMD_EN; // Enable VFTG
while ((rADBE_RT_CTL & ADBE_RT_CTL_VFTG_STATUS_EN) == 0); // Wait for it to be enabled
} else {
rADBE_RT_CTL &= ~ADBE_RT_CTL_VFTG_ENABLE_CMD_EN; // Disable VFTG
while ((rADBE_RT_CTL & ADBE_RT_CTL_VFTG_STATUS_EN) == ADBE_RT_CTL_VFTG_STATUS_EN); // Wait for it to be disabled
}
}
void adbe_enable_timing_generator(bool enable)
{
#ifdef TARGET_DISP_VIDEO_MODE
is_video_mode = TARGET_DISP_VIDEO_MODE;
#endif //TARGET_DISP_VIDEO_MODE
if (is_video_mode) {
rADBE_RT_CTL |= (ADBE_RT_CTL_UPDATE_ENABLE_TIMING_READY | ADBE_RT_CTL_UPDATE_REQ_TIMING_NOSYNC);
adbe_enable_timing_generator_v3_video_mode(enable);
} else {
rADBE_NRT_CTL |= ADBE_NRT_CTL_TE_MODE_POS | ADBE_NRT_CTL_VFTG_MODE_COMMAND | ADBE_NRT_CTL_TE_ENABLE_SEL_SW;
rADBE_RT_CTL |= (ADBE_RT_CTL_UPDATE_ENABLE_TIMING_READY | ADBE_RT_CTL_UPDATE_REQ_TIMING_NOSYNC);
adbe_enable_timing_generator_v3_command_mode(enable);
}
}
bool adbe_get_enable_timing_generator(void)
{
#ifdef TARGET_DISP_VIDEO_MODE
is_video_mode = TARGET_DISP_VIDEO_MODE;
#endif //TARGET_DISP_VIDEO_MODE
if (is_video_mode) {
return ((rADBE_RT_CTL & ADBE_RT_CTL_VFTG_ENABLE_VID_EN) == (uint32_t)ADBE_RT_CTL_VFTG_ENABLE_VID_EN);
} else {
return ((rADBE_RT_CTL & ADBE_RT_CTL_VFTG_ENABLE_CMD_EN) == (uint32_t)ADBE_RT_CTL_VFTG_ENABLE_CMD_EN);
}
}
@@ -0,0 +1,20 @@
/*
* 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 __APPLE_DISPLAY_BACKEND_H
#define __APPLE_DISPLAY_BACKEND_H
void adbe_enable_clocks(bool enable);
void adbe_init(struct display_timing *timing);
void adbe_enable_timing_generator(bool enable);
bool adbe_get_enable_timing_generator(void);
void adbe_install_gamma_table(u_int32_t *red_lut, u_int32_t *green_lut, u_int32_t *blue_lut, struct syscfg_wpcl *wpcl);
#endif /* __APPLE_DISPLAY_BACKEND_H */
+27
View File
@@ -0,0 +1,27 @@
# Copyright (C) 2012-2014 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)
OPTIONS += \
DISPLAYPIPE_BASE_ADDR=ADBE_DISPLAYPIPE_BASE_ADDR \
WITH_DBE_ADBE=1 \
ADBE_VERSION=$(ADBE_VERSION)
ALL_OBJS += \
$(LOCAL_DIR)/adbe.o
ifeq ($(ADBE_VERSION),)
$(error "ADBE_VERSION not set")
else
ALL_OBJS += \
$(LOCAL_DIR)/adbe_v$(ADBE_VERSION).o
endif
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+325
View File
@@ -0,0 +1,325 @@
/*
* Copyright (C) 2009-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include "adfe_regs.h"
#include <debug.h>
#include <drivers/display.h>
#include <lib/env.h>
#include <lib/paint.h>
#include <platform.h>
#include <platform/chipid.h>
#include <platform/clocks.h>
#include <platform/int.h>
#include <platform/memmap.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwisr.h>
#include <sys.h>
#include <sys/task.h>
#include <drivers/adfe/adfe.h>
/* Display Tunables structures */
struct adfe_v1_tuneable {
char *name;
uint32_t disp_dpcclkcntl[2];
uint32_t disp_dpbclklvl_clock_off_level[2];
uint32_t disp_dpbclklvl_clock_on_level[2];
uint32_t disp_dpusrcstrd[2];
uint32_t disp_dpcqoscnfg[2];
uint32_t disp_dpbqoslvl_med_watermark[2];
uint32_t disp_dpbqoslvl_high_watermark[2];
uint32_t disp_dpureqcfg[2];
uint32_t disp_dpvreqcfg[2];
uint32_t disp_dpvsrcstrd[2];
uint32_t disp_dpcwbstrd[2];
};
#include <platform/soc/display.h>
#ifndef DISP_VERSION
#error DISP_VERSION undefined
#endif
static struct adfe_v1_tuneable *adfe_tuneables_info;
static const int32_t adfe_tuneables_list_size = sizeof(adfe_tuneables) / sizeof(struct adfe_v1_tuneable);
static void adfe_irq_handler(void *arg)
{
int which = (int)arg;
dprintf(DEBUG_INFO, "adfe_irq_handler: DPCIRQ(%d) is 0x%x -- attempting to clear\n", which, rDPCIRQ);
rDPCIRQ = rDPCIRQ;
}
void adfe_init(struct display_timing *timing)
{
const char *env;
int32_t cnt;
env = env_get("adfe-tunables");
if (env == 0) env = "default";
for (cnt = 0; cnt < adfe_tuneables_list_size; cnt++) {
if (strcmp(env, adfe_tuneables[cnt].name)) continue;
adfe_tuneables_info = adfe_tuneables + cnt;
}
if (adfe_tuneables_info == 0) {
dprintf(DEBUG_INFO, "Failed to find adfe tunables info, bailing adfe_init()\n");
return;
}
adfe_enable_error_handler();
#if DISP_VERSION < 5
// Turn on AutoMode
rDPCPFDMA |= DPCPFDMA_AUTOMODE;
// Set FIFO DMA Burst Size to 2 Words
rDPCPFDMA = (rDPCPFDMA & ~DPCPFDMA_BURSTSIZE_MASK) | DPCPFDMA_BURSTSIZE_2WORDS;
// Set FIFO DMA Water Mark to 0x400
rDPCPFDMA = (rDPCPFDMA & ~DPCPFDMA_WATERMARK_MASK) | DPCPFDMA_WATERMARK(0x400);
#else
// Turn on AutoMode
rDPCPFMODE = DPCPFMODE_AUTOEN;
#endif
// Set screen size
rDPCSIZE = (timing->h_active << 16) | (timing->v_active << 0);
// Set the blend layer clock gating on level based on which adfe
#ifdef DISP0_BASE_ADDR
if (DISPLAYPIPE_BASE_ADDR == DISP0_BASE_ADDR) {
rDPBCLKLVL =
adfe_tuneables_info->disp_dpbclklvl_clock_off_level[0] |
adfe_tuneables_info->disp_dpbclklvl_clock_on_level[0];
} else
#endif
#ifdef DISP1_BASE_ADDR
if (DISPLAYPIPE_BASE_ADDR == DISP1_BASE_ADDR) {
rDPBCLKLVL =
adfe_tuneables_info->disp_dpbclklvl_clock_off_level[1] |
adfe_tuneables_info->disp_dpbclklvl_clock_on_level[1];
} else
#endif
panic("adfe_init: unsupported adfe_base_addr: %p", (void *)DISPLAYPIPE_BASE_ADDR);
#if (DISP_VERSION < 3)
// Set blend layer panic level to 0x90
rDPBPANLVL = 0x90;
// Enable memory panic for blender with 5000 cycle delay
rDPCPANCNFG = DPCPANCNFG_PANENAB | DPCPANCNFG_PANBENAB | DPCPANCNFG_PANTIMER(5000);
#else
#ifdef DISP0_BASE_ADDR
if (DISPLAYPIPE_BASE_ADDR == DISP0_BASE_ADDR) {
// Set the blend QOS level
rDPBQOSLVL =
adfe_tuneables_info->disp_dpbqoslvl_med_watermark[0] |
adfe_tuneables_info->disp_dpbqoslvl_high_watermark[0];
// Enable memory panic
rDPCQOSCNFG = adfe_tuneables_info->disp_dpcqoscnfg[0];
} else
#endif
#ifdef DISP1_BASE_ADDR
if (DISPLAYPIPE_BASE_ADDR == DISP1_BASE_ADDR) {
// Set the blend QOS level
rDPBQOSLVL =
adfe_tuneables_info->disp_dpbqoslvl_med_watermark[1] |
adfe_tuneables_info->disp_dpbqoslvl_high_watermark[1];
// Enable memory panic
rDPCQOSCNFG = adfe_tuneables_info->disp_dpcqoscnfg[1];
} else
#endif
panic("adfe_init: unsupported adfe_base_addr: %p", (void *)DISPLAYPIPE_BASE_ADDR);
// Set the CSC to pass through
rDPBCSCCOEFR(0) = 0x1000;
rDPBCSCCOEFG(1) = 0x1000;
rDPBCSCCOEFB(2) = 0x1000;
#endif
#if 0
// Enable clock gating but not in U0, U1 or V
rDPCCLKCNTL = DPCCLKCNTL_GATEENAB;
#endif
#if (DISP_VERSION > 4)
uint32_t i;
#ifdef DISP0_BASE_ADDR
if (DISPLAYPIPE_BASE_ADDR == DISP0_BASE_ADDR) {
for (i = 0; i < 2; i ++) {
rDPCWBSTRD(i) = adfe_tuneables_info->disp_dpcwbstrd[0];
rDPUSRCSTRD(i) = adfe_tuneables_info->disp_dpusrcstrd[0];
rDPUREQCFG(i) = (rDPUREQCFG(i) & DPUREQCFG_CACHEHINT_MASK) | adfe_tuneables_info->disp_dpureqcfg[0];
}
for (i = 0; i < 3; i ++) {
rDPVREQCFG(i) = (rDPVREQCFG(i) & DPVREQCFG_CACHEHINT_MASK) | adfe_tuneables_info->disp_dpvreqcfg[0];
rDPVSRCSTRD(i) = adfe_tuneables_info->disp_dpvsrcstrd[0];
}
rDPCCLKCNTL = adfe_tuneables_info->disp_dpcclkcntl[0];
} else
#endif
#ifdef DISP1_BASE_ADDR
if (DISPLAYPIPE_BASE_ADDR == DISP1_BASE_ADDR) {
for (i = 0; i < 2; i ++) {
rDPCWBSTRD(i) = adfe_tuneables_info->disp_dpcwbstrd[1];
rDPUSRCSTRD(i) = adfe_tuneables_info->disp_dpusrcstrd[1];
rDPUREQCFG(i) = (rDPUREQCFG(i) & DPUREQCFG_CACHEHINT_MASK) | adfe_tuneables_info->disp_dpureqcfg[1];
}
for (i = 0; i < 3; i ++) {
rDPVREQCFG(i) = (rDPVREQCFG(i) & DPVREQCFG_CACHEHINT_MASK) | adfe_tuneables_info->disp_dpvreqcfg[1];
rDPVSRCSTRD(i) = adfe_tuneables_info->disp_dpvsrcstrd[1];
}
rDPCCLKCNTL = adfe_tuneables_info->disp_dpcclkcntl[1];
} else
#endif
panic("adfe_init: unsupported adfe_base_addr: %p", (void *)DISPLAYPIPE_BASE_ADDR);
#endif
// Set the blend pipe underrun color to red
rDPBUNDRCNFG = (2 << 30) | (0x3FF << 20);
}
void adfe_set_ui_layer(u_int32_t layer, enum colorspace color, struct plane *plane0, struct plane *plane1,
u_int32_t width, u_int32_t height)
{
uint32_t adfe_color;
addr_t base;
if (layer > 1) return;
RELEASE_ASSERT(plane0 != NULL);
base = (addr_t)(plane0->fb_virt);
switch (color) {
case CS_RGB565 :
adfe_color = 4;
break;
case CS_RGB888 :
adfe_color = 0;
break;
default:
panic("unsupported color 0x%x", color);
return;
}
// Set adfe color, no swap and linear frame buffer
rDPUSRCFMT(layer) = (adfe_color << 8) | (0 << 4) | (1 << 0);
// Set base address of this layer (lower 32 bits, in case of 64 bits address)
rDPUSRCBASE(layer) = (uint32_t)(base);
// Set stride bytes
uint32_t rmw = rDPUSRCSTRD(layer);
rmw &= ~DPUSRCSTRD_SRCSTRIDE_MASK;
rmw |= (plane0->stride & DPUSRCSTRD_SRCSTRIDE_MASK);
rDPUSRCSTRD(layer) = rmw;
#if (DISP_VERSION >= 3)
// Set the source scale region geometry
rDPUSRCXY(layer) = 0;
rDPUSRCWH(layer) = (width << 16) | (height << 0);
// Set the destination frame geometry
rDPUDSTXY(layer) = 0;
rDPUDSTWH(layer) = (width << 16) | (height << 0);
// Enable source active region 0
rDPUSRCRGN(layer) = (1 << 0);
#if (DISP_VERSION < 5)
// No MMU for UI requests
// This should not be done on DISP_VERSION >= 5, as it clears
// HighAddr.
rDPUMMUCNTL(layer) = 0;
#endif
// No scaling (init=0,0 step=1.0,1.0)
rDPUDDAINITX(layer) = 0;
rDPUDDAINITY(layer) = 0;
rDPUDDASTEPX(layer) = 0x100000;
rDPUDDASTEPY(layer) = 0x100000;
#endif
#if (DISP_VERSION > 4)
rDPUMMUCNTL(layer) = ((base >> 32) & 0xf) << 4;
#endif
// Set first region for the requested window
rDPUSRCSTRXY(layer, 0) = (0 << 16) | (0 << 0);
rDPUSRCENDXY(layer, 0) = (width << 16) | (height << 0);
// Set blend layer 1 to pass through layer 1
rDPBLAY1CNFG = (0xFF << 24) | (0xFF << 16) | (2 << 8) | (2 << 0);
#if (DISP_VERSION < 3)
// Set first region enabled
rDPUSRCRGNENAB(layer) = (1 << 0);
// Set ui layer fifo on / off levels to 0x20 / 0x60
rDPUCLKLVL(layer) = (0x20 << 16) | (0x60 << 0);
// Set ui layer panic level to 0x20
rDPUPANLVL(layer) = (0x20 << 0);
#endif
}
void adfe_enable_error_handler(void)
{
#if (DISP_VERSION < 5)
// Error handling not implemented before version 5.
#else
rDPCIRQENAB |= DPCIRQ_MSTRERR;
install_int_handler(INT_DISP0, adfe_irq_handler, 0);
unmask_int(INT_DISP0);
#endif
}
void adfe_disable_error_handler(void)
{
#if (DISP_VERSION < 5)
#else
rDPCIRQENAB &= ~DPCIRQ_MSTRERR;
mask_int(INT_DISP0);
#endif
}
void adfe_set_background_color(u_int32_t color)
{
rDPBBACKCOLOR = color;
}
void adfe_activate_window(void)
{
u_int32_t layer = 0;
if (layer > 1) return;
// Enable the requested layer
rDPCENAB |= (1 << (layer + 8));
#if (DISP_VERSION > 4)
// Enable VBI, its needed for AutoMode
rDPCENAB |= (1 << 0);
#endif
}
bool adfe_get_enable(void)
{
#if (DISP_VERSION < 5)
return (rDPCPFDMA & DPCPFDMA_AUTOMODE) != 0;
#else
return (rDPCIRQENAB & DPCIRQ_MSTRERR) != 0;
#endif
}
+172
View File
@@ -0,0 +1,172 @@
/*
* Copyright (C) 2009-2014 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 __APPLE_DISPLAYPIPE_H
#define __APPLE_DISPLAYPIPE_H
#include <platform/soc/hwregbase.h>
#define rDPCVERSION (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1018))
#define rDPCSTATE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x101C))
#define rDPCGO (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1020))
#define rDPCRESTART (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1024))
#define rDPCIRQENAB (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1028))
#define DPCIRQ_MSTRERR (1<<11)
#define rDPCIRQ (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x102C))
#define rDPCSIZE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1030))
#define rDPCFRMCNT (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1034))
#define rDPCENAB (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1038))
#if DISP_VERSION < 5
#define rDPCPFTOP (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x103C))
#endif
#define rDPCPFSIZE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1040))
#define rDPCPFSTAT (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1044))
#define rDPCPFHEAD (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1048))
#if DISP_VERSION < 5
#define rDPCPFDMA (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x104C))
#define DPCPFDMA_AUTOMODE (1 << 4)
#define DPCPFDMA_BURSTSIZE_1WORD (0 << 8)
#define DPCPFDMA_BURSTSIZE_2WORDS (1 << 8)
#define DPCPFDMA_BURSTSIZE_4WORDS (2 << 8)
#define DPCPFDMA_BURSTSIZE_8WORDS (3 << 8)
#define DPCPFDMA_BURSTSIZE_16WORDS (4 << 8)
#define DPCPFDMA_BURSTSIZE_MASK (7 << 8)
#define DPCPFDMA_WATERMARK(n) ((n) << 16)
#define DPCPFDMA_WATERMARK_MASK (0x7FF << 16)
#else
#define rDPCPFMODE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x104C))
#define DPCPFMODE_WBEN (1 << 1)
#define DPCPFMODE_AUTOEN (1 << 0)
#endif
#define rDPCPFFLUSH (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1050))
#define rDPCCLKCNTL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1054))
#define DPCCLKCNTL_FLOOR(n) ((n & 0xFFFF) << 16)
#define DPCCLKCNTL_PIPE_ENABLE (1 << 12)
#define DPCCLKCNTL_LB_ENABLE (1 << 8)
#define DPCCLKCNTL_V_ENABLE (1 << 4)
#define DPCCLKCNTL_GATEENAB (1 << 0)
#define rDPCMEMACC (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1058))
#if (DISP_VERSION < 3)
#define rDPCPANCNFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x105C))
#define DPCPANCNFG_PANENAB (1 << 0)
#define DPCPANCNFG_PANU0ENAB (1 << 8)
#define DPCPANCNFG_PANU1ENAB (1 << 9)
#define DPCPANCNFG_PANVENAB (1 << 10)
#define DPCPANCNFG_PANBENAB (1 << 11)
#define DPCPANCNFG_PANTIMER(n) ((n) << 16)
#define DPCPANCNFG_PANTIMER_MASK (0xFFFF << 16)
#else
#define rDPCQOSCNFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x105C))
#define DPCQOSCNFG_QOS_ENABLE (1 << 0)
#define DPCQOSCNFG_UIFIFO_ENABLE (1 << 1)
#define DPCQOSCNFG_VIDFIFO_ENABLE (1 << 2)
#if (DISP_VERSION < 4)
#define DPCQOSCNFG_QOS_OPTIMISTIC (1 << 3)
#else
#define DPCQOSCNFG_QOS_OPTIMISTIC (1 << 4)
#endif
#define DPCQOSCNFG_PIPE_ENABLE (1 << 8)
#define DPCQOSCNFG_QOS_TIMER(n) ((n) << 16)
#endif
#if (DISP_VERSION > 4)
#define rDPCWBSTRD(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x4 * (n)) + 0x1068))
#define DPCWBSTRD_DSTBURST_1BLOCK (0 << 0)
#define DPCWBSTRD_DSTBURST_2BLOCKS (1 << 0)
#define DPCWBSTRD_DSTBURST_4BLOCKS (2 << 0)
#define DPCWBSTRD_DSTBURST_8BLOCKS (3 << 0)
#define DPCWBSTRD_DSTBURST_MASK (3 << 0)
#define DPCWBSTRD_DSTSTRIDE_MASK (~0x3F)
#endif
#define rDPBBACKCOLOR (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x203C))
#define rDPBLAY1CNFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2040))
#define rDPBLAY2CNFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2044))
#define rDPBLAY3CNFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2048))
#define rDPBCRCENAB (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x204C))
#define rDPBCRCDATA (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2050))
#define rDPBCRCSNAP (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2054))
#define rDPBOUTSIZE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2058))
#define rDPBCLKLVL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x205C))
#define DPBCLKLVL_OFFLVL(n) ((n) << 0)
#define DPBCLKLVL_ONLVL(n) ((n) << 16)
#define rDPBUNDRCNFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2064))
#if (DISP_VERSION < 3)
#define rDPBPANLVL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2060))
#else
#define rDPBQOSLVL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2060))
#define DPBQOSLVL_MED_WATERMARK(n) ((n) << 0)
#define DPBQOSLVL_HIGH_WATERMARK(n) ((n) << 16)
#define rDPBCSCCOEFR(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x4 * (n)) + 0x2068))
#define rDPBCSCCOEFG(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x4 * (n)) + 0x2074))
#define rDPBCSCCOEFB(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x4 * (n)) + 0x2080))
#define rDPBCSCCOFFR (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x208C))
#define rDPBCSCCOFFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2090))
#define rDPBCSCCOFFB (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2094))
#endif
#if (DISP_VERSION > 4)
#define rDPVREQCFG(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x4 * (n)) + 0x3050))
#define DPVREQCFG_REQ_CNT(_n) ((_n) & 0xFF)
#define DPVREQCFG_CACHEHINT_MASK (7 << 8)
#endif
#define rDPVSRCSTRD(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x4 * (n)) + 0x3088))
#define DPVSRCSTRD_SRCBURST_1BLOCK (0 << 0)
#define DPVSRCSTRD_SRCBURST_2BLOCKS (1 << 0)
#define DPVSRCSTRD_SRCBURST_4BLOCKS (2 << 0)
#define DPVSRCSTRD_SRCBURST_8BLOCKS (3 << 0)
#define DPVSRCSTRD_SRCBURST_MASK (3 << 0)
#define DPVSRCSTRD_SRCSTRIDE_MASK (~0x3F)
#if (DISP_VERSION > 4)
#define rDPUREQCFG(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x403C))
#define DPUREQCFG_REQ_CNT(_n) ((_n) & 0xFF)
#define DPUREQCFG_CACHEHINT_MASK (7 << 8)
#endif
#define rDPUSRCFMT(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4040))
#define rDPUSRCBASE(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4044))
#define rDPUSRCSTRD(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4048))
#define DPUSRCSTRD_SRCBURST_1BLOCK (0 << 0)
#define DPUSRCSTRD_SRCBURST_2BLOCKS (1 << 0)
#define DPUSRCSTRD_SRCBURST_4BLOCKS (2 << 0)
#define DPUSRCSTRD_SRCBURST_8BLOCKS (3 << 0)
#define DPUSRCSTRD_SRCBURST_MASK (3 << 0)
#define DPUSRCSTRD_SRCSTRIDE_MASK (~0x3F)
#if (DISP_VERSION < 3)
#define rDPUSRCRGNENAB(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x404C))
#define rDPUOUTSIZE(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4070))
#define rDPUCLKLVL(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4074))
#define rDPUPANLVL(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4078))
#define rDPUSRCSTRXY(n, r) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4050 + (4 * (r))))
#define rDPUSRCENDXY(n, r) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4060 + (4 * (r))))
#else
#define rDPUSRCXY(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x404C))
#define rDPUSRCWH(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4050))
#define rDPUDSTXY(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4054))
#define rDPUDSTWH(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4058))
#define rDPUSRCRGN(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x405C))
#define rDPUSRCSTRXY(n, r) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4060 + (4 * (r))))
#define rDPUSRCENDXY(n, r) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4070 + (4 * (r))))
#define rDPUDDAINITX(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4080))
#define rDPUDDAINITY(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4084))
#define rDPUDDASTEPX(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4088))
#define rDPUDDASTEPY(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x408C))
#define rDPUMMUCNTL(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + (0x1000 * (n)) + 0x4090))
#endif
#define rDPCPERFCNTL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x6008))
#define rDPCPERFSTAT (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x600C))
#define rDPCPERFCNFG(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x6010 + (4 * (n))))
#define rDPCPERFDATA(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x6020 + (4 * (n))))
#define rDPCPERFSNAP(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x6030 + (4 * (n))))
#endif /* ! __APPLE_DISPLAYPIPE_H */
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __APPLE_DISPLAY_FRONTEND_H
#define __APPLE_DISPLAY_FRONTEND_H
void adfe_init(struct display_timing *timing);
void adfe_set_ui_layer(u_int32_t pixel_pipe, enum colorspace color, struct plane *plane0, struct plane *plane1, u_int32_t width, u_int32_t height);
void adfe_enable_error_handler(void);
void adfe_disable_error_handler(void);
void adfe_set_background_color(u_int32_t color);
void adfe_activate_window(void);
bool adfe_get_enable(void);
#endif /* __APPLE_DISPLAY_FRONTEND_H */
+18
View File
@@ -0,0 +1,18 @@
# Copyright (C) 2009-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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_DFE_ADFE=1
ALL_OBJS += \
$(LOCAL_DIR)/adfe.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+407
View File
@@ -0,0 +1,407 @@
/*
* Copyright (C) 2014-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include "adfe_v2_regs.h"
#include <debug.h>
#include <drivers/display.h>
#include <lib/env.h>
#include <lib/paint.h>
#include <platform.h>
#include <platform/chipid.h>
#include <platform/clocks.h>
#include <platform/int.h>
#include <platform/memmap.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwisr.h>
#include <sys.h>
#include <sys/task.h>
#include <drivers/adfe_v2/adfe.h>
#if TARGET_USES_GP_CM || TARGET_USES_BLEND_CM
#include <target/display_gamma_tables.h>
#endif //TARGET_USES_GP_CM || TARGET_USES_BLEND_CM
#if WITH_SYSCFG
#include <lib/syscfg.h>
#endif
#if WITH_DEVICETREE
#include <lib/devicetree.h>
#endif
struct adfe_v2_tuneable {
char *name;
uint32_t disp_dpcclkcntl;
uint32_t disp_dpcclklvl_clock_on_level;
uint32_t disp_dpcclklvl_clock_off_level;
uint32_t disp_dpcqoscfg;
uint32_t disp_dpcqosylvl_yellow_off;
uint32_t disp_dpcqosylvl_yellow_on;
uint32_t disp_dpcqosrlvl_red_off;
uint32_t disp_dpcqosrlvl_red_on;
uint32_t disp_dpclinkdown;
uint32_t disp_dpgpreqaggr;
uint32_t disp_dpcafclkgate; //ADP_VERSION > 1
uint32_t disp_dpcenab;
};
#include <platform/soc/display.h>
#ifndef ADP_VERSION
#error ADP_VERSION undefined
#endif
static void adfe_set_pixel_pipe_plane(u_int32_t pixel_pipe, u_int32_t plane_num, struct plane *plane);
static void adfe_gp_gamut_adjustment(u_int32_t pixel_pipe);
static void adfe_blend_gamut_adjustment(void);
static uint8_t display_pipe;
static uint8_t gen_pixel_pipe = 0;
static struct adfe_v2_tuneable *adfe_tuneables_info;
static const int32_t adfe_tuneables_list_size = sizeof(adfe_tuneables) / sizeof(struct adfe_v2_tuneable);
static void adfe_irq_handler(void *arg)
{
int which = (int)arg;
dprintf(DEBUG_INFO, "adfe_irq_handler: ADPCIRQ(%d) is 0x%x -- attempting to clear\n", which, rADPCIRQ);
rADPCIRQ = rADPCIRQ;
}
void adfe_init(struct display_timing *timing)
{
const char *env;
int32_t cnt;
env = env_get("adfe-tunables");
if (env == 0) env = "default";
for (cnt = 0; cnt < adfe_tuneables_list_size; cnt++) {
if (strcmp(env, adfe_tuneables[cnt].name)) continue;
adfe_tuneables_info = adfe_tuneables + cnt;
}
if (adfe_tuneables_info == 0) {
panic("Failed to find adfe tunables info, bailing adfe_init()\n");
}
display_pipe = 0;
gen_pixel_pipe = 0;
#ifdef DISP1_BASE_ADDR
if (DISPLAYPIPE_BASE_ADDR == DISP1_BASE_ADDR) {
display_pipe = 1;
gen_pixel_pipe = 0;
}
#endif //DISP1_BASE_ADDR
adfe_enable_error_handler();
// Turn on AutoMode
rADPCPFMODE = ADPCPFMODE_AUTOEN | ADPCPFMODE_VBIEN;
// Set screen size
rADPCFRAMESIZE = (timing->h_active << 16) | (timing->v_active << 0);
// Set the pipes clock gating on level (generic to both pipes)
rADPCCLKLVL = adfe_tuneables_info->disp_dpcclklvl_clock_off_level |
adfe_tuneables_info->disp_dpcclklvl_clock_on_level;
// Set the Memory QOS configuration
rADPCQOSCFG = adfe_tuneables_info->disp_dpcqoscfg;
//set output FIFO QOS Yellow level
rADPCQOSYLVL = adfe_tuneables_info->disp_dpcqosylvl_yellow_on |
adfe_tuneables_info->disp_dpcqosylvl_yellow_off;
//set output FIFO QOS Red level
rADPCQOSRLVL = adfe_tuneables_info->disp_dpcqosrlvl_red_on |
adfe_tuneables_info->disp_dpcqosrlvl_red_off;
rADPCCLKCNTL = adfe_tuneables_info->disp_dpcclkcntl;
rADPCLINKDOWN = adfe_tuneables_info->disp_dpclinkdown;
// Register added in Capri..
#if ADP_VERSION > 1
rADPCAFCLKGATE = adfe_tuneables_info->disp_dpcafclkgate;
#endif
// Disable CSC
rADPCCRCCTRL = 0;
}
void adfe_set_axis_flip(uint32_t pixel_pipe, bool flipX, bool flipY)
{
rADPGPSRCFMT(pixel_pipe) |= ((!!flipX) << 2) | ((!!flipY) << 1);
}
// Algorithm provided by display team to do fixed point rounding.
static uint64_t fixed_to_fixed( uint64_t in, int inprec, int outprec )
{
long long sval = *((long long *) &in);
bool neg = sval < 0;
if( neg ) sval = -sval;
if( outprec < inprec ) {
sval = ((sval >> (inprec - outprec - 1)) + 1) >> 1;
} else {
sval <<= outprec - inprec;
}
if( neg ) sval = -sval;
return *((uint64_t *) &sval);
}
/*
* The ADP has 2 Generic Pixel Pipes. These pipes process pixels from memory before entering the Blend Unit.
* A Plane is a single contigous location in memory containing pixel information
* No scaling of any component is required (i.e. DDAInitX/DDAInitY are equal to SrcX/SrcY, and all DDA steps are equal to 1).
* The Scale Region is equal to the Destination Region.
* All pixels in the scale region are also in an Active Region (ARGB formats only).
* 2DSN is disabled (YCbCr 4:4:4 formats only).
*/
void adfe_set_ui_layer(u_int32_t pixel_pipe, enum colorspace color, struct plane *plane0, struct plane *plane1,
u_int32_t width, u_int32_t height)
{
uint8_t num_planes;
uint8_t pixel_size, pixel_fmt;
uint8_t is_ARGB;
uint32_t reg = 0;
if (pixel_pipe > 1) return;
switch(color) {
case CS_RGB565 :
is_ARGB = true;
pixel_size = 2;
pixel_fmt = 2;
num_planes = 1;
break;
case CS_RGB888 :
is_ARGB = true;
pixel_size = 1;
pixel_fmt = 1;
num_planes = 1;
break;
case CS_ARGB8101010 :
is_ARGB = true;
pixel_size = 3;
pixel_fmt = 0;
num_planes = 2;
break;
default:
return;
}
RELEASE_ASSERT(plane0 != NULL);
if (num_planes > 1) RELEASE_ASSERT(plane1 != NULL);
#if defined(__arm64__)
rADPSMMU_BYPASS_ADDR = (((((addr_t)plane0->fb_virt) >> 32) & 0xF) << 8);
#endif
rADPSMMU_DIAG_BOGUS_ACCESS = 0x20ffff;
rADPDART_DIAG_CONFIG = 0x100;
rADPDART_DIAG_BOGUS_ACCESS = 0x20ffff;
rADPDART_FETCH_REQ_CONFIG = 0xe0303;
// Set displaypixel_pipe color, no swap and linear frame buffer
reg = rADPGPSRCFMT(pixel_pipe);
//clean up the fields we are about to set
reg &= ~((0x3 << 26) | (0x3 << 24) | (1 << 22) | (1 << 21) | (1 << 20) | (0x1f << 4) | (1 << 0));
reg |= (pixel_fmt << 26) | (pixel_size << 24) | ((num_planes - 1 ) << 22) | (is_ARGB << 21) | (0 << 4) | (1 << 0);
rADPGPSRCFMT(pixel_pipe) = reg;
adfe_set_pixel_pipe_plane(pixel_pipe, 0, plane0);
if (num_planes > 1) {
adfe_set_pixel_pipe_plane(pixel_pipe, 1, plane1);
}
// Enable source active region 0
rADPGPSRCCFG(pixel_pipe) = (1 << 0);
// Set the destination frame geometry
rADPGPDSTXY(pixel_pipe) = 0;
rADPGPDSTWH(pixel_pipe) = (width << 16) | (height << 0);
//No Scale Mode
rADPGPCFG(pixel_pipe) = ADPGPCFG_NO_SCALE;
//Dithering off
rADPGPNOISECFG(pixel_pipe) = 0;
//No color Space Conversion
rADPGPCSCCFG(pixel_pipe)= ADPGPCSCCFG_CSC_BYPASS;
// No Color Management
rADPGPCMCFG(pixel_pipe)= ADPGPCMCFG_CM_BYPASS;
//Bypass Color space conversion
rADPBCSCCFG = ADPBCSCCFG_CSCBYPASS;
adfe_gp_gamut_adjustment(pixel_pipe);
// Bypass Blend Color Management
rADPBCMCFG = ADPBCMCFG_CMBYPASS;
//Tunable
rADPGPREQAGGR(pixel_pipe, 0) = adfe_tuneables_info->disp_dpgpreqaggr;
rADPGPREQAGGR(pixel_pipe, 1) = adfe_tuneables_info->disp_dpgpreqaggr;
//No Need for Blend
#define BLEND_BYPASS 1
#if BLEND_BYPASS
rADPBCFG = ADPBCFG_BLEND_BYPASS;
#endif //BLEND_BYPASS
rADPBLAYCFG(pixel_pipe) = (1 << 4) | (pixel_pipe << 0);
rADPBLAYCFG(1-pixel_pipe) = (0 << 4) | ((1-pixel_pipe) << 0);
//rADPBBACKCOLOR = 0xf;
adfe_blend_gamut_adjustment();
}
static void adfe_set_pixel_pipe_plane(u_int32_t pixel_pipe, u_int32_t plane_num, struct plane *plane)
{
// Set base address of this pixel_pipe (lower 32 bits, in case of 64 bits address)
rADPGPSRCBASE(pixel_pipe, plane_num) = (uint32_t)plane->fb_virt;
// Set burst size and stride bytes
rADPGPSRCSTRD(pixel_pipe, plane_num) = plane->stride;
// Set the source scale region geometry
rADPGPSRCXY(pixel_pipe, plane_num) = 0;
rADPGPSRCWH(pixel_pipe, plane_num) = (plane->width << 16) | (plane->height << 0);
//Note that if the pipe is being used in No Scale or Scaler Bypass mode DdaInitX must equal SrcX
rADPGPDDAINITX(pixel_pipe, plane_num) = 0;
rADPGPDDASTEPX(pixel_pipe, plane_num) = 0x100000;
//Note that if the pipe is being used in No Scale or Scaler Bypass mode DdaInitY must equal SrcY
rADPGPDDAINITY(pixel_pipe, plane_num) = 0;
rADPGPDDASTEPY(pixel_pipe, plane_num) = 0x100000;
// Set first region for the requested window
rADPGPSRCACTXY(pixel_pipe, plane_num) = (0 << 16) | (0 << 0);
rADPGPSRCACTWH(pixel_pipe, plane_num) = (plane->width << 16) | (plane->height << 0);
}
void adfe_enable_error_handler(void)
{
rADPCIRQENAB |= ADPCIRQ_OUTUNDERIRQ;
install_int_handler(INT_DISP0, adfe_irq_handler, 0);
unmask_int(INT_DISP0);
}
void adfe_disable_error_handler(void)
{
rADPCIRQENAB &= ~ADPCIRQ_OUTUNDERIRQ;
mask_int(INT_DISP0);
}
void adfe_set_background_color(u_int32_t color)
{
rADPBBACKCOLOR = color;
}
void adfe_activate_window(void)
{
if (gen_pixel_pipe > 1) return;
//Set SID to bypass due to
//<rdar://problem/13098516> SMMU Configuration Timing
// Enable the requested generic pixel pipe
rADPCENAB = adfe_tuneables_info->disp_dpcenab | ADPCENAB_SIDSEL_BYPASS | (1 << (gen_pixel_pipe * 4));
}
bool adfe_get_enable(void)
{
return (rADPCIRQENAB & ADPCIRQ_OUTUNDERIRQ) != 0;
}
static void adfe_blend_gamut_adjustment(void)
{
#if TARGET_USES_BLEND_CM
#if WITH_SYSCFG
struct primary_calibration_matrix {
uint32_t version;
uint32_t matrix[3][3];
};
struct primary_calibration_matrix pcm;
if (syscfgCopyDataForTag('DPCl', (u_int8_t *)&pcm, sizeof(pcm)) > 0) {
int row, col;
//Program degamma LUT
for (row = 0; row < ADP_CM_DEGAMMA_PAIRED_LUT_SIZE; row++) {
rADPBDEGAMMATABLE(row) = target_blend_degamma_tables[row];
}
//Program Linear Degamma
rADPBDEGAMMALINEAR = target_blend_degamma_tables[row];
for(row = 0; row < 3; row ++) {
for(col = 0; col < 3; col++) {
// Convert from 8.24 to 4.12
rADPBCMCOEF(row, col) = (uint32_t)(fixed_to_fixed( pcm.matrix[row][col], 24, 12 ) & 0xFFFF);
}
}
for (row = 0; row < ADP_CM_ENGAMMA_PAIRED_LUT_SIZE; row++) {
rADPBGAMMATABLE_R(row) = target_blend_engamma_tables[row];
rADPBGAMMATABLE_G(row) = target_blend_engamma_tables[row];
rADPBGAMMATABLE_B(row) = target_blend_engamma_tables[row];
}
rADPBGAMMALINEAR_R = target_blend_engamma_tables[row];
rADPBGAMMALINEAR_G = target_blend_engamma_tables[row];
rADPBGAMMALINEAR_B = target_blend_engamma_tables[row];
// Turn off Blend Color Management Bypass
rADPBCMCFG &= ~ADPBCMCFG_CMBYPASS;
}
#endif
#endif
}
static void adfe_gp_gamut_adjustment(u_int32_t pixel_pipe)
{
#if TARGET_USES_GP_CM
int col;
int row;
//Program degamma LUT
for (row = 0; row < ADP_CM_DEGAMMA_PAIRED_LUT_SIZE; row++) {
rADPGPDEGAMMATABLE(pixel_pipe, row) = target_gp_degamma_tables[row];
}
//Program Linear Degamma
rADPGPDEGAMMALINEAR(pixel_pipe) = target_gp_degamma_tables[row];
for(row = 0; row < 3; row ++ ) {
for(col = 0; col < 3; col ++ ) {
rADPGPCMCOEF(pixel_pipe, row, col) = target_gp_csc_matrix[row][col];
}
}
for (row = 0; row < ADP_CM_ENGAMMA_PAIRED_LUT_SIZE; row++) {
rADPGPGAMMATABLE(pixel_pipe, row) = target_gp_engamma_tables[row];
}
rADPGPGAMMALINEAR(pixel_pipe) = target_gp_engamma_tables[row];
//Unbypass the gamut adjustment block
rADPGPCMCFG(pixel_pipe) &= ~ADPGPCMCFG_CM_BYPASS;
#endif //TARGET_USES_GP_CM
}
+206
View File
@@ -0,0 +1,206 @@
/*
* Copyright (C) 2013-2014 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 __APPLE_DISPLAY_FRONTEND_REGS_H
#define __APPLE_DISPLAY_FRONTEND_REGS_H
#include <platform/soc/hwregbase.h>
//General control registers
#define rADPCSPARE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1000))
#define rADPCVERSION (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1018))
#define rADPCSTATE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x101c))
#define rADPCGO (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1020))
#define rADPCRESTART (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1024))
#define rADPCIRQENAB (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1028))
#define ADPCIRQ_WBPARTIRQ (1 << 14)
#define ADPCIRQ_WBCMPLIRQ (1 << 13)
#define ADPCIRQ_WRERRIRQ (1 << 12)
#define ADPCIRQ_RDERRIRQ (1 << 1)
#define ADPCIRQ_PFPROCIRQ (1 << 10)
#define ADPCIRQ_PFOVERIRQ (1 << 9)
#define ADPCIRQ_PFHDRIRQ (1 << 8)
#define ADPCIRQ_PFEMPTYIRQ (1 << 7)
#define ADPCIRQ_PFALIGNIRQ (1 << 6)
#define ADPCIRQ_PFREPEATIRQ (1 << 5)
#define ADPCIRQ_PFSYNCIRQ (1 << 4)
#define ADPCIRQ_PFMISSIRQ (1 << 3)
#define ADPCIRQ_PFUNDERIRQ (1 << 2)
#define ADPCIRQ_OUTUNDERIRQ (1 << 1)
#define ADPCIRQ_VBIIRQ (1 << 0)
#define rADPCIRQ (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x102c))
#define rADPCFRAMESIZE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1030))
#define rADPCFRMCNT (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1034))
#define rADPCENAB (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1038))
#define ADPCENAB_IDEAL_ARB_ENAB (1 << 16)
#define ADPCENAB_SIDSEL_BYPASS (1 << 12)
#define rADPCPFSIZE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x103c))
#define rADPCPFSTAT (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1040))
#define rADPCPFHEAD (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1044))
#define rADPCPFMODE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1048))
#define ADPCPFMODE_AUTOEN (1 << 0)
#define ADPCPFMODE_VBIEN (1 << 4)
#define rADPCPFFLUSH (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x104c))
#define rADPCCLKCNTL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1050))
#define ADPCCLKCNTL_FLOOR(n) ((n) << 16)
#define ADPCCLKCNTL_PIPE_ENABLE (1 << 8)
#define ADPCCLKCNTL_LB_ENABLE (1 << 4)
#define ADPCCLKCNTL_PIO_GATE_ENABLE (1 << 3)
#define ADPCCLKCNTL_STAT_GATE_ENABLE (1 << 2)
#define ADPCCLKCNTL_EXT_GATE_ENABLE (1 << 1)
#define ADPCCLKCNTL_DYN_GATE_ENABLE (1 << 0)
#define rADPCCLKLVL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1054))
#define ADPCCLKLVL_ONLVL(n) ((n) << 16)
#define ADPCCLKLVL_OFFLVL(n) ((n) << 0)
#define rADPCQOSCFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1058))
#define ADPCQOSCFG_QOS_TIMER(n) ((n) << 16)
#define ADPCQOSCFG_PIPE_ENABLE (1 << 8)
#define ADPCQOSCFG_MINLVL_ENABLE (1 << 6)
#define ADPCQOSCFG_MON_MODE (1 << 5)
#define ADPCQOSCFG_MON_ENABLE (1 << 4)
#define ADPCQOSCFG_QOS_ENABLE (1 << 0)
#define rADPCQOSYLVL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x105c))
#define ADPCQOSYLVL_YELLOW_OFF(n) ((n) << 16)
#define ADPCQOSYLVL_YELLOW_ON(n) ((n) << 0)
#define rADPCQOSRLVL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1060))
#define ADPCQOSRLVL_RED_OFF(n) ((n) << 16)
#define ADPCQOSRLVL_RED_ON(n) ((n) << 0)
#define rADPCQOSGSNAP (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1064))
#define rADPCQOSYSNAP (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1068))
#define rADPCQOSRSNAP (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x106c))
#define rADPCQOSMINLVLSNAP (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1070))
#define rADPCCRCCTRL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1074))
#define rADPCLINKDOWN (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1078))
#define ADPCLINKDOWN_TEARDOWNNOSCL (1 << 8)
#define ADPCLINKDOWN_TEARDOWNAGGR (1 << 4)
#define ADPCLINKDOWN_TEARDOWNEN (1 << 0)
#if ADP_VERSION > 1
#define rADPCAFCLKGATE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x107C))
#define ADPAFIDLECOUNT(n) ((n) << 16)
#define ADPAFDYNCLKGATEEN (1 << 0)
#endif
#define rADPCPFTOP(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x10c0 + (4 * (n))))
//Blend Unit registers
#define rADPBSPARE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2000))
#define rADPBCFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2020))
#define ADPBCFG_BLEND_BYPASS (1 << 0)
#define rADPBBACKCOLOR (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2024))
#define rADPBLAYCFG(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2028 + (4 * (n))))
#define rADPBCRCDATA (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2030))
#define rADPBCSCCFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2034))
#define ADPBCSCCFG_CSCBYPASS (1 << 0)
#define rADPBCSCINOFF(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2038 + (4 * (n))))
#define rADPBCSCCOEF(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2044 + (12 * (p)) + (4 * (n))))
#define rADPBCSCOUTOFF(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2068 + (4 * (n))))
#define rADPBCMCFG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2074))
#define ADPBCMCFG_CMBYPASS (1 << 0)
#define rADPBDEGAMMALINEAR (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2078))
#define rADPBCMCOEF(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x207c + (12 * (p)) + (4 * (n))))
#define rADPBGAMMALINEAR (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x20a0))
#define rADPBGAMMALINEAR_R (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x20a0))
#define rADPBGAMMALINEAR_G (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x20a4))
#define rADPBGAMMALINEAR_B (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x20a8))
#define rADPBOUTFIFODEPTH (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x20ac))
#define rADPBDEGAMMATABLE(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2200 + (4 * (n))))
#define rADPBGAMMATABLE(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2800 + (4 * (n))))
#define rADPBGAMMATABLE_R(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x2800 + (4 * (n))))
#define rADPBGAMMATABLE_G(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x3000 + (4 * (n))))
#define rADPBGAMMATABLE_B(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x3800 + (4 * (n))))
//Generic Pipe registers
#define rADPGPSPARE(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4000 + ((p) * 0x2000)))
#define rADPGPCFG(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4020 + ((p) * 0x2000)))
#define ADPGPCFG_SCALE_BYPASS (1 << 4)
#define ADPGPCFG_NO_SCALE (1 << 0)
#define rADPGPREQAGGR(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4024 + ((p) * 0x2000) + (4 * (n))))
#define ADPGPREQARRG_CACHEHINT_MASK (0x0F0000)
#define ADPGPREQAGGR_CACHEHINT(n) ((n) << 16)
#define ADPGPREQAGGR_REQAGGRTHRESH(n) ((n) << 4)
#define ADPGPREQARRG_OPPORTUNISMENAB (1 << 1)
#define ADPGPREQAGGR_REQAGGRENAB (1 << 0)
#define rADPGPSRCFMT(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x402c + ((p) * 0x2000)))
#define rADPGPSRCBASE(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4030 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPSRCSTRD(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4038 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPSRCXY(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4040 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPSRCWH(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4048 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPDSTXY(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4050 + ((p) * 0x2000)))
#define rADPGPDSTWH(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4054 + ((p) * 0x2000)))
#define rADPGPTBEDGEALPHA(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4058 + ((p) * 0x2000)))
#define rADPGPLREDGEALPHA(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x405c + ((p) * 0x2000)))
#define rADPGPTCEDGEALPHA(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4060 + ((p) * 0x2000)))
#define rADPGPBCEDGEALPHA(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4064 + ((p) * 0x2000)))
#define rADPGPSRCCFG(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4068 + ((p) * 0x2000)))
#define rADPGPSRCACTXY(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x406c + ((p) * 0x2000) + (4 * (n))))
#define rADPGPSRCACTWH(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x407c + ((p) * 0x2000) + (4 * (n))))
#define rADPGPNOISECFG(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x408c + ((p) * 0x2000)))
#define rADPGPNOISELFSR(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4090 + ((p) * 0x2000)))
#define rADPGPDDAINITX(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4094 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPDDASTEPX(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x409c + ((p) * 0x2000) + (4 * (n))))
#define rADPGPDDAINITY(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40a4 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPDDASTEPY(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40ac + ((p) * 0x2000) + (4 * (n))))
#define rADPGPCSCCFG(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40b4 + ((p) * 0x2000)))
#define ADPGPCSCCFG_CSC_BYPASS (1 << 0)
#define rADPGPCSCINOFF(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40b8 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPCSCCOEF(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40c4 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPCSCOUTOFF(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40e8 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPCMCFG(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40f4 + ((p) * 0x2000)))
#define ADPGPCMCFG_CM_BYPASS (1 << 0)
#define rADPGPDEGAMMALINEAR(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40f8 + ((p) * 0x2000)))
#define rADPGPCMCOEF(p, r, c) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x40fc + ((p) * 0x2000) + ((r) * 0xc) + (4 * (c))))
#define rADPGPGAMMALINEAR(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4120 + ((p) * 0x2000)))
#define rADPGPCRCCTRL(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4124 + ((p) * 0x2000)))
#define rADPGPCRCDATA(p) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4128 + ((p) * 0x2000)))
#define rADPGPINVDDASTEPX(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x412c + ((p) * 0x2000) + (4 * (n))))
#define rADPGPDEGAMMATABLE(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4200 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPGAMMATABLE(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x4800 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPCOEFX(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x5000 + ((p) * 0x2000) + (4 * (n))))
#define rADPGPCOEFY(p, n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x5800 + ((p) * 0x2000) + (4 * (n))))
//DP Noise RAM Registers
#define rADPNOISEARRAY(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x8000 + (4 * (n)))
//DP Write Back Registers
#define rADPWBSPARE (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9000))
#define rADPWBBASE(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9020 + (4 * (n))))
#define rADPWBSTRD(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9028 + (4 * (n))))
#define rADPWBCNTL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9030))
#define rADPWBCHROMADOWN (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9034))
#define rADPWBLINECNT(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9038 + (4 * (n))))
#define rADP_DITHER_SKEW0 (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9040))
#define rADP_DITHER_SKEW1 (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9044))
#define rADP_DITHER_SKEW2 (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x9048))
#define rADP_DITHER_KERNEL (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x904c))
//SMMU Registers
#define rADPSMMU_CONFIG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x10000c))
#define rADPSMMU_ERR_STATUS (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x100010))
#define rADPSMMU_ERR_AXI_REQ0 (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x100014))
#define rADPSMMU_ERR_AXI_REQ1 (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x100018))
#define rADPSMMU_ERR_ADDRESS (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x10001c))
#define rADPSMMU_DIAG_CONFIG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x100020))
#define rADPSMMU_DIAG_BOGUS_ACCESS (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x100024))
#define rADPSMMU_BYPASS_ADDR (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x10002c))
#define rADPSMMU_ERR_STTIDX (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x100030))
#define rADPSMMU_REQ_SCOREBOARD(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x100080 + ((n) * 4))
#define rADPSMMU_ACK_SCOREBOARD(n) (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x1000c0 + ((n) * 4))
#define rADPSMMU_PERF_CONFIG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x101000))
#define rADPSMMU_CTR (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x101004))
#define rADPSMMU_STT_PA_DATA (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x102000))
//DART Registers
#define rADPDART_DIAG_CONFIG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x104020))
#define rADPDART_DIAG_BOGUS_ACCESS (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x104024))
#define rADPDART_FETCH_REQ_CONFIG (*(volatile u_int32_t *)(DISPLAYPIPE_BASE_ADDR + 0x104030))
#endif /* ! __APPLE_DISPLAY_FRONTEND_REGS_H */
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __APPLE_DISPLAY_FRONTEND_H
#define __APPLE_DISPLAY_FRONTEND_H
void adfe_init(struct display_timing *timing);
void adfe_set_ui_layer(u_int32_t pixel_pipe, enum colorspace color, struct plane *plane0, struct plane *plane1, u_int32_t width, u_int32_t height);
void adfe_enable_error_handler(void);
void adfe_disable_error_handler(void);
void adfe_set_background_color(u_int32_t color);
void adfe_activate_window(void);
bool adfe_get_enable(void);
void adfe_set_axis_flip(uint32_t pixel_pipe, bool flipX, bool flipY);
#endif /* __APPLE_DISPLAY_FRONTEND_H */
+18
View File
@@ -0,0 +1,18 @@
# Copyright (C) 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_DFE_ADFE_V2=1
ALL_OBJS += \
$(LOCAL_DIR)/adfe_v2.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+225
View File
@@ -0,0 +1,225 @@
/*
* 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 <drivers/aes.h>
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include "aes_ap.h"
void _load_input_block(const uint32_t *src);
void _store_output_block(uint32_t *dst);
#if AES_AP_VERSION < 1
void
aes_ap_disable_keys(uint32_t gid, uint32_t uid)
{
uint32_t keydis = (((gid & AES_DIS_GID_MASK) << AES_DIS_SET_GID_SHIFT) | ((uid & AES_DIS_UID_MASK) << AES_DIS_SET_UID_SHIFT));
dprintf(DEBUG_SPEW, "gid:0x%08x uid:0x%08x\n", gid, uid);
if (!gid && !uid) return;
clock_gate(CLK_AES0, true);
rAES_AP_DIS = keydis;
clock_gate(CLK_AES0, false);
}
bool
aes_ap_keys_disabled(uint32_t gid, uint32_t uid)
{
uint32_t key_disabled;
dprintf(DEBUG_SPEW, "gid:0x%08x uid:0x%08x\n", gid, uid);
if (!gid && !uid) return true;
clock_gate(CLK_AES0, true);
key_disabled = rAES_AP_DIS;
clock_gate(CLK_AES0, false);
return (key_disabled & ((gid & AES_DIS_GID_MASK) << AES_DIS_GID_SHIFT)) && (key_disabled & ((uid & AES_DIS_UID_MASK) << AES_DIS_UID_SHIFT));
}
#endif // AES_AP_VERSION < 1
int
aes_hw_crypto_cmd(u_int32_t cmd, void *src, void *dst, size_t len, u_int32_t opts, const void *key, void *iv)
{
uint32_t key_in_ctrl;
uint32_t blocks;
uint32_t *local_src, *local_dst, *local_iv, *local_key;
dprintf(DEBUG_SPEW, "aes_hw_crypto_cmd: cmd: %08x, src: %p, dst: %p, len: %08zx, opts: %08x, key: %p, iv: %p \n",
cmd, src, dst, len, opts, key, iv);
clock_gate(CLK_AES0, true);
ASSERT(src != NULL);
ASSERT(dst != NULL);
local_src = (uint32_t *)src;
local_dst = (uint32_t *)dst;
local_iv = (uint32_t *)iv;
local_key = (uint32_t *)key;
/* Make sure length is multiple of 16 bytes */
ASSERT((len > 0) && ((len & 0xf) == 0));
blocks = len / 16;
key_in_ctrl = 0;
switch (cmd & AES_CMD_MODE_MASK) {
case AES_CMD_ECB : key_in_ctrl |= KEY_IN_CTRL_MOD_ECB; break;
case AES_CMD_CBC : key_in_ctrl |= KEY_IN_CTRL_MOD_CBC; break;
default : goto fail;
}
switch (cmd & AES_CMD_DIR_MASK) {
case AES_CMD_ENC : key_in_ctrl |= KEY_IN_CTRL_DIR_ENC; break;
case AES_CMD_DEC : key_in_ctrl |= KEY_IN_CTRL_DIR_DEC; break;
default : goto fail;
}
/* Get the key length */
switch (opts & AES_KEY_SIZE_MASK) {
case AES_KEY_SIZE_128 : key_in_ctrl |= KEY_IN_CTRL_LEN_128; break;
case AES_KEY_SIZE_192 : key_in_ctrl |= KEY_IN_CTRL_LEN_192; break;
case AES_KEY_SIZE_256 : key_in_ctrl |= KEY_IN_CTRL_LEN_256; break;
default : goto fail;
}
/* Set the key */
switch (opts & AES_KEY_TYPE_MASK) {
case AES_KEY_TYPE_USER :
key_in_ctrl |= KEY_IN_CTRL_SEL_SW;
switch (opts & AES_KEY_SIZE_MASK) {
default:
rAES_AP_KEY_IN7 = local_key[7];
rAES_AP_KEY_IN6 = local_key[6];
case AES_KEY_SIZE_192:
rAES_AP_KEY_IN5 = local_key[5];
rAES_AP_KEY_IN4 = local_key[4];
case AES_KEY_SIZE_128:
rAES_AP_KEY_IN3 = local_key[3];
rAES_AP_KEY_IN2 = local_key[2];
rAES_AP_KEY_IN1 = local_key[1];
rAES_AP_KEY_IN0 = local_key[0];
}
break;
case AES_KEY_TYPE_UID0 : key_in_ctrl |= KEY_IN_CTRL_SEL_UID1; break;
case AES_KEY_TYPE_GID0 : key_in_ctrl |= KEY_IN_CTRL_SEL_GID0; break;
case AES_KEY_TYPE_GID1 : key_in_ctrl |= KEY_IN_CTRL_SEL_GID1; break;
}
/* Make sure the requested key is not disabled */
if (((opts & AES_KEY_TYPE_MASK) != AES_KEY_TYPE_USER) && ((rAES_AP_DIS & (opts & AES_KEY_TYPE_MASK)) == (opts & AES_KEY_TYPE_MASK))) {
dprintf(DEBUG_INFO, "SIO_AES: requested AES key has been disabled\n");
return -1;
}
/* Make sure AES block is not busy */
ASSERT(rAES_AP_KEY_IN_STS & KEY_IN_STS_RDY);
ASSERT(rAES_AP_TXT_IN_STS & TXT_IN_STS_RDY);
ASSERT(!(rAES_AP_TXT_OUT_STS & TXT_OUT_STS_VAL_SET));
/* Setup Key configurator, and load the context */
rAES_AP_KEY_IN_CTRL = key_in_ctrl;
rAES_AP_KEY_IN_CTRL |= KEY_IN_CTRL_VAL_SET;
dprintf(DEBUG_SPEW, "sio_aes: key_in_ctrl:0x%08x, rAES_AP_KEY_IN_CTRL:0x%08x\n", key_in_ctrl, rAES_AP_KEY_IN_CTRL);
/* Load IV */
if (iv != 0) {
rAES_AP_IV_IN0 = local_iv[0];
rAES_AP_IV_IN1 = local_iv[1];
rAES_AP_IV_IN2 = local_iv[2];
rAES_AP_IV_IN3 = local_iv[3];
} else {
rAES_AP_IV_IN0 = 0;
rAES_AP_IV_IN1 = 0;
rAES_AP_IV_IN2 = 0;
rAES_AP_IV_IN3 = 0;
}
rAES_AP_IV_IN_CTRL = (0 << IV_IN_CTRL_CTX_SHIFT);
rAES_AP_IV_IN_CTRL |= IV_IN_CTRL_VAL_SET;
/* Perform AES operation */
/* Load first block */
_load_input_block(local_src);
rAES_AP_TXT_IN_CTRL = ((0 << TXT_IN_CTRL_IV_CTX_SHIFT) | (0 << TXT_IN_CTRL_KEY_CTX_SHIFT) | TXT_IN_CTRL_VAL_SET);
while(--blocks) {
/* Wait until we can shove next block in */
while ((rAES_AP_TXT_IN_STS & TXT_IN_STS_RDY) != TXT_IN_STS_RDY);
/* Load next block */
local_src += 4;
_load_input_block(local_src);
rAES_AP_TXT_IN_CTRL = ((0 << TXT_IN_CTRL_IV_CTX_SHIFT) | (0 << TXT_IN_CTRL_KEY_CTX_SHIFT));
rAES_AP_TXT_IN_CTRL |= TXT_IN_CTRL_VAL_SET;
/* Store result of the previous operation */
while ((rAES_AP_TXT_OUT_STS & TXT_OUT_STS_VAL_SET) != TXT_OUT_STS_VAL_SET);
_store_output_block(local_dst);
local_dst += 4;
}
/* Store result of the last operation */
while ((rAES_AP_TXT_OUT_STS & TXT_OUT_STS_VAL_SET) != TXT_OUT_STS_VAL_SET);
_store_output_block(local_dst);
/* Clear user key from the registers */
if ((opts & AES_KEY_TYPE_MASK) == AES_KEY_TYPE_USER) {
rAES_AP_KEY_IN7 = 0;
rAES_AP_KEY_IN6 = 0;
rAES_AP_KEY_IN5 = 0;
rAES_AP_KEY_IN4 = 0;
rAES_AP_KEY_IN3 = 0;
rAES_AP_KEY_IN2 = 0;
rAES_AP_KEY_IN1 = 0;
rAES_AP_KEY_IN0 = 0;
}
clock_gate(CLK_AES0, false);
return 0;
fail:
panic("SIO_AES: bad arguments\n");
}
void _load_input_block(const uint32_t *src)
{
dprintf(DEBUG_SPEW, "src: ");
for(int i = 0; i < 4; i++) dprintf(DEBUG_SPEW, "%08x ", src[i]);
dprintf(DEBUG_SPEW, "\n");
rAES_AP_TXT_IN0 = src[0];
rAES_AP_TXT_IN1 = src[1];
rAES_AP_TXT_IN2 = src[2];
rAES_AP_TXT_IN3 = src[3];
}
void _store_output_block(uint32_t *dst)
{
dst[0] = rAES_AP_TXT_OUT0;
dst[1] = rAES_AP_TXT_OUT1;
dst[2] = rAES_AP_TXT_OUT2;
dst[3] = rAES_AP_TXT_OUT3;
dprintf(DEBUG_SPEW, "dst: ");
for(int i = 0; i < 4; i++) dprintf(DEBUG_SPEW, "%08x ", dst[i]);
dprintf(DEBUG_SPEW, "\n");
}
+101
View File
@@ -0,0 +1,101 @@
/*
* 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.
*/
#ifndef __APPLE_AES_AP_H
#define __APPLE_AES_AP_H
#include <platform/soc/hwregbase.h>
/* AES-AP registers */
#define rAES_AP_STS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0000))
#define STS_BUSY (1U << 0)
#define rAES_AP_DIS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0004))
#define AES_DIS_GID1 (1U << 10)
#define AES_DIS_GID0 (1U << 9)
#define AES_DIS_UID1 (1U << 8)
#define AES_DIS_GID_SHIFT (9)
#define AES_DIS_UID_SHIFT (8)
#define AES_DIS_SET_DSB (1U << 3)
#define AES_DIS_SET_GID1 (1U << 2)
#define AES_DIS_SET_GID0 (1U << 1)
#define AES_DIS_SET_UID1 (1U << 0)
#define AES_DIS_SET_GID_SHIFT (1)
#define AES_DIS_SET_UID_SHIFT (0)
#define AES_DIS_GID_MASK (0x3)
#define AES_DIS_UID_MASK (0x1)
#define rAES_AP_TXT_IN_CTRL (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0008))
#define TXT_IN_CTRL_IV_CTX_SHIFT (2)
#define TXT_IN_CTRL_KEY_CTX_SHIFT (1)
#define TXT_IN_CTRL_VAL_SET (1U << 0)
#define rAES_AP_TXT_IN_STS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x000C))
#define TXT_IN_STS_RDY (1U << 0)
#define rAES_AP_TXT_IN0 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0040))
#define rAES_AP_TXT_IN1 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0044))
#define rAES_AP_TXT_IN2 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0048))
#define rAES_AP_TXT_IN3 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x004C))
#define rAES_AP_TXT_OUT_STS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0050))
#define TXT_OUT_STS_IV_CTX_SHIFT (2)
#define TXT_OUT_STS_KEY_CTX_SHIFT (1)
#define TXT_OUT_STS_VAL_SET (1U << 0)
#define rAES_AP_TXT_OUT0 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0080))
#define rAES_AP_TXT_OUT1 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0084))
#define rAES_AP_TXT_OUT2 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0088))
#define rAES_AP_TXT_OUT3 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x008C))
#define rAES_AP_KEY_IN_CTRL (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0090))
#define KEY_IN_CTRL_MOD_CBC (1U << 13)
#define KEY_IN_CTRL_MOD_ECB (0U << 13)
#define KEY_IN_CTRL_DIR_ENC (1U << 12)
#define KEY_IN_CTRL_DIR_DEC (0U << 12)
#define KEY_IN_CTRL_LEN_256 (2U << 6)
#define KEY_IN_CTRL_LEN_192 (1U << 6)
#define KEY_IN_CTRL_LEN_128 (0U << 6)
#define KEY_IN_CTRL_SEL_GID1 (3U << 4)
#define KEY_IN_CTRL_SEL_GID0 (2U << 4)
#define KEY_IN_CTRL_SEL_UID1 (1U << 4)
#define KEY_IN_CTRL_SEL_SW (0U << 4)
#define KEY_IN_CTRL_CTX_SHIFT (1)
#define KEY_IN_CTRL_VAL_SET (1U << 0)
#define rAES_AP_KEY_IN_STS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0094))
#define KEY_IN_STS_RDY (1U << 0)
#define rAES_AP_KEY_IN0 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00C0))
#define rAES_AP_KEY_IN1 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00C4))
#define rAES_AP_KEY_IN2 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00C8))
#define rAES_AP_KEY_IN3 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00CC))
#define rAES_AP_KEY_IN4 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00D0))
#define rAES_AP_KEY_IN5 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00D4))
#define rAES_AP_KEY_IN6 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00D8))
#define rAES_AP_KEY_IN7 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00DC))
#define rAES_AP_IV_IN_CTRL (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x00E0))
#define IV_IN_CTRL_CTX_SHIFT (1)
#define IV_IN_CTRL_VAL_SET (1U << 0)
#define rAES_AP_IV_IN0 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0100))
#define rAES_AP_IV_IN1 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0104))
#define rAES_AP_IV_IN2 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x0108))
#define rAES_AP_IV_IN3 (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x010C))
/* rAES_AP_IV_OUTxxxx to rAES_AP_DSB_xxxx */
#define rAES_AP_ERR (*(volatile uint32_t *)(AES_AP_BASE_ADDR + 0x01D0))
#define AES_ERR_SET (1U << 0)
#endif /* __APPLE_AES_AP_H */
+20
View File
@@ -0,0 +1,20 @@
# 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_HW_AES=1
MODULES += \
drivers/aes
ALL_OBJS += \
$(LOCAL_DIR)/aes_ap.o
+265
View File
@@ -0,0 +1,265 @@
/*
* 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 <drivers/aes.h>
#include <drivers/dma.h>
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwdmachannels.h>
#include <sys/task.h>
#include "aes_s7002.h"
void _load_input_block(const uint32_t *src);
void _store_output_block(uint32_t *dst);
#if AES_USE_DMA
int
aes_execute_cmd(uint32_t cmd, void *addr, uint32_t length, bool block)
{
struct task_event event;
struct dma_segment seg;
void *fifo;
int32_t ret;
int dma_channel;
// build an SGL for the one segment
switch (cmd & DMA_CMD_DIR_MASK) {
case DMA_CMD_DIR_TX:
seg.paddr = (uintptr_t)addr;
fifo = (void*)0x47380040;
dma_channel = DMA_AES_WR;
break;
case DMA_CMD_DIR_RX:
seg.paddr = (uintptr_t)addr;
fifo = (void*)0x47380080;
dma_channel = DMA_AES_RD;
break;
default:
return -1;
}
seg.length = length;
if (block) {
// run the operation
event_init(&event, EVENT_FLAG_AUTO_UNSIGNAL, false);
ret = dma_execute_async(cmd, dma_channel, &seg, fifo, length, 0, 0,
(dma_completion_function)event_signal, (void *)&event);
if (!ret)
// and block waiting for it to complete
event_wait(&event);
} else {
ret = dma_execute_async(cmd, dma_channel, &seg, fifo, length, 0, 0,
NULL, NULL);
}
return ret;
}
#endif
int
aes_hw_crypto_cmd(u_int32_t cmd, void *src, void *dst, size_t len, u_int32_t opts, const void *key, void *iv)
{
uint32_t key_in_ctrl;
uint32_t blocks;
uint32_t *local_iv, *local_key;
dprintf(DEBUG_SPEW, "aes_hw_crypto_cmd: cmd: %08x, src: %p, dst: %p, len: %zx, opts: %08x, key: %p, iv: %p \n",
cmd, src, dst, len, opts, key, iv);
clock_gate(CLK_AES0, true);
ASSERT(src != NULL);
ASSERT(dst != NULL);
local_iv = (uint32_t *)iv;
local_key = (uint32_t *)key;
/* Make sure length is multiple of 16 bytes */
ASSERT((len > 0) && ((len & 0xf) == 0));
blocks = len / 16;
key_in_ctrl = 0;
switch (cmd & AES_CMD_MODE_MASK) {
case AES_CMD_ECB : key_in_ctrl |= KEY_IN_CTRL_MOD_ECB; break;
case AES_CMD_CBC : key_in_ctrl |= KEY_IN_CTRL_MOD_CBC; break;
default : goto fail;
}
switch (cmd & AES_CMD_DIR_MASK) {
case AES_CMD_ENC : key_in_ctrl |= KEY_IN_CTRL_DIR_ENC; break;
case AES_CMD_DEC : key_in_ctrl |= KEY_IN_CTRL_DIR_DEC; break;
default : goto fail;
}
/* Get the key length */
switch (opts & AES_KEY_SIZE_MASK) {
case AES_KEY_SIZE_128 : key_in_ctrl |= KEY_IN_CTRL_LEN_128; break;
case AES_KEY_SIZE_192 : key_in_ctrl |= KEY_IN_CTRL_LEN_192; break;
case AES_KEY_SIZE_256 : key_in_ctrl |= KEY_IN_CTRL_LEN_256; break;
default : goto fail;
}
bool key_disabled = false;
/* Set the key */
switch (opts & AES_KEY_TYPE_MASK) {
case AES_KEY_TYPE_USER :
key_in_ctrl |= KEY_IN_CTRL_SEL_SW;
switch (opts & AES_KEY_SIZE_MASK) {
default:
rAES_S7002_KEY_IN7 = local_key[7];
rAES_S7002_KEY_IN6 = local_key[6];
case AES_KEY_SIZE_192:
rAES_S7002_KEY_IN5 = local_key[5];
rAES_S7002_KEY_IN4 = local_key[4];
case AES_KEY_SIZE_128:
rAES_S7002_KEY_IN3 = local_key[3];
rAES_S7002_KEY_IN2 = local_key[2];
rAES_S7002_KEY_IN1 = local_key[1];
rAES_S7002_KEY_IN0 = local_key[0];
}
break;
case AES_KEY_TYPE_UID0 :
key_in_ctrl |= KEY_IN_CTRL_SEL_UID1;
key_disabled = platform_keys_disabled(0,1);
break;
case AES_KEY_TYPE_GID0 :
key_in_ctrl |= KEY_IN_CTRL_SEL_GID0;
key_disabled = platform_keys_disabled(1,0);
break;
case AES_KEY_TYPE_GID1 :
key_in_ctrl |= KEY_IN_CTRL_SEL_GID1;
key_disabled = platform_keys_disabled(1,0);
break;
}
if (key_disabled) {
dprintf(DEBUG_INFO, "SIO_AES: requested AES key has been disabled\n");
return -1;
}
/* Make sure AES block is not busy */
ASSERT(rAES_S7002_KEY_IN_STS & KEY_IN_STS_RDY);
ASSERT(rAES_S7002_TXT_IN_STS & TXT_IN_FIFO_SPACE_AVAIL);
ASSERT(!(rAES_S7002_TXT_OUT_STS & TXT_OUT_DATA_AVAIL));
/* Setup Key configurator, and load the context */
rAES_S7002_KEY_IN_CTRL = key_in_ctrl;
rAES_S7002_KEY_IN_CTRL |= KEY_IN_CTRL_VAL_SET;
dprintf(DEBUG_SPEW, "sio_aes: key_in_ctrl:0x%08x, rAES_S7002_KEY_IN_CTRL:0x%08x\n", key_in_ctrl, rAES_S7002_KEY_IN_CTRL);
/* Load IV */
if (iv != 0) {
rAES_S7002_IV_IN0 = local_iv[0];
rAES_S7002_IV_IN1 = local_iv[1];
rAES_S7002_IV_IN2 = local_iv[2];
rAES_S7002_IV_IN3 = local_iv[3];
} else {
rAES_S7002_IV_IN0 = 0;
rAES_S7002_IV_IN1 = 0;
rAES_S7002_IV_IN2 = 0;
rAES_S7002_IV_IN3 = 0;
}
rAES_S7002_IV_IN_CTRL = (0 << IV_IN_CTRL_CTX_SHIFT);
rAES_S7002_IV_IN_CTRL |= IV_IN_CTRL_VAL_SET;
/* Perform AES operation */
/* Load first block */
rAES_S7002_TXT_IN_CTRL = ((0 << TXT_IN_CTRL_IV_CTX_SHIFT) | (0 << TXT_IN_CTRL_KEY_CTX_SHIFT));
#if AES_USE_DMA
/* Do cache operations */
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, (void *)((uint32_t)dst & ~(CPU_CACHELINE_SIZE-1)), ROUNDUP(len, CPU_CACHELINE_SIZE) + CPU_CACHELINE_SIZE);
/* start the operation */
aes_execute_cmd(DMA_CMD_DIR_RX, dst, len, false);
/* Do cache operations */
platform_cache_operation(CACHE_CLEAN, (void *)((uint32_t)src & ~(CPU_CACHELINE_SIZE-1)), ROUNDUP(len, CPU_CACHELINE_SIZE) + CPU_CACHELINE_SIZE);
/* start the operation */
aes_execute_cmd(DMA_CMD_DIR_TX, src, len, true);
#else
uint32_t *local_src = (uint32_t *)src;
uint32_t *local_dst = (uint32_t *)dst;
rAES_S7002_TXT_IN_CTRL = ((0 << TXT_IN_CTRL_IV_CTX_SHIFT) | (0 << TXT_IN_CTRL_KEY_CTX_SHIFT));
_load_input_block(local_src);
while(--blocks) {
/* Wait until we can shove next block in */
while ((rAES_S7002_TXT_IN_STS & TXT_IN_FIFO_SPACE_AVAIL) != TXT_IN_FIFO_SPACE_AVAIL);
/* Load next block */
local_src += 4;
rAES_S7002_TXT_IN_CTRL = ((0 << TXT_IN_CTRL_IV_CTX_SHIFT) | (0 << TXT_IN_CTRL_KEY_CTX_SHIFT));
_load_input_block(local_src);
/* Store result of the previous operation */
while ((rAES_S7002_TXT_OUT_STS & TXT_OUT_DATA_AVAIL) != TXT_OUT_DATA_AVAIL);
_store_output_block(local_dst);
local_dst += 4;
}
/* Store result of the last operation */
while ((rAES_S7002_TXT_OUT_STS & TXT_OUT_DATA_AVAIL) != TXT_OUT_DATA_AVAIL);
_store_output_block(local_dst);
#endif
/* Clear user key from the registers */
if ((opts & AES_KEY_TYPE_MASK) == AES_KEY_TYPE_USER) {
rAES_S7002_KEY_IN7 = 0;
rAES_S7002_KEY_IN6 = 0;
rAES_S7002_KEY_IN5 = 0;
rAES_S7002_KEY_IN4 = 0;
rAES_S7002_KEY_IN3 = 0;
rAES_S7002_KEY_IN2 = 0;
rAES_S7002_KEY_IN1 = 0;
rAES_S7002_KEY_IN0 = 0;
}
clock_gate(CLK_AES0, false);
return 0;
fail:
panic("AES_S7002: bad arguments\n");
}
void _load_input_block(const uint32_t *src)
{
dprintf(DEBUG_SPEW, "src: ");
for(int i = 0; i < 4; i++) dprintf(DEBUG_SPEW, "%08x ", src[i]);
dprintf(DEBUG_SPEW, "\n");
rAES_S7002_TXT_IN = src[0];
rAES_S7002_TXT_IN = src[1];
rAES_S7002_TXT_IN = src[2];
rAES_S7002_TXT_IN = src[3];
}
void _store_output_block(uint32_t *dst)
{
dst[0] = rAES_S7002_TXT_OUT;
dst[1] = rAES_S7002_TXT_OUT;
dst[2] = rAES_S7002_TXT_OUT;
dst[3] = rAES_S7002_TXT_OUT;
dprintf(DEBUG_SPEW, "dst: ");
for(int i = 0; i < 4; i++) dprintf(DEBUG_SPEW, "%08x ", dst[i]);
dprintf(DEBUG_SPEW, "\n");
}
+79
View File
@@ -0,0 +1,79 @@
/*
* 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.
*/
#ifndef __APPLE_AES_S7002_H
#define __APPLE_AES_S7002_H
#include <platform/soc/hwregbase.h>
/* AES-AP registers */
#define rAES_S7002_STS (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0000))
#define STS_BUSY (1U << 0)
#define rAES_S7002_TXT_IN_CTRL (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0008))
#define TXT_IN_CTRL_IV_CTX_SHIFT (2)
#define TXT_IN_CTRL_KEY_CTX_SHIFT (1)
#define rAES_S7002_TXT_IN_STS (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x000C))
#define TXT_IN_FIFO_SPACE_AVAIL (1U << 0)
#define rAES_S7002_TXT_IN (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0040))
#define rAES_S7002_TXT_OUT_STS (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0050))
#define TXT_OUT_STS_IV_CTX_SHIFT (2)
#define TXT_OUT_STS_KEY_CTX_SHIFT (1)
#define TXT_OUT_DATA_AVAIL (1U << 0)
#define rAES_S7002_TXT_OUT (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0080))
#define rAES_S7002_KEY_IN_CTRL (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0090))
#define KEY_IN_CTRL_MOD_CBC (1U << 13)
#define KEY_IN_CTRL_MOD_ECB (0U << 13)
#define KEY_IN_CTRL_DIR_ENC (1U << 12)
#define KEY_IN_CTRL_DIR_DEC (0U << 12)
#define KEY_IN_CTRL_LEN_256 (2U << 6)
#define KEY_IN_CTRL_LEN_192 (1U << 6)
#define KEY_IN_CTRL_LEN_128 (0U << 6)
#define KEY_IN_CTRL_SEL_GID1 (3U << 4)
#define KEY_IN_CTRL_SEL_GID0 (2U << 4)
#define KEY_IN_CTRL_SEL_UID1 (1U << 4)
#define KEY_IN_CTRL_SEL_SW (0U << 4)
#define KEY_IN_CTRL_CTX_SHIFT (1)
#define KEY_IN_CTRL_VAL_SET (1U << 0)
#define rAES_S7002_KEY_IN_STS (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0094))
#define KEY_IN_STS_RDY (1U << 0)
#define rAES_S7002_KEY_IN0 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00C0))
#define rAES_S7002_KEY_IN1 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00C4))
#define rAES_S7002_KEY_IN2 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00C8))
#define rAES_S7002_KEY_IN3 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00CC))
#define rAES_S7002_KEY_IN4 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00D0))
#define rAES_S7002_KEY_IN5 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00D4))
#define rAES_S7002_KEY_IN6 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00D8))
#define rAES_S7002_KEY_IN7 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00DC))
#define rAES_S7002_IV_IN_CTRL (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x00E0))
#define IV_IN_CTRL_CTX_SHIFT (1)
#define IV_IN_CTRL_VAL_SET (1U << 0)
#define rAES_S7002_IV_IN0 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0100))
#define rAES_S7002_IV_IN1 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0104))
#define rAES_S7002_IV_IN2 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x0108))
#define rAES_S7002_IV_IN3 (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x010C))
/* rAES_S7002_IV_OUTxxxx to rAES_S7002_DSB_xxxx */
#define rAES_S7002_ERR (*(volatile uint32_t *)(AES_S7002_BASE_ADDR + 0x01D0))
#define AES_ERR_SET (1U << 0)
#endif /* __APPLE_AES_S7002_H */
+20
View File
@@ -0,0 +1,20 @@
# 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_HW_AES=1
MODULES += \
drivers/aes
ALL_OBJS += \
$(LOCAL_DIR)/aes_s7002.o
+429
View File
@@ -0,0 +1,429 @@
/*
* 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 <drivers/aes.h>
#if WITH_HW_SEP
#include <drivers/sep/sep_client.h>
#endif
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include "aes_v2.h"
#define COMMAND_FIFO_SIZE 128
typedef enum {
BLOCK_MODE_ECB = 0,
BLOCK_MODE_CBC = 1,
BLOCK_MODE_CTR = 2,
} block_mode_t;
typedef enum {
KEY_LEN_128 = 0,
KEY_LEN_192 = 1,
KEY_LEN_256 = 2,
} key_len_t;
typedef enum {
KEY_SELECT_SOFTWARE = 0,
KEY_SELECT_UID1 = 1,
KEY_SELECT_GID_AP_1 = 2,
KEY_SELECT_GID_AP_2 = 3,
KEY_SELECT_HDCP_0 = 4,
KEY_SELECT_HDCP_1 = 5,
KEY_SELECT_HDCP_2 = 6,
KEY_SELECT_HDCP_3 = 7,
} key_select_t;
typedef enum {
KEY_FUNC_NONE = 0,
KEY_FUNC_LEGACY = 1,
KEY_FUNC_FAIRPLAY_LEGACY = 2,
KEY_FUNC_FAIRPLAY_H8F = 3,
} key_func_t;
typedef enum {
OPCODE_KEY = 0x01,
OPCODE_IV = 0x02,
OPCODE_DSB = 0x03,
OPCODE_SKG = 0x04,
OPCODE_DATA = 0x05,
OPCODE_STORE_IV = 0x06,
OPCODE_WRITE_REG = 0x07,
OPCODE_FLAG = 0x08,
} command_opcodes_t;
#define COMMAND_OPCODE_SHIFT (28)
#define COMMAND_OPCODE_MASK (0xF)
typedef struct command_key {
#define COMMAND_KEY_COMMAND_KEY_CONTEXT_SHIFT (27)
#define COMMAND_KEY_COMMAND_KEY_CONTEXT_MASK (0x1)
#define COMMAND_KEY_COMMAND_KEY_SELECT_SHIFT (24)
#define COMMAND_KEY_COMMAND_KEY_SELECT_MASK (0x7)
#define COMMAND_KEY_COMMAND_KEY_LENGTH_SHIFT (22)
#define COMMAND_KEY_COMMAND_KEY_LENGTH_MASK (0x3)
#define COMMAND_KEY_COMMAND_WRAPPED_SHIFT (21)
#define COMMAND_KEY_COMMAND_WRAPPED_MASK (0x1)
#define COMMAND_KEY_COMMAND_ENCRYPT_SHIFT (20)
#define COMMAND_KEY_COMMAND_ENCRYPT_MASK (0x1)
#define COMMAND_KEY_COMMAND_KEY_FUNC_SHIFT (18)
#define COMMAND_KEY_COMMAND_KEY_FUNC_MASK (0x3)
#define COMMAND_KEY_COMMAND_BLOCK_MODE_SHIFT (16)
#define COMMAND_KEY_COMMAND_BLOCK_MODE_MASK (0x3)
#define COMMAND_KEY_COMMAND_COMMAND_ID_SHIFT (0)
#define COMMAND_KEY_COMMAND_COMMAND_ID_MASK (0xFF)
uint32_t command;
uint32_t key[8];
} command_key_t;
typedef struct aes_command_iv {
#define COMMAND_IV_COMMAND_IV_CONTEXT_SHIFT (26)
#define COMMAND_IV_COMMAND_IV_CONTEXT_MASK (0x3)
#define COMMAND_IV_COMMAND_HDCP_KEY_SHIFT (25)
#define COMMAND_IV_COMMAND_HDCP_KEY_MASK (0x1)
#define COMMAND_IV_COMMAND_IV_IN_HDCP_SHIFT (23)
#define COMMAND_IV_COMMAND_IV_IN_HDCP_MASK (0x3)
uint32_t command;
uint32_t iv[4];
} command_iv_t;
typedef struct aes_command_data {
#define COMMAND_DATA_COMMAND_KEY_CONTEXT_SHIFT (27)
#define COMMAND_DATA_COMMAND_KEY_CONTEXT_MASK (0x1)
#define COMMAND_DATA_COMMAND_IV_CONTEXT_SHIFT (25)
#define COMMAND_DATA_COMMAND_IV_CONTEXT_MASK (0x3)
#define COMMAND_DATA_COMMAND_LENGTH_SHIFT (0)
#define COMMAND_DATA_COMMAND_LENGTH_MASK (0xFFFFFF)
uint32_t command;
#define COMMAND_DATA_UPPER_ADDR_SOURCE_SHIFT (16)
#define COMMAND_DATA_UPPER_ADDR_SOURCE_MASK (0xFF)
#define COMMAND_DATA_UPPER_ADDR_DEST_SHIFT (0)
#define COMMAND_DATA_UPPER_ADDR_DEST_MASK (0xFF)
uint32_t upper_addr;
uint32_t source_addr;
uint32_t dest_addr;
} command_data_t;
typedef struct aes_command_store_iv {
#define COMMAND_STORE_IV_COMMAND_CONTEXT_SHIFT (26)
#define COMMAND_STORE_IV_COMMAND_CONTEXT_MASK (0x3)
#define COMMAND_STORE_IV_COMMAND_UPPER_ADDR_DEST_SHIFT (0)
#define COMMAND_STORE_IV_COMMAND_UPPER_ADDR_DEST_MASK (0xFF)
uint32_t command;
uint32_t dest_addr;
} command_store_iv_t;
#define COMMAND_FLAG_ID_CODE_SHIFT (0)
#define COMMAND_FLAG_ID_CODE_MASK (0xFF)
#define COMMAND_FLAG_STOP_COMMANDS_SHIFT (26)
#define COMMAND_FLAG_SEND_INTERRUPT_SHIFT (27)
#if WITH_DPA
static bool dpa_seeded(void) {
if ((rAES_STATUS & AES_BLK_STATUS_TEXT_DPA_RANDOM_SEEDED_UMASK) == 0 ||
(rAES_STATUS & AES_BLK_STATUS_KEY_UNWRAP_DPA_RANDOM_SEEDED_UMASK) == 0) {
return false;
} else {
return true;
}
}
#endif
uint32_t command_fifo_level(void) {
return ((rAES_COMMAND_FIFO_STATUS) & AES_BLK_COMMAND_FIFO_STATUS_LEVEL_UMASK) >> 8;
}
void push_commands(uint32_t *cmd, uint32_t size) {
uint32_t words;
ASSERT(size % sizeof(uint32_t) == 0);
words = size / sizeof(uint32_t);
ASSERT(command_fifo_level() + words <= COMMAND_FIFO_SIZE);
for (uint32_t i = 0; i < words; i ++) {
dprintf(DEBUG_SPEW, "sio_aes: cmd[%d]: 0x%08x\n", i, cmd[i]);
rAES_COMMAND_FIFO = cmd[i];
}
}
uint32_t key_size(uint8_t mode) {
switch(mode) {
case KEY_LEN_128: return 128;
case KEY_LEN_192: return 192;
case KEY_LEN_256: return 256;
default: panic("Unknown key size: %d\n", mode);
}
return 0;
}
void push_command_key(uint32_t command, uint8_t *key)
{
command_key_t ckey;
memset(&ckey, 0, sizeof(ckey));
ckey.command = OPCODE_KEY << COMMAND_OPCODE_SHIFT | command;
if(((command >> COMMAND_KEY_COMMAND_KEY_SELECT_SHIFT) & COMMAND_KEY_COMMAND_KEY_SELECT_MASK) == 0) {
// software key (Key Select == 0)
ASSERT(key != NULL);
uint32_t key_len =
key_size((command >> COMMAND_KEY_COMMAND_KEY_LENGTH_SHIFT) & COMMAND_KEY_COMMAND_KEY_LENGTH_MASK) / 8;
memcpy(ckey.key, key, key_len);
// Key is not wrapped
push_commands((uint32_t*)&ckey.command, sizeof(ckey.command));
push_commands((uint32_t*)&ckey.key[0], key_len);
} else {
// non-software keys just need the command word
push_commands((uint32_t*)&ckey.command, sizeof(ckey.command));
}
}
void push_command_iv(uint8_t context, uint8_t hdcp_key, bool iv_in_hdcp, uint8_t* iv)
{
command_iv_t civ;
memset(&civ, 0, sizeof(civ));
civ.command = (OPCODE_IV << COMMAND_OPCODE_SHIFT) |
((context & COMMAND_IV_COMMAND_IV_CONTEXT_MASK) << COMMAND_IV_COMMAND_IV_CONTEXT_SHIFT) |
((hdcp_key & COMMAND_IV_COMMAND_HDCP_KEY_MASK) << COMMAND_IV_COMMAND_HDCP_KEY_SHIFT) |
((iv_in_hdcp & COMMAND_IV_COMMAND_IV_IN_HDCP_MASK) << COMMAND_IV_COMMAND_IV_IN_HDCP_SHIFT);
if (iv) {
memcpy(&civ.iv, iv, sizeof(civ.iv));
}
push_commands((uint32_t*)&civ, sizeof(command_iv_t));
}
void push_command_data(uint8_t key_ctx, uint8_t iv_ctx, uint64_t src, uint64_t dst, uint32_t len)
{
command_data_t data;
memset(&data, 0, sizeof(data));
data.command = (OPCODE_DATA << COMMAND_OPCODE_SHIFT) |
((len & COMMAND_DATA_COMMAND_LENGTH_MASK) << COMMAND_DATA_COMMAND_LENGTH_SHIFT) |
((key_ctx & COMMAND_DATA_COMMAND_KEY_CONTEXT_MASK) << COMMAND_DATA_COMMAND_KEY_CONTEXT_SHIFT) |
((iv_ctx & COMMAND_DATA_COMMAND_IV_CONTEXT_MASK) << COMMAND_DATA_COMMAND_IV_CONTEXT_SHIFT);
data.upper_addr =
(((src >> 32) & COMMAND_DATA_UPPER_ADDR_SOURCE_MASK) << COMMAND_DATA_UPPER_ADDR_SOURCE_SHIFT) |
(((dst >> 32) & COMMAND_DATA_UPPER_ADDR_DEST_MASK) << COMMAND_DATA_UPPER_ADDR_DEST_SHIFT);
data.source_addr = (uint32_t)src;
data.dest_addr = (uint32_t)dst;
push_commands((uint32_t*)&data, sizeof(command_data_t));
}
void push_command_flag(uint16_t id_code, bool stop, bool interrupt)
{
uint32_t flag = 0;
flag = (OPCODE_FLAG << COMMAND_OPCODE_SHIFT) |
((id_code & COMMAND_FLAG_ID_CODE_MASK) << COMMAND_FLAG_ID_CODE_SHIFT);
if (stop)
flag |= 1 << COMMAND_FLAG_SEND_INTERRUPT_SHIFT;
if (interrupt)
flag |= 1 << COMMAND_FLAG_STOP_COMMANDS_SHIFT;
push_commands(&flag, sizeof(flag));
}
uint32_t create_key_command(bool context, uint8_t select, uint8_t len, bool wrapped, bool encrypt, uint8_t func, uint8_t mode, uint8_t id) {
return (OPCODE_KEY << COMMAND_OPCODE_SHIFT) |
((context & COMMAND_KEY_COMMAND_KEY_CONTEXT_MASK) << COMMAND_KEY_COMMAND_KEY_CONTEXT_SHIFT) |
((select & COMMAND_KEY_COMMAND_KEY_SELECT_MASK) << COMMAND_KEY_COMMAND_KEY_SELECT_SHIFT) |
((len & COMMAND_KEY_COMMAND_KEY_LENGTH_MASK) << COMMAND_KEY_COMMAND_KEY_LENGTH_SHIFT) |
((wrapped & COMMAND_KEY_COMMAND_WRAPPED_MASK) << COMMAND_KEY_COMMAND_WRAPPED_SHIFT) |
((encrypt & COMMAND_KEY_COMMAND_ENCRYPT_MASK) << COMMAND_KEY_COMMAND_ENCRYPT_SHIFT) |
((func & COMMAND_KEY_COMMAND_KEY_FUNC_MASK) << COMMAND_KEY_COMMAND_KEY_FUNC_SHIFT) |
((mode & COMMAND_KEY_COMMAND_BLOCK_MODE_MASK) << COMMAND_KEY_COMMAND_BLOCK_MODE_SHIFT) |
((id & COMMAND_KEY_COMMAND_COMMAND_ID_MASK) << COMMAND_KEY_COMMAND_COMMAND_ID_SHIFT);
}
void wait_for_command_flag(void)
{
while ((rAES_INT_STATUS & AES_BLK_INT_STATUS_FLAG_COMMAND_UMASK) == 0) {}
rAES_INT_STATUS = AES_BLK_INT_STATUS_FLAG_COMMAND_UMASK;
dprintf(DEBUG_SPEW, "sio_aes: AES_STATUS=0x%08x\n", rAES_STATUS);
dprintf(DEBUG_SPEW, "sio_aes: AES_COMMAND_FIFO_STATUS=0x%08x\n", rAES_COMMAND_FIFO_STATUS);
dprintf(DEBUG_SPEW, "sio_aes: INT_STATUS=0x%08x\n", rAES_INT_STATUS);
ASSERT((rAES_COMMAND_FIFO_STATUS & AES_BLK_COMMAND_FIFO_STATUS_EMPTY_UMASK) != 0);
if (rAES_INT_STATUS) {
panic("AES command failed, AES_STATUS=0x%08x, AES_COMMAND_FIFO_STATUS=0x%08x, INT_STATUS=0x%08x", rAES_STATUS, rAES_COMMAND_FIFO_STATUS, rAES_INT_STATUS);
}
}
int
aes_hw_crypto_cmd(u_int32_t cmd, void *src, void *dst, size_t len, u_int32_t opts, const void *key, void *iv)
{
uintptr_t *local_src, *local_dst;
uint8_t *local_iv, *local_key;
dprintf(DEBUG_SPEW, "aes_hw_crypto_cmd: cmd: 0x%08x, src: %p, dst: %p, len: 0x%08zx, opts: 0x%08x, key: %p, iv: %p \n",
cmd, src, dst, len, opts, key, iv);
clock_gate(CLK_AES0, true);
#if WITH_DPA
if (!dpa_seeded()) {
sep_client_seed_aes();
if(!dpa_seeded()) {
panic("AES DPA not Seeded");
}
}
#endif
ASSERT(src != NULL);
ASSERT(dst != NULL);
local_src = (uintptr_t *)src;
local_dst = (uintptr_t *)dst;
local_iv = (uint8_t *)iv;
local_key = (uint8_t *)key;
/* Make sure length is multiple of 16 bytes */
ASSERT((len > 0) && ((len & 0xf) == 0));
uint8_t key_select = KEY_SELECT_SOFTWARE;
uint8_t key_len = KEY_LEN_128;
uint8_t key_mode = BLOCK_MODE_ECB;
bool encrypt = false;
switch (cmd & AES_CMD_MODE_MASK) {
case AES_CMD_ECB : key_mode = BLOCK_MODE_ECB; break;
case AES_CMD_CBC : key_mode = BLOCK_MODE_CBC; break;
default : goto fail;
}
switch (cmd & AES_CMD_DIR_MASK) {
case AES_CMD_ENC : encrypt = true; break;
case AES_CMD_DEC : encrypt = false; break;
default : goto fail;
}
/* Get the key length */
switch (opts & AES_KEY_SIZE_MASK) {
case AES_KEY_SIZE_128 : key_len = KEY_LEN_128; break;
case AES_KEY_SIZE_192 : key_len = KEY_LEN_192; break;
case AES_KEY_SIZE_256 : key_len = KEY_LEN_256; break;
default : goto fail;
}
bool key_disabled = false;
/* Set the key */
/* Make sure the requested key is not disabled */
switch (opts & AES_KEY_TYPE_MASK) {
case AES_KEY_TYPE_USER :
key_select = KEY_SELECT_SOFTWARE;
break;
case AES_KEY_TYPE_UID0 :
key_select = KEY_SELECT_UID1;
key_disabled = platform_keys_disabled(0,1);
break;
case AES_KEY_TYPE_GID0 :
key_select = KEY_SELECT_GID_AP_1;
key_disabled = platform_keys_disabled(1,0);
break;
case AES_KEY_TYPE_GID1 :
key_select = KEY_SELECT_GID_AP_2;
key_disabled = platform_keys_disabled(2,0);
break;
default : goto fail;
}
if (key_disabled) {
dprintf(DEBUG_INFO, "SIO_AES: requested AES key has been disabled\n");
return -1;
}
uint32_t key_command =
create_key_command(0, key_select, key_len, false, encrypt, KEY_FUNC_NONE, key_mode, 0);
dprintf(DEBUG_SPEW, "sio_aes: key_command:0x%08x\n", key_command);
/* Verify everything is flushed out of write buffers */
platform_memory_barrier();
// We're going to poll for the flag interrupt after the command finishes, so clear it now
rAES_INT_STATUS = AES_BLK_INT_STATUS_FLAG_COMMAND_UMASK;
/* Start the block consuming commands */
dprintf(DEBUG_SPEW, "sio_aes: AES_CONTROL_START\n");
rAES_CONTROL = AES_BLK_CONTROL_START_UMASK;
#if WITH_NON_COHERENT_DMA
platform_cache_operation(CACHE_CLEAN, (void *)((uint32_t)local_key & ~(CPU_CACHELINE_SIZE-1)), ROUNDUP(len, CPU_CACHELINE_SIZE) + CPU_CACHELINE_SIZE);
#endif /*WITH_NON_COHERENT_DMA*/
// Push the key command out to the block
push_command_key(key_command, local_key);
#if WITH_NON_COHERENT_DMA
platform_cache_operation(CACHE_CLEAN, (void *)((uint32_t)local_iv & ~(CPU_CACHELINE_SIZE-1)), ROUNDUP(len, CPU_CACHELINE_SIZE) + CPU_CACHELINE_SIZE);
#endif /* WITH_NON_COHERENT_DMA */
/* Load IV */
push_command_iv(0, 0, 0, local_iv);
#if WITH_NON_COHERENT_DMA
platform_cache_operation(CACHE_CLEAN, (void *)((uint32_t)local_src & ~(CPU_CACHELINE_SIZE-1)), ROUNDUP(len, CPU_CACHELINE_SIZE) + CPU_CACHELINE_SIZE);
#endif /*WITH_NON_COHERENT_DMA*/
/* Perform AES operation */
push_command_data(0, 0, (uint64_t)local_src, (uint64_t)local_dst, len);
// Raise an interrupt and stop executing commands once all AF responses are received
push_command_flag(0, true, true);
wait_for_command_flag();
platform_memory_barrier();
#if WITH_NON_COHERENT_DMA
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, (void *)((uint32_t)local_dst & ~(CPU_CACHELINE_SIZE-1)), ROUNDUP(len, CPU_CACHELINE_SIZE) + CPU_CACHELINE_SIZE);
#endif /*WITH_NON_COHERENT_DMA*/
/* Stop the block consuming commands */
dprintf(DEBUG_SPEW, "sio_aes: AES_CONTROL_STOP\n");
rAES_CONTROL = AES_BLK_CONTROL_STOP_UMASK;
clock_gate(CLK_AES0, false);
return 0;
fail:
panic("SIO_AES: bad arguments\n");
}
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2013-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __APPLE_AES_V2_H
#define __APPLE_AES_V2_H
#include <platform/soc/hwregbase.h>
#include SUB_PLATFORM_SPDS_HEADER(aes)
/* AES-v2 registers */
#define rAES_VERSION (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_VERSION_OFFSET))
#define rAES_CONFIG (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_CONFIG_OFFSET))
#define rAES_CONTROL (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_CONTROL_OFFSET))
#define rAES_STATUS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_STATUS_OFFSET))
#define rAES_INT_STATUS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_INT_STATUS_OFFSET))
#define rAES_INT_ENABLE (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_INT_ENABLE_OFFSET))
#define rAES_WATERMARKS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_WATERMARKS_OFFSET))
#define rAES_COMMAND_FIFO_STATUS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_COMMAND_FIFO_STATUS_OFFSET))
#define rAES_HISTORY_FIFO_STATUS (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_HISTORY_FIFO_STATUS_OFFSET))
#define rAES_COMMAND_FIFO_COUNT (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_COMMAND_FIFO_COUNT_OFFSET))
#define rAES_FLAG_COMMAND (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_FLAG_COMMAND_OFFSET))
#define rAES_SKG_KEY (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_SKG_KEY_OFFSET))
#define rAES_COMMAND_FIFO (*(volatile uint32_t *)(AES_AP_BASE_ADDR + AES_BLK_COMMAND_FIFO_OFFSET))
#endif /* __APPLE_AES_V2_H */
+21
View File
@@ -0,0 +1,21 @@
# 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_HW_AES=1
MODULES += \
drivers/aes
ALL_OBJS += \
$(LOCAL_DIR)/aes_v2.o
+533
View File
@@ -0,0 +1,533 @@
/*
* Copyright (C) 2009-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 <arch.h>
#include <arch/arm/arm.h>
#include <debug.h>
#include <drivers/aic/aic.h>
#include <platform.h>
#include <platform/int.h>
#include <platform/timer.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwisr.h>
#include <platform/soc/hwregbase.h>
#include <platform/soc/pmgr.h>
#include <sys/callout.h>
#if WITH_AIC_TIMERS
static void timer_deadline(void *arg);
static void (* timer_deadline_func)(void);
#endif
#if WITH_AIC_INTERRUPTS || WITH_AIC_TIMERS
static inline uint32_t _aic_read_reg(volatile uint32_t *reg)
{
uint32_t val;
#if PLATFORM_VARIANT_IOP || AIC_VERSION > 0
val = *reg;
#else
/* An exclusive load is required for the CPU ID to be passed along */
__asm__ volatile( "ldrex %0, [%1]" : "=r" (val) : "r" (reg));
#endif // PLATFORM_VARIANT_IOP || AIC_VERSION > 0
return val;
}
static inline void _aic_write_reg(volatile uint32_t *reg, uint32_t val)
{
*reg = val;
}
static void _aic_init()
{
#if AIC_VERSION > 0
rAIC_GLB_CFG |= (AIC_GLBCFG_SYNC_ACG | AIC_GLBCFG_EIR_ACG | AIC_GLBCFG_REG_ACG);
/* Clear the timeout values before setting them to avoid set bits from the default values */
rAIC_GLB_CFG &= ~(AIC_GLBCFG_SEWT(AIC_GLBCFG_WT_MASK) | AIC_GLBCFG_AEWT(AIC_GLBCFG_WT_MASK));
rAIC_GLB_CFG &= ~(AIC_GLBCFG_SIWT(AIC_GLBCFG_WT_MASK) | AIC_GLBCFG_AIWT(AIC_GLBCFG_WT_MASK));
rAIC_GLB_CFG |= (AIC_GLBCFG_SEWT(AIC_GLBCFG_WT_64MICRO) | AIC_GLBCFG_AEWT(AIC_GLBCFG_WT_64MICRO));
rAIC_GLB_CFG |= (AIC_GLBCFG_SIWT(AIC_GLBCFG_WT_64MICRO) | AIC_GLBCFG_AIWT(AIC_GLBCFG_WT_64MICRO));
#else
rAIC_GLB_CFG |= AIC_GLBCFG_ACG;
/* Clear the timeout values before setting them to avoid set bits from the default values */
rAIC_GLB_CFG &= ~(AIC_GLBCFG_EWT(AIC_GLBCFG_WT_MASK) | AIC_GLBCFG_IWT(AIC_GLBCFG_WT_MASK));
rAIC_GLB_CFG |= (AIC_GLBCFG_EWT(AIC_GLBCFG_WT_64MICRO) | AIC_GLBCFG_IWT(AIC_GLBCFG_WT_64MICRO));
#endif // AIC_VERSION > 0
// Enable Interrupts
rAIC_GLB_CFG |= AIC_GLBCFG_IEN;
}
#endif
#if WITH_AIC_INTERRUPTS
/*
* Interrupt support
*/
extern void __arm_irq(void);
static struct interrupt_entry handlers[kAIC_NUM_INTS];
#if AIC_VERSION < 1
static uint32_t fiq_source = kAIC_INT_SPURIOUS;
#endif // AIC_VERSION < 1
static void _aic_mask_timer_int(bool mask)
{
#if AIC_VERSION < 1
if (mask)
_aic_write_reg(&rAIC_TMR_ST_SET, AIC_TMRST_TIM);
else
_aic_write_reg(&rAIC_TMR_ST_CLR, AIC_TMRST_TIM);
#endif // AIC_VERSION < 1
}
static void _aic_mask_int_internal(uint32_t vector)
{
if (vector == kAIC_VEC_IPI) {
/* Not maskable */
} else if (vector == kAIC_VEC_TMR) {
_aic_mask_timer_int(true);
} else if (vector == kAIC_VEC_SW_TMR) {
/* Not maskable */
} else {
uint32_t reg = AIC_SRC_TO_EIR(vector);
rAIC_EIR_MASK_SET(reg) = AIC_SRC_TO_MASK(vector);
}
}
static void _aic_unmask_int_internal(uint32_t vector)
{
if (vector == kAIC_VEC_IPI) {
/* Not maskable */
} else if (vector == kAIC_VEC_TMR) {
_aic_mask_timer_int(false);
} else {
/* if AIC client requested interrupt state is not masked, unmask it */
if (!handlers[vector].int_mask_requested) {
uint32_t reg = AIC_SRC_TO_EIR(vector);
rAIC_EIR_MASK_CLR(reg) = AIC_SRC_TO_MASK(vector);
}
}
}
int interrupt_init(void)
{
_aic_init();
#if !PLATFORM_VARIANT_IOP
/* mask everything */
interrupt_mask_all();
#endif
/* also enable it */
exit_critical_section();
return 0;
}
void interrupt_mask_all(void)
{
uint32_t eir;
/* mask everything */
for (eir = 0; eir < kAIC_NUM_EIRS; eir++) {
rAIC_EIR_MASK_SET(eir) = 0xffffffff;
}
/* XXX timers? */
}
void mask_int(uint32_t vector)
{
/* save AIC client requested interrupt mask state */
handlers[vector].int_mask_requested = true;
_aic_mask_int_internal(vector);
}
void unmask_int(uint32_t vector)
{
/* clear AIC client requested interrupt mask state */
handlers[vector].int_mask_requested = false;
_aic_unmask_int_internal(vector);
}
void set_int_type(uint32_t vector, int type)
{
enter_critical_section();
#if AIC_VERSION < 1
uint32_t reg;
if (type & INT_TYPE_FIQ) {
reg = _aic_read_reg(&rAIC_TMR_CFG);
reg &= ~kAIC_TMRCFG_FSL_MASK;
if ((reg & (AIC_TMRCFG_IMD|AIC_TMRCFG_EMD|AIC_TMRCFG_SMD)) !=
(AIC_TMRCFG_IMD|AIC_TMRCFG_EMD|AIC_TMRCFG_SMD))
panic("Can't support multiple timer FIQ sources\n");
if (vector == kAIC_VEC_TMR) {
reg &= ~AIC_TMRCFG_IMD;
_aic_write_reg(&rAIC_TMR_CFG, reg | AIC_TMRCFG_FSL(kAIC_TMRCFGFSL_PVT));
fiq_source = kAIC_INT_PVT_TMR;
arm_enable_fiqs();
} else if (vector == kAIC_VEC_SW_TMR) {
reg &= ~AIC_TMRCFG_SMD;
_aic_write_reg(&rAIC_TMR_CFG, reg | AIC_TMRCFG_FSL(kAIC_TMRCFGFSL_SGT));
fiq_source = kAIC_INT_SW_TMR;
arm_enable_fiqs();
}
} else {
if (vector == kAIC_VEC_TMR) {
_aic_write_reg(&rAIC_TMR_CFG, _aic_read_reg(&rAIC_TMR_CFG) | AIC_TMRCFG_IMD);
} else if (vector == kAIC_VEC_SW_TMR) {
_aic_write_reg(&rAIC_TMR_CFG, _aic_read_reg(&rAIC_TMR_CFG) | AIC_TMRCFG_SMD);
}
}
#endif // AIC_VERSION < 1
if (type & INT_TYPE_EDGE)
panic("set_int_type: edge not supported\n");
exit_critical_section();
}
int install_int_handler(uint32_t vector, int_handler handler, void *arg)
{
ASSERT(vector < kAIC_NUM_INTS);
enter_critical_section();
handlers[vector].handler = handler;
handlers[vector].arg = arg;
if (vector < kAIC_MAX_EXTID) {
rAIC_EIR_DEST(vector) = 1 << AIC_CPU_ID;
}
exit_critical_section();
return 0;
}
static uint32_t spurious = 0;
#define SPURIOUS_DEBUG 0
#define PLATFORM_IRQ_SLICES ((PLATFORM_IRQ_COUNT + 31) / 32)
void platform_irq(void)
{
#if SPURIOUS_DEBUG
uint32_t unmasked[PLATFORM_IRQ_SLICES];
uint32_t i;
for (i = 0; i < PLATFORM_IRQ_SLICES; i++) {
unmasked[i] = rAIC_EIR_INT_RO(i) & ~rAIC_EIR_MASK_CLR(i);
}
#endif
uint32_t vector = _aic_read_reg(&rAIC_IACK);
uint32_t source;
if (vector == kAIC_INT_SPURIOUS) {
/* Do some extra checking to be sure IACK is behaving
* as expected. We don't really expect spurious
* interrupts in this environment, and certainly want
* to see a non-spurious IACK any time a source is
* active. */
#if SPURIOUS_DEBUG
for (i = 0; i < PLATFORM_IRQ_SLICES; i++) {
if (unmasked[i])
panic("IACK=0 but sources are pending\n");
}
printf("spurious\n");
#endif
spurious++;
return;
}
while (vector != kAIC_INT_SPURIOUS) {
if (AIC_INT_EXT(vector)) {
source = AIC_INT_EXTID(vector);
} else if (AIC_INT_IPI(vector)) {
panic("Unexpected IPI\n");
#if AIC_VERSION < 1
} else if (vector == kAIC_INT_PVT_TMR) {
source = kAIC_VEC_TMR;
} else if (vector == kAIC_INT_SW_TMR) {
_aic_write_reg(&rAIC_TMR_ST_CLR, AIC_TMRST_SGT);
source = kAIC_VEC_SW_TMR;
#endif // AIC_VERSION < 1
} else {
panic("Unrecognized IRQ vector: %x\n", vector);
}
if (handlers[source].handler)
handlers[source].handler(handlers[source].arg);
_aic_unmask_int_internal(source);
vector = _aic_read_reg(&rAIC_IACK);
}
}
#if AIC_VERSION < 1
void platform_fiq(void)
{
uint32_t source;
if (fiq_source == kAIC_INT_SW_TMR) {
_aic_write_reg(&rAIC_TMR_ST_CLR, AIC_TMRST_SGT);
source = kAIC_VEC_SW_TMR;
} else if (fiq_source == kAIC_INT_PVT_TMR) {
source = kAIC_VEC_TMR;
} else
panic("Unexpected FIQ\n");
if (handlers[source].handler)
handlers[source].handler(handlers[source].arg);
_aic_unmask_int_internal(source);
}
#endif // AIC_VERSION < 1
#if AIC_VERSION == 2
void platform_fiq(void)
{
/* clear FIQ and disable decrementer */
_aic_write_reg(&rAIC_TMR_CFG, ~AIC_TMRCFG_EN);
_aic_write_reg(&rAIC_TMR_ISR, AIC_TMRISR_PCT);
/* if we have a callback, invoke it now */
if (timer_deadline_func) {
timer_deadline_func();
}
}
#endif // AIC_VERSION == 2
#if PLATFORM_VARIANT_IOP
void interrupt_generate_ipc(uint32_t vector)
{
uint32_t reg = AIC_SRC_TO_EIR(vector);
rAIC_EIR_SW_SET(reg) = AIC_SRC_TO_MASK(vector);
}
void interrupt_clear_ipc(uint32_t vector)
{
uint32_t reg = AIC_SRC_TO_EIR(vector);
rAIC_EIR_SW_CLR(reg) = AIC_SRC_TO_MASK(vector);
}
#endif
#endif
#if WITH_AIC_TIMERS
/*
* Timer support; currently assumes that the banked register block works
* (XXX no it doesn't - see top of file)
*/
#define DECR_MAX_COUNT (0xffffffffULL)
int timer_init(uint32_t timer)
{
/* Allow only banked access to CPU's own timer */
if (timer != 0) return -1;
/* Default to disabled and IRQ for all modes */
_aic_write_reg(&rAIC_TMR_CFG, AIC_TMRCFG_IMD|AIC_TMRCFG_EMD|AIC_TMRCFG_SMD);
/* install our interrupt handler */
install_int_handler(kAIC_VEC_TMR, (int_handler)&timer_deadline, NULL);
unmask_int(kAIC_VEC_TMR);
return 0;
}
void timer_stop_all(void)
{
/* Even though it says "all", only stop the dedicated timer */
_aic_write_reg(&rAIC_TMR_CFG, _aic_read_reg(&rAIC_TMR_CFG) & ~AIC_TMRCFG_EN);
}
void timer_deadline_enter(uint64_t deadline, void (* func)(void))
{
uint64_t ticks;
uint32_t decr;
timer_deadline_func = func;
if (func) {
// printf("installing deadline %p\n", func);
/* convert absolute deadline to relative time */
ticks = timer_get_ticks();
if (deadline < ticks) {
// printf(" %llu too soon (it is now %llu)\n", deadline, ticks);
#if AIC_VERSION == 2
deadline = 1;
#else // AIC_VERSION == 2
deadline = 0;
#endif
} else {
deadline -= ticks;
}
/* clamp the deadline to our maximum, which is about 178 seconds */
decr = (deadline > DECR_MAX_COUNT) ? DECR_MAX_COUNT : deadline;
// printf(" using decrementer count %u\n", decr);
/*
* Reset the decrementer by programming the max count, clearing
* any pending interrupt status, then programming the desired count.
*/
_aic_write_reg(&rAIC_TMR_CNT, DECR_MAX_COUNT);
_aic_write_reg(&rAIC_TMR_CFG, _aic_read_reg(&rAIC_TMR_CFG) | AIC_TMRCFG_EN);
_aic_write_reg(&rAIC_TMR_ISR, AIC_TMRISR_PCT);
_aic_write_reg(&rAIC_TMR_CNT, decr);
} else {
/* no deadline, disable the decrementer */
_aic_write_reg(&rAIC_TMR_CFG, _aic_read_reg(&rAIC_TMR_CFG) & ~AIC_TMRCFG_EN);
_aic_write_reg(&rAIC_TMR_ISR, _aic_read_reg(&rAIC_TMR_ISR) | AIC_TMRISR_PCT);
}
}
static void timer_deadline(void *arg)
{
/* acknowledge the interrupt and disable the timer */
_aic_write_reg(&rAIC_TMR_CFG, _aic_read_reg(&rAIC_TMR_CFG) & ~AIC_TMRCFG_EN);
_aic_write_reg(&rAIC_TMR_ISR, _aic_read_reg(&rAIC_TMR_ISR) | AIC_TMRISR_PCT);
/* if we have a callback, invoke it now */
if (timer_deadline_func)
timer_deadline_func();
}
#endif // WITH_AIC_TIMERS
/*
* The rest are defined for all targets that include the AIC driver
*/
uint64_t aic_get_ticks(void)
{
uint32_t time_lo, time_hi;
/* read the timebase */
do {
time_hi = rAIC_TIME_HI;
time_lo = rAIC_TIME_LO;
} while (time_hi != rAIC_TIME_HI);
return ((uint64_t)time_hi << 32) | time_lo;
}
void aic_spin(uint32_t usecs)
{
uint32_t delta_time = usecs * (OSC_FREQ / 1000000);
uint32_t start_time = rAIC_TIME_LO;
while ((rAIC_TIME_LO - start_time) < delta_time);
}
#if WITH_AIC_TIMERS
#ifdef OSC_FREQ
utime_t timer_ticks_to_usecs(uint64_t ticks)
{
#if (OSC_FREQ % 1000000) == 0
return ticks / (OSC_FREQ / 1000000);
#else
#error "The code below has overflow issues. Make sure you really want to use it"
return (ticks * 1000 * 1000) / OSC_FREQ;
#endif
}
uint64_t timer_usecs_to_ticks(utime_t usecs)
{
#if (OSC_FREQ % 1000000) == 0
return usecs * (OSC_FREQ / 1000000);
#else
#error "The code below has overflow issues. Make sure you really want to use it"
uint64_t timer_scale = ((uint64_t)(OSC_FREQ) << 20) / (1000 * 1000);
return (ticks * timer_scale) >> 20;
#endif
}
uint32_t timer_get_tick_rate(void)
{
return OSC_FREQ;
}
#endif // OSC_FREQ
uint64_t timer_get_ticks(void)
{
return aic_get_ticks();
}
#endif // WITH_AIC_TIMERS
uint32_t timer_get_entropy(void)
{
return arch_get_entropy(&rAIC_TIME_LO);
}
#ifndef PMGR_WDG_VERSION
#error "PMGR_WDG_VERSION not defined"
#endif
#if PMGR_WDG_VERSION < 1
void wdt_chip_reset(void)
{
rPMGR_WDOG_CTL = 0; // Turn off any pending events
rPMGR_WDOG_RST = 1; // Set counter for immediate reset
rPMGR_WDOG_TMR = 0x80000000; // Set counter to a safe value
rPMGR_WDOG_CTL = 4; // Enable watchdog reset
rPMGR_WDOG_TMR = 0; // Reset counter to zero
}
void wdt_enable(void)
{
rPMGR_WDOG_CTL = 0; // Turn off any pending events
rPMGR_WDOG_RST = 120*OSC_FREQ; // Set counter for two minute reset
rPMGR_WDOG_TMR = 0x80000000; // Set counter to a safe value
rPMGR_WDOG_CTL = 0x0C; // Enable watchdog system reset
rPMGR_WDOG_TMR = 0; // Reset counter to zero
}
#else
void wdt_chip_reset(void)
{
rPMGR_CHIP_WDOG_CTL = 0;
rPMGR_CHIP_WDOG_RST_CNT = 1;
rPMGR_CHIP_WDOG_TMR = 0x80000000;
rPMGR_CHIP_WDOG_CTL = 4;
rPMGR_CHIP_WDOG_TMR = 0;
}
void wdt_system_reset(void)
{
rPMGR_SYS_WDOG_CTL = 0; // Turn off watchdog
rPMGR_SYS_WDOG_RST_CNT = 1; // Set counter for immediate reset
rPMGR_SYS_WDOG_TMR = 0x80000000;// Set up-counter to safe value
rPMGR_SYS_WDOG_CTL = 4; // Turn on interrupt
rPMGR_SYS_WDOG_TMR = 0; // Reset counter to zero
}
void wdt_enable(void)
{
rPMGR_SYS_WDOG_CTL = 0;
rPMGR_SYS_WDOG_RST_CNT = 120 * OSC_FREQ;
rPMGR_SYS_WDOG_TMR = 0x80000000;
rPMGR_SYS_WDOG_CTL = 4;
}
#endif
+150
View File
@@ -0,0 +1,150 @@
/*
* Copyright (C) 2009-2014 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 __PLATFORM_SOC_AIC_H
#define __PLATFORM_SOC_AIC_H
#include <platform/soc/hwregbase.h>
// AIC_VERSION
// 0 - < H6
// 1 - H6-H8, M7
// 2 - M8
// 3 - H9
#ifndef AIC_VERSION
#error "AIC_VERSION is not defined in hwregbase.h"
#endif
#ifndef AIC_INT_COUNT
#error "AIC_INT_COUNT is not defined in hwregbase.h"
#endif
#define rAIC_REV (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x0000))
#define rAIC_CAP0 (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x0004))
#define rAIC_CAP1 (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x0008))
#define rAIC_RST (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x000C))
#define rAIC_GLB_CFG (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x0010))
#define AIC_GLBCFG_IEN (1 << 0)
#if AIC_VERSION < 1
#define AIC_GLBCFG_TEN (1 << 1)
#define AIC_GLBCFG_EWT(_t) ((_t) << 4)
#define AIC_GLBCFG_IWT(_t) ((_t) << 8)
#define AIC_GLBCFG_ACG (1 << 16)
#define AIC_GLBCFG_WT_MASK (7)
#else
#define AIC_GLBCFG_AEWT(_t) ((_t) << 4)
#define AIC_GLBCFG_SEWT(_t) ((_t) << 8)
#define AIC_GLBCFG_AIWT(_t) ((_t) << 12)
#define AIC_GLBCFG_SIWT(_t) ((_t) << 16)
#define AIC_GLBCFG_SYNC_ACG (1 << 29)
#define AIC_GLBCFG_EIR_ACG (1 << 30)
#define AIC_GLBCFG_REG_ACG (1 << 31)
#define AIC_GLBCFG_WT_MASK (15)
#endif // AIC_VERSION < 1
#define AIC_GLBCFG_WT_64MICRO (7)
#if AIC_VERSION < 1
#define rAIC_TIME_LO (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x0020))
#define rAIC_TIME_HI (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x0028))
#elif AIC_VERSION < 3
#define rAIC_TIME_LO (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x1020))
#define rAIC_TIME_HI (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x1028))
#else // (AIC_VERSION >= 3)
#define rAIC_TIME_LO (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x8020))
#define rAIC_TIME_HI (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x8028))
#endif // AIC_VERSION
#define rAIC_WHOAMI (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2000))
#define rAIC_IACK (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2004))
#define rAIC_IPI_SET (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2008))
#define rAIC_IPI_CLR (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x200C))
#define AIC_IPI_NORMAL (1 << 0)
#define AIC_IPI_SELF (1 << 31)
#define rAIC_TMR_CFG (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2010))
#define AIC_TMRCFG_EN (1 << 0)
#define AIC_TMRCFG_IMD (1 << 1)
#define AIC_TMRCFG_EMD (1 << 2)
#define AIC_TMRCFG_SMD (1 << 3)
#define AIC_TMRCFG_FSL(_s) ((_s) << 4)
#define kAIC_TMRCFGFSL_PVT 0
#define kAIC_TMRCFGFSL_SGT 1
#define kAIC_TMRCFGFSL_EXT 2
#define kAIC_TMRCFG_FSL_MASK (AIC_TMRCFG_FSL(3))
#if AIC_VERSION < 1
#define rAIC_TMR_CNT (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2014))
#define rAIC_TMR_ISR (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2018))
#define AIC_TMRISR_PCT (1 << 0)
#define AIC_TMRISR_ETS (1 << 1)
#define AIC_TMRISR_STS (1 << 2)
#define rAIC_TMR_ST_SET (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x201C))
#define rAIC_TMR_ST_CLR (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2020))
#define AIC_TMRST_SGT (1 << 0)
#define AIC_TMRST_TIM (1 << 1)
#endif // AIC_VERSION < 1
#define rAIC_IPI_MASK_SET (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2024))
#define rAIC_IPI_MASK_CLR (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2028))
#if AIC_VERSION > 0
#define rAIC_PVT_STAMP_CFG (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2040))
#define AIC_PVT_STAMP_CFG_EN (1 << 31)
#define rAIC_PVT_STAMP_LO (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x2048))
#define rAIC_PVT_STAMP_HI (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x204C))
#endif // AIC_VERSION > 0
#define rAIC_EIR_DEST(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x3000 + ((_n) * 4)))
#define rAIC_EIR_SW_SET(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x4000 + ((_n) * 4)))
#define rAIC_EIR_SW_CLR(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x4080 + ((_n) * 4)))
#define rAIC_EIR_MASK_SET(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x4100 + ((_n) * 4)))
#define rAIC_EIR_MASK_CLR(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x4180 + ((_n) * 4)))
#define rAIC_EIR_INT_RO(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x4200 + ((_n) * 4)))
#define rAIC_WHOAMI_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5000 + ((_n) * 0x80)))
#define rAIC_IACK_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5004 + ((_n) * 0x80)))
#define rAIC_IPI_SET_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5008 + ((_n) * 0x80)))
#define rAIC_IPI_CLR_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x500C + ((_n) * 0x80)))
#define rAIC_TMR_CFG_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5010 + ((_n) * 0x80)))
#define rAIC_TMR_CNT_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5014 + ((_n) * 0x80)))
#define rAIC_TMR_ISR_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5018 + ((_n) * 0x80)))
#define rAIC_TMR_ST_SET_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x501C + ((_n) * 0x80)))
#define rAIC_TMR_ST_CLR_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5020 + ((_n) * 0x80)))
#define rAIC_IPI_MASK_SET_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5024 + ((_n) * 0x80)))
#define rAIC_IPI_MASK_CLR_Pn(_n) (*(volatile u_int32_t *)(AIC_BASE_ADDR + 0x5028 + ((_n) * 0x80)))
#define kAIC_INT_SPURIOUS (0x00000)
#define kAIC_INT_EXT (0x10000)
#define kAIC_INT_IPI (0x40000)
#define kAIC_INT_IPI_NORM (0x40001)
#define kAIC_INT_IPI_SELF (0x40002)
#define kAIC_INT_TMR (0x70000)
#define kAIC_INT_PVT_TMR (0x70001)
#define kAIC_INT_EXT_TMR (0x70002)
#define kAIC_INT_SW_TMR (0x70004)
#define AIC_INT_EXT(_v) (((_v) & 0x70000) == kAIC_INT_EXT)
#define AIC_INT_IPI(_v) (((_v) & 0x70000) == kAIC_INT_IPI)
#define AIC_INT_TMR(_v) (((_v) & 0x70000) == kAIC_INT_TMR)
#define AIC_INT_EXTID(_v) ((_v) & 0x1FF)
#define AIC_SRC_TO_EIR(_s) ((_s) >> 5)
#define AIC_SRC_TO_MASK(_s) (1 << ((_s) & 0x1F))
#define kAIC_MAX_EXTID (AIC_INT_COUNT)
#define kAIC_VEC_IPI (kAIC_MAX_EXTID)
#define kAIC_VEC_TMR (kAIC_MAX_EXTID + 1)
#define kAIC_VEC_SW_TMR (kAIC_VEC_TMR + 1)
#define kAIC_NUM_INTS (kAIC_VEC_SW_TMR + 1)
#define kAIC_NUM_EIRS AIC_SRC_TO_EIR(kAIC_MAX_EXTID)
#if AIC_VERSION < 1
#define kAIC_NUM_TMRS (3)
#endif // AIC_VERSION < 1
#endif /* ! __PLATFORM_SOC_AIC_H */
+34
View File
@@ -0,0 +1,34 @@
# Copyright (C) 2009-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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_HW_AIC=1
ifneq ($(PLATFORM_VARIANT),Audio)
OPTIONS += \
WITH_AIC_INTERRUPTS=1
endif
ifeq ($(HW_TIMER),)
OPTIONS += \
WITH_HW_TIMER=1
ifneq ($(PLATFORM_VARIANT),Audio)
OPTIONS += \
WITH_AIC_TIMERS=1
endif
endif
ALL_OBJS += $(LOCAL_DIR)/aic.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+790
View File
@@ -0,0 +1,790 @@
/*
* Copyright (C) 2009-2014 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/amc/amc.h>
#include <drivers/amc/amc_phy.h>
#include <drivers/amc/amc_regs.h>
#include <drivers/dram.h>
#include <drivers/miu.h>
#include <lib/env.h>
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include <platform/memmap.h>
#include <platform/timer.h>
#include <sys.h>
#include <string.h>
#include <target.h>
// if there are separate ap/dev parameters, amc_init will copy
// the appropriate ones here
#if AMC_PARAMS_AP_DEV
static struct amc_param amc_params;
#endif
static bool amc_params_initialized;
static const struct amc_channel_addrs {
volatile uint32_t *rnkcfg;
volatile uint32_t *mrcmd;
volatile uint32_t *mrstatus;
uint32_t mrpoll;
uint32_t mrshift;
volatile uint32_t *initcmd;
volatile uint32_t *initstatus;
uint32_t mcuen;
} _amc_chregs[] = {
{ &rAMC_CH0RNKCFG0, &rAMC_CH0MRCMD, &rAMC_CH01MRSTATUS, 0x01, 8, &rAMC_CH0INITCMD, &rAMC_CH01INITSTATUS, 0x0001 },
{ &rAMC_CH1RNKCFG0, &rAMC_CH1MRCMD, &rAMC_CH01MRSTATUS, 0x10, 16, &rAMC_CH1INITCMD, &rAMC_CH01INITSTATUS, 0x0100 },
{ &rAMC_CH2RNKCFG0, &rAMC_CH2MRCMD, &rAMC_CH23MRSTATUS, 0x01, 8, &rAMC_CH2INITCMD, &rAMC_CH23INITSTATUS, 0x0010 },
{ &rAMC_CH3RNKCFG0, &rAMC_CH3MRCMD, &rAMC_CH23MRSTATUS, 0x10, 16, &rAMC_CH3INITCMD, &rAMC_CH23INITSTATUS, 0x1000 },
};
static struct amc_memory_device_info _amc_device_info;
static bool _amc_device_info_inited;
// Local static functions
static uint32_t amc_odd_parity(uint32_t input);
/*
* Based on H4P/H4G AMC UM 0.63, H4 Tunables 0.36,
* H5P/Bali AMC UM 0.48, H5P/Bali Tunables 0.63
* Alcatraz AMC Init.html (A0: AMC: 3.53.5 AMP: 2.13.0 (v22). B0: 3.56.4 AMP: 2.13.1 (v76))
* Alcatraz A0 AMC Tunables dated Dec 8, 2012
* M7 AMC Init.html (AMC: 12.3.0 AMP: 5.7.0, dated Wed Mar 11 17:47:57 2014, Tunables as of Apr 9, 2014)
*/
void amc_mrcmd(amc_mrcmd_op_t op, uint8_t channels, uint8_t ranks, int reg, uintptr_t val)
{
uint8_t ch, r;
for (ch = 0; ch < channels; ch++) {
for (r = 0; r < ranks; r++) {
amc_mrcmd_to_ch_rnk(op, ch, r, reg, val);
}
}
}
// Only send the cmd to specific channel and rank (used during calibration on H6 and later)
void amc_mrcmd_to_ch_rnk(amc_mrcmd_op_t op, uint8_t channel, uint8_t rank, int32_t reg, uintptr_t val)
{
uint32_t cmd, regval;
uint8_t *buffer = (uint8_t *) val;
if (op == MR_READ)
cmd = 0x00000011 | (reg << 8);
else
cmd = 0x00000001 | (reg << 8) | (((uint32_t)val) << 24);
*_amc_chregs[channel].mrcmd = cmd | (rank << 16);
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
#if AMC_REG_VERSION > 2
platform_memory_barrier();
#endif
while(((regval = *_amc_chregs[channel].mrstatus) & _amc_chregs[channel].mrpoll) != 0) ;
if (op == MR_READ)
*buffer++ = (regval >> _amc_chregs[channel].mrshift) & 0xff;
}
void amc_enable_autorefresh(void)
{
// Configure auto-refresh. Freq0 has the auto-refresh enable, so do it last.
rAMC_AREFEN_FREQ(1) = 0x00000000 | amc_params.aref_freq1;
rAMC_AREFEN_FREQ(2) = 0x00000000;
rAMC_AREFEN_FREQ(3) = 0x00000000;
rAMC_AREFEN_FREQ(0) = 0x01011001 | amc_params.aref_freq0;
}
void amc_configure_default_address_decoding_and_mapping(void)
{
rAMC_ADDRCFG = 0x00020101; // Default: 2Gb geometry: 9col, 14row, 8bank
if (AMC_NUM_RANKS > 1)
rAMC_ADDRCFG |= 0x01000000; // 2rank
rAMC_CHNLDEC = 0x00040000 | amc_params.chnldec; // 2Gb/channel, interleaved
#if AMC_REG_VERSION < 3 && !SUB_PLATFORM_S7002
if (amc_params.chnldec2)
rAMC_CHNLDEC2 = amc_params.chnldec2;
if (amc_params.chnldec4)
rAMC_CHNLDEC4 = amc_params.chnldec4;
#endif
rAMC_ADDRMAP_MODE = 2; // RIBI2
#if AMC_REG_VERSION < 3 && !SUB_PLATFORM_S7002
if (amc_params.flags & FLAG_AMC_PARAM_MRR_BIT_SWIZZLE)
rAMC_PHYMRRDATADQBITMUX = 0x56714230;
if (amc_params.flags & FLAG_AMC_PARAM_MRR_BYTE_SWIZZLE)
rAMC_PHYMRRDATADQBYTEMUX = 0x2;
#endif
}
int32_t amc_init(bool resume)
{
uint8_t config_id = 0;
uint32_t tREFi;
uint64_t deadline;
uint32_t ch, r, i;
#if AMC_PARAMS_AP_DEV
if (target_config_dev()) {
memcpy(&amc_params, &amc_params_dev, sizeof(amc_params));
} else {
memcpy(&amc_params, &amc_params_ap, sizeof(amc_params));
}
#endif
amc_params_initialized = true;
#if (AMC_REG_VERSION == 2 && SUB_PLATFORM_S7002)
clocks_set_performance(kPerformanceMemoryLow);
#else
// Make sure we're at full memory frequency
clocks_set_performance(kPerformanceMemoryFull);
#endif
// The clock_reset_device() call takes care of the requirements in <rdar://problem/7269959>
clock_reset_device(CLK_MCU);
// Keep track of 50us after MCU reset to ensure resume timing is in spec
deadline = timer_get_ticks() + timer_usecs_to_ticks(50);
//////////////////////////////////////////////////////////
//
// 1. AMC initial configuration
//
//////////////////////////////////////////////////////////
amc_phy_enable_dqs_pulldown(false);
tREFi = amc_params.tREFi;
for (i = 0; i < AMC_FREQUENCY_SLOTS; i++) {
rAMC_CAS_FREQ(i) = amc_params.freq[i].cas;
rAMC_PCH_FREQ(i) = amc_params.freq[i].pch;
rAMC_ACT_FREQ(i) = amc_params.freq[i].act;
rAMC_AUTO_FREQ(i) = amc_params.freq[i].autoref | ((i == 0) ? tREFi : 0);
rAMC_SELF_FREQ(i) = amc_params.freq[i].selfref;
rAMC_MODE_FREQ(i) = amc_params.freq[i].modereg;
rAMC_MIFCASSCH_FREQ(i) = amc_params.freq[i].mifcassch;
}
#if (AMC_REG_VERSION == 2 && SUB_PLATFORM_S7002)
rAMC_TREFBWBASECYC_FREQ(0) = amc_params.freq[0].trefbwbasecyc;
rAMC_TREFBWBASECYC_FREQ(1) = amc_params.freq[1].trefbwbasecyc;
rAMC_TREFBWBASECYC_FREQ(2) = amc_params.freq[2].trefbwbasecyc;
#endif
rAMC_LAT = (amc_params.rdlat << 16) | (amc_params.wrlat << 8);
rAMC_PDN = amc_params.pdn;
rAMC_DERATE = amc_params.derate;
rAMC_RD = amc_params.read;
if (amc_params.flags & FLAG_AMC_PARAM_BUSTAT23) {
rAMC_BUSTAT_FREQ01 = amc_params.bustat;
rAMC_BUSTAT_FREQ23 = amc_params.bustat2;
} else {
rAMC_BUSTAT = amc_params.bustat;
}
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
for (r = 0; r < AMC_NUM_RANKS; r++)
*(_amc_chregs[ch].rnkcfg + AMC_RNKCFG_OFFSET(r)) = 1;
rAMC_PHYRDWRTIM = (amc_params.phywrlat << 16) | (amc_params.phyrdlat << 8) | (amc_params.rdlat - 2);
rAMC_PWRMNGTEN = amc_params.pwrmngten_default;
rAMC_SCHEN = amc_params.schen_default; // disable the scheduler
rAMC_MCPHY_UPDTPARAM = amc_params.mcphyupdate;
#if (AMC_REG_VERSION == 3) || (AMC_REG_VERSION == 2 && SUB_PLATFORM_S7002)
rAMC_MCPHY_UPDTPARAM1 = amc_params.mcphyupdate1;
#endif
if (amc_params.autoref_params)
rAMC_AUTOREF_PARAMS = amc_params.autoref_params;
amc_configure_address_decoding_and_mapping();
// Enable MCUs
rAMC_AMCEN = (amc_params.flags & FLAG_AMC_PARAM_LEGACY) ? 0x80000000 : 0;
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
#if AMC_REG_VERSION > 2
platform_memory_barrier();
#endif
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
rAMC_AMCEN |= _amc_chregs[ch].mcuen;
// Enable AIU, if supported
if (amc_params.flags & FLAG_AMC_PARAM_ENABLE_AIU)
rAMC_AMCEN |= 0x10000;
//////////////////////////////////////////////////////////
//
// 2. PHY Initial Configuartions
//
//////////////////////////////////////////////////////////
#ifdef AMP_SWIZZLE
#if (AMP_SWIZZLE == AMP_SWIZZLE_PER_J34M) // per <rdar://15498696>
// Set up the MRR Bit Mapping Muxen
rAMC_PHYMRRDATADQBYTEMUX = 0x00000002;
rAMC_PHYMRRDATADQBITMUX = 0x76543210;
#endif
#endif
amc_phy_init(resume);
//////////////////////////////////////////////////////////
//
// 3. Self-Refresh and DRAM Reset
//
//////////////////////////////////////////////////////////
#if (AMC_REG_VERSION == 3) || ((AMC_REG_VERSION == 2) && SUB_PLATFORM_S7002)
rAMC_AREFPARAM = amc_params.freq[0].arefparam;
for (i = 1; i < AMC_FREQUENCY_SLOTS; i++) {
rAMC_AREFPARAM_FREQ(i) = amc_params.freq[i].arefparam;
}
#else
rAMC_AREFPARAM = 0x00060532 | amc_params.arefparam;
#endif
#if !((AMC_REG_VERSION == 2) && SUB_PLATFORM_S7002)
amc_enable_slow_boot(true);
#endif
// <rdar://problem/8082114> <rdar://problem/8222443>
// <rdar://problem/8080928> <rdar://problem/8711948>
rAMC_LONGSR = 0x00000000;
#if (AMC_REG_VERSION == 3) || ((AMC_REG_VERSION == 2) && SUB_PLATFORM_S7002)
rAMC_LONGSR = 0x01000000 | amc_params.longsrcnt | amc_params.srextrarefcnt;
#endif
if (resume) {
// Enable temperature based refresh rate modulation to compensate for missing refresh
if (amc_params.odts) {
#if SUPPORT_FPGA
rAMC_ODTS = amc_params.odts;
#else
rAMC_ODTS = 0x00010000 | amc_params.odts;
#endif
}
amc_enable_autorefresh();
// Software must guarantee that at least 50 us have passed since the de-assertion
// of AMC reset before self-refresh exit, in the resume-boot case.
while (deadline > timer_get_ticks()) ;
}
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
*_amc_chregs[ch].initcmd = 0x00001000; // start self-refresh exit seq on ch
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
#if AMC_REG_VERSION > 2
platform_memory_barrier();
#endif
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
while (*_amc_chregs[ch].initcmd != 0) ;
#if AMC_REG_VERSION < 3 && !SUB_PLATFORM_S7002
rAMC_AREFPARAM = 0x00020532 | amc_params.arefparam;
rAMC_LONGSR = 0x05000000 | amc_params.longsrcnt | amc_params.srextrarefcnt;
#endif
//////////////////////////////////////////////////////////
//
// 4. DRAM Reset, ZQ Calibration & Configuration (cold boot only)
//
//////////////////////////////////////////////////////////
if (!resume) {
spin(200);
// MR63 (DRAM reset and auto-refresh enable)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x3f, amc_params.mr63);
spin(12);
// MR10 (ZQ initial calibration)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0xa, 0xff);
spin(1);
// MR2 register (read/write latency, assumes legal combo in amc_params)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x2, (amc_params.mr2 ? amc_params.mr2 : (amc_params.rdlat - 2)));
}
// Read device info: vendor, revision, and configuration info
// Configuration info: device width, device type, device density
// We are assuming all of our devices are identical
amc_mrcmd(MR_READ, 1, 1, 0x5, (uintptr_t)&_amc_device_info.vendor_id);
amc_mrcmd(MR_READ, 1, 1, 0x6, (uintptr_t)&_amc_device_info.rev_id);
amc_mrcmd(MR_READ, 1, 1, 0x7, (uintptr_t)&_amc_device_info.rev_id2);
amc_mrcmd(MR_READ, 1, 1, 0x8, (uintptr_t)&config_id);
if ((_amc_device_info.vendor_id == 0) || (config_id == 0))
panic("failed to read vendor-id/config-id, vid:%08x, config:%08x, rev:%08x\n", _amc_device_info.vendor_id,
config_id, _amc_device_info.rev_id);
_amc_device_info.width = (32 >> ((config_id >> JEDEC_MR8_WIDTH_SHIFT) & JEDEC_MR8_WIDTH_MASK)) >> 3;
_amc_device_info.density = ((config_id >> JEDEC_MR8_DENSITY_SHIFT) & JEDEC_MR8_DENSITY_MASK);
_amc_device_info.type = ((config_id >> JEDEC_MR8_TYPE_SHIFT) & JEDEC_MR8_TYPE_MASK);
_amc_device_info_inited = true;
dprintf(DEBUG_INFO, "sdram vendor id:0x%02x rev id:0x%02x rev id2:%02x\n",
_amc_device_info.vendor_id, _amc_device_info.rev_id, _amc_device_info.rev_id2);
dprintf(DEBUG_INFO, "sdram config: width %d/%d Mbit/type %d\n", _amc_device_info.width << 3,
64 << _amc_device_info.density, _amc_device_info.type);
if ((_amc_device_info.density < JEDEC_DENSITY_1Gb) || (_amc_device_info.density > JEDEC_DENSITY_4Gb))
panic("unsupported DRAM density: %dMbit", 64 << _amc_device_info.density);
if (!resume) {
// MR1 (nWR=pch_freq0.tWRCyc), WC=wrap, BT=Seq, BL=16)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x1,
(amc_params.mr1 ? amc_params.mr1 :
(((amc_params.freq[0].pch - 0x200) & 0xf00) >> 3) | 0x04));
// MR3 register (output buffer drive strength 48-Ohm unless overridden)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x3, (amc_params.mr3 ? amc_params.mr3 : 0x3));
}
// DRAM vendor-specific workarounds
amc_dram_workarounds(resume);
//////////////////////////////////////////////////////////
//
// 5. Topology-specific AMC re-configuration
//
//////////////////////////////////////////////////////////
if (amc_params.flags & FLAG_AMC_PARAM_RECONFIG) {
uint8_t num_banks;
num_banks = 8;
if (((_amc_device_info.type == JEDEC_TYPE_S4_SDRAM) && (_amc_device_info.density <= JEDEC_DENSITY_512Mb)) ||
((_amc_device_info.type == JEDEC_TYPE_S2_SDRAM) && (_amc_device_info.density <= JEDEC_DENSITY_2Gb)))
num_banks = 4;
if (_amc_device_info.density == JEDEC_DENSITY_1Gb) {
if (_amc_device_info.type == JEDEC_TYPE_S4_SDRAM)
rAMC_AUTO_FREQ(0) = amc_params.freq[0].autoref | amc_params.tREFi_1Gb;
rAMC_LONGSR = 0x05010000 | amc_params.longsrcnt_1Gb | amc_params.srextrarefcnt;
if ((AMC_NUM_RANKS == 1) && (num_banks == 8)) {
rAMC_CHNLDEC &= ~(7 << 16);
rAMC_CHNLDEC |= 0x00030000; // 1Gb/channel, interleaved
rAMC_ADDRCFG = 0x00010101;
}
}
else if (_amc_device_info.density == JEDEC_DENSITY_4Gb) {
if ((AMC_NUM_RANKS == 1) && (num_banks == 8)) {
rAMC_CHNLDEC &= ~(7 << 16);
rAMC_CHNLDEC |= 0x00050000; // 4Gb/channel, interleaved
rAMC_ADDRCFG = 0x00020201;
}
}
if (AMC_NUM_CHANNELS == 1) {
switch(_amc_device_info.density) {
case JEDEC_DENSITY_2Gb:
rAMC_CHNLDEC |= 0x00000001; // 2Gb/channel, stacked
break;
case JEDEC_DENSITY_4Gb:
rAMC_CHNLDEC &= ~(7 << 16);
rAMC_CHNLDEC |= 0x00050001; // 4Gb/channel, stacked
break;
case JEDEC_DENSITY_1Gb:
rAMC_CHNLDEC &= ~(7 << 16);
rAMC_CHNLDEC |= 0x00030001; // 1Gb/channel, stacked
break;
}
}
}
// For Alcatraz and later, we can configure the total memory size register dynamically
#if AMC_REG_VERSION > 2
uint32_t device_size_Mbits = 64 << _amc_device_info.density;
uint32_t total_size_Mbytes = (AMC_NUM_CHANNELS * AMC_NUM_RANKS * device_size_Mbits) >> 3;
// Units of 128 MBs in the register
rMCC_DRAMACCCTRL = (total_size_Mbytes >> 7) - 1;
dprintf(DEBUG_INFO, "rMCC_DRAMACCCTRL: 0x%08x, memory_size: %u bytes\n", rMCC_DRAMACCCTRL, (total_size_Mbytes << 20));
#endif
if (amc_params.flags & FLAG_AMC_PARAM_ZQCL) {
if (resume) {
uint8_t temp;
rAMC_ZQC = 0x00090000;
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0xa, 0xab);
spin(1);
rAMC_ZQC = 0x00080000;
// MR4 read to bring memory out of self-refresh
amc_mrcmd(MR_READ, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x4, (uintptr_t)&temp);
}
// Wait 5 us before freq change to make sure all refreshes have been flushed
spin(5);
}
//////////////////////////////////////////////////////////
//
// 6. Switch from boot-clock speed to normal speed
//
//////////////////////////////////////////////////////////
#if !SUPPORT_FPGA
// Only enable AutoSR on pre-H6 devices
#if AMC_REG_VERSION < 3 && !SUB_PLATFORM_S7002
rAMC_PWRMNGTEN |= 0x00000010;
#endif
#endif // !SUPPORT_FPGA
rAMC_SCHEN = amc_params.schen_default | 0x1; // enable the scheduler
amc_enable_slow_boot(false);
amc_phy_enable_dqs_pulldown(true);
//////////////////////////////////////////////////////////
//
// 7. PHY DQ and address timing calibration
//
//////////////////////////////////////////////////////////
#if !SUPPORT_FPGA
rAMC_READ_LEVELING = amc_params.readleveling;
#endif // !SUPPORT_FPGA
amc_phy_calibration_ca_rddq_cal(resume);
//////////////////////////////////////////////////////////
//
// 8. Enable power saving and other features, and turn on AMC scheduler
//
//////////////////////////////////////////////////////////
amc_finalize(resume);
amc_phy_finalize();
#if AMC_REG_VERSION < 3 && !SUB_PLATFORM_S7002
// Program tunables
for (i = 0; i < sizeof(amc_tunables) / sizeof(amc_tunables[0]); i++) {
if (amc_tunables[i].reg == 0)
break;
*amc_tunables[i].reg = amc_tunables[i].value;
}
#endif
//////////////////////////////////////////////////////////
//
// 9. PHY write DQ calibration
//
//////////////////////////////////////////////////////////
amc_phy_calibration_wrdq_cal(resume);
#if (AMC_REG_VERSION == 3) || ((AMC_REG_VERSION == 2) && SUB_PLATFORM_S7002)
// <rdar://problem/13752969> requires moving MR4 from step 8 to after wrdqcal
if (!resume) {
// MR4 to bring memory out of self-refresh
uint8_t odts;
amc_mrcmd(MR_READ, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x4, (uintptr_t)&odts);
}
// Program tunables after wrdqcal for H6
for (i = 0; i < sizeof(amc_tunables) / sizeof(amc_tunables[0]); i++) {
if (amc_tunables[i].reg == 0)
break;
*amc_tunables[i].reg = amc_tunables[i].value;
}
#endif
// cache memory info for later
platform_set_memory_info(_amc_device_info.vendor_id, amc_get_memory_size());
return 0;
}
void mcu_late_init(void)
{
}
uint64_t amc_get_memory_size(void)
{
// if memory is not inited, density is unknown, spin here ...
if (false == _amc_device_info_inited)
for(;;) ;
// device density (in MBytes) * num of channels * num of ranks
return ((8 << _amc_device_info.density) * AMC_NUM_CHANNELS * AMC_NUM_RANKS);
}
const struct amc_memory_device_info *amc_get_memory_device_info(void)
{
// if memory is not inited, device info is unknown, spin here ...
if (false == _amc_device_info_inited)
for(;;) ;
return ((const struct amc_memory_device_info *)&_amc_device_info);
}
const struct amc_param *amc_get_params(void)
{
ASSERT(amc_params_initialized);
return &amc_params;
}
void amc_scheduler_en_workaround(bool init)
{
if (init) {
uint8_t temp[AMC_NUM_CHANNELS];
rAMC_PWRMNGTEN = 0x00000000;
amc_mrcmd(MR_READ, AMC_NUM_CHANNELS, 1, 0x4, (uintptr_t)temp);
} else {
rAMC_PWRMNGTEN = 0x00000010;
}
}
// H6 and M7 specific routine used during dynamic calibration
#if (AMC_REG_VERSION == 3) || ((AMC_REG_VERSION == 2) && SUB_PLATFORM_S7002)
// returns 1 if number of 1s in input is odd, otherwise returns 0
static uint32_t amc_odd_parity(uint32_t input)
{
uint32_t output = input;
output = (output & 0x0000ffff) ^ (output >> 16);
output = (output & 0x000000ff) ^ (output >> 8);
output = (output & 0x0000000f) ^ (output >> 4);
output = (output & 0x00000003) ^ (output >> 2);
output = (output & 0x00000001) ^ (output >> 1);
return output;
}
// Given ch, rnk, bank, row, and col, compute the Apple Fabric address that CPU can use to do reads/writes
// For details of addr mapping, see "Address_Unamp.xls" at
// https://seg-fijipublic.ecs.apple.com/doc/release/index.php?dir=/reference/org-seg-services-vhost-seg--fijipublic.ecs.apple.com/content/doc/release/specs/Apple_IP/AMC
addr_t amc_get_uncached_dram_virt_addr(uint32_t ch, uint32_t rnk, uint32_t bank, uint32_t row, uint32_t col)
{
addr_t system_addr;
uint32_t ch_dropped_addr, ch_inserted_val;
uint32_t col_val;
uint32_t rank_off, bank_off, row_off, col_off;
uint32_t temp_bank_bit2, temp_bank_bit1, temp_bank_bit0;
uint32_t rank_wid, bank_wid, row_wid, col_wid;
uint32_t addrcfg = rAMC_ADDRCFG;
uint32_t ch_insert_point, ch_insert_width, ch_insert_mask;
uint32_t addrmapmode = rAMC_ADDRMAP_MODE;
#if AMC_REG_VERSION < 3
uint32_t addrbankhash0 = rAMC_AIU_ADDRBANKHASH0;
uint32_t addrbankhash1 = rAMC_AIU_ADDRBANKHASH1;
uint32_t addrbankhash2 = rAMC_AIU_ADDRBANKHASH2;
#else
uint32_t addrbankhash0 = rAMC_MCSADDRBNKHASH(0);
uint32_t addrbankhash1 = rAMC_MCSADDRBNKHASH(1);
uint32_t addrbankhash2 = rAMC_MCSADDRBNKHASH(2);
#endif
uint32_t chnldec = rAMC_CHNLDEC;
uint32_t amcen = rAMC_AMCEN;
#if AMC_REG_VERSION < 3
uint32_t temp_ch_bit0, temp_ch_bit1;
bool h4p_legacy_mode = amcen & 0x80000000;
#endif
system_addr = SDRAM_BASE_UNCACHED;
/*
DRAM Address Mapping Mode (H6 and M7 uses RIBI2)
RSBS: 0 Rank Stacked, Bank Stacked. {CS, BA, RA, CA}
RIBI1: 1 Rank Interleaved, Bank Interleaved, Option 1. {RA, CA-high, CS, BA, CA-low(128B)}
RIBI2: 2 Rank Interleaved, Bank Interleaved, Option 2. {RA, CS, BA, CA}
RSBI1: 3 Rank Stacked, Bank Interleaved, Option 1. {CS, RA, CA-high, BA, CA-low(128B)}
RIBI3: 4 Rank Interleaved, Bank Interleaved, Option 3. {RA, CS, CA-high, BA, CA-low(128B)}
*/
/*
BnkAddrWid
2-bits: 0
3-bits: 1 (H6)
ColAddrWid
8-bits: 0
9-bits: 1
10-bits: 2 (H6)
11-bits: 3
RowAddrWid
12-bits: 0
13-bits: 1
14-bits: 2 (H6)
15-bits: 3
CsWid
0-bits: 0 (N51)
1-bits: 1 (J71)
*/
// whether rank needs a bit depends on ADDRCFG.CSWID bit
rank_wid = ((addrcfg >> 24) & 1);
// rest of the bit widths also depend on ADDRCFG fields
bank_wid = (addrcfg & 1) + 2;
row_wid = ((addrcfg >> 16) & 0x3) + 12;
col_wid = ((addrcfg >> 8) & 0x3) + 8;
// column bits always start at bit 2 (each [row, col] specifies 4 bytes)
col_off = 2;
// these are used in addressing modes 1, 3, and 4
uint32_t col_low_bits = 5; // 128B - 2
uint32_t col_low_mask = (1 << col_low_bits) - 1;
switch(addrmapmode)
{
case 0:
col_val = col;
row_off = col_off + col_wid;
bank_off = row_off + row_wid;
rank_off = bank_off + bank_wid;
break;
case 1:
col_val = ((col & ~col_low_mask) << (rank_wid + bank_wid)) | (col & col_low_mask);
bank_off = col_off + col_low_bits;
rank_off = bank_off + bank_wid;
row_off = col_off + col_wid + bank_wid + rank_wid; // slightly different due to col split
break;
default:
case 2:
// RIBI2 (H6)
col_val = col;
bank_off = col_off + col_wid;
rank_off = bank_off + bank_wid;
row_off = rank_off + rank_wid;
break;
case 3:
col_val = ((col & ~col_low_mask) << bank_wid) | (col & col_low_mask);
bank_off = col_off + col_low_bits;
row_off = col_off + col_wid + bank_wid; // slightly different due to col split
rank_off = row_off + row_wid;
break;
case 4:
col_val = ((col & ~col_low_mask) << bank_wid) | (col & col_low_mask);
bank_off = col_off + col_low_bits;
rank_off = col_off + col_wid + bank_wid; // slightly different due to col split
row_off = rank_off + rank_wid;
break;
}
// bank hashing
//
temp_bank_bit2 = amc_odd_parity(row & ~addrbankhash2);
temp_bank_bit1 = amc_odd_parity(row & ~addrbankhash1);
temp_bank_bit0 = amc_odd_parity(row & ~addrbankhash0);
bank = bank ^ ((temp_bank_bit2 << 2) | (temp_bank_bit1 << 1) | temp_bank_bit0);
// our address so far - only the channel num stuff is missing now
//
ch_dropped_addr = (rnk << rank_off) | (bank << bank_off) | (row << row_off) | (col_val << col_off);
/*
ChSelTyp
Interleaving: 0 (H6)
Stacked: 1
*/
if (chnldec & 1) {
// in stacked mode, ch will be inserted at bit 29 for H6
ch_inserted_val = ch_dropped_addr | (ch << (((chnldec >> 16) & 0x7) + 24));
}
else { // interleaving
#if AMC_REG_VERSION < 3
if (h4p_legacy_mode) {
switch((chnldec >> 8) & 0xf) {
case (1 << 0):
ch_insert_point = 6;
break;
case (1 << 1):
ch_insert_point = 8;
break;
case (1 << 2):
ch_insert_point = 10;
break;
case (1 << 3):
ch_insert_point = 12;
break;
default:
panic("AMC CHNLDEC is not programmed correctly\n");
}
}
else
#endif
{
// ch is inserted at bit 6 for interleaving
ch_insert_point = 6;
}
// ch insertion width ( 1 or 0 bits) depends on whether more than 1 channel is enabled
ch_insert_width = (amcen >> 8) & 1;
ch_insert_width += (amcen >> 12) & 1;
// now fix the address so we can reconstruct the XOR
ch_insert_mask = (1 << ch_insert_point) - 1;
ch_dropped_addr = ((ch_dropped_addr & ~ch_insert_mask) << ch_insert_width) | (ch_dropped_addr & ch_insert_mask);
// calculate the XOR value - XOR all the bits
ch_inserted_val = ch;
#if AMC_REG_VERSION < 3
if (h4p_legacy_mode) {
switch((chnldec >> 8) & 0xf) {
case (1 << 0):
ch_inserted_val ^= (ch_dropped_addr >> 6);
break;
case (1 << 1):
ch_inserted_val ^= (ch_dropped_addr >> 8);
break;
case (1 << 2):
ch_inserted_val ^= (ch_dropped_addr >> 10);
break;
case (1 << 3):
ch_inserted_val ^= (ch_dropped_addr >> 12);
break;
}
}
else {
temp_ch_bit0 = amc_odd_parity(ch_inserted_val & (rAMC_CHNLDEC2 & 0x3ffffff));
temp_ch_bit1 = amc_odd_parity(ch_inserted_val & (rAMC_CHNLDEC4 & 0x3ffffff));
ch_inserted_val = (temp_ch_bit1 << 1) | temp_ch_bit0;
}
#else
ch_inserted_val |= (ch_dropped_addr >> ch_insert_point);
ch_inserted_val = amc_odd_parity(ch_inserted_val & rMCC_MCUCHNHASH);
#endif
// finally, insert the XOR bits
ch_insert_mask = (1 << ch_insert_width) - 1; // reuse this var in a pseudo-related way
ch_inserted_val = ch_dropped_addr | ((ch_inserted_val & ch_insert_mask) << ch_insert_point);
}
system_addr += (addr_t) ch_inserted_val;
return system_addr;
}
#endif // AMC_REG_VERSION > 2
+660
View File
@@ -0,0 +1,660 @@
/*
* Copyright (C) 2013-2014 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/amc/amc.h>
#include <drivers/amc/amc_phy.h>
#include <drivers/amc/amc_regs.h>
#include <drivers/dram.h>
#include <drivers/miu.h>
#include <lib/env.h>
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include <platform/chipid.h>
#include <platform/memmap.h>
#include <platform/timer.h>
#include <sys.h>
#include <string.h>
#include <target.h>
// if there are separate ap/dev parameters, amc_init will copy
// the appropriate ones here
#if AMC_PARAMS_AP_DEV
static struct amc_param amc_params;
#endif
static bool amc_params_initialized;
static const struct amc_channel_addrs {
volatile uint32_t *rnkcfg;
volatile uint32_t *mrcmd;
volatile uint32_t *mrstatus;
uint32_t mrpoll;
uint32_t mrshift;
volatile uint32_t *initcmd;
volatile uint32_t *initstatus;
uint32_t mcuen;
} _amc_chregs[] = {
{ &rAMC_CH0RNKCFG0, &rAMC_CH0MRCMD, &rAMC_CH01MRSTATUS, 0x01, 8, &rAMC_CH0INITCMD, &rAMC_CH01INITSTATUS, 0x0001 },
{ &rAMC_CH1RNKCFG0, &rAMC_CH1MRCMD, &rAMC_CH01MRSTATUS, 0x10, 16, &rAMC_CH1INITCMD, &rAMC_CH01INITSTATUS, 0x0100 },
{ &rAMC_CH2RNKCFG0, &rAMC_CH2MRCMD, &rAMC_CH23MRSTATUS, 0x01, 8, &rAMC_CH2INITCMD, &rAMC_CH23INITSTATUS, 0x0010 },
{ &rAMC_CH3RNKCFG0, &rAMC_CH3MRCMD, &rAMC_CH23MRSTATUS, 0x10, 16, &rAMC_CH3INITCMD, &rAMC_CH23INITSTATUS, 0x1000 },
};
static struct amc_memory_device_info _amc_device_info;
static bool _amc_device_info_inited;
/*
* Based on Fiji AMC Init.html (v48 - dated May 23, 2014). Tunables v7.1.0
* Capri AMC Init.html (v23 - dated May 23, 2014). Tunables v8.6.0
* j42d and j96 AMC Init.2GB.html (v48 - dated Dec 11, 2014)
*/
void amc_mrcmd(amc_mrcmd_op_t op, uint8_t channels, uint8_t ranks, int reg, uintptr_t val)
{
uint8_t ch, r;
for (ch = 0; ch < channels; ch++) {
for (r = 0; r < ranks; r++) {
amc_mrcmd_to_ch_rnk(op, ch, r, reg, val);
}
}
}
// Only send the cmd to specific channel and rank (used during calibration on H6 and later)
void amc_mrcmd_to_ch_rnk(amc_mrcmd_op_t op, uint8_t channel, uint8_t rank, int32_t reg, uintptr_t val)
{
uint32_t cmd, regval;
uint8_t *buffer = (uint8_t *) val;
if (op == MR_READ)
cmd = 0x00000011 | (reg << 8);
else
cmd = 0x00000001 | (reg << 8) | (((uint32_t)val) << 24);
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
platform_memory_barrier();
*_amc_chregs[channel].mrcmd = cmd | (rank << 16);
while(((regval = *_amc_chregs[channel].mrstatus) & _amc_chregs[channel].mrpoll) != 0) ;
if (op == MR_READ)
*buffer++ = (regval >> _amc_chregs[channel].mrshift) & 0xff;
}
void amc_enable_autorefresh(void)
{
// Configure auto-refresh. Freq0 has the auto-refresh enable, so do it last.
rAMC_AREFEN_FREQ(3) = 0x00000000;
rAMC_AREFEN_FREQ(2) = 0x00000000;
rAMC_AREFEN_FREQ(1) = 0x00000000;
rAMC_AREFEN_FREQ(0) = 0x01011111;
}
int32_t amc_init(bool resume)
{
uint8_t config_id = 0;
uint32_t tREFi;
uint64_t deadline;
uint32_t ch, r, i;
#if AMC_PARAMS_AP_DEV
if (target_config_dev()) {
memcpy(&amc_params, &amc_params_dev, sizeof(amc_params));
} else {
memcpy(&amc_params, &amc_params_ap, sizeof(amc_params));
}
#endif
amc_params_initialized = true;
// Make sure we're at full memory frequency
clocks_set_performance(kPerformanceMemoryFull);
// The clock_reset_device() call takes care of the requirements in <rdar://problem/7269959>
clock_reset_device(CLK_MCU);
// Keep track of 50us after MCU reset to ensure resume timing is in spec
deadline = timer_get_ticks() + timer_usecs_to_ticks(50);
//////////////////////////////////////////////////////////
//
// 1. AMC initial configuration
//
//////////////////////////////////////////////////////////
rAMC_PHYUPDATETIMERS = 0x50;
amc_phy_preinit();
rAMC_LAT = amc_params.lat;
rAMC_PHYRDWRTIM = amc_params.phyrdwrtim;
tREFi = amc_params.tREFi;
for (i = 0; i < AMC_FREQUENCY_SLOTS; i++) {
rAMC_CAS_FREQ(i) = amc_params.freq[i].cas;
rAMC_PCH_FREQ(i) = amc_params.freq[i].pch;
rAMC_ACT_FREQ(i) = amc_params.freq[i].act;
rAMC_AUTO_FREQ(i) = amc_params.freq[i].autoref | ((i == 0) ? tREFi : 0);
rAMC_SELF_FREQ(i) = amc_params.freq[i].selfref;
rAMC_MODE_FREQ(i) = amc_params.freq[i].modereg;
}
rAMC_PDN = amc_params.pdn;
rAMC_DERATE = amc_params.derate;
rAMC_RD = amc_params.read;
rAMC_BUSTAT_FREQ01 = amc_params.bustat;
rAMC_BUSTAT_FREQ23 = amc_params.bustat2;
rAMC_MIFCASSCH_FREQ(0) = 0x110;
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
for (r = 0; r < AMC_NUM_RANKS; r++)
*(_amc_chregs[ch].rnkcfg + AMC_RNKCFG_OFFSET(r)) = 1;
rAMC_PWRMNGTEN = amc_params.pwrmngten_default;
rAMC_SCHEN = amc_params.schen_default; // disable the scheduler
rAMC_MCPHY_UPDTPARAM1 = amc_params.mcphyupdate1;
rAMC_MCPHY_UPDTPARAM = amc_params.mcphyupdate;
// Enable MCUs
rAMC_AMCEN = 0;
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
platform_memory_barrier();
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
rAMC_AMCEN |= _amc_chregs[ch].mcuen;
amc_configure_address_decoding_and_mapping();
//////////////////////////////////////////////////////////
//
// 2. PHY Initial Configuartions
//
//////////////////////////////////////////////////////////
amc_phy_init(resume);
//////////////////////////////////////////////////////////
//
// 3. Self-Refresh and DRAM Reset
//
//////////////////////////////////////////////////////////
// Wait 5 us after Impedence Calibration to avoid McPhyPending
// preventing the SRFSM from exiting SR.
spin(5);
amc_phy_restore_calibration_values(resume);
rAMC_AREFPARAM = amc_params.arefparam;
amc_enable_slow_boot(true);
#if !SUPPORT_FPGA
// Enable auto refresg derating by setting TempDrtEn
rAMC_ODTS = 0x00010000;
#endif
rAMC_LONGSR = amc_params.longsr;
if (resume) {
amc_enable_autorefresh();
// Software must guarantee that at least 50 us have passed since the de-assertion
// of AMC reset before self-refresh exit, in the resume-boot case.
while (deadline > timer_get_ticks()) ;
}
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
*_amc_chregs[ch].initcmd = 0x00001000; // start self-refresh exit seq on ch
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
platform_memory_barrier();
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
while (*_amc_chregs[ch].initcmd != 0) ;
//////////////////////////////////////////////////////////
//
// 4. DRAM Reset, ZQ Calibration & Configuration (cold boot only)
//
//////////////////////////////////////////////////////////
if (!resume) {
spin(200);
// MR63 (DRAM reset and auto-refresh enable)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x3f, 0xfc);
spin(12);
// MR10 (ZQ initial calibration)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0xa, 0xff);
spin(1);
// MR2 register (read/write latency, assumes legal combo in amc_params)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x2, amc_params.mr2);
// MR1
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x1, amc_params.mr1);
// MR3 register (output buffer drive strength 48-Ohm unless overridden)
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x3, (amc_params.mr3 ? amc_params.mr3 : 0x3));
}
//////////////////////////////////////////////////////////
//
// 5. Topology-specific AMC re-configuration
//
//////////////////////////////////////////////////////////
if (resume) {
rAMC_ZQC = 0x00090000;
amc_mrcmd(MR_WRITE, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0xa, 0xab);
spin(1);
rAMC_ZQC = 0x00080000;
}
rAMC_ADDRCFG = amc_params.addrcfg;
// Read device info: vendor, revision, and configuration info
// Configuration info: device width, device type, device density
// We are assuming all of our devices are identical
amc_mrcmd(MR_READ, 1, 1, 0x5, (uintptr_t)&_amc_device_info.vendor_id);
amc_mrcmd(MR_READ, 1, 1, 0x6, (uintptr_t)&_amc_device_info.rev_id);
amc_mrcmd(MR_READ, 1, 1, 0x7, (uintptr_t)&_amc_device_info.rev_id2);
amc_mrcmd(MR_READ, 1, 1, 0x8, (uintptr_t)&config_id);
#if SUPPORT_FPGA
if ((config_id == 0xff) || (config_id == 0)) {
// Fake the MR_READ results to something accurate but innocuous
config_id = (0 << JEDEC_MR8_WIDTH_SHIFT) | (5 << JEDEC_MR8_DENSITY_SHIFT) | (0 << JEDEC_MR8_TYPE_SHIFT);
_amc_device_info.vendor_id = JEDEC_MANUF_ID_RSVD2;
}
#endif
if ((_amc_device_info.vendor_id == 0) || (config_id == 0))
panic("failed to read vendor-id/config-id, vid:%08x, config:%08x, rev:%08x\n", _amc_device_info.vendor_id,
config_id, _amc_device_info.rev_id);
_amc_device_info.width = (32 >> ((config_id >> JEDEC_MR8_WIDTH_SHIFT) & JEDEC_MR8_WIDTH_MASK)) >> 3;
_amc_device_info.density = ((config_id >> JEDEC_MR8_DENSITY_SHIFT) & JEDEC_MR8_DENSITY_MASK);
_amc_device_info.type = ((config_id >> JEDEC_MR8_TYPE_SHIFT) & JEDEC_MR8_TYPE_MASK);
_amc_device_info_inited = true;
dprintf(DEBUG_INFO, "sdram vendor id:0x%02x rev id:0x%02x rev id2:%02x\n",
_amc_device_info.vendor_id, _amc_device_info.rev_id, _amc_device_info.rev_id2);
dprintf(DEBUG_INFO, "sdram config: width %d/%d Mbit/type %d\n", _amc_device_info.width << 3,
64 << _amc_device_info.density, _amc_device_info.type);
if ((_amc_device_info.density < JEDEC_DENSITY_1Gb) || (_amc_device_info.density > JEDEC_DENSITY_32Gb))
panic("unsupported DRAM density: %dMbit", 64 << _amc_device_info.density);
uint32_t device_size_Mbits = 64 << _amc_device_info.density;
uint32_t total_size_Mbytes = (AMC_NUM_CHANNELS * AMC_NUM_RANKS * device_size_Mbits) >> 3;
// Units of 128 MBs in the register
rMCC_DRAMACCCTRL = (total_size_Mbytes >> 7) - 1;
dprintf(DEBUG_INFO, "rMCC_DRAMACCCTRL: 0x%08x, memory_size: %u bytes\n", rMCC_DRAMACCCTRL, (total_size_Mbytes << 20));
rMCC_CHNLDEC = amc_params.mccchnldec;
rAMC_MCSCHNLDEC = amc_params.mcschnldec;
rMCC_MCUCHNHASH = amc_params.mcuchnhash;
if (amc_params.mcuchnhash2)
rMCC_MCUCHNHASH2 = amc_params.mcuchnhash2;
// DRAM vendor-specific workarounds
amc_dram_workarounds(resume);
//////////////////////////////////////////////////////////
//
// 6. Switch from boot-clock speed to normal speed
//
//////////////////////////////////////////////////////////
// Wait 5 us before freq change to make sure all refreshes have been flushed
spin(5);
rAMC_SCHEN = amc_params.schen_default | 0x1; // enable the scheduler
amc_phy_pre_normal_speed_enable();
amc_enable_slow_boot(false);
//////////////////////////////////////////////////////////
//
// 7. PHY DQ and address timing calibration
//
//////////////////////////////////////////////////////////
#if !SUPPORT_FPGA
rAMC_READ_LEVELING = amc_params.readleveling;
amc_phy_calibration_ca_rddq_cal(resume);
#endif // !SUPPORT_FPGA
//////////////////////////////////////////////////////////
//
// 8. Enable other features
//
//////////////////////////////////////////////////////////
rAMC_ZQC = 0x010c03ff;
rAMC_QBREN = 0x00110001;
if (!resume)
amc_enable_autorefresh();
//////////////////////////////////////////////////////////
//
// 9. Enable the Fast Critical Word Forwarding feature
//
//////////////////////////////////////////////////////////
rAMC_QBRPARAM = amc_params.qbrparam;
rAMC_QBREN = 0x00111001;
rMCC_MCCGEN = 0x00000126;
//////////////////////////////////////////////////////////
//
// 10. PHY write DQ calibration
//
//////////////////////////////////////////////////////////
#if !SUPPORT_FPGA
amc_phy_calibration_wrdq_cal(resume);
#endif
rAMC_PHYUPDATETIMERS = 0x00000f50;
//////////////////////////////////////////////////////////
//
// 11. Enable Power & ClockGating features
//
//////////////////////////////////////////////////////////
amc_phy_finalize();
amc_finalize(resume);
//////////////////////////////////////////////////////////
//
// 12. ODTS read and bring memory out of self-refresh
//
//////////////////////////////////////////////////////////
// MR4 read to bring memory out of self-refresh
uint8_t temp;
amc_mrcmd(MR_READ, AMC_NUM_CHANNELS, AMC_NUM_RANKS, 0x4, (uintptr_t)&temp);
rAMC_ODTS |= amc_params.odts;
// Program tunables at the end
for (i = 0; i < sizeof(amc_tunables) / sizeof(amc_tunables[0]); i++) {
if (amc_tunables[i].reg == 0)
break;
*amc_tunables[i].reg = amc_tunables[i].value;
}
// cache memory info for later
platform_set_memory_info(_amc_device_info.vendor_id, amc_get_memory_size());
return 0;
}
void mcu_late_init(void)
{
}
uint64_t amc_get_memory_size(void)
{
// if memory is not inited, density is unknown, spin here ...
if (false == _amc_device_info_inited)
for(;;) ;
// device density (in MBytes) * num of channels * num of ranks
return ((8 << _amc_device_info.density) * AMC_NUM_CHANNELS * AMC_NUM_RANKS);
}
const struct amc_memory_device_info *amc_get_memory_device_info(void)
{
// if memory is not inited, device info is unknown, spin here ...
if (false == _amc_device_info_inited)
for(;;) ;
return ((const struct amc_memory_device_info *)&_amc_device_info);
}
const struct amc_param *amc_get_params(void)
{
ASSERT(amc_params_initialized);
return &amc_params;
}
/*
* Some routines used during dynamic calibration
*/
// Some AMC features to be changed before calibration starts, and restored after calibration is complete
void amc_calibration_start(bool start)
{
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
platform_memory_barrier();
if (start) {
// Disable OdtsRdIntrvl
rAMC_ODTS &= 0xFFFFFC00;
} else {
// Re-enable OdtsRdIntrvl
rAMC_ODTS |= amc_params.odts;
}
}
void amc_enable_rddqcal(bool enable)
{
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
platform_memory_barrier();
if (enable) {
rAMC_READ_LEVELING |= 1;
} else {
rAMC_READ_LEVELING &= ~1;
}
}
void amc_wrdqcal_start(bool start)
{
if (start) {
// Enable WriteMergeEn and WqInOrderEn
rAMC_PSQWQCTL0 = (1 << 8) | (1 << 0);
// <rdar://problem/16239984> Alcatraz, Fiji, Capri: L2_TB: MCU PIO accesses to the same address and device stream getting reordered in CP
platform_memory_barrier();
// Set SelfRefTmrVal to max
rAMC_PWRMNGTPARAM |= (0xFFFF << 16);
// Designer suggests 0xBB, so that writes do not age out
rAMC_PSQWQCTL1 = 0xBB;
} else {
rAMC_PSQWQCTL0 = 0;
}
}
// returns 1 if number of 1s in input is odd, otherwise returns 0
static uint32_t amc_odd_parity(uint32_t input)
{
uint32_t output = input;
output = (output & 0x0000ffff) ^ (output >> 16);
output = (output & 0x000000ff) ^ (output >> 8);
output = (output & 0x0000000f) ^ (output >> 4);
output = (output & 0x00000003) ^ (output >> 2);
output = (output & 0x00000001) ^ (output >> 1);
return output;
}
// Given ch, rnk, bank, row, and col, compute the Apple Fabric address that CPU can use to do reads/writes
// For details of addr mapping, see "Address_Unamp.xls" at
// https://seg-fijipublic.ecs.apple.com/doc/release/index.php?dir=/reference/org-seg-services-vhost-seg--fijipublic.ecs.apple.com/content/doc/release/specs/Apple_IP/AMC
uint64_t amc_get_uncached_dram_virt_addr(uint32_t ch, uint32_t rnk, uint32_t bank, uint32_t row, uint32_t col)
{
uint64_t system_addr;
uint32_t ch_dropped_addr, ch_inserted_val;
uint32_t col_val;
uint32_t bank_addr_pos, col_low_bits, col_low_mask;
uint32_t rank_off, bank_off, row_off, col_off;
uint32_t temp_bank_bit2, temp_bank_bit1, temp_bank_bit0;
uint32_t rank_wid, bank_wid, row_wid, col_wid;
uint32_t addrcfg = rAMC_ADDRCFG;
uint32_t ch_insert_point, ch_insert_width, ch_insert_mask;
uint32_t addrmapmode = rAMC_ADDRMAP_MODE;
uint32_t mcsaddrbankhash0 = rAMC_MCSADDRBNKHASH(0);
uint32_t mcsaddrbankhash1 = rAMC_MCSADDRBNKHASH(1);
uint32_t mcsaddrbankhash2 = rAMC_MCSADDRBNKHASH(2);
uint32_t chnldec = rMCC_CHNLDEC;
uint32_t mcschnldec = rAMC_MCSCHNLDEC;
system_addr = SDRAM_BASE_UNCACHED;
/*
DRAM Address Mapping Mode (H7 uses RIBI1)
RSBS: 0 Rank Stacked, Bank Stacked. {CS, BA, RA, CA}
RIBI1: 1 Rank Interleaved, Bank Interleaved, Option 1. {RA, CA-high, CS, BA, CA-low(128B)}
RIBI2: 2 Rank Interleaved, Bank Interleaved, Option 2. {RA, CS, BA, CA}
RSBI1: 3 Rank Stacked, Bank Interleaved, Option 1. {CS, RA, CA-high, BA, CA-low(128B)}
RIBI3: 4 Rank Interleaved, Bank Interleaved, Option 3. {RA, CS, CA-high, BA, CA-low(128B)}
*/
/*
BnkAddrWid
2-bits: 0
3-bits: 1 (H7)
ColAddrWid
8-bits: 0
9-bits: 1
10-bits: 2 (H7)
11-bits: 3
RowAddrWid
12-bits: 0
13-bits: 1
14-bits: 2 (H7)
15-bits: 3
CsWid
0-bits: 0
1-bits: 1
*/
// whether rank needs a bit depends on ADDRCFG.CSWID bit
rank_wid = ((addrcfg >> 24) & 1);
// rest of the bit widths also depend on ADDRCFG fields
bank_wid = (addrcfg & 1) + 2;
row_wid = ((addrcfg >> 16) & 0x3) + 12;
col_wid = ((addrcfg >> 8) & 0x3) + 8;
// column bits always start at bit 2 (each [row, col] specifies 4 bytes)
col_off = 2;
bank_addr_pos = 6 + ((addrmapmode & 0x700) >> 8);
switch(addrmapmode & 1)
{
case 0:
col_val = col;
row_off = col_off + col_wid;
bank_off = row_off + row_wid;
rank_off = bank_off + bank_wid;
break;
default:
case 1:
// RIBI1 (H7)
if (bank_addr_pos == (col_wid + col_off)) {
col_val = col;
bank_off = col_off + col_wid;
rank_off = bank_off + bank_wid;
row_off = rank_off + rank_wid;
} else {
// bank bits interleaved with column bits (not POR on H7)
col_low_bits = bank_addr_pos - col_off;
col_low_mask = (1 << col_low_bits) - 1;
col_val = ((col & ~col_low_mask) << bank_wid) | (col & col_low_mask);
bank_off = bank_addr_pos;
rank_off = col_off + col_wid + bank_wid;
row_off = rank_off + rank_wid;
}
break;
}
// bank hashing
//
temp_bank_bit2 = amc_odd_parity(row & ~mcsaddrbankhash2);
temp_bank_bit1 = amc_odd_parity(row & ~mcsaddrbankhash1);
temp_bank_bit0 = amc_odd_parity(row & ~mcsaddrbankhash0);
bank = bank ^ ((temp_bank_bit2 << 2) | (temp_bank_bit1 << 1) | temp_bank_bit0);
// our address so far - only the channel num stuff is missing now
//
ch_dropped_addr = (rnk << rank_off) | (bank << bank_off) | (row << row_off) | (col_val << col_off);
/*
ChSelTyp
Interleaving: 0 (H7)
Stacked: 1
*/
if (chnldec & 1) {
// in stacked mode, ch will be inserted at bit 29 for H7
ch_inserted_val = ch_dropped_addr | (ch << (((chnldec >> 16) & 0xF) + 24));
}
else { // interleaving
// for H7, ch is inserted for interleaving at bit specified by rAMC_MCSCHNLDEC.ChnlStartBit
ch_insert_point = 6 + ((mcschnldec & 0x300) >> 8);
// ch insertion width (0, 1, 2, or 3 bits) depends on how many channels are enabled
ch_insert_width = (mcschnldec & 0x30000) >> 16;
// now fix the address so we can reconstruct the XOR
ch_insert_mask = (1 << ch_insert_point) - 1;
ch_dropped_addr = ((ch_dropped_addr & ~ch_insert_mask) << ch_insert_width) | (ch_dropped_addr & ch_insert_mask);
if (ch_insert_width <= 1) {
// calculate the XOR value - XOR all the bits (only the bits that can participate -- determined via rMCC_MCUCHNHASH)
ch_inserted_val = ch | (ch_dropped_addr >> ch_insert_point);
// now shift up the ch_inserted_val to align with rMCC_MCUCHNHASH, whose bit 0 maps to PA[6] of AF address
ch_inserted_val = amc_odd_parity((ch_inserted_val << (ch_insert_point - 6)) & rMCC_MCUCHNHASH);
} else {
// This code only handles 2 bits for channel number
if (ch_insert_width > 2)
panic("Unable to handle addressing for more than 4 channels");
// handle 2 bit channel value differently (for Capri)
uint32_t chnhash_addr = (ch << (ch_insert_point - 6) | (ch_dropped_addr >> 6));
ch_inserted_val = amc_odd_parity(chnhash_addr & rMCC_MCUCHNHASH);
ch_inserted_val |= (amc_odd_parity(chnhash_addr & rMCC_MCUCHNHASH2)) << 1;
}
// finally, insert the XOR bits
ch_insert_mask = (1 << ch_insert_width) - 1; // reuse this var in a pseudo-related way
ch_inserted_val = ch_dropped_addr | ((ch_inserted_val & ch_insert_mask) << ch_insert_point);
}
system_addr += (uint64_t) ch_inserted_val;
return system_addr;
}
// Returns number of consecutive bytes given channel and rank before channel interleaving
uint32_t amc_get_consecutive_bytes_perchnrnk(void)
{
// FIXME: DV says assume this is 0 for now (resulting in 64 consecutive bytes)
// uint32_t ch_start_bit = (rAMC_MCSCHNLDEC & 0x300) >> 8;
uint32_t ch_start_bit = 0;
// given ChnlStartBit, consecutive bytes is simply 1 << (6 + ChnlStartBit)
return (1 << (6 + ch_start_bit));
}
+576
View File
@@ -0,0 +1,576 @@
/*
* 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 <drivers/amc/amc.h>
#include <drivers/amc/amc_phy.h>
#include <drivers/dram.h>
#include <drivers/miu.h>
#include <drivers/power.h>
#include <lib/libc.h>
#include <platform/memmap.h>
#include <platform/soc/hwregbase.h>
#include <sys.h>
// Constants across phys
#define NUM_BYTES (AMC_CHANNEL_WIDTH) // channel width in words
#define RD_DQ_RETEST_COUNT (1)
#define WR_DQ_RETEST_COUNT (1)
#define BINARY_SEARCH_THRESHOLD (2)
#define INCR_SEARCH_STEP_SIZE (4)
#define WRITE_REGION_SIZE (64) // in words
#define CA_PIVOTS_LIST_MAX_SIZE (9)
#define DQ_PIVOTS_LIST_MAX_SIZE (5)
#define CA_PIVOT_THRESHOLD (2)
// Phy specific
#define CA_PIVOTS_LIST_SIZE (calibration_data->ca_pivots_list_size)
#define DQ_PIVOTS_LIST_SIZE (calibration_data->dq_pivots_list_size)
#define BIT_TIME_PS (calibration_data->bit_time_ps)
#define MIN_CA_WINDOW_WIDTH_PS (calibration_data->min_ca_window_width_ps)
#define MIN_DQ_WINDOW_WIDTH_PS (calibration_data->min_dq_window_width_ps)
#define CA_PIVOT_STEP_SIZE_PS (calibration_data->ca_pivot_step_size_ps)
#define DQ_PIVOT_STEP_SIZE_PS (calibration_data->dq_pivot_step_size_ps)
#define MAX_OFFSET_SETTING (calibration_data->max_offset_setting)
#define MIN_OFFSET_FACTOR (calibration_data->min_offset_factor)
#define DLL_F2_DELAY_FS (calibration_data->dll_f2_delay_fs)
// Macros
#define RD_WR_ADDR_OFFSET(offset) (((((offset) < 0) ? 1 : 0) << 6) | __abs((offset)))
// Local variables
static int calibration_done;
static const struct amc_phy_calibration_data *calibration_data;
static const int *ca_pivot_ps;
static const int *dq_pivot_ps;
static int ca_pivot_fs[CA_PIVOTS_LIST_MAX_SIZE] = { -1 };
static int dq_pivot_fs[DQ_PIVOTS_LIST_MAX_SIZE] = { -1 };
static int min_offset_fs = -1;
static int max_offset_fs = -1;
static int dq_pivot_step_size_fs = -1;
static int min_dq_window_width_fs = -1;
static uint32_t save_restore_region_content[WRITE_REGION_SIZE];
// Local functions
static void calibration_ca_rddq_cal_init();
static void calibration_ca_rddq_cal_finalize();
static int calibration_find_min_element(int8_t *array, uint8_t array_len);
static int calibration_binary_search_offset(uint8_t ch, uint8_t byte, int8_t sweep_lo, int8_t sweep_hi);
static int calibration_check_rddq(uint8_t ch, uint8_t byte);
static void calibration_rddq_cal(uint8_t ch, int8_t *rd_dq_offset, int8_t *rd_dq_window);
static int8_t calibration_ca_rddq_cal(uint8_t ch);
static void calibration_wrdq_cal(uint8_t ch, int8_t *wr_dq_offset, int8_t *wr_dq_window);
static void calibration_get_save_restore_region(uint8_t ch, uint32_t **region);
// External functions
extern void amc_scheduler_en_workaround(bool init);
///////////////////////////////////////////////////////////////////////////////
////// Global functions
///////////////////////////////////////////////////////////////////////////////
void amc_phy_calibration_restore_ca_offset(uint8_t ch)
{
// restore CA offsets from PMU
int8_t ca_offset;
if (power_get_nvram(kPowerNVRAMiBootMemCalCAOffset0Key + ch, (uint8_t *)&ca_offset) == -1)
for(;;) ;
amc_phy_set_addr_offset(ch, RD_WR_ADDR_OFFSET(ca_offset));
}
void amc_phy_calibration_ca_rddq_cal(bool resume)
{
uint8_t ch;
int8_t ca_offset;
if (amc_phy_rddq_cal() == true) {
calibration_done = 1;
return;
}
calibration_data = amc_phy_get_calibration_data();
ca_pivot_ps = calibration_data->ca_pivot_ps;
dq_pivot_ps = calibration_data->dq_pivot_ps;
// force resume boot flow if indicated by phy data (for AMP)
if (calibration_data->use_resume_boot_flow)
resume = true;
calibration_ca_rddq_cal_init();
if (!resume) {
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
// find offset, and save address offset to PMU
ca_offset = calibration_ca_rddq_cal(ch);
if (power_set_nvram(kPowerNVRAMiBootMemCalCAOffset0Key + ch, ca_offset) != 0)
for (;;) ;
}
}
else {
int8_t rd_dq_offset[NUM_BYTES];
int8_t rd_dq_window[NUM_BYTES];
uint8_t byte;
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
calibration_rddq_cal(ch, rd_dq_offset, rd_dq_window);
// shift it, if needed
amc_phy_shift_dq_offset(rd_dq_offset, NUM_BYTES);
for (byte = 0; byte < NUM_BYTES; byte++)
amc_phy_set_rd_offset(ch, byte, RD_WR_ADDR_OFFSET(rd_dq_offset[byte]));
amc_phy_run_dll_update(ch);
}
}
calibration_ca_rddq_cal_finalize();
}
void amc_phy_calibration_wrdq_cal(bool resume)
{
uint8_t ch;
uint32_t saved_addr_map_mode, chnselhibits;
const struct amc_memory_device_info *dev_info;
if (calibration_done)
return;
saved_addr_map_mode = 0;
// disable pulse-mode dll operation
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
amc_phy_configure_dll_pulse_mode(ch, false);
// save aiucfg.aiuchnldec
saved_addr_map_mode = *(volatile uint32_t *)(AMC_BASE_ADDR + 0x0A4);
dev_info = amc_get_memory_device_info();
if (dev_info->density == JEDEC_DENSITY_4Gb)
chnselhibits = 5;
else if (dev_info->density == JEDEC_DENSITY_2Gb)
chnselhibits = 4;
else
chnselhibits = 3;
// aiucfg.aiuchnldec = (DENSITY = 2Gb) ? 0x0004_0101) : 0x0003_0101
*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0A4) = ((chnselhibits << 16) | (1 << 8) | (1 << 0));
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
int8_t wr_dq_window[NUM_BYTES];
int8_t wr_dq_offset[NUM_BYTES];
uint8_t byte;
if (resume) {
uint32_t word;
uint32_t *region;
memset(save_restore_region_content, 0, sizeof(save_restore_region_content));
calibration_get_save_restore_region(ch, &region);
for(word = 0; word < WRITE_REGION_SIZE; word++)
save_restore_region_content[word] = *(region + word);
}
memset(wr_dq_window, 0, sizeof(wr_dq_window));
memset(wr_dq_offset, 0, sizeof(wr_dq_offset));
calibration_wrdq_cal(ch, wr_dq_offset, wr_dq_window);
// shift it, if needed
amc_phy_shift_dq_offset(wr_dq_offset, NUM_BYTES);
for (byte = 0; byte < NUM_BYTES; byte++)
amc_phy_set_wr_offset(ch, byte, RD_WR_ADDR_OFFSET(wr_dq_offset[byte]));
amc_phy_run_dll_update(ch);
if (resume) {
uint32_t word;
uint32_t *region;
calibration_get_save_restore_region(ch, &region);
for(word = 0; word < WRITE_REGION_SIZE; word++)
*(region + word) = save_restore_region_content[word];
}
}
// restore aiucfg.aiuchnldec
*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0A4) = saved_addr_map_mode;
// re-enable pulse mode
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++)
amc_phy_configure_dll_pulse_mode(ch, true);
calibration_done = 1;
}
///////////////////////////////////////////////////////////////////////////////
////// Local functions
///////////////////////////////////////////////////////////////////////////////
static void calibration_ca_rddq_cal_init()
{
uint8_t i;
uint32_t fine_lock_ps;
amc_phy_calibration_init(&fine_lock_ps);
// workaround for AMC scheduler enable issue
amc_scheduler_en_workaround(true);
max_offset_fs = __min((int)MAX_OFFSET_SETTING, ((BIT_TIME_PS / 4) / (int)fine_lock_ps));
min_offset_fs = __max(-((int)MAX_OFFSET_SETTING), (-((BIT_TIME_PS / 4) / (int)fine_lock_ps) + MIN_OFFSET_FACTOR + DLL_F2_DELAY_FS));
for (i = 0; i < CA_PIVOTS_LIST_SIZE; i++) {
if (ca_pivot_ps[i] > 0)
ca_pivot_fs[i] = __min((ca_pivot_ps[i] / (int)fine_lock_ps),
((BIT_TIME_PS / 4) / (int)fine_lock_ps));
else
ca_pivot_fs[i] = __max((ca_pivot_ps[i] / (int)fine_lock_ps),
(-((BIT_TIME_PS / 4) / (int)fine_lock_ps) + MIN_OFFSET_FACTOR + DLL_F2_DELAY_FS));
}
for (i = 0; i < DQ_PIVOTS_LIST_SIZE; i++) {
if (dq_pivot_ps[i] > 0)
dq_pivot_fs[i] = __min((dq_pivot_ps[i] / (int)fine_lock_ps),
((BIT_TIME_PS / 4) / (int)fine_lock_ps));
else
dq_pivot_fs[i] = __max((dq_pivot_ps[i] / (int)fine_lock_ps),
(-((BIT_TIME_PS / 4) / (int)fine_lock_ps) + MIN_OFFSET_FACTOR));
}
dq_pivot_step_size_fs = DQ_PIVOT_STEP_SIZE_PS / (int)fine_lock_ps;
min_dq_window_width_fs = MIN_DQ_WINDOW_WIDTH_PS / (int)fine_lock_ps;
}
static void calibration_ca_rddq_cal_finalize()
{
// workaround for AMC scheduler enable issue
amc_scheduler_en_workaround(false);
}
static int calibration_find_min_element(int8_t *array, uint8_t array_len)
{
uint8_t i;
int8_t min;
min = array[0];
for (i = 1; i < array_len; i++) {
if (array[i] < min)
min = array[i];
}
return (min);
}
static int calibration_check_rddq(uint8_t ch, uint8_t byte)
{
uint8_t byte_result;
uint8_t i;
for (i = 0; i < RD_DQ_RETEST_COUNT; i++) {
amc_phy_run_dq_training(ch);
if ((byte_result = amc_phy_get_dq_training_status(ch, byte, NUM_BYTES)) == 0)
break;
}
// '1' pass, '0' fail
return (byte_result);
}
static int calibration_binary_search_offset(uint8_t ch, uint8_t byte, int8_t sweep_lo, int8_t sweep_hi)
{
int8_t mid;
amc_phy_set_rd_offset(ch, byte, RD_WR_ADDR_OFFSET(sweep_hi));
amc_phy_run_dll_update(ch);
if (calibration_check_rddq(ch, byte) != 0)
return sweep_hi;
do {
mid = (sweep_lo + sweep_hi) / 2;
amc_phy_set_rd_offset(ch, byte, RD_WR_ADDR_OFFSET(mid));
amc_phy_run_dll_update(ch);
if (calibration_check_rddq(ch, byte) != 0)
sweep_lo = mid;
else
sweep_hi = mid;
} while (__abs(sweep_hi - sweep_lo) > BINARY_SEARCH_THRESHOLD);
return sweep_lo;
}
static void calibration_rddq_cal(uint8_t ch, int8_t *rd_dq_offset, int8_t *rd_dq_window)
{
int8_t min_pivot[NUM_BYTES];
int8_t max_pivot[NUM_BYTES];
int8_t pivot_count[NUM_BYTES];
uint8_t i, pivot, byte;
int8_t pos_sweep_hi, pos_sweep_lo, neg_sweep_hi, neg_sweep_lo;
int8_t pos_offset, neg_offset;
for (i = 0; i < NUM_BYTES; i++) {
min_pivot[i] = max_offset_fs;
max_pivot[i] = min_offset_fs;
pivot_count[i] = 0;
rd_dq_offset[i] = 0;
rd_dq_window[i] = 0;
}
for (pivot = 0; pivot < DQ_PIVOTS_LIST_SIZE; pivot++) {
for (byte = 0; byte < NUM_BYTES; byte++)
amc_phy_set_rd_offset(ch, byte, RD_WR_ADDR_OFFSET(dq_pivot_fs[pivot]));
amc_phy_run_dll_update(ch);
for (byte = 0; byte < NUM_BYTES; byte++) {
if (0 != calibration_check_rddq(ch, byte)) {
if (dq_pivot_fs[pivot] < min_pivot[byte])
min_pivot[byte] = dq_pivot_fs[pivot];
if (dq_pivot_fs[pivot] > max_pivot[byte])
max_pivot[byte] = dq_pivot_fs[pivot];
pivot_count[byte]++;
}
}
}
if (calibration_find_min_element(pivot_count, NUM_BYTES) <
(MIN_DQ_WINDOW_WIDTH_PS / DQ_PIVOT_STEP_SIZE_PS))
return;
for (byte = 0; byte < NUM_BYTES; byte++) {
pos_sweep_hi = __min(max_offset_fs, (max_pivot[byte] + dq_pivot_step_size_fs));
neg_sweep_hi = __max(min_offset_fs, (min_pivot[byte] - dq_pivot_step_size_fs));
pos_sweep_lo = (pos_sweep_hi + neg_sweep_hi) / 2;
neg_sweep_lo = pos_sweep_lo;
pos_offset = calibration_binary_search_offset(ch, byte, pos_sweep_lo, pos_sweep_hi);
neg_offset = calibration_binary_search_offset(ch, byte, neg_sweep_lo, neg_sweep_hi);
rd_dq_offset[byte] = (pos_offset + neg_offset) / 2;
rd_dq_window[byte] = __abs(pos_offset - neg_offset);
}
}
static int8_t calibration_ca_rddq_cal(uint8_t ch)
{
bool prev_ca_status; // 0: fail, 1: pass
int8_t ca_pass_count, ca_offset;
int8_t ca_weighted_offset[CA_PIVOTS_LIST_SIZE][2];
int8_t saved_rd_dq_offset[NUM_BYTES];
int8_t saved_rd_dq_window[NUM_BYTES];
int8_t rd_dq_offset[NUM_BYTES];
int8_t rd_dq_window[NUM_BYTES];
uint8_t i, byte;
int8_t min_rd_dq_window;
int32_t sum;
prev_ca_status = false;
ca_pass_count = 0;
memset(saved_rd_dq_offset, 0, sizeof(saved_rd_dq_offset));
memset(saved_rd_dq_window, 0, sizeof(saved_rd_dq_window));
for (i = 0; i < CA_PIVOTS_LIST_SIZE; i++) {
//if the saturation point and the next CA pivot is closer than 2 fine-steps,
// jump to the next CA pivot
if (i > 0 && ( (ca_pivot_fs[i] - ca_pivot_fs[i-1]) < CA_PIVOT_THRESHOLD ) )
continue;
amc_phy_set_addr_offset(ch, RD_WR_ADDR_OFFSET(ca_pivot_fs[i]));
amc_phy_run_dll_update(ch);
calibration_rddq_cal(ch, rd_dq_offset, rd_dq_window);
min_rd_dq_window = calibration_find_min_element(rd_dq_window, NUM_BYTES);
amc_phy_reset_fifos();
if (min_rd_dq_window < min_dq_window_width_fs) {
// XXX soft reset?
if (prev_ca_status == true)
break;
continue;
}
prev_ca_status = true;
ca_weighted_offset[ca_pass_count][0] = ca_pivot_fs[i];
ca_weighted_offset[ca_pass_count][1] = min_rd_dq_window;
ca_pass_count++;
for (byte = 0; byte < NUM_BYTES; byte++) {
if (rd_dq_window[byte] > saved_rd_dq_window[byte]) {
saved_rd_dq_window[byte] = rd_dq_window[byte];
saved_rd_dq_offset[byte] = rd_dq_offset[byte];
}
}
}
// if ca window too small, spin
if (ca_pass_count < (MIN_CA_WINDOW_WIDTH_PS / CA_PIVOT_STEP_SIZE_PS))
for(;;) ;
sum = 0;
for (i = 0; i < ca_pass_count; i++)
sum += ca_weighted_offset[i][1];
ca_offset = 0;
for (i = 0; i < ca_pass_count; i++)
ca_offset += (ca_weighted_offset[i][0] * ca_weighted_offset[i][1] / sum);
amc_phy_set_addr_offset(ch, RD_WR_ADDR_OFFSET(ca_offset));
// Shift the rd_dq offset, if needed
amc_phy_shift_dq_offset(saved_rd_dq_offset, NUM_BYTES);
for(byte = 0; byte < NUM_BYTES; byte++)
amc_phy_set_rd_offset(ch, byte, RD_WR_ADDR_OFFSET(saved_rd_dq_offset[byte]));
amc_phy_run_dll_update(ch);
return (ca_offset);
}
static void calibration_get_save_restore_region(uint8_t channel, uint32_t **region)
{
uint32_t device_size; // in bytes
device_size = (amc_get_memory_size() / AMC_NUM_CHANNELS) * 1024 * 1024;
*region = (uint32_t *)(SDRAM_BASE + ((channel + 1) * device_size)) - WRITE_REGION_SIZE;
}
static uint8_t calibration_check_wrdq(uint8_t channel)
{
uint8_t i, byte, word;
static const uint32_t patterns[] = {
0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
0x00000000, 0x00000000, 0xffffffff, 0xffffffff
};
uint32_t *save_restore_region;
uint8_t result;
uint32_t temp;
uint32_t num_patterns;
result = 0;
num_patterns = sizeof(patterns) / sizeof(patterns[0]);
calibration_get_save_restore_region(channel, &save_restore_region);
for (i = 0; i < WR_DQ_RETEST_COUNT; i++) {
for (word = 0; word < WRITE_REGION_SIZE; word++) {
*(save_restore_region + word) = patterns[word % num_patterns];
}
for (word = 0; word < WRITE_REGION_SIZE; word++)
if ((temp = (*(save_restore_region + word) ^ patterns[word % num_patterns])) != 0) {
for (byte = 0; byte < NUM_BYTES; byte++)
if (temp & (0xf << byte))
result |= (1 << byte);
break;
}
}
return result;
}
static void calibration_incr_search(uint8_t ch, int8_t sweep_lo, int8_t sweep_hi, int8_t step, int8_t *passing_offsets)
{
uint8_t fail_flag, result, mask;
uint8_t byte;
int8_t sweep;
fail_flag = 0;
for (sweep = sweep_lo; __abs(sweep + step) <= __abs(sweep_hi); sweep += step)
{
for (byte = 0; byte < NUM_BYTES; byte++)
amc_phy_set_wr_offset(ch, byte, RD_WR_ADDR_OFFSET(sweep));
amc_phy_run_dll_update(ch);
result = calibration_check_wrdq(ch);
for (byte = 0; byte < NUM_BYTES; byte++) {
mask = (1 << byte);
if (fail_flag & mask)
continue;
if ((result & mask) == 0)
passing_offsets[byte] = sweep;
else
fail_flag |= mask;
}
// all failed
if (fail_flag & 0xf)
break;
}
}
static void calibration_wrdq_cal(uint8_t ch, int8_t *wr_dq_offset, int8_t *wr_dq_window)
{
uint8_t byte;
int8_t min_pivot, max_pivot;
uint32_t pivot_count;
int8_t pivot;
int8_t pos_sweep_hi, pos_sweep_lo, neg_sweep_hi, neg_sweep_lo;
int8_t pos_offset[NUM_BYTES], neg_offset[NUM_BYTES];
min_pivot = max_offset_fs;
max_pivot = min_offset_fs;
pivot_count = 0;
memset(pos_offset, 0, sizeof(pos_offset));
memset(neg_offset, 0, sizeof(neg_offset));
for (pivot = 0; pivot < DQ_PIVOTS_LIST_SIZE; pivot++) {
for (byte = 0; byte < NUM_BYTES; byte++)
amc_phy_set_wr_offset(ch, byte, RD_WR_ADDR_OFFSET(dq_pivot_fs[pivot]));
amc_phy_run_dll_update(ch);
if (calibration_check_wrdq(ch) == 0) {
if (dq_pivot_fs[pivot] < min_pivot)
min_pivot = dq_pivot_fs[pivot];
if (dq_pivot_fs[pivot] > max_pivot)
max_pivot = dq_pivot_fs[pivot];
pivot_count++;
}
}
//if wr dq window too small, spin
if (pivot_count < (uint32_t)(MIN_DQ_WINDOW_WIDTH_PS / DQ_PIVOT_STEP_SIZE_PS))
for(;;) ;
pos_sweep_hi = __min(max_offset_fs, (max_pivot + dq_pivot_step_size_fs));
neg_sweep_hi = __max(min_offset_fs, (min_pivot - dq_pivot_step_size_fs));
pos_sweep_lo = (pos_sweep_hi + neg_sweep_hi) / 2;
neg_sweep_lo = pos_sweep_lo;
calibration_incr_search(ch, pos_sweep_lo, pos_sweep_hi, INCR_SEARCH_STEP_SIZE, pos_offset);
calibration_incr_search(ch, neg_sweep_lo, neg_sweep_hi, -INCR_SEARCH_STEP_SIZE, neg_offset);
for (byte = 0; byte < NUM_BYTES; byte++) {
wr_dq_offset[byte] = (pos_offset[byte] + neg_offset[byte]) / 2;
wr_dq_window[byte] = __abs(pos_offset[byte] - neg_offset[byte]);
}
}
+146
View File
@@ -0,0 +1,146 @@
/*
* Copyright (C) 2009-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.
*/
#ifndef __AMC_H
#define __AMC_H
#include <sys/types.h>
/* Apple Memory Controller */
#define AMC_MAX_FREQUENCY_SLOTS 4
#define AMC_MAX_TUNABLES 50
#define FLAG_AMC_PARAM_BUSTAT23 0x0001
#define FLAG_AMC_PARAM_LEGACY 0x0002
#define FLAG_AMC_PARAM_SLOW_BOOT 0x0004
#define FLAG_AMC_PARAM_ENABLE_AIU 0x0008
#define FLAG_AMC_PARAM_RECONFIG 0x0010
#define FLAG_AMC_PARAM_MRR_BYTE_SWIZZLE 0x0020
#define FLAG_AMC_PARAM_MRR_BIT_SWIZZLE 0x0040
#define FLAG_AMC_PARAM_ZQCL 0x0080
#define AMP_SWIZZLE_PER_J34M 2 // ...and This is the second Swizzle ever needed for H6
// per <rdar://15498696>
#define __abs(x) (((x) < 0) ? -(x) : (x))
typedef enum {
MR_READ,
MR_WRITE
} amc_mrcmd_op_t;
struct amc_per_freq {
uint32_t cas;
uint32_t pch;
uint32_t act;
uint32_t autoref;
uint32_t selfref;
uint32_t modereg;
uint32_t mifcassch;
uint32_t mifqmaxctrl;
uint32_t arefparam;
uint32_t trefbwbasecyc;
};
struct amc_param {
uint32_t flags;
uint32_t freqsel;
uint32_t tREFi;
uint32_t tREFi_1Gb;
uint32_t longsrcnt;
uint32_t longsrcnt_1Gb;
uint32_t srextrarefcnt;
uint32_t rdlat;
uint32_t wrlat;
uint32_t phyrdlat;
uint32_t phywrlat;
uint32_t pdn;
uint32_t read;
uint32_t bustat;
uint32_t bustat2;
uint32_t derate;
uint32_t mr1;
uint32_t mr2;
uint32_t mr3;
uint32_t mr63;
uint32_t mcphyupdate;
uint32_t autoref_params;
uint32_t pwrmngtparam_small;
uint32_t pwrmngtparam_guided;
uint32_t arefparam;
uint32_t chnldec;
uint32_t chnldec2;
uint32_t chnldec4;
uint32_t aref_freq0;
uint32_t aref_freq1;
uint32_t bootclkdivsr;
uint32_t schen_default;
uint32_t pwrmngten_default;
uint32_t mcphyupdate1;
uint32_t odts;
uint32_t readleveling;
uint32_t lat;
uint32_t phyrdwrtim;
uint32_t longsr;
uint32_t addrcfg;
uint32_t mccchnldec;
uint32_t mcuchnhash;
uint32_t mcuchnhash2;
uint32_t mcschnldec;
uint32_t qbrparam;
uint32_t addrmapmode;
uint32_t bankhash0;
uint32_t bankhash1;
uint32_t bankhash2;
int8_t offset_shift_hynix;
int8_t offset_shift_elpida;
int8_t offset_shift_elpida25nm;
struct amc_per_freq freq[AMC_MAX_FREQUENCY_SLOTS];
};
struct amc_tunable {
volatile uint32_t *reg;
uint32_t value;
};
struct amc_memory_device_info {
uint32_t vendor_id;
uint32_t rev_id;
uint32_t rev_id2;
uint32_t type;
uint32_t width; // Device width in Bytes
uint32_t density; // Device density in MBytes
};
// AMC protected functions (meant to be called from per platform/target amc implementation)
int32_t amc_init(bool resume);
uint64_t amc_get_memory_size(void);
const struct amc_memory_device_info *amc_get_memory_device_info(void);
void amc_mrcmd(amc_mrcmd_op_t op, uint8_t channels, uint8_t ranks, int32_t reg, uintptr_t val);
void amc_mrcmd_to_ch_rnk(amc_mrcmd_op_t op, uint8_t channel, uint8_t rank, int32_t reg, uintptr_t val);
void amc_enable_autorefresh(void);
void amc_finalize(bool resume);
void amc_dram_workarounds(bool resume);
void amc_dram_shift_dq_offset(int8_t *dq_offset, uint8_t num_bytes);
void amc_enable_slow_boot(bool enable);
void amc_configure_address_decoding_and_mapping(void);
void amc_configure_default_address_decoding_and_mapping(void);
addr_t amc_get_uncached_dram_virt_addr(uint32_t ch, uint32_t rnk, uint32_t bank, uint32_t row, uint32_t col);
uint32_t amc_get_consecutive_bytes_perchnrnk(void);
const struct amc_param *amc_get_params(void);
// AMC function to be called from AMC PHY calibration code
void amc_calibration_start(bool start);
void amc_enable_rddqcal(bool enable);
void amc_wrdqcal_start(bool start);
#endif /* ! __AMC_H */
@@ -0,0 +1,58 @@
/*
* 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.
*/
#ifndef __DRIVERS_AMC_PHY_H
#define __DRIVERS_AMC_PHY_H
#include <sys/types.h>
/* XXX TODO: cleanup 'int' to what's needed */
struct amc_phy_calibration_data {
int bit_time_ps;
int min_ca_window_width_ps;
int min_dq_window_width_ps;
int ca_pivot_step_size_ps;
int dq_pivot_step_size_ps;
int max_offset_setting;
int min_offset_factor;
int dll_f2_delay_fs;
uint8_t ca_pivots_list_size;
int *ca_pivot_ps;
uint8_t dq_pivots_list_size;
int *dq_pivot_ps;
bool use_resume_boot_flow;
};
void amc_phy_preinit(void);
void amc_phy_init(bool resume);
void amc_phy_pre_normal_speed_enable();
void amc_phy_scale_dll(int freqsel, int factor);
bool amc_phy_rddq_cal();
void amc_phy_bypass_prep(int step);
void amc_phy_finalize();
const struct amc_phy_calibration_data *amc_phy_get_calibration_data();
void amc_phy_calibration_init(uint32_t *fine_lock_ps);
void amc_phy_run_dll_update(uint8_t ch);
void amc_phy_set_addr_offset(uint8_t ch, uint8_t value);
void amc_phy_set_rd_offset(uint8_t ch, uint8_t byte, uint8_t value);
void amc_phy_set_wr_offset(uint8_t ch, uint8_t byte, uint8_t value);
void amc_phy_configure_dll_pulse_mode(uint8_t ch, bool enable);
void amc_phy_run_dq_training(uint8_t ch);
uint32_t amc_phy_get_dq_training_status(uint8_t ch, uint8_t byte, uint8_t num_bytes);
void amc_phy_reset_fifos();
void amc_phy_enable_dqs_pulldown(bool enable);
void amc_phy_restore_calibration_values(bool resume);
void amc_phy_calibration_restore_ca_offset(uint8_t ch);
void amc_phy_calibration_ca_rddq_cal(bool resume);
void amc_phy_calibration_wrdq_cal(bool resume);
void amc_phy_shift_dq_offset(int8_t *dq_offset, uint8_t num_bytes);
#endif /* __DRIVERS_AMC_PHY_H */
@@ -0,0 +1,27 @@
/*
* 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.
*/
#ifndef __AMC_REGS_H
#define __AMC_REGS_H
#include <platform/soc/hwregbase.h>
#if (AMC_REG_VERSION == 1 || AMC_REG_VERSION == 2)
#include "amc_regs_v12.h"
#elif AMC_REG_VERSION == 3
#include "amc_regs_v3.h"
#elif (AMC_REG_VERSION == 4 || AMC_REG_VERSION == 5)
#include "amc_regs_v45.h"
#else
#error "amc_regs header missing"
#endif
#endif /* __AMC_REGS_H */
@@ -0,0 +1,183 @@
/*
* Copyright (C) 2009-2014 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.
*/
/* Apple Memory Controller */
#ifndef __PLATFORM_SOC_AMC_H
#define __PLATFORM_SOC_AMC_H
#include <drivers/amc/amc.h>
#include <platform.h>
#include <platform/soc/hwregbase.h>
#include <sys/types.h>
#define AMC_FREQUENCY_SLOTS (4)
#define rAMC_AMCEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x000))
#define rAMC_BOOTCLK (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x004))
#define rAMC_CLKGATE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x008))
#define rAMC_FREQSEL (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x00C))
#define rAMC_AIUPRT_CFG (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x080))
#define rAMC_AIUPRT_RD_CWF (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x084))
#define rAMC_AIUPRT_RD_GEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x088))
#define rAMC_AIUPRT_ROTT_D1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x08C))
#define rAMC_AIUPRT_ROTT_D2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x090))
#define rAMC_AIUPRT_WR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x094))
#define rAMC_AIUPRT_WOTT_D1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x098))
#define rAMC_AIUPRT_WOTT_D2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x09C))
#define rAMC_AIUPRT_TBADDR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0A0))
#define rAMC_AIU_CHNLDEC (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0A4))
#define rAMC_CHNLDEC rAMC_AIU_CHNLDEC
#define rAMC_AIU_CHNLDEC2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0A8))
#define rAMC_CHNLDEC2 rAMC_AIU_CHNLDEC2
#define rAMC_AIU_CHNLDEC4 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0AC))
#define rAMC_CHNLDEC4 rAMC_AIU_CHNLDEC4
#define rAMC_AIU_ADDRBANKHASH0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0B0))
#define rAMC_AIU_ADDRBANKHASH1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0B4))
#define rAMC_AIU_ADDRBANKHASH2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x0B8))
#define rAMC_AIU_CHNLCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x100))
#define rAMC_AIU_CHNLTM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x104))
#define rAMC_AIU_RDBRSTLEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x108))
#define rAMC_AIU_RDMAXCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x10C))
#define rAMC_AIU_RDMINCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x110))
#define rAMC_AIU_RDREFL (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x114))
#define rAMC_AIU_WRBRSTLEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x118))
#define rAMC_AIU_WRMAXCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x11C))
#define rAMC_AIU_WRMINCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x120))
#define rAMC_AIU_WRREFL (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x124))
#define rAMC_AIU_CPUSPCREQ (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x128))
#define rAMC_AIU_GFXSPCREQ (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x12C))
#define rAMC_AIU_NRTSPCREQ (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x130))
#define rAMC_AIU_RTSPCREQ (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x134))
#define rAMC_AIU_WPQSCH (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x138))
#define rAMC_AIU_THOTLEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x13C))
#define rAMC_AIU_THOTLCPUPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x140))
#define rAMC_AIU_THOTLRTPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x144))
#define rAMC_AIU_THOTLNRTPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x148))
#define rAMC_AIU_THOTLGFXPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x14C))
#define rAMC_AIU_PUSHEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x150))
#if AMC_REG_VERSION == 2 && SUB_PLATFORM_S7002
#define rAMC_AIU_THOTLCPUPARAM2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x154))
#define rAMC_AIU_THOTLRTPARAM2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x158))
#define rAMC_AIU_THOTLNRTPARAM2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x15C))
#define rAMC_AIU_THOTLGFXPARAM2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x160))
#endif
#define rAMC_AIU_LLTSCHCTL (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x164))
#define rAMC_SCHEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x200))
#define rAMC_OPIDLETMR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x204))
#define rAMC_OPTMRADJEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x208))
#define rAMC_OPTMRADJPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x20C))
#define rAMC_MIFNRTAGE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x210))
#define rAMC_MIFRTAGE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x214))
#define rAMC_MIFPCAGE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x218))
#define rAMC_QBREN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x21C))
#define rAMC_QBRPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x220))
#define rAMC_MIFACTSCH (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x224))
#define rAMC_MIFCASSCH_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x228))
#define rAMC_PSQAFNTY (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x238))
#define rAMC_PSQRQCTL0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x23C))
#define rAMC_PSQRQCTL1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x240))
#define rAMC_PSQRQTIMER0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x244))
#define rAMC_PSQRQTIMER1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x248))
#define rAMC_PSQRQTIMER2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x24C))
#define rAMC_PSQRQBRST (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x250))
#define rAMC_PSQRQSCHCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x254))
#define rAMC_PSQWQCTL0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x258))
#define rAMC_PSQWQCTL1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x25C))
#define rAMC_PSQWQTHR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x260))
#define rAMC_PSQWQBRST (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x264))
#define rAMC_PSQWQSCHCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x268))
#define rAMC_MCUQOS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x26C))
#define rAMC_MCUQOSLLT (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x270))
#define rAMC_PHYRDWRTIM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x280))
#define rAMC_PHYMRRDATADQBITMUX (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x300))
#define rAMC_PHYMRRDATADQBYTEMUX (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x304))
#define rAMC_LAT (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x380))
#define rAMC_CAS_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x384))
#define rAMC_PCH_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x394))
#define rAMC_ACT_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3A4))
#define rAMC_AUTO_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3B4))
#define rAMC_SELF_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3C4))
#define rAMC_PDN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3D4))
#define rAMC_MODE_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3D8))
#define rAMC_RD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3E8))
#define rAMC_BUSTAT (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3EC))
#define rAMC_BUSTAT_FREQ01 rAMC_BUSTAT
#define rAMC_DERATE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3F0))
#define rAMC_TRANSGAP (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3F4))
#define rAMC_AUTOREF_PARAMS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3F8))
#define rAMC_BUSTAT_FREQ23 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3FC))
#define rAMC_ADDRMAP_MODE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x400))
#define rAMC_ADDRCFG (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x404))
#define rAMC_CH0RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x408))
#define rAMC_CH0RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x40C))
#define rAMC_CH1RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x410))
#define rAMC_CH1RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x414))
#define rAMC_AREFEN_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x418))
#define rAMC_AREFPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x428))
#define rAMC_LONGSR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x42C))
#define rAMC_ZQC (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x430))
#define rAMC_PWRMNGTEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x434))
#define rAMC_PWRMNGTPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x438))
#define rAMC_ODTS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x43C))
#define rAMC_ODTS_MAPPING (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x440))
#define rAMC_MCPHY_UPDTPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x444))
#define rAMC_READ_LEVELING (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x448))
#define rAMC_CH2RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x44C))
#define rAMC_CH2RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x450))
#define rAMC_CH3RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x454))
#define rAMC_CH3RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x458))
#define AMC_RNKCFG_OFFSET(_r) ((_r) * 1)
#if AMC_REG_VERSION == 2 && SUB_PLATFORM_S7002
// These defs are for AREFPARAM regs for freqs 1, 2, and 3 only (freq0 already defined above as rAMC_AREFPARAM)
#define rAMC_AREFPARAM_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x460))
#define rAMC_MCPHY_UPDTPARAM1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x478))
#endif
#define rAMC_CH0MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x480))
#define rAMC_CH0INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x484))
#define rAMC_CH1MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x488))
#define rAMC_CH1INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x48C))
#define rAMC_CH01MRSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x490))
#define rAMC_CH01INITSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x494))
#define rAMC_CH2MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x498))
#define rAMC_CH2INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x49C))
#define rAMC_CH3MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4A0))
#define rAMC_CH3INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4A4))
#define rAMC_CH23MRSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4A8))
#define rAMC_CH23INITSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4AC))
/* XXX perfcntr */
#define rAMC_INTEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x700))
#define rAMC_INTSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x704))
#define rAMC_BAELOG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x708))
#define rAMC_BAELOG2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x70C))
#define rAMC_MIFQMAXCTRL_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x780))
#if AMC_REG_VERSION == 2 && SUB_PLATFORM_S7002
#define rAMC_TREFBWBASECYC_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x800))
#endif
#include <platform/amcconfig.h>
#endif /* ! __PLATFORM_SOC_AMC_H */
@@ -0,0 +1,150 @@
/*
* Copyright (C) 2011-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.
*/
/* Apple Memory Controller */
#ifndef __PLATFORM_SOC_AMC_H
#define __PLATFORM_SOC_AMC_H
#include <drivers/amc/amc.h>
#include <platform.h>
#include <platform/soc/hwregbase.h>
#include <sys/types.h>
#define AMC_FREQUENCY_SLOTS (4)
#define rAMC_AMCEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x000))
#define rAMC_BOOTCLK (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x004))
#define rAMC_CLKGATE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x008))
#define rAMC_FREQSEL (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x00C))
#define rAMC_CLKPWRGATE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x010))
#define rAMC_CLKPWRGATE2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x014))
#define rAMC_MCSADDRBNKHASH(_n) (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x080 + ((_n) * 4)))
#define rAMC_MCSRDRTNCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x100))
#define rAMC_MCSCHNLCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x104))
#define rAMC_MCSCHNLTM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x108))
#define rAMC_MCSARBCFG (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x10C))
#define rAMC_SCHEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x200))
#define rAMC_OPIDLETMR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x204))
#define rAMC_OPTMRADJEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x208))
#define rAMC_OPTMRADJPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x20C))
#define rAMC_MIFNRTAGE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x210))
#define rAMC_MIFRTAGE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x214))
#define rAMC_MIFPCAGE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x218))
#define rAMC_QBREN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x21C))
#define rAMC_QBRPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x220))
#define rAMC_MIFACTSCH (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x224))
#define rAMC_MIFCASSCH_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x228))
#define rAMC_PSQAFNTY (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x238))
#define rAMC_PSQRQCTL0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x23C))
#define rAMC_PSQRQCTL1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x240))
#define rAMC_PSQRQTIMER0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x244))
#define rAMC_PSQRQTIMER1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x248))
#define rAMC_PSQRQTIMER2 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x24C))
#define rAMC_PSQRQBRST (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x250))
#define rAMC_PSQRQSCHCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x254))
#define rAMC_PSQWQCTL0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x258))
#define rAMC_PSQWQCTL1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x25C))
#define rAMC_PSQWQTHR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x260))
#define rAMC_PSQWQBRST (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x264))
#define rAMC_PSQWQSCHCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x268))
#define rAMC_MCUQOS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x26C))
#define rAMC_MCUQOSLLT (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x270))
#define rAMC_PSQRQTIMER3 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x274))
#define rAMC_PHYRDWRTIM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x280))
#define rAMC_PHYMRRDATADQBITMUX (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x300))
#define rAMC_PHYMRRDATADQBYTEMUX (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x304))
#define rAMC_LAT (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x380))
#define rAMC_CAS_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x384))
#define rAMC_PCH_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x394))
#define rAMC_ACT_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3A4))
#define rAMC_AUTO_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3B4))
#define rAMC_SELF_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3C4))
#define rAMC_PDN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3D4))
#define rAMC_MODE_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x3D8))
#define rAMC_RD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3E8))
#define rAMC_BUSTAT (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3EC))
#define rAMC_BUSTAT_FREQ01 rAMC_BUSTAT
#define rAMC_DERATE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3F0))
#define rAMC_TRANSGAP (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3F4))
#define rAMC_AUTOREF_PARAMS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3F8))
#define rAMC_BUSTAT_FREQ23 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x3FC))
#define rAMC_ADDRMAP_MODE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x400))
#define rAMC_ADDRCFG (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x404))
#define rAMC_CH0RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x408))
#define rAMC_CH0RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x40C))
#define rAMC_CH1RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x410))
#define rAMC_CH1RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x414))
#define rAMC_AREFEN_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x418))
#define rAMC_AREFPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x428))
#define rAMC_LONGSR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x42C))
#define rAMC_ZQC (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x430))
#define rAMC_PWRMNGTEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x434))
#define rAMC_PWRMNGTPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x438))
#define rAMC_ODTS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x43C))
#define rAMC_ODTS_MAPPING (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x440))
#define rAMC_MCPHY_UPDTPARAM (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x444))
#define rAMC_READ_LEVELING (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x448))
#define rAMC_CH2RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x44C))
#define rAMC_CH2RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x450))
#define rAMC_CH3RNKCFG0 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x454))
#define rAMC_CH3RNKCFG1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x458))
#define AMC_RNKCFG_OFFSET(_r) ((_r) * 1)
// These defs are for AREFPARAM regs for freqs 1, 2, and 3 only (freq0 already defined above as rAMC_AREFPARAM)
#define rAMC_AREFPARAM_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x460))
#define rAMC_MCPHY_UPDTPARAM1 (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x478))
#define rAMC_CH0MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x480))
#define rAMC_CH0INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x484))
#define rAMC_CH1MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x488))
#define rAMC_CH1INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x48C))
#define rAMC_CH01MRSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x490))
#define rAMC_CH01INITSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x494))
#define rAMC_CH2MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x498))
#define rAMC_CH2INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x49C))
#define rAMC_CH3MRCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4A0))
#define rAMC_CH3INITCMD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4A4))
#define rAMC_CH23MRSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4A8))
#define rAMC_CH23INITSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x4AC))
#define rAMC_INTEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x700))
#define rAMC_INTSTATUS (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x704))
#define rAMC_MIFQMAXCTRL_FREQ(_f) (*(volatile uint32_t *)(AMC_BASE_ADDR + ((_f) * 4) + 0x780))
#define rMCC_MCCEN (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x800))
#define rMCC_CHNLDEC (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x80C))
#define rAMC_CHNLDEC rMCC_CHNLDEC
#define rMCC_MCUCHNHASH (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x810))
#define rMCC_DRAMACCCTRL (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x81C))
#define rMCC_ALCHINT (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x850))
#define rMCC_AFWRMERGE (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x854))
#define rMCC_MCSCMDCRD (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x880))
#define rMCC_MCCAFDTHR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x884))
#define rMCC_MCDHWMTHR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x888))
#define rMCC_MCFTHR (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x88C))
#define rMCC_DATASETID(_n) (*(volatile uint32_t *)(AMC_BASE_ADDR + 0x1000 + ((_n) * 0x1000)))
#include <platform/amcconfig.h>
#endif /* __PLATFORM_SOC_AMC_H */
@@ -0,0 +1,165 @@
/*
* Copyright (C) 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.
*/
/* Apple Memory Controller version 3 */
#ifndef __PLATFORM_SOC_AMC_H
#define __PLATFORM_SOC_AMC_H
#include <drivers/amc/amc.h>
#include <platform.h>
#include <platform/soc/hwregbase.h>
#include <sys/types.h>
#define AMC_FREQUENCY_SLOTS (4)
// AMCX registers
#define rAMC_AMCEN (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x000))
#define rAMC_CLKGATE (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x004))
#define rAMC_FREQSEL (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x008))
#define rAMC_CLKPWRGATE (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x010))
#define rAMC_CLKPWRGATE2 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x014))
#define rAMC_MCSADDRBNKHASH(_n) (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x080 + ((_n) * 4)))
#define rAMC_MCSCHNLDEC (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x08C))
#define rAMC_ADDRMAP_MODE (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x090))
#define rAMC_ADDRCFG (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x094))
#define rAMC_MCSRDRTNCRD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x100))
#define rAMC_MCSCHNLCRD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x104))
#define rAMC_MCSCHNLTM (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x108))
#define rAMC_MCSARBCFG (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x10C))
#define rAMC_SCHEN (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x180))
#define rAMC_OPIDLETMR (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x184))
#define rAMC_OPTMRADJEN (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x188))
#define rAMC_OPTMRADJPARAM (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x18C))
#define rAMC_MIFNRTAGE (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x190))
#define rAMC_MIFRTAGE (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x194))
#define rAMC_MIFPCAGE (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x198))
#define rAMC_QBREN (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x19C))
#define rAMC_QBRPARAM (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1A0))
#define rAMC_MIFACTSCH (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1A4))
#define rAMC_MIFCASSCH_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x1A8))
#define rAMC_PSQAFNTY (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1B8))
#define rAMC_PSQRQCTL0 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1BC))
#define rAMC_PSQRQCTL1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1C0))
#define rAMC_PSQRQTIMER0 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1C4))
#define rAMC_PSQRQTIMER1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1C8))
#define rAMC_PSQRQTIMER2 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1CC))
#define rAMC_PSQRQBRST (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1D0))
#define rAMC_PSQRQSCHCRD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1D4))
#define rAMC_PSQWQCTL0 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1D8))
#define rAMC_PSQWQCTL1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1DC))
#define rAMC_PSQWQTHR (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1E0))
#define rAMC_PSQWQBRST (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1E4))
#define rAMC_PSQWQSCHCRD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1E8))
#define rAMC_MCUQOS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1EC))
#define rAMC_MCUQOSLLT (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1F0))
#define rAMC_PSQRQTIMER3 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x1F4))
#define rAMC_PHYRDWRTIM (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x200))
#define rAMC_PHYUPDATETIMERS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x280))
#define rAMC_LAT (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x300))
#define rAMC_CAS_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x304))
#define rAMC_PCH_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x314))
#define rAMC_ACT_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x324))
#define rAMC_AUTO_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x334))
#define rAMC_SELF_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x344))
#define rAMC_PDN (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x354))
#define rAMC_MODE_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x358))
#define rAMC_RD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x368))
#define rAMC_BUSTAT (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x36C))
#define rAMC_BUSTAT_FREQ01 rAMC_BUSTAT
#define rAMC_DERATE (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x370))
#define rAMC_TRANSGAP (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x374))
#define rAMC_AUTOREF_PARAMS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x378))
#define rAMC_BUSTAT_FREQ23 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x37C))
#define rAMC_CH0RNKCFG0 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x380))
#define rAMC_CH0RNKCFG1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x384))
#define rAMC_CH1RNKCFG0 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x388))
#define rAMC_CH1RNKCFG1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x38C))
#define rAMC_AREFEN_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x390))
#define rAMC_AREFPARAM (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3A0))
#define rAMC_LONGSR (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3A4))
#define rAMC_ZQC (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3A8))
#define rAMC_PWRMNGTEN (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3AC))
#define rAMC_PWRMNGTPARAM (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3B0))
#define rAMC_ODTS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3B4))
#define rAMC_ODTS_MAPPING (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3B8))
#define rAMC_MCPHY_UPDTPARAM (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3BC))
#define rAMC_READ_LEVELING (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3C0))
#define rAMC_CH2RNKCFG0 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3C4))
#define rAMC_CH2RNKCFG1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3C8))
#define rAMC_CH3RNKCFG0 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3CC))
#define rAMC_CH3RNKCFG1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3D0))
#define AMC_RNKCFG_OFFSET(_r) ((_r) * 1)
// These defs are for AREFPARAM regs for freqs 1, 2, and 3 only (freq0 already defined above as rAMC_AREFPARAM)
#define rAMC_AREFPARAM_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x3D8))
#define rAMC_MCPHY_UPDTPARAM1 (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x3F0))
#define rAMC_CH0MRCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x400))
#define rAMC_CH0INITCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x404))
#define rAMC_CH1MRCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x408))
#define rAMC_CH1INITCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x40C))
#if AMC_REG_VERSION == 4
#define rAMC_CH01MRSTATUS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x410))
#define rAMC_CH01INITSTATUS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x414))
#define rAMC_CH2MRCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x418))
#define rAMC_CH2INITCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x41C))
#define rAMC_CH3MRCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x420))
#define rAMC_CH3INITCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x424))
#else
#define rAMC_CH2MRCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x410))
#define rAMC_CH2INITCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x414))
#define rAMC_CH3MRCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x418))
#define rAMC_CH3INITCMD (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x41C))
#define rAMC_CH01MRSTATUS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x420))
#define rAMC_CH01INITSTATUS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x424))
#endif
#define rAMC_CH23MRSTATUS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x428))
#define rAMC_CH23INITSTATUS (*(volatile uint32_t *)(AMCX_BASE_ADDR + 0x42C))
#define rAMC_MIFQMAXCTRL_FREQ(_f) (*(volatile uint32_t *)(AMCX_BASE_ADDR + ((_f) * 4) + 0x700))
// AMCC registers
#define rMCC_CHNLDEC (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x4A4))
#define rMCC_MCUCHNHASH (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x4A8))
#define rMCC_MCUCHNHASH2 (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x4AC))
#define rMCC_DRAMACCCTRL (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x4B4))
#define rAMC_INTEN (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x700))
#define rAMC_INTSTATUS (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x704))
#define rAMC_MCCTAGPARLOG1 (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x710))
#define rAMC_MCCTAGPARLOG2 (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x714))
#define rAMC_MCCDATERRLOG (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x718))
#define rAMC_MCCAFERRLOG0 (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x71c))
#define rAMC_MCCAFERRLOG1 (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x720))
#define rAMC_MCCAFERRLOG2 (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x724))
#define rAMC_MCCDPERRCNTCTRL (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x728))
#define rMCC_MCCGEN (*(volatile uint32_t *)(AMCC_BASE_ADDR + 0x780))
#include <platform/amcconfig.h>
#endif /* __PLATFORM_SOC_AMC_H */
+28
View File
@@ -0,0 +1,28 @@
# Copyright (C) 2009-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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
ifeq ($(AMC_REG_VERSION),)
OPTIONS += AMC_REG_VERSION=1
else
OPTIONS += AMC_REG_VERSION=$(AMC_REG_VERSION)
endif
ifeq ($(AMC_FILE_VERSION),)
ALL_OBJS += $(LOCAL_DIR)/amc.o
else
ALL_OBJS += $(LOCAL_DIR)/amc_v2.o
endif
ifeq ($(NO_AMP_CALIBRATION),true)
ALL_OBJS += $(LOCAL_DIR)/calibration_v1.o
endif
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+328
View File
@@ -0,0 +1,328 @@
/*
* Copyright (C) 2009-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/amc/amc.h>
#include <drivers/amc/amc_phy.h>
#include <drivers/dram.h>
#include <lib/libc.h>
#include <platform/chipid.h>
#include <sys.h>
#include "amg.h"
#define CA_PIVOTS_LIST_SIZE (7)
#define DQ_PIVOTS_LIST_SIZE (5)
static const int ca_pivot_ps[CA_PIVOTS_LIST_SIZE] = {-375, -250, -125, 0, 125, 250, 375};
static const int dq_pivot_ps[DQ_PIVOTS_LIST_SIZE] = {-500, -250, 0, 250, 500};
static struct amc_phy_calibration_data amg_calibration_data = {
.bit_time_ps = 2500,
.min_ca_window_width_ps = 250,
.min_dq_window_width_ps = 250,
.ca_pivot_step_size_ps = 125,
.dq_pivot_step_size_ps = 250,
.max_offset_setting = 63,
.min_offset_factor = 12,
.ca_pivots_list_size = CA_PIVOTS_LIST_SIZE,
.ca_pivot_ps = (int *)ca_pivot_ps,
.dq_pivots_list_size = DQ_PIVOTS_LIST_SIZE,
.dq_pivot_ps = (int *)dq_pivot_ps,
};
void amc_phy_init(bool resume)
{
int i;
// overwrite bit_time_ps if presented
if (amc_phy_params.bit_time_ps)
amg_calibration_data.bit_time_ps = amc_phy_params.bit_time_ps;
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMG_INDEX_FOR_CHANNEL(i); // cope with hole in AMG address space
rAMG_CORE_CONFIG(ch) = amc_phy_params.core_config;
#if !SUPPORT_FPGA
// PHY ZQ calibration
rAMG_ZQ_CONF(ch) = 0x00ff0096; // <rdar://problem/8263127>
rAMG_ZQ_CONTROL(ch) = 0x00000009; // <rdar://problem/7502673>
rAMG_ZQ_CONTROL(ch) = 0x0000000b;
// Not testing the error bit. This will never happen in normal operation,
// and in fact _can't_ be set in H4P B0.
while ((rAMG_ZQ_STATUS(ch) & 0x80) == 0) ;
// Train master DLL
rAMG_DLL_CONTROL(ch) = 0x00110001;
rAMG_DLL_CONTROL(ch) = 0x00110005;
while ((rAMG_DLL_STATUS(ch) & 1) != 1) ;
// check for timeout
if ((rAMG_DLL_STATUS(ch) & 0x4) != 0)
for (;;) ;
if (amc_phy_params.flags & FLAG_AMG_PARAM_CAL_STATIC) {
// CA static offset programming; note it's too early to use
// MRRs, so this relies on the SOC fusing.
uint16_t fine_lock = (rAMG_DLL_STATUS(ch) >> 5) & 0x3ff;
uint32_t fine_unit = (amg_calibration_data.bit_time_ps) / fine_lock;
uint32_t addr_offset;
uint32_t vendor_id = chipid_get_memory_manufacturer();
switch (vendor_id) {
case JEDEC_MANUF_ID_SAMSUNG:
addr_offset = (110/fine_unit) | (1 << 6); /* -110ps */
break;
case JEDEC_MANUF_ID_ELPIDA:
addr_offset = (50/fine_unit) | (1 << 6); /* -50ps */
break;
case JEDEC_MANUF_ID_HYNIX:
addr_offset = 0; /* 0ps */
break;
default:
addr_offset = 0;
break;
}
rAMG_ADDR_OFFSET(ch) = addr_offset;
} else if (resume) {
amc_phy_calibration_restore_ca_offset(i);
}
rAMG_DLL_TIMER(ch) = 0x0003061a;
// set frequency scaling parameters
if (likely(!amc_phy_params.freq_scale))
rAMG_FREQ_SCALE(ch) = 0x00e40688;
else
rAMG_FREQ_SCALE(ch) = amc_phy_params.freq_scale;
#endif // !SUPPORT_FPGA
rAMG_READ_LATENCY(ch) = amc_phy_params.read_latency; // [linked to AMC phyrdwrtim]
rAMG_GATE_OFFSET(ch) = amc_phy_params.gate_offset;
rAMG_INIT_CONTROL(ch) = 0x00000001;
}
}
void amc_phy_scale_dll(int freqsel, int factor)
{
int i;
// Make sure AMG was inited.
// Assumptions: all supported channels are inited together,
// and channel 0 is always used.
if ((rAMG_INIT_CONTROL(0) & 1) == 0)
return;
// Scale the current lock value
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMG_INDEX_FOR_CHANNEL(i);
uint16_t new_lock;
uint16_t fine_lock;
// The fine_lock is 10 bits and coarse is 8. Since the override
// is in coarse units, we do shifty math on the fine units.
fine_lock = (rAMG_DLL_STATUS(ch) >> 5) & 0x3ff;
if (factor == 1)
new_lock = fine_lock >> 2;
else if (factor == 8)
new_lock = fine_lock << 1;
else
panic("amc_phy_scale_dll: unsupported DLL scale factor");
if (new_lock > 0xff)
new_lock = 0xff;
rAMG_DLL_OVERRIDE(ch) = new_lock;
rAMG_DLL_CONTROL(ch) = 0x00110004;
while (!(rAMG_DLL_STATUS(ch) & 1)) ;
}
}
bool amc_phy_rddq_cal()
{
uint32_t *dq_cal_data;
bool result;
uint8_t index, i;
uint32_t device_width;
uint8_t slot, ch;
uint16_t fine_lock;
uint32_t fine_unit;
uint32_t offset;
result = false;
if (amc_phy_params.flags & FLAG_AMG_PARAM_CAL_STATIC) {
dq_cal_data = malloc(AMC_NUM_CHANNELS * 2 * sizeof(uint32_t));
if (chipid_get_memory_dqcal(dq_cal_data)) {
index = 0;
device_width = (amc_get_memory_device_info())->width;
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
ch = AMG_INDEX_FOR_CHANNEL(i); // cope with hole in AMG address space
fine_lock = (rAMG_DLL_STATUS(ch) >> 5) & 0x3ff;
fine_unit = (amg_calibration_data.bit_time_ps) / fine_lock;
// Loop across all bytes twice, first for read then for write,
// which matches the order in which the data is given to us.
for (slot = 0; slot < device_width * 2; slot++) {
offset = (((dq_cal_data[index] & 0x8) << 3) |
((((dq_cal_data[index] & 0x7) * 40) / fine_unit) & 0x3f));
dq_cal_data[index] >>= 4;
if (slot < device_width)
rAMG_RD_OFFSET(ch, slot) = offset;
else
rAMG_WR_OFFSET(ch, (slot - device_width)) = offset;
// Bump at end of "device_width" bytes of read and write
if ((slot % device_width) == (device_width - 1))
index++;
}
}
result = true;
}
free(dq_cal_data);
}
return result;
}
void amc_phy_bypass_prep(int step)
{
// Make sure AMG was inited.
// Assumptions: all supported channels are inited together,
// and channel 0 is always used.
if ((rAMG_INIT_CONTROL(0) & 1) == 0)
return;
// We need to be sure the DLL is in forced mode. Reload the
// original full-speed lock result. <rdar://problem/7269959>
// Note the 0 is the unused freqsel argument.
amc_phy_scale_dll(0, 1);
}
void amc_phy_finalize()
{
int i;
// Enable pulse-mode DLL training
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMG_INDEX_FOR_CHANNEL(i); // cope with hole in AMG address space
rAMG_DLL_FILTER(ch) = 0x0000002e;
rAMG_DLL_CONTROL(ch) = 0x00110006;
}
}
void amc_phy_enable_dqs_pulldown(bool enable)
{
}
void amc_phy_reset_fifos()
{
}
const struct amc_phy_calibration_data * amc_phy_get_calibration_data()
{
return &amg_calibration_data;
}
void amc_phy_calibration_init(uint32_t *fine_lock_ps)
{
uint8_t ch;
uint16_t lock_result;
const struct amc_memory_device_info *dev_info;
ASSERT(fine_lock_ps != NULL);
*fine_lock_ps = 0;
dev_info = amc_get_memory_device_info();
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
rAMG_DLL_FILTER(AMG_INDEX_FOR_CHANNEL(ch)) = 0;
lock_result = ((rAMG_DLL_STATUS(AMG_INDEX_FOR_CHANNEL(ch)) >> 5) & 0x3ff); // fine value
rAMG_DLL_OVERRIDE(AMG_INDEX_FOR_CHANNEL(ch)) = lock_result / 4; // coarse value
amc_phy_run_dll_update(ch);
*fine_lock_ps += (amg_calibration_data.bit_time_ps) / (lock_result);
// <rdar://problem/10996362> Modified guidance for AMG bit_sample field setting
if (((dev_info->vendor_id == JEDEC_MANUF_ID_SAMSUNG) && (dev_info->density == JEDEC_DENSITY_2Gb) && (dev_info->rev_id == 0)) ||
((dev_info->vendor_id == JEDEC_MANUF_ID_SAMSUNG) && (dev_info->density == JEDEC_DENSITY_4Gb) && (dev_info->rev_id == 1)) ||
((dev_info->vendor_id == JEDEC_MANUF_ID_HYNIX) && (dev_info->density == JEDEC_DENSITY_1Gb)))
rAMG_DQCAL_CONTROL(AMG_INDEX_FOR_CHANNEL(ch)) = 0x00001ffb;
else
rAMG_DQCAL_CONTROL(AMG_INDEX_FOR_CHANNEL(ch)) = 0x00003ffb;
}
*fine_lock_ps = *fine_lock_ps / AMC_NUM_CHANNELS;
}
void amc_phy_run_dll_update(uint8_t ch)
{
uint8_t ch_amg_idx = AMG_INDEX_FOR_CHANNEL(ch);
rAMG_DLL_CONTROL(ch_amg_idx) = 0x00110000 | (1 << 2) | (0 << 0);
while ((rAMG_DLL_STATUS(ch_amg_idx) & 1) == 0) ;
}
void amc_phy_set_addr_offset(uint8_t ch, uint8_t value)
{
rAMG_ADDR_OFFSET(AMG_INDEX_FOR_CHANNEL(ch)) = value;
}
void amc_phy_set_rd_offset(uint8_t ch, uint8_t byte, uint8_t value)
{
rAMG_RD_OFFSET(AMG_INDEX_FOR_CHANNEL(ch), byte) = value;
}
void amc_phy_set_wr_offset(uint8_t ch, uint8_t byte, uint8_t value)
{
rAMG_WR_OFFSET(AMG_INDEX_FOR_CHANNEL(ch), byte) = value;
}
void amc_phy_configure_dll_pulse_mode(uint8_t ch, bool enable)
{
if (!enable) {
rAMG_DLL_FILTER(AMG_INDEX_FOR_CHANNEL(ch)) = 0x0000000a;
}
else {
rAMG_DLL_FILTER(AMG_INDEX_FOR_CHANNEL(ch)) = 0x0000002e;
rAMG_DLL_CONTROL(AMG_INDEX_FOR_CHANNEL(ch)) = 0x00110006;
}
}
void amc_phy_run_dq_training(uint8_t ch)
{
uint8_t ch_amg_idx = AMG_INDEX_FOR_CHANNEL(ch);
rAMG_DQCAL_CONTROL(ch_amg_idx) |= (1 << 14); // start
while ((rAMG_DQCAL_STATUS(ch_amg_idx) & 1) == 0) ; // wait for 'Done' bit to set
}
uint32_t amc_phy_get_dq_training_status(uint8_t ch, uint8_t byte, uint8_t num_bytes)
{
uint8_t byte_result;
uint32_t status;
status = rAMG_DQCAL_STATUS(AMG_INDEX_FOR_CHANNEL(ch));
// bits[MAX_BYTE-1:0] of the byte_result field are for pos DQS strobe,
// and bits [2*MAX_BYTE-1:MAX_BYTE] for neg DQS strobe. Final result is
// 'AND' of two, for specified byte
byte_result = (status & (1 << (byte + 1)));
byte_result = byte_result && (status & (1 << (byte + num_bytes + 1)));
return byte_result;
}
void amc_phy_shift_dq_offset(int8_t *dq_offset, uint8_t num_bytes) {
amc_dram_shift_dq_offset(dq_offset, num_bytes);
}
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2009-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 __PLATFORM_SOC_AMG_H
#define __PLATFORM_SOC_AMG_H
#include <platform/soc/hwregbase.h>
/* Apple Memory Gasket */
#define AMG_INDEX_FOR_CHANNEL(_c) (((_c) < 2) ? (_c) : ((_c) + 2))
#define rAMG_DLL_CONFIG(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x00))
#define rAMG_DLL_OVERRIDE(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x04))
#define rAMG_DLL_CONTROL(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x08))
#define rAMG_DLL_STATUS(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x0C))
#define rAMG_DLL_TIMER(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x1C))
#define rAMG_GATE_OFFSET(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x10))
#define rAMG_FINE_OFFSET(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x14))
#define rAMG_ADDR_OFFSET(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x18))
#define rAMG_RD_OFFSET(_c,_n) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x20 + ((_n)*4)))
#define rAMG_WR_OFFSET(_c,_n) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x30 + ((_n)*4)))
#define rAMG_CORE_CONFIG(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x40))
#define rAMG_INIT_CONTROL(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x44))
#define rAMG_DLL_FILTER(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x48))
#define rAMG_FREQ_SCALE(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x4C))
#define rAMG_ZQ_OVERRIDE(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x50))
#define rAMG_ZQ_STATUS(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x54))
#define rAMG_ZQ_CONTROL(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x58))
#define rAMG_READ_LATENCY(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x5C))
#define rAMG_DQCAL_CONTROL(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x60))
#define rAMG_DQCAL_STATUS(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x64))
#define rAMG_ZQ_CONF(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x70))
#define rAMG_CKSTOP_CONF(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x74))
#define rAMG_DLLTIMER_CONF(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x78))
#define rAMG_DLL_CONF(_c) (*(volatile u_int32_t *)(AMG_BASE_ADDR + ((_c)*AMG_SPACING) + 0x7C))
struct amg_params {
uint32_t flags;
uint32_t core_config;
uint32_t read_latency;
uint32_t gate_offset;
uint32_t freq_scale;
uint32_t bit_time_ps;
};
#define FLAG_AMG_PARAM_CAL_STATIC 0x0001
#include <platform/amgconfig.h>
#endif /* ! __PLATFORM_SOC_AMG_H */
+14
View File
@@ -0,0 +1,14 @@
# Copyright (C) 2010 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)
OPTIONS += WITH_HW_AMG=1
ALL_OBJS += $(LOCAL_DIR)/amg.o
+270
View File
@@ -0,0 +1,270 @@
/*
* Copyright (C) 2010-2014 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/amc/amc.h>
#include <drivers/amc/amc_phy.h>
#include <drivers/amp/amp_v1.h>
#include <drivers/dram.h>
#include <drivers/miu.h>
#include <platform.h>
#include <platform/chipid.h>
#include <sys.h>
#define CA_PIVOTS_LIST_SIZE (9)
#define DQ_PIVOTS_LIST_SIZE (5)
static const int ca_pivot_ps[CA_PIVOTS_LIST_SIZE] = {-400, -300, -200, -100, 0, 100, 200, 300, 400};
static const int dq_pivot_ps[DQ_PIVOTS_LIST_SIZE] = {-300, -150, 0, 150, 300};
static const struct amc_phy_calibration_data amp_calibration_data = {
.bit_time_ps = 1875,
.min_ca_window_width_ps = 150,
.min_dq_window_width_ps = 150,
.ca_pivot_step_size_ps = 100,
.dq_pivot_step_size_ps = 150,
.max_offset_setting = 63,
.min_offset_factor = 0,
.dll_f2_delay_fs = 10,
.ca_pivots_list_size = CA_PIVOTS_LIST_SIZE,
.ca_pivot_ps = (int *)ca_pivot_ps,
.dq_pivots_list_size = DQ_PIVOTS_LIST_SIZE,
.dq_pivot_ps = (int *)dq_pivot_ps,
.use_resume_boot_flow = true, // to use static CA but dynamic DQ calibration
};
static uint32_t amp_dllupdtctrl[AMC_NUM_CHANNELS];
void amc_phy_init(bool resume)
{
int i, d, f;
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMP_INDEX_FOR_CHANNEL(i); // cope with hole in AMP address space
rAMP_AMPEN(ch) = 1;
#if !SUPPORT_FPGA
rAMP_DQDQSDS(ch) = 0x0a0a0a0a;
rAMP_NONDQDS(ch) = 0x0a0a0a0a;
#endif
if (amc_phy_params.flags & FLAG_AMP_PARAM_FULLDIFFMODE) {
for (f = 0; f < AMP_FREQUENCY_SLOTS; f++)
rAMP_DIFFMODE_FREQ(ch, f) = 0x00000121;
}
for (f = 0; f < AMP_FREQUENCY_SLOTS; f++) {
for (d = 0; d < AMP_NUM_DLL; d++) {
rAMP_DQSINDLLSCL_FREQ(ch,d,f) = amc_phy_params.freq[f].scl;
rAMP_DQOUTDLLSCL_FREQ(ch,d,f) = amc_phy_params.freq[f].scl;
}
rAMP_CAOUTDLLSCL_FREQ(ch,f) = amc_phy_params.freq[f].scl;
rAMP_CTLOUTDLLSCL_FREQ(ch,f) = amc_phy_params.freq[f].scl;
}
#if !SUPPORT_FPGA
for (f = 0; f < AMP_FREQUENCY_SLOTS; f++) {
rAMP_RDCAPCFG_FREQ(ch,f) = amc_phy_params.freq[f].rdcapcfg;
}
rAMP_DLLEN(ch) = 0x100;
// Reset the master DLL to make sure that master DLL locking happens from scratch
rAMP_DLLEN(ch) |= 0x1;
rAMP_DLLEN(ch) &= ~0x1;
amc_phy_run_dll_update(ch);
#endif
rAMP_AMPINIT(ch) = 0x1;
#if !SUPPORT_FPGA
rAMP_IMPCALCMD(ch) = 0x101;
while (rAMP_IMPCALCMD(ch) & 0x1) ;
#endif
}
}
void amc_phy_enable_dqs_pulldown(bool enable)
{
}
void amc_phy_scale_dll(int freqsel, int factor)
{
int i;
for (i=0; i<AMC_NUM_CHANNELS; i++) {
int ch = AMP_INDEX_FOR_CHANNEL(i); // cope with hole in AMP address space
rAMP_AMPCLK(ch) = freqsel << 16;
amc_phy_run_dll_update(ch);
}
}
bool amc_phy_rddq_cal()
{
// use static CA offset and calibrated & shifted DQ offsets
return false;
}
void amc_phy_bypass_prep(int step)
{
int i;
// Make sure AMP was inited.
// Assumptions: all supported channels are inited together,
// and channel 0 is always used.
if ((rAMP_AMPINIT(0) & 1) == 0)
return;
switch (step) {
case 0:
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMP_INDEX_FOR_CHANNEL(i); // cope with hole in AMP address space
// change the DllUpdtIntvl and DllFastUpdtIntvl to 0.
// DllUpdtAlwaysOn and DllFastUpdtAlwaysOn should be enabled
rAMP_DLLUPDTINTVL(ch) = (1 << 28) | (1 << 12);
// disable DLLEn
rAMP_DLLEN(ch) = 0;
};
break;
case 1:
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMP_INDEX_FOR_CHANNEL(i); // cope with hole in AMP address space
// Turn off periodic DLL update
// Taken care of in step(0)
// Turn off periodic impedance auto-calibration
rAMP_IMPAUTOCAL(ch) = 0;
};
break;
}
}
void amc_phy_finalize()
{
uint8_t i;
// Change Master DLL from Always-on mode to periodic-on mode
for(i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMP_INDEX_FOR_CHANNEL(i); // cope with hole in AMP address space
rAMP_DLLUPDTINTVL(ch) = ((1 << 28) | (0 << 12) | (0x80 << 0));
if (amc_phy_params.flags & FLAG_AMP_PARAM_SUPPORT_FMCLK_OFF)
rAMP_AMPCLK(ch) |= (1 << 8);
// Make sure the pmgr_ENABLE_CLK_GATE.MCU_CLK_FIXED_GATE_ENABLE is enabled in the PMGR
// AMC should be enabled so that it can respond to phyupd_req from AMP
rAMP_IMPAUTOCAL(ch) = 0x00010514;
}
}
void amc_phy_reset_fifos()
{
}
const struct amc_phy_calibration_data * amc_phy_get_calibration_data()
{
return &amp_calibration_data;
}
void amc_phy_calibration_init(uint32_t *fine_lock_ps)
{
uint8_t i;
const struct amc_memory_device_info *dev_info;
dev_info = amc_get_memory_device_info();
ASSERT(fine_lock_ps != NULL);
*fine_lock_ps = 0;
for (i = 0; i < AMC_NUM_CHANNELS; i++) {
int ch = AMP_INDEX_FOR_CHANNEL(i); // cope with hole in AMP address space
amp_dllupdtctrl[ch] = rAMP_DLLUPDTCTRL(ch);
rAMP_DLLUPDTCTRL(ch) &= ~((3 << 20) | (1 << 16)); // DLLUptMode = 0, DllUpdtPhyUpdtTyp = 0
*fine_lock_ps += amp_calibration_data.bit_time_ps / (((rAMP_MDLLCODE(ch) & 0x7f) + amp_calibration_data.dll_f2_delay_fs) * 4);
rAMP_CALPATCFG(ch) = (0x3 << 8);
rAMP_DQTRNCFG(ch) = 0x3f;
if ( ((dev_info->vendor_id == JEDEC_MANUF_ID_SAMSUNG) && (dev_info->rev_id == 0)) ||
((dev_info->vendor_id == JEDEC_MANUF_ID_HYNIX) && (dev_info->density == JEDEC_DENSITY_1Gb)) )
rAMP_CALDQMSK(ch) = 0xfefefefe;
else
rAMP_CALDQMSK(ch) = 0x00000000;
}
*fine_lock_ps = *fine_lock_ps / AMC_NUM_CHANNELS;
}
void amc_phy_run_dll_update(uint8_t ch)
{
ch = AMP_INDEX_FOR_CHANNEL(ch); // cope with hole in AMP address space
rAMP_DLLUPDTCMD(ch) = 0x1;
while ((rAMP_DLLUPDTCMD(ch) & 0x1) != 0) ;
}
void amc_phy_set_addr_offset(uint8_t ch, uint8_t value)
{
rAMP_CAOUTDLLOVRRD(AMP_INDEX_FOR_CHANNEL(ch)) = value;
}
void amc_phy_set_rd_offset(uint8_t ch, uint8_t byte, uint8_t value)
{
rAMP_DQSINDLLOVRRD(AMP_INDEX_FOR_CHANNEL(ch), byte) = value;
}
void amc_phy_set_wr_offset(uint8_t ch, uint8_t byte, uint8_t value)
{
rAMP_DQOUTDLLOVRRD(AMP_INDEX_FOR_CHANNEL(ch), byte) = value;
}
void amc_phy_run_dq_training(uint8_t ch)
{
ch = AMP_INDEX_FOR_CHANNEL(ch); // cope with hole in AMP address space
amc_phy_run_dll_update(ch);
rAMP_DQTRNCMD(ch) = 0x1; // execute DQ training sequence
while ((rAMP_DQTRNCMD(ch) & 0x1) != 0) ; // wait for training to be finished
}
uint32_t amc_phy_get_dq_training_status(uint8_t ch, uint8_t byte, uint8_t num_bytes)
{
uint8_t byte_result;
uint32_t status;
status = rAMP_DQTRNSTS(AMP_INDEX_FOR_CHANNEL(ch));
byte_result = (status & (1 << (byte + 16)));
return byte_result;
}
void amc_phy_configure_dll_pulse_mode(uint8_t ch, bool enable)
{
ch = AMP_INDEX_FOR_CHANNEL(ch); // cope with hole in AMP address space
if (!enable) {
rAMP_DLLUPDTCTRL(ch) &= ~((3 << 20) | (1 << 16)); // DLLUptMode = 0, DllUpdtPhyUpdtTyp = 0
}
else {
rAMP_DLLUPDTCTRL(ch) = amp_dllupdtctrl[ch];
amc_phy_run_dll_update(ch);
}
}
void amc_phy_shift_dq_offset(int8_t *dq_offset, uint8_t num_bytes) {
amc_dram_shift_dq_offset(dq_offset, num_bytes);
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2010-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 _AMP_V1_H
#define _AMP_V1_H
#include <platform/soc/hwregbase.h>
/* Apple Memory Phy */
#define AMP_NUM_DLL (4)
#define AMP_FREQUENCY_SLOTS (4)
#define AMP_INDEX_FOR_CHANNEL(_c) (((_c) < 2) ? (_c) : ((_c) + 4))
#define rAMP_AMPEN(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x000))
#define rAMP_AMPCLK(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x004))
#define rAMP_AMPINIT(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x008))
#define rAMP_AMPVER(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x00C))
#define rAMP_IMPCODE(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x080))
#define rAMP_IMPOVRRD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x084))
#define rAMP_IMPAUTOCAL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x088))
#define rAMP_IMPCALPHYUPDT(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x08C))
#define rAMP_IMPCALCMD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x090))
#define rAMP_DRAMSIGDLY(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x094))
#define rAMP_DRAMSIGPH(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x098))
#define rAMP_DQDQSDS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x09C))
#define rAMP_NONDQDS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x0A0))
#define rAMP_DIFFMODE_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x0A4 + ((_f) * 4)))
#define rAMP_DQFLTCTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x0B4))
#define rAMP_RDCAPCFG_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x100 + ((_f) * 4)))
#define rAMP_DQSPDRES(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x110))
#define rAMP_CALDQMSK(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x114))
#define rAMP_CALPATCFG(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x118))
#define rAMP_GATETRNCMD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x11C))
#define rAMP_GATETRNRESLT(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x120))
#define rAMP_DQTRNCFG(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x124))
#define rAMP_DQTRNCMD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x128))
#define rAMP_DQTRNSTS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x12C))
#define rAMP_DLLEN(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x180))
#define rAMP_DLLUPDTCMD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x184))
#define rAMP_MDLLCODE(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x188))
#define rAMP_DLLLOCKTIM(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x18C))
#define rAMP_DLLLOCKCTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x190))
#define rAMP_DLLUPDTINTVL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x194))
#define rAMP_DLLUPDTCTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x198))
#define rAMP_DLLSTS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x19C))
#define rAMP_DQSINDLLCODE(_c,_d) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x1A0 + ((_d) * 0x18)))
#define rAMP_DQSINDLLOVRRD(_c,_d) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x1A4 + ((_d) * 0x18)))
#define rAMP_DQSINDLLSCL_FREQ(_c,_d,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x1A8 + ((_d) * 0x18) + ((_f) * 4)))
#define rAMP_DQOUTDLLCODE(_c,_d) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x200 + ((_d) * 0x18)))
#define rAMP_DQOUTDLLOVRRD(_c,_d) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x204 + ((_d) * 0x18)))
#define rAMP_DQOUTDLLSCL_FREQ(_c,_d,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x208 + ((_d) * 0x18) + ((_f) * 4)))
#define rAMP_CAOUTDLLCODE(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x260))
#define rAMP_CAOUTDLLOVRRD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x264))
#define rAMP_CAOUTDLLSCL_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x268 + ((_f) * 4)))
#define rAMP_CTLOUTDLLCODE(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x278))
#define rAMP_CTLOUTDLLOVRRD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x27C))
#define rAMP_CTLOUTDLLSCL_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x280 + ((_f) * 4)))
#define rAMP_CAPSTDLLCODE(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x290))
#define rAMP_CAPSTDLLOVRRD(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x294))
#define rAMP_CAPSTDLLSCL_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x298 + ((_f) * 4)))
#define rAMP_INTEN(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x400))
#define rAMP_INSTS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x404))
struct amp_per_freq {
uint32_t scl;
uint32_t rdcapcfg;
};
struct amp_params {
uint32_t flags;
struct amp_per_freq freq[AMP_FREQUENCY_SLOTS];
};
#define FLAG_AMP_PARAM_SUPPORT_FMCLK_OFF 0x0001
#define FLAG_AMP_PARAM_FULLDIFFMODE 0x0002
#include <platform/ampconfig.h>
#endif /* ! _AMP_V1_H */
@@ -0,0 +1,137 @@
/*
* 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.
*/
#ifndef _AMP_V2_H
#define _AMP_V2_H
#include <platform/soc/hwregbase.h>
#define AMP_FREQUENCY_SLOTS (4)
/* _t: type, CA or DQ */
/* _c: channel, 0 or 1 */
#define AMP_DQ (0)
#define AMP_CA (1)
#ifndef AMP_REG_OFFSET
# define AMP_REG_OFFSET (0)
#endif
#define rAMP_AMPEN(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x000))
#define rAMP_AMPCLK(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x004))
#define rAMP_AMPINIT(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x008))
#define rAMP_AMPVER(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x00C))
#define rAMP_IMPCODE(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x080))
#define rAMP_IMPOVRRD(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x084))
#define rAMP_IMPAUTOCAL(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x088))
#define rAMP_IMPCALPHYUPDT(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x08C))
#define rAMP_IMPCALCMD(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x090))
#define rAMP_DRAMSIGDLY(_t,_c,_n) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x094 + ((_n) * 4)))
#define rAMP_NONDQDS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x098))
#define rAMP_DQDQSDS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x0A4))
#define rAMP_DIFFMODE_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x0A8 + ((_f) * 4)))
#define rAMP_DQFLTCTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x0B8))
#define rAMP_RDCAPCFG_FREQ(_t,_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x100 + ((_f) * 4)))
#define rAMP_DQSPDENALWYSON(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x110))
#define rAMP_DQSPDRES(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x114))
#define rAMP_RDFIFOPTRSTS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x118))
#define rAMP_CALDQMSK(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x11C))
#define rAMP_CALPATCFG(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x120) - ((_t)*0xC))
#define rAMP_DQTRNCFG(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x124) - ((_t)*0xC))
#define rAMP_DQTRNCMD(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x128) - ((_t)*0xC))
#define rAMP_DQTRNSTS(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x12C) - ((_t)*0xC))
#define rAMP_DLLEN(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x180))
#if SUB_PLATFORM_S7002
#define rAMP_MDLLFREQBINDISABLE(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x184))
#endif
#define rAMP_DLLUPDTCMD(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x184 + AMP_REG_OFFSET))
#define rAMP_MDLLOVRRD(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x04) + 0x188 + AMP_REG_OFFSET))
#define rAMP_MDLLCODE(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) - ((_t)*0x04) + 0x18C + AMP_REG_OFFSET))
#define rAMP_DLLLOCKTIM(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x190 + AMP_REG_OFFSET))
#define rAMP_DLLLOCKCTRL(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x194 + AMP_REG_OFFSET))
#define rAMP_DLLUPDTINTVL(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x198 + AMP_REG_OFFSET))
#define rAMP_DLLUPDTCTRL(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x19C + AMP_REG_OFFSET))
#define rAMP_DLLSTS(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + 0x1A0 + AMP_REG_OFFSET))
#define rAMP_DQSINDLLSCL_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x1B8 + ((_f) * 4) + AMP_REG_OFFSET))
#define rAMP_CAOUTDLLSCL_FREQ(_c,_f) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x1B8 + ((_f) * 4) + AMP_REG_OFFSET))
#define rAMP_TESTMODE(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x180) + 0x200))
#define rAMP_WRDQDESKEW_CTRL(_c,_r,_d) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x400 + ((_r)*0x28) + ((_d)*4)))
#define rAMP_WRDQSDESKEW_CTRL(_c,_r) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x420 + ((_r)*0x28)))
#define rAMP_WRDMDESKEW_CTRL(_c,_b) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x424 + ((_b)*0x28)))
#define rAMP_RDDQDESKEW_CTRL(_c,_r,_d) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x4A0 + ((_r)*0x28) + ((_d)*4)))
#define rAMP_RDDQSDESKEW_CTRL(_c,_r) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x4C0 + ((_r)*0x28)))
#define rAMP_RDDMDESKEW_CTRL(_c,_r) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x4C4 + ((_r)*0x28)))
#define rAMP_CADESKEW_CTRL(_c,_d) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + ((_d)*4) + 0x500))
#define rAMP_CSDESKEW_CTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x528))
#define rAMP_CKEDESKEW_CTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x52C))
#define rAMP_CKDESKEW_CTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x530))
#define rAMP_DQSDLLCTRL_WR(_c, _b) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_b)*0x08) + 0x600))
#define rAMP_DQSDLLCTRL_RD(_c, _b) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_b)*0x08) + 0x620))
#define rAMP_DQWRLVLTIM(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x700))
#define rAMP_DQWRLVLDLYCHAINCTRL(_c, _b) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_b)*0x04) + 0x704))
#define rAMP_DQWRLVLSDLLCODE(_c, _b) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_b)*0x04) + 0x714))
#define rAMP_DQWRLVLRUN(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x724))
#define rAMP_DQWRLVLDATA(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x728))
#define rAMP_CASDLLCTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x700))
#define rAMP_CAWRLVLSDLLCODE(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x800))
#define rAMP_CAWRLVLCLKDLYSEL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x804))
#define rAMP_CACALCTRL(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x100) + 0x800))
#define rAMP_CACALMASK(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x100) + 0x804))
#define rAMP_CACALBYTESEL(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x100) + 0x808))
#define rAMP_CACALBITSELMAP(_t,_c,_n) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x100) + ((_n)*0x04) + 0x80C))
#define rAMP_CACALPAT(_t,_c, _p) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x100) + ((_p)*0x04) + 0x818))
#define rAMP_CACALRUN(_t,_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_CA_SPACING) + ((_t)*0x100) + 0x838))
#define rAMP_CACALRESULT(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x83C))
#define rAMP_DQCALCTRL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x900))
#define rAMP_DQCALRUN(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x908))
#define rAMP_DQCALRESULT(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + 0x90C))
#define rAMP_CAPHYUPDTCRTL(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0xb00))
#define rAMP_CAPHYUPDTSTATUS(_c) (*(volatile u_int32_t *)(AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0xb04))
// Some bit definitions
#define CACALRUN_CACALMODE (1 << 16)
#define CACALRUN_RUNCACAL (1 << 0)
#define TESTMODE_FORCECKELOW (1 << 8)
#define SIGN_BIT_POS (6)
#define AMP_MAX_RD (4)
#define AMP_MAX_DQ (8)
#define AMP_MAX_RANKS_PER_CHAN (2)
struct amp_per_freq {
uint32_t caoutdllscl;
uint32_t dqsindllscl;
uint32_t rdcapcfg;
};
struct amp_params {
struct amp_per_freq freq[AMP_FREQUENCY_SLOTS];
uint32_t drive_strength;
uint32_t cacalib_hw_loops;
uint32_t cacalib_sw_loops;
bool wrlvl_togglephyupdt;
uint32_t imp_auto_cal;
};
#include <platform/ampconfig.h>
#endif /* _AMP_V2_H */
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2012-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.
*/
#ifndef __AMP_V2_CALIBRATION_H
#define __AMP_V2_CALIBRATION_H
#define AMP_MAX_PATTERNS 8
#define CALIB_SAVE 0
#define CALIB_RESTORE 1
#define CALIB_PMU_BYTES 64
// 10 CA bit offsets (8 bits * 10), CK/CKE/CS deskew (8 bits), 5 WrLvl SDLLs (8 bits * 5)
#define CALIB_NUM_BYTES_TO_SAVE (AMC_NUM_CHANNELS * (16))
#define CA_NUM_BITS 10
#define CA_ALL_BITS ((1 << CA_NUM_BITS) - 1)
#define CA_NUM_PATTERNS 64
#define DELIMIT_POS_ADJ_CASDLL 5
#define DELIMIT_POS_ADJ_WRDQSDLL 5
#define CA_MAX_SW_LOOPS CA_NUM_PATTERNS
#define CA_MAX_LOOP_CHN_RNK (CA_MAX_SW_LOOPS * AMC_NUM_CHANNELS * AMC_NUM_RANKS)
#define MR2 0x02
#define MR5 0x05
#define MR41 0x29
#define MR42 0x2A
#define MR48 0x30
#define MIN_ENDPT 0
#define MAX_ENDPT 1
#define MAX_DESKEW_OFFSET 24
#define MAX_DESKEW_PROGRAMMED 31
#define MAX_SDLL_VAL 63
#define MIN_SDLL_VAL 24
#define FINER_STEP_SZ 1
#define COARSE_STEP_SZ 4
#define SOLID_PASS_DETECT 8
#define DLLVAL_BITS 0x7F
#define DESKEW_CTRL_BITS 0x1F
#define SDLL_NUM_BITS 7
#define DESKEW_NUM_BITS 5
#if SUB_PLATFORM_S7002
#define RD_LATENCY_ENCODE 6
#else
#define RD_LATENCY_ENCODE 26
#endif
// maximum possible loops in the hw
#define RDDQ_LOOPCNT 63
#define DQ_NUM_BYTES 4
#define DQ_NUM_BITS_PER_BYTE 8
#define DQ_TOTAL_BITS (DQ_NUM_BYTES * DQ_NUM_BITS_PER_BYTE)
#define DQ_MAX_DESKEW_PER_BIT 24
#define MAX_CAWRLVL_CODE 47
#define MAX_DQWRLVL_CODE 127
#define DQ_NUM_PATTERNS 128
// The number of bytes below is consecutive for a given ch, rnk, bank, and row (interleaving starts after these bytes)
#define DQ_CONSECUTIVE_BYTES_PER_CHRNK 64
#define DQ_BYTES_PER_COL 4 // That makes for 16 consecutive columns (or words)
// the bank and row numbers where patterns will be written
#define DQ_ROW 0
#define DQ_BANK 0
#define DQ_ADDR_RANK_BIT 16 // RIBI2 addressing for dual rank devices
// Macros to change format between signed integer value and offset with sign and magnitude
#define INT_TO_OFFSET(val) ((((val < 0) ? 1 : 0) << SIGN_BIT_POS) | __abs(val))
#define OFFSET_TO_INT(val) ((val & ~(1 << SIGN_BIT_POS)) * ((val & (1 << SIGN_BIT_POS)) ? -1 : 1))
#endif /* ! __AMP_V2_CALIBRATION_H */
+20
View File
@@ -0,0 +1,20 @@
# Copyright (C) 2010-2014 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)
OPTIONS += WITH_HW_AMP=1
ifeq ($(AMP_FILE_VERSION),)
ALL_OBJS += $(LOCAL_DIR)/amp_v1.o
else
ALL_OBJS += $(LOCAL_DIR)/amp_v2.o
endif
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+185
View File
@@ -0,0 +1,185 @@
/*
* Copyright (C) 2013-2014 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 "iboot/amp_v3_shim.h"
///////////////////////////////////////////////////////////////////////////////
////// Global functions
///////////////////////////////////////////////////////////////////////////////
void amc_phy_preinit(void)
{
uint32_t ch;
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
CSR_WRITE(rAMP_DLLUPDTCTRL(AMP_DQ0, ch), 0x00017307);
CSR_WRITE(rAMP_DLLUPDTCTRL(AMP_DQ1, ch), 0x00017307);
CSR_WRITE(rAMP_DLLUPDTCTRL(AMP_CA, ch), 0x00017307);
}
}
void amc_phy_init(bool resume)
{
uint32_t ch, f;
#if !SUPPORT_FPGA
uint32_t rd, dq;
#endif
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
CSR_WRITE(rAMP_AMPEN(AMP_CA, ch), 1);
CSR_WRITE(rAMP_AMPEN(AMP_DQ0, ch), 1);
CSR_WRITE(rAMP_AMPEN(AMP_DQ1, ch), 1);
#if !SUPPORT_FPGA
CSR_WRITE(rAMP_DQDQSDS(AMP_DQ0, ch), amc_phy_params.dqdqsds);
CSR_WRITE(rAMP_DQDQSDS(AMP_DQ1, ch), amc_phy_params.dqdqsds);
CSR_WRITE(rAMP_NONDQDS(ch), amc_phy_params.nondqds);
for (f = 0; f < AMP_FREQUENCY_SLOTS; f++) {
CSR_WRITE(rAMP_DIFFMODE_FREQ(AMP_DQ0, ch, f), 0x00000121);
CSR_WRITE(rAMP_DIFFMODE_FREQ(AMP_DQ1, ch, f), 0x00000121);
}
for (rd = 0; rd < AMP_MAX_RD; rd++) {
for (dq = 0; dq < AMP_MAX_DQ; dq++) {
CSR_WRITE(rAMP_RDDQDESKEW_CTRL(AMP_DQ0, ch, rd, dq), 0x00000006);
CSR_WRITE(rAMP_RDDQDESKEW_CTRL(AMP_DQ1, ch, rd, dq), 0x00000006);
}
}
CSR_WRITE(rAMP_DLLLOCKTIM(AMP_CA, ch), 0x000d0013);
CSR_WRITE(rAMP_DLLLOCKTIM(AMP_DQ0, ch), 0x000d0013);
CSR_WRITE(rAMP_DLLLOCKTIM(AMP_DQ1, ch), 0x000d0013);
#endif
for (f = 0; f < AMP_FREQUENCY_SLOTS; f++) {
CSR_WRITE(rAMP_CAOUTDLLSCL_FREQ(ch, f), amc_phy_params.freq[f].caoutdllscl);
CSR_WRITE(rAMP_DQSINDLLSCL_FREQ(AMP_DQ0, ch, f), amc_phy_params.freq[f].dqsindllscl);
CSR_WRITE(rAMP_DQSINDLLSCL_FREQ(AMP_DQ1, ch, f), amc_phy_params.freq[f].dqsindllscl);
CSR_WRITE(rAMP_RDCAPCFG_FREQ(AMP_DQ0, ch, f), amc_phy_params.freq[f].rdcapcfg);
CSR_WRITE(rAMP_RDCAPCFG_FREQ(AMP_DQ1, ch, f), amc_phy_params.freq[f].rdcapcfg);
CSR_WRITE(rAMP_DQODTVREF_F(AMP_DQ0, ch, f), 0x00000080);
CSR_WRITE(rAMP_DQODTVREF_F(AMP_DQ1, ch, f), 0x00000080);
}
#if !SUPPORT_FPGA
CSR_WRITE(rAMP_DLLUPDTCTRL(AMP_CA, ch), 0x00017507);
CSR_WRITE(rAMP_DLLUPDTCTRL(AMP_DQ0, ch), 0x00017507);
CSR_WRITE(rAMP_DLLUPDTCTRL(AMP_DQ1, ch), 0x00017507);
CSR_WRITE(rAMP_IMPAUTOCAL(AMP_DQ0, ch), 0x00010000);
CSR_WRITE(rAMP_IMPAUTOCAL(AMP_DQ1, ch), 0x00010000);
CSR_WRITE(rAMP_IMPAUTOCAL(AMP_CA, ch), 0x00010000);
CSR_WRITE(rAMP_DLLUPDTINTVL(AMP_CA, ch), 0x10200020);
CSR_WRITE(rAMP_DLLUPDTINTVL(AMP_DQ0, ch), 0x10200020);
CSR_WRITE(rAMP_DLLUPDTINTVL(AMP_DQ1, ch), 0x10200020);
CSR_WRITE(rAMP_DLLEN(AMP_CA, ch), 0x00000100);
CSR_WRITE(rAMP_DLLEN(AMP_DQ0, ch), 0x00000100);
CSR_WRITE(rAMP_DLLEN(AMP_DQ1, ch), 0x00000100);
CSR_WRITE(rAMP_DLLEN(AMP_CA, ch), 0x00000101);
CSR_WRITE(rAMP_DLLEN(AMP_DQ0, ch), 0x00000101);
CSR_WRITE(rAMP_DLLEN(AMP_DQ1, ch), 0x00000101);
CSR_WRITE(rAMP_DLLEN(AMP_CA, ch), 0x00000100);
CSR_WRITE(rAMP_DLLEN(AMP_DQ0, ch), 0x00000100);
CSR_WRITE(rAMP_DLLEN(AMP_DQ1, ch), 0x00000100);
amc_phy_run_dll_update(ch);
CSR_WRITE(rAMP_IMPCALCMD(AMP_CA, ch), 0x00000101);
CSR_WRITE(rAMP_IMPCALCMD(AMP_DQ0, ch), 0x00000101);
CSR_WRITE(rAMP_IMPCALCMD(AMP_DQ1, ch), 0x00000101);
while (CSR_READ(rAMP_IMPCALCMD(AMP_CA, ch)) & 0x1) {}
while (CSR_READ(rAMP_IMPCALCMD(AMP_DQ0, ch)) & 0x1) {}
while (CSR_READ(rAMP_IMPCALCMD(AMP_DQ1, ch)) & 0x1) {}
#endif
CSR_WRITE(rAMP_AMPINIT(AMP_CA, ch), 0x00000001);
CSR_WRITE(rAMP_AMPINIT(AMP_DQ0, ch), 0x00000001);
CSR_WRITE(rAMP_AMPINIT(AMP_DQ1, ch), 0x00000001);
}
}
void amc_phy_run_dll_update(uint8_t ch)
{
CSR_WRITE(rAMP_DLLUPDTCMD(AMP_CA, ch), 0x00000001);
CSR_WRITE(rAMP_DLLUPDTCMD(AMP_DQ0, ch), 0x00000001);
CSR_WRITE(rAMP_DLLUPDTCMD(AMP_DQ1, ch), 0x00000001);
while ((CSR_READ(rAMP_DLLUPDTCMD(AMP_CA, ch)) & 0x1)) ;
while ((CSR_READ(rAMP_DLLUPDTCMD(AMP_DQ0, ch)) & 0x1)) ;
while ((CSR_READ(rAMP_DLLUPDTCMD(AMP_DQ1, ch)) & 0x1)) ;
}
// <rdar://problem/15810647>: workaround to avoid memory read failure when switching from boot speed (f = 3) to normal speed (f = 0)
void amc_phy_pre_normal_speed_enable()
{
uint8_t ch, f;
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
for (f = 1; f < AMP_FREQUENCY_SLOTS; f++) {
CSR_WRITE(rAMP_CAOUTDLLSCL_FREQ(ch, f), amc_phy_params.freq[0].caoutdllscl);
CSR_WRITE(rAMP_DQSINDLLSCL_FREQ(AMP_DQ0, ch, f), amc_phy_params.freq[0].dqsindllscl);
CSR_WRITE(rAMP_DQSINDLLSCL_FREQ(AMP_DQ1, ch, f), amc_phy_params.freq[0].dqsindllscl);
}
#if !SUPPORT_FPGA
amc_phy_run_dll_update(ch);
#endif
}
}
void amc_phy_finalize()
{
uint8_t ch;
for (ch = 0; ch < AMC_NUM_CHANNELS; ch++) {
CSR_WRITE(rAMP_AMPCLK(AMP_CA, ch), amc_phy_params.ampclk);
CSR_WRITE(rAMP_AMPCLK(AMP_DQ0, ch), amc_phy_params.ampclk);
CSR_WRITE(rAMP_AMPCLK(AMP_DQ1, ch), amc_phy_params.ampclk);
}
}
void amc_phy_bypass_prep(int step)
{
}
void amc_phy_restore_calibration_values(bool resume)
{
#if !SUPPORT_FPGA
#ifndef AMP_CALIBRATION_SKIP
// Restore offsets from PMU
if (resume)
calibration_save_restore_regs(CALIB_RESTORE, AMC_NUM_CHANNELS);
#endif
#endif
}
// Perform CA, RDDQ, and WRLVL calibration
void amc_phy_calibration_ca_rddq_cal(bool resume)
{
#ifndef AMP_CALIBRATION_SKIP
if (!resume)
calibration_ca_rddq_wrlvl(resume);
#endif
}
void amc_phy_calibration_wrdq_cal(bool resume)
{
#ifndef AMP_CALIBRATION_SKIP
if (!resume)
calibration_wrdq_rddq(resume);
#endif
}
File diff suppressed because it is too large. Load diff
+105
View File
@@ -0,0 +1,105 @@
/*
* Copyright (C) 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 "amp_v3_shim.h"
// This array will hold the contents of memory that will be used for dq calibration
// static uint8_t dqcal_saved_data[AMC_NUM_RANKS][sizeof(DQ_PRBS7_PATTERNS) * AMC_NUM_CHANNELS]__aligned(32);
static void shim_save_restore_memory_region(uint32_t save_or_restore);
///////////////////////////////////////////////////////////////////////////////
////// Local functions
///////////////////////////////////////////////////////////////////////////////
// Before starting dq calibration, saves the contents of dram region that will be written to with calibration patterns.
// After calibration is complete, restores the contents back to DRAM.
static void shim_save_restore_memory_region(uint32_t save_or_restore)
{
}
///////////////////////////////////////////////////////////////////////////////
////// Global functions
///////////////////////////////////////////////////////////////////////////////
void shim_init_calibration_params(struct amp_calibration_params *cfg_params)
{
// Set the number of channels and ranks on this target
cfg_params->num_channels = AMC_NUM_CHANNELS;
cfg_params->num_ranks = AMC_NUM_RANKS;
// Fiji A0 has a 1 to 1 deskew to sdll step ratio
if((platform_get_chip_id() == 0x7000) && (platform_get_chip_revision() == CHIP_REVISION_A0)) {
cfg_params->sdll_scale = 1;
cfg_params->deskew_scale = 1;
}
}
void shim_configure_pre_ca(void)
{
amc_calibration_start(true);
}
void shim_enable_rddqcal(bool enable)
{
amc_enable_rddqcal(enable);
}
void shim_configure_post_wrlvl(struct amp_calibration_params *cfg_params)
{
amc_calibration_start(false);
}
void shim_configure_pre_wrdq(bool resume)
{
amc_calibration_start(true);
// ok to keep PSQWQCTL0 and PSQWQCTL1 at their value setup for wrdqcal even for the rddqcal that follows
amc_wrdqcal_start(true);
}
void shim_configure_post_prbs_rddq(struct amp_calibration_params *cfg_params)
{
amc_wrdqcal_start(false);
amc_calibration_start(false);
// Save off the CA, WrLvl, Rddq, and Wrdq offsets to PMU
if (!(cfg_params->resume))
calibration_save_restore_regs(CALIB_SAVE, cfg_params->num_channels);
}
void shim_mrcmd_to_ch_rnk(uint8_t rw, uint8_t channel, uint8_t rank, int32_t reg, uintptr_t val)
{
amc_mrcmd_to_ch_rnk((amc_mrcmd_op_t) rw, channel, rank, reg, val);
}
uint64_t shim_compute_dram_addr(uint32_t ch, uint32_t rnk, uint32_t bank, uint32_t row, uint32_t col)
{
return amc_get_uncached_dram_virt_addr(ch, rnk, bank, row, col);
}
uint32_t shim_get_consecutive_bytes_perchnrnk(void)
{
// query AMC for how many consecutive bytes before channel interleaving
return amc_get_consecutive_bytes_perchnrnk();
}
void shim_store_memory_calibration(void *cal_values, uint32_t cal_size)
{
if (power_store_memory_calibration(cal_values, cal_size) == 0)
panic("Unable to save memory calibration values to PMU nvram\n");
}
void shim_load_memory_calibration(void *cal_values, uint32_t cal_size)
{
if (power_load_memory_calibration(cal_values, cal_size) == 0)
panic("Unable to load memory calibration values from PMU nvram\n");
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (C) 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.
*/
#ifndef _AMP_T7000_SHIM_H
#define _AMP_T7000_SHIM_H
#include <debug.h>
#include <sys/menu.h>
#include <drivers/amc/amc.h>
#include <drivers/amc/amc_phy.h>
#include <drivers/dram.h>
#include <drivers/miu.h>
#include <drivers/power.h>
#include <platform.h>
#include <platform/chipid.h>
#include <sys.h>
#include <platform/soc/hwregbase.h>
#include "amp_v3.h"
#include "amp_v3_calibration.h"
#define AMP_MAX_RD (2) // 4 bytes are split across 2 DQ PHYs with 2 bytes each
#define AMP_MAX_DQ (8)
#define shim_panic(...) do { calibration_dump_results(SELECT_CAL_ALL, true); panic(__VA_ARGS__); } while(0)
#define shim_printf(...) dprintf(DEBUG_CRITICAL, __VA_ARGS__)
#define CSR_READ(x) *(volatile u_int32_t *) x
#define CSR_WRITE(x, y) *(volatile u_int32_t *) x = y
// <rdar://problem/13899661>
// "word" for DV requires +1, so for iBoot, should subtract 1 before adding to mem_base
#define MEM_WRITE(mem_base, data, word) *(uint32_t *)(mem_base + ((word-1) << 2)) = data
#define MEM_READ(mem_base, word) *(uint32_t *)(mem_base + ((word-1) << 2))
void shim_init_calibration_params(struct amp_calibration_params *cfg_params);
void shim_configure_pre_ca(void);
void shim_enable_rddqcal(bool enable);
void shim_configure_post_wrlvl(struct amp_calibration_params *cfg_params);
void shim_configure_pre_wrdq(bool resume);
void shim_configure_post_prbs_rddq(struct amp_calibration_params *cfg_params);
void shim_mrcmd_to_ch_rnk(uint8_t rw, uint8_t channel, uint8_t rank, int32_t reg, uintptr_t val);
uint64_t shim_compute_dram_addr(uint32_t ch, uint32_t rnk, uint32_t bank, uint32_t row, uint32_t col);
uint32_t shim_get_consecutive_bytes_perchnrnk(void);
void shim_store_memory_calibration(void *cal_values, uint32_t cal_size);
void shim_load_memory_calibration(void *cal_values, uint32_t cal_size);
struct amp_per_freq {
uint32_t caoutdllscl;
uint32_t dqsindllscl;
uint32_t rdcapcfg;
};
struct amp_params {
struct amp_per_freq freq[AMP_FREQUENCY_SLOTS];
uint32_t dqdqsds;
uint32_t nondqds;
uint32_t ampclk;
};
#include <platform/ampconfig.h>
#endif /* _AMP_T7000_SHIM_H */
+114
View File
@@ -0,0 +1,114 @@
/*
* Copyright (C) 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.
*/
#ifndef _AMP_T7000_H
#define _AMP_T7000_H
#define AMP_FREQUENCY_SLOTS (4)
/* _t: type, DQ0, DQ1, or CA */
/* _c: channel, 0 or 1 */
#define AMP_DQ0 (0)
#define AMP_DQ1 (1)
#define AMP_CA (2)
#define rAMP_AMPEN(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x000)
#define rAMP_AMPCLK(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x004)
#define rAMP_AMPINIT(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x008)
#define rAMP_AMPVER(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x00C)
#define rAMP_IMPCODE(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x080)
#define rAMP_IMPOVRRD(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x084)
#define rAMP_IMPAUTOCAL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x088)
#define rAMP_IMPCALPHYUPDT(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x08C)
#define rAMP_IMPCALCMD(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x090)
#define rAMP_DRAMSIGDLY(_t,_c,_n) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x094 + ((_n) * 4))
#define rAMP_NONDQDS(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x098)
#define rAMP_DQDQSDS(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x09C)
#define rAMP_DIFFMODE_FREQ(_t,_c,_f) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x0A0 + ((_f) * 4))
#define rAMP_DQFLTCTRL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x0B0)
#define rAMP_RDCAPCFG_FREQ(_t,_c,_f) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x100 + ((_f) * 4))
#define rAMP_DQSPDENALWYSON(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x110)
#define rAMP_DQSPDRES(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x114)
#define rAMP_RDFIFOPTRSTS(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x118)
#define rAMP_CALDQMSK(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x11C)
#define rAMP_CALPATCFG(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x120 - ((_t >> 1) * 0x10))
#define rAMP_DQTRNCFG(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x124 - ((_t >> 1) * 0x10))
#define rAMP_DQTRNCMD(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x128 - ((_t >> 1) * 0x10))
#define rAMP_DQTRNSTS(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x12C - ((_t >> 1) * 0x10))
#define rAMP_DLLEN(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x180)
#define rAMP_DLLUPDTCMD(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x184)
#define rAMP_MDLLOVRRD(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x188 + ((_t >> 1) * 4))
#define rAMP_MDLLCODE(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x18C - ((_t >> 1) * 4))
#define rAMP_DLLLOCKTIM(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x190)
#define rAMP_DLLLOCKCTRL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x194)
#define rAMP_DLLUPDTINTVL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x198)
#define rAMP_DLLUPDTCTRL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x19C)
#define rAMP_DLLSTS(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x1A0)
#define rAMP_DQSINDLLSCL_FREQ(_t,_c,_f) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x1B8 + ((_f) * 4))
#define rAMP_CAOUTDLLSCL_FREQ(_c,_f) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x1B8 + ((_f) * 4))
// <rdar://problem/13919568>
#define rAMP_TESTMODE(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x200 + ((_t >> 1) * 0x180))
#define rAMP_WRDQDESKEW_CTRL(_t,_c,_r,_d) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x400 + ((_r)*0x28) + ((_d)*4))
#define rAMP_WRDQSDESKEW_CTRL(_t,_c,_r) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x420 + ((_r)*0x28))
#define rAMP_WRDMDESKEW_CTRL(_t,_c,_b) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x424 + ((_b)*0x28))
#define rAMP_RDDQDESKEW_CTRL(_t,_c,_r,_d) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x450 + ((_r)*0x28) + ((_d)*4))
#define rAMP_RDDQSDESKEW_CTRL(_t,_c,_r) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x470 + ((_r)*0x28))
#define rAMP_RDDMDESKEW_CTRL(_t,_c,_r) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x474 + ((_r)*0x28))
#define rAMP_CADESKEW_CTRL(_c,_d) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x500 + ((_d)*4))
#define rAMP_CSDESKEW_CTRL(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x528)
#define rAMP_CKEDESKEW_CTRL(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x52C)
#define rAMP_CKDESKEW_CTRL(_c,_d) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x530 + ((_d)*4))
#define rAMP_DQSDLLCTRL_WR(_t,_c,_b) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x600 + ((_b)*0x08))
#define rAMP_DQSDLLCTRL_RD(_t,_c,_b) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x610 + ((_b)*0x08))
#define rAMP_DQWRLVLTIM(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x700)
#define rAMP_DQWRLVLDLYCHAINCTRL(_t,_c,_b) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x704 + ((_b)*0x04))
#define rAMP_DQWRLVLSDLLCODE(_t,_c,_b) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x70C + ((_b)*0x04))
#define rAMP_DQWRLVLRUN(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x714)
#define rAMP_DQWRLVLDATA(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x718)
#define rAMP_CASDLLCTRL(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x700)
#define rAMP_CAWRLVLSDLLCODE(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x800)
#define rAMP_CAWRLVLCLKDLYSEL(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0x804)
#define rAMP_CACALCTRL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x800 + ((_t >> 1) * 0x100))
#define rAMP_CACALMASK(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x804)
#define rAMP_CACALCABYTESEL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x808)
#define rAMP_CACALCAMAP0(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x80C)
#define rAMP_CACALCAMAP1(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x810)
#define rAMP_CACALCAMAP2(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x814)
#define rAMP_CACALPAT(_t,_c,_p) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x818 + ((_t >> 1) * 0xEC) + ((_p)*0x04))
#define rAMP_CACALRUN(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x838 + ((_t >> 1) * 0xEC))
#define rAMP_CACALRESULT(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x83C)
#define rAMP_DQCALCTRL(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x900)
#define rAMP_DQCALRUN(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x908)
#define rAMP_DQCALRESULT(_t,_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0x90C)
#define rAMP_DQODTVREF_F(_t,_c,_f) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + ((_t)*AMP_DQCA_SPACING) + 0xB00 + ((_f)*0x04))
#define rAMP_CAPHYUPDTREQ(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0xB00)
#define rAMP_CAPHYUPDTSTATUS(_c) (AMP_BASE_ADDR + ((_c)*AMP_SPACING) + AMP_CA_SPACING + 0xB04)
// Some bit definitions
#define CACALRUN_CACALMODE (1 << 16)
#define CACALRUN_RUNCACAL (1 << 0)
#define TESTMODE_FORCECKELOW (1 << 8)
#define SIGN_BIT_POS (6)
#define AMP_MAX_RANKS_PER_CHAN (2)
#endif /* _AMP_T7000_H */
@@ -0,0 +1,132 @@
/*
* Copyright (C) 2012-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.
*/
#ifndef __AMP_V3_CALIBRATION_H
#define __AMP_V3_CALIBRATION_H
#define AMP_DQ_PER_CHAN 2
#define AMP_MAX_PATTERNS 8
#define CALIB_SAVE 0
#define CALIB_RESTORE 1
#define CALIB_PMU_BYTES 400
// Each register is saved as 1 byte in the array. We will save 1 offset per bit, where offset = SDLL + deskew.
// Number of bytes to save per channel = 10 CA bit offsets + 1 CK/CKE/CS deskew + 5 WrLvl SDLLs
// + 32 RDDQ deskews + 32 WRDQ deskews = 80
#define CALIB_NUM_BYTES_TO_SAVE (AMC_NUM_CHANNELS * (80))
#define CA_NUM_BITS 10
#define CA_ALL_BITS ((1 << CA_NUM_BITS) - 1)
#define CA_NUM_PATTERNS 64
// <rdar://problem/13821643>
#define DELIMIT_POS_ADJ_CASDLL 6
#define DELIMIT_POS_ADJ_WRDQSDLL 6
#define CSBIT (CA_NUM_BITS)
#define CKBIT (CA_NUM_BITS + 1)
#define CKEBIT (CA_NUM_BITS + 2)
#define CASDLLBIT (CA_NUM_BITS + 3)
#define CACAL_MAX_SWLOOPS (8)
#define MR_READ 0
#define MR_WRITE 1
#define MR2 0x02
#define MR5 0x05
#define MR41 0x29
#define MR42 0x2A
#define MR48 0x30
#define MIN_ENDPT 0
#define MAX_ENDPT 1
/* defines for conversion between sdll and deskew steps */
#define DIRECTION_DESKEW_TO_SDLL 0
#define DIRECTION_SDLL_TO_DESKEW 1
#define CA_MAX_DESKEW_OFFSET 29
#define MAX_DESKEW_PROGRAMMED 31
#define MAX_SDLL_VAL 63
#define MIN_SDLL_VAL 24
#define FINER_STEP_SZ 1
#define COARSE_STEP_SZ 4
#define SOLID_PASS_DETECT 8
#define DLLVAL_BITS 0x7F
#define DESKEW_CTRL_BITS 0x1F
#define SDLL_NUM_BITS 7
#define DESKEW_NUM_BITS 5
#define RD_LATENCY_ENCODE 26
// maximum possible loops in the hw
#define RDDQ_LOOPCNT 63
#define DQ_NUM_BYTES 4
#define DQ_NUM_BYTES_PER_DQ 2
#define DQ_NUM_BITS_PER_BYTE 8
#define DQ_TOTAL_BITS (DQ_NUM_BYTES * DQ_NUM_BITS_PER_BYTE)
#define DQ_MAX_DESKEW_PER_BIT 29
#define MAX_CAWRLVL_CODE 127
#define MAX_DQWRLVL_CODE 127
#define DQ_NUM_PATTERNS 128
// The number of bytes below is consecutive for a given ch, rnk, bank, and row (interleaving starts after these bytes)
//#define DQ_CONSECUTIVE_BYTES_PER_CHRNK 256
#define DQ_BYTES_PER_COL 4 // That makes for 64 consecutive columns (or words)
// the bank and row numbers where patterns will be written
#define DQ_ROW 0
#define DQ_BANK 0
#define DQ_ADDR_RANK_BIT 16 // RIBI2 addressing for dual rank devices
// Calibration operation selection
#define SELECT_CACAL 0x1
#define SELECT_WRLVLCAL 0x2
#define SELECT_RDDQCAL 0x4
#define SELECT_WRDQCAL 0x8
#define SELECT_RDDQCAL2 0x10
#define SELECT_CAL_ALL (SELECT_RDDQCAL2 | SELECT_WRDQCAL | SELECT_RDDQCAL | SELECT_WRLVLCAL | SELECT_CACAL)
// This defintion is put here for non-iBoot compilation environments
#ifndef __abs
#define __abs(x) (((x) < 0) ? -(x) : (x))
#endif
// Macros to change format between signed integer value and offset with sign and magnitude
#define INT_TO_OFFSET(val) ((((val < 0) ? 1 : 0) << SIGN_BIT_POS) | __abs(val))
#define OFFSET_TO_INT(val) ((val & ~(1 << SIGN_BIT_POS)) * ((val & (1 << SIGN_BIT_POS)) ? -1 : 1))
void calibration_ca_rddq_wrlvl(bool resume);
void calibration_wrdq_rddq(bool resume);
void calibration_save_restore_regs(uint32_t save_or_restore, uint32_t channels);
void calibration_dump_results(uint32_t operations, bool dump_passing_points);
struct amp_calibration_params {
uint32_t num_channels;
uint32_t num_ranks;
bool resume;
uint32_t cacalib_hw_loops;
uint32_t cacalib_sw_loops;
/*
* Starting with Fiji B0, 1 deskew step is ~22% bigger than 1 sdll step.
* Fiji B0 / Capri B0 should define deskew_scale to 100 and sdll_scale to 122 (or some combo of numbers that indicates 22% increase),
* while Fiji A0 should define 1 and 1.
*/
int32_t sdll_scale;
int32_t deskew_scale;
// SEG specific flags
bool dv_params_valid; // DV flag
bool dv_randomize; // flag to be used by DV to randomize some register values for DV purposes
uint32_t dbg_calib_mode; // flag to be used by SEG to skip calibration operations for debug purposes
};
#endif /* ! __AMP_V3_CALIBRATION_H */
+22
View File
@@ -0,0 +1,22 @@
# Copyright (C) 2010-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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += WITH_HW_AMP=1
# Set ENV_IBOOT for calibration code that is shared with SEG
OPTIONS += ENV_IBOOT
ALL_OBJS += \
$(LOCAL_DIR)/amp_v3.o \
$(LOCAL_DIR)/iboot/amp_v3_shim.o \
$(LOCAL_DIR)/amp_v3_calibration.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+528
View File
@@ -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]);
}
}
+24
View File
@@ -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_
+226
View File
@@ -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_
+119
View File
@@ -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
+659
View File
@@ -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);
}
+73
View File
@@ -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
+46
View File
@@ -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
+893
View File
@@ -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
+99
View File
@@ -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
+247
View File
@@ -0,0 +1,247 @@
/*
* Copyright (C) 2012-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.
*/
#ifdef APCIE_DEBUG_LEVEL
#define DEBUG_LEVEL APCIE_DEBUG_LEVEL
#endif
#include <debug.h>
#include <drivers/apcie.h>
#include <drivers/pci.h>
#include <lib/devicetree.h>
#include <platform.h>
#include <platform/apcie_regs.h>
#include <platform/gpio.h>
#include <platform/gpiodef.h>
#include <platform/timer.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwisr.h>
#include <platform/soc/hwregbase.h>
#include <sys.h>
#include <sys/menu.h>
struct apcie_link_status apcie_link_statuses[APCIE_NUM_LINKS];
struct apcie_link_config *apcie_link_configs;
static pci_device_t host_bridge;
static pci_device_t port_bridges[APCIE_NUM_LINKS];
void apcie_config_read_raw(void *dst, uint32_t bdfo, int size)
{
uintptr_t addr = PCI_CONFIG_BASE | bdfo;
uint32_t value;
dprintf(DEBUG_SPEW, "apcie_config_read[0x%lx, %d]", addr, size);
switch (size) {
case 1:
*(uint8_t *)dst = *(volatile uint8_t *)addr;
value = *(uint8_t *)dst;
break;
case 2:
*(uint16_t *)dst = *(volatile uint16_t *)addr;
value = *(uint16_t *)dst;
break;
case 4:
*(uint32_t *)dst = *(volatile uint32_t *)addr;
value = *(uint32_t *)dst;
break;
default:
panic("apcie_config_read: invalid size %d", size);
}
dprintf(DEBUG_SPEW, " = 0x%x\n", value);
}
static void apcie_config_read(void *priv, void *dst, uint32_t bdfo, int size)
{
struct apcie_link_status *link_status = (struct apcie_link_status *)priv;
if (link_status == NULL && apcie_get_link_enable_count() == 0) {
panic("apcie: config read with no links enabled");
memset(dst, 0xff, size);
return;
}
if (link_status != NULL && !link_status->enabled) {
panic("apcie: config read from disabled link");
memset(dst, 0xff, size);
return;
}
apcie_config_read_raw(dst, bdfo, size);
}
void apcie_config_write_raw(const void *src, uint32_t bdfo, int size)
{
uintptr_t addr = PCI_CONFIG_BASE | bdfo;
switch (size) {
case 1:
dprintf(DEBUG_SPEW, "apcie_config_write[0x%lx, %d] = 0x%x\n",
addr, size, *(uint8_t *)src);
*(volatile uint8_t *)addr = *(uint8_t *)src;
break;
case 2:
dprintf(DEBUG_SPEW, "apcie_config_write[0x%lx, %d] = 0x%x\n",
addr, size, *(uint16_t *)src);
*(volatile uint16_t *)addr = *(uint16_t *)src;
break;
case 4:
dprintf(DEBUG_SPEW, "apcie_config_write[0x%lx, %d] = 0x%x\n",
addr, size, *(uint32_t *)src);
*(volatile uint32_t *)addr = *(uint32_t *)src;
break;
default:
panic("apcie_config_read: invalid size %d", size);
}
}
static void apcie_config_write(void *priv, const void *src, uint32_t bdfo, int size)
{
struct apcie_link_status *link_status = (struct apcie_link_status *)priv;
if (link_status == NULL && apcie_get_link_enable_count() == 0) {
panic("apcie: config write with no links enabled");
}
if (link_status != NULL && !link_status->enabled) {
panic("apcie: config write to disabled link");
}
apcie_config_write_raw(src, bdfo, size);
}
/* Configure the virtual PCI2PCI bridge associated with the port. */
void apcie_setup_root_port_bridge(uint32_t link, struct apcie_link_config *config)
{
pci_device_t bridge;
uint8_t header_type;
dprintf(DEBUG_INFO, "apcie: Probing port bridge for link %d\n", link);
ASSERT(port_bridges[link] == 0);
bridge = pci_bridge_probe(host_bridge, link, 100);
if (bridge == NULL) {
panic("apcie: failed to probe port bridge on link %u\n", link);
}
header_type = pci_get_header_type(bridge);
if (header_type != 1) {
panic("PCI2PCI bridge has wrong header type %d (expected 1)", header_type);
}
pci_bridge_assign_secondary_bus(bridge);
pci_bus_master_enable(bridge, true);
pci_memory_space_enable(bridge, true);
pci_bridge_serr_enable(bridge, true);
port_bridges[link] = bridge;
}
void apcie_disable_all(void)
{
for (int i = 0; i < APCIE_NUM_LINKS; i++)
apcie_disable_link(i);
}
void apcie_init(void)
{
uint32_t memory_base;
// At some point, we may allow targets to override the PCI
// configuration, but this will do for now
apcie_link_configs = platform_apcie_link_configs;
memory_base = platform_map_host_to_pci_addr(PCI_32BIT_BASE);
host_bridge = pci_create_host_bridge("host bridge", 0, memory_base, PCI_32BIT_LEN,
NULL, apcie_config_read, apcie_config_write);
}
pci_device_t apcie_get_port_bridge(uint32_t link)
{
ASSERT(link < APCIE_NUM_LINKS);
return port_bridges[link];
}
void apcie_free_port_bridge(uint32_t link)
{
ASSERT(link < APCIE_NUM_LINKS);
if (port_bridges[link] != NULL) {
pci_free(port_bridges[link]);
port_bridges[link] = NULL;
}
}
static int do_apcie_debug_cmd(int argc, struct cmd_arg *args)
{
int result = -1;
int link;
const char *cmd = args[1].str;
if (cmd == NULL) {
result = -1;
} else {
if (strcmp(cmd, "enable") == 0 && argc == 3) {
link = args[2].n;
if (link >= 0 && link < APCIE_NUM_LINKS) {
apcie_enable_link(link);
result = 0;
}
} else if (strcmp(cmd, "disable") == 0 && argc == 3) {
link = args[2].n;
if (link >= 0 && link < APCIE_NUM_LINKS) {
apcie_disable_link(link);
result = 0;
}
} else if (strcmp(cmd, "counters") == 0 && argc == 4) {
link = args[3].n;
if (strcmp(args[2].str, "read") == 0 &&
link >= 0 && link < APCIE_NUM_LINKS) {
if (apcie_link_statuses[link].enabled) {
rAPCIE_COUNTER_COMMAND(link) = APCIE_COUNTER_ENABLE | APCIE_COUNTER_CAPTURE;
printf("time_L0:\t%u\n", rAPCIE_COUNTER_VALUE(link, 0));
printf("time_L1:\t%u\n", rAPCIE_COUNTER_VALUE(link, 1));
printf("time_L1.1:\t%u\n", rAPCIE_COUNTER_VALUE(link, 2));
printf("time_L1.2:\t%u\n", rAPCIE_COUNTER_VALUE(link, 3));
printf("entry_L0:\t%u\n", rAPCIE_COUNTER_VALUE(link, 4));
printf("entry_L1:\t%u\n", rAPCIE_COUNTER_VALUE(link, 5));
printf("entry_L1.1:\t%u\n", rAPCIE_COUNTER_VALUE(link, 6));
printf("entry_L1.2:\t%u\n", rAPCIE_COUNTER_VALUE(link, 7));
} else {
printf("link not enabled\n");
}
result = 0;
} else if(strcmp(args[2].str, "reset") == 0 &&
link >= 0 && link < APCIE_NUM_LINKS) {
if (apcie_link_statuses[link].enabled) {
rAPCIE_COUNTER_COMMAND(link) = APCIE_COUNTER_ENABLE | APCIE_COUNTER_CLEAR;
} else {
printf("link not enabled\n");
}
result = 0;
}
}
}
if (result < 0) {
printf("Usage:\n");
printf("\tenable <link>\t\t - Enables the specified link\n");
printf("\tdisable <link>\t\t - Disables the specified link\n");
printf("\tcounters read <link>\t - Reads counters for the specified link\n");
printf("\tcounters reset <link>\t - Resets counters for the specified link\n");
}
return result;
}
MENU_COMMAND_DEBUG(apcie, do_apcie_debug_cmd, "APCIe debug commands", NULL);
+16
View File
@@ -0,0 +1,16 @@
# Copyright (C) 2012-2014 Apple Inc. All rights reserved.
#
# This document is the property of Apple Computer, 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 Computer, Inc.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_HW_APCIE=1
ALL_OBJS += \
$(LOCAL_DIR)/apcie.o
+376
View File
@@ -0,0 +1,376 @@
/*
* Copyright (C) 2012 Apple Inc. All rights reserved.
*
* This document is the property of Apple Computer, 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.
*/
#define ASP_TARGET_RTXC 1
#define CASSERT(x, name) typedef char __ASP_CASSERT_##name[(x) ? 1 : -1]
#include <stdint.h>
#include <csi_ipc_protocol.h>
#include <csi_platform_defines.h>
#include <arch.h>
#include <aspcore_mbox.h>
#include <aspcore_protocol.h>
#include <debug.h>
#include <drivers/asp.h>
#include <drivers/csi.h>
#include <lib/env.h>
#include <lib/heap.h>
#include <lib/partition.h>
#include <platform.h>
#include <stdio.h>
#include <sys.h>
#include <sys/menu.h>
#include <target/aspnandconfig.h>
#if !SUPPORT_FPGA
#include <target/powerconfig.h>
#endif
#include "common_util.h"
//
// Defines
//
#define MY_ASP_PROTOCOL_VERSION 10
CASSERT(ASP_PROTOCOL_VERSION == MY_ASP_PROTOCOL_VERSION, protocol_versions_match);
//
// Prototypes
//
static bool asp_get_nand_info(void);
//
// Globals
//
asp_t asp;
aspproto_nand_geom_t nand_info;
struct blockdev *asp_nand_dev;
struct blockdev *asp_nvram_dev;
struct blockdev *asp_firmware_dev;
struct blockdev *asp_llb_dev;
struct blockdev *asp_effaceable_dev;
struct blockdev *asp_syscfg_dev;
struct blockdev *asp_paniclog_dev;
static int asp_set_atv(void)
{
aspproto_cmd_t * command;
command = asp_get_cmd_for_tag(ASP_TAG_GENERIC);
command->op = ASPPROTO_CMD_SETOPTIONS;
command->opts.isATV = true;
if ((asp_send_command(command->tag) != ASPPROTO_CMD_STATUS_SUCCESS)){
dprintf(DEBUG_CRITICAL, "Unable to set atv mode\n");
return -1;
}
return 0;
}
int asp_init(void)
{
csi_status_t result;
asp.state = ASP_STATE_INITIALIZING;
asp.writable = false;
asp_nand_dev = NULL;
asp_nvram_dev = NULL;
asp_firmware_dev = NULL;
asp_llb_dev = NULL;
asp_effaceable_dev = NULL;
asp_syscfg_dev = NULL;
asp_paniclog_dev = NULL;
event_init(&asp.msg_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
result = csi_register_endpoint(CSI_COPROC_ANS, IPC_ENDPOINT_ASP, &asp.msg_event, &asp.csi_token, &asp.ep_name);
if (result != CSI_STATUS_OK)
{
asp.state = ASP_STATE_ERROR_CRITICAL;
dprintf(DEBUG_CRITICAL, "Failed to register ASP endpoint");
return -1;
}
#if !ASP_ENABLE_TIMEOUTS
dprintf(DEBUG_CRITICAL, "ASP Timeouts disabled!\n");
#endif
if (!asp_wait_for_ready())
{
asp.state = ASP_STATE_ERROR_CRITICAL;
return -1;
}
if (!asp_init_tags())
{
asp.state = ASP_STATE_ERROR_CRITICAL;
return -1;
}
if (!asp_get_geometry())
{
// need to create dummy NVRAM device anyways to prevet iBoot panic
asp_create_block_device(ASP_NVRAM);
asp.state = ASP_STATE_ERROR_NOT_REGISTERED;
return -1;
}
if (!asp_get_nand_info())
{
dprintf(DEBUG_CRITICAL, "asp_get_nand_info failed\n");
}
asp_reinit();
if (!asp_create_block_device(ASP_NVRAM))
{
asp.state = ASP_STATE_ERROR_NOT_REGISTERED;
return -1;
}
#if TARGET_POWER_NO_BATTERY
if (asp_set_atv() != 0) {
return -1;
}
#endif
asp_create_block_device(ASP_FIRMWARE);
asp_create_block_device(ASP_LLB);
asp_create_block_device(ASP_EFFACEABLE);
asp_create_block_device(ASP_SYSCFG);
asp_create_block_device(ASP_PANICLOG);
asp.state = ASP_STATE_READY;
return 0;
}
bool asp_wait_for_ready(void)
{
msg_payload_t msg;
uint32_t tag;
csi_status_t result;
#if ASP_ENABLE_TIMEOUTS
if (!event_wait_timeout(&asp.msg_event, ASP_READY_TIMEOUT_US))
{
dprintf(DEBUG_CRITICAL, "ASP timed out waiting for hardware to become ready!");
asp.state = ASP_STATE_TIMEOUT;
return false;
}
#else
event_wait(&asp.msg_event);
#endif
result = csi_receive_message(asp.csi_token, &msg);
if (result != CSI_STATUS_OK)
{
return false;
}
tag = ASPMBOX_FIN_GET_TAG(msg);
if (tag != ASPMBOX_TAG_AWAKE)
{
return false;
}
else
{
if (ASPMBOX_FIN_GET_ERRCODE(msg) != ASP_PROTOCOL_VERSION)
{
dprintf(DEBUG_CRITICAL, "iBoot ASP protocol version %d aspcore protocol version %lld",
ASP_PROTOCOL_VERSION, ASPMBOX_FIN_GET_ERRCODE(msg));
return false;
}
}
return true;
}
bool asp_init_tags(void)
{
addr_t paddr;
uint64_t payload;
uint32_t i;
asp.asp_command = csi_allocate_shared_memory(asp.csi_token,
ASP_NUM_TAGS * ASPPROTO_CMD_LINES * CACHELINE_BYTES);
if (!asp.asp_command)
{
dprintf(DEBUG_CRITICAL, "Unable to allocate ASP command memory");
asp.asp_command = NULL;
return false;
}
paddr = mem_static_map_physical((addr_t)asp.asp_command);
payload = ASPMBOX_MAKE_CMD_SETBASE((uint64_t)paddr, ASP_NUM_TAGS * ASPPROTO_CMD_LINES);
dprintf(DEBUG_CRITICAL, "Using paddr %p, setbase message 0x%016llx\n", (void *)paddr, payload);
if (csi_send_message(asp.csi_token, payload) != CSI_STATUS_OK)
{
dprintf(DEBUG_CRITICAL, "Unable to send ASPMBOX_MASK_CMD_SETBASE message\n");
return false;
}
for (i = 0; i < ASP_NUM_TAGS; i++)
{
aspproto_cmd_t *cmd;
payload = ASPMBOX_MAKE_CMD_SETADDR(i, (i * ASPPROTO_CMD_LINES), ASPPROTO_CMD_LINES);
if (csi_send_message(asp.csi_token, payload) != CSI_STATUS_OK)
{
dprintf(DEBUG_CRITICAL, "Unable to send ASPMBOX_MAKE_CMD_SETADDR message\n");
return false;
}
cmd = asp_get_cmd_for_tag(i);
cmd->tag = i;
}
return true;
}
static bool asp_get_nand_info(void)
{
aspproto_cmd_t * command = asp_get_cmd_for_tag(ASP_TAG_GENERIC);
command->op = ASP_PROTO_CMD_DEVICE_INFO;
if (asp_send_command(command->tag) != ASPPROTO_CMD_STATUS_SUCCESS)
{
dprintf(DEBUG_CRITICAL, "Unable to read ASP device info\n");
return false;
}
if(command->nand_info.size > sizeof(nand_info))
{
panic ("nand info size exceeded\n");
}
memcpy(&nand_info, command->nand_info.data, command->nand_info.size);
return true;
}
bool asp_send_open(void)
{
aspproto_cmd_t * command = asp_get_cmd_for_tag(ASP_TAG_GENERIC);
int status;
command->op = ASPPROTO_CMD_OPEN;
status = asp_send_command(command->tag);
if (status != ASPPROTO_CMD_STATUS_SUCCESS)
{
dprintf(DEBUG_CRITICAL, "Unable to open ASP: 0x%08x\n", status);
return false;
}
return true;
}
int asp_nand_open(void)
{
if (asp.state != ASP_STATE_READY)
{
return -1;
}
if (!asp_send_open())
{
return -1;
}
// NOTE: Need to get NAND geometry again after sending an OPEN
// command to ASP to ensure that the lbaFormatted field is
// correctly updated after CLOG replay
if (!asp_get_geometry())
{
asp.state = ASP_STATE_ERROR_NOT_REGISTERED;
return -1;
}
if (!asp_create_block_device(ASP_NAND))
{
asp.state = ASP_STATE_ERROR_NOT_REGISTERED;
return -1;
}
partition_scan_and_publish_subdevices("asp_nand");
return 0;
}
int asp_set_default_dies_in_parallel(void)
{
asp_set_dies_in_parallel(ASPNAND_SLC_WRITE_DIES_IN_PARALLEL,
ASPNAND_READ_DIES_IN_PARALLEL,
ASPNAND_ERASE_DIES_IN_PARALLEL,
ASPNAND_MLC_WRITE_DIES_IN_PARALLEL,
ASPNAND_TLC_SLC_WRITE_DIES_IN_PARALLEL,
ASPNAND_TLC_READ_DIES_IN_PARALLEL,
ASPNAND_TLC_ERASE_DIES_IN_PARALLEL,
ASPNAND_TLC_TLC_WRITE_DIES_IN_PARALLEL,
CORE_POWERSTATE_HIGH_POWER);
asp_set_dies_in_parallel(ASPNAND_SLC_WRITE_LOW_POWER_DIES_IN_PARALLEL,
ASPNAND_READ_LOW_POWER_DIES_IN_PARALLEL,
ASPNAND_ERASE_LOW_POWER_DIES_IN_PARALLEL,
ASPNAND_MLC_WRITE_LOW_POWER_DIES_IN_PARALLEL,
ASPNAND_TLC_SLC_WRITE_LOW_POWER_DIES_IN_PARALLEL,
ASPNAND_TLC_READ_LOW_POWER_DIES_IN_PARALLEL,
ASPNAND_TLC_ERASE_LOW_POWER_DIES_IN_PARALLEL,
ASPNAND_TLC_TLC_WRITE_LOW_POWER_DIES_IN_PARALLEL,
CORE_POWERSTATE_LOW_POWER);
asp_set_power_state(CORE_POWERSTATE_HIGH_POWER);
return 0;
}
int asp_disable_uid(void)
{
aspproto_cmd_t * command = asp_get_cmd_for_tag(ASP_TAG_GENERIC);
command->op = ASPPROTO_CMD_NAND_DEBUG;
command->tunnel.opcode = NAND_DEBUG_DISABLE_UID;
command->tunnel.buffer_paddr = 0;
command->tunnel.bufferLen = 0;
command->tunnel.options.mask = (1 << ANC_MAX_BUSSES) - 1;
dprintf(DEBUG_CRITICAL, "Disabling ANS UID keys\n");
if (asp_send_command(command->tag) != ASPPROTO_CMD_STATUS_SUCCESS)
{
dprintf(DEBUG_CRITICAL, "Failed to disable UID keys\n");
return -1;
}
return 0;
}
File diff suppressed because it is too large. Load diff
+186
View File
@@ -0,0 +1,186 @@
/*
* 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 __common_util_h__
#define __common_util_h__
//#define ASP_ENABLE_NEURALIZE 1
#define ASP_ENABLE_WRITES 0
#if !SUPPORT_FPGA
#define ASP_ENABLE_TIMEOUTS 1
#else
#define ASP_ENABLE_TIMEOUTS 0
#endif
#define ASP_READY_TIMEOUT_US (90 * 1000 * 1000)
#define ASP_IO_TIMEOUT_US (90 * 1000 * 1000)
typedef struct
{
csi_coproc_t coproc;
struct task_event msg_event;
void * csi_token;
void * asp_command;
uint32_t num_lbas;
uint32_t bytes_per_lba;
bool lba_formatted;
bool util_formatted;
int state;
bool writable;
const char * ep_name;
uint32_t lastUserBand;
uint32_t lastBand;
uint32_t numVirtualSLCBonfireBands;
uint32_t firstIntermediateBand;
uint32_t lastIntermediateBand;
uint8_t chip_id[ANC_MAX_BUSSES][ANC_NAND_ID_SIZE];
uint8_t mfg_id[ANC_MAX_BUSSES][ANC_NAND_ID_SIZE];
} asp_t;
enum
{
ASP_TAG_GENERIC = 0,
ASP_TAG_NAND,
ASP_TAG_NVRAM,
ASP_TAG_FIRMWARE,
ASP_TAG_LLB,
ASP_TAG_EFFACEABLE,
ASP_TAG_SYSCFG,
ASP_TAG_PANICLOG,
ASP_NUM_TAGS
};
//
// Definitions
//
enum
{
ASP_NAND_BLKSZ = (4 * 1024),
ASP_NVRAM_BLKSZ = (8 * 1024),
ASP_FIRMWARE_BLKSZ = (4 * 1024),
ASP_LLB_BLKSZ = (4 * 1024),
ASP_EFFACEABLE_BLKSZ = (4 * 1024),
ASP_SYSCFG_BLKSZ = (8 * 1024),
ASP_PANICLOG_BLKSZ = (4 * 1024),
};
enum
{
ASP_NAND_NUMBLKS = 0, // For general NAND, size should be looked up from geometry
ASP_NVRAM_NUMBLKS = 1,
ASP_FIRMWARE_NUMBLKS = 2048,
#if defined (ASP_LLB_OVERRIDE_NUM_BLKS)
ASP_LLB_NUMBLKS = ASP_LLB_OVERRIDE_NUM_BLKS,
# else
ASP_LLB_NUMBLKS = 253,
#endif
ASP_EFFACEABLE_NUMBLKS = 1,
ASP_SYSCFG_NUMBLKS = 18,
ASP_PANICLOG_NUMBLKS = 256,
};
enum
{
ASP_NAND = 1,
ASP_NVRAM,
ASP_FIRMWARE,
ASP_LLB,
ASP_EFFACEABLE,
ASP_SYSCFG,
ASP_PANICLOG,
};
enum
{
ASP_STATE_INITIALIZING = 0,
ASP_STATE_INITIALIZED,
ASP_STATE_READY,
ASP_STATE_TIMEOUT,
ASP_STATE_ERROR_NOT_REGISTERED,
ASP_STATE_ERROR_NOT_WRITABLE,
ASP_STATE_ERROR_NEURALIZE,
ASP_STATE_ERROR_INVALID_PPNFW,
ASP_STATE_ERROR_CRITICAL,
ASP_STATE_PANIC_RECOVERY,
};
enum
{
ASP_FORMAT_UTIL,
ASP_FORMAT_LBA,
ASP_FORMAT_ALL,
};
#define MAX_SGL_ENTRIES (512)
//Calculate number of cache lines needed for the command and round them up
#define ASPPROTO_CMD_LINES ((((MAX_SGL_ENTRIES * sizeof(uint32_t)) + sizeof(aspproto_cmd_t))/CACHELINE_BYTES) + 1)
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) < (b)) ? (b) : (a))
#define ASP_NAND_BLK_ALIGN_SHIFT (12)
#define ASP_NAND_BLK_ALIGNMENT (1 << ASP_NAND_BLK_ALIGN_SHIFT)
#define VADDR_TO_PADDR32(buffer) (mem_static_map_physical((addr_t)(buffer)) >> ASP_NAND_BLK_ALIGN_SHIFT)
#define ALIGN_UP(val, n) ((((val) + (n) - 1) / (n)) * (n))
int asp_send_command(uint32_t tag);
int asp_wait_for_completion(uint32_t tag);
bool asp_set_writable(void);
bool asp_get_geometry(void);
bool asp_create_block_device(uint8_t type);
bool asp_set_dies_in_parallel(uint32_t mlc_slc_write_dies,
uint32_t mlc_read_dies,
uint32_t mlc_erase_dies,
uint32_t mlc_write_dies,
uint32_t tlc_slc_write_dies,
uint32_t tlc_read_dies,
uint32_t tlc_erase_dies,
uint32_t tlc_tlc_write_dies,
CorePowerState_e power_level);
bool asp_set_power_state(CorePowerState_e powerState);
bool asp_set_indirection_memory(uint32_t indirection_memory, uint32_t legacy_memory);
bool asp_test_scratchpad(void);
#if !RELEASE_BUILD && WITH_MENU
int asp_update_ppn_firmware(const void *fw_buffer, size_t fw_length);
#endif // #if !RELEASE_BUILD && WITH_MENU
aspproto_cmd_t * asp_get_cmd_for_tag(uint32_t tag);
int asp_read_block(struct blockdev *_dev, void *ptr, block_addr block, uint32_t count);
int asp_write_block(struct blockdev *_dev, const void *ptr, block_addr block, uint32_t count);
#if !RELEASE_BUILD
int asp_erase_block(struct blockdev * _dev, off_t offset, uint64_t len);
#endif
bool asp_sync(void);
int asp_type_from_blkdev (struct blockdev *device);
struct blockdev * asp_get_blkdev_for_type (int type);
int asp_set_blkdev_for_type (int type, struct blockdev * device);
bool asp_set_photoflow_mode(core_flow_mode_e slc_mode);
bool asp_enable_bg(void);
bool asp_disable_bg(void);
bool asp_send_open(void);
int asp_panic_recover(void);
bool asp_init_tags(void);
void asp_reinit(void);
bool asp_wait_for_ready(void);
#if defined(ASP_ENABLE_NEURALIZE) && ASP_ENABLE_NEURALIZE
bool asp_neuralize(void);
#endif // ASP_ENABLE_NEURALIZE
#endif // __common_util_h__
File diff suppressed because it is too large. Load diff
+23
View File
@@ -0,0 +1,23 @@
# 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
GLOBAL_INCLUDES += $(LOCAL_DIR)/include \
$(DSTROOT)/usr/local/standalone/firmware \
$(SDKROOT)/../../../usr/local/standalone/firmware
ALL_OBJS += \
$(LOCAL_DIR)/asp.o \
$(LOCAL_DIR)/debug.o \
$(LOCAL_DIR)/common_util.o
OPTIONS += \
WITH_HW_ASP=1 \
WITH_NAND_BOOT=1
+231
View File
@@ -0,0 +1,231 @@
/*
* Copyright (C) 2009-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 <platform.h>
#include <platform/int.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/hwregbase.h>
#include <platform/soc/pmgr.h>
#include <platform/timer.h>
#include <arch/arm/arm.h>
#include <drivers/audio/audio.h>
/*
* AE2 Decrementer
*
* Note that for absolute time, we rely on externally defined timer_get_ticks and
* it is assumed that the tick rate matches our decrementer's.
*/
static void timer_deadline(void *arg);
static void (* timer_deadline_func)(void);
#define DECR_MAX_COUNT (0x7fffffffULL)
static uint32_t timer_count = 0;
static uint32_t timer_late_count = 0;
int timer_init(u_int32_t timer)
{
if (timer) return -1;
/* Disable timer */
rAE2_ADECSR = 0;
/* Install handler but mask for now */
install_int_handler(AE2_INT_DEC, (int_handler)timer_deadline, NULL);
set_int_type(AE2_INT_DEC, INT_TYPE_IRQ | INT_TYPE_LEVEL);
mask_int(AE2_INT_DEC);
return 0;
}
void timer_deadline_enter(u_int64_t deadline, void (* func)(void))
{
uint64_t ticks;
uint32_t decr;
timer_deadline_func = func;
if (func) {
/* convert absolute deadline to relative time */
ticks = timer_get_ticks();
timer_count++;
if (deadline < ticks) {
timer_late_count++;
deadline = 0;
} else {
deadline -= ticks;
}
/* clamp the deadline to our maximum, which is about 89 seconds */
decr = (deadline > DECR_MAX_COUNT) ? DECR_MAX_COUNT : deadline;
/*
* Stop the decrementer and clear the value to ensure
* no pending interrupts. Load the value and go.
*/
rAE2_ADECSR = 0;
rAE2_ADECTR = 0;
unmask_int(AE2_INT_DEC);
rAE2_ADECTR = decr;
rAE2_ADECSR = 1;
} else {
/* no deadline, disable the decrementer and its interrupt */
dprintf(DEBUG_INFO, "timer off\n");
mask_int(AE2_INT_DEC);
rAE2_ADECSR = 0;
}
}
static void
timer_deadline(void *arg)
{
/* acknowledge the interrupt and disable the decrementer */
mask_int(AE2_INT_DEC);
/* if we have a callback, invoke it now */
if (timer_deadline_func)
timer_deadline_func();
}
#if OSC_FREQ == 24000000
utime_t timer_ticks_to_usecs(uint64_t ticks)
{
return ticks / 24;
}
uint64_t timer_usecs_to_ticks(utime_t usecs)
{
return usecs * 24;
}
#endif
uint32_t timer_get_tick_rate(void)
{
return OSC_FREQ;
}
uint64_t timer_get_ticks(void)
{
extern uint64_t aic_get_ticks();
return aic_get_ticks();
}
/*
* AE2 interrupts
*/
static struct interrupt_entry handlers[AE2_MAX_INTS];
#if SUPPORT_SLEEP
struct ae2_int_state {
u_int32_t irqs;
u_int32_t fiqs;
} ae2_saved_state;
#endif
int interrupt_init(void)
{
rAE2_AIRQCR = 0xffffffff;
rAE2_AFIQCR = 0xffffffff;
#if SUPPORT_SLEEP
rAE2_AIRQSR = ae2_saved_state.irqs;
rAE2_AFIQSR = ae2_saved_state.fiqs;
#endif
/* also enable it */
exit_critical_section();
return 0;
}
void unmask_int(uint32_t vector)
{
if (handlers[vector].edge)
rAE2_AFIQSR = 1 << vector;
else
rAE2_AIRQSR = 1 << vector;
#if SUPPORT_SLEEP
ae2_saved_state.irqs = rAE2_AIRQER;
ae2_saved_state.fiqs = rAE2_AFIQER;
#endif
}
void mask_int(uint32_t vector)
{
if (handlers[vector].edge)
rAE2_AFIQCR = 1 << vector;
else
rAE2_AIRQCR = 1 << vector;
#if SUPPORT_SLEEP
ae2_saved_state.irqs = rAE2_AIRQER;
ae2_saved_state.fiqs = rAE2_AFIQER;
#endif
}
void set_int_type(uint32_t vector, int type)
{
/* Overload the "edge" member to indicate FIQ */
handlers[vector].edge = (type & INT_TYPE_FIQ) != 0;
if (type & INT_TYPE_FIQ)
arm_enable_fiqs();
}
int install_int_handler(uint32_t vector, int_handler handler, void *arg)
{
ASSERT(vector < AE2_MAX_INTS);
enter_critical_section();
handlers[vector].handler = handler;
handlers[vector].arg = arg;
exit_critical_section();
return 0;
}
void platform_irq(void)
{
u_int32_t pending, vector;
if (0 == (pending = (rAE2_AIRQRR & rAE2_AIRQER))) {
return;
}
vector = __builtin_ctz(pending);
if (handlers[vector].handler)
handlers[vector].handler(handlers[vector].arg);
}
void platform_fiq(void)
{
u_int32_t pending, vector;
if (0 == (pending = (rAE2_AFIQRR & rAE2_AFIQER))) {
return;
}
vector = __builtin_ctz(pending);
if (handlers[vector].handler)
handlers[vector].handler(handlers[vector].arg);
}
void interrupt_generate_ipc(u_int32_t vector)
{
rAE2_ASFISR = 1 << vector;
}
void interrupt_clear_ipc(u_int32_t vector)
{
rAE2_ASFICR = 1 << vector;
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2009 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Computer, 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 Computer, Inc.
*/
#include <debug.h>
#include <sys/menu.h>
#include <lib/env.h>
#include <platform/memmap.h>
#include <platform/soc/hwregbase.h>
#include <drivers/audio/audio.h>
#if WITH_MENU
#if DEBUG_BUILD
#define AE2_ALIGN (1 << 12)
#define AE2_ALIGN_MASK (AE2_ALIGN - 1)
int do_ae2_go(int argc, struct cmd_arg *args)
{
addr_t addr;
addr = env_get_uint("loadaddr", DEFAULT_LOAD_ADDRESS);
if (addr & AE2_ALIGN_MASK) {
dprintf(DEBUG_CRITICAL, "load address not on a page boundary, cannot remap\n");
return(-1);
}
dprintf(DEBUG_INFO, "configuring AE2 for image @ 0x%08x\n", addr);
/* reset the AE2 processor */
rAE2_MCSCSR = 0;
/* set up translation */
rAE2_MCSATB = addr;
/* release reset */
rAE2_MCSCSR = 1;
return(0);
}
MENU_COMMAND_DEBUG(ae2_go, do_ae2_go, "start AE2 with a downloaded image", NULL);
int do_ae2_stop(int argc, struct cmd_arg *args)
{
/* reset the AE2 processor */
rAE2_MCSCSR = 0;
return(0);
}
MENU_COMMAND_DEBUG(ae2_stop, do_ae2_stop, "stop the AE2 processor", NULL);
#endif /* DEBUG_BUILD */
#endif /* WITH_MENU */
@@ -0,0 +1,60 @@
#ifndef __APPLE_AUDIO_H
#define __APPLE_AUDIO_H
#include <platform/soc/hwregbase.h>
#define rAE2_MCSVER (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e0000))
#define rAE2_MCSCSR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e0004))
#define rAE2_MCSATB (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e0008))
#define rAE2_MIRQRR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1000))
#define rAE2_MIRQER (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1004))
#define rAE2_MIRQSR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1008))
#define rAE2_MIRQCR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e100c))
#define rAE2_MFIQRR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1010))
#define rAE2_MFIQER (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1014))
#define rAE2_MFIQSR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1018))
#define rAE2_MFIQCR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e101c))
#define rAE2_MSFISR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1020))
#define rAE2_MSFICR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001e1024))
#define rAE2_ACSCSR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a0000))
#define rAE2_AIRQRR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1000))
#define rAE2_AIRQER (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1004))
#define rAE2_AIRQSR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1008))
#define rAE2_AIRQCR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a100c))
#define rAE2_AFIQRR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1010))
#define rAE2_AFIQER (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1014))
#define rAE2_AFIQSR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1018))
#define rAE2_AFIQCR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a101c))
#define rAE2_ASFISR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1020))
#define rAE2_ASFICR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a1024))
#define rAE2_ADECSR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a2000))
#define rAE2_ADECTR (*(volatile u_int32_t *)(AUDIO_BASE_ADDR + 0x001a2004))
#define AE2_INT_DEC 0 // Decrementer
#define AE2_INT_DMACINTERR 1 // PL080 error
#define AE2_INT_DMACINTTC 2 // PL080 transaction completion
#define AE2_INT_SW0 4 // Software interrupt 0
#define AE2_INT_SW1 5 // Software interrupt 1
#define AE2_INT_SW2 6 // Software interrupt 2
#define AE2_INT_SW3 7 // Software interrupt 3
#define AE2_INT_BCZ0 8 // Ring buffer 0 byte count exhausted
#define AE2_INT_BCZ1 9 // Ring buffer 1 byte count exhausted
#define AE2_INT_BCZ2 10 // Ring buffer 2 byte count exhausted
#define AE2_INT_BCZ3 11 // Ring buffer 3 byte count exhausted
#define AE2_INT_I2S0 16 // I2S 0 interrupt
#define AE2_INT_I2S1 17 // I2S 1 interrupt
#define AE2_INT_I2S2 18 // I2S 2 interrupt
#define AE2_INT_I2S3 19 // I2S 3 interrupt
#define AE2_INT_SPDIF 20 // SPDIF interrupt
#define AE2_INT_DP0 21 // DisplayPort 0 interrupt
#define AE2_INT_DP1 22 // DisplayPort 1 interrupt
#define AE2_INT_MCA0 23 // MCA0 interrupt
#define AE2_MAX_INTS 24
#endif /* !__APPLE_AUDIO_H */
+20
View File
@@ -0,0 +1,20 @@
# Copyright (C) 2009-2010 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)
ifeq ($(PLATFORM_VARIANT),Audio)
ALL_OBJS += ${LOCAL_DIR}/audio.o
OPTIONS += \
WITH_HW_TIMER=1
else
ALL_OBJS += ${LOCAL_DIR}/debug.o
endif
GLOBAL_INCLUDES += ${LOCAL_DIR}/include
+253
View File
@@ -0,0 +1,253 @@
/*
* Copyright (C) 2011-2014 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 <lib/devicetree.h>
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include <platform/usbconfig.h>
#include <platform/soc/chipid.h>
#include <sys.h>
#include "ausb.h"
// USB Widget related constants
#if !AUSB_USB20PHY_ONLY_VERSION
#if APPLICATION_IBOOT && (PRODUCT_IBOOT || PRODUCT_IBEC)
static const uint32_t high_addr_bits = (1 << 8) | ((SDRAM_BASE >> 32) & 0xf);
#elif APPLICATION_SECUREROM || (APPLICATION_IBOOT && WITH_DFU_MODE)
static const uint32_t high_addr_bits = (1 << 8) | ((SRAM_BASE >> 32) & 0xf);
#else
#error Not Supported
#endif
#endif
///////////////////////////////////////////////////////////
//
// USB PHY Control
//
///////////////////////////////////////////////////////////
static bool usbphy_powered;
void usbphy_power_up(void)
{
if (usbphy_powered)
return;
clock_gate(CLK_USB, true);
clock_gate(CLK_USBCTLREG, true);
clock_gate(CLK_USB_OTG, true);
#if !AUSB_USB20PHY_ONLY_VERSION
// Set the USB OTG Widget register
rAUSB_WIDGET_OTG_ADDR = high_addr_bits;
#endif
// * expects SIDDQ and VBUSVLDEXTSEL set to 1 out of reset.
// * program tuning values
rAUSB_USB20PHY_CFG0 = USBPHY_OTGTUNE0;
#if defined(USBPHY_OTGTUNE1)
rAUSB_USB20PHY_CFG1 = USBPHY_OTGTUNE1;
#endif
// <rdar://problem/15495710> ECO_216: Add register control to FSEL of USB PiCOPHY to get better jitter performance
// The bit USB20PHY_CFG1::PLLBTUNE needs to be set for Fiji revisions > A0 and all Capri revisions
#if defined(SUB_PLATFORM_T7000) || defined(SUB_PLATFORM_T7001)
rAUSB_USB20PHY_CFG1 |= (1 << 2);
#endif
// <rdar://problem/16373379> Fiji >= B1 and Capri >= A1 need to adjust USB20PHY_CFG1:PLLITUNE
#if defined(SUB_PLATFORM_T7000)
if(platform_get_chip_revision() >= CHIP_REVISION_B1)
rAUSB_USB20PHY_CFG1 |= (2 << 4);
#endif
#if defined(SUB_PLATFORM_T7001)
if(platform_get_chip_revision() >= CHIP_REVISION_A1)
rAUSB_USB20PHY_CFG1 |= (2 << 4);
#endif
// Maui A0/A1 uses different tunable than >= B0
#if defined(SUB_PLATFORM_S8000)
if(platform_get_chip_revision() <= CHIP_REVISION_A1)
rAUSB_USB20PHY_CFG0 = USBPHY_OTGTUNE0_AX;
#endif
// * assert PHY_RESET
rAUSB_USB20PHY_CTL |= (1 << 0);
// * clear analog power-down (SIDDQ) and otg-block power-down bits
rAUSB_USB20PHY_CTL &= ~((1 << 3) | (1 << 2));
// * wait 10us delay
spin(10);
// * de-assert PHY_RESET
rAUSB_USB20PHY_CTL &= ~(1 << 0);
// * wait 1000us delay: This wait for PLL to be locked after POR.
spin(1000);
usbphy_powered = true;
}
void usbphy_enable_pullup(void)
{
if (!usbphy_powered)
return;
// Enable D+ PU
rAUSB_USB20PHY_OTGSIG |= (1 << 1);
}
void usbphy_power_down(void)
{
if (!usbphy_powered)
return;
// * Assert PHY_RESET
rAUSB_USB20PHY_CTL |= (1 << 0);
// * disable D+ PU
rAUSB_USB20PHY_OTGSIG &= ~(1 << 1);
// * wait 10us delay
spin(10);
// * De-assert PHY_RESET
rAUSB_USB20PHY_CTL &= ~(1 << 0);
// * wait 1000us delay: This wait for PLL to be locked after POR.
spin(1000);
// * set analog and otg block power down bits
rAUSB_USB20PHY_CTL |= ((1 << 3) | (1 << 2));
clock_gate(CLK_USB_OTG, false);
clock_gate(CLK_USBCTLREG, false);
clock_gate(CLK_USB, false);
usbphy_powered = false;
}
bool usbphy_is_cable_connected(void)
{
bool connected;
if (!usbphy_powered) {
clock_gate(CLK_USB, true);
clock_gate(CLK_USBCTLREG, true);
}
connected = (rAUSB_USB20PHY_OTGSIG & (1 << 8)) != 0;
if (!usbphy_powered) {
clock_gate(CLK_USBCTLREG, false);
clock_gate(CLK_USB, false);
}
return connected;
}
bool usbphy_set_dpdm_monitor(int select)
{
// XXX IBOOT64_TODO
return false;
}
#if WITH_DEVICETREE
void update_devicetree_property(DTNode *node, char * propName, uint32_t value, bool doOR)
{
void *propData;
uint32_t propSize;
if (FindProperty(node, &propName, &propData, &propSize)) {
if (propSize >= sizeof(uint32_t)) {
if(doOR) {
*(uint32_t *)propData |= value;
}
else {
*(uint32_t *)propData = value;
}
}
}
}
void usbphy_update_device_tree(DTNode *node)
{
uint32_t phy_tuning_val;
phy_tuning_val = 0;
#ifdef USBPHY_UOTGTUNE
phy_tuning_val = USBPHY_UOTGTUNE;
#endif
// Fill in the phy-tuning-val property
update_devicetree_property(node, "phy-tuning-val", phy_tuning_val, false);
// <rdar://problem/15495710> ECO_216: Add register control to FSEL of USB PiCOPHY to get better jitter performance
// The bit USB20PHY_CFG1::PLLBTUNE needs to be set for Fiji revisions > A0 and all Capri revisions
#if defined(SUB_PLATFORM_T7000) || defined(SUB_PLATFORM_T7001)
update_devicetree_property(node, "cfg1-device", (1 << 2), true);
update_devicetree_property(node, "cfg1-host", (1 << 2), true);
#endif
// <rdar://problem/16373379> Fiji >= B1 and Capri >= A1 need to adjust USB20PHY_CFG1:PLLITUNE
#if defined(SUB_PLATFORM_T7000)
if(platform_get_chip_revision() >= CHIP_REVISION_B1) {
update_devicetree_property(node, "cfg1-device", (2 << 4), true);
update_devicetree_property(node, "cfg1-host", (2 << 4), true);
}
#endif
#if defined(SUB_PLATFORM_T7001)
if(platform_get_chip_revision() >= CHIP_REVISION_A1) {
update_devicetree_property(node, "cfg1-device", (2 << 4), true);
update_devicetree_property(node, "cfg1-host", (2 << 4), true);
}
#endif
// Maui A0/A1 uses different tunable than >= B0
#if defined(SUB_PLATFORM_S8000)
if(platform_get_chip_revision() <= CHIP_REVISION_A1) {
update_devicetree_property(node, "cfg0-device", USBPHY_OTGTUNE0_AX, false);
}
#endif
}
#endif
///////////////////////////////////////////////////////////
//
// USB Widgets Control
//
///////////////////////////////////////////////////////////
#if !AUSB_USB20PHY_ONLY_VERSION
void ausb_setup_widgets()
{
clock_gate(CLK_USB, true);
// USB_CTL clock should be enabled
rAUSB_WIDGET_OTG_ADDR = high_addr_bits;
rAUSB_WIDGET_OHCI0_ADDR = high_addr_bits;
// Only if EHCI is NOT capable of 64 bit addressing ...
#if (USBEHCI_ADDR_EXT_WIDGET_EN == 1)
rAUSB_WIDGET_EHCI0_ADDR = high_addr_bits;
rAUSB_WIDGET_EHCI1_ADDR = high_addr_bits;
#endif
clock_gate(CLK_USB, false);
}
#endif
+46
View File
@@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef __AUSB_H
#define __AUSB_H
#include <platform/soc/hwregbase.h>
#define rAUSB_USB20PHY_CTL (*(volatile uint32_t *)(AUSB_CTL_REG_BASE_ADDR + AUSB_CTL_USB20PHY_REG_OFFSET + 0x00))
#define rAUSB_USB20PHY_OTGSIG (*(volatile uint32_t *)(AUSB_CTL_REG_BASE_ADDR + AUSB_CTL_USB20PHY_REG_OFFSET + 0x04))
#define rAUSB_USB20PHY_CFG0 (*(volatile uint32_t *)(AUSB_CTL_REG_BASE_ADDR + AUSB_CTL_USB20PHY_REG_OFFSET + 0x08))
#define rAUSB_USB20PHY_CFG1 (*(volatile uint32_t *)(AUSB_CTL_REG_BASE_ADDR + AUSB_CTL_USB20PHY_REG_OFFSET + 0x0C))
#define rAUSB_USB20PHY_BATCTL (*(volatile uint32_t *)(AUSB_CTL_REG_BASE_ADDR + AUSB_CTL_USB20PHY_REG_OFFSET + 0x10))
#define rAUSB_USB20PHY_TEST (*(volatile uint32_t *)(AUSB_CTL_REG_BASE_ADDR + AUSB_CTL_USB20PHY_REG_OFFSET + 0x1C))
#if !AUSB_USB20PHY_ONLY_VERSION
#define rAUSB_WIDGET_OTG_QOS (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x14))
#define rAUSB_WIDGET_OTG_CACHE (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x18))
#define rAUSB_WIDGET_OTG_ADDR (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x1C))
#define rAUSB_WIDGET_EHCI0_QOS (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x34))
#define rAUSB_WIDGET_EHCI0_CACHE (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x38))
#define rAUSB_WIDGET_EHCI0_ADDR (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x3C))
#define rAUSB_WIDGET_OHCI0_QOS (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x54))
#define rAUSB_WIDGET_OHCI0_CACHE (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x58))
#define rAUSB_WIDGET_OHCI0_ADDR (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x5C))
#define rAUSB_WIDGET_EHCI1_QOS (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x74))
#define rAUSB_WIDGET_EHCI1_CACHE (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x78))
#define rAUSB_WIDGET_EHCI1_ADDR (*(volatile uint32_t *)(AUSB_PL301_WIDGET_BASE_ADDR + 0x7C))
#endif
// Errata bits
enum
{
ERRATA_PHY_JITTER_IMPROVEMENT = 1
};
#endif /* __AUSB_H */
+16
View File
@@ -0,0 +1,16 @@
# 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_HW_USBPHY=1
ALL_OBJS += \
$(LOCAL_DIR)/ausb.o
+68
View File
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2012-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <drivers/ccc/ccc.h>
#include <platform/soc/hwregbase.h>
void ccc_override_and_lock_iorvbar(addr_t base_address)
{
rCCC_CPU0_IMPL_IORVBAR = ((base_address >> 11) << 11) | (1 << 0);
rCCC_CPU1_IMPL_IORVBAR = ((base_address >> 11) << 11) | (1 << 0);
#if SUB_PLATFORM_T7001
rCCC_CPU2_IMPL_IORVBAR = ((base_address >> 11) << 11) | (1 << 0);
dprintf(DEBUG_INFO, "IORVBAR:: CPU0:0x%016llx CPU1:0x%016llx CPU2:0x%016llx\n",
rCCC_CPU0_IMPL_IORVBAR, rCCC_CPU1_IMPL_IORVBAR, rCCC_CPU2_IMPL_IORVBAR);
#else
dprintf(DEBUG_INFO, "IORVBAR:: CPU0:0x%016llx CPU1:0x%016llx\n", rCCC_CPU0_IMPL_IORVBAR, rCCC_CPU1_IMPL_IORVBAR);
#endif /* SUB_PLATFORM_T7001 */
}
void ccc_handle_asynchronous_exception(void)
{
dprintf(DEBUG_CRITICAL, "CPU0_IMPL: \n");
dprintf(DEBUG_CRITICAL, "\tFED_ERR_STS:0x%016llx LSU_ERR_STS:0x%016llx MMU_ERR_STS:0x%016llx\n",
rCCC_CPU0_IMPL_FED_ERR_STS, rCCC_CPU0_IMPL_LSU_ERR_STS, rCCC_CPU0_IMPL_MMU_ERR_STS);
#if defined(rCCC_CPU0_IMPL_MIGSTS_EL1)
dprintf(DEBUG_CRITICAL, "\tE_FED_ERR_STS:0x%016llx E_LSU_ERR_STS:0x%016llx MIGSTS_EL1:0x%016llx\n",
rCCC_CPU0_IMPL_E_FED_ERR_STS, rCCC_CPU0_IMPL_E_LSU_ERR_STS, rCCC_CPU0_IMPL_MIGSTS_EL1);
#endif
dprintf(DEBUG_CRITICAL, "\tL2C_ERR_STS:0x%016llx L2C_ERR_ADR:0x%016llx L2C_ERR_INF:0x%016llx\n",
rCCC_CCC_IMPL_L2C_ERR_STS, rCCC_CCC_IMPL_L2C_ERR_ADR, rCCC_CCC_IMPL_L2C_ERR_INF);
}
void ccc_enable_custom_errors(void)
{
// rCCC_CPU0_IMPL_CPU_IOACC_CTL_EL3 |= (0x1ULL << 0); /* enable ns access to CPU_IMPL and HID */
// rCCC_CCC_IMPL_CPM_IOACC_CTL_EL3 |= (0x7ULL << 0); /* enable ns access to CPM IMPL, HID, CNTCTL, and CNTRD
// CPM Thermal, CPM APSC, DVFM, PLL, and PSW */
rCCC_CCC_IMPL_L2C_ERR_STS &= ~(0xffffffffULL); /* clear old status bits */
rCCC_CCC_IMPL_L2C_ERR_ADR = 0; /* clear */
rCCC_CCC_IMPL_L2C_ERR_INF = 0; /* clear */
rCCC_CCC_IMPL_L2C_ERR_STS |= (1ULL << 41); /* enable PIOErr */
}
void ccc_disable_custom_errors(void)
{
rCCC_CCC_IMPL_L2C_ERR_STS &= ~(1ULL << 41); /* disable PIOErr */
}
void ccc_dump_registers(void)
{
// dprintf(DEBUG_INFO, "CPU_IOACC_CTL_EL3:0x%016llx, CPM_IOACC_CTL_EL3:0x%016llx\n", rCCC_CPU0_IMPL_CPU_IOACC_CTL_EL3, rCCC_CCC_IMPL_CPM_IOACC_CTL_EL3);
dprintf(DEBUG_INFO, "FED_ERR_STS:0x%016llx LSU_ERR_STS:0x%016llx MMU_ERR_STS:0x%016llx\n",
rCCC_CPU0_IMPL_FED_ERR_STS, rCCC_CPU0_IMPL_LSU_ERR_STS, rCCC_CPU0_IMPL_MMU_ERR_STS);
dprintf(DEBUG_INFO, "L2C_ERR_STS:0x%016llx L2C_ERR_ADR:0x%016llx L2C_ERR_INF:0x%016llx\n",
rCCC_CCC_IMPL_L2C_ERR_STS, rCCC_CCC_IMPL_L2C_ERR_ADR, rCCC_CCC_IMPL_L2C_ERR_INF);
dprintf(DEBUG_INFO, "CPU0_IORVBAR:0x%016llx CPU1_IORVBAR:0x%016llx\n", rCCC_CPU0_IMPL_IORVBAR, rCCC_CPU1_IMPL_IORVBAR);
}
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2012-2013, 2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#ifndef __APPLE_CCC_H
#define __APPLE_CCC_H
#include <platform/soc/ccc.h>
void ccc_override_and_lock_iorvbar(addr_t base_address);
void ccc_handle_asynchronous_exception(void);
void ccc_enable_custom_errors(void);
void ccc_disable_custom_errors(void);
void ccc_dump_registers(void);
#endif /* __APPLE_CCC_H */
+15
View File
@@ -0,0 +1,15 @@
# 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
ALL_OBJS += \
$(LOCAL_DIR)/ccc.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
File diff suppressed because it is too large. Load diff
+152
View File
@@ -0,0 +1,152 @@
/*
* Copyright (C) 2007 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 __APPLE_CDMA_H
#define __APPLE_CDMA_H
#include <sys/types.h>
#include <platform/soc/hwregbase.h>
__BEGIN_DECLS
#define rCDMA_CHANNEL_CSR(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000000 + (n) * 0x1000))
#define CDMA_CSR_GO (1<<0)
#define CDMA_CSR_ABT (1<<1)
#define CDMA_CSR_PS (1<<2)
#define CDMA_CSR_HIE (1<<3)
#define CDMA_CSR_CIE (1<<4)
#define CDMA_CSR_MTM (1<<7)
#define CDMA_CSR_FC(_x) (((_x) & 0xff) << 8)
#define CDMA_CSR_FC_NONE 0
#define CDMA_CSR_RUN(_x) (((_x) >> 16) & 3)
#define CDMA_CSR_RUN_HALTED 0
#define CDMA_CSR_RUN_RUNNING 1
#define CDMA_CSR_RUN_STOPPED 2
#define CDMA_CSR_ERR (1<<18)
#define CDMA_CSR_HIR (1<<19)
#define CDMA_CSR_CIR (1<<20)
#define CDMA_CSR_PSD (1<<21)
#define CDMA_CSR_HIGH (1<<22)
#define CDMA_CSR_SMALL (1<<23)
#define CDMA_CSR_CCACHE(_x) (((_x) & 0xf) << 24)
#define CDMA_CACHE_BUFFER (1<<0)
#define CDMA_CACHE_CACHE (1<<1)
#define CDMA_CACHE_RALLOC (1<<2)
#define CDMA_CACHE_WALLOC (1<<3)
#define rCDMA_CHANNEL_DCR(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000004 + (n) * 0x1000))
#define CDMA_DCR_DL (1<<0)
#define CDMA_DCR_DTD_RX (0<<1)
#define CDMA_DCR_DTD_TX (1<<1)
#define CDMA_DCR_DW_1 (0<<2)
#define CDMA_DCR_DW_2 (1<<2)
#define CDMA_DCR_DW_4 (2<<2)
#define CDMA_DCR_DBS_1 (0<<4)
#define CDMA_DCR_DBS_2 (1<<4)
#define CDMA_DCR_DBS_4 (2<<4)
#define CDMA_DCR_DBS_8 (3<<4)
#define CDMA_DCR_DBS_16 (4<<4)
#define CDMA_DCR_DBS_32 (5<<4)
#define CDMA_DCR_ST (1<<7)
#define CDMA_DCR_REQ(_x) (((_x) & 0x3f) << 16)
#define rCDMA_CHANNEL_DAR(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000008 + (n) * 0x1000))
#define rCDMA_CHANNEL_DBR(n) (*(volatile int32_t *)(CDMA_BASE_ADDR + 0x00000C + (n) * 0x1000))
#define rCDMA_CHANNEL_MAR(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000010 + (n) * 0x1000))
#define rCDMA_CHANNEL_CAR(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000014 + (n) * 0x1000))
#define rCDMA_CHANNEL_ERR(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000018 + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND0(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000020 + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND1(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000024 + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND2(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000028 + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND3(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x00002C + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND4(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000030 + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND5(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000034 + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND6(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000038 + (n) * 0x1000))
#define rCDMA_CHANNEL_CMND7(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x00003C + (n) * 0x1000))
#define rCDMA_CHANNEL_FIFOST(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000040 + (n) * 0x1000))
#define rCDMA_CHANNEL_FIFODT(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000400 + (n) * 0x1000))
#define rCDMA_CLOCK_ON(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000000 + (n) * 0x4))
#define rCDMA_CLOCK_OFF(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000008 + (n) * 0x4))
#define rCDMA_CLOCK_STATUS(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x000010 + (n) * 0x4))
#define rCDMA_CHANNEL_ERR_MASK (0xFF)
// v4+
#define CDMA_CLOCK_AES_CORE (30)
#define CDMA_CLOCK_AES_WRAP (31)
#define rCDMA_FILTER_KEYDIS (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800000))
#define rCDMA_FILTER_CSR(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800000 + (n) * 0x1000))
#define CDMA_FCSR_LCK (1<<0)
#define CDMA_FCSR_CHANNEL(_x) (((_x) & 0xff) << 8)
#define CDMA_FCSR_ENC (1<<16)
#define CDMA_FCSR_CBC (1<<17)
#define CDMA_FCSR_KL_128 (0<<18)
#define CDMA_FCSR_KL_192 (1<<18)
#define CDMA_FCSR_KL_256 (2<<18)
#define CDMA_FCSR_KS_VARIABLE (1<<20)
#define CDMA_FCSR_KEY(_x) (((_x) & 0x0f) << 21)
#define rCDMA_FILTER_IVR0(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800010 + (n) * 0x1000))
#define rCDMA_FILTER_IVR1(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800014 + (n) * 0x1000))
#define rCDMA_FILTER_IVR2(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800018 + (n) * 0x1000))
#define rCDMA_FILTER_IVR3(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x80001C + (n) * 0x1000))
#define rCDMA_FILTER_KBR0(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800020 + (n) * 0x1000))
#define rCDMA_FILTER_KBR1(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800024 + (n) * 0x1000))
#define rCDMA_FILTER_KBR2(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800028 + (n) * 0x1000))
#define rCDMA_FILTER_KBR3(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x80002C + (n) * 0x1000))
#define rCDMA_FILTER_KBR4(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800030 + (n) * 0x1000))
#define rCDMA_FILTER_KBR5(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800034 + (n) * 0x1000))
#define rCDMA_FILTER_KBR6(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800038 + (n) * 0x1000))
#define rCDMA_FILTER_KBR7(n) (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x80003C + (n) * 0x1000))
#define CDMA_FILTER_CONTEXTS 8
#define CDMA_FILTER_CONTEXT_NORMAL_M2M 1
#define CDMA_FILTER_CONTEXT_DESCRAMBLER 8
// v4+
#define rCDMA_FILTER_SKGCNTL (*(volatile u_int32_t *)(CDMA_BASE_ADDR + 0x800428))
#define CDMA_FSKGCNTL_SKGDIS (1 << 1)
struct cdma_command {
u_int32_t nxt;
u_int32_t ctrl;
#define CDMA_CTRL_CMD_HLT 0
#define CDMA_CTRL_CMD_NOP 1
#define CDMA_CTRL_CMD_LDIV 2
#define CDMA_CTRL_CMD_MEM 3
#define CDMA_CTRL_CMD_STP 4
#define CDMA_CTRL_CMD_MASK 0xf
#define CDMA_CTRL_BAR (1 << 8)
#define CDMA_CTRL_CIR (1 << 9)
#define CDMA_CTRL_FE (1 << 16)
#define CDMA_CTRL_FR (1 << 17)
#define CDMA_CTRL_QOS(_x) (((_x) & 0xf) << 20)
#define CDMA_CTRL_CACHE(_x) (((_x) & 0xf) << 24)
u_int32_t addr;
u_int32_t length;
u_int32_t iv0;
u_int32_t iv1;
u_int32_t iv2;
u_int32_t iv3;
};
bool cdma_clock_enable(int channel, bool state);
__END_DECLS
#endif /* ! __APPLE_CDMA_H */
+299
View File
@@ -0,0 +1,299 @@
/*
* Copyright (C) 2008 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/aes.h>
#include <drivers/dma.h>
#include <platform.h>
#include <platform/int.h>
#include <platform/soc/hwdmachannels.h>
#include <platform/soc/hwisr.h>
#include <platform/soc/hwclocks.h>
#include <sys/task.h>
#include "cdma.h"
#define CDMA_AES_UID_MASK (1 << 0)
#define CDMA_AES_UID_PLUS_MASK (1 << 1) // v4+
static int dma_setup_channel(u_int32_t cmd_dir, int dma_channel,
u_int32_t mem_addr, u_int32_t dev_addr, u_int32_t length,
u_int32_t word_size, u_int32_t burst_size, bool filter);
static void dma_wait_channel_halted(int dma_channel);
static void cdma_dump_aes_channel(int channel);
static struct cdma_command cdma_aes_command[4] __attribute__((aligned(32)));
void
platform_disable_keys(u_int32_t gid, u_int32_t uid)
{
u_int32_t keydis = ((gid << 1) | (uid & CDMA_AES_UID_MASK)) & 0x0000FFFF;
cdma_clock_enable(DMA_MEMORY_TX, true);
rCDMA_FILTER_KEYDIS = keydis;
cdma_clock_enable(DMA_MEMORY_TX, false);
// SKG disable feature is broken.
// To workaroud, UID+ will tag along UID. If UID is disabled, we assume UID+ is also disabled
#if CDMA_VERSION >= 4
if (uid & CDMA_AES_UID_MASK) {
rCDMA_FILTER_SKGCNTL = CDMA_FSKGCNTL_SKGDIS;
}
#endif /* CDMA_VERSION >= 4 */
}
int
aes_hw_crypto_cmd(u_int32_t cmd, void *src, void *dst, size_t len, u_int32_t opts, const void *key, void *iv)
{
u_int32_t cbc_val, dec_val, kl_val, ks_val, kx_val;
clock_gate(CLK_CDMA, true);
cdma_clock_enable(DMA_MEMORY_TX, true);
cdma_clock_enable(DMA_MEMORY_RX, true);
/* clip length to multiple of 16 bytes */
if (len & 0xf)
goto fail;
switch (cmd & AES_CMD_MODE_MASK) {
case AES_CMD_ECB : cbc_val = 0; break;
case AES_CMD_CBC : cbc_val = 1; break;
default : goto fail;
}
switch (cmd & AES_CMD_DIR_MASK) {
case AES_CMD_ENC : dec_val = 1; break;
case AES_CMD_DEC : dec_val = 0; break;
default : goto fail;
}
/* Set the IV */
if (iv != 0) {
rCDMA_FILTER_IVR0(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)iv)[0];
rCDMA_FILTER_IVR1(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)iv)[1];
rCDMA_FILTER_IVR2(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)iv)[2];
rCDMA_FILTER_IVR3(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)iv)[3];
} else {
rCDMA_FILTER_IVR0(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_IVR1(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_IVR2(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_IVR3(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
}
/* Get the key length */
kl_val = 0;
switch (opts & AES_KEY_SIZE_MASK) {
case AES_KEY_SIZE_128 : kl_val = 0; break;
case AES_KEY_SIZE_192 : kl_val = 1; break;
case AES_KEY_SIZE_256 : kl_val = 2; break;
default : goto fail;
}
/* Set the key */
ks_val = 0;
kx_val = 0;
switch (opts & AES_KEY_TYPE_MASK) {
case AES_KEY_TYPE_USER :
ks_val = 1;
switch (kl_val) {
default:
rCDMA_FILTER_KBR7(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[7];
rCDMA_FILTER_KBR6(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[6];
case 1:
rCDMA_FILTER_KBR5(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[5];
rCDMA_FILTER_KBR4(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[4];
case 0:
rCDMA_FILTER_KBR3(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[3];
rCDMA_FILTER_KBR2(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[2];
rCDMA_FILTER_KBR1(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[1];
rCDMA_FILTER_KBR0(CDMA_FILTER_CONTEXT_NORMAL_M2M) = ((u_int32_t *)key)[0];
}
case AES_KEY_TYPE_UID0 : kx_val = 0; break;
case AES_KEY_TYPE_GID0 : kx_val = 1; break;
case AES_KEY_TYPE_GID1 : kx_val = 2; break;
}
/* make sure the requested key is available */
if ((0 == ks_val) && (rCDMA_FILTER_KEYDIS & (1 << kx_val))) {
dprintf(DEBUG_INFO, "CDMA: requested AES key has been disabled\n");
return -1;
}
rCDMA_FILTER_CSR(CDMA_FILTER_CONTEXT_NORMAL_M2M) =
((DMA_MEMORY_TX << 8) | // DMA Channel
(dec_val << 16) | // decode / encode
(cbc_val << 17) | // cbc / ecb
(kl_val << 18) | // key length
(ks_val << 20) | // key select: fixed / variable
(kx_val << 21)); // key index
if (0 != dma_setup_channel(DMA_CMD_DIR_MEM, DMA_MEMORY_TX, (u_int32_t)src, 0, len, 0, 0, true))
goto fail;
if (0 != dma_setup_channel(DMA_CMD_DIR_MEM, DMA_MEMORY_RX, (u_int32_t)dst, 0, len, 0, 0, false))
goto fail;
platform_cache_operation(CACHE_CLEAN, src, len);
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, dst, len);
/* Start the channel */
rCDMA_CHANNEL_CSR(DMA_MEMORY_TX) |= (1 << 0);
rCDMA_CHANNEL_CSR(DMA_MEMORY_RX) |= (1 << 0);
/* Wait for both channels to halt (this ensures both are marked idle) */
dma_wait_channel_halted(DMA_MEMORY_TX);
dma_wait_channel_halted(DMA_MEMORY_RX);
#if CDMA_IS_INCOHERENT
/* If core did any speculative prefetching during DMA, invalidate the cache lines again */
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, dst, len);
#endif
/* Clear user key from the registers */
if (ks_val != 0) {
rCDMA_FILTER_KBR0(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_KBR1(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_KBR2(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_KBR3(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_KBR4(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_KBR5(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_KBR6(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
rCDMA_FILTER_KBR7(CDMA_FILTER_CONTEXT_NORMAL_M2M) = 0;
}
cdma_clock_enable(DMA_MEMORY_TX, false);
cdma_clock_enable(DMA_MEMORY_RX, false);
return 0;
fail:
panic("CDMA AES: bad arguments");
}
static int
dma_setup_channel(u_int32_t cmd_dir, int dma_channel,
u_int32_t mem_addr, u_int32_t dev_addr, u_int32_t length,
u_int32_t word_size, u_int32_t burst_size, bool filter)
{
struct cdma_command *cdma_cmd;
u_int32_t dw_val, dbs_val, dcr_val, ccache_val = 0;
int result = -1;
/* must always abort the channel before configuring it */
rCDMA_CHANNEL_CSR(dma_channel) = CDMA_CSR_ABT;
cdma_cmd = &cdma_aes_command[(dma_channel * 2) - 2];
cdma_cmd->ctrl = (filter ? CDMA_CTRL_FE | CDMA_CTRL_FR : 0) | CDMA_CTRL_BAR | CDMA_CTRL_CMD_MEM;
#if (CDMA_VERSION == 3) || (CDMA_VERSION == 4)
ccache_val = CDMA_CTRL_CACHE(CDMA_CACHE_CACHE);
cdma_cmd->ctrl |= CDMA_CTRL_CACHE(CDMA_CACHE_CACHE);
#elif CDMA_VERSION >= 5
ccache_val = CDMA_CTRL_CACHE(CDMA_CACHE_BUFFER | CDMA_CACHE_CACHE | CDMA_CACHE_WALLOC);
cdma_cmd->ctrl |= CDMA_CTRL_CACHE(CDMA_CACHE_BUFFER | CDMA_CACHE_CACHE);
if (dma_channel == DMA_MEMORY_TX)
cdma_cmd->ctrl |= CDMA_CTRL_CACHE(CDMA_CACHE_WALLOC);
else
cdma_cmd->ctrl |= CDMA_CTRL_CACHE(CDMA_CACHE_RALLOC);
#endif
cdma_cmd->addr = mem_addr;
cdma_cmd->length = length;
/* terminate the chain */
cdma_cmd->nxt = (u_int32_t)(cdma_cmd + 1);
(cdma_cmd + 1)->ctrl = CDMA_CTRL_CMD_HLT;
if (cmd_dir == DMA_CMD_DIR_MEM) {
dcr_val = CDMA_CSR_MTM;
} else {
dcr_val = 0; /* ! CDMA_CSR_MTM */
switch (word_size) {
case 1 : dw_val = 0; break;
case 2 : dw_val = 1; break;
case 4 : dw_val = 2; break;
default : goto exit; break;
}
switch (burst_size) {
case 1 : dbs_val = 0; break;
case 2 : dbs_val = 1; break;
case 4 : dbs_val = 2; break;
case 8 : dbs_val = 3; break;
case 16 : dbs_val = 4; break;
case 32 : dbs_val = 5; break;
default : goto exit; break;
}
rCDMA_CHANNEL_DCR(dma_channel) =
((cmd_dir == DMA_CMD_DIR_TX) ? CDMA_DCR_DTD_TX : CDMA_DCR_DTD_RX) |
(dw_val << 2) |
(dbs_val << 4);
rCDMA_CHANNEL_DAR(dma_channel) = dev_addr;
}
platform_cache_operation(CACHE_CLEAN , cdma_cmd, sizeof(struct cdma_command));
rCDMA_CHANNEL_DBR(dma_channel) = length;
rCDMA_CHANNEL_CAR(dma_channel) = (u_int32_t)cdma_cmd;
/* Clear channel status and configure */
rCDMA_CHANNEL_CSR(dma_channel) = CDMA_CSR_CIR | CDMA_CSR_HIR | CDMA_CSR_ERR | (filter << 8) | dcr_val | ccache_val;
result = 0;
exit:
return result;
}
static void
dma_wait_channel_halted(int dma_channel)
{
while (CDMA_CSR_RUN(rCDMA_CHANNEL_CSR(dma_channel)) == CDMA_CSR_RUN_RUNNING)
task_yield();
}
static void
cdma_dump_aes_channel(int channel)
{
int filter;
bool clock_state;
clock_state = cdma_clock_enable(channel, true);
printf("CDMA: CSR 0x%08x DCR 0x%08x DAR 0x%08x DBR 0x%08x MAR 0x%08x CAR 0x%08x\n",
rCDMA_CHANNEL_CSR(channel), rCDMA_CHANNEL_DCR(channel), rCDMA_CHANNEL_DAR(channel),
rCDMA_CHANNEL_DBR(channel), rCDMA_CHANNEL_MAR(channel), rCDMA_CHANNEL_CAR(channel));
printf("CDMA: CMD_NXT 0x%08x CMD_CMD 0x%08x CMD_ADDR 0x%08x CMD_LEN 0x%08x\n",
rCDMA_CHANNEL_CMND0(channel), rCDMA_CHANNEL_CMND1(channel), rCDMA_CHANNEL_CMND2(channel),
rCDMA_CHANNEL_CMND3(channel));
filter = (rCDMA_CHANNEL_CSR(channel) >> 8) & 0xff;
if (filter > 0) {
printf("FILT: CSR 0x%08x\n", rCDMA_FILTER_CSR(filter));
printf("FILT: IV 0x%08x 0x%08x 0x%08x 0x%08x\n",
rCDMA_FILTER_IVR0(filter),
rCDMA_FILTER_IVR1(filter),
rCDMA_FILTER_IVR2(filter),
rCDMA_FILTER_IVR3(filter));
printf("FILT: KEY 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
rCDMA_FILTER_KBR0(filter),
rCDMA_FILTER_KBR1(filter),
rCDMA_FILTER_KBR2(filter),
rCDMA_FILTER_KBR3(filter),
rCDMA_FILTER_KBR4(filter),
rCDMA_FILTER_KBR5(filter),
rCDMA_FILTER_KBR6(filter),
rCDMA_FILTER_KBR7(filter));
}
cdma_clock_enable(channel, clock_state);
}
+21
View File
@@ -0,0 +1,21 @@
# Copyright (C) 2007 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)
OPTIONS += \
WITH_HW_DMA=1 \
WITH_HW_AES=1
MODULES += \
drivers/aes
ALL_OBJS += \
$(LOCAL_DIR)/cdma.o \
$(LOCAL_DIR)/cdma_aes.o
@@ -0,0 +1,204 @@
/*
* Copyright (C) 2011-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/consistent_debug.h>
#include <platform/memmap.h>
#include <arch/arm/arm.h>
#include <platform.h>
#include <platform/timer.h>
#include <platform/soc/pmgr.h>
#include <stdio.h>
static dbg_registry_t * consistent_debug_registry = NULL;
static dbg_cpr_t* ap_cpr;
static dbg_registry_t* init_consistent_debug_registry(void *consistent_debug_base);
static dbg_record_header_t* consistent_debug_allocate_entry();
static void consistent_debug_register_root_pointer(void);
static void consistent_debug_ensure_visibility()
{
platform_memory_barrier();
#if WITH_NON_COHERENT_DMA
// On platforms without coherent DMA, JTAG access is likely incoherent as well.
platform_cache_operation(CACHE_CLEAN, consistent_debug_registry, sizeof(dbg_registry_t));
#endif
}
int consistent_debug_resume(void)
{
// When resuming from hibernate, assume we have a valid Consistent Debug Registry, and
// put the root address back in the PMGR scratch (which gets cleared on hibernate)
dprintf(DEBUG_SPEW, "Restoring consistent debug state, preserving existing entries...\n");
consistent_debug_registry = (dbg_registry_t*)((void*)CONSISTENT_DEBUG_BASE);
ap_cpr = &consistent_debug_registry->ap_cpr_region;
// Ensure the header is visible before publishing it in the scratch register.
consistent_debug_ensure_visibility();
consistent_debug_register_root_pointer();
return 0;
}
int consistent_debug_init(void)
{
dprintf(DEBUG_SPEW, "Enabling consistent debug...\n");
ASSERT(CONSISTENT_DEBUG_SIZE >= sizeof(dbg_registry_t));
consistent_debug_registry = init_consistent_debug_registry((void*)CONSISTENT_DEBUG_BASE);
// Set up the CPR
dbg_record_header_t ap_progress_report;
ap_progress_report.record_id = kDbgIdCPRHeaderAP;
ap_progress_report.physaddr = (uint64_t)(mem_static_map_physical((uintptr_t)(&consistent_debug_registry->ap_cpr_region)));
ap_progress_report.length = sizeof(dbg_cpr_t);
ap_cpr = &consistent_debug_registry->ap_cpr_region;
consistent_debug_update_ap_cpr(DBG_CPR_STATE_BOOTING, 0);
// Set up the XNU PANIC_BASE pointer, so once booted Astris can still unpack the panic string.
dbg_record_header_t panic_region;
panic_region.record_id = kDbgIdXNUPanicRegion;
panic_region.physaddr = (uint64_t)(PANIC_BASE);
panic_region.length = (uint64_t)(PANIC_SIZE);
if(!consistent_debug_register_header(panic_region))
{
dprintf(DEBUG_INFO, "Unable to register XNU panic region in consistent debug.\n");
}
dbg_record_header_t* hdr = (dbg_record_header_t*)consistent_debug_register_header(ap_progress_report);
RELEASE_ASSERT(hdr);
// Ensure the header is visible before publishing it in the scratch register.
consistent_debug_ensure_visibility();
consistent_debug_register_root_pointer();
return 0;
}
static void consistent_debug_register_root_pointer(void)
{
uint32_t root;
uintptr_t consistent_debug_addr = mem_static_map_physical((uintptr_t)consistent_debug_registry);
root = consistent_debug_encode_root_pointer(consistent_debug_addr, 0);
platform_set_consistent_debug_root_pointer(root);
dprintf(DEBUG_SPEW, "Registered consistent debug root pointer (encoded as 0x%x)\n", (unsigned int)root);
}
dbg_registry_t* consistent_debug_get_registry(void)
{
return consistent_debug_registry;
}
void consistent_debug_update_ap_cpr(cp_state_t state, int arg)
{
if(ap_cpr) {
enter_critical_section();
if(ap_cpr->rdptr + 1 == ap_cpr->wrptr)
{
dprintf(DEBUG_SPEW, "AP CPR is full, advancing rdptr\n");
// Eat the oldest entry if buffer gets full.
ap_cpr->rdptr++;
consistent_debug_ensure_visibility();
}
dbg_cpr_state_entry_t* entry = &ap_cpr->cp_state_entries[ap_cpr->wrptr];
entry->cp_state = state;
entry->cp_state_arg = arg;
entry->timestamp = timer_get_ticks();
consistent_debug_ensure_visibility();
ap_cpr->wrptr++;
exit_critical_section();
dprintf(DEBUG_SPEW, "AP CPR updated at time %llu with state %d (argument %d)\n", entry->timestamp, entry->cp_state, entry->cp_state_arg);
}
}
static dbg_registry_t* init_consistent_debug_registry(void* consistent_debug_base)
{
dbg_registry_t* reg = (dbg_registry_t*)(consistent_debug_base);
memset(reg, 0, sizeof(dbg_registry_t));
reg->top_level_header.record_id = kDbgIdTopLevelHeader;
reg->top_level_header.num_records = DEBUG_REGISTRY_MAX_RECORDS;
reg->top_level_header.record_size_bytes = sizeof(dbg_record_header_t);
return reg;
}
/**
* Finds a free entry in the Consistent Debug Registry and
* reserves it.
*
* @author jdong (12/7/2012)
*
* @return NULL if unsuccessful, otherwise a pointer to a
* reserved entry (where the record_id is set to
* kDbgIdReservedEntry)
*/
static dbg_record_header_t* consistent_debug_allocate_entry(void) {
if (!consistent_debug_registry) {
enter_critical_section();
if(!consistent_debug_registry) {
// Check again to make sure someone else didn't enable it already
consistent_debug_init();
}
exit_critical_section();
return consistent_debug_allocate_entry();
}
for (unsigned int i = 0; i < consistent_debug_registry->top_level_header.num_records; i++) {
dbg_record_header_t *record = &consistent_debug_registry->records[i];
if (__sync_bool_compare_and_swap(&record->record_id, kDbgIdUnusedEntry, kDbgIdReservedEntry)) {
// Reserved an entry at position i.
return (dbg_record_header_t*)record;
}
}
return NULL;
}
dbg_record_header_t* consistent_debug_register_header(dbg_record_header_t hdr) {
dbg_record_header_t *allocated_header = consistent_debug_allocate_entry();
if (allocated_header) {
allocated_header->length = hdr.length;
allocated_header->physaddr = hdr.physaddr;
consistent_debug_ensure_visibility();
// Make sure the hdr/length are visible before the record_id.
allocated_header->record_id = hdr.record_id;
consistent_debug_ensure_visibility();
}
return allocated_header;
}
int consistent_debug_unregister_header(dbg_record_header_t *hdr)
{
if (!consistent_debug_registry) {
return -1;
}
if ((hdr < &consistent_debug_registry->records[0]) ||
(hdr >= &consistent_debug_registry->records[consistent_debug_registry->top_level_header.num_records])) {
// Out of range
return -1;
}
// The record ID may be modified by the JTAG observer, and the caller
// loops on the value changing to kDbgIdUnusedEntry. Make sure we read it from memory.
switch (*(volatile uint64_t*)(&hdr->record_id)) {
case kDbgIdUnusedEntry:
return -1;
case kDbgIdFreeReqEntry:
return 0;
case kDbgIdFreeAckEntry:
hdr->record_id = kDbgIdUnusedEntry;
return 1;
default:
hdr->record_id = kDbgIdFreeReqEntry;
return 0;
}
}
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2011-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 __CONSISTENT_DEBUG_HELPER_FNS__
#define __CONSISTENT_DEBUG_HELPER_FNS__
#include "consistent_debug_registry.h"
// C Helper functions that should serve as a pseudo-library
// for other codebases that use Consistent Debug
// Root Pointer encoder/decoder
/**
* Encode 64-bit physical address of root pointer into a
* suitable 32-bit format.
*
* @param root_pointer 64-bit pointer to the physical address of
* the consistent debug registry
* @param pointer_type One of the types documented in "Debug
* Root Pointer Scratch Register Format" of
* consistent_debug_registry.h
*
* @return uint32_t 0: Cannot encode address with specified
* type, or invalid type. Otherwise, returns a 32-bit
* representation of the address.
*/
static inline uint32_t consistent_debug_encode_root_pointer(uint64_t root_pointer, unsigned int pointer_type)
{
if (pointer_type != 0) {
return 0; // Only type 0 is supported currently
}
if (root_pointer & 0xFFF) {
return 0; // Not page-aligned, truncation would lose information
}
root_pointer >>= 12;
if (root_pointer >= 0x3FFFFFFFF) {
return 0; // Too large to represent
}
return (uint32_t)root_pointer;
}
/**
* opposite of consistent_debug_encode_root_pointer; decodes a root
* pointer encoded in that manner.
*
* @return uint64_t 0 if cannot be decoded, otherwise the
* physical address.
*/
static inline uint64_t consistent_debug_decode_root_pointer(uint32_t encoded_value)
{
if (encoded_value & 0xC0000000) {
return 0; // Can't decode anything other than a "type 0" address
}
uint64_t ret = encoded_value;
ret <<= 12;
return ret;
}
#endif // __CONSISTENT_DEBUG_HELPER_FNS__
@@ -0,0 +1,235 @@
/*
* Copyright (C) 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.
*/
#ifndef __DRIVERS_CONSISTENT_DEBUG_REGISTRY_H
#define __DRIVERS_CONSISTENT_DEBUG_REGISTRY_H
// Consistent Debugging Root Structure Definition.
// See documentation at <TODO: CONSISTENT DEBUGGING WIKI LINK>
// Debug Root Pointer Definitions:
//
// The Debug Root Pointer is used to find the location of the
// Debug Registry. It is currently implemented as a 32-bit PMGR
// scratch register that's reset on boot.
// Debug Root Pointer Scratch Register Format:
// We have 64 bit addresses but a 32-bit scratch register, so
// do a bit of encoding to at least futureproof the use of a
// 32-bit register to the foreseeable future.
//
// Bit: ---31..30-|---- 29...0 -----
// | TYPE | ADDR |
// -------------------------
//
// TYPE:
// 0b00: ADDR is (physical address >> 12). This is good as
// long as our physical address space is within 42 bits,
// which like it will be true for a while.
//
// -other-: Reserved for future encodings. Expected use
// cases are for larger-sized granularity, or indexing off
// another known location like SRAM_BASE/SDRAM_BASE.
//
// Helper functions for producing these encodings are in
// consistent_debug_helper_fns.h
// Debug Registry Definitions:
typedef enum {
DBG_PROCESSOR_AP = 1,
DBG_COPROCESSOR_ANS,
DBG_COPROCESSOR_SEP,
DBG_COPROCESSOR_SIO,
DBG_COPROCESSOR_ISP,
DBG_COPROCESSOR_OSCAR,
DBG_NUM_PROCESSORS
} dbg_processor_t;
#define DEBUG_REGISTRY_MAX_RECORDS 512
#define DEBUG_RECORD_ID_LONG(a, b,c ,d, e, f, g, h) ( ((unsigned long long)((((h) << 24) & 0xFF000000) | (((g) << 16) & 0x00FF0000) | (((f) << 8) & 0x0000FF00) | ((e) & 0x00FF)) << 32) | \
(unsigned long long)((((d) << 24) & 0xFF000000) | (((c) << 16) & 0x00FF0000) | (((b) << 8) & 0x0000FF00) | ((a) & 0x00FF)) )
#define DEBUG_RECORD_ID_SHORT(a,b,c,d) DEBUG_RECORD_ID_LONG(a,b,c,d,0,0,0,0)
/* The Debug Registry lives near the top of SDRAM in a reserved
region. Its size is fixed at compile time and defined as
DEBUG_REGISTRY_MAX_RECORDS. This region holds pointers to
where the actual structures are. This allows more costly data
structures to be allocated at runtime and as needed.
iOS and iBoot will provide APIs for registering records here.
Note that ONLY the AP will be allowed to register entries in
the Consistent Debug Registry. An IOP that wishes to have an
entry have an AP-side handler reserve a record. Once a record
is reserved, anyone may own it.
* |---------------------------|
* | record_id |
* |---------------------------|
* | length |
* |---------------------------|
* | physaddr |
* |---------------------------|
* | next_record_id |
.......
*/
typedef struct {
uint64_t record_id; // 64-bit unique ID identifying the record
uint64_t length; // Length of the payload
uint64_t physaddr; // System physical address of entry
} dbg_record_header_t;
// Life cycle of a record_id:
// Starts out as DbgIdUnusedEntry. When reserved, it becomes
// kDbgIdReservedEntry. Once the correct address/length has been
// filled in, the owner can write the appropriate record ID.
//
// When freeing an entry, the agent should write
// kDbgIdFreeReqEntry to the field. Then, the external reader is
// expected to notice the record_id change and stop using this
// debug region. After the reader no longer is using these
// resources, it will write in kDbgIdFreeAckEntry. Then, the
// consistent debug driver will respond by zeroing the entry.
#define kDbgIdUnusedEntry 0x0ULL
#define kDbgIdReservedEntry DEBUG_RECORD_ID_LONG('R','E','S','E','R','V','E', 'D')
#define kDbgIdFreeReqEntry DEBUG_RECORD_ID_LONG('F','R','E','E','-','R','E','Q')
#define kDbgIdFreeAckEntry DEBUG_RECORD_ID_LONG('F','R','E','E','-','A','C','K')
#define kDbgIdTopLevelHeader DEBUG_RECORD_ID_SHORT('D','B','G','H')
/*
The first entry in the debug area is a "top level header",
which has a different layout than following records. It
describes the size and number of records. Although these
parameters are derivable by looking up the top level
header's magic record ID, this approach lends to more robust
code run-time parsing of the debug area that doesn't have to
be constantly updated for minor format changes.
*/
typedef struct {
uint64_t record_id; // = kDbgIdTopLevelHeader
uint32_t num_records; // = DEBUG_REGISTRY_MAX_RECORDS
uint32_t record_size_bytes; // = sizeof(dbg_record_header_t)
} dbg_top_level_header_t;
/*
* Shared Memory Console Descriptors:
* Record ID: One per SHMConsole
*/
#define DbgIdConsoleHeaderForIOP(which_dbg_processor, which_num) (DEBUG_RECORD_ID_LONG('C','O','N',0,0,0,which_dbg_processor,which_num))
#define kDbgIdConsoleHeaderAP DbgIdConsoleHeaderForIOP(DBG_PROCESSOR_AP, 0)
#define kDbgIdConsoleHeaderANS DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_ANS, 0)
#define kDbgIdConsoleHeaderSIO DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_SIO, 0)
#define kDbgIdConsoleHeaderSEP DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_SEP, 0)
#define kDbgIdConsoleHeaderISP DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_ISP, 0)
#define kDbgIdConsoleHeaderOscar DbgIdConsoleHeaderForIOP(DBG_COPROCESSOR_OSCAR, 0)
/*
* Coprocessor Progress Reports
*
* The CPR is a standardized structure across all coprocessors
* that gives brief info as to its state.
*
* Each coprocessor is responsible for updating its state. The
ring buffer is supposed to wrap around when full, ensuring
that the current state is always present.
*/
#define DbgIdCPRHeaderForIOP(which_dbg_processor, which_num) (DEBUG_RECORD_ID_LONG('C','P','R',0,0,0,which_dbg_processor,which_num))
#define kDbgIdCPRHeaderBase DbgIdCPRHeaderForIOP(0, 0)
#define kDbgIdCPRHeaderAP DbgIdCPRHeaderForIOP(DBG_PROCESSOR_AP, 0)
#define kDbgIdCPRHeaderANS DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_ANS, 0)
#define kDbgIdCPRHeaderSIO DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_SIO, 0)
#define kDbgIdCPRHeaderSEP DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_SEP, 0)
#define kDbgIdCPRHeaderISP DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_ISP, 0)
#define kDbgIdCPRHeaderOscar DbgIdCPRHeaderForIOP(DBG_COPROCESSOR_OSCAR, 0)
typedef enum {
DBG_CPR_STATE_POWEROFF,
DBG_CPR_STATE_BOOTING, // In the bootloader
DBG_CPR_STATE_RUNNING, // Somewhere in the kernel
DBG_CPR_STATE_QUIESCING,
DBG_CPR_STATE_ASLEEP,
DBG_CPR_STATE_CRASHED // Panicked / Crashed
} cp_state_t;
typedef enum {
DBG_CPR_AP_PANICKED_IN_IBOOT,
DBG_CPR_AP_PANICKED_IN_DARWIN,
} cp_ap_crash_arg_t;
typedef struct {
uint64_t timestamp;
uint32_t cp_state; // One of the cp_state_t enumerations
uint32_t cp_state_arg; // IOP-defined supplemental value
} dbg_cpr_state_entry_t;
#define CPR_MAX_STATE_ENTRIES 16 // Arbitrary value
// This second-level struct should be what the Debug Registry record (e.g. kDbgIdCPRHeaderANS) points to.
typedef struct {
uint32_t rdptr;
uint32_t wrptr;
uint32_t num_cp_state_entries;
uint32_t checksum;
dbg_cpr_state_entry_t cp_state_entries[CPR_MAX_STATE_ENTRIES];
} dbg_cpr_t;
/*
* Panic String Locator
*
* Points to the location / length of the panic string.
*/
#define DbgIdPanicHeaderForIOP(which_dbg_processor, which_num) (DEBUG_RECORD_ID_LONG('P','A','N','I','C',0,which_dbg_processor,which_num))
#define kDbgIdPanicHeaderAP DbgIdPanicHeaderForIOP(DBG_PROCESSOR_AP, 0)
/*
* Memory Map Hints:
*
* Useful regions (such as those defined in platform/memmap.h) start with magic "MAP"
*
*/
// XNU's PANIC_BASE will be recorded here. This can allow Astris to read the kernel's
#define kDbgIdXNUPanicRegion (DEBUG_RECORD_ID_LONG('M','A','P','P','A','N','I','C'))
// XNU's physical load address for Astris's use in coredumps
#define kDbgIdXNUKernelRegion (DEBUG_RECORD_ID_LONG('M','A','P','K','E','R','N','L'))
typedef struct {
dbg_top_level_header_t top_level_header;
dbg_record_header_t records[DEBUG_REGISTRY_MAX_RECORDS];
// Stuff the AP's Progress Report buffer at the end of this
// structure. It's currently the only processor that doesn't
// have some easier form of persistent memory that survives the
// iBoot->iOS handoff (e.g. ANS has its private heap)
dbg_cpr_t ap_cpr_region;
} dbg_registry_t;
#endif
+22
View File
@@ -0,0 +1,22 @@
# Copyright (C) 2011-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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
OPTIONS += \
WITH_CONSISTENT_DBG=1
MODULES += \
drivers/apple/consistent_debug
ALL_OBJS += \
$(LOCAL_DIR)/consistent_debug.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+747
View File
@@ -0,0 +1,747 @@
/*
* Copyright (C) 2011-2012 Apple Computer, Inc. All rights reserved.
*
* This document is the property of Apple Computer, 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 Computer, Inc.
*/
#include <platform.h>
#include <platform/memmap.h>
#include <arch.h>
#include <debug.h>
#include <sys/task.h>
#include <sys/boot.h>
#include <lib/env.h>
#include <platform/timer.h>
#include <drivers/a7iop/a7iop.h>
#include <drivers/csi.h>
#include "csi_private.h"
// protocol files
#include <csi_system.h>
#include "endpoints/management_ep.h"
#include "endpoints/syslog_ep.h"
#include "endpoints/console_ep.h"
#include "endpoints/crashlog_ep.h"
#include <platform/soc/hwclocks.h>
#include <platform/clocks.h>
#include <platform/soc/pmgr.h>
// XXX <rdar://problem/10422340> addresses the need for a common copy of this file
#include "queue.h"
static const MailboxEndpointConfig endpoint_config[] = MAILBOX_ENDPOINT_INITIALIZERS;
#define MAILBOX_ENDPOINT_INITIALIZER_COUNT (int)(sizeof(endpoint_config)/sizeof(*endpoint_config))
#define EP_QUEUE_ADVANCE(_index, _size) ((_index) = ((((_index) + 1) >= _size) ? 0 : ((_index) + 1)))
// A simple mechanism to put a governor on potentially high volume log scenarios
#define LOG_GOV_PERIOD_USEC 5000000
typedef struct {
int occ_count;
u_int64_t last_log;
} log_governor_t;
typedef struct {
bool registered;
csi_coproc_t coproc;
uint32_t index;
const char *name;
uint32_t rcv_queue_size;
msg_payload_t *rcv_queue;
uint32_t next_in;
uint32_t next_out;
uint32_t sm_alignment;
struct task_event *rcv_not_empty_event;
} endpoint_desc_t;
typedef enum {
COPROC_STATE_RESET = 0,
COPROC_STATE_ERROR_FW,
COPROC_STATE_ERROR_STARTING,
COPROC_STATE_RUNNING,
COPROC_STATE_STOPPED,
} coproc_state_t;
typedef struct {
csi_coproc_t coproc;
coproc_state_t state;
coproc_feature_t feature;
uint32_t send_timeout;
uint32_t endpoint_count;
endpoint_desc_t endpoints[CSI_MAX_ENDPOINTS];
fw_desc_t fw_desc;
struct task_event power_state_event;
log_governor_t gov_ep_queue_ovflw;
log_governor_t gov_ep_not_reg;
} csi_desc_t;
static csi_desc_t *csi_descs[CSI_COPROC_MAX] = {NULL};
//
// Private functions
//
static endpoint_desc_t *find_endpoint(csi_coproc_t which_coproc, ipc_endpoint_t which_ep);
static int inbox_not_empty_task(void *arg);
static void message_dispatcher(endpoint_desc_t *ep, msg_payload_t msg_payload);
static void *allocate_shared_memory(uint32_t capacity, uint32_t alignment);
static bool check_log_gov(log_governor_t *gov, csi_coproc_t which_coproc);
//
// csi_init
//
csi_status_t
csi_init (csi_coproc_t which_coproc)
{
int j;
csi_desc_t *csi;
csi_status_t status;
endpoint_desc_t *next_ep;
if (which_coproc >= CSI_COPROC_MAX) {
return CSI_STATUS_UNSUPPORTED;
}
// enforce single instance
REQUIRE(csi_descs[which_coproc]==NULL);
csi_descs[which_coproc] = malloc(sizeof(csi_desc_t));
REQUIRE(csi_descs[which_coproc]!=NULL);
csi = csi_descs[which_coproc];
csi->coproc = which_coproc;
csi->state = COPROC_STATE_RESET;
csi->send_timeout = CSI_SEND_MESSAGE_TIMEOUT;
csi->gov_ep_queue_ovflw.occ_count = 0;
csi->gov_ep_not_reg.occ_count = 0;
csi->feature = COPROC_FEATURE_NONE;
// Create all endpoint structures - all are inactive until registered.
csi->endpoint_count = 0;
next_ep = csi->endpoints;
for (j=CSI_MAX_ENDPOINTS; --j>=0;) {
next_ep->registered = false;
next_ep->coproc = csi->coproc;
next_ep->index = 0;
next_ep->name = "none";
next_ep->rcv_queue_size = 0;
next_ep->rcv_queue = NULL;
next_ep->next_in = 0;
next_ep->next_out = 0;
next_ep->rcv_not_empty_event = NULL;
next_ep++;
}
next_ep = csi->endpoints;
for (j=0; (j<MAILBOX_ENDPOINT_INITIALIZER_COUNT) && (csi->endpoint_count<CSI_MAX_ENDPOINTS); j++) {
if (endpoint_config[j].rcv_queue_size != 0) {
next_ep->index = endpoint_config[j].index;
next_ep->name = endpoint_config[j].name;
next_ep->rcv_queue_size = endpoint_config[j].rcv_queue_size;
next_ep->rcv_queue = malloc(sizeof(*next_ep->rcv_queue) * endpoint_config[j].rcv_queue_size);
REQUIRE(next_ep->rcv_queue!=NULL);
next_ep->next_in = 0;
next_ep->next_out = ~(0);
next_ep++;
csi->endpoint_count++;
}
}
// create built-in endpoints
bi_ep_mgmt_create(csi->coproc, &(csi->power_state_event));
bi_ep_crashlog_create(csi->coproc);
bi_ep_console_create(csi->coproc);
bi_ep_syslog_create(csi->coproc);
// Find the firmware, prep it, start the coprocessor.
if (CSI_COPROC_ANS == which_coproc) {
// region is provided by iBoot
csi->fw_desc.region_base = ASP_BASE;
csi->fw_desc.region_size = (uint32_t)(ASP_SIZE);
} else {
// Allocate region for all other corpoc
// XXX: what size is needed - to be added later when/if other coproc are supported.
csi->fw_desc.region_base = 0x00;
csi->fw_desc.region_size = 0x00;
return CSI_STATUS_UNSUPPORTED;
}
status = fw_fixup_and_relocate(csi->coproc, &csi->fw_desc);
if (status != CSI_STATUS_OK) {
CSI_LOG(CRITICAL, which_coproc, "fw_fixup_and_relocate() error (%s)\n", CSI_STATUS_STR(status));
csi->state = COPROC_STATE_ERROR_FW;
return status;
}
status = csi_start (which_coproc);
if (status != CSI_STATUS_OK) {
return status;
}
// create the power state event
event_init(&(csi->power_state_event), EVENT_FLAG_AUTO_UNSIGNAL, false);
return CSI_STATUS_OK;
}
csi_status_t
csi_start (csi_coproc_t which_coproc)
{
csi_desc_t *csi;
addr_t remap_base;
uint64_t remap_size;
int status;
csi = csi_descs[which_coproc];
remap_base = (const addr_t)csi->fw_desc.region_base;
remap_size = (const uint64_t)csi->fw_desc.region_size;
status = akf_start(KFW(csi->coproc), remap_base, remap_size);
if (status != 0) {
CSI_LOG(CRITICAL, which_coproc, "akf_start() error: %d\n", status);
csi->state = COPROC_STATE_ERROR_STARTING;
return CSI_STATUS_ERROR;
}
csi_clr_feature (which_coproc, COPROC_FEATURE_SHUTDOWN_IN_PROGRESS);
CSI_LOG(DEBUG_SPEW, which_coproc, "coproc started: remap base = %p, size = 0x%llx (feature=%x)\n", (void *)remap_base, remap_size, csi_get_feature(which_coproc));
csi->state = COPROC_STATE_RUNNING;
// start the message reading task
task_start(task_create("csi inbox_not_empty_task", inbox_not_empty_task, (void*)csi, kTaskStackSize_inbox_not_empty));
task_yield(); // give them a chance to run
return CSI_STATUS_OK;
}
csi_status_t
csi_panic_recover (csi_coproc_t which_coproc)
{
csi_desc_t *csi;
csi_status_t status;
csi = csi_descs[which_coproc];
// stop the AKF to reset it.
csi_stop (which_coproc);
// destroy all the allocated shared memory
// force a power state change to off.
handle_power_state_ack (mgmt_descs[which_coproc], CSI_PS_OFF);
clock_reset_device(CLK_ANS);
// give a chance to all other task to terminate
task_yield();
// reset the memory
status = fw_fixup_and_relocate (csi->coproc, &csi->fw_desc);
if (status != CSI_STATUS_OK) {
CSI_LOG(CRITICAL, which_coproc, "panic recovery failed: fw_fixup_and_relocate() error (%s)\n", CSI_STATUS_STR(status));
csi->state = COPROC_STATE_ERROR_FW;
return status;
}
// restart the AKF
return csi_start (which_coproc);
}
csi_status_t
csi_late_init (void) {
#if APPLICATION_IBOOT
const char *boot_args;
char *arg_str;
uint32_t verbosity;
verbosity = 9999;
boot_args = env_get("boot-args");
if (boot_args != NULL) {
arg_str = strstr(boot_args, "csi_syslog_verbosity=");
if (arg_str != NULL) {
verbosity = arg_str[strlen("csi_syslog_verbosity=")] - '0';
}
}
for (int j = 0; j < CSI_COPROC_MAX; j++) {
bi_ep_syslog_verbosity(j, verbosity);
}
#endif
return CSI_STATUS_OK;
}
csi_status_t
csi_stop (csi_coproc_t which_coproc)
{
csi_desc_t *csi;
csi = csi_descs[which_coproc];
akf_stop (KFW(csi->coproc));
csi->state = COPROC_STATE_STOPPED;
return CSI_STATUS_OK;
}
csi_status_t
csi_quiesce (enum boot_target target)
{
csi_status_t status = CSI_STATUS_OK;
for (int j = 0; j < CSI_COPROC_MAX; j++) {
csi_desc_t *csi = csi_descs[j];
if (NULL != csi) {
if (csi->state == COPROC_STATE_RUNNING) {
// put the coproc in suspend to ram for all state
status = hibernate_iop (csi->coproc);
}
}
}
return status;
}
csi_status_t
request_iop_power_state (csi_coproc_t which_coproc, csi_power_state_t ps)
{
csi_desc_t *csi;
csi = csi_descs[which_coproc];
// if the power state event was previously signaled (panic recovery for example)
// unsignal it was we need to wait for a new transition
event_unsignal (&(csi->power_state_event));
// Request the IOP to transition to the specified power state
// power message are always send thru the management channel
bi_ep_mgmt_send_ps (which_coproc, ps);
// Wait for the acknowledge message.
event_wait (&(csi->power_state_event));
// make sure the power state is the one we want
if (bi_ep_mgmt_get_power_state(csi->coproc) != ps) {
return CSI_STATUS_ERROR;
}
return CSI_STATUS_OK;
}
csi_status_t
quiesce_iop (csi_coproc_t which_coproc)
{
csi_desc_t *csi;
csi_status_t status;
csi = csi_descs[which_coproc];
// Request the new power state
status = request_iop_power_state (which_coproc, CSI_PS_QUIESCE);
if (CSI_STATUS_OK != status) {
CSI_LOG(CRITICAL, csi->coproc, "Failed to quiesce\n");
return CSI_STATUS_ERROR;
}
CSI_LOG(CRITICAL, csi->coproc, "quiesced\n");
return CSI_STATUS_OK;
}
csi_status_t
hibernate_iop (csi_coproc_t which_coproc)
{
csi_desc_t *csi;
csi_status_t status;
csi = csi_descs[which_coproc];
// Request the new power state
csi_set_feature (which_coproc, COPROC_FEATURE_SHUTDOWN_IN_PROGRESS);
status = request_iop_power_state (which_coproc, CSI_PS_SLEEP);
if (CSI_STATUS_OK != status) {
CSI_LOG(CRITICAL, csi->coproc, "Failed to hibernate\n");
return CSI_STATUS_ERROR;
}
CSI_LOG(CRITICAL, csi->coproc, "in suspend to RAM\n");
// now turn off the iop
return csi_stop (which_coproc);
}
csi_status_t
set_send_timeout (csi_coproc_t which_coproc, uint32_t timeout)
{
csi_desc_t *csi = csi_descs[which_coproc];
csi->send_timeout = timeout;
return CSI_STATUS_OK;
}
uint32_t
get_send_timeout (csi_coproc_t which_coproc)
{
csi_desc_t *csi = csi_descs[which_coproc];
return csi->send_timeout;
}
csi_status_t
csi_set_feature (csi_coproc_t which_coproc, coproc_feature_t feature)
{
csi_desc_t *csi = csi_descs[which_coproc];
csi->feature = feature;
return CSI_STATUS_OK;
}
coproc_feature_t
csi_get_feature (csi_coproc_t which_coproc)
{
csi_desc_t *csi = csi_descs[which_coproc];
return csi->feature;
}
csi_status_t
csi_clr_feature (csi_coproc_t which_coproc, coproc_feature_t feature)
{
csi_desc_t *csi = csi_descs[which_coproc];
csi->feature &= ~(feature);
return CSI_STATUS_OK;
}
void
csi_info (csi_coproc_t which_coproc)
{
fw_print_version (which_coproc, &(csi_descs[which_coproc]->fw_desc));
}
////////////////////////////////////////////////////////////////////////////////
// allocate shared memory
//
static void *
allocate_shared_memory(uint32_t capacity, uint32_t alignment)
{
uint32_t actual_capacity;
void *sm;
// We always allocate page-aligned and with multiples of the page size for alignment
actual_capacity = roundup(capacity, PAGE_SIZE);
alignment = roundup(alignment, PAGE_SIZE);
// allocate
sm = memalign(actual_capacity, alignment);
maybe_do_cache_operation(CACHE_CLEAN, sm, actual_capacity);
return sm;
}
static void
free_shared_memory(void *sm)
{
free(sm);
}
static endpoint_desc_t *
find_endpoint(csi_coproc_t which_coproc, ipc_endpoint_t which_ep)
{
int j;
csi_desc_t *this_csi;
endpoint_desc_t *next_ep;
if (which_coproc < CSI_COPROC_MAX) {
this_csi = csi_descs[which_coproc];
if (this_csi != NULL) {
next_ep = this_csi->endpoints;
for (j=this_csi->endpoint_count; --j>=0; next_ep++) {
if (next_ep->index == which_ep) {
return next_ep;
}
}
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
// inbox_not_empty_task
//
// Wait for and dispatch incoming messages from the IOP.
// Get all the pending message in the mailbox and dispatch them to the appropriate
// endpoint. Message to non existent endpoint are silently discarded.
//
static int
inbox_not_empty_task(void *token)
{
volatile csi_desc_t *csi;
int status;
msg_payload_t msg;
endpoint_desc_t *ep;
REQUIRE (NULL != (csi = (csi_desc_t*)token));
if (csi->state != COPROC_STATE_RUNNING) {
CSI_LOG(CRITICAL, (csi_coproc_t)csi->coproc, "error: inbox_not_empty_task() coproc not running\n");
return 1;
}
// we should only be trying to read message when the AKF is running otherwise data abort can happen.
while (COPROC_STATE_RUNNING == csi->state) {
// check the coproc status every 100ms
while ((status = akf_recv_mbox(KFW(csi->coproc), &msg, 100000)) == 0) {
// queue the message, the endpoint will ignore it if disabled.
ep = find_endpoint(csi->coproc, ipc_msg_get_endpoint(&msg));
if (ep) {
message_dispatcher(ep, (msg&IPC_MSG_PAYLOAD_MASK));
} else {
CSI_LOG(CRITICAL, (csi_coproc_t)csi->coproc, "error: message received for unknown endpoint => message discarded (%d, 0x%llx)\n", ipc_msg_get_endpoint(&msg), msg);
}
}
}
// coproc has stopped running, terminate task
return 0;
}
static void
message_dispatcher(endpoint_desc_t *ep, msg_payload_t msg)
{
// do some basic filtering before signaling
if (!ep->registered) {
if (check_log_gov(&csi_descs[ep->coproc]->gov_ep_not_reg, ep->coproc)) {
CSI_LOG(CRITICAL, ep->coproc, "error: %s endpoint not registered => message discarded\n", ep->name);
}
} else {
// add the message to the queue
ep->rcv_queue[ep->next_in] = msg;
EP_QUEUE_ADVANCE(ep->next_in, ep->rcv_queue_size);
// check for overflow. discard oldest message if it happens.
if (ep->next_in == ep->next_out) {
if (check_log_gov(&csi_descs[ep->coproc]->gov_ep_queue_ovflw, ep->coproc)) {
CSI_LOG(CRITICAL, ep->coproc, "error: %s endpoint queue overflow\n", ep->name);
}
EP_QUEUE_ADVANCE(ep->next_out, ep->rcv_queue_size);
}
// if this was the first message move the _nextOut pointer to the newly received message
if ((uint32_t)~(0) == ep->next_out) {
ep->next_out = 0;
}
// signal the endpoint that its rcv queue is not empty
REQUIRE(ep->rcv_not_empty_event!=NULL);
event_signal(ep->rcv_not_empty_event);
}
}
// endpoint support
// NOTE: an unregister method could be added if necessary
csi_status_t
csi_register_endpoint(csi_coproc_t which_coproc, uint32_t which_ep, struct task_event *event, void **return_token, const char **name)
{
endpoint_desc_t *ep;
ep = find_endpoint(which_coproc, (ipc_endpoint_t)which_ep);
if (ep==NULL) {
CSI_LOG(CRITICAL, which_coproc, "csi_register_endpoint(): no knowledge of endpoint #%d\n", which_ep);
return CSI_STATUS_UNSUPPORTED;
}
if (ep->registered) {
CSI_LOG(CRITICAL, which_coproc, "csi_register_endpoint(): %s endpoint already registered\n", ep->name);
return CSI_STATUS_ERROR;
}
if (name != NULL) {
*name = ep->name;
}
ep->rcv_not_empty_event = event;
ep->registered = true;
ep->sm_alignment = csi_descs[which_coproc]->fw_desc.alignment_req;
*return_token = (void*)ep;
return CSI_STATUS_OK;
}
void *
csi_allocate_shared_memory(void *token, uint32_t capacity)
{
endpoint_desc_t *ep = (endpoint_desc_t*)token;
void *sm;
sm = allocate_shared_memory(capacity, ep->sm_alignment);
return sm;
}
void
csi_free_shared_memory(void *sm)
{
free_shared_memory (sm);
// remove element from the list
}
csi_status_t
csi_receive_message(void *token, msg_payload_t *msg_payload)
{
endpoint_desc_t *ep = (endpoint_desc_t*)token;
REQUIRE(ep != NULL);
if (!ep->registered) {
return CSI_STATUS_ERROR;
}
// make sure we have a message available
if (((uint32_t)~(0) == ep->next_out) || (ep->next_out == ep->next_in)) {
return CSI_STATUS_UNAVAILABLE;
}
// get the message from ep input queue and return it.
*msg_payload = ep->rcv_queue[ep->next_out];
EP_QUEUE_ADVANCE(ep->next_out, ep->rcv_queue_size);
return CSI_STATUS_OK;
}
csi_status_t
csi_send_message (void *token, msg_payload_t msg_payload)
{
endpoint_desc_t *ep;
ipc_msg_t msg_out;
int status;
csi_desc_t *csi;
REQUIRE(token != NULL);
ep = (endpoint_desc_t*)token;
msg_out = (ipc_msg_t)msg_payload;
if (!ep->registered) {
return CSI_STATUS_ERROR;
}
// FixMe - some clients already put in the endpoint field - others expect it to be done for them
if ((msg_out & IPC_MSG_ENDPOINT_MASK) == 0) {
ipc_msg_set_endpoint(&msg_out, ep->index);
}
if (ipc_msg_get_endpoint(&msg_out) != ep->index) {
return CSI_STATUS_ERROR;
}
ipc_msg_set_endpoint(&msg_out, ep->index);
csi = csi_descs[ep->coproc];
status = akf_send_mbox(KFW(ep->coproc), msg_out, csi->send_timeout);
if (-2 == status) {
// timeout
CSI_LOG(CRITICAL, ep->coproc, "csi_send_message(): failed to send message %llx in %dus, AKF hanged?\n", msg_payload, csi->send_timeout);
return CSI_STATUS_TIMEOUT;
}
// all other errors are non fatal
if (0 != status) {
return CSI_STATUS_ERROR;
}
return CSI_STATUS_OK;
}
static bool
check_log_gov(log_governor_t *gov, csi_coproc_t which_coproc)
{
gov->occ_count++;
if ((gov->occ_count == 1) || (timer_ticks_to_usecs(timer_get_ticks() - gov->last_log) >= LOG_GOV_PERIOD_USEC)) {
if (gov->occ_count > 2) {
CSI_LOG(CRITICAL, which_coproc, "WARNING: The condition logged below has occurred %d times\n", (gov->occ_count-1));
}
gov->occ_count = 1;
gov->last_log = timer_get_ticks();
return true;
}
return false;
}
void maybe_do_cache_operation(int operation, void *address, u_int32_t length)
{
#if WITH_NON_COHERENT_DMA
void *aligned_address;
u_int32_t aligned_length;
aligned_address = (void*)((uintptr_t)address & ~(CPU_CACHELINE_SIZE-1));
aligned_length = roundup((length + (address - aligned_address)), CPU_CACHELINE_SIZE);
platform_cache_operation(operation, aligned_address, aligned_length);
#endif
}
Loaded 100 of 2612 files, more files were not shown because too many files have changed in this diff. Show more