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 void 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 
19 	/* initialize PHY configuration */
20 	dram_cfg = dram_timing->ddrphy_cfg;
21 	num  = dram_timing->ddrphy_cfg_num;
22 	for (i = 0; i < num; i++) {
23 		/* config phy reg */
24 		dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
25 		dram_cfg++;
26 	}
27 
28 	/* load the frequency setpoint message block config */
29 	fsp_msg = dram_timing->fsp_msg;
30 	for (i = 0; i < dram_timing->fsp_msg_num; i++) {
31 		debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
32 		/* set dram PHY input clocks to desired frequency */
33 		ddrphy_init_set_dfi_clk(fsp_msg->drate);
34 
35 		/* load the dram training firmware image */
36 		dwc_ddrphy_apb_wr(0xd0000, 0x0);
37 		ddr_load_train_firmware(fsp_msg->fw_type);
38 
39 		/* load the frequency set point message block parameter */
40 		dram_cfg = fsp_msg->fsp_cfg;
41 		num = fsp_msg->fsp_cfg_num;
42 		for (j = 0; j < num; j++) {
43 			dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
44 			dram_cfg++;
45 		}
46 
47 		/*
48 		 * -------------------- excute the firmware --------------------
49 		 * Running the firmware is a simply process to taking the
50 		 * PMU out of reset and stall, then the firwmare will be run
51 		 * 1. reset the PMU;
52 		 * 2. begin the excution;
53 		 * 3. wait for the training done;
54 		 * 4. read the message block result.
55 		 * -------------------------------------------------------------
56 		 */
57 		dwc_ddrphy_apb_wr(0xd0000, 0x1);
58 		dwc_ddrphy_apb_wr(0xd0099, 0x9);
59 		dwc_ddrphy_apb_wr(0xd0099, 0x1);
60 		dwc_ddrphy_apb_wr(0xd0099, 0x0);
61 
62 		/* Wait for the training firmware to complete */
63 		wait_ddrphy_training_complete();
64 
65 		/* Halt the microcontroller. */
66 		dwc_ddrphy_apb_wr(0xd0099, 0x1);
67 
68 		/* Read the Message Block results */
69 		dwc_ddrphy_apb_wr(0xd0000, 0x0);
70 		ddrphy_init_read_msg_block(fsp_msg->fw_type);
71 		dwc_ddrphy_apb_wr(0xd0000, 0x1);
72 
73 		fsp_msg++;
74 	}
75 
76 	/* Load PHY Init Engine Image */
77 	dram_cfg = dram_timing->ddrphy_pie;
78 	num = dram_timing->ddrphy_pie_num;
79 	for (i = 0; i < num; i++) {
80 		dwc_ddrphy_apb_wr(dram_cfg->reg, dram_cfg->val);
81 		dram_cfg++;
82 	}
83 
84 	/* save the ddr PHY trained CSR in memory for low power use */
85 	ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num);
86 }
87