]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
87f2e079 | 2 | /* |
f3d7c2fe | 3 | * Mem setup common file for different types of DDR present on Exynos boards. |
87f2e079 RS |
4 | * |
5 | * Copyright (C) 2012 Samsung Electronics | |
87f2e079 RS |
6 | */ |
7 | ||
d678a59d | 8 | #include <common.h> |
87f2e079 RS |
9 | #include <asm/arch/spl.h> |
10 | ||
11 | #include "clock_init.h" | |
643be9c0 RS |
12 | #include "common_setup.h" |
13 | #include "exynos5_setup.h" | |
87f2e079 RS |
14 | |
15 | #define ZQ_INIT_TIMEOUT 10000 | |
16 | ||
f3d7c2fe RS |
17 | int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16, |
18 | uint32_t *phy1_con16, uint32_t *phy0_con17, | |
19 | uint32_t *phy1_con17) | |
87f2e079 RS |
20 | { |
21 | unsigned long val = 0; | |
22 | int i; | |
23 | ||
24 | /* | |
25 | * ZQ Calibration: | |
26 | * Select Driver Strength, | |
27 | * long calibration for manual calibration | |
28 | */ | |
29 | val = PHY_CON16_RESET_VAL; | |
30 | val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT; | |
31 | val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT; | |
32 | val |= ZQ_CLK_DIV_EN; | |
f3d7c2fe RS |
33 | writel(val, phy0_con16); |
34 | writel(val, phy1_con16); | |
87f2e079 RS |
35 | |
36 | /* Disable termination */ | |
37 | if (mem->zq_mode_noterm) | |
38 | val |= PHY_CON16_ZQ_MODE_NOTERM_MASK; | |
f3d7c2fe RS |
39 | writel(val, phy0_con16); |
40 | writel(val, phy1_con16); | |
87f2e079 RS |
41 | |
42 | /* ZQ_MANUAL_START: Enable */ | |
43 | val |= ZQ_MANUAL_STR; | |
f3d7c2fe RS |
44 | writel(val, phy0_con16); |
45 | writel(val, phy1_con16); | |
87f2e079 RS |
46 | |
47 | /* ZQ_MANUAL_START: Disable */ | |
48 | val &= ~ZQ_MANUAL_STR; | |
49 | ||
50 | /* | |
51 | * Since we are manaully calibrating the ZQ values, | |
52 | * we are looping for the ZQ_init to complete. | |
53 | */ | |
54 | i = ZQ_INIT_TIMEOUT; | |
f3d7c2fe | 55 | while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { |
87f2e079 RS |
56 | sdelay(100); |
57 | i--; | |
58 | } | |
59 | if (!i) | |
60 | return -1; | |
f3d7c2fe | 61 | writel(val, phy0_con16); |
87f2e079 RS |
62 | |
63 | i = ZQ_INIT_TIMEOUT; | |
f3d7c2fe | 64 | while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { |
87f2e079 RS |
65 | sdelay(100); |
66 | i--; | |
67 | } | |
68 | if (!i) | |
69 | return -1; | |
f3d7c2fe | 70 | writel(val, phy1_con16); |
87f2e079 RS |
71 | |
72 | return 0; | |
73 | } | |
74 | ||
f3d7c2fe | 75 | void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode) |
87f2e079 RS |
76 | { |
77 | unsigned long val; | |
78 | ||
79 | if (mode == DDR_MODE_DDR3) { | |
80 | val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE; | |
f3d7c2fe | 81 | writel(val, phycontrol0); |
87f2e079 RS |
82 | } |
83 | ||
84 | /* Update DLL Information: Force DLL Resyncronization */ | |
f3d7c2fe | 85 | val = readl(phycontrol0); |
87f2e079 | 86 | val |= FP_RSYNC; |
f3d7c2fe | 87 | writel(val, phycontrol0); |
87f2e079 RS |
88 | |
89 | /* Reset Force DLL Resyncronization */ | |
f3d7c2fe | 90 | val = readl(phycontrol0); |
87f2e079 | 91 | val &= ~FP_RSYNC; |
f3d7c2fe | 92 | writel(val, phycontrol0); |
87f2e079 RS |
93 | } |
94 | ||
f3d7c2fe | 95 | void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd) |
87f2e079 RS |
96 | { |
97 | int channel, chip; | |
98 | ||
99 | for (channel = 0; channel < mem->dmc_channels; channel++) { | |
100 | unsigned long mask; | |
101 | ||
102 | mask = channel << DIRECT_CMD_CHANNEL_SHIFT; | |
103 | for (chip = 0; chip < mem->chips_to_configure; chip++) { | |
104 | int i; | |
105 | ||
106 | mask |= chip << DIRECT_CMD_CHIP_SHIFT; | |
107 | ||
108 | /* Sending NOP command */ | |
f3d7c2fe | 109 | writel(DIRECT_CMD_NOP | mask, directcmd); |
87f2e079 RS |
110 | |
111 | /* | |
112 | * TODO(alim.akhtar@samsung.com): Do we need these | |
113 | * delays? This one and the next were not there for | |
114 | * DDR3. | |
115 | */ | |
116 | sdelay(0x10000); | |
117 | ||
118 | /* Sending EMRS/MRS commands */ | |
119 | for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) { | |
120 | writel(mem->direct_cmd_msr[i] | mask, | |
f3d7c2fe | 121 | directcmd); |
87f2e079 RS |
122 | sdelay(0x10000); |
123 | } | |
124 | ||
125 | if (mem->send_zq_init) { | |
126 | /* Sending ZQINIT command */ | |
127 | writel(DIRECT_CMD_ZQINIT | mask, | |
f3d7c2fe | 128 | directcmd); |
87f2e079 RS |
129 | |
130 | sdelay(10000); | |
131 | } | |
132 | } | |
133 | } | |
134 | } | |
135 | ||
f3d7c2fe | 136 | void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd) |
87f2e079 RS |
137 | { |
138 | int channel, chip; | |
139 | ||
140 | for (channel = 0; channel < mem->dmc_channels; channel++) { | |
141 | unsigned long mask; | |
142 | ||
143 | mask = channel << DIRECT_CMD_CHANNEL_SHIFT; | |
144 | for (chip = 0; chip < mem->chips_per_channel; chip++) { | |
145 | mask |= chip << DIRECT_CMD_CHIP_SHIFT; | |
146 | ||
147 | /* PALL (all banks precharge) CMD */ | |
f3d7c2fe | 148 | writel(DIRECT_CMD_PALL | mask, directcmd); |
87f2e079 RS |
149 | sdelay(0x10000); |
150 | } | |
151 | } | |
152 | } | |
153 | ||
643be9c0 | 154 | void mem_ctrl_init(int reset) |
87f2e079 RS |
155 | { |
156 | struct spl_machine_param *param = spl_get_machine_params(); | |
157 | struct mem_timings *mem; | |
158 | int ret; | |
159 | ||
160 | mem = clock_get_mem_timings(); | |
161 | ||
162 | /* If there are any other memory variant, add their init call below */ | |
163 | if (param->mem_type == DDR_MODE_DDR3) { | |
cfde7588 | 164 | ret = ddr3_mem_ctrl_init(mem, reset); |
87f2e079 RS |
165 | if (ret) { |
166 | /* will hang if failed to init memory control */ | |
167 | while (1) | |
168 | ; | |
169 | } | |
170 | } else { | |
171 | /* will hang if unknow memory type */ | |
172 | while (1) | |
173 | ; | |
174 | } | |
175 | } |