bootm: Correct the arguments for the ELF image loader
[platform/kernel/u-boot.git] / arch / arm / cpu / armv7 / exynos / dmc_common.c
1 /*
2  * Mem setup common file for different types of DDR present on SMDK5250 boards.
3  *
4  * Copyright (C) 2012 Samsung Electronics
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include <common.h>
26 #include <asm/arch/spl.h>
27
28 #include "clock_init.h"
29 #include "common_setup.h"
30 #include "exynos5_setup.h"
31
32 #define ZQ_INIT_TIMEOUT 10000
33
34 int dmc_config_zq(struct mem_timings *mem,
35                   struct exynos5_phy_control *phy0_ctrl,
36                   struct exynos5_phy_control *phy1_ctrl)
37 {
38         unsigned long val = 0;
39         int i;
40
41         /*
42          * ZQ Calibration:
43          * Select Driver Strength,
44          * long calibration for manual calibration
45          */
46         val = PHY_CON16_RESET_VAL;
47         val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;
48         val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;
49         val |= ZQ_CLK_DIV_EN;
50         writel(val, &phy0_ctrl->phy_con16);
51         writel(val, &phy1_ctrl->phy_con16);
52
53         /* Disable termination */
54         if (mem->zq_mode_noterm)
55                 val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
56         writel(val, &phy0_ctrl->phy_con16);
57         writel(val, &phy1_ctrl->phy_con16);
58
59         /* ZQ_MANUAL_START: Enable */
60         val |= ZQ_MANUAL_STR;
61         writel(val, &phy0_ctrl->phy_con16);
62         writel(val, &phy1_ctrl->phy_con16);
63
64         /* ZQ_MANUAL_START: Disable */
65         val &= ~ZQ_MANUAL_STR;
66
67         /*
68          * Since we are manaully calibrating the ZQ values,
69          * we are looping for the ZQ_init to complete.
70          */
71         i = ZQ_INIT_TIMEOUT;
72         while ((readl(&phy0_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
73                 sdelay(100);
74                 i--;
75         }
76         if (!i)
77                 return -1;
78         writel(val, &phy0_ctrl->phy_con16);
79
80         i = ZQ_INIT_TIMEOUT;
81         while ((readl(&phy1_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
82                 sdelay(100);
83                 i--;
84         }
85         if (!i)
86                 return -1;
87         writel(val, &phy1_ctrl->phy_con16);
88
89         return 0;
90 }
91
92 void update_reset_dll(struct exynos5_dmc *dmc, enum ddr_mode mode)
93 {
94         unsigned long val;
95
96         if (mode == DDR_MODE_DDR3) {
97                 val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
98                 writel(val, &dmc->phycontrol0);
99         }
100
101         /* Update DLL Information: Force DLL Resyncronization */
102         val = readl(&dmc->phycontrol0);
103         val |= FP_RSYNC;
104         writel(val, &dmc->phycontrol0);
105
106         /* Reset Force DLL Resyncronization */
107         val = readl(&dmc->phycontrol0);
108         val &= ~FP_RSYNC;
109         writel(val, &dmc->phycontrol0);
110 }
111
112 void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)
113 {
114         int channel, chip;
115
116         for (channel = 0; channel < mem->dmc_channels; channel++) {
117                 unsigned long mask;
118
119                 mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
120                 for (chip = 0; chip < mem->chips_to_configure; chip++) {
121                         int i;
122
123                         mask |= chip << DIRECT_CMD_CHIP_SHIFT;
124
125                         /* Sending NOP command */
126                         writel(DIRECT_CMD_NOP | mask, &dmc->directcmd);
127
128                         /*
129                          * TODO(alim.akhtar@samsung.com): Do we need these
130                          * delays? This one and the next were not there for
131                          * DDR3.
132                          */
133                         sdelay(0x10000);
134
135                         /* Sending EMRS/MRS commands */
136                         for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
137                                 writel(mem->direct_cmd_msr[i] | mask,
138                                        &dmc->directcmd);
139                                 sdelay(0x10000);
140                         }
141
142                         if (mem->send_zq_init) {
143                                 /* Sending ZQINIT command */
144                                 writel(DIRECT_CMD_ZQINIT | mask,
145                                        &dmc->directcmd);
146
147                                 sdelay(10000);
148                         }
149                 }
150         }
151 }
152
153 void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc)
154 {
155         int channel, chip;
156
157         for (channel = 0; channel < mem->dmc_channels; channel++) {
158                 unsigned long mask;
159
160                 mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
161                 for (chip = 0; chip < mem->chips_per_channel; chip++) {
162                         mask |= chip << DIRECT_CMD_CHIP_SHIFT;
163
164                         /* PALL (all banks precharge) CMD */
165                         writel(DIRECT_CMD_PALL | mask, &dmc->directcmd);
166                         sdelay(0x10000);
167                 }
168         }
169 }
170
171 void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc)
172 {
173         writel(mem->memconfig, &dmc->memconfig0);
174         writel(mem->memconfig, &dmc->memconfig1);
175         writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0);
176         writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1);
177 }
178
179 void mem_ctrl_init(int reset)
180 {
181         struct spl_machine_param *param = spl_get_machine_params();
182         struct mem_timings *mem;
183         int ret;
184
185         mem = clock_get_mem_timings();
186
187         /* If there are any other memory variant, add their init call below */
188         if (param->mem_type == DDR_MODE_DDR3) {
189                 ret = ddr3_mem_ctrl_init(mem, param->mem_iv_size, reset);
190                 if (ret) {
191                         /* will hang if failed to init memory control */
192                         while (1)
193                                 ;
194                 }
195         } else {
196                 /* will hang if unknow memory type  */
197                 while (1)
198                         ;
199         }
200 }