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