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