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

+288
View File
@@ -0,0 +1,288 @@
/*
* Copyright (C) 2007-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/aes.h>
#include <sys/menu.h>
#include <sys.h>
#if WITH_CORECRYPTO
#include <corecrypto/ccaes.h>
#include <corecrypto/ccmode.h>
static const struct ccmode_cbc *aes_get_ccaes_cbc_decrypt_mode()
{
#if WITH_VFP
return ((const struct ccmode_cbc *)ccaes_cbc_decrypt_mode());
#else
return (&ccaes_gladman_cbc_decrypt_mode);
#endif
}
static const struct ccmode_cbc *aes_get_ccaes_cbc_encrypt_mode()
{
#if WITH_VFP
return ((const struct ccmode_cbc *)ccaes_cbc_encrypt_mode());
#else
return (&ccaes_gladman_cbc_encrypt_mode);
#endif
}
static const struct ccmode_ecb *aes_get_ccaes_ecb_decrypt_mode()
{
#if WITH_VFP
return ((const struct ccmode_ecb *)ccaes_ecb_decrypt_mode());
#else
return (&ccaes_ltc_ecb_decrypt_mode);
#endif
}
static const struct ccmode_ecb *aes_get_ccaes_ecb_encrypt_mode()
{
#if WITH_VFP
return ((const struct ccmode_ecb *)ccaes_ecb_encrypt_mode());
#else
return (&ccaes_ltc_ecb_encrypt_mode);
#endif
}
#endif // WITH_CORECRYPTO
int
aes_crypto_cmd(u_int32_t cmd, void *src, void *dst, size_t len, u_int32_t opts, const void *key, void *iv)
{
/* argument sanity */
if (0 != (len % AES_BLOCK_SIZE))
goto fail;
if ((AES_KEY_TYPE_USER == (opts & AES_KEY_TYPE_MASK)) && (NULL == key))
goto fail;
switch (cmd & AES_CMD_DIR_MASK) {
case AES_CMD_ENC : break;
case AES_CMD_DEC : break;
default : goto fail;
}
#if WITH_CORECRYPTO
u_int32_t key_size;
// Ops with explicit user key will be handled by libcorecrypto (SW AES)
if (AES_KEY_TYPE_USER == (opts & AES_KEY_TYPE_MASK)) {
switch (opts & AES_KEY_SIZE_MASK) {
case AES_KEY_SIZE_128:
key_size = CCAES_KEY_SIZE_128;
break;
case AES_KEY_SIZE_192:
key_size = CCAES_KEY_SIZE_192;
break;
case AES_KEY_SIZE_256:
key_size = CCAES_KEY_SIZE_256;
break;
default:
panic("invalid AES key size");
break;
}
if (likely((cmd & AES_CMD_MODE_MASK) == AES_CMD_CBC)) {
const struct ccmode_cbc *mode;
if (likely((cmd & AES_CMD_DIR_MASK) == AES_CMD_DEC))
mode = aes_get_ccaes_cbc_decrypt_mode();
else
mode = aes_get_ccaes_cbc_encrypt_mode();
cccbc_one_shot(mode, key_size, key, iv, (len / AES_BLOCK_SIZE), src, dst);
}
else {
const struct ccmode_ecb *mode;
if (likely((cmd & AES_CMD_DIR_MASK) == AES_CMD_DEC))
mode = aes_get_ccaes_ecb_decrypt_mode();
else
mode = aes_get_ccaes_ecb_encrypt_mode();
ccecb_one_shot(mode, key_size, key, len, src, dst);
}
return 0;
}
#endif
#if WITH_HW_OLD_AES
u_int32_t keyType = 0;
/* Only supports UID0, GID0 and USER keys */
switch (opts & AES_KEY_TYPE_MASK) {
case AES_KEY_TYPE_USER : keyType = AES_KEY_TYPE_REGISTER; break;
case AES_KEY_TYPE_UID0 : keyType = AES_KEY_TYPE_CHIP; break;
case AES_KEY_TYPE_GID0 : keyType = AES_KEY_TYPE_GLOBAL; break;
default: goto fail;
}
/* Only 128 bit keys are supported */
if ((opts & AES_KEY_SIZE_MASK) != AES_KEY_SIZE_128) goto exit;
/* Only CBC mode is supported */
if ((cmd & AES_CMD_MODE_MASK) != AES_CMD_CBC) goto exit;
if (dst == NULL)
dst = src;
if (dst != src)
memcpy(dst, src, len);
switch (cmd & AES_CMD_DIR_MASK) {
case AES_CMD_ENC :
(void)AES_CBC_EncryptInPlace(dst, len, keyType, (void *)key, iv);
break;
case AES_CMD_DEC :
(void)AES_CBC_DecryptInPlace(dst, len, keyType, (void *)key, iv);
break;
}
#elif WITH_HW_AES
if (aes_hw_crypto_cmd(cmd, src, dst, len, opts, key, iv))
return(-1);
goto exit;
#else
#error "aes_crypto_cmd: no valid implementation\n";
#endif
exit:
dprintf(DEBUG_SPEW, "aes_crypto_cmd: cmd: %08x, src: %p, dst: %p, len: %08zx, opts: %08x, key: %p, iv: %p \n",
cmd, src, dst, len, opts, key, iv);
return(0);
fail:
panic("AES: bad arguments");
}
int
do_aes_cmd(int argc, struct cmd_arg *args)
{
u_int8_t pt[32];
u_int8_t ct[32];
u_int8_t k[16];
u_int8_t iv[16];
int i;
/* seed the plaintext */
for (i = 0; i < 32; i++) {
pt[i] = system_time() & 0xff;
}
memset(k, 0x55, sizeof(k));
memset(iv, 0, sizeof(iv));
if (argc > 1) {
if (strcmp(args[1].str, "uid0") == 0) {
printf("uid0\n");
aes_cbc_encrypt(k, k, sizeof(k), AES_KEY_TYPE_UID0, NULL, NULL);
}
else if (strcmp(args[1].str, "gid0") == 0) {
printf("gid0\n");
aes_cbc_encrypt(k, k, sizeof(k), AES_KEY_TYPE_GID0, NULL, NULL);
}
else if (strcmp(args[1].str, "gid1") == 0) {
printf("gid1\n");
aes_cbc_encrypt(k, k, sizeof(k), AES_KEY_TYPE_GID1, NULL, NULL);
}
}
printf("AES plaintext input:\n");
hexdump(pt, 32);
memset(ct, 0, 32);
aes_crypto_cmd(
AES_CMD_ENC | AES_CMD_CBC,
&pt[0],
&ct[0],
32,
AES_KEY_TYPE_USER | AES_KEY_SIZE_128,
k,
iv);
printf("AES ciphertext result:\n");
hexdump(ct, 32);
memset(pt, 0, 32);
aes_crypto_cmd(
AES_CMD_DEC | AES_CMD_CBC,
&ct[0],
&pt[0],
32,
AES_KEY_TYPE_USER | AES_KEY_SIZE_128,
k,
iv);
printf("AES plaintext result:\n");
hexdump(pt, 32);
return 0;
}
int
do_aes_golden_vec_cmd(int argc, struct cmd_arg *args)
{
uint8_t ct[16];
uint8_t pt[16];
printf("encrypt:\n");
for (int i = 0; i < 10; i++) {
memset(pt, 0, sizeof(pt));
memset(ct, 0x55, sizeof(pt));
pt[0] = i;
printf("src: [%p]", pt);
for (unsigned int j = 0; j < sizeof(pt); j++)
printf(" %02x", pt[j]);
printf("\n");
if (aes_crypto_cmd(AES_CMD_ENC | AES_CMD_CBC, pt, ct, sizeof(pt), AES_KEY_TYPE_GID0 | AES_KEY_SIZE_256, NULL, NULL) != 0) {
printf("encyrpt failed\n");
return -1;
}
printf("dst: [%p]", ct);
for (unsigned int j = 0; j < sizeof(ct); j++)
printf(" %02x", ct[j]);
printf("\n");
}
printf("decrypt\n");
for (int i = 0; i < 10; i++) {
memset(ct, 0, sizeof(pt));
memset(pt, 0x55, sizeof(pt));
ct[0] = i;
printf("src: [%p]", ct);
for (unsigned int j = 0; j < sizeof(ct); j++)
printf(" %02x", ct[j]);
printf("\n");
if (aes_crypto_cmd(AES_CMD_DEC | AES_CMD_CBC, ct, pt, sizeof(pt), AES_KEY_TYPE_GID0 | AES_KEY_SIZE_256, NULL, NULL) != 0) {
printf("decrypt failed\n");
return -1;
}
printf("dst: [%p]", pt);
for (unsigned int j = 0; j < sizeof(pt); j++)
printf(" %02x", pt[j]);
printf("\n");
}
return 0;
}
// Turned off to save space, enable as needed
//MENU_COMMAND_DEBUG(aes, do_aes_cmd, "AES test", NULL);
//MENU_COMMAND_DEBUG(aes_golden_vec, do_aes_golden_vec_cmd, "AES golden vector test", NULL);
+16
View File
@@ -0,0 +1,16 @@
# 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_AES=1
ALL_OBJS += \
$(LOCAL_DIR)/aes.o
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,36 @@
/*
* Copyright (C) 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 DRIVER_DISPLAYPORT_H
#define DRIVER_DISPLAYPORT_H 1
#include <drivers/display.h>
#include <drivers/displayAV.h>
typedef struct
{
uint32_t mode : 4; // 3:0
uint32_t type : 4; // 7:4
uint32_t min_link_rate : 8; // 15:8
uint32_t max_link_rate : 8; // 23:16
uint32_t lanes : 4; // 27:24
uint32_t ssc : 1; // 28
uint32_t alpm : 1; // 29
uint32_t vrr_enable : 1; // 30
uint32_t vrr_on : 1; // 31
uint32_t rx_n1;
uint32_t rx_n2;
uint32_t rx_n3;
uint32_t rx_n5;
bool fast_link_training;
} dp_t;
#endif //DRIVER_DISPLAYPORT_H
File diff suppressed because it is too large. Load diff
+17
View File
@@ -0,0 +1,17 @@
# Copyright (C) 2013,2015 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
GLOBAL_INCLUDES +=
ALL_OBJS += \
$(LOCAL_DIR)/displayport.o
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
+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);
}
Loaded 100 of 2612 files, more files were not shown because too many files have changed in this diff. Show more