]>
Commit | Line | Data |
---|---|---|
e3963c09 PF |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2018 NXP | |
4 | */ | |
5 | ||
6 | #include <common.h> | |
f7ae49fc | 7 | #include <log.h> |
e3963c09 | 8 | #include <spl.h> |
401d1c4f | 9 | #include <asm/global_data.h> |
e3963c09 PF |
10 | #include <asm/io.h> |
11 | #include <errno.h> | |
12 | #include <asm/io.h> | |
13 | #include <asm/arch/ddr.h> | |
14 | #include <asm/arch/ddr.h> | |
15 | #include <asm/arch/lpddr4_define.h> | |
16 | #include <asm/sections.h> | |
17 | ||
18 | DECLARE_GLOBAL_DATA_PTR; | |
19 | ||
20 | #define IMEM_LEN 32768 /* byte */ | |
21 | #define DMEM_LEN 16384 /* byte */ | |
22 | #define IMEM_2D_OFFSET 49152 | |
23 | ||
24 | #define IMEM_OFFSET_ADDR 0x00050000 | |
25 | #define DMEM_OFFSET_ADDR 0x00054000 | |
26 | #define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0) | |
27 | ||
28 | /* We need PHY iMEM PHY is 32KB padded */ | |
29 | void ddr_load_train_firmware(enum fw_type type) | |
30 | { | |
31 | u32 tmp32, i; | |
32 | u32 error = 0; | |
33 | unsigned long pr_to32, pr_from32; | |
34 | unsigned long fw_offset = type ? IMEM_2D_OFFSET : 0; | |
35 | unsigned long imem_start = (unsigned long)&_end + fw_offset; | |
28cb058f PF |
36 | unsigned long dmem_start; |
37 | ||
38 | #ifdef CONFIG_SPL_OF_CONTROL | |
39 | if (gd->fdt_blob && !fdt_check_header(gd->fdt_blob)) { | |
40 | imem_start = roundup((unsigned long)&_end + | |
41 | fdt_totalsize(gd->fdt_blob), 4) + | |
42 | fw_offset; | |
43 | } | |
44 | #endif | |
45 | ||
46 | dmem_start = imem_start + IMEM_LEN; | |
e3963c09 PF |
47 | |
48 | pr_from32 = imem_start; | |
49 | pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR; | |
50 | for (i = 0x0; i < IMEM_LEN; ) { | |
51 | tmp32 = readl(pr_from32); | |
52 | writew(tmp32 & 0x0000ffff, pr_to32); | |
53 | pr_to32 += 4; | |
54 | writew((tmp32 >> 16) & 0x0000ffff, pr_to32); | |
55 | pr_to32 += 4; | |
56 | pr_from32 += 4; | |
57 | i += 4; | |
58 | } | |
59 | ||
60 | pr_from32 = dmem_start; | |
61 | pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR; | |
62 | for (i = 0x0; i < DMEM_LEN; ) { | |
63 | tmp32 = readl(pr_from32); | |
64 | writew(tmp32 & 0x0000ffff, pr_to32); | |
65 | pr_to32 += 4; | |
66 | writew((tmp32 >> 16) & 0x0000ffff, pr_to32); | |
67 | pr_to32 += 4; | |
68 | pr_from32 += 4; | |
69 | i += 4; | |
70 | } | |
71 | ||
825ab6b4 | 72 | debug("check ddr_pmu_train_imem code\n"); |
e3963c09 PF |
73 | pr_from32 = imem_start; |
74 | pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * IMEM_OFFSET_ADDR; | |
75 | for (i = 0x0; i < IMEM_LEN; ) { | |
76 | tmp32 = (readw(pr_to32) & 0x0000ffff); | |
77 | pr_to32 += 4; | |
78 | tmp32 += ((readw(pr_to32) & 0x0000ffff) << 16); | |
79 | ||
80 | if (tmp32 != readl(pr_from32)) { | |
81 | debug("%lx %lx\n", pr_from32, pr_to32); | |
82 | error++; | |
83 | } | |
84 | pr_from32 += 4; | |
85 | pr_to32 += 4; | |
86 | i += 4; | |
87 | } | |
88 | if (error) | |
825ab6b4 | 89 | printf("check ddr_pmu_train_imem code fail=%d\n", error); |
e3963c09 | 90 | else |
825ab6b4 | 91 | debug("check ddr_pmu_train_imem code pass\n"); |
e3963c09 PF |
92 | |
93 | debug("check ddr4_pmu_train_dmem code\n"); | |
94 | pr_from32 = dmem_start; | |
95 | pr_to32 = DDR_TRAIN_CODE_BASE_ADDR + 4 * DMEM_OFFSET_ADDR; | |
96 | for (i = 0x0; i < DMEM_LEN;) { | |
97 | tmp32 = (readw(pr_to32) & 0x0000ffff); | |
98 | pr_to32 += 4; | |
99 | tmp32 += ((readw(pr_to32) & 0x0000ffff) << 16); | |
100 | if (tmp32 != readl(pr_from32)) { | |
101 | debug("%lx %lx\n", pr_from32, pr_to32); | |
102 | error++; | |
103 | } | |
104 | pr_from32 += 4; | |
105 | pr_to32 += 4; | |
106 | i += 4; | |
107 | } | |
108 | ||
109 | if (error) | |
825ab6b4 | 110 | printf("check ddr_pmu_train_dmem code fail=%d", error); |
e3963c09 | 111 | else |
825ab6b4 | 112 | debug("check ddr_pmu_train_dmem code pass\n"); |
e3963c09 PF |
113 | } |
114 | ||
115 | void ddrphy_trained_csr_save(struct dram_cfg_param *ddrphy_csr, | |
116 | unsigned int num) | |
117 | { | |
118 | int i = 0; | |
119 | ||
120 | /* enable the ddrphy apb */ | |
121 | dwc_ddrphy_apb_wr(0xd0000, 0x0); | |
122 | dwc_ddrphy_apb_wr(0xc0080, 0x3); | |
123 | for (i = 0; i < num; i++) { | |
124 | ddrphy_csr->val = dwc_ddrphy_apb_rd(ddrphy_csr->reg); | |
125 | ddrphy_csr++; | |
126 | } | |
127 | /* disable the ddrphy apb */ | |
128 | dwc_ddrphy_apb_wr(0xc0080, 0x2); | |
129 | dwc_ddrphy_apb_wr(0xd0000, 0x1); | |
130 | } | |
131 | ||
132 | void dram_config_save(struct dram_timing_info *timing_info, | |
133 | unsigned long saved_timing_base) | |
134 | { | |
135 | int i = 0; | |
136 | struct dram_timing_info *saved_timing = (struct dram_timing_info *)saved_timing_base; | |
137 | struct dram_cfg_param *cfg; | |
138 | ||
139 | saved_timing->ddrc_cfg_num = timing_info->ddrc_cfg_num; | |
140 | saved_timing->ddrphy_cfg_num = timing_info->ddrphy_cfg_num; | |
141 | saved_timing->ddrphy_trained_csr_num = ddrphy_trained_csr_num; | |
142 | saved_timing->ddrphy_pie_num = timing_info->ddrphy_pie_num; | |
143 | ||
144 | /* save the fsp table */ | |
145 | for (i = 0; i < 4; i++) | |
146 | saved_timing->fsp_table[i] = timing_info->fsp_table[i]; | |
147 | ||
148 | cfg = (struct dram_cfg_param *)(saved_timing_base + | |
149 | sizeof(*timing_info)); | |
150 | ||
151 | /* save ddrc config */ | |
152 | saved_timing->ddrc_cfg = cfg; | |
153 | for (i = 0; i < timing_info->ddrc_cfg_num; i++) { | |
154 | cfg->reg = timing_info->ddrc_cfg[i].reg; | |
155 | cfg->val = timing_info->ddrc_cfg[i].val; | |
156 | cfg++; | |
157 | } | |
158 | ||
159 | /* save ddrphy config */ | |
160 | saved_timing->ddrphy_cfg = cfg; | |
161 | for (i = 0; i < timing_info->ddrphy_cfg_num; i++) { | |
162 | cfg->reg = timing_info->ddrphy_cfg[i].reg; | |
163 | cfg->val = timing_info->ddrphy_cfg[i].val; | |
164 | cfg++; | |
165 | } | |
166 | ||
167 | /* save the ddrphy csr */ | |
168 | saved_timing->ddrphy_trained_csr = cfg; | |
169 | for (i = 0; i < ddrphy_trained_csr_num; i++) { | |
170 | cfg->reg = ddrphy_trained_csr[i].reg; | |
171 | cfg->val = ddrphy_trained_csr[i].val; | |
172 | cfg++; | |
173 | } | |
174 | ||
175 | /* save the ddrphy pie */ | |
176 | saved_timing->ddrphy_pie = cfg; | |
177 | for (i = 0; i < timing_info->ddrphy_pie_num; i++) { | |
178 | cfg->reg = timing_info->ddrphy_pie[i].reg; | |
179 | cfg->val = timing_info->ddrphy_pie[i].val; | |
180 | cfg++; | |
181 | } | |
182 | } |