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