/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include enum { DDR_FREQ_533M = 0, DDR_FREQ_800M, }; static void init_pll(void) { unsigned int data; data = mmio_read_32((0xf7032000 + 0x000)); data |= 0x1; mmio_write_32((0xf7032000 + 0x000), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x000)); } while (!(data & (1 << 28))); data = mmio_read_32((0xf7800000 + 0x000)); data &= ~0x007; data |= 0x004; mmio_write_32((0xf7800000 + 0x000), data); dsb(); do { data = mmio_read_32((0xf7800000 + 0x014)); data &= 0x007; } while (data != 0x004); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101); data = mmio_read_32(PERI_SC_PERIPH_STAT1); mmio_write_32(0xf7032000 + 0x02c, 0x5110103e); data = mmio_read_32(0xf7032000 + 0x050); data |= 1 << 28; mmio_write_32(0xf7032000 + 0x050, data); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101); mdelay(1); data = mmio_read_32(PERI_SC_PERIPH_STAT1); NOTICE("syspll frequency:%dHz\n", data); } static void init_freq(void) { unsigned int data, tmp; unsigned int cpuext_cfg, ddr_cfg; mmio_write_32((0xf7032000 + 0x374), 0x4a); mmio_write_32((0xf7032000 + 0x368), 0xda); mmio_write_32((0xf7032000 + 0x36c), 0x01); mmio_write_32((0xf7032000 + 0x370), 0x01); mmio_write_32((0xf7032000 + 0x360), 0x60); mmio_write_32((0xf7032000 + 0x364), 0x60); mmio_write_32((0xf7032000 + 0x114), 0x1000); data = mmio_read_32((0xf7032000 + 0x110)); data |= (3 << 12); mmio_write_32((0xf7032000 + 0x110), data); data = mmio_read_32((0xf7032000 + 0x110)); data |= (1 << 4); mmio_write_32((0xf7032000 + 0x110), data); data = mmio_read_32((0xf7032000 + 0x110)); data &= ~0x7; data |= 0x5; mmio_write_32((0xf7032000 + 0x110), data); dsb(); mdelay(10); do { data = mmio_read_32((0xf6504000 + 0x008)); data &= (3 << 20); } while (data != (3 << 20)); dsb(); mdelay(10); data = mmio_read_32((0xf6504000 + 0x054)); data &= ~((1 << 0) | (1 << 11)); mmio_write_32((0xf6504000 + 0x054), data); mdelay(10); data = mmio_read_32((0xf7032000 + 0x104)); data &= ~(3 << 8); data |= (1 << 8); mmio_write_32((0xf7032000 + 0x104), data); data = mmio_read_32((0xf7032000 + 0x100)); data |= (1 << 0); mmio_write_32((0xf7032000 + 0x100), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x100)); data &= (1 << 2); } while (data != (1 << 2)); data = mmio_read_32((0xf6504000 + 0x06c)); data &= ~0xffff; data |= 0x56; mmio_write_32((0xf6504000 + 0x06c), data); data = mmio_read_32((0xf6504000 + 0x06c)); data &= ~(0xffffff << 8); data |= 0xc7a << 8; mmio_write_32((0xf6504000 + 0x06c), data); data = mmio_read_32((0xf6504000 + 0x058)); data &= ((1 << 13) - 1); data |= 0xccb; mmio_write_32((0xf6504000 + 0x058), data); mmio_write_32((0xf6504000 + 0x060), 0x1fff); mmio_write_32((0xf6504000 + 0x064), 0x1ffffff); mmio_write_32((0xf6504000 + 0x068), 0x7fffffff); mmio_write_32((0xf6504000 + 0x05c), 0x1); data = mmio_read_32((0xf6504000 + 0x054)); data &= ~(0xf << 12); data |= 1 << 12; mmio_write_32((0xf6504000 + 0x054), data); dsb(); data = mmio_read_32((0xf7032000 + 0x000)); data &= ~(1 << 0); mmio_write_32((0xf7032000 + 0x000), data); mmio_write_32((0xf7032000 + 0x004), 0x5110207d); mmio_write_32((0xf7032000 + 0x134), 0x10000005); data = mmio_read_32((0xf7032000 + 0x134)); data = mmio_read_32((0xf7032000 + 0x000)); data |= (1 << 0); mmio_write_32((0xf7032000 + 0x000), data); mmio_write_32((0xf7032000 + 0x368), 0x100da); data = mmio_read_32((0xf7032000 + 0x378)); data &= ~((1 << 7) - 1); data |= 0x6b; mmio_write_32((0xf7032000 + 0x378), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x378)); tmp = data & 0x7f; data = (data & (0x7f << 8)) >> 8; if (data != tmp) continue; data = mmio_read_32((0xf7032000 + 0x37c)); } while (!(data & 1)); data = mmio_read_32((0xf7032000 + 0x104)); data &= ~((3 << 0) | (3 << 8)); cpuext_cfg = 1; ddr_cfg = 1; data |= cpuext_cfg | (ddr_cfg << 8); mmio_write_32((0xf7032000 + 0x104), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x104)); tmp = (data & (3 << 16)) >> 16; if (cpuext_cfg != tmp) continue; tmp = (data & (3 << 24)) >> 24; if (ddr_cfg != tmp) continue; data = mmio_read_32((0xf7032000 + 0x000)); data &= 1 << 28; } while (!data); data = mmio_read_32((0xf7032000 + 0x100)); data &= ~(1 << 0); mmio_write_32((0xf7032000 + 0x100), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x100)); data &= (1 << 1); } while (data != (1 << 1)); mdelay(1000); data = mmio_read_32((0xf6504000 + 0x054)); data &= ~(1 << 28); mmio_write_32((0xf6504000 + 0x054), data); dsb(); data = mmio_read_32((0xf7032000 + 0x110)); data &= ~((1 << 4) | (3 << 12)); mmio_write_32((0xf7032000 + 0x110), data); } int cat_533mhz_800mhz(void) { unsigned int data, i; unsigned int bdl[5]; data = mmio_read_32((0xf712c000 + 0x1c8)); data &= 0xfffff0f0; data |= 0x100f0f; mmio_write_32((0xf712c000 + 0x1c8), data); for (i = 0; i < 0x20; i++) { mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); data = (i << 0x10) + i; mmio_write_32((0xf712c000 + 0x140), data); mmio_write_32((0xf712c000 + 0x144), data); mmio_write_32((0xf712c000 + 0x148), data); mmio_write_32((0xf712c000 + 0x14c), data); mmio_write_32((0xf712c000 + 0x150), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xfff7ffff; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0x0); mmio_write_32((0xf712c000 + 0x004), 0x801); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (!(data & 0x400)) { mdelay(10); return 0; } WARN("lpddr3 cat fail\n"); data = mmio_read_32((0xf712c000 + 0x1d4)); if ((data & 0x1f00) && ((data & 0x1f) == 0)) { bdl[0] = mmio_read_32((0xf712c000 + 0x140)); bdl[1] = mmio_read_32((0xf712c000 + 0x144)); bdl[2] = mmio_read_32((0xf712c000 + 0x148)); bdl[3] = mmio_read_32((0xf712c000 + 0x14c)); bdl[4] = mmio_read_32((0xf712c000 + 0x150)); if ((!(bdl[0] & 0x1f001f)) || (!(bdl[1] & 0x1f001f)) || (!(bdl[2] & 0x1f001f)) || (!(bdl[3] & 0x1f001f)) || (!(bdl[4] & 0x1f001f))) { WARN("lpddr3 cat deskew error\n"); if (i == 0x1f) { WARN("addrnbdl is max\n"); return -EINVAL; } mmio_write_32((0xf712c000 + 0x008), 0x400); } else { WARN("lpddr3 cat other error1\n"); return -EINVAL; } } else { WARN("lpddr3 cat other error2\n"); return -EINVAL; } } return -EINVAL; } static void ddrx_rdet(void) { unsigned int data, rdet, bdl[4]; data = mmio_read_32((0xf712c000 + 0x0d0)); data &= 0xf800ffff; data |= 0x8f0000; mmio_write_32((0xf712c000 + 0x0d0), data); data = mmio_read_32((0xf712c000 + 0x0dc)); data &= 0xfffffff0; data |= 0xf; mmio_write_32((0xf712c000 + 0x0dc), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xfff7ffff; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf0000000; data |= 0x80000000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x101); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (!(data & 1)); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x100) WARN("rdet lbs fail\n"); bdl[0] = mmio_read_32((0xf712c000 + 0x22c)) & 0x7f; bdl[1] = mmio_read_32((0xf712c000 + 0x2ac)) & 0x7f; bdl[2] = mmio_read_32((0xf712c000 + 0x32c)) & 0x7f; bdl[3] = mmio_read_32((0xf712c000 + 0x3ac)) & 0x7f; do { data = mmio_read_32((0xf712c000 + 0x22c)); data &= ~0x7f; data |= bdl[0]; mmio_write_32((0xf712c000 + 0x22c), data); data = mmio_read_32((0xf712c000 + 0x2ac)); data &= ~0x7f; data |= bdl[1]; mmio_write_32((0xf712c000 + 0x2ac), data); data = mmio_read_32((0xf712c000 + 0x32c)); data &= ~0x7f; data |= bdl[2]; mmio_write_32((0xf712c000 + 0x32c), data); data = mmio_read_32((0xf712c000 + 0x3ac)); data &= ~0x7f; data |= bdl[3]; mmio_write_32((0xf712c000 + 0x3ac), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xfff7ffff; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf0000000; data |= 0x40000000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x101); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); rdet = data & 0x100; if (rdet) { INFO("rdet ds fail\n"); mmio_write_32((0xf712c000 + 0x008), 0x100); } bdl[0]++; bdl[1]++; bdl[2]++; bdl[3]++; } while (rdet); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf0000000; data |= 0x30000000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x101); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x100) INFO("rdet rbs av fail\n"); } static void ddrx_wdet(void) { unsigned int data, wdet, zero_bdl = 0, dq[4]; int i; data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf; data |= 0xf; mmio_write_32((0xf712c000 + 0x0d0), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= ~0x80000; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf000; data |= 0x8000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x201); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x200) INFO("wdet lbs fail\n"); dq[0] = mmio_read_32((0xf712c000 + 0x234)) & 0x1f00; dq[1] = mmio_read_32((0xf712c000 + 0x2b4)) & 0x1f00; dq[2] = mmio_read_32((0xf712c000 + 0x334)) & 0x1f00; dq[3] = mmio_read_32((0xf712c000 + 0x3b4)) & 0x1f00; do { mmio_write_32((0xf712c000 + 0x234), dq[0]); mmio_write_32((0xf712c000 + 0x2b4), dq[1]); mmio_write_32((0xf712c000 + 0x334), dq[2]); mmio_write_32((0xf712c000 + 0x3b4), dq[3]); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= ~0x80000; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf000; data |= 0x4000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x201); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); wdet = data & 0x200; if (wdet) { INFO("wdet ds fail\n"); mmio_write_32((0xf712c000 + 0x008), 0x200); } mdelay(10); for (i = 0; i < 4; i++) { data = mmio_read_32((0xf712c000 + 0x210 + i * 0x80)); if ((!(data & 0x1f)) || (!(data & 0x1f00)) || (!(data & 0x1f0000)) || (!(data & 0x1f000000))) zero_bdl = 1; data = mmio_read_32((0xf712c000 + 0x214 + i * 0x80)); if ((!(data & 0x1f)) || (!(data & 0x1f00)) || (!(data & 0x1f0000)) || (!(data & 0x1f000000))) zero_bdl = 1; data = mmio_read_32((0xf712c000 + 0x218 + i * 0x80)); if (!(data & 0x1f)) zero_bdl = 1; if (zero_bdl) { if (i == 0) dq[0] = dq[0] - 0x100; if (i == 1) dq[1] = dq[1] - 0x100; if (i == 2) dq[2] = dq[2] - 0x100; if (i == 3) dq[3] = dq[3] - 0x100; } } } while (wdet); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf000; data |= 0x3000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x201); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x200) INFO("wdet rbs av fail\n"); } static void set_ddrc_533mhz(void) { unsigned int data; mmio_write_32((0xf7032000 + 0x580), 0x3); mmio_write_32((0xf7032000 + 0x5a8), 0x11111); data = mmio_read_32((0xf7032000 + 0x104)); data |= 0x100; mmio_write_32((0xf7032000 + 0x104), data); mmio_write_32((0xf7030000 + 0x050), 0x30); mmio_write_32((0xf7030000 + 0x240), 0x5ffff); mmio_write_32((0xf7030000 + 0x344), 0xf5ff); mmio_write_32((0xf712c000 + 0x00c), 0x400); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x090), 0x6400000); mmio_write_32((0xf712c000 + 0x258), 0x640); mmio_write_32((0xf712c000 + 0x2d8), 0x640); mmio_write_32((0xf712c000 + 0x358), 0x640); mmio_write_32((0xf712c000 + 0x3d8), 0x640); mmio_write_32((0xf712c000 + 0x018), 0x0); mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f); mmio_write_32((0xf712c000 + 0x0b4), 0xf); mmio_write_32((0xf712c000 + 0x088), 0x3fff801); mmio_write_32((0xf712c000 + 0x070), 0x8940000); data = mmio_read_32((0xf712c000 + 0x078)); data |= 4; mmio_write_32((0xf712c000 + 0x078), data); mmio_write_32((0xf712c000 + 0x01c), 0x8000080); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xfffffffe; mmio_write_32((0xf712c000 + 0x020), data); mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); mmio_write_32((0xf712c000 + 0x010), 0x500000f); mmio_write_32((0xf712c000 + 0x014), 0x10); data = mmio_read_32((0xf712c000 + 0x1e4)); data &= 0xffffff00; mmio_write_32((0xf712c000 + 0x1e4), data); mmio_write_32((0xf712c000 + 0x030), 0x9dd87855); mmio_write_32((0xf712c000 + 0x034), 0xa7138bb); mmio_write_32((0xf712c000 + 0x038), 0x20091477); mmio_write_32((0xf712c000 + 0x03c), 0x84534e16); mmio_write_32((0xf712c000 + 0x040), 0x3008817); mmio_write_32((0xf712c000 + 0x064), 0x106c3); mmio_write_32((0xf712c000 + 0x068), 0xff0a0000); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xffff0000; data |= 0x305; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x048)); data |= 0x40000000; mmio_write_32((0xf712c000 + 0x048), data); data = mmio_read_32((0xf712c000 + 0x020)); data &= ~0x10; mmio_write_32((0xf712c000 + 0x020), data); data = mmio_read_32((0xf712c000 + 0x080)); data &= ~0x2000; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf712c000 + 0x270), 0x3); mmio_write_32((0xf712c000 + 0x2f0), 0x3); mmio_write_32((0xf712c000 + 0x370), 0x3); mmio_write_32((0xf712c000 + 0x3f0), 0x3); mmio_write_32((0xf712c000 + 0x048), 0xd0420900); mmio_write_32((0xf7128000 + 0x040), 0x0); mmio_write_32((0xf712c000 + 0x004), 0x140f); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) { NOTICE("failed to init lpddr3 rank0 dram phy\n"); return; } NOTICE("succeed to init lpddr3 rank0 dram phy\n"); } static void set_ddrc_800mhz(void) { unsigned int data; mmio_write_32((0xf7032000 + 0x580), 0x2); mmio_write_32((0xf7032000 + 0x5a8), 0x1003); data = mmio_read_32((0xf7032000 + 0x104)); data &= 0xfffffcff; mmio_write_32((0xf7032000 + 0x104), data); mmio_write_32((0xf7030000 + 0x050), 0x30); mmio_write_32((0xf7030000 + 0x240), 0x5ffff); mmio_write_32((0xf7030000 + 0x344), 0xf5ff); mmio_write_32((0xf712c000 + 0x00c), 0x400); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x090), 0x5400000); mmio_write_32((0xf712c000 + 0x258), 0x540); mmio_write_32((0xf712c000 + 0x2d8), 0x540); mmio_write_32((0xf712c000 + 0x358), 0x540); mmio_write_32((0xf712c000 + 0x3d8), 0x540); mmio_write_32((0xf712c000 + 0x018), 0x0); mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f); mmio_write_32((0xf712c000 + 0x0b4), 0xf); mmio_write_32((0xf712c000 + 0x088), 0x3fff801); mmio_write_32((0xf712c000 + 0x070), 0x8940000); data = mmio_read_32((0xf712c000 + 0x078)); data |= 4; mmio_write_32((0xf712c000 + 0x078), data); mmio_write_32((0xf712c000 + 0x01c), 0x8000080); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xfffffffe; mmio_write_32((0xf712c000 + 0x020), data); mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); mmio_write_32((0xf712c000 + 0x010), 0x500000f); mmio_write_32((0xf712c000 + 0x014), 0x10); data = mmio_read_32((0xf712c000 + 0x1e4)); data &= 0xffffff00; mmio_write_32((0xf712c000 + 0x1e4), data); mmio_write_32((0xf712c000 + 0x030), 0xe663ab77); mmio_write_32((0xf712c000 + 0x034), 0xea952db); mmio_write_32((0xf712c000 + 0x038), 0x200d1cb1); mmio_write_32((0xf712c000 + 0x03c), 0xc67d0721); mmio_write_32((0xf712c000 + 0x040), 0x3008aa1); mmio_write_32((0xf712c000 + 0x064), 0x11a43); mmio_write_32((0xf712c000 + 0x068), 0xff0a0000); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xffff0000; data |= 0x507; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x048)); data |= 0x40000000; mmio_write_32((0xf712c000 + 0x048), data); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xffffffef; mmio_write_32((0xf712c000 + 0x020), data); data = mmio_read_32((0xf712c000 + 0x080)); data &= 0xffffdfff; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf712c000 + 0x270), 0x3); mmio_write_32((0xf712c000 + 0x2f0), 0x3); mmio_write_32((0xf712c000 + 0x370), 0x3); mmio_write_32((0xf712c000 + 0x3f0), 0x3); mmio_write_32((0xf712c000 + 0x048), 0xd0420900); mmio_write_32((0xf7128000 + 0x040), 0x2001); mmio_write_32((0xf712c000 + 0x004), 0x140f); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) { WARN("failed to init lpddr3 rank0 dram phy\n"); return; } } static void ddrc_common_init(int ddr800) { unsigned int data; mmio_write_32((0xf7120000 + 0x020), 0x1); mmio_write_32((0xf7120000 + 0x100), 0x1700); mmio_write_32((0xf7120000 + 0x104), 0x71040004); mmio_write_32((0xf7121400 + 0x104), 0xf); mmio_write_32((0xf7121800 + 0x104), 0xf); mmio_write_32((0xf7121800 + 0x104), 0xf); mmio_write_32((0xf7121c00 + 0x104), 0xf); mmio_write_32((0xf7122000 + 0x104), 0xf); mmio_write_32((0xf7128000 + 0x02c), 0x6); mmio_write_32((0xf7128000 + 0x020), 0x1); mmio_write_32((0xf7128000 + 0x028), 0x310201); mmio_write_32((0xf712c000 + 0x1e4), 0xfe007600); mmio_write_32((0xf7128000 + 0x01c), 0xaf001); data = mmio_read_32((0xf7128000 + 0x280)); data |= 1 << 7; mmio_write_32((0xf7128000 + 0x280), data); mmio_write_32((0xf7128000 + 0x244), 0x3); if (ddr800) mmio_write_32((0xf7128000 + 0x240), 167 * 400000 / 1024); else mmio_write_32((0xf7128000 + 0x240), 167 * 533000 / 1024); data = mmio_read_32((0xf712c000 + 0x080)); data &= 0xffff; data |= 0x4002000; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf7128000 + 0x000), 0x0); do { data = mmio_read_32((0xf7128000 + 0x294)); } while (data & 1); mmio_write_32((0xf7128000 + 0x000), 0x2); } static int dienum_det_and_rowcol_cfg(void) { unsigned int data; mmio_write_32((0xf7128000 + 0x210), 0x87); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)) & 0xfc; switch (data) { case 0x18: mmio_write_32((0xf7128000 + 0x060), 0x132); mmio_write_32((0xf7128000 + 0x064), 0x132); mmio_write_32((0xf7120000 + 0x100), 0x1600); mmio_write_32((0xf7120000 + 0x104), 0x71040004); break; case 0x1c: mmio_write_32((0xf7128000 + 0x060), 0x142); mmio_write_32((0xf7128000 + 0x064), 0x142); mmio_write_32((0xf7120000 + 0x100), 0x1700); mmio_write_32((0xf7120000 + 0x104), 0x71040004); break; case 0x58: mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7120000 + 0x100), 0x1700); mmio_write_32((0xf7120000 + 0x104), 0x71040004); break; default: break; } if (!data) return -EINVAL; return 0; } static int detect_ddr_chip_info(void) { unsigned int data, mr5, mr6, mr7; mmio_write_32((0xf7128000 + 0x210), 0x57); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)); mr5 = data & 0xff; switch (mr5) { case 1: INFO("Samsung DDR\n"); break; case 6: INFO("Hynix DDR\n"); break; case 3: INFO("Elpida DDR\n"); break; default: INFO("DDR from other vendors\n"); break; } mmio_write_32((0xf7128000 + 0x210), 0x67); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)); mr6 = data & 0xff; mmio_write_32((0xf7128000 + 0x210), 0x77); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)); mr7 = data & 0xff; data = mr5 + (mr6 << 8) + (mr7 << 16); return data; } int lpddr3_freq_init(int freq) { unsigned int data; if (freq == DDR_FREQ_800M) { set_ddrc_800mhz(); INFO("%s, set ddrc 800mhz\n", __func__); } else { set_ddrc_533mhz(); INFO("%s, set ddrc 533mhz\n", __func__); } mmio_write_32((0xf712c000 + 0x004), 0xf1); if (freq == DDR_FREQ_800M) mmio_write_32((0xf7128000 + 0x050), 0x100023); else mmio_write_32((0xf7128000 + 0x050), 0x100123); mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7128000 + 0x200), 0xa1000); if (freq == DDR_FREQ_800M) { mmio_write_32((0xf7128000 + 0x100), 0x755a9d12); mmio_write_32((0xf7128000 + 0x104), 0x1753b055); mmio_write_32((0xf7128000 + 0x108), 0x7401505f); mmio_write_32((0xf7128000 + 0x10c), 0x578ca244); mmio_write_32((0xf7128000 + 0x110), 0x10700000); mmio_write_32((0xf7128000 + 0x114), 0x13141306); } else { mmio_write_32((0xf7128000 + 0x100), 0xb77b6718); mmio_write_32((0xf7128000 + 0x104), 0x1e82a071); mmio_write_32((0xf7128000 + 0x108), 0x9501c07e); mmio_write_32((0xf7128000 + 0x10c), 0xaf50c255); mmio_write_32((0xf7128000 + 0x110), 0x10b00000); mmio_write_32((0xf7128000 + 0x114), 0x13181908); } mmio_write_32((0xf7128000 + 0x118), 0x44); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) { NOTICE("fail to init ddr3 rank0\n"); return -EFAULT; } INFO("init ddr3 rank0\n"); ddrx_rdet(); ddrx_wdet(); data = mmio_read_32((0xf712c000 + 0x048)); data |= 1; mmio_write_32((0xf712c000 + 0x048), data); mmio_write_32((0xf712c000 + 0x004), 0x21); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) NOTICE("ddr3 rank1 init failure\n"); else INFO("ddr3 rank1 init pass\n"); data = mmio_read_32((0xf712c000 + 0x048)); data &= ~0xf; mmio_write_32((0xf712c000 + 0x048), data); return 0; } static void init_ddr(int freq) { unsigned int data; int ret; data = mmio_read_32((0xf7032000 + 0x030)); data |= 1; mmio_write_32((0xf7032000 + 0x030), data); data = mmio_read_32((0xf7032000 + 0x010)); data |= 1; mmio_write_32((0xf7032000 + 0x010), data); udelay(100); do { data = mmio_read_32((0xf7032000 + 0x030)); data &= 3 << 28; } while (data != (3 << 28)); do { data = mmio_read_32((0xf7032000 + 0x010)); data &= 3 << 28; } while (data != (3 << 28)); ret = lpddr3_freq_init(freq); if (ret) return; } static void init_ddrc_qos(void) { unsigned int port, data; mmio_write_32((0xf7124000 + 0x088), 1); port = 0; mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x1210); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x11111111); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x11111111); mmio_write_32((0xf7120000 + 0x400 + 0 * 0x10), 0x001d0007); for (port = 3; port <= 4; port++) { mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x1210); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x77777777); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x77777777); } port = 1; mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x30000); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x1234567); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x1234567); mmio_write_32((0xf7124000 + 0x1f0), 0); mmio_write_32((0xf7124000 + 0x0bc), 0x3020100); mmio_write_32((0xf7124000 + 0x0d0), 0x3020100); mmio_write_32((0xf7124000 + 0x1f4), 0x01000100); mmio_write_32((0xf7124000 + 0x08c + 0 * 4), 0xd0670402); mmio_write_32((0xf7124000 + 0x068 + 0 * 4), 0x31); mmio_write_32((0xf7124000 + 0x000), 0x7); data = mmio_read_32((0xf7124000 + 0x09c)); data &= ~0xff0000; data |= 0x400000; mmio_write_32((0xf7124000 + 0x09c), data); data = mmio_read_32((0xf7124000 + 0x0ac)); data &= ~0xff0000; data |= 0x400000; mmio_write_32((0xf7124000 + 0x0ac), data); port = 2; mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x30000); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x1234567); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x1234567); mmio_write_32((0xf7124000 + 0x09c), 0xff7fff); mmio_write_32((0xf7124000 + 0x0a0), 0xff); mmio_write_32((0xf7124000 + 0x0ac), 0xff7fff); mmio_write_32((0xf7124000 + 0x0b0), 0xff); mmio_write_32((0xf7124000 + 0x0bc), 0x3020100); mmio_write_32((0xf7124000 + 0x0d0), 0x3020100); } static void ddr_phy_reset(void) { mmio_write_32(0xf7030340, 0xa000); mmio_write_32(0xf7030344, 0xa000); } void hikey_ddr_init(void) { uint32_t data; init_pll(); init_freq(); /* * Init DDR with 533MHz. Otherwise, DDR initialization * may fail on 800MHz on some boards. */ ddr_phy_reset(); init_ddr(DDR_FREQ_533M); /* Init DDR with 800MHz. */ ddr_phy_reset(); init_ddr(DDR_FREQ_800M); ddrc_common_init(1); dienum_det_and_rowcol_cfg(); detect_ddr_chip_info(); data = mmio_read_32(0xf7032000 + 0x010); data &= ~0x1; mmio_write_32(0xf7032000 + 0x010, data); data = mmio_read_32(0xf7032000 + 0x010); /* * Test memory access. Do not use address 0x0 because the compiler * may assume it is not a valid address and generate incorrect code * (GCC 4.9.1 without -fno-delete-null-pointer-checks for instance). */ mmio_write_32(0x4, 0xa5a55a5a); INFO("ddr test value:0x%x\n", mmio_read_32(0x4)); init_ddrc_qos(); }