Merge tag 'u-boot-imx-20200107' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
[oweals/u-boot.git] / drivers / ddr / imx / imx8m / ddrphy_train.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2018 NXP
4  */
5
6 #include <common.h>
7 #include <linux/kernel.h>
8 #include <asm/arch/ddr.h>
9 #include <asm/arch/lpddr4_define.h>
10
11 int ddr_cfg_phy(struct dram_timing_info *dram_timing)
12 {
13         struct dram_cfg_param *dram_cfg;
14         struct dram_fsp_msg *fsp_msg;
15         unsigned int num;
16         int i = 0;
17         int j = 0;
18         int ret;
19
20         /* initialize PHY configuration */
21         dram_cfg = dram_timing->ddrphy_cfg;
22         num  = dram_timing->ddrphy_cfg_num;
23         for (i = 0; i < num; i++) {
24                 /* config phy reg */
25                 dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
26                 dram_cfg++;
27         }
28
29         /* load the frequency setpoint message block config */
30         fsp_msg = dram_timing->fsp_msg;
31         for (i = 0; i < dram_timing->fsp_msg_num; i++) {
32                 debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
33                 /* set dram PHY input clocks to desired frequency */
34                 ddrphy_init_set_dfi_clk(fsp_msg->drate);
35
36                 /* load the dram training firmware image */
37                 dwc_ddrphy_apb_wr(0xd0000, 0x0);
38                 ddr_load_train_firmware(fsp_msg->fw_type);
39
40                 /* load the frequency set point message block parameter */
41                 dram_cfg = fsp_msg->fsp_cfg;
42                 num = fsp_msg->fsp_cfg_num;
43                 for (j = 0; j < num; j++) {
44                         dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
45                         dram_cfg++;
46                 }
47
48                 /*
49                  * -------------------- excute the firmware --------------------
50                  * Running the firmware is a simply process to taking the
51                  * PMU out of reset and stall, then the firwmare will be run
52                  * 1. reset the PMU;
53                  * 2. begin the excution;
54                  * 3. wait for the training done;
55                  * 4. read the message block result.
56                  * -------------------------------------------------------------
57                  */
58                 dwc_ddrphy_apb_wr(0xd0000, 0x1);
59                 dwc_ddrphy_apb_wr(0xd0099, 0x9);
60                 dwc_ddrphy_apb_wr(0xd0099, 0x1);
61                 dwc_ddrphy_apb_wr(0xd0099, 0x0);
62
63                 /* Wait for the training firmware to complete */
64                 ret = wait_ddrphy_training_complete();
65                 if (ret)
66                         return ret;
67
68                 /* Halt the microcontroller. */
69                 dwc_ddrphy_apb_wr(0xd0099, 0x1);
70
71                 /* Read the Message Block results */
72                 dwc_ddrphy_apb_wr(0xd0000, 0x0);
73                 ddrphy_init_read_msg_block(fsp_msg->fw_type);
74                 dwc_ddrphy_apb_wr(0xd0000, 0x1);
75
76                 fsp_msg++;
77         }
78
79         /* Load PHY Init Engine Image */
80         dram_cfg = dram_timing->ddrphy_pie;
81         num = dram_timing->ddrphy_pie_num;
82         for (i = 0; i < num; i++) {
83                 dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
84                 dram_cfg++;
85         }
86
87         /* save the ddr PHY trained CSR in memory for low power use */
88         ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num);
89
90         return 0;
91 }