text: /*
   * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
   *
   * SPDX-License-Identifier: BSD-3-Clause
   */
  
  #include <assert.h>
  #include <errno.h>
  
  #include <arch_helpers.h>
  #include <common/debug.h>
  #include <drivers/arm/sp804_delay_timer.h>
  #include <lib/mmio.h>
  
  #include <hi6220.h>
  #include <hi6553.h>
  #include <hisi_sram_map.h>
  #include "hikey_private.h"
  
  static void init_pll(void)
  {
  	unsigned int data;
  
  	data = mmio_read_32((0xf7032000 + 0x000));
  	data |= 0x1;
  	mmio_write_32((0xf7032000 + 0x000), data);
  	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);
  	do {
  		data = mmio_read_32((0xf7800000 + 0x014));
  		data &= 0x007;
  	} while (data != 0x004);
  
  	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101);
  	dsb();
  	isb();
  	udelay(10);
  	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2001);
  	dsb();
  	isb();
  	udelay(10);
  	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2201);
  	dsb();
  	isb();
  	udelay(10);
  	mmio_write_32(0xf7032000 + 0x02c, 0x5110103e);
  	dsb();
  	isb();
  	udelay(10);
  	data = mmio_read_32(0xf7032000 + 0x050);
  	data |= 1 << 28;
  	mmio_write_32(0xf7032000 + 0x050, data);
  	dsb();
  	isb();
  	udelay(10);
  	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101);
  	dsb();
  	isb();
  	udelay(10);
  	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2001);
  	dsb();
  	isb();
  	udelay(10);
  	mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2201);
  	dsb();
  	isb();
  	udelay(10);
  }
  
  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 &= ~(0xffffffu << 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 |= 0x100f01;
  	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) == 0) {
  			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");
  }
  
  void set_ddrc_150mhz(void)
  {
  	unsigned int data;
  
  	mmio_write_32((0xf7032000 + 0x580), 0x1);
  	mmio_write_32((0xf7032000 + 0x5a8), 0x7);
  	data = mmio_read_32((0xf7032000 + 0x104));
  	data &= 0xfffffcff;
  	mmio_write_32((0xf7032000 + 0x104), data);
  
  	mmio_write_32((0xf7030000 + 0x050), 0x31);
  	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
  	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
  	mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f);
  	mmio_write_32((0xf712c000 + 0x00c), 0xf0f);
  	mmio_write_32((0xf712c000 + 0x018), 0x7);
  	mmio_write_32((0xf712c000 + 0x090), 0x7200000);
  	mmio_write_32((0xf712c000 + 0x258), 0x720);
  	mmio_write_32((0xf712c000 + 0x2d8), 0x720);
  	mmio_write_32((0xf712c000 + 0x358), 0x720);
  	mmio_write_32((0xf712c000 + 0x3d8), 0x720);
  	mmio_write_32((0xf712c000 + 0x018), 0x7);
  	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), 0x30c82355);
  	mmio_write_32((0xf712c000 + 0x034), 0x62112bb);
  	mmio_write_32((0xf712c000 + 0x038), 0x20041022);
  	mmio_write_32((0xf712c000 + 0x03c), 0x63177497);
  	mmio_write_32((0xf712c000 + 0x040), 0x3008407);
  	mmio_write_32((0xf712c000 + 0x064), 0x10483);
  	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
  	data = mmio_read_32((0xf712c000 + 0x070));
  	data &= 0xffff0000;
  	data |= 0x184;
  	mmio_write_32((0xf712c000 + 0x070), data);
  	data = mmio_read_32((0xf712c000 + 0x048));
  	data &= 0xbfffffff;
  	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), 0x90420880);
  
  	mmio_write_32((0xf7128000 + 0x040), 0x0);
  	mmio_write_32((0xf712c000 + 0x004), 0x146d);
  	mmio_write_32((0xf7128000 + 0x050), 0x100123);
  	mmio_write_32((0xf7128000 + 0x060), 0x133);
  	mmio_write_32((0xf7128000 + 0x064), 0x133);
  	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
  
  	mmio_write_32((0xf7128000 + 0x100), 0xb3290d08);
  	mmio_write_32((0xf7128000 + 0x104), 0x9621821);
  	mmio_write_32((0xf7128000 + 0x108), 0x45009023);
  	mmio_write_32((0xf7128000 + 0x10c), 0xaf44c145);
  	mmio_write_32((0xf7128000 + 0x110), 0x10b00000);
  	mmio_write_32((0xf7128000 + 0x114), 0x11080806);
  	mmio_write_32((0xf7128000 + 0x118), 0x44);
  	do {
  		data = mmio_read_32((0xf712c000 + 0x004));
  	} while (data & 1);
  	data = mmio_read_32((0xf712c000 + 0x008));
  	if (data & 8) {
  		NOTICE("fail to init ddr3 rank0\n");
  		return;
  	}
  
  	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 & 0x8)
  		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);
  	INFO("succeed to set ddrc 150mhz\n");
  }
  
  void set_ddrc_266mhz(void)
  {
  	unsigned int data;
  
  	mmio_write_32((0xf7032000 + 0x580), 0x3);
  	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), 0x31);
  	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
  	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
  	mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f);
  	mmio_write_32((0xf712c000 + 0x00c), 0xf0f);
  	mmio_write_32((0xf712c000 + 0x018), 0x7);
  	mmio_write_32((0xf712c000 + 0x090), 0x7200000);
  	mmio_write_32((0xf712c000 + 0x258), 0x720);
  	mmio_write_32((0xf712c000 + 0x2d8), 0x720);
  	mmio_write_32((0xf712c000 + 0x358), 0x720);
  	mmio_write_32((0xf712c000 + 0x3d8), 0x720);
  	mmio_write_32((0xf712c000 + 0x018), 0x7);
  	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), 0x510d4455);
  	mmio_write_32((0xf712c000 + 0x034), 0x8391ebb);
  	mmio_write_32((0xf712c000 + 0x038), 0x2005103c);
  	mmio_write_32((0xf712c000 + 0x03c), 0x6329950b);
  	mmio_write_32((0xf712c000 + 0x040), 0x300858c);
  	mmio_write_32((0xf712c000 + 0x064), 0x10483);
  	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
  	data = mmio_read_32((0xf712c000 + 0x070));
  	data &= 0xffff0000;
  	data |= 0x184;
  	mmio_write_32((0xf712c000 + 0x070), data);
  	data = mmio_read_32((0xf712c000 + 0x048));
  	data &= 0xbfffffff;
  	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), 0x90420880);
  
  	mmio_write_32((0xf7128000 + 0x040), 0x0);
  	mmio_write_32((0xf712c000 + 0x004), 0x146d);
  	mmio_write_32((0xf7128000 + 0x050), 0x100123);
  	mmio_write_32((0xf7128000 + 0x060), 0x133);
  	mmio_write_32((0xf7128000 + 0x064), 0x133);
  	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
  
  	mmio_write_32((0xf7128000 + 0x100), 0xb441d50d);
  	mmio_write_32((0xf7128000 + 0x104), 0xf721839);
  	mmio_write_32((0xf7128000 + 0x108), 0x5500f03f);
  	mmio_write_32((0xf7128000 + 0x10c), 0xaf486145);
  	mmio_write_32((0xf7128000 + 0x110), 0x10b00000);
  	mmio_write_32((0xf7128000 + 0x114), 0x12080d06);
  	mmio_write_32((0xf7128000 + 0x118), 0x44);
  	do {
  		data = mmio_read_32((0xf712c000 + 0x004));
  	} while (data & 1);
  	data = mmio_read_32((0xf712c000 + 0x008));
  	if (data & 8) {
  		NOTICE("fail to init ddr3 rank0\n");
  		return;
  	}
  
  	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 & 0x8)
  		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);
  	INFO("succeed to set ddrc 266mhz\n");
  }
  
  void set_ddrc_400mhz(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), 0x31);
  	mmio_write_32((0xf7030000 + 0x240), 0x5ffff);
  	mmio_write_32((0xf7030000 + 0x344), 0xf5ff);
  	mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f);
  	mmio_write_32((0xf712c000 + 0x00c), 0xf0f);
  	mmio_write_32((0xf712c000 + 0x018), 0x7);
  	mmio_write_32((0xf712c000 + 0x090), 0x7200000);
  	mmio_write_32((0xf712c000 + 0x258), 0x720);
  	mmio_write_32((0xf712c000 + 0x2d8), 0x720);
  	mmio_write_32((0xf712c000 + 0x358), 0x720);
  	mmio_write_32((0xf712c000 + 0x3d8), 0x720);
  	mmio_write_32((0xf712c000 + 0x018), 0x7);
  	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), 0x75525655);
  	mmio_write_32((0xf712c000 + 0x034), 0xa552abb);
  	mmio_write_32((0xf712c000 + 0x038), 0x20071059);
  	mmio_write_32((0xf712c000 + 0x03c), 0x633e8591);
  	mmio_write_32((0xf712c000 + 0x040), 0x3008691);
  	mmio_write_32((0xf712c000 + 0x064), 0x10483);
  	mmio_write_32((0xf712c000 + 0x068), 0xff0a0000);
  	data = mmio_read_32((0xf712c000 + 0x070));
  	data &= 0xffff0000;
  	data |= 0x184;
  	mmio_write_32((0xf712c000 + 0x070), data);
  	data = mmio_read_32((0xf712c000 + 0x048));
  	data &= 0xbfffffff;
  	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), 0x90420880);
  
  	mmio_write_32((0xf7128000 + 0x040), 0x0);
  	mmio_write_32((0xf712c000 + 0x004), 0x146d);
  	mmio_write_32((0xf7128000 + 0x050), 0x100123);
  	mmio_write_32((0xf7128000 + 0x060), 0x133);
  	mmio_write_32((0xf7128000 + 0x064), 0x133);
  	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
  
  	mmio_write_32((0xf7128000 + 0x100), 0xb55a9d12);
  	mmio_write_32((0xf7128000 + 0x104), 0x17721855);
  	mmio_write_32((0xf7128000 + 0x108), 0x7501505f);
  	mmio_write_32((0xf7128000 + 0x10c), 0xaf4ca245);
  	mmio_write_32((0xf7128000 + 0x110), 0x10b00000);
  	mmio_write_32((0xf7128000 + 0x114), 0x13081306);
  	mmio_write_32((0xf7128000 + 0x118), 0x44);
  	do {
  		data = mmio_read_32((0xf712c000 + 0x004));
  	} while (data & 1);
  	data = mmio_read_32((0xf712c000 + 0x008));
  	if (data & 8) {
  		NOTICE("fail to init ddr3 rank0\n");
  		return;
  	}
  
  	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 & 0x8)
  		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);
  	INFO("succeed to set ddrc 400mhz\n");
  }
  
  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 + 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;
  	}
  	cat_533mhz_800mhz();
  
  	mmio_write_32((0xf712c000 + 0x004), 0xf1);
  	mmio_write_32((0xf7128000 + 0x050), 0x100123);
  	mmio_write_32((0xf7128000 + 0x060), 0x133);
  	mmio_write_32((0xf7128000 + 0x064), 0x133);
  	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
  
  	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;
  	}
  	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);
  	INFO("succeed to set ddrc 533mhz\n");
  }
  
  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 + 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;
  	}
  	cat_533mhz_800mhz();
  
  	mmio_write_32((0xf712c000 + 0x004), 0xf1);
  	mmio_write_32((0xf7128000 + 0x050), 0x100023);
  	mmio_write_32((0xf7128000 + 0x060), 0x133);
  	mmio_write_32((0xf7128000 + 0x064), 0x133);
  	mmio_write_32((0xf7128000 + 0x200), 0xa1000);
  
  	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);
  	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;
  	}
  	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);
  	INFO("succeed to set ddrc 800mhz\n");
  }
  
  static void ddrc_common_init(int freq)
  {
  	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((0xf7121c00 + 0x104), 0xf);
  	mmio_write_32((0xf7122000 + 0x104), 0xf);
  	mmio_write_32((0xf7128000 + 0x02c), 0x6);
  	mmio_write_32((0xf7128000 + 0x020), 0x30003);
  	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 (freq == DDR_FREQ_800M)
  		mmio_write_32((0xf7128000 + 0x240), 167 * (freq / 2) / 1024);
  	else
  		mmio_write_32((0xf7128000 + 0x240), 167 * freq / 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);
  		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x40000000);
  		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);
  		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000);
  		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);
  		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000);
  		break;
  	default:
  		mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000);
  		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;
  }
  
  void ddr_phy_reset(void)
  {
  	mmio_write_32(0xf7030340, 0xa000);
  	mmio_write_32(0xf7030344, 0xa000);
  }
  
  void lpddrx_save_ddl_para_bypass(uint32_t *ddr_ddl_para, unsigned int index)
  {
  	uint32_t value;
  	uint32_t cnt = index;
  	uint32_t i;
  
  	for (i = 0; i < 4; i++) {
  		value = mmio_read_32(0xf712c000 + 0x22c + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x23c + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x240 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x640 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  	}
  }
  
  void lpddrx_save_ddl_para_mission(uint32_t *ddr_ddl_para, unsigned int index)
  {
  	uint32_t value;
  	uint32_t cnt = index;
  	uint32_t i;
  
  	value = mmio_read_32(0xf712c000 + 0x140);
  	ddr_ddl_para[cnt++] = value;
  	value = mmio_read_32(0xf712c000 + 0x144);
  	ddr_ddl_para[cnt++] = value;
  	value = mmio_read_32(0xf712c000 + 0x148);
  	ddr_ddl_para[cnt++] = value;
  	value = mmio_read_32(0xf712c000 + 0x14c);
  	ddr_ddl_para[cnt++] = value;
  	value = mmio_read_32(0xf712c000 + 0x150);
  	ddr_ddl_para[cnt++] = value;
  	value = mmio_read_32(0xf712c000 + 0x1d4);
  	ddr_ddl_para[cnt++] = value;
  	for (i = 0; i < 4; i++) {
  		value = mmio_read_32(0xf712c000 + 0x210 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x214 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x218 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x21c + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x220 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x224 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x228 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x22c + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x230 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x234 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x238 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x23c + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x240 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  		value = mmio_read_32(0xf712c000 + 0x640 + i * 0x80);
  		ddr_ddl_para[cnt++] = value;
  	}
  	value = mmio_read_32(0xf712c000 + 0x168);
  	ddr_ddl_para[cnt++] = value;
  	value = mmio_read_32(0xf712c000 + 0x24c + 0 * 0x80);
  	ddr_ddl_para[cnt++] = value;
  	value = mmio_read_32(0xf712c000 + 0x24c + 2 * 0x80);
  	ddr_ddl_para[cnt++] = value;
  }
  
  int lpddr3_freq_init(int freq)
  {
  	set_ddrc_150mhz();
  	lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR, 0);
  	if (freq > DDR_FREQ_150M) {
  		ddr_phy_reset();
  		set_ddrc_266mhz();
  		lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
  					    16);
  	}
  	if (freq > DDR_FREQ_266M) {
  		ddr_phy_reset();
  		set_ddrc_400mhz();
  		lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
  					    16 * 2);
  	}
  	if (freq > DDR_FREQ_400M) {
  		ddr_phy_reset();
  		set_ddrc_533mhz();
  		lpddrx_save_ddl_para_mission((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
  					     16 * 3);
  	}
  	if (freq > DDR_FREQ_533M) {
  		ddr_phy_reset();
  		set_ddrc_800mhz();
  		lpddrx_save_ddl_para_mission((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR,
  					     16 * 3 + 61);
  	}
  	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(300);
  	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);
  }
  
  void hikey_ddr_init(unsigned int ddr_freq)
  {
  	uint32_t data;
  
  	assert((ddr_freq == DDR_FREQ_150M) || (ddr_freq == DDR_FREQ_266M) ||
  	       (ddr_freq == DDR_FREQ_400M) || (ddr_freq == DDR_FREQ_533M) ||
  	       (ddr_freq == DDR_FREQ_800M));
  	init_pll();
  	init_freq();
  
  	init_ddr(ddr_freq);
  
  	ddrc_common_init(ddr_freq);
  	dienum_det_and_rowcol_cfg();
  	detect_ddr_chip_info();
  
  	if ((ddr_freq == DDR_FREQ_400M) || (ddr_freq == DDR_FREQ_800M)) {
  		data = mmio_read_32(0xf7032000 + 0x010);
  		data &= ~0x1;
  		mmio_write_32(0xf7032000 + 0x010, data);
  	} else if ((ddr_freq == DDR_FREQ_266M) || (ddr_freq == DDR_FREQ_533M)) {
  		data = mmio_read_32(0xf7032000 + 0x030);
  		data &= ~0x1;
  		mmio_write_32(0xf7032000 + 0x030, data);
  	} else {
  		data = mmio_read_32(0xf7032000 + 0x010);
  		data &= ~0x1;
  		mmio_write_32(0xf7032000 + 0x010, data);
  		data = mmio_read_32(0xf7032000 + 0x030);
  		data &= ~0x1;
  		mmio_write_32(0xf7032000 + 0x030, data);
  	}
  	dsb();
  	isb();
  
  	/*
  	 * 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();
  }
  