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