SPDX: Convert all of our single license tags to Linux Kernel style
[platform/kernel/u-boot.git] / arch / arm / mach-exynos / dmc_common.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Mem setup common file for different types of DDR present on Exynos boards.
4  *
5  * Copyright (C) 2012 Samsung Electronics
6  */
7
8 #include <common.h>
9 #include <asm/arch/spl.h>
10
11 #include "clock_init.h"
12 #include "common_setup.h"
13 #include "exynos5_setup.h"
14
15 #define ZQ_INIT_TIMEOUT 10000
16
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)
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;
33         writel(val, phy0_con16);
34         writel(val, phy1_con16);
35
36         /* Disable termination */
37         if (mem->zq_mode_noterm)
38                 val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
39         writel(val, phy0_con16);
40         writel(val, phy1_con16);
41
42         /* ZQ_MANUAL_START: Enable */
43         val |= ZQ_MANUAL_STR;
44         writel(val, phy0_con16);
45         writel(val, phy1_con16);
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;
55         while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
56                 sdelay(100);
57                 i--;
58         }
59         if (!i)
60                 return -1;
61         writel(val, phy0_con16);
62
63         i = ZQ_INIT_TIMEOUT;
64         while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
65                 sdelay(100);
66                 i--;
67         }
68         if (!i)
69                 return -1;
70         writel(val, phy1_con16);
71
72         return 0;
73 }
74
75 void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode)
76 {
77         unsigned long val;
78
79         if (mode == DDR_MODE_DDR3) {
80                 val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
81                 writel(val, phycontrol0);
82         }
83
84         /* Update DLL Information: Force DLL Resyncronization */
85         val = readl(phycontrol0);
86         val |= FP_RSYNC;
87         writel(val, phycontrol0);
88
89         /* Reset Force DLL Resyncronization */
90         val = readl(phycontrol0);
91         val &= ~FP_RSYNC;
92         writel(val, phycontrol0);
93 }
94
95 void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd)
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 */
109                         writel(DIRECT_CMD_NOP | mask, directcmd);
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,
121                                        directcmd);
122                                 sdelay(0x10000);
123                         }
124
125                         if (mem->send_zq_init) {
126                                 /* Sending ZQINIT command */
127                                 writel(DIRECT_CMD_ZQINIT | mask,
128                                        directcmd);
129
130                                 sdelay(10000);
131                         }
132                 }
133         }
134 }
135
136 void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd)
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 */
148                         writel(DIRECT_CMD_PALL | mask, directcmd);
149                         sdelay(0x10000);
150                 }
151         }
152 }
153
154 void mem_ctrl_init(int reset)
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) {
164                 ret = ddr3_mem_ctrl_init(mem, reset);
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 }