hekate/hwinit/sdram.c
2018-03-27 12:04:16 +13:00

505 lines
14 KiB
C

/*
* Copyright (c) 2018 naehrwert
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "i2c.h"
#include "t210.h"
#include "mc.h"
//#include "emc.h"
#include "pmc.h"
#include "util.h"
#include "fuse.h"
#include "sdram.inl"
static u32 _get_sdram_id()
{
return (fuse_read_odm(4) & 0x38) >> 3;
}
static void _sdram_config(const u32 *_cfg)
{
const u32 *_cfg_120 = _cfg + 0x120;
const u32 *_cfg_100 = _cfg + 0x100;
PMC(0x45C) = (((4 * _cfg[0x12F] >> 2) + 0x80000000) ^ 0xFFFF) & 0xC000FFFF;
sleep(_cfg[0x111]);
u32 req = (4 * _cfg_120[0x10] >> 2) + 0x80000000;
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0x3FFF0000) >> 16 << 16;
sleep(_cfg_100[0x12]);
PMC(APBDEV_PMC_IO_DPD4_REQ) = (req ^ 0xFFFF) & 0xC000FFFF;
sleep(_cfg_100[0x12]);
PMC(APBDEV_PMC_WEAK_BIAS) = 0;
sleep(1);
CLOCK(0x98) = _cfg[4];
CLOCK(0x9C) = 0;
CLOCK(0x90) = (_cfg[2] << 8) | (*((u16 *)_cfg + 0xA) << 20) | _cfg[1] | 0x40000000;
u32 wait_end = TMR(0x10) + 300;
while (!((CLOCK(0x90) >> 27) & 1))
{
if (TMR(0x10) >= wait_end)
goto break_nosleep;
}
sleep(10);
break_nosleep:
CLOCK(0x19C) = _cfg[0x16] & 0xFFFEFFFF | (_cfg[0x175] >> 11) & 0x10000;
if (_cfg[0x17])
CLOCK(0x664) = _cfg[0x17];
if (_cfg[0x1A])
CLOCK(0x44C) = 0x40000000;
CLOCK(0x328) = 0x2000001;
CLOCK(0x284) = 0x4000;
CLOCK(0x30C) = 0x2000001;
EMC(0xC34) = _cfg_120[0x13];
EMC(0xC38) = _cfg_120[0x14];
EMC(0xCF0) = _cfg_120[0x15];
EMC(0x28) = 1;
sleep(1);
EMC(0x8) = _cfg[0xA9] | 2 * _cfg[0xAA];
if (_cfg[0xA])
*(vu32 *)_cfg[0xA] = _cfg[0xB];
EMC(0x584) = _cfg[0x7B];
EMC(0x380) = _cfg[0x7D];
EMC(0x384) = _cfg[0x7E];
EMC(0x388) = _cfg[0x7F];
EMC(0x38C) = _cfg[0x80];
EMC(0x390) = _cfg[0x81];
EMC(0x394) = _cfg[0x82];
EMC(0x398) = _cfg[0x83];
EMC(0x39C) = _cfg[0x84];
EMC(0x3A0) = _cfg[0x85];
EMC(0x3A4) = _cfg[0x86];
EMC(0x3A8) = _cfg[0x87];
EMC(0x3AC) = _cfg[0x88];
EMC(0x3B0) = _cfg[0x89];
EMC(0xC80) = _cfg[0x14A];
EMC(0xC84) = _cfg[0x14B];
EMC(0xC88) = _cfg[0x14C];
EMC(0x330) = (_cfg_120[0x16] | 0xFEEDFEED) & 0x1FFF1FFF;
EMC(0x5F0) = _cfg[0x149];
EMC(0x5C8) = _cfg[0x7C];
EMC(0x404) = _cfg_100[0x18];
EMC(0x408) = _cfg_100[0x19];
EMC(0x40C) = _cfg_100[0x1A];
EMC(0x410) = _cfg_100[0x1B];
EMC(0x418) = _cfg_100[0x1C];
EMC(0x41C) = _cfg_100[0x1D];
EMC(0x420) = _cfg_100[0x1E];
EMC(0x424) = _cfg_100[0x1F];
if (_cfg[0xE])
*(vu32 *)_cfg[0xE] = _cfg[0xF];
EMC(0x30C) = _cfg[0x31];
EMC(0x578) = _cfg[0x32];
EMC(0x2F4) = _cfg[0x33];
EMC(0x458) = _cfg[0x1D];
EMC(0x45C) = _cfg[0x1E];
EMC(0x5B0) = _cfg[0x1F];
EMC(0x5B4) = _cfg[0x20];
EMC(0x5CC) = _cfg[0x21];
EMC(0x574) = _cfg[0x22];
EMC(0x2DC) = _cfg[0x23];
EMC(0xC48) = _cfg[0x2A];
EMC(0xC70) = _cfg[0x2B];
EMC(0xC74) = _cfg[0x2C];
EMC(0xC4C) = _cfg[0x2D];
EMC(0xC78) = _cfg[0x2E];
EMC(0x464) = _cfg[0x26];
EMC(0xC44) = _cfg[0x2F];
EMC(0x5E4) = _cfg_120[0xD];
EMC(0x5E8) = _cfg_120[0xE];
EMC(0x2C8) = _cfg[0xB0];
EMC(0x588) = _cfg_120[1];
EMC(0x58C) = _cfg_120[2];
EMC(0x594) = _cfg_120[3];
EMC(0x598) = _cfg_120[4];
EMC(0x59C) = _cfg_120[5];
EMC(0x5A0) = _cfg_120[6];
EMC(0x5A4) = _cfg_120[7];
EMC(0x5A8) = _cfg_120[8];
EMC(0x5AC) = _cfg_120[9];
EMC(0x5B8) = _cfg_120[0xA];
EMC(0x5BC) = _cfg_120[0xB];
EMC(0x5C4) = _cfg_120[0xC];
EMC(0x330) = (_cfg_120[0x16] | 0xFE40FE40) & 0x1FFF1FFF;
EMC(0xC40) = _cfg_120[0x12];
EMC(0x318) = _cfg_120[0x17];
EMC(0x334) = _cfg_120[0x18] & 0xFF7FFF7F;
EMC(0x31C) = _cfg_120[0x19];
EMC(0xC3C) = _cfg_120[0x1A];
EMC(0xC54) = _cfg_120[0x1B];
EMC(0xC50) = _cfg_120[0x1C];
EMC(0xC64) = _cfg_120[0x1F];
EMC(0xC5C) = _cfg_120[0x1D];
EMC(0xC58) = _cfg_120[0x1E];
EMC(0xC60) = _cfg[0x141];
EMC(0x49C) = _cfg[0x142];
EMC(0x720) = _cfg[0x143];
EMC(0x724) = _cfg[0x144];
EMC(0x728) = _cfg[0x145];
EMC(0x72C) = _cfg[0x146];
EMC(0x730) = _cfg[0x147];
EMC(0x734) = _cfg[0x148];
EMC(0x740) = _cfg[0x14D];
EMC(0x744) = _cfg[0x14E];
EMC(0x748) = _cfg[0x14F];
EMC(0x74C) = _cfg[0x150];
EMC(0x750) = _cfg[0x151];
EMC(0x754) = _cfg[0x152];
EMC(0x760) = _cfg[0x153];
EMC(0x770) = _cfg[0x154];
EMC(0x774) = _cfg[0x155];
EMC(0x778) = _cfg[0x156];
EMC(0x780) = _cfg[0x157];
EMC(0x784) = _cfg[0x158];
EMC(0x788) = _cfg[0x159];
EMC(0xBE0) = _cfg[0xB6];
EMC(0xBE4) = _cfg[0xB7];
EMC(0xBF0) = _cfg[0xB8];
EMC(0xBF4) = _cfg[0xB9];
EMC(0xCF4) = _cfg[0xBA];
EMC(0x600) = _cfg[0xBD];
EMC(0x604) = _cfg[0xBE];
EMC(0x608) = _cfg[0xBF];
EMC(0x60C) = _cfg[0xC0];
EMC(0x610) = _cfg[0xC1];
EMC(0x614) = _cfg[0xC2];
EMC(0x620) = _cfg[0xC3];
EMC(0x624) = _cfg[0xC4];
EMC(0x628) = _cfg[0xC5];
EMC(0x62C) = _cfg[0xC6];
EMC(0x630) = _cfg[0xC7];
EMC(0x634) = _cfg[0xC8];
EMC(0x330) = _cfg_120[0x16];
EMC(0x640) = _cfg[0xC9];
EMC(0x644) = _cfg[0xCA];
EMC(0x648) = _cfg[0xCB];
EMC(0x64C) = _cfg[0xCC];
EMC(0x650) = _cfg[0xCD];
EMC(0x654) = _cfg[0xCE];
EMC(0x660) = _cfg[0xCF];
EMC(0x664) = _cfg[0xD0];
EMC(0x668) = _cfg[0xD1];
EMC(0x66C) = _cfg[0xD2];
EMC(0x670) = _cfg[0xD3];
EMC(0x674) = _cfg[0xD4];
EMC(0x680) = _cfg[0xD5];
EMC(0x684) = _cfg[0xD6];
EMC(0x688) = _cfg[0xD7];
EMC(0x68C) = _cfg[0xD8];
EMC(0x690) = _cfg[0xD9];
EMC(0x694) = _cfg[0xDA];
EMC(0x6A0) = _cfg[0xDB];
EMC(0x6A4) = _cfg[0xDC];
EMC(0x6A8) = _cfg[0xDD];
EMC(0x6AC) = _cfg[0xDE];
EMC(0x6B0) = _cfg[0xDF];
EMC(0x6B4) = _cfg[0xE0];
EMC(0x6C0) = _cfg[0xE1];
EMC(0x6C4) = _cfg[0xE2];
EMC(0x6C8) = _cfg[0xE3];
EMC(0x6CC) = _cfg[0xE4];
EMC(0x6E0) = _cfg[0xE5];
EMC(0x6E4) = _cfg[0xE6];
EMC(0x6E8) = _cfg[0xE7];
EMC(0x6EC) = _cfg[0xE8];
EMC(0xC00) = _cfg[0xE9];
EMC(0xC04) = _cfg[0xEA];
EMC(0xC08) = _cfg[0xEB];
EMC(0xC0C) = _cfg[0xEC];
EMC(0xC10) = _cfg[0xED];
EMC(0xC20) = _cfg[0xEE];
EMC(0xC24) = _cfg[0xEF];
EMC(0xC28) = _cfg[0xF0];
EMC(0xC68) = (*((u8 *)_cfg + 0x500) | 0xFFFFFFFE) & 0xF;
if (_cfg[0xC])
*(vu32 *)_cfg[0xC] = _cfg[0xD];
EMC(0x28) = 1;
MC(0x648) = _cfg[0x180];
MC(0x978) = _cfg[0x181];
MC(0x64C) = _cfg[0x182];
MC(0x418) = _cfg[0x183];
MC(0x590) = _cfg[0x184];
MC(0x984) = _cfg[0x185];
MC(0x988) = _cfg[0x186];
MC(0x54) = _cfg[0x15A];
MC(0x58) = _cfg[0x15B];
MC(0x5C) = _cfg[0x15C];
MC(0x60) = _cfg[0x15D];
MC(0x64) = _cfg[0x15E];
MC(0x68) = _cfg[0x15F];
MC(0x6C) = _cfg[0x160];
MC(0x50) = _cfg[0x161];
MC(0x670) = _cfg[0x187];
MC(0x9D4) = _cfg[0x188];
MC(0x674) = _cfg[0x189];
MC(0x9A0) = _cfg[0x1D6];
MC(0x9A8) = _cfg[0x1D7];
MC(0x9A4) = _cfg[0x1D8];
MC(0x90) = _cfg[0x162];
MC(0x94) = _cfg[0x163];
MC(0x6F0) = _cfg[0x164];
MC(0x6F4) = _cfg[0x165];
MC(0x98) = _cfg[0x166];
MC(0x9C) = _cfg[0x167];
MC(0xA0) = _cfg[0x168];
MC(0xA4) = _cfg[0x169];
MC(0xA8) = _cfg[0x16A];
MC(0xAC) = _cfg[0x16B];
MC(0xB0) = _cfg[0x16C];
MC(0xB4) = _cfg[0x16D];
MC(0xB8) = _cfg[0x16E];
MC(0xBC) = _cfg[0x16F];
MC(0x6C4) = _cfg[0x17D];
MC(0xC0) = _cfg[0x170];
MC(0xC4) = _cfg[0x171];
MC(0x6C0) = _cfg[0x172];
MC(0xD0) = _cfg[0x173];
MC(0xD4) = _cfg[0x174];
MC(0xD8) = _cfg[0x175];
MC(0xDC) = _cfg[0x176];
MC(0xC8) = _cfg[0x177];
MC(0xE0) = _cfg[0x178];
MC(0xE8) = _cfg[0x179];
MC(0x968) = _cfg[0x17A];
MC(0xEC) = _cfg[0x17B];
MC(0x9DC) = _cfg[0x17C];
MC(0xFC) = 1;
MC(0xF4) = _cfg[0x17E];
MC(0x100) = _cfg[0x17F];
EMC(0x10) = _cfg[0x34];
EMC(0x140) = _cfg_100[7];
EMC(0x700) = _cfg[0x27];
EMC(0x704) = _cfg[0x28];
EMC(0x708) = _cfg[0x29];
EMC(0x2F8) = _cfg[0x24];
EMC(0x300) = _cfg[0x25];
EMC(0x2A8) = _cfg[0x1B];
EMC(0x2A4) = _cfg[0x1C];
sleep(_cfg[0x30]);
if (_cfg[0x10])
*(vu32 *)_cfg[0x10] = _cfg[0x11];
EMC(0x2B8) = _cfg[0xA4];
EMC(0x560) = _cfg[0xA5];
EMC(0x55C) = _cfg[0xBB];
EMC(0x554) = _cfg[0xBC];
EMC(0xF0) = _cfg[0xAB];
EMC(0xF4) = _cfg[0xAC];
EMC(0xC8) = _cfg[0xA1];
EMC(0xC4) = _cfg[0xA2];
EMC(0x104) = _cfg[0x7A];
EMC(0x2C) = _cfg[0x3A];
EMC(0x30) = _cfg[0x3B];
EMC(0x590) = _cfg[0x3C];
EMC(0x580) = _cfg[0x3D];
EMC(0xC0) = _cfg[0x3E];
EMC(0x34) = _cfg[0x3F];
EMC(0x38) = _cfg[0x40];
EMC(0xAC) = _cfg[0x47];
EMC(0x144) = _cfg[0x41];
EMC(0x148) = _cfg[0x42];
EMC(0x3C) = _cfg[0x43];
EMC(0x40) = _cfg[0x44];
EMC(0x44) = _cfg[0x45];
EMC(0x48) = _cfg[0x46];
EMC(0x5C0) = _cfg[0x48];
EMC(0x4C) = _cfg[0x49];
EMC(0x50) = _cfg[0x4A];
EMC(0x54) = _cfg[0x4B];
EMC(0x58) = _cfg[0x4C];
EMC(0xB8) = _cfg[0x4D];
EMC(0x5C) = _cfg[0x4E];
EMC(0x4E0) = _cfg[0x4F];
EMC(0x498) = _cfg[0x50];
EMC(0x494) = _cfg[0x51];
EMC(0x2D0) = _cfg[0x52];
EMC(0x490) = _cfg[0x53];
EMC(0x48C) = _cfg[0x54];
EMC(0x60) = _cfg[0x55];
EMC(0x568) = _cfg[0x56];
EMC(0x468) = _cfg[0x57];
EMC(0x46C) = _cfg[0x58];
EMC(0x14C) = _cfg[0x59];
EMC(0x150) = _cfg[0x5A];
EMC(0x154) = _cfg[0x5B];
EMC(0x56C) = _cfg[0x5C];
EMC(0xC68) = _cfg[0x140];
EMC(0x8) = _cfg[0xA9];
EMC(0x64) = _cfg[0x5D];
EMC(0x428) = 0;
EMC(0x68) = _cfg[0x5E];
EMC(0x6C) = _cfg[0x5F];
EMC(0x2CC) = _cfg[0x60];
EMC(0x2D8) = _cfg[0x61];
EMC(0x2D4) = _cfg[0x62];
EMC(0x564) = _cfg[0x63];
EMC(0x70) = _cfg[0x64];
EMC(0x74) = _cfg[0x65];
EMC(0x3DC) = _cfg[0x66];
EMC(0x78) = _cfg[0x67];
EMC(0x7C) = _cfg[0x68];
EMC(0x80) = _cfg[0x69];
EMC(0x84) = _cfg[0x6A];
EMC(0x88) = _cfg[0x6B];
EMC(0x8C) = _cfg[0x6C];
EMC(0x11C) = _cfg[0x6D];
EMC(0x118) = _cfg[0x6E];
EMC(0xB4) = _cfg[0x6F];
EMC(0x90) = _cfg[0x70];
EMC(0x3E4) = _cfg[0x71];
EMC(0x94) = _cfg[0x72];
EMC(0x158) = _cfg[0x73];
EMC(0x15C) = _cfg[0x74];
EMC(0x98) = _cfg[0x75];
EMC(0x9C) = _cfg[0x76];
EMC(0xA0) = _cfg[0x77];
EMC(0xA4) = _cfg[0x78];
EMC(0xA8) = _cfg[0x79];
EMC(0xB0) = _cfg[0xF2];
EMC(0x2BC) = _cfg[0xAF];
EMC(0x2C0) = _cfg[0xB1];
EMC(0x100) = _cfg[0x8A] & 0xFFFFFFFD;
EMC(0x120) = _cfg[0x8B];
EMC(0x440) = _cfg_120[0xF];
EMC(0x444) = _cfg_120[0x10];
EMC(0x448) = _cfg_120[0x11];
EMC(0x124) = _cfg_100[0x17];
EMC(0x480) = *_cfg_120;
EMC(0xC) = ((_cfg[0xA3] & 4 | 0x3C00000) & 0xFFFFFFF7 | _cfg[0xA3] & 8) & 0xFFFFFFFD | _cfg[0xA3] & 2;
if ((_cfg[0x1D4] & 0x80000000) != 0)
{
*(vu32 *)(4 * _cfg[0x1D4] + 0x70000000) = _cfg[0x1D5];
MC(0xFC) = 1;
}
PMC(0x45C) = ((4 * _cfg_120[0xF] >> 2) + 0x40000000) & 0xCFFF0000;
sleep(_cfg_100[0x11]);
if (!_cfg[0x1B])
EMC(0x2A4) = _cfg[0x1C] | 0x200;
EMC(0x334) = _cfg_120[0x18];
if (_cfg[0xFA] << 31)
{
if (*_cfg == 2)
EMC(0x2E4) = 8 * _cfg[0xF4];
if (*_cfg == 3)
{
EMC(0x2E4) = _cfg[0xF4];
EMC(0x2E8) = _cfg[0xF5];
}
}
EMC(0x28) = 1;
sleep(_cfg[0x39]);
PMC(0x4E4) &= 0xFFF8007F;
sleep(_cfg_100[0x15]);
if (*_cfg == 2)
{
EMC(0x24) = (_cfg[0x37] << 16) | (_cfg[0x38] << 12);
sleep(_cfg[0x36] + 200);
EMC(0x24) = ((_cfg[0x37] << 16) | (_cfg[0x38] << 12)) + 0x100;
sleep(_cfg[0x36] + 500);
}
if (*_cfg == 3)
{
EMC(0x24) = (_cfg[0x37] << 16) | (_cfg[0x38] << 12);
sleep(_cfg[0x36] + 200);
EMC(0x24) = ((_cfg[0x37] << 16) | (_cfg[0x38] << 12)) + 0x100;
sleep(_cfg[0x36] + 2000);
}
EMC(0x24) = ((_cfg[0x37] << 16) | (_cfg[0x38] << 12)) + 0x101;
sleep(_cfg[0x35]);
if (*_cfg != 3)
EMC(0xDC) = (_cfg[0xB2] << 30) + 1;
if (*_cfg == 1)
sleep(_cfg[0x36] + 200);
if (*_cfg == 3)
{
if (_cfg[0x12])
*(vu32 *)_cfg[0x12] = _cfg[0x13];
EMC(0x134) = _cfg[0x91];
EMC(0xE8) = _cfg[0x90];
EMC(0x138) = _cfg[0x92];
EMC(0x13C) = _cfg[0x93];
EMC(0x4A4) = _cfg[0x94];
EMC(0x4C4) = _cfg[0x9A];
EMC(0x4AC) = _cfg[0x95];
EMC(0x4BC) = _cfg[0x98];
EMC(0x4B0) = _cfg[0x96];
EMC(0x4C0) = _cfg[0x99];
if (_cfg[0xFA] << 31)
{
EMC(0x2EC) = _cfg[0xF7];
sleep(_cfg[0xF9]);
EMC(0x2EC) = _cfg[0xF7] ^ 3;
if (!(_cfg[0xB2] & 2))
{
EMC(0x2EC) = _cfg[0xF8];
sleep(_cfg[0xF9]);
EMC(0x2EC) = _cfg[0xF8] ^ 3;
}
}
}
PMC(0x1D0) = _cfg_100[0xF];
if (_cfg[0] == 1 || _cfg[0] == 2 || _cfg[0] == 3)
{
EMC(0x2E0) = _cfg[0xF3];
EMC(0x2E4) = _cfg[0xF4];
EMC(0x2E8) = _cfg[0xF5];
}
if (_cfg[0x14])
*(vu32 *)_cfg[0x14] = _cfg[0x15];
EMC(0x28) = 1;
if (_cfg_100[8])
EMC(0xD4) = ((1 << _cfg_100[8] << 8) - 0xFD) | (_cfg[0x38] << 30);
EMC(0x20) = _cfg[0xB2] | 0x80000000;
EMC(0x3E0) = _cfg[0xAD];
EMC(0x5F4) = _cfg[0xA8];
EMC(0xC) = _cfg[0xA3];
EMC(0x310) = _cfg[0xB4];
EMC(0x314) = _cfg[0xB5];
EMC(0x3D8) = _cfg[0xB3];
EMC(0x100) = _cfg[0x8A] | 2;
EMC(0x28) = 1;
EMC(0x558) = _cfg[0xA6];
EMC(0x4D8) = _cfg[0xA7];
SYSREG(AHB_ARBITRATION_XBAR_CTRL) = SYSREG(AHB_ARBITRATION_XBAR_CTRL) & 0xFFFEFFFF | (*((u16 *)_cfg + 0x15C) << 16);
MC(0x650) = _cfg[0x18A];
MC(0x678) = _cfg[0x18B];
MC(0x9AC) = _cfg[0x1D9];
MC(MC_EMEM_CFG_ACCESS_CTRL) = 1; //Disable write access to a bunch of MC registers.
}
void sdram_init()
{
u32 sdram_id = _get_sdram_id();
const u32 *cfg = _dram_cfgs[sdram_id]; //TODO: sdram_id should be in [0,4].
i2c_send_byte(I2C_5, 0x3C, 0x22, 0x05);
i2c_send_byte(I2C_5, 0x3C, 0x17, 40); //40 = (1000 * 1100 - 600000) / 12500
PMC(APBDEV_PMC_VDDP_SEL) = cfg[0x10C];
sleep(cfg[0x10D]);
PMC(APBDEV_PMC_DDR_PWR) = PMC(0xE8);
PMC(APBDEV_PMC_NO_IOPOWER) = cfg[0x114];
PMC(APBDEV_PMC_REG_SHORT) = cfg[0x113];
PMC(APBDEV_PMC_DDR_CNTRL) = cfg[0x116];
if (cfg[8])
*(vu32 *)cfg[8] = cfg[9];
_sdram_config(cfg);
}