diff options
Diffstat (limited to 'arch/arm/cpu')
35 files changed, 3366 insertions, 354 deletions
| diff --git a/arch/arm/cpu/arm720t/tegra-common/cpu.c b/arch/arm/cpu/arm720t/tegra-common/cpu.c index 9294611be..72c69b914 100644 --- a/arch/arm/cpu/arm720t/tegra-common/cpu.c +++ b/arch/arm/cpu/arm720t/tegra-common/cpu.c @@ -49,33 +49,68 @@ int get_num_cpus(void)   * Timing tables for each SOC for all four oscillator options.   */  struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { -	/* T20: 1 GHz */ -	/*  n,  m, p, cpcon */ -	{{ 1000, 13, 0, 12},	/* OSC 13M */ -	 { 625,  12, 0, 8},	/* OSC 19.2M */ -	 { 1000, 12, 0, 12},	/* OSC 12M */ -	 { 1000, 26, 0, 12},	/* OSC 26M */ +	/* +	 * T20: 1 GHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      22:20    3 +	 * PLLX_BASE  n      17: 8   10 +	 * PLLX_BASE  m       4: 0    5 +	 * PLLX_MISC  cpcon  11: 8    4 +	 */ +	{ +		{ .n = 1000, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */ +		{ .n =  625, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */ +		{ .n = 1000, .m = 12, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */ +		{ .n = 1000, .m = 26, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */  	}, - -	/* T25: 1.2 GHz */ -	{{ 923, 10, 0, 12}, -	 { 750, 12, 0, 8}, -	 { 600,  6, 0, 12}, -	 { 600, 13, 0, 12}, +	/* +	 * T25: 1.2 GHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      22:20    3 +	 * PLLX_BASE  n      17: 8   10 +	 * PLLX_BASE  m       4: 0    5 +	 * PLLX_MISC  cpcon  11: 8    4 +	 */ +	{ +		{ .n = 923, .m = 10, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */ +		{ .n = 750, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */ +		{ .n = 600, .m =  6, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */ +		{ .n = 600, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */  	}, - -	/* T30: 1.4 GHz */ -	{{ 862, 8, 0, 8}, -	 { 583, 8, 0, 4}, -	 { 700, 6, 0, 8}, -	 { 700, 13, 0, 8}, +	/* +	 * T30: 1.4 GHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      22:20    3 +	 * PLLX_BASE  n      17: 8   10 +	 * PLLX_BASE  m       4: 0    5 +	 * PLLX_MISC  cpcon  11: 8    4 +	 */ +	{ +		{ .n = 862, .m =  8, .p = 0, .cpcon = 8 }, /* OSC: 13.0 MHz */ +		{ .n = 583, .m =  8, .p = 0, .cpcon = 4 }, /* OSC: 19.2 MHz */ +		{ .n = 700, .m =  6, .p = 0, .cpcon = 8 }, /* OSC: 12.0 MHz */ +		{ .n = 700, .m = 13, .p = 0, .cpcon = 8 }, /* OSC: 26.0 MHz */  	}, - -	/* T114: 1.4 GHz */ -	{{ 862, 8, 0, 8}, -	 { 583, 8, 0, 4}, -	 { 696, 12, 0, 8}, -	 { 700, 13, 0, 8}, +	/* +	 * T114: 700 MHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      23:20    4 +	 * PLLX_BASE  n      15: 8    8 +	 * PLLX_BASE  m       7: 0    8 +	 */ +	{ +		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */ +		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */ +		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */ +		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */  	},  }; @@ -100,6 +135,7 @@ void adjust_pllp_out_freqs(void)  int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,  		u32 divp, u32 cpcon)  { +	int chip = tegra_get_chip();  	u32 reg;  	/* If PLLX is already enabled, just return */ @@ -116,7 +152,10 @@ int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,  	writel(reg, &pll->pll_base);  	/* Set cpcon to PLLX_MISC */ -	reg = (cpcon << PLL_CPCON_SHIFT); +	if (chip == CHIPID_TEGRA20 || chip == CHIPID_TEGRA30) +		reg = (cpcon << PLL_CPCON_SHIFT); +	else +		reg = 0;  	/* Set dccon to PLLX_MISC if freq > 600MHz */  	if (divn > 600) diff --git a/arch/arm/cpu/armv7/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c index 803aa9c54..c7dad6681 100644 --- a/arch/arm/cpu/armv7/am33xx/board.c +++ b/arch/arm/cpu/armv7/am33xx/board.c @@ -241,3 +241,11 @@ void s_init(void)  	sdram_init();  #endif  } + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ +	/* Enable D-cache. I-cache is already enabled in start.S */ +	dcache_enable(); +} +#endif /* !CONFIG_SYS_DCACHE_OFF */ diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c index 8e5f3c671..0672798fe 100644 --- a/arch/arm/cpu/armv7/am33xx/clock.c +++ b/arch/arm/cpu/armv7/am33xx/clock.c @@ -101,9 +101,15 @@ void do_setup_dpll(const struct dpll_regs *dpll_regs,  static void setup_dplls(void)  {  	const struct dpll_params *params; -	do_setup_dpll(&dpll_core_regs, &dpll_core); -	do_setup_dpll(&dpll_mpu_regs, &dpll_mpu); -	do_setup_dpll(&dpll_per_regs, &dpll_per); + +	params = get_dpll_core_params(); +	do_setup_dpll(&dpll_core_regs, params); + +	params = get_dpll_mpu_params(); +	do_setup_dpll(&dpll_mpu_regs, params); + +	params = get_dpll_per_params(); +	do_setup_dpll(&dpll_per_regs, params);  	writel(0x300, &cmwkup->clkdcoldodpllper);  	params = get_dpll_ddr_params(); diff --git a/arch/arm/cpu/armv7/am33xx/clock_am33xx.c b/arch/arm/cpu/armv7/am33xx/clock_am33xx.c index fabe2595a..92142c893 100644 --- a/arch/arm/cpu/armv7/am33xx/clock_am33xx.c +++ b/arch/arm/cpu/armv7/am33xx/clock_am33xx.c @@ -62,6 +62,21 @@ const struct dpll_params dpll_core = {  const struct dpll_params dpll_per = {  		960, OSC-1, 5, -1, -1, -1, -1}; +const struct dpll_params *get_dpll_mpu_params(void) +{ +	return &dpll_mpu; +} + +const struct dpll_params *get_dpll_core_params(void) +{ +	return &dpll_core; +} + +const struct dpll_params *get_dpll_per_params(void) +{ +	return &dpll_per; +} +  void setup_clocks_for_console(void)  {  	clrsetbits_le32(&cmwkup->wkclkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK, diff --git a/arch/arm/cpu/armv7/am33xx/clock_am43xx.c b/arch/arm/cpu/armv7/am33xx/clock_am43xx.c index c4890f2b4..97c00b492 100644 --- a/arch/arm/cpu/armv7/am33xx/clock_am43xx.c +++ b/arch/arm/cpu/armv7/am33xx/clock_am43xx.c @@ -18,6 +18,7 @@  struct cm_perpll *const cmper = (struct cm_perpll *)CM_PER;  struct cm_wkuppll *const cmwkup = (struct cm_wkuppll *)CM_WKUP; +struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;  const struct dpll_regs dpll_mpu_regs = {  	.cm_clkmode_dpll	= CM_WKUP + 0x560, @@ -47,15 +48,9 @@ const struct dpll_regs dpll_ddr_regs = {  	.cm_idlest_dpll		= CM_WKUP + 0x5A4,  	.cm_clksel_dpll		= CM_WKUP + 0x5AC,  	.cm_div_m2_dpll		= CM_WKUP + 0x5B0, +	.cm_div_m4_dpll		= CM_WKUP + 0x5B8,  }; -const struct dpll_params dpll_mpu = { -		-1, -1, -1, -1, -1, -1, -1}; -const struct dpll_params dpll_core = { -		-1, -1, -1, -1, -1, -1, -1}; -const struct dpll_params dpll_per = { -		-1, -1, -1, -1, -1, -1, -1}; -  void setup_clocks_for_console(void)  {  	/* Do not add any spl_debug prints in this function */ @@ -107,4 +102,7 @@ void enable_basic_clocks(void)  	};  	do_enable_clocks(clk_domains, clk_modules_explicit_en, 1); + +	/* Select the Master osc clk as Timer2 clock source */ +	writel(0x1, &cmdpll->clktimer2clk);  } diff --git a/arch/arm/cpu/armv7/am33xx/ddr.c b/arch/arm/cpu/armv7/am33xx/ddr.c index 5b0454c3e..d05e666a7 100644 --- a/arch/arm/cpu/armv7/am33xx/ddr.c +++ b/arch/arm/cpu/armv7/am33xx/ddr.c @@ -36,6 +36,73 @@ static struct ddr_data_regs *ddr_data_reg[2] = {  static struct ddr_cmdtctrl *ioctrl_reg = {  			(struct ddr_cmdtctrl *)DDR_CONTROL_BASE_ADDR}; +static inline u32 get_mr(int nr, u32 cs, u32 mr_addr) +{ +	u32 mr; + +	mr_addr |= cs << EMIF_REG_CS_SHIFT; +	writel(mr_addr, &emif_reg[nr]->emif_lpddr2_mode_reg_cfg); + +	mr = readl(&emif_reg[nr]->emif_lpddr2_mode_reg_data); +	debug("get_mr: EMIF1 cs %d mr %08x val 0x%x\n", cs, mr_addr, mr); +	if (((mr & 0x0000ff00) >>  8) == (mr & 0xff) && +	    ((mr & 0x00ff0000) >> 16) == (mr & 0xff) && +	    ((mr & 0xff000000) >> 24) == (mr & 0xff)) +		return mr & 0xff; +	else +		return mr; +} + +static inline void set_mr(int nr, u32 cs, u32 mr_addr, u32 mr_val) +{ +	mr_addr |= cs << EMIF_REG_CS_SHIFT; +	writel(mr_addr, &emif_reg[nr]->emif_lpddr2_mode_reg_cfg); +	writel(mr_val, &emif_reg[nr]->emif_lpddr2_mode_reg_data); +} + +static void configure_mr(int nr, u32 cs) +{ +	u32 mr_addr; + +	while (get_mr(nr, cs, LPDDR2_MR0) & LPDDR2_MR0_DAI_MASK) +		; +	set_mr(nr, cs, LPDDR2_MR10, 0x56); + +	set_mr(nr, cs, LPDDR2_MR1, 0x43); +	set_mr(nr, cs, LPDDR2_MR2, 0x2); + +	mr_addr = LPDDR2_MR2 | EMIF_REG_REFRESH_EN_MASK; +	set_mr(nr, cs, mr_addr, 0x2); +} + +/* + * Configure EMIF4D5 registers and MR registers + */ +void config_sdram_emif4d5(const struct emif_regs *regs, int nr) +{ +	writel(0x0, &emif_reg[nr]->emif_pwr_mgmt_ctrl); +	writel(0x0, &emif_reg[nr]->emif_pwr_mgmt_ctrl_shdw); +	writel(0x1, &emif_reg[nr]->emif_iodft_tlgc); +	writel(regs->zq_config, &emif_reg[nr]->emif_zq_config); + +	writel(regs->temp_alert_config, &emif_reg[nr]->emif_temp_alert_config); +	writel(regs->emif_rd_wr_lvl_rmp_win, +	       &emif_reg[nr]->emif_rd_wr_lvl_rmp_win); +	writel(regs->emif_rd_wr_lvl_rmp_ctl, +	       &emif_reg[nr]->emif_rd_wr_lvl_rmp_ctl); +	writel(regs->emif_rd_wr_lvl_ctl, &emif_reg[nr]->emif_rd_wr_lvl_ctl); +	writel(regs->emif_rd_wr_exec_thresh, +	       &emif_reg[nr]->emif_rd_wr_exec_thresh); + +	writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl); +	writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config); + +	if (emif_sdram_type() == EMIF_SDRAM_TYPE_LPDDR2) { +		configure_mr(nr, 0); +		configure_mr(nr, 1); +	} +} +  /**   * Configure SDRAM   */ @@ -72,15 +139,67 @@ void set_sdram_timings(const struct emif_regs *regs, int nr)  	writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3_shdw);  } +void __weak emif_get_ext_phy_ctrl_const_regs(const u32 **regs, u32 *size) +{ +} + +/* + * Configure EXT PHY registers + */ +static void ext_phy_settings(const struct emif_regs *regs, int nr) +{ +	u32 *ext_phy_ctrl_base = 0; +	u32 *emif_ext_phy_ctrl_base = 0; +	const u32 *ext_phy_ctrl_const_regs; +	u32 i = 0; +	u32 size; + +	ext_phy_ctrl_base = (u32 *)&(regs->emif_ddr_ext_phy_ctrl_1); +	emif_ext_phy_ctrl_base = +			(u32 *)&(emif_reg[nr]->emif_ddr_ext_phy_ctrl_1); + +	/* Configure external phy control timing registers */ +	for (i = 0; i < EMIF_EXT_PHY_CTRL_TIMING_REG; i++) { +		writel(*ext_phy_ctrl_base, emif_ext_phy_ctrl_base++); +		/* Update shadow registers */ +		writel(*ext_phy_ctrl_base++, emif_ext_phy_ctrl_base++); +	} + +	/* +	 * external phy 6-24 registers do not change with +	 * ddr frequency +	 */ +	emif_get_ext_phy_ctrl_const_regs(&ext_phy_ctrl_const_regs, &size); + +	if (!size) +		return; + +	for (i = 0; i < size; i++) { +		writel(ext_phy_ctrl_const_regs[i], emif_ext_phy_ctrl_base++); +		/* Update shadow registers */ +		writel(ext_phy_ctrl_const_regs[i], emif_ext_phy_ctrl_base++); +	} +} +  /**   * Configure DDR PHY   */  void config_ddr_phy(const struct emif_regs *regs, int nr)  { +	/* +	 * disable initialization and refreshes for now until we +	 * finish programming EMIF regs. +	 */ +	setbits_le32(&emif_reg[nr]->emif_sdram_ref_ctrl, +		     EMIF_REG_INITREF_DIS_MASK); +  	writel(regs->emif_ddr_phy_ctlr_1,  		&emif_reg[nr]->emif_ddr_phy_ctrl_1);  	writel(regs->emif_ddr_phy_ctlr_1,  		&emif_reg[nr]->emif_ddr_phy_ctrl_1_shdw); + +	if (get_emif_rev((u32)emif_reg[nr]) == EMIF_4D5) +		ext_phy_settings(regs, nr);  }  /** @@ -88,6 +207,9 @@ void config_ddr_phy(const struct emif_regs *regs, int nr)   */  void config_cmd_ctrl(const struct cmd_control *cmd, int nr)  { +	if (!cmd) +		return; +  	writel(cmd->cmd0csratio, &ddr_cmd_reg[nr]->cm0csratio);  	writel(cmd->cmd0iclkout, &ddr_cmd_reg[nr]->cm0iclkout); @@ -105,6 +227,9 @@ void config_ddr_data(const struct ddr_data *data, int nr)  {  	int i; +	if (!data) +		return; +  	for (i = 0; i < DDR_DATA_REGS_NR; i++) {  		writel(data->datardsratio0,  			&(ddr_data_reg[nr]+i)->dt0rdsratio0); @@ -121,11 +246,20 @@ void config_ddr_data(const struct ddr_data *data, int nr)  	}  } -void config_io_ctrl(unsigned long val) +void config_io_ctrl(const struct ctrl_ioregs *ioregs)  { -	writel(val, &ioctrl_reg->cm0ioctl); -	writel(val, &ioctrl_reg->cm1ioctl); -	writel(val, &ioctrl_reg->cm2ioctl); -	writel(val, &ioctrl_reg->dt0ioctl); -	writel(val, &ioctrl_reg->dt1ioctl); +	if (!ioregs) +		return; + +	writel(ioregs->cm0ioctl, &ioctrl_reg->cm0ioctl); +	writel(ioregs->cm1ioctl, &ioctrl_reg->cm1ioctl); +	writel(ioregs->cm2ioctl, &ioctrl_reg->cm2ioctl); +	writel(ioregs->dt0ioctl, &ioctrl_reg->dt0ioctl); +	writel(ioregs->dt1ioctl, &ioctrl_reg->dt1ioctl); +#ifdef CONFIG_AM43XX +	writel(ioregs->dt2ioctrl, &ioctrl_reg->dt2ioctrl); +	writel(ioregs->dt3ioctrl, &ioctrl_reg->dt3ioctrl); +	writel(ioregs->emif_sdram_config_ext, +	       &ioctrl_reg->emif_sdram_config_ext); +#endif  } diff --git a/arch/arm/cpu/armv7/am33xx/emif4.c b/arch/arm/cpu/armv7/am33xx/emif4.c index 59ad25c5b..d28fceb75 100644 --- a/arch/arm/cpu/armv7/am33xx/emif4.c +++ b/arch/arm/cpu/armv7/am33xx/emif4.c @@ -48,6 +48,11 @@ static struct vtp_reg *vtpreg[2] = {  #ifdef CONFIG_AM33XX  static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR;  #endif +#ifdef CONFIG_AM43XX +static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR; +static struct cm_device_inst *cm_device = +				(struct cm_device_inst *)CM_DEVICE_INST; +#endif  #ifdef CONFIG_TI81XX  void config_dmm(const struct dmm_lisa_map_regs *regs) @@ -87,7 +92,7 @@ void __weak ddr_pll_config(unsigned int ddrpll_m)  {  } -void config_ddr(unsigned int pll, unsigned int ioctrl, +void config_ddr(unsigned int pll, const struct ctrl_ioregs *ioregs,  		const struct ddr_data *data, const struct cmd_control *ctrl,  		const struct emif_regs *regs, int nr)  { @@ -99,7 +104,18 @@ void config_ddr(unsigned int pll, unsigned int ioctrl,  	config_ddr_data(data, nr);  #ifdef CONFIG_AM33XX -	config_io_ctrl(ioctrl); +	config_io_ctrl(ioregs); + +	/* Set CKE to be controlled by EMIF/DDR PHY */ +	writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl); +#endif +#ifdef CONFIG_AM43XX +	writel(readl(&cm_device->cm_dll_ctrl) & ~0x1, &cm_device->cm_dll_ctrl); +	while ((readl(&cm_device->cm_dll_ctrl) && CM_DLL_READYST) == 0) +		; +	writel(0x0, &ddrctrl->ddrioctrl); + +	config_io_ctrl(ioregs);  	/* Set CKE to be controlled by EMIF/DDR PHY */  	writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl); @@ -108,6 +124,9 @@ void config_ddr(unsigned int pll, unsigned int ioctrl,  	/* Program EMIF instance */  	config_ddr_phy(regs, nr);  	set_sdram_timings(regs, nr); -	config_sdram(regs, nr); +	if (get_emif_rev(EMIF1_BASE) == EMIF_4D5) +		config_sdram_emif4d5(regs, nr); +	else +		config_sdram(regs, nr);  }  #endif diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 84a50470a..5bde9d180 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -96,7 +96,7 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)  	freq = CONFIG_SYS_CLK_FREQ; -	if (pllreg == EPLL) { +	if (pllreg == EPLL || pllreg == RPLL) {  		k = k & 0xffff;  		/* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */  		fout = (m + k / PLL_DIV_65536) * (freq / (p * (1 << s))); @@ -117,7 +117,7 @@ static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)  			div = PLL_DIV_1024;  		else if (proid_is_exynos4412())  			div = PLL_DIV_65535; -		else if (proid_is_exynos5250()) +		else if (proid_is_exynos5250() || proid_is_exynos5420())  			div = PLL_DIV_65536;  		else  			return 0; @@ -362,6 +362,43 @@ unsigned long clock_get_periph_rate(int peripheral)  		return 0;  } +/* exynos5420: return pll clock frequency */ +static unsigned long exynos5420_get_pll_clk(int pllreg) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long r, k = 0; + +	switch (pllreg) { +	case APLL: +		r = readl(&clk->apll_con0); +		break; +	case MPLL: +		r = readl(&clk->mpll_con0); +		break; +	case EPLL: +		r = readl(&clk->epll_con0); +		k = readl(&clk->epll_con1); +		break; +	case VPLL: +		r = readl(&clk->vpll_con0); +		k = readl(&clk->vpll_con1); +		break; +	case BPLL: +		r = readl(&clk->bpll_con0); +		break; +	case RPLL: +		r = readl(&clk->rpll_con0); +		k = readl(&clk->rpll_con1); +		break; +	default: +		printf("Unsupported PLL (%d)\n", pllreg); +		return 0; +	} + +	return exynos_get_pll_clk(pllreg, r, k); +} +  /* exynos4: return ARM clock frequency */  static unsigned long exynos4_get_arm_clk(void)  { @@ -485,6 +522,27 @@ static unsigned long exynos4x12_get_pwm_clk(void)  	return pclk;  } +/* exynos5420: return pwm clock frequency */ +static unsigned long exynos5420_get_pwm_clk(void) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long pclk, sclk; +	unsigned int ratio; + +	/* +	 * CLK_DIV_PERIC0 +	 * PWM_RATIO [31:28] +	 */ +	ratio = readl(&clk->div_peric0); +	ratio = (ratio >> 28) & 0xf; +	sclk = get_pll_clk(MPLL); + +	pclk = sclk / (ratio + 1); + +	return pclk; +} +  /* exynos4: return uart clock frequency */  static unsigned long exynos4_get_uart_clk(int dev_index)  { @@ -624,6 +682,53 @@ static unsigned long exynos5_get_uart_clk(int dev_index)  	return uclk;  } +/* exynos5420: return uart clock frequency */ +static unsigned long exynos5420_get_uart_clk(int dev_index) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long uclk, sclk; +	unsigned int sel; +	unsigned int ratio; + +	/* +	 * CLK_SRC_PERIC0 +	 * UART0_SEL [6:4] +	 * UART1_SEL [10:8] +	 * UART2_SEL [14:12] +	 * UART3_SEL [18:16] +	 * generalised calculation as follows +	 * sel = (sel >> ((dev_index * 4) + 4)) & mask; +	 */ +	sel = readl(&clk->src_peric0); +	sel = (sel >> ((dev_index * 4) + 4)) & 0x7; + +	if (sel == 0x3) +		sclk = get_pll_clk(MPLL); +	else if (sel == 0x6) +		sclk = get_pll_clk(EPLL); +	else if (sel == 0x7) +		sclk = get_pll_clk(RPLL); +	else +		return 0; + +	/* +	 * CLK_DIV_PERIC0 +	 * UART0_RATIO [11:8] +	 * UART1_RATIO [15:12] +	 * UART2_RATIO [19:16] +	 * UART3_RATIO [23:20] +	 * generalised calculation as follows +	 * ratio = (ratio >> ((dev_index * 4) + 8)) & mask; +	 */ +	ratio = readl(&clk->div_peric0); +	ratio = (ratio >> ((dev_index * 4) + 8)) & 0xf; + +	uclk = sclk / (ratio + 1); + +	return uclk; +} +  static unsigned long exynos4_get_mmc_clk(int dev_index)  {  	struct exynos4_clock *clk = @@ -718,6 +823,47 @@ static unsigned long exynos5_get_mmc_clk(int dev_index)  	return uclk;  } +static unsigned long exynos5420_get_mmc_clk(int dev_index) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned long uclk, sclk; +	unsigned int sel, ratio; + +	/* +	 * CLK_SRC_FSYS +	 * MMC0_SEL [10:8] +	 * MMC1_SEL [14:12] +	 * MMC2_SEL [18:16] +	 * generalised calculation as follows +	 * sel = (sel >> ((dev_index * 4) + 8)) & mask +	 */ +	sel = readl(&clk->src_fsys); +	sel = (sel >> ((dev_index * 4) + 8)) & 0x7; + +	if (sel == 0x3) +		sclk = get_pll_clk(MPLL); +	else if (sel == 0x6) +		sclk = get_pll_clk(EPLL); +	else +		return 0; + +	/* +	 * CLK_DIV_FSYS1 +	 * MMC0_RATIO [9:0] +	 * MMC1_RATIO [19:10] +	 * MMC2_RATIO [29:20] +	 * generalised calculation as follows +	 * ratio = (ratio >> (dev_index * 10)) & mask +	 */ +	ratio = readl(&clk->div_fsys1); +	ratio = (ratio >> (dev_index * 10)) & 0x3ff; + +	uclk = (sclk / (ratio + 1)); + +	return uclk; +} +  /* exynos4: set the mmc clock */  static void exynos4_set_mmc_clk(int dev_index, unsigned int div)  { @@ -804,6 +950,29 @@ static void exynos5_set_mmc_clk(int dev_index, unsigned int div)  	writel(val, addr);  } +/* exynos5: set the mmc clock */ +static void exynos5420_set_mmc_clk(int dev_index, unsigned int div) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	unsigned int addr; +	unsigned int val, shift; + +	/* +	 * CLK_DIV_FSYS1 +	 * MMC0_RATIO [9:0] +	 * MMC1_RATIO [19:10] +	 * MMC2_RATIO [29:20] +	 */ +	addr = (unsigned int)&clk->div_fsys1; +	shift = dev_index * 10; + +	val = readl(addr); +	val &= ~(0x3ff << shift); +	val |= (div & 0x3ff) << shift; +	writel(val, addr); +} +  /* get_lcd_clk: return lcd clock frequency */  static unsigned long exynos4_get_lcd_clk(void)  { @@ -1324,6 +1493,71 @@ static int exynos5_set_spi_clk(enum periph_id periph_id,  	return 0;  } +static int exynos5420_set_spi_clk(enum periph_id periph_id, +					unsigned int rate) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	int main; +	unsigned int fine; +	unsigned shift, pre_shift; +	unsigned div_mask = 0xf, pre_div_mask = 0xff; +	u32 *reg; +	u32 *pre_reg; + +	main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); +	if (main < 0) { +		debug("%s: Cannot set clock rate for periph %d", +		      __func__, periph_id); +		return -1; +	} +	main = main - 1; +	fine = fine - 1; + +	switch (periph_id) { +	case PERIPH_ID_SPI0: +		reg = &clk->div_peric1; +		shift = 20; +		pre_reg = &clk->div_peric4; +		pre_shift = 8; +		break; +	case PERIPH_ID_SPI1: +		reg = &clk->div_peric1; +		shift = 24; +		pre_reg = &clk->div_peric4; +		pre_shift = 16; +		break; +	case PERIPH_ID_SPI2: +		reg = &clk->div_peric1; +		shift = 28; +		pre_reg = &clk->div_peric4; +		pre_shift = 24; +		break; +	case PERIPH_ID_SPI3: +		reg = &clk->div_isp1; +		shift = 16; +		pre_reg = &clk->div_isp1; +		pre_shift = 0; +		break; +	case PERIPH_ID_SPI4: +		reg = &clk->div_isp1; +		shift = 20; +		pre_reg = &clk->div_isp1; +		pre_shift = 8; +		break; +	default: +		debug("%s: Unsupported peripheral ID %d\n", __func__, +		      periph_id); +		return -1; +	} + +	clrsetbits_le32(reg, div_mask << shift, (main & div_mask) << shift); +	clrsetbits_le32(pre_reg, pre_div_mask << pre_shift, +			(fine & pre_div_mask) << pre_shift); + +	return 0; +} +  static unsigned long exynos4_get_i2c_clk(void)  {  	struct exynos4_clock *clk = @@ -1341,9 +1575,11 @@ static unsigned long exynos4_get_i2c_clk(void)  unsigned long get_pll_clk(int pllreg)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_pll_clk(pllreg);  		return exynos5_get_pll_clk(pllreg); -	else { +	} else {  		if (proid_is_exynos4412())  			return exynos4x12_get_pll_clk(pllreg);  		return exynos4_get_pll_clk(pllreg); @@ -1375,9 +1611,11 @@ unsigned long get_i2c_clk(void)  unsigned long get_pwm_clk(void)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_pwm_clk();  		return clock_get_periph_rate(PERIPH_ID_PWM0); -	else { +	} else {  		if (proid_is_exynos4412())  			return exynos4x12_get_pwm_clk();  		return exynos4_get_pwm_clk(); @@ -1386,9 +1624,11 @@ unsigned long get_pwm_clk(void)  unsigned long get_uart_clk(int dev_index)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_uart_clk(dev_index);  		return exynos5_get_uart_clk(dev_index); -	else { +	} else {  		if (proid_is_exynos4412())  			return exynos4x12_get_uart_clk(dev_index);  		return exynos4_get_uart_clk(dev_index); @@ -1397,17 +1637,23 @@ unsigned long get_uart_clk(int dev_index)  unsigned long get_mmc_clk(int dev_index)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_get_mmc_clk(dev_index);  		return exynos5_get_mmc_clk(dev_index); -	else +	} else {  		return exynos4_get_mmc_clk(dev_index); +	}  }  void set_mmc_clk(int dev_index, unsigned int div)  { -	if (cpu_is_exynos5()) -		exynos5_set_mmc_clk(dev_index, div); -	else { +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			exynos5420_set_mmc_clk(dev_index, div); +		else +			exynos5_set_mmc_clk(dev_index, div); +	} else {  		if (proid_is_exynos4412())  			exynos4x12_set_mmc_clk(dev_index, div);  		else @@ -1439,10 +1685,13 @@ void set_mipi_clk(void)  int set_spi_clk(int periph_id, unsigned int rate)  { -	if (cpu_is_exynos5()) +	if (cpu_is_exynos5()) { +		if (proid_is_exynos5420()) +			return exynos5420_set_spi_clk(periph_id, rate);  		return exynos5_set_spi_clk(periph_id, rate); -	else +	} else {  		return 0; +	}  }  int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq, diff --git a/arch/arm/cpu/armv7/exynos/clock_init.h b/arch/arm/cpu/armv7/exynos/clock_init.h index c28ff3ab1..a875d0b48 100644 --- a/arch/arm/cpu/armv7/exynos/clock_init.h +++ b/arch/arm/cpu/armv7/exynos/clock_init.h @@ -10,7 +10,11 @@  #define __EXYNOS_CLOCK_INIT_H  enum { +#ifdef CONFIG_EXYNOS5420 +	MEM_TIMINGS_MSR_COUNT	= 5, +#else  	MEM_TIMINGS_MSR_COUNT	= 4, +#endif  };  /* These are the ratio's for configuring ARM clock */ @@ -59,6 +63,18 @@ struct mem_timings {  	unsigned bpll_mdiv;  	unsigned bpll_pdiv;  	unsigned bpll_sdiv; +	unsigned kpll_mdiv; +	unsigned kpll_pdiv; +	unsigned kpll_sdiv; +	unsigned dpll_mdiv; +	unsigned dpll_pdiv; +	unsigned dpll_sdiv; +	unsigned ipll_mdiv; +	unsigned ipll_pdiv; +	unsigned ipll_sdiv; +	unsigned spll_mdiv; +	unsigned spll_pdiv; +	unsigned spll_sdiv;  	unsigned pclk_cdrex_ratio;  	unsigned direct_cmd_msr[MEM_TIMINGS_MSR_COUNT]; @@ -115,6 +131,7 @@ struct mem_timings {  	uint8_t send_zq_init;		/* 1 to send this command */  	unsigned impedance;		/* drive strength impedeance */  	uint8_t gate_leveling_enable;	/* check gate leveling is enabled */ +	uint8_t read_leveling_enable;	/* check h/w read leveling is enabled */  };  /** diff --git a/arch/arm/cpu/armv7/exynos/clock_init_exynos5.c b/arch/arm/cpu/armv7/exynos/clock_init_exynos5.c index a24c2f387..1d6977fa4 100644 --- a/arch/arm/cpu/armv7/exynos/clock_init_exynos5.c +++ b/arch/arm/cpu/armv7/exynos/clock_init_exynos5.c @@ -24,6 +24,24 @@  DECLARE_GLOBAL_DATA_PTR;  struct arm_clk_ratios arm_clk_ratios[] = { +#ifdef CONFIG_EXYNOS5420 +	{ +		.arm_freq_mhz = 900, + +		.apll_mdiv = 0x96, +		.apll_pdiv = 0x2, +		.apll_sdiv = 0x1, + +		.arm2_ratio = 0x0, +		.apll_ratio = 0x3, +		.pclk_dbg_ratio = 0x6, +		.atb_ratio = 0x6, +		.periph_ratio = 0x7, +		.acp_ratio = 0x0, +		.cpud_ratio = 0x2, +		.arm_ratio = 0x0, +	} +#else  	{  		.arm_freq_mhz = 600, @@ -115,8 +133,133 @@ struct arm_clk_ratios arm_clk_ratios[] = {  		.cpud_ratio = 0x3,  		.arm_ratio = 0x0,  	} +#endif  }; +  struct mem_timings mem_timings[] = { +#ifdef CONFIG_EXYNOS5420 +	{ +		.mem_manuf = MEM_MANUF_SAMSUNG, +		.mem_type = DDR_MODE_DDR3, +		.frequency_mhz = 800, + +		/* MPLL @800MHz*/ +		.mpll_mdiv = 0xc8, +		.mpll_pdiv = 0x3, +		.mpll_sdiv = 0x1, +		/* CPLL @666MHz */ +		.cpll_mdiv = 0xde, +		.cpll_pdiv = 0x4, +		.cpll_sdiv = 0x1, +		/* EPLL @600MHz */ +		.epll_mdiv = 0x64, +		.epll_pdiv = 0x2, +		.epll_sdiv = 0x1, +		/* VPLL @430MHz */ +		.vpll_mdiv = 0xd7, +		.vpll_pdiv = 0x3, +		.vpll_sdiv = 0x2, +		/* BPLL @800MHz */ +		.bpll_mdiv = 0xc8, +		.bpll_pdiv = 0x3, +		.bpll_sdiv = 0x1, +		/* KPLL @600MHz */ +		.kpll_mdiv = 0x190, +		.kpll_pdiv = 0x4, +		.kpll_sdiv = 0x2, +		/* DPLL @600MHz */ +		.dpll_mdiv = 0x190, +		.dpll_pdiv = 0x4, +		.dpll_sdiv = 0x2, +		/* IPLL @370MHz */ +		.ipll_mdiv = 0xb9, +		.ipll_pdiv = 0x3, +		.ipll_sdiv = 0x2, +		/* SPLL @400MHz */ +		.spll_mdiv = 0xc8, +		.spll_pdiv = 0x3, +		.spll_sdiv = 0x2, + +		.direct_cmd_msr = { +			0x00020018, 0x00030000, 0x00010046, 0x00000d70, +			0x00000c70 +		}, +		.timing_ref = 0x000000bb, +		.timing_row = 0x6836650f, +		.timing_data = 0x3630580b, +		.timing_power = 0x41000a26, +		.phy0_dqs = 0x08080808, +		.phy1_dqs = 0x08080808, +		.phy0_dq = 0x08080808, +		.phy1_dq = 0x08080808, +		.phy0_tFS = 0x8, +		.phy1_tFS = 0x8, +		.phy0_pulld_dqs = 0xf, +		.phy1_pulld_dqs = 0xf, + +		.lpddr3_ctrl_phy_reset = 0x1, +		.ctrl_start_point = 0x10, +		.ctrl_inc = 0x10, +		.ctrl_start = 0x1, +		.ctrl_dll_on = 0x1, +		.ctrl_ref = 0x8, + +		.ctrl_force = 0x1a, +		.ctrl_rdlat = 0x0b, +		.ctrl_bstlen = 0x08, + +		.fp_resync = 0x8, +		.iv_size = 0x7, +		.dfi_init_start = 1, +		.aref_en = 1, + +		.rd_fetch = 0x3, + +		.zq_mode_dds = 0x7, +		.zq_mode_term = 0x1, +		.zq_mode_noterm = 1, + +		/* +		* Dynamic Clock: Always Running +		* Memory Burst length: 8 +		* Number of chips: 1 +		* Memory Bus width: 32 bit +		* Memory Type: DDR3 +		* Additional Latancy for PLL: 0 Cycle +		*/ +		.memcontrol = DMC_MEMCONTROL_CLK_STOP_DISABLE | +			DMC_MEMCONTROL_DPWRDN_DISABLE | +			DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE | +			DMC_MEMCONTROL_TP_DISABLE | +			DMC_MEMCONTROL_DSREF_DISABLE | +			DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(0) | +			DMC_MEMCONTROL_MEM_TYPE_DDR3 | +			DMC_MEMCONTROL_MEM_WIDTH_32BIT | +			DMC_MEMCONTROL_NUM_CHIP_1 | +			DMC_MEMCONTROL_BL_8 | +			DMC_MEMCONTROL_PZQ_DISABLE | +			DMC_MEMCONTROL_MRR_BYTE_7_0, +		.memconfig = DMC_MEMCONFIG_CHIP_MAP_SPLIT | +			DMC_MEMCONFIGX_CHIP_COL_10 | +			DMC_MEMCONFIGX_CHIP_ROW_15 | +			DMC_MEMCONFIGX_CHIP_BANK_8, +		.prechconfig_tp_cnt = 0xff, +		.dpwrdn_cyc = 0xff, +		.dsref_cyc = 0xffff, +		.concontrol = DMC_CONCONTROL_DFI_INIT_START_DISABLE | +			DMC_CONCONTROL_TIMEOUT_LEVEL0 | +			DMC_CONCONTROL_RD_FETCH_DISABLE | +			DMC_CONCONTROL_EMPTY_DISABLE | +			DMC_CONCONTROL_AREF_EN_DISABLE | +			DMC_CONCONTROL_IO_PD_CON_DISABLE, +		.dmc_channels = 1, +		.chips_per_channel = 1, +		.chips_to_configure = 1, +		.send_zq_init = 1, +		.gate_leveling_enable = 1, +		.read_leveling_enable = 0, +	} +#else  	{  		.mem_manuf = MEM_MANUF_ELPIDA,  		.mem_type = DDR_MODE_DDR3, @@ -324,6 +467,7 @@ struct mem_timings mem_timings[] = {  		.impedance = IMP_OUTPUT_DRV_40_OHM,  		.gate_leveling_enable = 1,  	} +#endif  };  /** @@ -399,7 +543,7 @@ struct mem_timings *clock_get_mem_timings(void)  	return NULL;  } -void system_clock_init() +static void exynos5250_system_clock_init(void)  {  	struct exynos5_clock *clk =  		(struct exynos5_clock *)samsung_get_base_clock(); @@ -436,19 +580,13 @@ void system_clock_init()  	} while ((val | MUX_BPLL_SEL_MASK) != val);  	/* PLL locktime */ -	writel(APLL_LOCK_VAL, &clk->apll_lock); - -	writel(MPLL_LOCK_VAL, &clk->mpll_lock); - -	writel(BPLL_LOCK_VAL, &clk->bpll_lock); - -	writel(CPLL_LOCK_VAL, &clk->cpll_lock); - -	writel(GPLL_LOCK_VAL, &clk->gpll_lock); - -	writel(EPLL_LOCK_VAL, &clk->epll_lock); - -	writel(VPLL_LOCK_VAL, &clk->vpll_lock); +	writel(mem->apll_pdiv * PLL_LOCK_FACTOR, &clk->apll_lock); +	writel(mem->mpll_pdiv * PLL_LOCK_FACTOR, &clk->mpll_lock); +	writel(mem->bpll_pdiv * PLL_LOCK_FACTOR, &clk->bpll_lock); +	writel(mem->cpll_pdiv * PLL_LOCK_FACTOR, &clk->cpll_lock); +	writel(mem->gpll_pdiv * PLL_X_LOCK_FACTOR, &clk->gpll_lock); +	writel(mem->epll_pdiv * PLL_X_LOCK_FACTOR, &clk->epll_lock); +	writel(mem->vpll_pdiv * PLL_X_LOCK_FACTOR, &clk->vpll_lock);  	writel(CLK_REG_DISABLE, &clk->pll_div2_sel); @@ -640,6 +778,192 @@ void system_clock_init()  	writel(val, &clk->div_fsys2);  } +static void exynos5420_system_clock_init(void) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	struct mem_timings *mem; +	struct arm_clk_ratios *arm_clk_ratio; +	u32 val; + +	mem = clock_get_mem_timings(); +	arm_clk_ratio = get_arm_ratios(); + +	/* PLL locktime */ +	writel(arm_clk_ratio->apll_pdiv * PLL_LOCK_FACTOR, &clk->apll_lock); +	writel(mem->mpll_pdiv * PLL_LOCK_FACTOR, &clk->mpll_lock); +	writel(mem->bpll_pdiv * PLL_LOCK_FACTOR, &clk->bpll_lock); +	writel(mem->cpll_pdiv * PLL_LOCK_FACTOR, &clk->cpll_lock); +	writel(mem->dpll_pdiv * PLL_LOCK_FACTOR, &clk->dpll_lock); +	writel(mem->epll_pdiv * PLL_X_LOCK_FACTOR, &clk->epll_lock); +	writel(mem->vpll_pdiv * PLL_LOCK_FACTOR, &clk->vpll_lock); +	writel(mem->ipll_pdiv * PLL_LOCK_FACTOR, &clk->ipll_lock); +	writel(mem->spll_pdiv * PLL_LOCK_FACTOR, &clk->spll_lock); +	writel(mem->kpll_pdiv * PLL_LOCK_FACTOR, &clk->kpll_lock); + +	setbits_le32(&clk->src_cpu, MUX_HPM_SEL_MASK); + +	writel(0, &clk->src_top6); + +	writel(0, &clk->src_cdrex); +	writel(SRC_KFC_HPM_SEL, &clk->src_kfc); +	writel(HPM_RATIO,  &clk->div_cpu1); +	writel(CLK_DIV_CPU0_VAL,  &clk->div_cpu0); + +	/* switch A15 clock source to OSC clock before changing APLL */ +	clrbits_le32(&clk->src_cpu, APLL_FOUT); + +	/* Set APLL */ +	writel(APLL_CON1_VAL, &clk->apll_con1); +	val = set_pll(arm_clk_ratio->apll_mdiv, +		      arm_clk_ratio->apll_pdiv, +		      arm_clk_ratio->apll_sdiv); +	writel(val, &clk->apll_con0); +	while ((readl(&clk->apll_con0) & PLL_LOCKED) == 0) +		; + +	/* now it is safe to switch to APLL */ +	setbits_le32(&clk->src_cpu, APLL_FOUT); + +	writel(SRC_KFC_HPM_SEL, &clk->src_kfc); +	writel(CLK_DIV_KFC_VAL, &clk->div_kfc0); + +	/* switch A7 clock source to OSC clock before changing KPLL */ +	clrbits_le32(&clk->src_kfc, KPLL_FOUT); + +	/* Set KPLL*/ +	writel(KPLL_CON1_VAL, &clk->kpll_con1); +	val = set_pll(mem->kpll_mdiv, mem->kpll_pdiv, mem->kpll_sdiv); +	writel(val, &clk->kpll_con0); +	while ((readl(&clk->kpll_con0) & PLL_LOCKED) == 0) +		; + +	/* now it is safe to switch to KPLL */ +	setbits_le32(&clk->src_kfc, KPLL_FOUT); + +	/* Set MPLL */ +	writel(MPLL_CON1_VAL, &clk->mpll_con1); +	val = set_pll(mem->mpll_mdiv, mem->mpll_pdiv, mem->mpll_sdiv); +	writel(val, &clk->mpll_con0); +	while ((readl(&clk->mpll_con0) & PLL_LOCKED) == 0) +		; + +	/* Set DPLL */ +	writel(DPLL_CON1_VAL, &clk->dpll_con1); +	val = set_pll(mem->dpll_mdiv, mem->dpll_pdiv, mem->dpll_sdiv); +	writel(val, &clk->dpll_con0); +	while ((readl(&clk->dpll_con0) & PLL_LOCKED) == 0) +		; + +	/* Set EPLL */ +	writel(EPLL_CON2_VAL, &clk->epll_con2); +	writel(EPLL_CON1_VAL, &clk->epll_con1); +	val = set_pll(mem->epll_mdiv, mem->epll_pdiv, mem->epll_sdiv); +	writel(val, &clk->epll_con0); +	while ((readl(&clk->epll_con0) & PLL_LOCKED) == 0) +		; + +	/* Set CPLL */ +	writel(CPLL_CON1_VAL, &clk->cpll_con1); +	val = set_pll(mem->cpll_mdiv, mem->cpll_pdiv, mem->cpll_sdiv); +	writel(val, &clk->cpll_con0); +	while ((readl(&clk->cpll_con0) & PLL_LOCKED) == 0) +		; + +	/* Set IPLL */ +	writel(IPLL_CON1_VAL, &clk->ipll_con1); +	val = set_pll(mem->ipll_mdiv, mem->ipll_pdiv, mem->ipll_sdiv); +	writel(val, &clk->ipll_con0); +	while ((readl(&clk->ipll_con0) & PLL_LOCKED) == 0) +		; + +	/* Set VPLL */ +	writel(VPLL_CON1_VAL, &clk->vpll_con1); +	val = set_pll(mem->vpll_mdiv, mem->vpll_pdiv, mem->vpll_sdiv); +	writel(val, &clk->vpll_con0); +	while ((readl(&clk->vpll_con0) & PLL_LOCKED) == 0) +		; + +	/* Set BPLL */ +	writel(BPLL_CON1_VAL, &clk->bpll_con1); +	val = set_pll(mem->bpll_mdiv, mem->bpll_pdiv, mem->bpll_sdiv); +	writel(val, &clk->bpll_con0); +	while ((readl(&clk->bpll_con0) & PLL_LOCKED) == 0) +		; + +	/* Set SPLL */ +	writel(SPLL_CON1_VAL, &clk->spll_con1); +	val = set_pll(mem->spll_mdiv, mem->spll_pdiv, mem->spll_sdiv); +	writel(val, &clk->spll_con0); +	while ((readl(&clk->spll_con0) & PLL_LOCKED) == 0) +		; + +	writel(CLK_DIV_CDREX0_VAL, &clk->div_cdrex0); +	writel(CLK_DIV_CDREX1_VAL, &clk->div_cdrex1); + +	writel(CLK_SRC_TOP0_VAL, &clk->src_top0); +	writel(CLK_SRC_TOP1_VAL, &clk->src_top1); +	writel(CLK_SRC_TOP2_VAL, &clk->src_top2); +	writel(CLK_SRC_TOP7_VAL, &clk->src_top7); + +	writel(CLK_DIV_TOP0_VAL, &clk->div_top0); +	writel(CLK_DIV_TOP1_VAL, &clk->div_top1); +	writel(CLK_DIV_TOP2_VAL, &clk->div_top2); + +	writel(0, &clk->src_top10); +	writel(0, &clk->src_top11); +	writel(0, &clk->src_top12); + +	writel(CLK_SRC_TOP3_VAL, &clk->src_top3); +	writel(CLK_SRC_TOP4_VAL, &clk->src_top4); +	writel(CLK_SRC_TOP5_VAL, &clk->src_top5); + +	/* DISP1 BLK CLK SELECTION */ +	writel(CLK_SRC_DISP1_0_VAL, &clk->src_disp10); +	writel(CLK_DIV_DISP1_0_VAL, &clk->div_disp10); + +	/* AUDIO BLK */ +	writel(AUDIO0_SEL_EPLL, &clk->src_mau); +	writel(DIV_MAU_VAL, &clk->div_mau); + +	/* FSYS */ +	writel(CLK_SRC_FSYS0_VAL, &clk->src_fsys); +	writel(CLK_DIV_FSYS0_VAL, &clk->div_fsys0); +	writel(CLK_DIV_FSYS1_VAL, &clk->div_fsys1); +	writel(CLK_DIV_FSYS2_VAL, &clk->div_fsys2); + +	writel(CLK_SRC_ISP_VAL, &clk->src_isp); +	writel(CLK_DIV_ISP0_VAL, &clk->div_isp0); +	writel(CLK_DIV_ISP1_VAL, &clk->div_isp1); + +	writel(CLK_SRC_PERIC0_VAL, &clk->src_peric0); +	writel(CLK_SRC_PERIC1_VAL, &clk->src_peric1); + +	writel(CLK_DIV_PERIC0_VAL, &clk->div_peric0); +	writel(CLK_DIV_PERIC1_VAL, &clk->div_peric1); +	writel(CLK_DIV_PERIC2_VAL, &clk->div_peric2); +	writel(CLK_DIV_PERIC3_VAL, &clk->div_peric3); +	writel(CLK_DIV_PERIC4_VAL, &clk->div_peric4); + +	writel(CLK_DIV_CPERI1_VAL, &clk->div_cperi1); + +	writel(CLK_DIV2_RATIO, &clk->clkdiv2_ratio); +	writel(CLK_DIV4_RATIO, &clk->clkdiv4_ratio); +	writel(CLK_DIV_G2D, &clk->div_g2d); + +	writel(CLK_SRC_TOP6_VAL, &clk->src_top6); +	writel(CLK_SRC_CDREX_VAL, &clk->src_cdrex); +	writel(CLK_SRC_KFC_VAL, &clk->src_kfc); +} + +void system_clock_init(void) +{ +	if (proid_is_exynos5420()) +		exynos5420_system_clock_init(); +	else +		exynos5250_system_clock_init(); +} +  void clock_init_dp_clock(void)  {  	struct exynos5_clock *clk = diff --git a/arch/arm/cpu/armv7/exynos/dmc_common.c b/arch/arm/cpu/armv7/exynos/dmc_common.c index 53cfe6edb..cca925e42 100644 --- a/arch/arm/cpu/armv7/exynos/dmc_common.c +++ b/arch/arm/cpu/armv7/exynos/dmc_common.c @@ -1,5 +1,5 @@  /* - * Mem setup common file for different types of DDR present on SMDK5250 boards. + * Mem setup common file for different types of DDR present on Exynos boards.   *   * Copyright (C) 2012 Samsung Electronics   * @@ -15,9 +15,9 @@  #define ZQ_INIT_TIMEOUT	10000 -int dmc_config_zq(struct mem_timings *mem, -		  struct exynos5_phy_control *phy0_ctrl, -		  struct exynos5_phy_control *phy1_ctrl) +int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16, +			uint32_t *phy1_con16, uint32_t *phy0_con17, +			uint32_t *phy1_con17)  {  	unsigned long val = 0;  	int i; @@ -31,19 +31,19 @@ int dmc_config_zq(struct mem_timings *mem,  	val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;  	val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;  	val |= ZQ_CLK_DIV_EN; -	writel(val, &phy0_ctrl->phy_con16); -	writel(val, &phy1_ctrl->phy_con16); +	writel(val, phy0_con16); +	writel(val, phy1_con16);  	/* Disable termination */  	if (mem->zq_mode_noterm)  		val |= PHY_CON16_ZQ_MODE_NOTERM_MASK; -	writel(val, &phy0_ctrl->phy_con16); -	writel(val, &phy1_ctrl->phy_con16); +	writel(val, phy0_con16); +	writel(val, phy1_con16);  	/* ZQ_MANUAL_START: Enable */  	val |= ZQ_MANUAL_STR; -	writel(val, &phy0_ctrl->phy_con16); -	writel(val, &phy1_ctrl->phy_con16); +	writel(val, phy0_con16); +	writel(val, phy1_con16);  	/* ZQ_MANUAL_START: Disable */  	val &= ~ZQ_MANUAL_STR; @@ -53,47 +53,47 @@ int dmc_config_zq(struct mem_timings *mem,  	 * we are looping for the ZQ_init to complete.  	 */  	i = ZQ_INIT_TIMEOUT; -	while ((readl(&phy0_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { +	while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {  		sdelay(100);  		i--;  	}  	if (!i)  		return -1; -	writel(val, &phy0_ctrl->phy_con16); +	writel(val, phy0_con16);  	i = ZQ_INIT_TIMEOUT; -	while ((readl(&phy1_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { +	while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {  		sdelay(100);  		i--;  	}  	if (!i)  		return -1; -	writel(val, &phy1_ctrl->phy_con16); +	writel(val, phy1_con16);  	return 0;  } -void update_reset_dll(struct exynos5_dmc *dmc, enum ddr_mode mode) +void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode)  {  	unsigned long val;  	if (mode == DDR_MODE_DDR3) {  		val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE; -		writel(val, &dmc->phycontrol0); +		writel(val, phycontrol0);  	}  	/* Update DLL Information: Force DLL Resyncronization */ -	val = readl(&dmc->phycontrol0); +	val = readl(phycontrol0);  	val |= FP_RSYNC; -	writel(val, &dmc->phycontrol0); +	writel(val, phycontrol0);  	/* Reset Force DLL Resyncronization */ -	val = readl(&dmc->phycontrol0); +	val = readl(phycontrol0);  	val &= ~FP_RSYNC; -	writel(val, &dmc->phycontrol0); +	writel(val, phycontrol0);  } -void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc) +void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd)  {  	int channel, chip; @@ -107,7 +107,7 @@ void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)  			mask |= chip << DIRECT_CMD_CHIP_SHIFT;  			/* Sending NOP command */ -			writel(DIRECT_CMD_NOP | mask, &dmc->directcmd); +			writel(DIRECT_CMD_NOP | mask, directcmd);  			/*  			 * TODO(alim.akhtar@samsung.com): Do we need these @@ -119,14 +119,14 @@ void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)  			/* Sending EMRS/MRS commands */  			for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {  				writel(mem->direct_cmd_msr[i] | mask, -				       &dmc->directcmd); +				       directcmd);  				sdelay(0x10000);  			}  			if (mem->send_zq_init) {  				/* Sending ZQINIT command */  				writel(DIRECT_CMD_ZQINIT | mask, -				       &dmc->directcmd); +				       directcmd);  				sdelay(10000);  			} @@ -134,7 +134,7 @@ void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)  	}  } -void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc) +void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd)  {  	int channel, chip; @@ -146,20 +146,12 @@ void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc)  			mask |= chip << DIRECT_CMD_CHIP_SHIFT;  			/* PALL (all banks precharge) CMD */ -			writel(DIRECT_CMD_PALL | mask, &dmc->directcmd); +			writel(DIRECT_CMD_PALL | mask, directcmd);  			sdelay(0x10000);  		}  	}  } -void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc) -{ -	writel(mem->memconfig, &dmc->memconfig0); -	writel(mem->memconfig, &dmc->memconfig1); -	writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0); -	writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1); -} -  void mem_ctrl_init(int reset)  {  	struct spl_machine_param *param = spl_get_machine_params(); diff --git a/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c b/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c index 5f5914ede..487e6f423 100644 --- a/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c +++ b/arch/arm/cpu/armv7/exynos/dmc_init_ddr3.c @@ -1,5 +1,5 @@  /* - * DDR3 mem setup file for SMDK5250 board based on EXYNOS5 + * DDR3 mem setup file for board based on EXYNOS5   *   * Copyright (C) 2012 Samsung Electronics   * @@ -11,12 +11,14 @@  #include <asm/arch/clock.h>  #include <asm/arch/cpu.h>  #include <asm/arch/dmc.h> +#include <asm/arch/power.h>  #include "common_setup.h"  #include "exynos5_setup.h"  #include "clock_init.h" -#define RDLVL_COMPLETE_TIMEOUT	10000 +#define TIMEOUT	10000 +#ifdef CONFIG_EXYNOS5250  static void reset_phy_ctrl(void)  {  	struct exynos5_clock *clk = @@ -57,7 +59,8 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  	writel(val, &phy1_ctrl->phy_con42);  	/* ZQ Calibration */ -	if (dmc_config_zq(mem, phy0_ctrl, phy1_ctrl)) +	if (dmc_config_zq(mem, &phy0_ctrl->phy_con16, &phy1_ctrl->phy_con16, +			  &phy0_ctrl->phy_con17, &phy1_ctrl->phy_con17))  		return SETUP_ERR_ZQ_CALIBRATION_FAILURE;  	/* DQ Signal */ @@ -68,7 +71,7 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  		| (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),  		&dmc->concontrol); -	update_reset_dll(dmc, DDR_MODE_DDR3); +	update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);  	/* DQS Signal */  	writel(mem->phy0_dqs, &phy0_ctrl->phy_con4); @@ -93,7 +96,7 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  	writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),  	       &phy1_ctrl->phy_con12); -	update_reset_dll(dmc, DDR_MODE_DDR3); +	update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);  	writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),  	       &dmc->concontrol); @@ -124,10 +127,10 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  	writel(mem->timing_power, &dmc->timingpower);  	/* Send PALL command */ -	dmc_config_prech(mem, dmc); +	dmc_config_prech(mem, &dmc->directcmd);  	/* Send NOP, MRS and ZQINIT commands */ -	dmc_config_mrs(mem, dmc); +	dmc_config_mrs(mem, &dmc->directcmd);  	if (mem->gate_leveling_enable) {  		val = PHY_CON0_RESET_VAL; @@ -174,7 +177,7 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  		writel(val, &phy1_ctrl->phy_con1);  		writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config); -		i = RDLVL_COMPLETE_TIMEOUT; +		i = TIMEOUT;  		while ((readl(&dmc->phystatus) &  			(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=  			(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) { @@ -202,11 +205,11 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  		writel(val, &phy0_ctrl->phy_con12);  		writel(val, &phy1_ctrl->phy_con12); -		update_reset_dll(dmc, DDR_MODE_DDR3); +		update_reset_dll(&dmc->phycontrol0, DDR_MODE_DDR3);  	}  	/* Send PALL command */ -	dmc_config_prech(mem, dmc); +	dmc_config_prech(mem, &dmc->directcmd);  	writel(mem->memcontrol, &dmc->memcontrol); @@ -215,3 +218,419 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  		| (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol);  	return 0;  } +#endif + +#ifdef CONFIG_EXYNOS5420 +int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size, +		       int reset) +{ +	struct exynos5420_clock *clk = +		(struct exynos5420_clock *)samsung_get_base_clock(); +	struct exynos5420_power *power = +		(struct exynos5420_power *)samsung_get_base_power(); +	struct exynos5420_phy_control *phy0_ctrl, *phy1_ctrl; +	struct exynos5420_dmc *drex0, *drex1; +	struct exynos5420_tzasc *tzasc0, *tzasc1; +	uint32_t val, n_lock_r, n_lock_w_phy0, n_lock_w_phy1; +	int chip; +	int i; + +	phy0_ctrl = (struct exynos5420_phy_control *)samsung_get_base_dmc_phy(); +	phy1_ctrl = (struct exynos5420_phy_control *)(samsung_get_base_dmc_phy() +							+ DMC_OFFSET); +	drex0 = (struct exynos5420_dmc *)samsung_get_base_dmc_ctrl(); +	drex1 = (struct exynos5420_dmc *)(samsung_get_base_dmc_ctrl() +							+ DMC_OFFSET); +	tzasc0 = (struct exynos5420_tzasc *)samsung_get_base_dmc_tzasc(); +	tzasc1 = (struct exynos5420_tzasc *)(samsung_get_base_dmc_tzasc() +							+ DMC_OFFSET); + +	/* Enable PAUSE for DREX */ +	setbits_le32(&clk->pause, ENABLE_BIT); + +	/* Enable BYPASS mode */ +	setbits_le32(&clk->bpll_con1, BYPASS_EN); + +	writel(MUX_BPLL_SEL_FOUTBPLL, &clk->src_cdrex); +	do { +		val = readl(&clk->mux_stat_cdrex); +		val &= BPLL_SEL_MASK; +	} while (val != FOUTBPLL); + +	clrbits_le32(&clk->bpll_con1, BYPASS_EN); + +	/* Specify the DDR memory type as DDR3 */ +	val = readl(&phy0_ctrl->phy_con0); +	val &= ~(PHY_CON0_CTRL_DDR_MODE_MASK << PHY_CON0_CTRL_DDR_MODE_SHIFT); +	val |= (DDR_MODE_DDR3 << PHY_CON0_CTRL_DDR_MODE_SHIFT); +	writel(val, &phy0_ctrl->phy_con0); + +	val = readl(&phy1_ctrl->phy_con0); +	val &= ~(PHY_CON0_CTRL_DDR_MODE_MASK << PHY_CON0_CTRL_DDR_MODE_SHIFT); +	val |= (DDR_MODE_DDR3 << PHY_CON0_CTRL_DDR_MODE_SHIFT); +	writel(val, &phy1_ctrl->phy_con0); + +	/* Set Read Latency and Burst Length for PHY0 and PHY1 */ +	val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) | +		(mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT); +	writel(val, &phy0_ctrl->phy_con42); +	writel(val, &phy1_ctrl->phy_con42); + +	val = readl(&phy0_ctrl->phy_con26); +	val &= ~(T_WRDATA_EN_MASK << T_WRDATA_EN_OFFSET); +	val |= (T_WRDATA_EN_DDR3 << T_WRDATA_EN_OFFSET); +	writel(val, &phy0_ctrl->phy_con26); + +	val = readl(&phy1_ctrl->phy_con26); +	val &= ~(T_WRDATA_EN_MASK << T_WRDATA_EN_OFFSET); +	val |= (T_WRDATA_EN_DDR3 << T_WRDATA_EN_OFFSET); +	writel(val, &phy1_ctrl->phy_con26); + +	/* +	 * Set Driver strength for CK, CKE, CS & CA to 0x7 +	 * Set Driver strength for Data Slice 0~3 to 0x7 +	 */ +	val = (0x7 << CA_CK_DRVR_DS_OFFSET) | (0x7 << CA_CKE_DRVR_DS_OFFSET) | +		(0x7 << CA_CS_DRVR_DS_OFFSET) | (0x7 << CA_ADR_DRVR_DS_OFFSET); +	val |= (0x7 << DA_3_DS_OFFSET) | (0x7 << DA_2_DS_OFFSET) | +		(0x7 << DA_1_DS_OFFSET) | (0x7 << DA_0_DS_OFFSET); +	writel(val, &phy0_ctrl->phy_con39); +	writel(val, &phy1_ctrl->phy_con39); + +	/* ZQ Calibration */ +	if (dmc_config_zq(mem, &phy0_ctrl->phy_con16, &phy1_ctrl->phy_con16, +			  &phy0_ctrl->phy_con17, &phy1_ctrl->phy_con17)) +		return SETUP_ERR_ZQ_CALIBRATION_FAILURE; + +	clrbits_le32(&phy0_ctrl->phy_con16, ZQ_CLK_DIV_EN); +	clrbits_le32(&phy1_ctrl->phy_con16, ZQ_CLK_DIV_EN); + +	/* DQ Signal */ +	val = readl(&phy0_ctrl->phy_con14); +	val |= mem->phy0_pulld_dqs; +	writel(val, &phy0_ctrl->phy_con14); +	val = readl(&phy1_ctrl->phy_con14); +	val |= mem->phy1_pulld_dqs; +	writel(val, &phy1_ctrl->phy_con14); + +	val = MEM_TERM_EN | PHY_TERM_EN; +	writel(val, &drex0->phycontrol0); +	writel(val, &drex1->phycontrol0); + +	writel(mem->concontrol | +		(mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT) | +		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT), +		&drex0->concontrol); +	writel(mem->concontrol | +		(mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT) | +		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT), +		&drex1->concontrol); + +	do { +		val = readl(&drex0->phystatus); +	} while ((val & DFI_INIT_COMPLETE) != DFI_INIT_COMPLETE); +	do { +		val = readl(&drex1->phystatus); +	} while ((val & DFI_INIT_COMPLETE) != DFI_INIT_COMPLETE); + +	clrbits_le32(&drex0->concontrol, DFI_INIT_START); +	clrbits_le32(&drex1->concontrol, DFI_INIT_START); + +	update_reset_dll(&drex0->phycontrol0, DDR_MODE_DDR3); +	update_reset_dll(&drex1->phycontrol0, DDR_MODE_DDR3); + +	/* +	 * Set Base Address: +	 * 0x2000_0000 ~ 0x5FFF_FFFF +	 * 0x6000_0000 ~ 0x9FFF_FFFF +	 */ +	/* MEMBASECONFIG0 */ +	val = DMC_MEMBASECONFIGX_CHIP_BASE(DMC_CHIP_BASE_0) | +		DMC_MEMBASECONFIGX_CHIP_MASK(DMC_CHIP_MASK); +	writel(val, &tzasc0->membaseconfig0); +	writel(val, &tzasc1->membaseconfig0); + +	/* MEMBASECONFIG1 */ +	val = DMC_MEMBASECONFIGX_CHIP_BASE(DMC_CHIP_BASE_1) | +		DMC_MEMBASECONFIGX_CHIP_MASK(DMC_CHIP_MASK); +	writel(val, &tzasc0->membaseconfig1); +	writel(val, &tzasc1->membaseconfig1); + +	/* +	 * Memory Channel Inteleaving Size +	 * Ares Channel interleaving = 128 bytes +	 */ +	/* MEMCONFIG0/1 */ +	writel(mem->memconfig, &tzasc0->memconfig0); +	writel(mem->memconfig, &tzasc1->memconfig0); +	writel(mem->memconfig, &tzasc0->memconfig1); +	writel(mem->memconfig, &tzasc1->memconfig1); + +	/* Precharge Configuration */ +	writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT, +	       &drex0->prechconfig0); +	writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT, +	       &drex1->prechconfig0); + +	/* +	 * TimingRow, TimingData, TimingPower and Timingaref +	 * values as per Memory AC parameters +	 */ +	writel(mem->timing_ref, &drex0->timingref); +	writel(mem->timing_ref, &drex1->timingref); +	writel(mem->timing_row, &drex0->timingrow0); +	writel(mem->timing_row, &drex1->timingrow0); +	writel(mem->timing_data, &drex0->timingdata0); +	writel(mem->timing_data, &drex1->timingdata0); +	writel(mem->timing_power, &drex0->timingpower0); +	writel(mem->timing_power, &drex1->timingpower0); + +	if (reset) { +		/* +		 * Send NOP, MRS and ZQINIT commands +		 * Sending MRS command will reset the DRAM. We should not be +		 * reseting the DRAM after resume, this will lead to memory +		 * corruption as DRAM content is lost after DRAM reset +		 */ +		dmc_config_mrs(mem, &drex0->directcmd); +		dmc_config_mrs(mem, &drex1->directcmd); +	} else { +		/* +		 * During Suspend-Resume & S/W-Reset, as soon as PMU releases +		 * pad retention, CKE goes high. This causes memory contents +		 * not to be retained during DRAM initialization. Therfore, +		 * there is a new control register(0x100431e8[28]) which lets us +		 * release pad retention and retain the memory content until the +		 * initialization is complete. +		 */ +		writel(PAD_RETENTION_DRAM_COREBLK_VAL, +		       &power->pad_retention_dram_coreblk_option); +		do { +			val = readl(&power->pad_retention_dram_status); +		} while (val != 0x1); + +		/* +		 * CKE PAD retention disables DRAM self-refresh mode. +		 * Send auto refresh command for DRAM refresh. +		 */ +		for (i = 0; i < 128; i++) { +			for (chip = 0; chip < mem->chips_to_configure; chip++) { +				writel(DIRECT_CMD_REFA | +				       (chip << DIRECT_CMD_CHIP_SHIFT), +				       &drex0->directcmd); +				writel(DIRECT_CMD_REFA | +				       (chip << DIRECT_CMD_CHIP_SHIFT), +				       &drex1->directcmd); +			} +		} +	} + +	if (mem->gate_leveling_enable) { +		writel(PHY_CON0_RESET_VAL, &phy0_ctrl->phy_con0); +		writel(PHY_CON0_RESET_VAL, &phy1_ctrl->phy_con0); + +		setbits_le32(&phy0_ctrl->phy_con0, P0_CMD_EN); +		setbits_le32(&phy1_ctrl->phy_con0, P0_CMD_EN); + +		val = PHY_CON2_RESET_VAL; +		val |= INIT_DESKEW_EN; +		writel(val, &phy0_ctrl->phy_con2); +		writel(val, &phy1_ctrl->phy_con2); + +		val =  readl(&phy0_ctrl->phy_con1); +		val |= (RDLVL_PASS_ADJ_VAL << RDLVL_PASS_ADJ_OFFSET); +		writel(val, &phy0_ctrl->phy_con1); + +		val =  readl(&phy1_ctrl->phy_con1); +		val |= (RDLVL_PASS_ADJ_VAL << RDLVL_PASS_ADJ_OFFSET); +		writel(val, &phy1_ctrl->phy_con1); + +		n_lock_r = readl(&phy0_ctrl->phy_con13); +		n_lock_w_phy0 = (n_lock_r & CTRL_LOCK_COARSE_MASK) >> 2; +		n_lock_r = readl(&phy0_ctrl->phy_con12); +		n_lock_r &= ~CTRL_DLL_ON; +		n_lock_r |= n_lock_w_phy0; +		writel(n_lock_r, &phy0_ctrl->phy_con12); + +		n_lock_r = readl(&phy1_ctrl->phy_con13); +		n_lock_w_phy1 = (n_lock_r & CTRL_LOCK_COARSE_MASK) >> 2; +		n_lock_r = readl(&phy1_ctrl->phy_con12); +		n_lock_r &= ~CTRL_DLL_ON; +		n_lock_r |= n_lock_w_phy1; +		writel(n_lock_r, &phy1_ctrl->phy_con12); + +		val = (0x3 << DIRECT_CMD_BANK_SHIFT) | 0x4; +		for (chip = 0; chip < mem->chips_to_configure; chip++) { +			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +			       &drex0->directcmd); +			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +			       &drex1->directcmd); +		} + +		setbits_le32(&phy0_ctrl->phy_con2, RDLVL_GATE_EN); +		setbits_le32(&phy1_ctrl->phy_con2, RDLVL_GATE_EN); + +		setbits_le32(&phy0_ctrl->phy_con0, CTRL_SHGATE); +		setbits_le32(&phy1_ctrl->phy_con0, CTRL_SHGATE); + +		val = readl(&phy0_ctrl->phy_con1); +		val &= ~(CTRL_GATEDURADJ_MASK); +		writel(val, &phy0_ctrl->phy_con1); + +		val = readl(&phy1_ctrl->phy_con1); +		val &= ~(CTRL_GATEDURADJ_MASK); +		writel(val, &phy1_ctrl->phy_con1); + +		writel(CTRL_RDLVL_GATE_ENABLE, &drex0->rdlvl_config); +		i = TIMEOUT; +		while (((readl(&drex0->phystatus) & RDLVL_COMPLETE_CHO) != +			RDLVL_COMPLETE_CHO) && (i > 0)) { +			/* +			 * TODO(waihong): Comment on how long this take to +			 * timeout +			 */ +			sdelay(100); +			i--; +		} +		if (!i) +			return SETUP_ERR_RDLV_COMPLETE_TIMEOUT; +		writel(CTRL_RDLVL_GATE_DISABLE, &drex0->rdlvl_config); + +		writel(CTRL_RDLVL_GATE_ENABLE, &drex1->rdlvl_config); +		i = TIMEOUT; +		while (((readl(&drex1->phystatus) & RDLVL_COMPLETE_CHO) != +			RDLVL_COMPLETE_CHO) && (i > 0)) { +			/* +			 * TODO(waihong): Comment on how long this take to +			 * timeout +			 */ +			sdelay(100); +			i--; +		} +		if (!i) +			return SETUP_ERR_RDLV_COMPLETE_TIMEOUT; +		writel(CTRL_RDLVL_GATE_DISABLE, &drex1->rdlvl_config); + +		writel(0, &phy0_ctrl->phy_con14); +		writel(0, &phy1_ctrl->phy_con14); + +		val = (0x3 << DIRECT_CMD_BANK_SHIFT); +		for (chip = 0; chip < mem->chips_to_configure; chip++) { +			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +			       &drex0->directcmd); +			writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +			       &drex1->directcmd); +		} + +		if (mem->read_leveling_enable) { +			/* Set Read DQ Calibration */ +			val = (0x3 << DIRECT_CMD_BANK_SHIFT) | 0x4; +			for (chip = 0; chip < mem->chips_to_configure; chip++) { +				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +				       &drex0->directcmd); +				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +				       &drex1->directcmd); +			} + +			val = readl(&phy0_ctrl->phy_con1); +			val |= READ_LEVELLING_DDR3; +			writel(val, &phy0_ctrl->phy_con1); +			val = readl(&phy1_ctrl->phy_con1); +			val |= READ_LEVELLING_DDR3; +			writel(val, &phy1_ctrl->phy_con1); + +			val = readl(&phy0_ctrl->phy_con2); +			val |= (RDLVL_EN | RDLVL_INCR_ADJ); +			writel(val, &phy0_ctrl->phy_con2); +			val = readl(&phy1_ctrl->phy_con2); +			val |= (RDLVL_EN | RDLVL_INCR_ADJ); +			writel(val, &phy1_ctrl->phy_con2); + +			setbits_le32(&drex0->rdlvl_config, +				     CTRL_RDLVL_DATA_ENABLE); +			i = TIMEOUT; +			while (((readl(&drex0->phystatus) & RDLVL_COMPLETE_CHO) +				 != RDLVL_COMPLETE_CHO) && (i > 0)) { +				/* +				 * TODO(waihong): Comment on how long this take +				 * to timeout +				 */ +				sdelay(100); +				i--; +			} +			if (!i) +				return SETUP_ERR_RDLV_COMPLETE_TIMEOUT; + +			clrbits_le32(&drex0->rdlvl_config, +				     CTRL_RDLVL_DATA_ENABLE); +			setbits_le32(&drex1->rdlvl_config, +				     CTRL_RDLVL_DATA_ENABLE); +			i = TIMEOUT; +			while (((readl(&drex1->phystatus) & RDLVL_COMPLETE_CHO) +				 != RDLVL_COMPLETE_CHO) && (i > 0)) { +				/* +				 * TODO(waihong): Comment on how long this take +				 * to timeout +				 */ +				sdelay(100); +				i--; +			} +			if (!i) +				return SETUP_ERR_RDLV_COMPLETE_TIMEOUT; + +			clrbits_le32(&drex1->rdlvl_config, +				     CTRL_RDLVL_DATA_ENABLE); + +			val = (0x3 << DIRECT_CMD_BANK_SHIFT); +			for (chip = 0; chip < mem->chips_to_configure; chip++) { +				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +				       &drex0->directcmd); +				writel(val | (chip << DIRECT_CMD_CHIP_SHIFT), +				       &drex1->directcmd); +			} + +			update_reset_dll(&drex0->phycontrol0, DDR_MODE_DDR3); +			update_reset_dll(&drex1->phycontrol0, DDR_MODE_DDR3); +		} + +		/* Common Settings for Leveling */ +		val = PHY_CON12_RESET_VAL; +		writel((val + n_lock_w_phy0), &phy0_ctrl->phy_con12); +		writel((val + n_lock_w_phy1), &phy1_ctrl->phy_con12); + +		setbits_le32(&phy0_ctrl->phy_con2, DLL_DESKEW_EN); +		setbits_le32(&phy1_ctrl->phy_con2, DLL_DESKEW_EN); +	} + +	/* Send PALL command */ +	dmc_config_prech(mem, &drex0->directcmd); +	dmc_config_prech(mem, &drex1->directcmd); + +	writel(mem->memcontrol, &drex0->memcontrol); +	writel(mem->memcontrol, &drex1->memcontrol); + +	/* +	 * Set DMC Concontrol: Enable auto-refresh counter, provide +	 * read data fetch cycles and enable DREX auto set powerdown +	 * for input buffer of I/O in none read memory state. +	 */ +	writel(mem->concontrol | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT) | +		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)| +		DMC_CONCONTROL_IO_PD_CON(0x2), +		&drex0->concontrol); +	writel(mem->concontrol | (mem->aref_en << CONCONTROL_AREF_EN_SHIFT) | +		(mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)| +		DMC_CONCONTROL_IO_PD_CON(0x2), +		&drex1->concontrol); + +	/* +	 * Enable Clock Gating Control for DMC +	 * this saves around 25 mw dmc power as compared to the power +	 * consumption without these bits enabled +	 */ +	setbits_le32(&drex0->cgcontrol, DMC_INTERNAL_CG); +	setbits_le32(&drex1->cgcontrol, DMC_INTERNAL_CG); + +	return 0; +} +#endif diff --git a/arch/arm/cpu/armv7/exynos/exynos5_setup.h b/arch/arm/cpu/armv7/exynos/exynos5_setup.h index 696b38675..53b0ace6e 100644 --- a/arch/arm/cpu/armv7/exynos/exynos5_setup.h +++ b/arch/arm/cpu/armv7/exynos/exynos5_setup.h @@ -12,42 +12,16 @@  #include <config.h>  #include <asm/arch/dmc.h> -/* APLL_CON1	*/ -#define APLL_CON1_VAL	(0x00203800) - -/* MPLL_CON1	*/ -#define MPLL_CON1_VAL   (0x00203800) - -/* CPLL_CON1	*/ -#define CPLL_CON1_VAL	(0x00203800) - -/* GPLL_CON1	*/ -#define GPLL_CON1_VAL	(0x00203800) - -/* EPLL_CON1, CON2	*/ -#define EPLL_CON1_VAL	0x00000000 -#define EPLL_CON2_VAL	0x00000080 - -/* VPLL_CON1, CON2	*/ -#define VPLL_CON1_VAL	0x00000000 -#define VPLL_CON2_VAL	0x00000080 +#define NOT_AVAILABLE		0 +#define DATA_MASK		0xFFFFF -/* BPLL_CON1	*/ -#define BPLL_CON1_VAL	0x00203800 +#define ENABLE_BIT		0x1 +#define DISABLE_BIT		0x0 +#define CA_SWAP_EN		(1 << 0)  /* Set PLL */  #define set_pll(mdiv, pdiv, sdiv)	(1<<31 | mdiv<<16 | pdiv<<8 | sdiv) -/* CLK_SRC_CPU	*/ -/* 0 = MOUTAPLL,  1 = SCLKMPLL	*/ -#define MUX_HPM_SEL             0 -#define MUX_CPU_SEL             0 -#define MUX_APLL_SEL            1 - -#define CLK_SRC_CPU_VAL		((MUX_HPM_SEL << 20)    \ -				| (MUX_CPU_SEL << 16)  \ -				| (MUX_APLL_SEL)) -  /* MEMCONTROL register bit fields */  #define DMC_MEMCONTROL_CLK_STOP_DISABLE	(0 << 0)  #define DMC_MEMCONTROL_DPWRDN_DISABLE	(0 << 1) @@ -78,6 +52,7 @@  /* MEMCONFIG0 register bit fields */  #define DMC_MEMCONFIGX_CHIP_MAP_INTERLEAVED     (1 << 12) +#define DMC_MEMCONFIG_CHIP_MAP_SPLIT		(2 << 12)  #define DMC_MEMCONFIGX_CHIP_COL_10              (3 << 8)  #define DMC_MEMCONFIGX_CHIP_ROW_14              (2 << 4)  #define DMC_MEMCONFIGX_CHIP_ROW_15              (3 << 4) @@ -90,6 +65,17 @@  	DMC_MEMBASECONFIGX_CHIP_MASK(0x780)     \  ) +/* + * As we use channel interleaving, therefore value of the base address + * register must be set as half of the bus base address + * RAM start addess is 0x2000_0000 which means chip_base is 0x20, so + * we need to set half 0x10 to the membaseconfigx registers + * see exynos5420 UM section 17.17.3.21 for more. + */ +#define DMC_CHIP_BASE_0 0x10 +#define DMC_CHIP_BASE_1 0x50 +#define DMC_CHIP_MASK	0x7C0 +  #define DMC_MEMBASECONFIG0_VAL  DMC_MEMBASECONFIG_VAL(0x40)  #define DMC_MEMBASECONFIG1_VAL  DMC_MEMBASECONFIG_VAL(0x80) @@ -113,29 +99,24 @@  /* COJCONTROL register bit fields */  #define DMC_CONCONTROL_IO_PD_CON_DISABLE	(0 << 3) +#define DMC_CONCONTROL_IO_PD_CON_ENABLE		(1 << 3)  #define DMC_CONCONTROL_AREF_EN_DISABLE		(0 << 5) +#define DMC_CONCONTROL_AREF_EN_ENABLE		(1 << 5)  #define DMC_CONCONTROL_EMPTY_DISABLE		(0 << 8)  #define DMC_CONCONTROL_EMPTY_ENABLE		(1 << 8)  #define DMC_CONCONTROL_RD_FETCH_DISABLE		(0x0 << 12)  #define DMC_CONCONTROL_TIMEOUT_LEVEL0		(0xFFF << 16)  #define DMC_CONCONTROL_DFI_INIT_START_DISABLE	(0 << 28) -/* CLK_DIV_CPU0_VAL */ -#define CLK_DIV_CPU0_VAL	((ARM2_RATIO << 28)             \ -				| (APLL_RATIO << 24)            \ -				| (PCLK_DBG_RATIO << 20)        \ -				| (ATB_RATIO << 16)             \ -				| (PERIPH_RATIO << 12)          \ -				| (ACP_RATIO << 8)              \ -				| (CPUD_RATIO << 4)             \ -				| (ARM_RATIO)) +#define DMC_CONCONTROL_VAL	0x1FFF2101 +#define DREX_CONCONTROL_VAL	DMC_CONCONTROL_VAL			\ +				| DMC_CONCONTROL_AREF_EN_ENABLE		\ +				| DMC_CONCONTROL_IO_PD_CON_ENABLE -/* CLK_FSYS */ -#define CLK_SRC_FSYS0_VAL              0x66666 -#define CLK_DIV_FSYS0_VAL	       0x0BB00000 +#define DMC_CONCONTROL_IO_PD_CON(x)		(x << 6) -/* CLK_DIV_CPU1	*/ +/* CLK_DIV_CPU1 */  #define HPM_RATIO               0x2  #define COPY_RATIO              0x0 @@ -164,10 +145,367 @@  /* CLK_DIV_SYSLFT */  #define CLK_DIV_SYSLFT_VAL      0x00000311 +#define MUX_APLL_SEL_MASK	(1 << 0) +#define MUX_MPLL_SEL_MASK	(1 << 8) +#define MPLL_SEL_MOUT_MPLLFOUT	(2 << 8) +#define MUX_CPLL_SEL_MASK	(1 << 8) +#define MUX_EPLL_SEL_MASK	(1 << 12) +#define MUX_VPLL_SEL_MASK	(1 << 16) +#define MUX_GPLL_SEL_MASK	(1 << 28) +#define MUX_BPLL_SEL_MASK	(1 << 0) +#define MUX_HPM_SEL_MASK	(1 << 20) +#define HPM_SEL_SCLK_MPLL	(1 << 21) +#define PLL_LOCKED		(1 << 29) +#define APLL_CON0_LOCKED	(1 << 29) +#define MPLL_CON0_LOCKED	(1 << 29) +#define BPLL_CON0_LOCKED	(1 << 29) +#define CPLL_CON0_LOCKED	(1 << 29) +#define EPLL_CON0_LOCKED	(1 << 29) +#define GPLL_CON0_LOCKED	(1 << 29) +#define VPLL_CON0_LOCKED	(1 << 29) +#define CLK_REG_DISABLE		0x0 +#define TOP2_VAL		0x0110000 + +/* SCLK_SRC_ISP - set SPI0/1 to 6 = SCLK_MPLL_USER */ +#define SPI0_ISP_SEL		6 +#define SPI1_ISP_SEL		6 +#define SCLK_SRC_ISP_VAL	(SPI1_ISP_SEL << 4) \ +				| (SPI0_ISP_SEL << 0) + +/* SCLK_DIV_ISP - set SPI0/1 to 0xf = divide by 16 */ +#define SPI0_ISP_RATIO		0xf +#define SPI1_ISP_RATIO		0xf +#define SCLK_DIV_ISP_VAL	(SPI1_ISP_RATIO << 12) \ +				| (SPI0_ISP_RATIO << 0) + +/* CLK_DIV_FSYS2 */ +#define MMC2_RATIO_MASK		0xf +#define MMC2_RATIO_VAL		0x3 +#define MMC2_RATIO_OFFSET	0 + +#define MMC2_PRE_RATIO_MASK	0xff +#define MMC2_PRE_RATIO_VAL	0x9 +#define MMC2_PRE_RATIO_OFFSET	8 + +#define MMC3_RATIO_MASK		0xf +#define MMC3_RATIO_VAL		0x1 +#define MMC3_RATIO_OFFSET	16 + +#define MMC3_PRE_RATIO_MASK	0xff +#define MMC3_PRE_RATIO_VAL	0x0 +#define MMC3_PRE_RATIO_OFFSET	24 + +/* CLK_SRC_LEX */ +#define CLK_SRC_LEX_VAL         0x0 + +/* CLK_DIV_LEX */ +#define CLK_DIV_LEX_VAL         0x10 + +/* CLK_DIV_R0X */ +#define CLK_DIV_R0X_VAL         0x10 + +/* CLK_DIV_L0X */ +#define CLK_DIV_R1X_VAL         0x10 + +/* CLK_DIV_ISP2 */ +#define CLK_DIV_ISP2_VAL        0x1 + +/* CLK_SRC_KFC */ +#define SRC_KFC_HPM_SEL		(1 << 15) + +/* CLK_SRC_KFC */ +#define CLK_SRC_KFC_VAL		0x00008001 + +/* CLK_DIV_KFC */ +#define CLK_DIV_KFC_VAL		0x03300110 + +/* CLK_DIV2_RATIO */ +#define CLK_DIV2_RATIO		0x10111150 + +/* CLK_DIV4_RATIO */ +#define CLK_DIV4_RATIO		0x00000003 + +/* CLK_DIV_G2D */ +#define CLK_DIV_G2D		0x00000010 + +/* + * DIV_DISP1_0 + * For DP, divisor should be 2 + */ +#define CLK_DIV_DISP1_0_FIMD1	(2 << 0) + +/* CLK_GATE_IP_DISP1 */ +#define CLK_GATE_DP1_ALLOW	(1 << 4) + +/* AUDIO CLK SEL */ +#define AUDIO0_SEL_EPLL		(0x6 << 28) +#define AUDIO0_RATIO		0x5 +#define PCM0_RATIO		0x3 +#define DIV_MAU_VAL		(PCM0_RATIO << 24 | AUDIO0_RATIO << 20) + +/* CLK_SRC_CDREX */ +#define MUX_MCLK_CDR_MSPLL	(1 << 4) +#define MUX_BPLL_SEL_FOUTBPLL   (1 << 0) +#define BPLL_SEL_MASK   0x7 +#define FOUTBPLL        2 + +#define DDR3PHY_CTRL_PHY_RESET	(1 << 0) +#define DDR3PHY_CTRL_PHY_RESET_OFF	(0 << 0) + +#define PHY_CON0_RESET_VAL	0x17020a40 +#define P0_CMD_EN		(1 << 14) +#define BYTE_RDLVL_EN		(1 << 13) +#define CTRL_SHGATE		(1 << 8) + +#define PHY_CON1_RESET_VAL	0x09210100 +#define RDLVL_PASS_ADJ_VAL	0x6 +#define RDLVL_PASS_ADJ_OFFSET	16 +#define CTRL_GATEDURADJ_MASK	(0xf << 20) +#define READ_LEVELLING_DDR3	0x0100 + +#define PHY_CON2_RESET_VAL	0x00010004 +#define INIT_DESKEW_EN		(1 << 6) +#define DLL_DESKEW_EN		(1 << 12) +#define RDLVL_GATE_EN		(1 << 24) +#define RDLVL_EN		(1 << 25) +#define RDLVL_INCR_ADJ		(0x1 << 16) + +/* DREX_PAUSE */ +#define DREX_PAUSE_EN	(1 << 0) + +#define BYPASS_EN	(1 << 22) + +/* MEMMORY VAL */ +#define PHY_CON0_VAL	0x17021A00 + +#define PHY_CON12_RESET_VAL	0x10100070 +#define PHY_CON12_VAL		0x10107F50 +#define CTRL_START		(1 << 6) +#define CTRL_DLL_ON		(1 << 5) +#define CTRL_FORCE_MASK		(0x7F << 8) +#define CTRL_LOCK_COARSE_MASK	(0x7F << 10) + +#define CTRL_OFFSETD_RESET_VAL	0x8 +#define CTRL_OFFSETD_VAL	0x7F + +#define CTRL_OFFSETR0		0x7F +#define CTRL_OFFSETR1		0x7F +#define CTRL_OFFSETR2		0x7F +#define CTRL_OFFSETR3		0x7F +#define PHY_CON4_VAL	(CTRL_OFFSETR0 << 0 | \ +				CTRL_OFFSETR1 << 8 | \ +				CTRL_OFFSETR2 << 16 | \ +				CTRL_OFFSETR3 << 24) +#define PHY_CON4_RESET_VAL	0x08080808 + +#define CTRL_OFFSETW0		0x7F +#define CTRL_OFFSETW1		0x7F +#define CTRL_OFFSETW2		0x7F +#define CTRL_OFFSETW3		0x7F +#define PHY_CON6_VAL	(CTRL_OFFSETW0 << 0 | \ +				CTRL_OFFSETW1 << 8 | \ +				CTRL_OFFSETW2 << 16 | \ +				CTRL_OFFSETW3 << 24) +#define PHY_CON6_RESET_VAL	0x08080808 + +#define PHY_CON14_RESET_VAL	0x001F0000 +#define CTRL_PULLD_DQS		0xF +#define CTRL_PULLD_DQS_OFFSET	0 + +/* ZQ Configurations */ +#define PHY_CON16_RESET_VAL	0x08000304 + +#define ZQ_CLK_EN		(1 << 27) +#define ZQ_CLK_DIV_EN		(1 << 18) +#define ZQ_MANUAL_STR		(1 << 1) +#define ZQ_DONE			(1 << 0) +#define ZQ_MODE_DDS_OFFSET	24 + +#define CTRL_RDLVL_GATE_ENABLE	1 +#define CTRL_RDLVL_GATE_DISABLE	0 +#define CTRL_RDLVL_DATA_ENABLE	2 + +/* Direct Command */ +#define DIRECT_CMD_NOP			0x07000000 +#define DIRECT_CMD_PALL			0x01000000 +#define DIRECT_CMD_ZQINIT		0x0a000000 +#define DIRECT_CMD_CHANNEL_SHIFT	28 +#define DIRECT_CMD_CHIP_SHIFT		20 +#define DIRECT_CMD_BANK_SHIFT		16 +#define DIRECT_CMD_REFA		(5 << 24) +#define DIRECT_CMD_MRS1		0x71C00 +#define DIRECT_CMD_MRS2		0x10BFC +#define DIRECT_CMD_MRS3		0x0050C +#define DIRECT_CMD_MRS4		0x00868 +#define DIRECT_CMD_MRS5		0x00C04 + +/* Drive Strength */ +#define IMPEDANCE_48_OHM	4 +#define IMPEDANCE_40_OHM	5 +#define IMPEDANCE_34_OHM	6 +#define IMPEDANCE_30_OHM	7 +#define PHY_CON39_VAL_48_OHM	0x09240924 +#define PHY_CON39_VAL_40_OHM	0x0B6D0B6D +#define PHY_CON39_VAL_34_OHM	0x0DB60DB6 +#define PHY_CON39_VAL_30_OHM	0x0FFF0FFF + +#define CTRL_BSTLEN_OFFSET	8 +#define CTRL_RDLAT_OFFSET	0 + +#define CMD_DEFAULT_LPDDR3	0xF +#define CMD_DEFUALT_OFFSET	0 +#define T_WRDATA_EN		0x7 +#define T_WRDATA_EN_DDR3	0x8 +#define T_WRDATA_EN_OFFSET	16 +#define T_WRDATA_EN_MASK	0x1f + +#define PHY_CON31_VAL	0x0C183060 +#define PHY_CON32_VAL	0x60C18306 +#define PHY_CON33_VAL	0x00000030 + +#define PHY_CON31_RESET_VAL	0x0 +#define PHY_CON32_RESET_VAL	0x0 +#define PHY_CON33_RESET_VAL	0x0 + +#define SL_DLL_DYN_CON_EN	(1 << 1) +#define FP_RESYNC	(1 << 3) +#define CTRL_START	(1 << 6) + +#define DMC_AREF_EN		(1 << 5) +#define DMC_CONCONTROL_EMPTY	(1 << 8) +#define DFI_INIT_START		(1 << 28) + +#define DMC_MEMCONTROL_VAL	0x00312700 +#define CLK_STOP_EN		(1 << 0) +#define DPWRDN_EN		(1 << 1) +#define DSREF_EN		(1 << 5) + +#define MEMBASECONFIG_CHIP_MASK_VAL	0x7E0 +#define MEMBASECONFIG_CHIP_MASK_OFFSET	0 +#define MEMBASECONFIG0_CHIP_BASE_VAL	0x20 +#define MEMBASECONFIG1_CHIP_BASE_VAL	0x40 +#define CHIP_BASE_OFFSET		16 + +#define MEMCONFIG_VAL	0x1323 +#define PRECHCONFIG_DEFAULT_VAL	0xFF000000 +#define PWRDNCONFIG_DEFAULT_VAL	0xFFFF00FF + +#define TIMINGAREF_VAL	0x5d +#define TIMINGROW_VAL	0x345A8692 +#define TIMINGDATA_VAL	0x3630065C +#define TIMINGPOWER_VAL	0x50380336 +#define DFI_INIT_COMPLETE	(1 << 3) + +#define BRBRSVCONTROL_VAL	0x00000033 +#define BRBRSVCONFIG_VAL	0x88778877 + +/* Clock Gating Control (CGCONTROL) register */ +#define MEMIF_CG_EN	(1 << 3) /* Memory interface clock gating */ +#define SCG_CG_EN	(1 << 2) /* Scheduler clock gating */ +#define BUSIF_WR_CG_EN	(1 << 1) /* Bus interface write channel clock gating */ +#define BUSIF_RD_CG_EN	(1 << 0) /* Bus interface read channel clock gating */ +#define DMC_INTERNAL_CG	(MEMIF_CG_EN | SCG_CG_EN | \ +				 BUSIF_WR_CG_EN | BUSIF_RD_CG_EN) + +/* DMC PHY Control0 register */ +#define PHY_CONTROL0_RESET_VAL	0x0 +#define MEM_TERM_EN	(1 << 31)	/* Termination enable for memory */ +#define PHY_TERM_EN	(1 << 30)	/* Termination enable for PHY */ +#define DMC_CTRL_SHGATE	(1 << 29)	/* Duration of DQS gating signal */ +#define FP_RSYNC	(1 << 3)	/* Force DLL resyncronization */ + +/* Driver strength for CK, CKE, CS & CA */ +#define IMP_OUTPUT_DRV_40_OHM	0x5 +#define IMP_OUTPUT_DRV_30_OHM	0x7 +#define DA_3_DS_OFFSET		25 +#define DA_2_DS_OFFSET		22 +#define DA_1_DS_OFFSET		19 +#define DA_0_DS_OFFSET		16 +#define CA_CK_DRVR_DS_OFFSET	9 +#define CA_CKE_DRVR_DS_OFFSET	6 +#define CA_CS_DRVR_DS_OFFSET	3 +#define CA_ADR_DRVR_DS_OFFSET	0 + +#define PHY_CON42_CTRL_BSTLEN_SHIFT	8 +#define PHY_CON42_CTRL_RDLAT_SHIFT	0 + +/* + * Definitions that differ with SoC's. + * Below is the part defining macros for smdk5250. + * Else part introduces macros for smdk5420. + */ +#ifndef CONFIG_SMDK5420 + +/* APLL_CON1 */ +#define APLL_CON1_VAL	(0x00203800) + +/* MPLL_CON1 */ +#define MPLL_CON1_VAL   (0x00203800) + +/* CPLL_CON1 */ +#define CPLL_CON1_VAL	(0x00203800) + +/* DPLL_CON1 */ +#define DPLL_CON1_VAL	(NOT_AVAILABLE) + +/* GPLL_CON1 */ +#define GPLL_CON1_VAL	(0x00203800) + +/* EPLL_CON1, CON2 */ +#define EPLL_CON1_VAL	0x00000000 +#define EPLL_CON2_VAL	0x00000080 + +/* VPLL_CON1, CON2 */ +#define VPLL_CON1_VAL	0x00000000 +#define VPLL_CON2_VAL	0x00000080 + +/* RPLL_CON1, CON2 */ +#define RPLL_CON1_VAL	NOT_AVAILABLE +#define RPLL_CON2_VAL	NOT_AVAILABLE + +/* BPLL_CON1 */ +#define BPLL_CON1_VAL	0x00203800 + +/* SPLL_CON1 */ +#define SPLL_CON1_VAL	NOT_AVAILABLE + +/* IPLL_CON1 */ +#define IPLL_CON1_VAL	NOT_AVAILABLE + +/* KPLL_CON1 */ +#define KPLL_CON1_VAL	NOT_AVAILABLE + +/* CLK_SRC_ISP */ +#define CLK_SRC_ISP_VAL		NOT_AVAILABLE +#define CLK_DIV_ISP0_VAL	0x31 +#define CLK_DIV_ISP1_VAL	0x0 + +/* CLK_FSYS */ +#define CLK_SRC_FSYS0_VAL              0x66666 +#define CLK_DIV_FSYS0_VAL	       0x0BB00000 +#define CLK_DIV_FSYS1_VAL	       NOT_AVAILABLE +#define CLK_DIV_FSYS2_VAL	       NOT_AVAILABLE + +/* CLK_SRC_CPU */ +/* 0 = MOUTAPLL,  1 = SCLKMPLL */ +#define MUX_HPM_SEL             0 +#define MUX_CPU_SEL             0 +#define MUX_APLL_SEL            1 + +#define CLK_SRC_CPU_VAL		((MUX_HPM_SEL << 20)    \ +				| (MUX_CPU_SEL << 16)  \ +				| (MUX_APLL_SEL)) +  /* CLK_SRC_CDREX */  #define CLK_SRC_CDREX_VAL       0x1  /* CLK_DIV_CDREX */ +#define CLK_DIV_CDREX0_VAL	NOT_AVAILABLE +#define CLK_DIV_CDREX1_VAL	NOT_AVAILABLE + +/* CLK_DIV_CPU0_VAL */ +#define CLK_DIV_CPU0_VAL	NOT_AVAILABLE +  #define MCLK_CDREX2_RATIO       0x0  #define ACLK_EFCON_RATIO        0x1  #define MCLK_DPHY_RATIO		0x1 @@ -247,6 +585,11 @@  				| (MUX_ACLK_300_DISP1_SUB_SEL << 6)     \  				| (MUX_ACLK_200_DISP1_SUB_SEL << 4)) +#define CLK_SRC_TOP4_VAL	NOT_AVAILABLE +#define CLK_SRC_TOP5_VAL	NOT_AVAILABLE +#define CLK_SRC_TOP6_VAL	NOT_AVAILABLE +#define CLK_SRC_TOP7_VAL	NOT_AVAILABLE +  /* CLK_DIV_TOP0	*/  #define ACLK_300_DISP1_RATIO	0x2  #define ACLK_400_G3D_RATIO	0x0 @@ -279,40 +622,11 @@  				| (ACLK_400_IOP_RATIO << 16)		\  				| (ACLK_300_GSCL_RATIO << 12)) -/* APLL_LOCK	*/ -#define APLL_LOCK_VAL	(0x546) -/* MPLL_LOCK	*/ -#define MPLL_LOCK_VAL	(0x546) -/* CPLL_LOCK	*/ -#define CPLL_LOCK_VAL	(0x546) -/* GPLL_LOCK	*/ -#define GPLL_LOCK_VAL	(0x546) -/* EPLL_LOCK	*/ -#define EPLL_LOCK_VAL	(0x3A98) -/* VPLL_LOCK	*/ -#define VPLL_LOCK_VAL	(0x3A98) -/* BPLL_LOCK	*/ -#define BPLL_LOCK_VAL	(0x546) +#define CLK_DIV_TOP2_VAL	NOT_AVAILABLE -#define MUX_APLL_SEL_MASK	(1 << 0) -#define MUX_MPLL_SEL_MASK	(1 << 8) -#define MPLL_SEL_MOUT_MPLLFOUT	(2 << 8) -#define MUX_CPLL_SEL_MASK	(1 << 8) -#define MUX_EPLL_SEL_MASK	(1 << 12) -#define MUX_VPLL_SEL_MASK	(1 << 16) -#define MUX_GPLL_SEL_MASK	(1 << 28) -#define MUX_BPLL_SEL_MASK	(1 << 0) -#define MUX_HPM_SEL_MASK	(1 << 20) -#define HPM_SEL_SCLK_MPLL	(1 << 21) -#define APLL_CON0_LOCKED	(1 << 29) -#define MPLL_CON0_LOCKED	(1 << 29) -#define BPLL_CON0_LOCKED	(1 << 29) -#define CPLL_CON0_LOCKED	(1 << 29) -#define EPLL_CON0_LOCKED	(1 << 29) -#define GPLL_CON0_LOCKED	(1 << 29) -#define VPLL_CON0_LOCKED	(1 << 29) -#define CLK_REG_DISABLE		0x0 -#define TOP2_VAL		0x0110000 +/* PLL Lock Value Factor */ +#define PLL_LOCK_FACTOR		250 +#define PLL_X_LOCK_FACTOR	3000  /* CLK_SRC_PERIC0 */  #define PWM_SEL		6 @@ -336,18 +650,6 @@  				| (SPI1_SEL << 20) \  				| (SPI0_SEL << 16)) -/* SCLK_SRC_ISP - set SPI0/1 to 6 = SCLK_MPLL_USER */ -#define SPI0_ISP_SEL		6 -#define SPI1_ISP_SEL		6 -#define SCLK_SRC_ISP_VAL	(SPI1_ISP_SEL << 4) \ -				| (SPI0_ISP_SEL << 0) - -/* SCLK_DIV_ISP - set SPI0/1 to 0xf = divide by 16 */ -#define SPI0_ISP_RATIO		0xf -#define SPI1_ISP_RATIO		0xf -#define SCLK_DIV_ISP_VAL	(SPI1_ISP_RATIO << 12) \ -				| (SPI0_ISP_RATIO << 0) -  /* CLK_DIV_PERIL0	*/  #define UART5_RATIO	7  #define UART4_RATIO	7 @@ -380,105 +682,201 @@  #define PWM_RATIO		8  #define CLK_DIV_PERIC3_VAL	(PWM_RATIO << 0) -/* CLK_DIV_FSYS2 */ -#define MMC2_RATIO_MASK		0xf -#define MMC2_RATIO_VAL		0x3 -#define MMC2_RATIO_OFFSET	0 -#define MMC2_PRE_RATIO_MASK	0xff -#define MMC2_PRE_RATIO_VAL	0x9 -#define MMC2_PRE_RATIO_OFFSET	8 +/* CLK_DIV_PERIC4 */ +#define CLK_DIV_PERIC4_VAL	NOT_AVAILABLE -#define MMC3_RATIO_MASK		0xf -#define MMC3_RATIO_VAL		0x1 -#define MMC3_RATIO_OFFSET	16 +/* CLK_SRC_DISP1_0 */ +#define CLK_SRC_DISP1_0_VAL	0x6 +#define CLK_DIV_DISP1_0_VAL	NOT_AVAILABLE -#define MMC3_PRE_RATIO_MASK	0xff -#define MMC3_PRE_RATIO_VAL	0x0 -#define MMC3_PRE_RATIO_OFFSET	24 +#define APLL_FOUT		(1 << 0) +#define KPLL_FOUT		NOT_AVAILABLE -/* CLK_SRC_LEX */ -#define CLK_SRC_LEX_VAL         0x0 +#define CLK_DIV_CPERI1_VAL	NOT_AVAILABLE -/* CLK_DIV_LEX */ -#define CLK_DIV_LEX_VAL         0x10 +#else +#define PAD_RETENTION_DRAM_COREBLK_VAL	0x10000000 -/* CLK_DIV_R0X */ -#define CLK_DIV_R0X_VAL         0x10 +/* APLL_CON1 */ +#define APLL_CON1_VAL	(0x0020F300) -/* CLK_DIV_L0X */ -#define CLK_DIV_R1X_VAL         0x10 +/* MPLL_CON1 */ +#define MPLL_CON1_VAL   (0x0020F300) -/* CLK_DIV_ISP0 */ -#define CLK_DIV_ISP0_VAL        0x31 -/* CLK_DIV_ISP1 */ -#define CLK_DIV_ISP1_VAL        0x0 +/* CPLL_CON1 */ +#define CPLL_CON1_VAL	0x0020f300 -/* CLK_DIV_ISP2 */ -#define CLK_DIV_ISP2_VAL        0x1 +/* DPLL_CON1 */ +#define DPLL_CON1_VAL	(0x0020F300) -/* CLK_SRC_DISP1_0 */ -#define CLK_SRC_DISP1_0_VAL	0x6 +/* GPLL_CON1 */ +#define GPLL_CON1_VAL	(NOT_AVAILABLE) -/* - * DIV_DISP1_0 - * For DP, divisor should be 2 - */ -#define CLK_DIV_DISP1_0_FIMD1	(2 << 0) -/* CLK_GATE_IP_DISP1 */ -#define CLK_GATE_DP1_ALLOW	(1 << 4) +/* EPLL_CON1, CON2 */ +#define EPLL_CON1_VAL	0x00000000 +#define EPLL_CON2_VAL	0x00000080 -#define DDR3PHY_CTRL_PHY_RESET	(1 << 0) -#define DDR3PHY_CTRL_PHY_RESET_OFF	(0 << 0) +/* VPLL_CON1, CON2 */ +#define VPLL_CON1_VAL	0x0020f300 +#define VPLL_CON2_VAL	NOT_AVAILABLE -#define PHY_CON0_RESET_VAL	0x17020a40 -#define P0_CMD_EN		(1 << 14) -#define BYTE_RDLVL_EN		(1 << 13) -#define CTRL_SHGATE		(1 << 8) +/* RPLL_CON1, CON2 */ +#define RPLL_CON1_VAL	0x00000000 +#define RPLL_CON2_VAL	0x00000080 -#define PHY_CON1_RESET_VAL	0x09210100 -#define CTRL_GATEDURADJ_MASK	(0xf << 20) +/* BPLL_CON1 */ +#define BPLL_CON1_VAL	0x0020f300 -#define PHY_CON2_RESET_VAL	0x00010004 -#define INIT_DESKEW_EN		(1 << 6) -#define RDLVL_GATE_EN		(1 << 24) +/* SPLL_CON1 */ +#define SPLL_CON1_VAL	0x0020f300 -/*ZQ Configurations */ -#define PHY_CON16_RESET_VAL	0x08000304 +/* IPLL_CON1 */ +#define IPLL_CON1_VAL	0x00000080 -#define ZQ_CLK_DIV_EN		(1 << 18) -#define ZQ_MANUAL_STR		(1 << 1) -#define ZQ_DONE			(1 << 0) +/* KPLL_CON1 */ +#define KPLL_CON1_VAL	0x200000 -#define CTRL_RDLVL_GATE_ENABLE	1 -#define CTRL_RDLVL_GATE_DISABLE	1 +/* CLK_SRC_ISP */ +#define CLK_SRC_ISP_VAL		0x33366000 +#define CLK_DIV_ISP0_VAL	0x13131300 +#define CLK_DIV_ISP1_VAL	0xbb110202 -/* Direct Command */ -#define DIRECT_CMD_NOP			0x07000000 -#define DIRECT_CMD_PALL			0x01000000 -#define DIRECT_CMD_ZQINIT		0x0a000000 -#define DIRECT_CMD_CHANNEL_SHIFT	28 -#define DIRECT_CMD_CHIP_SHIFT		20 -/* DMC PHY Control0 register */ -#define PHY_CONTROL0_RESET_VAL	0x0 -#define MEM_TERM_EN	(1 << 31)	/* Termination enable for memory */ -#define PHY_TERM_EN	(1 << 30)	/* Termination enable for PHY */ -#define DMC_CTRL_SHGATE	(1 << 29)	/* Duration of DQS gating signal */ -#define FP_RSYNC	(1 << 3)	/* Force DLL resyncronization */ +/* CLK_FSYS */ +#define CLK_SRC_FSYS0_VAL              0x33033300 +#define CLK_DIV_FSYS0_VAL	       0x0 +#define CLK_DIV_FSYS1_VAL	       0x04f13c4f +#define CLK_DIV_FSYS2_VAL	       0x041d0000 -/* Driver strength for CK, CKE, CS & CA */ -#define IMP_OUTPUT_DRV_40_OHM	0x5 -#define IMP_OUTPUT_DRV_30_OHM	0x7 -#define CA_CK_DRVR_DS_OFFSET	9 -#define CA_CKE_DRVR_DS_OFFSET	6 -#define CA_CS_DRVR_DS_OFFSET	3 -#define CA_ADR_DRVR_DS_OFFSET	0 +/* CLK_SRC_CPU */ +/* 0 = MOUTAPLL,  1 = SCLKMPLL */ +#define MUX_HPM_SEL             1 +#define MUX_CPU_SEL             0 +#define MUX_APLL_SEL            1 -#define PHY_CON42_CTRL_BSTLEN_SHIFT	8 -#define PHY_CON42_CTRL_RDLAT_SHIFT	0 +#define CLK_SRC_CPU_VAL		((MUX_HPM_SEL << 20)    \ +				| (MUX_CPU_SEL << 16)  \ +				| (MUX_APLL_SEL)) + +/* CLK_SRC_CDREX */ +#define CLK_SRC_CDREX_VAL       0x00000011 + +/* CLK_DIV_CDREX */ +#define CLK_DIV_CDREX0_VAL	0x30010100 +#define CLK_DIV_CDREX1_VAL	0x300 + +#define CLK_DIV_CDREX_VAL       0x17010100 + +/* CLK_DIV_CPU0_VAL */ +#define CLK_DIV_CPU0_VAL	0x01440020 + +/* CLK_SRC_TOP */ +#define CLK_SRC_TOP0_VAL	0x12221222 +#define CLK_SRC_TOP1_VAL	0x00100200 +#define CLK_SRC_TOP2_VAL	0x11101000 +#define CLK_SRC_TOP3_VAL	0x11111111 +#define CLK_SRC_TOP4_VAL	0x11110111 +#define CLK_SRC_TOP5_VAL	0x11111100 +#define CLK_SRC_TOP6_VAL	0x11110111 +#define CLK_SRC_TOP7_VAL	0x00022200 + +/* CLK_DIV_TOP */ +#define CLK_DIV_TOP0_VAL	0x23712311 +#define CLK_DIV_TOP1_VAL	0x13100B00 +#define CLK_DIV_TOP2_VAL	0x11101100 + +/* PLL Lock Value Factor */ +#define PLL_LOCK_FACTOR		200 +#define PLL_X_LOCK_FACTOR	3000 + +/* CLK_SRC_PERIC0 */ +#define SPDIF_SEL	1 +#define PWM_SEL		3 +#define UART4_SEL	3 +#define UART3_SEL	3 +#define UART2_SEL	3 +#define UART1_SEL	3 +#define UART0_SEL	3 +/* SRC_CLOCK = SCLK_RPLL */ +#define CLK_SRC_PERIC0_VAL	((SPDIF_SEL << 28)	\ +				| (PWM_SEL << 24)	\ +				| (UART4_SEL << 20)	\ +				| (UART3_SEL << 16)	\ +				| (UART2_SEL << 12)	\ +				| (UART1_SEL << 8)	\ +				| (UART0_SEL << 4)) + +/* CLK_SRC_PERIC1 */ +/* SRC_CLOCK = SCLK_EPLL */ +#define SPI0_SEL		6 +#define SPI1_SEL		6 +#define SPI2_SEL		6 +#define AUDIO0_SEL		6 +#define AUDIO1_SEL		6 +#define AUDIO2_SEL		6 +#define CLK_SRC_PERIC1_VAL	((SPI2_SEL << 28)	\ +				| (SPI1_SEL << 24)	\ +				| (SPI0_SEL << 20)	\ +				| (AUDIO2_SEL << 16)	\ +				| (AUDIO2_SEL << 12)	\ +				| (AUDIO2_SEL << 8)) + +/* CLK_DIV_PERIC0 */ +#define PWM_RATIO	8 +#define UART4_RATIO	9 +#define UART3_RATIO	9 +#define UART2_RATIO	9 +#define UART1_RATIO	9 +#define UART0_RATIO	9 + +#define CLK_DIV_PERIC0_VAL	((PWM_RATIO << 28)	\ +				| (UART4_RATIO << 24)	\ +				| (UART3_RATIO << 20)    \ +				| (UART2_RATIO << 16)    \ +				| (UART1_RATIO << 12)    \ +				| (UART0_RATIO << 8)) +/* CLK_DIV_PERIC1 */ +#define SPI2_RATIO		0x1 +#define SPI1_RATIO		0x1 +#define SPI0_RATIO		0x1 +#define CLK_DIV_PERIC1_VAL	((SPI2_RATIO << 28)	\ +				| (SPI1_RATIO << 24)	\ +				| (SPI0_RATIO << 20)) + +/* CLK_DIV_PERIC2 */ +#define PCM2_RATIO		0x3 +#define PCM1_RATIO		0x3 +#define CLK_DIV_PERIC2_VAL	((PCM2_RATIO << 24) \ +				| (PCM1_RATIO << 16)) + +/* CLK_DIV_PERIC3 */ +#define AUDIO2_RATIO		0x5 +#define AUDIO1_RATIO		0x5 +#define AUDIO0_RATIO		0x5 +#define CLK_DIV_PERIC3_VAL	((AUDIO2_RATIO << 28)	\ +				| (AUDIO1_RATIO << 24)	\ +				| (AUDIO0_RATIO << 20)) + +/* CLK_DIV_PERIC4 */ +#define SPI2_PRE_RATIO		0x2 +#define SPI1_PRE_RATIO		0x2 +#define SPI0_PRE_RATIO		0x2 +#define CLK_DIV_PERIC4_VAL	((SPI2_PRE_RATIO << 24)	\ +				| (SPI1_PRE_RATIO << 16) \ +				| (SPI0_PRE_RATIO << 8)) + +/* CLK_SRC_DISP1_0 */ +#define CLK_SRC_DISP1_0_VAL	0x10666600 +#define CLK_DIV_DISP1_0_VAL	0x01050211 + +#define APLL_FOUT		(1 << 0) +#define KPLL_FOUT		(1 << 0) + +#define CLK_DIV_CPERI1_VAL	0x3f3f0000 +#endif  struct mem_timings; @@ -490,7 +888,7 @@ enum {  };  /* - * Memory variant specific initialization code + * Memory variant specific initialization code for DDR3   *   * @param mem		Memory timings for this memory type.   * @param mem_iv_size	Memory interleaving size is a configurable parameter @@ -503,49 +901,45 @@ enum {  int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,  			int reset); +/* Memory variant specific initialization code for LPDDR3 */ +void lpddr3_mem_ctrl_init(void); +  /*   * Configure ZQ I/O interface   *   * @param mem		Memory timings for this memory type. - * @param phy0_ctrl	Pointer to struct containing PHY0 control reg - * @param phy1_ctrl	Pointer to struct containing PHY1 control reg + * @param phy0_con16	Register address for dmc_phy0->phy_con16 + * @param phy1_con16	Register address for dmc_phy1->phy_con16 + * @param phy0_con17	Register address for dmc_phy0->phy_con17 + * @param phy1_con17	Register address for dmc_phy1->phy_con17   * @return 0 if ok, -1 on error   */ -int dmc_config_zq(struct mem_timings *mem, -		  struct exynos5_phy_control *phy0_ctrl, -		  struct exynos5_phy_control *phy1_ctrl); - +int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16, +			uint32_t *phy1_con16, uint32_t *phy0_con17, +			uint32_t *phy1_con17);  /*   * Send NOP and MRS/EMRS Direct commands   *   * @param mem		Memory timings for this memory type. - * @param dmc		Pointer to struct of DMC registers + * @param directcmd	Register address for dmc_phy->directcmd   */ -void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc); +void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd);  /*   * Send PALL Direct commands   *   * @param mem		Memory timings for this memory type. - * @param dmc		Pointer to struct of DMC registers - */ -void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc); - -/* - * Configure the memconfig and membaseconfig registers - * - * @param mem		Memory timings for this memory type. - * @param exynos5_dmc	Pointer to struct of DMC registers + * @param directcmd	Register address for dmc_phy->directcmd   */ -void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc); +void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd);  /*   * Reset the DLL. This function is common between DDR3 and LPDDR2.   * However, the reset value is different. So we are passing a flag   * ddr_mode to distinguish between LPDDR2 and DDR3.   * - * @param exynos5_dmc	Pointer to struct of DMC registers + * @param phycontrol0	Register address for dmc_phy->phycontrol0   * @param ddr_mode	Type of DDR memory   */ -void update_reset_dll(struct exynos5_dmc *, enum ddr_mode); +void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode);  #endif diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 74cc7009f..904177a14 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -46,6 +46,42 @@ static void exynos5_uart_config(int peripheral)  	}  } +static void exynos5420_uart_config(int peripheral) +{ +	struct exynos5420_gpio_part1 *gpio1 = +		(struct exynos5420_gpio_part1 *)samsung_get_base_gpio_part1(); +	struct s5p_gpio_bank *bank; +	int i, start, count; + +	switch (peripheral) { +	case PERIPH_ID_UART0: +		bank = &gpio1->a0; +		start = 0; +		count = 4; +		break; +	case PERIPH_ID_UART1: +		bank = &gpio1->a0; +		start = 4; +		count = 4; +		break; +	case PERIPH_ID_UART2: +		bank = &gpio1->a1; +		start = 0; +		count = 4; +		break; +	case PERIPH_ID_UART3: +		bank = &gpio1->a1; +		start = 4; +		count = 2; +		break; +	} + +	for (i = start; i < start + count; i++) { +		s5p_gpio_set_pull(bank, i, GPIO_PULL_NONE); +		s5p_gpio_cfg_pin(bank, i, GPIO_FUNC(0x2)); +	} +} +  static int exynos5_mmc_config(int peripheral, int flags)  {  	struct exynos5_gpio_part1 *gpio1 = @@ -101,6 +137,75 @@ static int exynos5_mmc_config(int peripheral, int flags)  	return 0;  } +static int exynos5420_mmc_config(int peripheral, int flags) +{ +	struct exynos5420_gpio_part3 *gpio3 = +		(struct exynos5420_gpio_part3 *)samsung_get_base_gpio_part3(); +	struct s5p_gpio_bank *bank = NULL, *bank_ext = NULL; +	int i, start; + +	switch (peripheral) { +	case PERIPH_ID_SDMMC0: +		bank = &gpio3->c0; +		bank_ext = &gpio3->c3; +		start = 0; +		break; +	case PERIPH_ID_SDMMC1: +		bank = &gpio3->c1; +		bank_ext = &gpio3->d1; +		start = 4; +		break; +	case PERIPH_ID_SDMMC2: +		bank = &gpio3->c2; +		bank_ext = NULL; +		start = 0; +		break; +	default: +		start = 0; +		debug("%s: invalid peripheral %d", __func__, peripheral); +		return -1; +	} + +	if ((flags & PINMUX_FLAG_8BIT_MODE) && !bank_ext) { +		debug("SDMMC device %d does not support 8bit mode", +		      peripheral); +		return -1; +	} + +	if (flags & PINMUX_FLAG_8BIT_MODE) { +		for (i = start; i <= (start + 3); i++) { +			s5p_gpio_cfg_pin(bank_ext, i, GPIO_FUNC(0x2)); +			s5p_gpio_set_pull(bank_ext, i, GPIO_PULL_UP); +			s5p_gpio_set_drv(bank_ext, i, GPIO_DRV_4X); +		} +	} + +	for (i = 0; i < 3; i++) { +		/* +		 * MMC0 is intended to be used for eMMC. The +		 * card detect pin is used as a VDDEN signal to +		 * power on the eMMC. The 5420 iROM makes +		 * this same assumption. +		 */ +		if ((peripheral == PERIPH_ID_SDMMC0) && (i == 2)) { +			s5p_gpio_set_value(bank, i, 1); +			s5p_gpio_cfg_pin(bank, i, GPIO_OUTPUT); +		} else { +			s5p_gpio_cfg_pin(bank, i, GPIO_FUNC(0x2)); +		} +		s5p_gpio_set_pull(bank, i, GPIO_PULL_NONE); +		s5p_gpio_set_drv(bank, i, GPIO_DRV_4X); +	} + +	for (i = 3; i <= 6; i++) { +		s5p_gpio_cfg_pin(bank, i, GPIO_FUNC(0x2)); +		s5p_gpio_set_pull(bank, i, GPIO_PULL_UP); +		s5p_gpio_set_drv(bank, i, GPIO_DRV_4X); +	} + +	return 0; +} +  static void exynos5_sromc_config(int flags)  {  	struct exynos5_gpio_part1 *gpio1 = @@ -216,6 +321,59 @@ static void exynos5_i2c_config(int peripheral, int flags)  	}  } +static void exynos5420_i2c_config(int peripheral) +{ +	struct exynos5420_gpio_part1 *gpio1 = +		(struct exynos5420_gpio_part1 *)samsung_get_base_gpio_part1(); + +	switch (peripheral) { +	case PERIPH_ID_I2C0: +		s5p_gpio_cfg_pin(&gpio1->b3, 0, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->b3, 1, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C1: +		s5p_gpio_cfg_pin(&gpio1->b3, 2, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->b3, 3, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C2: +		s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C3: +		s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C4: +		s5p_gpio_cfg_pin(&gpio1->a2, 0, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a2, 1, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C5: +		s5p_gpio_cfg_pin(&gpio1->a2, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->a2, 3, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C6: +		s5p_gpio_cfg_pin(&gpio1->b1, 3, GPIO_FUNC(0x4)); +		s5p_gpio_cfg_pin(&gpio1->b1, 4, GPIO_FUNC(0x4)); +		break; +	case PERIPH_ID_I2C7: +		s5p_gpio_cfg_pin(&gpio1->b2, 2, GPIO_FUNC(0x3)); +		s5p_gpio_cfg_pin(&gpio1->b2, 3, GPIO_FUNC(0x3)); +		break; +	case PERIPH_ID_I2C8: +		s5p_gpio_cfg_pin(&gpio1->b3, 4, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->b3, 5, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C9: +		s5p_gpio_cfg_pin(&gpio1->b3, 6, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->b3, 7, GPIO_FUNC(0x2)); +		break; +	case PERIPH_ID_I2C10: +		s5p_gpio_cfg_pin(&gpio1->b4, 0, GPIO_FUNC(0x2)); +		s5p_gpio_cfg_pin(&gpio1->b4, 1, GPIO_FUNC(0x2)); +		break; +	} +} +  static void exynos5_i2s_config(int peripheral)  {  	int i; @@ -279,6 +437,58 @@ void exynos5_spi_config(int peripheral)  	}  } +void exynos5420_spi_config(int peripheral) +{ +	int cfg, pin, i; +	struct s5p_gpio_bank *bank = NULL; +	struct exynos5420_gpio_part1 *gpio1 = +		(struct exynos5420_gpio_part1 *)samsung_get_base_gpio_part1(); +	struct exynos5420_gpio_part4 *gpio4 = +		(struct exynos5420_gpio_part4 *)samsung_get_base_gpio_part4(); + +	switch (peripheral) { +	case PERIPH_ID_SPI0: +		bank = &gpio1->a2; +		cfg = GPIO_FUNC(0x2); +		pin = 0; +		break; +	case PERIPH_ID_SPI1: +		bank = &gpio1->a2; +		cfg = GPIO_FUNC(0x2); +		pin = 4; +		break; +	case PERIPH_ID_SPI2: +		bank = &gpio1->b1; +		cfg = GPIO_FUNC(0x5); +		pin = 1; +		break; +	case PERIPH_ID_SPI3: +		bank = &gpio4->f1; +		cfg = GPIO_FUNC(0x2); +		pin = 0; +		break; +	case PERIPH_ID_SPI4: +		cfg = 0; +		pin = 0; +		break; +	default: +		cfg = 0; +		pin = 0; +		debug("%s: invalid peripheral %d", __func__, peripheral); +		return; +	} + +	if (peripheral != PERIPH_ID_SPI4) { +		for (i = pin; i < pin + 4; i++) +			s5p_gpio_cfg_pin(bank, i, cfg); +	} else { +		for (i = 0; i < 2; i++) { +			s5p_gpio_cfg_pin(&gpio4->f0, i + 2, GPIO_FUNC(0x4)); +			s5p_gpio_cfg_pin(&gpio4->e0, i + 4, GPIO_FUNC(0x4)); +		} +	} +} +  static int exynos5_pinmux_config(int peripheral, int flags)  {  	switch (peripheral) { @@ -325,6 +535,48 @@ static int exynos5_pinmux_config(int peripheral, int flags)  	return 0;  } +static int exynos5420_pinmux_config(int peripheral, int flags) +{ +	switch (peripheral) { +	case PERIPH_ID_UART0: +	case PERIPH_ID_UART1: +	case PERIPH_ID_UART2: +	case PERIPH_ID_UART3: +		exynos5420_uart_config(peripheral); +		break; +	case PERIPH_ID_SDMMC0: +	case PERIPH_ID_SDMMC1: +	case PERIPH_ID_SDMMC2: +	case PERIPH_ID_SDMMC3: +		return exynos5420_mmc_config(peripheral, flags); +	case PERIPH_ID_SPI0: +	case PERIPH_ID_SPI1: +	case PERIPH_ID_SPI2: +	case PERIPH_ID_SPI3: +	case PERIPH_ID_SPI4: +		exynos5420_spi_config(peripheral); +		break; +	case PERIPH_ID_I2C0: +	case PERIPH_ID_I2C1: +	case PERIPH_ID_I2C2: +	case PERIPH_ID_I2C3: +	case PERIPH_ID_I2C4: +	case PERIPH_ID_I2C5: +	case PERIPH_ID_I2C6: +	case PERIPH_ID_I2C7: +	case PERIPH_ID_I2C8: +	case PERIPH_ID_I2C9: +	case PERIPH_ID_I2C10: +		exynos5420_i2c_config(peripheral); +		break; +	default: +		debug("%s: invalid peripheral %d", __func__, peripheral); +		return -1; +	} + +	return 0; +} +  static void exynos4_i2c_config(int peripheral, int flags)  {  	struct exynos4_gpio_part1 *gpio1 = @@ -475,13 +727,17 @@ static int exynos4_pinmux_config(int peripheral, int flags)  int exynos_pinmux_config(int peripheral, int flags)  {  	if (cpu_is_exynos5()) { -		return exynos5_pinmux_config(peripheral, flags); +		if (proid_is_exynos5420()) +			return exynos5420_pinmux_config(peripheral, flags); +		else if (proid_is_exynos5250()) +			return exynos5_pinmux_config(peripheral, flags);  	} else if (cpu_is_exynos4()) {  		return exynos4_pinmux_config(peripheral, flags);  	} else {  		debug("pinmux functionality not supported\n"); -		return -1;  	} + +	return -1;  }  #ifdef CONFIG_OF_CONTROL diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c index fb3b12819..bf52f0d19 100644 --- a/arch/arm/cpu/armv7/mx5/clock.c +++ b/arch/arm/cpu/armv7/mx5/clock.c @@ -749,6 +749,18 @@ void enable_nfc_clk(unsigned char enable)  		MXC_CCM_CCGR5_EMI_ENFC(cg));  } +#ifdef CONFIG_FSL_IIM +void enable_efuse_prog_supply(bool enable) +{ +	if (enable) +		setbits_le32(&mxc_ccm->cgpr, +			     MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE); +	else +		clrbits_le32(&mxc_ccm->cgpr, +			     MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE); +} +#endif +  /* Config main_bus_clock for periphs */  static int config_periph_clk(u32 ref, u32 freq)  { diff --git a/arch/arm/cpu/armv7/mx6/clock.c b/arch/arm/cpu/armv7/mx6/clock.c index 873d9d0fd..fcc4f352c 100644 --- a/arch/arm/cpu/armv7/mx6/clock.c +++ b/arch/arm/cpu/armv7/mx6/clock.c @@ -94,7 +94,7 @@ static u32 decode_pll(enum pll_clocks pll, u32 infreq)  		div = __raw_readl(&imx_ccm->analog_pll_enet);  		div &= BM_ANADIG_PLL_ENET_DIV_SELECT; -		return (div == 3 ? 125000000 : 25000000 * (div << 1)); +		return 25000000 * (div + (div >> 1) + 1);  	default:  		return 0;  	} @@ -310,7 +310,18 @@ static u32 get_mmdc_ch0_clk(void)  	return freq / (podf + 1);  } +#else +static u32 get_mmdc_ch0_clk(void) +{ +	u32 cbcdr = __raw_readl(&imx_ccm->cbcdr); +	u32 mmdc_ch0_podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >> +				MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET; + +	return get_periph_clk() / (mmdc_ch0_podf + 1); +} +#endif +#ifdef CONFIG_FEC_MXC  int enable_fec_anatop_clock(void)  {  	u32 reg = 0; @@ -339,16 +350,6 @@ int enable_fec_anatop_clock(void)  	return 0;  } - -#else -static u32 get_mmdc_ch0_clk(void) -{ -	u32 cbcdr = __raw_readl(&imx_ccm->cbcdr); -	u32 mmdc_ch0_podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >> -				MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET; - -	return get_periph_clk() / (mmdc_ch0_podf + 1); -}  #endif  static u32 get_usdhc_clk(u32 port) diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c index a3902962b..009a644ab 100644 --- a/arch/arm/cpu/armv7/mx6/soc.c +++ b/arch/arm/cpu/armv7/mx6/soc.c @@ -19,6 +19,14 @@  #include <asm/arch/mxc_hdmi.h>  #include <asm/arch/crm_regs.h> +#define VDDPU_MASK	(0x1f << 9) + +enum ldo_reg { +	LDO_ARM, +	LDO_SOC, +	LDO_PU, +}; +  struct scu_regs {  	u32	ctrl;  	u32	config; @@ -93,6 +101,20 @@ void init_aips(void)  	writel(0x00000000, &aips2->opacr4);  } +static void clear_ldo_ramp(void) +{ +	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; +	int reg; + +	/* ROM may modify LDO ramp up time according to fuse setting, so in +	 * order to be in the safe side we neeed to reset these settings to +	 * match the reset value: 0'b00 +	 */ +	reg = readl(&anatop->ana_misc2); +	reg &= ~(0x3f << 24); +	writel(reg, &anatop->ana_misc2); +} +  /*   * Set the VDDSOC   * @@ -101,10 +123,11 @@ void init_aips(void)   * Possible values are from 0.725V to 1.450V in steps of   * 0.025V (25mV).   */ -void set_vddsoc(u32 mv) +static int set_ldo_voltage(enum ldo_reg ldo, u32 mv)  {  	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; -	u32 val, reg = readl(&anatop->reg_core); +	u32 val, step, old, reg = readl(&anatop->reg_core); +	u8 shift;  	if (mv < 725)  		val = 0x00;	/* Power gated off */ @@ -113,12 +136,37 @@ void set_vddsoc(u32 mv)  	else  		val = (mv - 700) / 25; +	clear_ldo_ramp(); + +	switch (ldo) { +	case LDO_SOC: +		shift = 18; +		break; +	case LDO_PU: +		shift = 9; +		break; +	case LDO_ARM: +		shift = 0; +		break; +	default: +		return -EINVAL; +	} + +	old = (reg & (0x1F << shift)) >> shift; +	step = abs(val - old); +	if (step == 0) +		return 0; + +	reg = (reg & ~(0x1F << shift)) | (val << shift); +	writel(reg, &anatop->reg_core); +  	/* -	 * Mask out the REG_CORE[22:18] bits (REG2_TRIG) -	 * and set them to the calculated value (0.7V + val * 0.25V) +	 * The LDO ramp-up is based on 64 clock cycles of 24 MHz = 2.6 us per +	 * step  	 */ -	reg = (reg & ~(0x1F << 18)) | (val << 18); -	writel(reg, &anatop->reg_core); +	udelay(3 * step); + +	return 0;  }  static void imx_set_wdog_powerdown(bool enable) @@ -131,13 +179,50 @@ static void imx_set_wdog_powerdown(bool enable)  	writew(enable, &wdog2->wmcr);  } +static void imx_set_vddpu_power_down(void) +{ +	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; +	struct gpc_regs *gpc = (struct gpc_regs *)GPC_BASE_ADDR; + +	u32 reg; + +	/* +	 * Disable the brown out detection since we are going to be +	 * disabling the LDO. +	 */ +	reg = readl(&anatop->ana_misc2); +	reg &= ~ANADIG_ANA_MISC2_REG1_BO_EN; +	writel(reg, &anatop->ana_misc2); + +	/* need to power down xPU in GPC before turning off PU LDO */ +	reg = readl(&gpc->gpu_ctrl); +	writel(reg | 0x1, &gpc->gpu_ctrl); + +	reg = readl(&gpc->ctrl); +	writel(reg | 0x1, &gpc->ctrl); +	while (readl(&gpc->ctrl) & 0x1) +		; + +	/* Mask the ANATOP brown out interrupt in the GPC. */ +	reg = readl(&gpc->imr4); +	reg |= 0x80000000; +	writel(reg, &gpc->imr4); + +	/* disable VDDPU */ +	writel(VDDPU_MASK, &anatop->reg_core_clr); + +	/* Clear the BO interrupt in the ANATOP. */ +	reg = readl(&anatop->ana_misc1); +	reg |= 0x80000000; +	writel(reg, &anatop->ana_misc1); +} +  int arch_cpu_init(void)  {  	init_aips(); -	set_vddsoc(1200);	/* Set VDDSOC to 1.2V */ -  	imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */ +	imx_set_vddpu_power_down();  #ifdef CONFIG_APBH_DMA  	/* Start APBH DMA */ @@ -147,9 +232,18 @@ int arch_cpu_init(void)  	return 0;  } +int board_postclk_init(void) +{ +	set_ldo_voltage(LDO_SOC, 1175);	/* Set VDDSOC to 1.175V */ + +	return 0; +} +  #ifndef CONFIG_SYS_DCACHE_OFF  void enable_caches(void)  { +	/* Avoid random hang when download by usb */ +	invalidate_dcache_all();  	/* Enable D-cache. I-cache is already enabled in start.S */  	dcache_enable();  } diff --git a/arch/arm/cpu/armv7/omap-common/abb.c b/arch/arm/cpu/armv7/omap-common/abb.c index a46783fae..423aeb980 100644 --- a/arch/arm/cpu/armv7/omap-common/abb.c +++ b/arch/arm/cpu/armv7/omap-common/abb.c @@ -11,6 +11,7 @@  #include <common.h>  #include <asm/omap_common.h> +#include <asm/arch/clock.h>  #include <asm/io.h>  #include <asm/arch/sys_proto.h> diff --git a/arch/arm/cpu/armv7/omap-common/emif-common.c b/arch/arm/cpu/armv7/omap-common/emif-common.c index 5a3f2858c..cd6289b4f 100644 --- a/arch/arm/cpu/armv7/omap-common/emif-common.c +++ b/arch/arm/cpu/armv7/omap-common/emif-common.c @@ -50,20 +50,6 @@ inline u32 emif_num(u32 base)  		return 0;  } -/* - * Get SDRAM type connected to EMIF. - * Assuming similar SDRAM parts are connected to both EMIF's - * which is typically the case. So it is sufficient to get - * SDRAM type from EMIF1. - */ -u32 emif_sdram_type() -{ -	struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE; - -	return (readl(&emif->emif_sdram_config) & -		EMIF_REG_SDRAM_TYPE_MASK) >> EMIF_REG_SDRAM_TYPE_SHIFT; -} -  static inline u32 get_mr(u32 base, u32 cs, u32 mr_addr)  {  	u32 mr; diff --git a/arch/arm/cpu/armv7/omap5/hw_data.c b/arch/arm/cpu/armv7/omap5/hw_data.c index 82910e87a..5268a1fca 100644 --- a/arch/arm/cpu/armv7/omap5/hw_data.c +++ b/arch/arm/cpu/armv7/omap5/hw_data.c @@ -39,17 +39,6 @@ static const struct dpll_params mpu_dpll_params_1_5ghz[NUM_SYS_CLKS] = {  	{625, 15, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}	/* 38.4 MHz */  }; -/* OPP NOM FREQUENCY for ES2.0, OPP HIGH for ES1.0 */ -static const struct dpll_params mpu_dpll_params_1100mhz[NUM_SYS_CLKS] = { -	{275, 2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 12 MHz   */ -	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 13 MHz   */ -	{1375, 20, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 16.8 MHz */ -	{1375, 23, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 19.2 MHz */ -	{550, 12, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 26 MHz   */ -	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ -	{1375, 47, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}	/* 38.4 MHz */ -}; -  /* OPP NOM FREQUENCY for ES1.0 */  static const struct dpll_params mpu_dpll_params_800mhz[NUM_SYS_CLKS] = {  	{200, 2, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 12 MHz   */ @@ -83,6 +72,7 @@ static const struct dpll_params mpu_dpll_params_499mhz[NUM_SYS_CLKS] = {  	{493, 37, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}	/* 38.4 MHz */  }; +/* OPP NOM FREQUENCY for OMAP5 ES2.0, and DRA7 ES1.0 */  static const struct dpll_params mpu_dpll_params_1ghz[NUM_SYS_CLKS] = {  	{250, 2, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1},		/* 12 MHz   */  	{500, 9, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1},		/* 20 MHz   */ @@ -169,13 +159,13 @@ static const struct dpll_params per_dpll_params_768mhz_es2[NUM_SYS_CLKS] = {  };  static const struct dpll_params per_dpll_params_768mhz_dra7xx[NUM_SYS_CLKS] = { -	{32, 0, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1},		/* 12 MHz   */ +	{32, 0, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1},		/* 12 MHz   */  	{96, 4, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1},		/* 20 MHz   */ -	{160, 6, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1},		/* 16.8 MHz */ -	{20, 0, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1},		/* 19.2 MHz */ -	{192, 12, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1},		/* 26 MHz   */ +	{160, 6, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1},		/* 16.8 MHz */ +	{20, 0, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1},		/* 19.2 MHz */ +	{192, 12, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1},		/* 26 MHz   */  	{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},	/* 27 MHz   */ -	{10, 0, 4, 1, 3, 4, 10, 2, -1, -1, -1, -1},		/* 38.4 MHz */ +	{10, 0, 4, 1, 3, 4, 4, 2, -1, -1, -1, -1},		/* 38.4 MHz */  };  static const struct dpll_params iva_dpll_params_2330mhz[NUM_SYS_CLKS] = { @@ -272,7 +262,7 @@ struct dplls omap5_dplls_es1 = {  };  struct dplls omap5_dplls_es2 = { -	.mpu = mpu_dpll_params_1100mhz, +	.mpu = mpu_dpll_params_1ghz,  	.core = core_dpll_params_2128mhz_ddr532_es2,  	.per = per_dpll_params_768mhz_es2,  	.iva = iva_dpll_params_2330mhz, diff --git a/arch/arm/cpu/armv7/zynq/slcr.c b/arch/arm/cpu/armv7/zynq/slcr.c index 717ec65ae..b4c11c324 100644 --- a/arch/arm/cpu/armv7/zynq/slcr.c +++ b/arch/arm/cpu/armv7/zynq/slcr.c @@ -101,6 +101,12 @@ void zynq_slcr_devcfg_enable(void)  	zynq_slcr_lock();  } +u32 zynq_slcr_get_boot_mode(void) +{ +	/* Get the bootmode register value */ +	return readl(&slcr_base->boot_mode); +} +  u32 zynq_slcr_get_idcode(void)  {  	return (readl(&slcr_base->pss_idcode) & SLCR_IDCODE_MASK) >> diff --git a/arch/arm/cpu/armv8/Makefile b/arch/arm/cpu/armv8/Makefile new file mode 100644 index 000000000..b6eb6de5e --- /dev/null +++ b/arch/arm/cpu/armv8/Makefile @@ -0,0 +1,17 @@ +# +# (C) Copyright 2000-2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +extra-y	:= start.o + +obj-y	+= cpu.o +obj-y	+= generic_timer.o +obj-y	+= cache_v8.o +obj-y	+= exceptions.o +obj-y	+= cache.o +obj-y	+= tlb.o +obj-y	+= gic.o +obj-y	+= transition.o diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S new file mode 100644 index 000000000..546a83e8f --- /dev/null +++ b/arch/arm/cpu/armv8/cache.S @@ -0,0 +1,136 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * This file is based on sample code from ARMv8 ARM. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <version.h> +#include <asm/macro.h> +#include <linux/linkage.h> + +/* + * void __asm_flush_dcache_level(level) + * + * clean and invalidate one level cache. + * + * x0: cache level + * x1~x9: clobbered + */ +ENTRY(__asm_flush_dcache_level) +	lsl	x1, x0, #1 +	msr	csselr_el1, x1		/* select cache level */ +	isb				/* sync change of cssidr_el1 */ +	mrs	x6, ccsidr_el1		/* read the new cssidr_el1 */ +	and	x2, x6, #7		/* x2 <- log2(cache line size)-4 */ +	add	x2, x2, #4		/* x2 <- log2(cache line size) */ +	mov	x3, #0x3ff +	and	x3, x3, x6, lsr #3	/* x3 <- max number of #ways */ +	add	w4, w3, w3 +	sub	w4, w4, 1		/* round up log2(#ways + 1) */ +	clz	w5, w4			/* bit position of #ways */ +	mov	x4, #0x7fff +	and	x4, x4, x6, lsr #13	/* x4 <- max number of #sets */ +	/* x1 <- cache level << 1 */ +	/* x2 <- line length offset */ +	/* x3 <- number of cache ways - 1 */ +	/* x4 <- number of cache sets - 1 */ +	/* x5 <- bit position of #ways */ + +loop_set: +	mov	x6, x3			/* x6 <- working copy of #ways */ +loop_way: +	lsl	x7, x6, x5 +	orr	x9, x1, x7		/* map way and level to cisw value */ +	lsl	x7, x4, x2 +	orr	x9, x9, x7		/* map set number to cisw value */ +	dc	cisw, x9		/* clean & invalidate by set/way */ +	subs	x6, x6, #1		/* decrement the way */ +	b.ge	loop_way +	subs	x4, x4, #1		/* decrement the set */ +	b.ge	loop_set + +	ret +ENDPROC(__asm_flush_dcache_level) + +/* + * void __asm_flush_dcache_all(void) + * + * clean and invalidate all data cache by SET/WAY. + */ +ENTRY(__asm_flush_dcache_all) +	dsb	sy +	mrs	x10, clidr_el1		/* read clidr_el1 */ +	lsr	x11, x10, #24 +	and	x11, x11, #0x7		/* x11 <- loc */ +	cbz	x11, finished		/* if loc is 0, exit */ +	mov	x15, lr +	mov	x0, #0			/* start flush at cache level 0 */ +	/* x0  <- cache level */ +	/* x10 <- clidr_el1 */ +	/* x11 <- loc */ +	/* x15 <- return address */ + +loop_level: +	lsl	x1, x0, #1 +	add	x1, x1, x0		/* x0 <- tripled cache level */ +	lsr	x1, x10, x1 +	and	x1, x1, #7		/* x1 <- cache type */ +	cmp	x1, #2 +	b.lt	skip			/* skip if no cache or icache */ +	bl	__asm_flush_dcache_level +skip: +	add	x0, x0, #1		/* increment cache level */ +	cmp	x11, x0 +	b.gt	loop_level + +	mov	x0, #0 +	msr	csselr_el1, x0		/* resotre csselr_el1 */ +	dsb	sy +	isb +	mov	lr, x15 + +finished: +	ret +ENDPROC(__asm_flush_dcache_all) + +/* + * void __asm_flush_dcache_range(start, end) + * + * clean & invalidate data cache in the range + * + * x0: start address + * x1: end address + */ +ENTRY(__asm_flush_dcache_range) +	mrs	x3, ctr_el0 +	lsr	x3, x3, #16 +	and	x3, x3, #0xf +	mov	x2, #4 +	lsl	x2, x2, x3		/* cache line size */ + +	/* x2 <- minimal cache line size in cache system */ +	sub	x3, x2, #1 +	bic	x0, x0, x3 +1:	dc	civac, x0	/* clean & invalidate data or unified cache */ +	add	x0, x0, x2 +	cmp	x0, x1 +	b.lo	1b +	dsb	sy +	ret +ENDPROC(__asm_flush_dcache_range) + +/* + * void __asm_invalidate_icache_all(void) + * + * invalidate all tlb entries. + */ +ENTRY(__asm_invalidate_icache_all) +	ic	ialluis +	isb	sy +	ret +ENDPROC(__asm_invalidate_icache_all) diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c new file mode 100644 index 000000000..131fdaba3 --- /dev/null +++ b/arch/arm/cpu/armv8/cache_v8.c @@ -0,0 +1,219 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <asm/system.h> +#include <asm/armv8/mmu.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SYS_DCACHE_OFF + +static void set_pgtable_section(u64 section, u64 memory_type) +{ +	u64 *page_table = (u64 *)gd->arch.tlb_addr; +	u64 value; + +	value = (section << SECTION_SHIFT) | PMD_TYPE_SECT | PMD_SECT_AF; +	value |= PMD_ATTRINDX(memory_type); +	page_table[section] = value; +} + +/* to activate the MMU we need to set up virtual memory */ +static void mmu_setup(void) +{ +	int i, j, el; +	bd_t *bd = gd->bd; + +	/* Setup an identity-mapping for all spaces */ +	for (i = 0; i < (PGTABLE_SIZE >> 3); i++) +		set_pgtable_section(i, MT_DEVICE_NGNRNE); + +	/* Setup an identity-mapping for all RAM space */ +	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { +		ulong start = bd->bi_dram[i].start; +		ulong end = bd->bi_dram[i].start + bd->bi_dram[i].size; +		for (j = start >> SECTION_SHIFT; +		     j < end >> SECTION_SHIFT; j++) { +			set_pgtable_section(j, MT_NORMAL); +		} +	} + +	/* load TTBR0 */ +	el = current_el(); +	if (el == 1) +		asm volatile("msr ttbr0_el1, %0" +			     : : "r" (gd->arch.tlb_addr) : "memory"); +	else if (el == 2) +		asm volatile("msr ttbr0_el2, %0" +			     : : "r" (gd->arch.tlb_addr) : "memory"); +	else +		asm volatile("msr ttbr0_el3, %0" +			     : : "r" (gd->arch.tlb_addr) : "memory"); + +	/* enable the mmu */ +	set_sctlr(get_sctlr() | CR_M); +} + +/* + * Performs a invalidation of the entire data cache at all levels + */ +void invalidate_dcache_all(void) +{ +	__asm_flush_dcache_all(); +} + +/* + * Performs a clean & invalidation of the entire data cache at all levels + */ +void flush_dcache_all(void) +{ +	__asm_flush_dcache_all(); +} + +/* + * Invalidates range in all levels of D-cache/unified cache + */ +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +	__asm_flush_dcache_range(start, stop); +} + +/* + * Flush range(clean & invalidate) from all levels of D-cache/unified cache + */ +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +	__asm_flush_dcache_range(start, stop); +} + +void dcache_enable(void) +{ +	/* The data cache is not active unless the mmu is enabled */ +	if (!(get_sctlr() & CR_M)) { +		invalidate_dcache_all(); +		__asm_invalidate_tlb_all(); +		mmu_setup(); +	} + +	set_sctlr(get_sctlr() | CR_C); +} + +void dcache_disable(void) +{ +	uint32_t sctlr; + +	sctlr = get_sctlr(); + +	/* if cache isn't enabled no need to disable */ +	if (!(sctlr & CR_C)) +		return; + +	set_sctlr(sctlr & ~(CR_C|CR_M)); + +	flush_dcache_all(); +	__asm_invalidate_tlb_all(); +} + +int dcache_status(void) +{ +	return (get_sctlr() & CR_C) != 0; +} + +#else	/* CONFIG_SYS_DCACHE_OFF */ + +void invalidate_dcache_all(void) +{ +} + +void flush_dcache_all(void) +{ +} + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void dcache_enable(void) +{ +} + +void dcache_disable(void) +{ +} + +int dcache_status(void) +{ +	return 0; +} + +#endif	/* CONFIG_SYS_DCACHE_OFF */ + +#ifndef CONFIG_SYS_ICACHE_OFF + +void icache_enable(void) +{ +	set_sctlr(get_sctlr() | CR_I); +} + +void icache_disable(void) +{ +	set_sctlr(get_sctlr() & ~CR_I); +} + +int icache_status(void) +{ +	return (get_sctlr() & CR_I) != 0; +} + +void invalidate_icache_all(void) +{ +	__asm_invalidate_icache_all(); +} + +#else	/* CONFIG_SYS_ICACHE_OFF */ + +void icache_enable(void) +{ +} + +void icache_disable(void) +{ +} + +int icache_status(void) +{ +	return 0; +} + +void invalidate_icache_all(void) +{ +} + +#endif	/* CONFIG_SYS_ICACHE_OFF */ + +/* + * Enable dCache & iCache, whether cache is actually enabled + * depend on CONFIG_SYS_DCACHE_OFF and CONFIG_SYS_ICACHE_OFF + */ +void enable_caches(void) +{ +	icache_enable(); +	dcache_enable(); +} + +/* + * Flush range from all levels of d-cache/unified-cache + */ +void flush_cache(unsigned long start, unsigned long size) +{ +	flush_dcache_range(start, start + size); +} diff --git a/arch/arm/cpu/armv8/config.mk b/arch/arm/cpu/armv8/config.mk new file mode 100644 index 000000000..027a68ca5 --- /dev/null +++ b/arch/arm/cpu/armv8/config.mk @@ -0,0 +1,15 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> +# +# SPDX-License-Identifier:	GPL-2.0+ +# +PLATFORM_RELFLAGS += -fno-common -ffixed-x18 + +# SEE README.arm-unaligned-accesses +PF_NO_UNALIGNED := $(call cc-option, -mstrict-align) +PLATFORM_NO_UNALIGNED := $(PF_NO_UNALIGNED) + +PF_CPPFLAGS_ARMV8 := $(call cc-option, -march=armv8-a) +PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_ARMV8) +PLATFORM_CPPFLAGS += $(PF_NO_UNALIGNED) diff --git a/arch/arm/cpu/armv8/cpu.c b/arch/arm/cpu/armv8/cpu.c new file mode 100644 index 000000000..e06c3cc04 --- /dev/null +++ b/arch/arm/cpu/armv8/cpu.c @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2008 Texas Insturments + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <asm/system.h> +#include <linux/compiler.h> + +int cleanup_before_linux(void) +{ +	/* +	 * this function is called just before we call linux +	 * it prepares the processor for linux +	 * +	 * disable interrupt and turn off caches etc ... +	 */ +	disable_interrupts(); + +	/* +	 * Turn off I-cache and invalidate it +	 */ +	icache_disable(); +	invalidate_icache_all(); + +	/* +	 * turn off D-cache +	 * dcache_disable() in turn flushes the d-cache and disables MMU +	 */ +	dcache_disable(); +	invalidate_dcache_all(); + +	return 0; +} diff --git a/arch/arm/cpu/armv8/exceptions.S b/arch/arm/cpu/armv8/exceptions.S new file mode 100644 index 000000000..b91a1b662 --- /dev/null +++ b/arch/arm/cpu/armv8/exceptions.S @@ -0,0 +1,113 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <version.h> +#include <asm/ptrace.h> +#include <asm/macro.h> +#include <linux/linkage.h> + +/* + * Enter Exception. + * This will save the processor state that is ELR/X0~X30 + * to the stack frame. + */ +.macro	exception_entry +	stp	x29, x30, [sp, #-16]! +	stp	x27, x28, [sp, #-16]! +	stp	x25, x26, [sp, #-16]! +	stp	x23, x24, [sp, #-16]! +	stp	x21, x22, [sp, #-16]! +	stp	x19, x20, [sp, #-16]! +	stp	x17, x18, [sp, #-16]! +	stp	x15, x16, [sp, #-16]! +	stp	x13, x14, [sp, #-16]! +	stp	x11, x12, [sp, #-16]! +	stp	x9, x10, [sp, #-16]! +	stp	x7, x8, [sp, #-16]! +	stp	x5, x6, [sp, #-16]! +	stp	x3, x4, [sp, #-16]! +	stp	x1, x2, [sp, #-16]! + +	/* Could be running at EL3/EL2/EL1 */ +	switch_el x11, 3f, 2f, 1f +3:	mrs	x1, esr_el3 +	mrs	x2, elr_el3 +	b	0f +2:	mrs	x1, esr_el2 +	mrs	x2, elr_el2 +	b	0f +1:	mrs	x1, esr_el1 +	mrs	x2, elr_el1 +0: +	stp	x2, x0, [sp, #-16]! +	mov	x0, sp +.endm + +/* + * Exception vectors. + */ +	.align	11 +	.globl	vectors +vectors: +	.align	7 +	b	_do_bad_sync	/* Current EL Synchronous Thread */ + +	.align	7 +	b	_do_bad_irq	/* Current EL IRQ Thread */ + +	.align	7 +	b	_do_bad_fiq	/* Current EL FIQ Thread */ + +	.align	7 +	b	_do_bad_error	/* Current EL Error Thread */ + +	.align	7 +	b	_do_sync	/* Current EL Synchronous Handler */ + +	.align	7 +	b	_do_irq		/* Current EL IRQ Handler */ + +	.align	7 +	b	_do_fiq		/* Current EL FIQ Handler */ + +	.align	7 +	b	_do_error	/* Current EL Error Handler */ + + +_do_bad_sync: +	exception_entry +	bl	do_bad_sync + +_do_bad_irq: +	exception_entry +	bl	do_bad_irq + +_do_bad_fiq: +	exception_entry +	bl	do_bad_fiq + +_do_bad_error: +	exception_entry +	bl	do_bad_error + +_do_sync: +	exception_entry +	bl	do_sync + +_do_irq: +	exception_entry +	bl	do_irq + +_do_fiq: +	exception_entry +	bl	do_fiq + +_do_error: +	exception_entry +	bl	do_error diff --git a/arch/arm/cpu/armv8/generic_timer.c b/arch/arm/cpu/armv8/generic_timer.c new file mode 100644 index 000000000..223b95e21 --- /dev/null +++ b/arch/arm/cpu/armv8/generic_timer.c @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <command.h> +#include <asm/system.h> + +/* + * Generic timer implementation of get_tbclk() + */ +unsigned long get_tbclk(void) +{ +	unsigned long cntfrq; +	asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq)); +	return cntfrq; +} + +/* + * Generic timer implementation of timer_read_counter() + */ +unsigned long timer_read_counter(void) +{ +	unsigned long cntpct; +	isb(); +	asm volatile("mrs %0, cntpct_el0" : "=r" (cntpct)); +	return cntpct; +} diff --git a/arch/arm/cpu/armv8/gic.S b/arch/arm/cpu/armv8/gic.S new file mode 100644 index 000000000..599aa8f2b --- /dev/null +++ b/arch/arm/cpu/armv8/gic.S @@ -0,0 +1,106 @@ +/* + * GIC Initialization Routines. + * + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <linux/linkage.h> +#include <asm/macro.h> +#include <asm/gic.h> + + +/************************************************************************* + * + * void gic_init(void) __attribute__((weak)); + * + * Currently, this routine only initialize secure copy of GIC + * with Security Extensions at EL3. + * + *************************************************************************/ +WEAK(gic_init) +	branch_if_slave	x0, 2f + +	/* Initialize Distributor and SPIs */ +	ldr	x1, =GICD_BASE +	mov	w0, #0x3		/* EnableGrp0 | EnableGrp1 */ +	str	w0, [x1, GICD_CTLR]	/* Secure GICD_CTLR */ +	ldr	w0, [x1, GICD_TYPER] +	and	w2, w0, #0x1f		/* ITLinesNumber */ +	cbz	w2, 2f			/* No SPIs */ +	add	x1, x1, (GICD_IGROUPRn + 4) +	mov	w0, #~0			/* Config SPIs as Grp1 */ +1:	str	w0, [x1], #0x4 +	sub	w2, w2, #0x1 +	cbnz	w2, 1b + +	/* Initialize SGIs and PPIs */ +2:	ldr	x1, =GICD_BASE +	mov	w0, #~0			/* Config SGIs and PPIs as Grp1 */ +	str	w0, [x1, GICD_IGROUPRn]	/* GICD_IGROUPR0 */ +	mov	w0, #0x1		/* Enable SGI 0 */ +	str	w0, [x1, GICD_ISENABLERn] + +	/* Initialize Cpu Interface */ +	ldr	x1, =GICC_BASE +	mov	w0, #0x1e7		/* Disable IRQ/FIQ Bypass & */ +					/* Enable Ack Group1 Interrupt & */ +					/* EnableGrp0 & EnableGrp1 */ +	str	w0, [x1, GICC_CTLR]	/* Secure GICC_CTLR */ + +	mov	w0, #0x1 << 7		/* Non-Secure access to GICC_PMR */ +	str	w0, [x1, GICC_PMR] + +	ret +ENDPROC(gic_init) + + +/************************************************************************* + * + * void gic_send_sgi(u64 sgi) __attribute__((weak)); + * + *************************************************************************/ +WEAK(gic_send_sgi) +	ldr	x1, =GICD_BASE +	mov	w2, #0x8000 +	movk	w2, #0x100, lsl #16 +	orr	w2, w2, w0 +	str	w2, [x1, GICD_SGIR] +	ret +ENDPROC(gic_send_sgi) + + +/************************************************************************* + * + * void wait_for_wakeup(void) __attribute__((weak)); + * + * Wait for SGI 0 from master. + * + *************************************************************************/ +WEAK(wait_for_wakeup) +	ldr	x1, =GICC_BASE +0:	wfi +	ldr	w0, [x1, GICC_AIAR] +	str	w0, [x1, GICC_AEOIR] +	cbnz	w0, 0b +	ret +ENDPROC(wait_for_wakeup) + + +/************************************************************************* + * + * void smp_kick_all_cpus(void) __attribute__((weak)); + * + *************************************************************************/ +WEAK(smp_kick_all_cpus) +	/* Kick secondary cpus up by SGI 0 interrupt */ +	mov	x0, xzr			/* SGI 0 */ +	mov	x29, lr			/* Save LR */ +	bl	gic_send_sgi +	mov	lr, x29			/* Restore LR */ +	ret +ENDPROC(smp_kick_all_cpus) diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S new file mode 100644 index 000000000..bcc260309 --- /dev/null +++ b/arch/arm/cpu/armv8/start.S @@ -0,0 +1,164 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <version.h> +#include <linux/linkage.h> +#include <asm/macro.h> +#include <asm/armv8/mmu.h> + +/************************************************************************* + * + * Startup Code (reset vector) + * + *************************************************************************/ + +.globl	_start +_start: +	b	reset + +	.align 3 + +.globl	_TEXT_BASE +_TEXT_BASE: +	.quad	CONFIG_SYS_TEXT_BASE + +/* + * These are defined in the linker script. + */ +.globl	_end_ofs +_end_ofs: +	.quad	_end - _start + +.globl	_bss_start_ofs +_bss_start_ofs: +	.quad	__bss_start - _start + +.globl	_bss_end_ofs +_bss_end_ofs: +	.quad	__bss_end - _start + +reset: +	/* +	 * Could be EL3/EL2/EL1, Initial State: +	 * Little Endian, MMU Disabled, i/dCache Disabled +	 */ +	adr	x0, vectors +	switch_el x1, 3f, 2f, 1f +3:	msr	vbar_el3, x0 +	msr	cptr_el3, xzr			/* Enable FP/SIMD */ +	ldr	x0, =COUNTER_FREQUENCY +	msr	cntfrq_el0, x0			/* Initialize CNTFRQ */ +	b	0f +2:	msr	vbar_el2, x0 +	mov	x0, #0x33ff +	msr	cptr_el2, x0			/* Enable FP/SIMD */ +	b	0f +1:	msr	vbar_el1, x0 +	mov	x0, #3 << 20 +	msr	cpacr_el1, x0			/* Enable FP/SIMD */ +0: + +	/* Cache/BPB/TLB Invalidate */ +	bl	__asm_flush_dcache_all		/* dCache clean&invalidate */ +	bl	__asm_invalidate_icache_all	/* iCache invalidate */ +	bl	__asm_invalidate_tlb_all	/* invalidate TLBs */ + +	/* Processor specific initialization */ +	bl	lowlevel_init + +	branch_if_master x0, x1, master_cpu + +	/* +	 * Slave CPUs +	 */ +slave_cpu: +	wfe +	ldr	x1, =CPU_RELEASE_ADDR +	ldr	x0, [x1] +	cbz	x0, slave_cpu +	br	x0			/* branch to the given address */ + +	/* +	 * Master CPU +	 */ +master_cpu: +	bl	_main + +/*-----------------------------------------------------------------------*/ + +WEAK(lowlevel_init) +	/* Initialize GIC Secure Bank Status */ +	mov	x29, lr			/* Save LR */ +	bl	gic_init + +	branch_if_master x0, x1, 1f + +	/* +	 * Slave should wait for master clearing spin table. +	 * This sync prevent salves observing incorrect +	 * value of spin table and jumping to wrong place. +	 */ +	bl	wait_for_wakeup + +	/* +	 * All processors will enter EL2 and optionally EL1. +	 */ +	bl	armv8_switch_to_el2 +#ifdef CONFIG_ARMV8_SWITCH_TO_EL1 +	bl	armv8_switch_to_el1 +#endif + +1: +	mov	lr, x29			/* Restore LR */ +	ret +ENDPROC(lowlevel_init) + +/*-----------------------------------------------------------------------*/ + +ENTRY(c_runtime_cpu_setup) +	/* If I-cache is enabled invalidate it */ +#ifndef CONFIG_SYS_ICACHE_OFF +	ic	iallu			/* I+BTB cache invalidate */ +	isb	sy +#endif + +#ifndef CONFIG_SYS_DCACHE_OFF +	/* +	 * Setup MAIR and TCR. +	 */ +	ldr	x0, =MEMORY_ATTRIBUTES +	ldr	x1, =TCR_FLAGS + +	switch_el x2, 3f, 2f, 1f +3:	orr	x1, x1, TCR_EL3_IPS_BITS +	msr	mair_el3, x0 +	msr	tcr_el3, x1 +	b	0f +2:	orr	x1, x1, TCR_EL2_IPS_BITS +	msr	mair_el2, x0 +	msr	tcr_el2, x1 +	b	0f +1:	orr	x1, x1, TCR_EL1_IPS_BITS +	msr	mair_el1, x0 +	msr	tcr_el1, x1 +0: +#endif + +	/* Relocate vBAR */ +	adr	x0, vectors +	switch_el x1, 3f, 2f, 1f +3:	msr	vbar_el3, x0 +	b	0f +2:	msr	vbar_el2, x0 +	b	0f +1:	msr	vbar_el1, x0 +0: + +	ret +ENDPROC(c_runtime_cpu_setup) diff --git a/arch/arm/cpu/armv8/tlb.S b/arch/arm/cpu/armv8/tlb.S new file mode 100644 index 000000000..f840b04df --- /dev/null +++ b/arch/arm/cpu/armv8/tlb.S @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <version.h> +#include <linux/linkage.h> +#include <asm/macro.h> + +/* + * void __asm_invalidate_tlb_all(void) + * + * invalidate all tlb entries. + */ +ENTRY(__asm_invalidate_tlb_all) +	switch_el x9, 3f, 2f, 1f +3:	tlbi	alle3 +	dsb	sy +	isb +	b	0f +2:	tlbi	alle2 +	dsb	sy +	isb +	b	0f +1:	tlbi	vmalle1 +	dsb	sy +	isb +0: +	ret +ENDPROC(__asm_invalidate_tlb_all) diff --git a/arch/arm/cpu/armv8/transition.S b/arch/arm/cpu/armv8/transition.S new file mode 100644 index 000000000..e0a594600 --- /dev/null +++ b/arch/arm/cpu/armv8/transition.S @@ -0,0 +1,83 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <version.h> +#include <linux/linkage.h> +#include <asm/macro.h> + +ENTRY(armv8_switch_to_el2) +	switch_el x0, 1f, 0f, 0f +0:	ret +1: +	mov	x0, #0x5b1	/* Non-secure EL0/EL1 | HVC | 64bit EL2 */ +	msr	scr_el3, x0 +	msr	cptr_el3, xzr	/* Disable coprocessor traps to EL3 */ +	mov	x0, #0x33ff +	msr	cptr_el2, x0	/* Disable coprocessor traps to EL2 */ + +	/* Initialize SCTLR_EL2 */ +	msr	sctlr_el2, xzr + +	/* Return to the EL2_SP2 mode from EL3 */ +	mov	x0, sp +	msr	sp_el2, x0	/* Migrate SP */ +	mrs	x0, vbar_el3 +	msr	vbar_el2, x0	/* Migrate VBAR */ +	mov	x0, #0x3c9 +	msr	spsr_el3, x0	/* EL2_SP2 | D | A | I | F */ +	msr	elr_el3, lr +	eret +ENDPROC(armv8_switch_to_el2) + +ENTRY(armv8_switch_to_el1) +	switch_el x0, 0f, 1f, 0f +0:	ret +1: +	/* Initialize Generic Timers */ +	mrs	x0, cnthctl_el2 +	orr	x0, x0, #0x3		/* Enable EL1 access to timers */ +	msr	cnthctl_el2, x0 +	msr	cntvoff_el2, x0 +	mrs	x0, cntkctl_el1 +	orr	x0, x0, #0x3		/* Enable EL0 access to timers */ +	msr	cntkctl_el1, x0 + +	/* Initilize MPID/MPIDR registers */ +	mrs	x0, midr_el1 +	mrs	x1, mpidr_el1 +	msr	vpidr_el2, x0 +	msr	vmpidr_el2, x1 + +	/* Disable coprocessor traps */ +	mov	x0, #0x33ff +	msr	cptr_el2, x0		/* Disable coprocessor traps to EL2 */ +	msr	hstr_el2, xzr		/* Disable coprocessor traps to EL2 */ +	mov	x0, #3 << 20 +	msr	cpacr_el1, x0		/* Enable FP/SIMD at EL1 */ + +	/* Initialize HCR_EL2 */ +	mov	x0, #(1 << 31)		/* 64bit EL1 */ +	orr	x0, x0, #(1 << 29)	/* Disable HVC */ +	msr	hcr_el2, x0 + +	/* SCTLR_EL1 initialization */ +	mov	x0, #0x0800 +	movk	x0, #0x30d0, lsl #16 +	msr	sctlr_el1, x0 + +	/* Return to the EL1_SP1 mode from EL2 */ +	mov	x0, sp +	msr	sp_el1, x0		/* Migrate SP */ +	mrs	x0, vbar_el2 +	msr	vbar_el1, x0		/* Migrate VBAR */ +	mov	x0, #0x3c5 +	msr	spsr_el2, x0		/* EL1_SP1 | D | A | I | F */ +	msr	elr_el2, lr +	eret +ENDPROC(armv8_switch_to_el1) diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds new file mode 100644 index 000000000..4c1222237 --- /dev/null +++ b/arch/arm/cpu/armv8/u-boot.lds @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2013 + * David Feng <fenghua@phytium.com.cn> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_start) +SECTIONS +{ +	. = 0x00000000; + +	. = ALIGN(8); +	.text : +	{ +		*(.__image_copy_start) +		CPUDIR/start.o (.text*) +		*(.text*) +	} + +	. = ALIGN(8); +	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + +	. = ALIGN(8); +	.data : { +		*(.data*) +	} + +	. = ALIGN(8); + +	. = .; + +	. = ALIGN(8); +	.u_boot_list : { +		KEEP(*(SORT(.u_boot_list*))); +	} + +	. = ALIGN(8); + +	.image_copy_end : +	{ +		*(.__image_copy_end) +	} + +	. = ALIGN(8); + +	.rel_dyn_start : +	{ +		*(.__rel_dyn_start) +	} + +	.rela.dyn : { +		*(.rela*) +	} + +	.rel_dyn_end : +	{ +		*(.__rel_dyn_end) +	} + +	_end = .; + +	. = ALIGN(8); + +	.bss_start : { +		KEEP(*(.__bss_start)); +	} + +	.bss : { +		*(.bss*) +		 . = ALIGN(8); +	} + +	.bss_end : { +		KEEP(*(.__bss_end)); +	} + +	/DISCARD/ : { *(.dynsym) } +	/DISCARD/ : { *(.dynstr*) } +	/DISCARD/ : { *(.dynamic*) } +	/DISCARD/ : { *(.plt*) } +	/DISCARD/ : { *(.interp*) } +	/DISCARD/ : { *(.gnu*) } +} diff --git a/arch/arm/cpu/pxa/pxa2xx.c b/arch/arm/cpu/pxa/pxa2xx.c index c9a7d4539..7e861e26d 100644 --- a/arch/arm/cpu/pxa/pxa2xx.c +++ b/arch/arm/cpu/pxa/pxa2xx.c @@ -279,6 +279,7 @@ void reset_cpu(ulong ignored)  	tmp = readl(OSCR);  	tmp += 0x1000;  	writel(tmp, OSMR3); +	writel(MDREFR_SLFRSH, MDREFR);  	for (;;)  		; diff --git a/arch/arm/cpu/tegra-common/ap.c b/arch/arm/cpu/tegra-common/ap.c index 6fb11cb5c..60d71a6c3 100644 --- a/arch/arm/cpu/tegra-common/ap.c +++ b/arch/arm/cpu/tegra-common/ap.c @@ -71,6 +71,7 @@ int tegra_get_chip_sku(void)  		switch (sku_id) {  		case SKU_ID_T33:  		case SKU_ID_T30: +		case SKU_ID_TM30MQS_P_A3:  			return TEGRA_SOC_T30;  		}  		break; |