first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -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
|
||||
Reference in new issue
Block a user