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
12int 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