summaryrefslogtreecommitdiff
path: root/drivers/ddr/imx8m/ddrphy_utils.c
blob: b7c314ec98ae94840894009a301ee599bf6fdd83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
* Copyright 2018 NXP
*
* SPDX-License-Identifier: GPL-2.0+
*/

#include <common.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/ddr.h>
#include <asm/arch/clock.h>
#include <asm/arch/imx8m_ddr.h>
#include <asm/arch/lpddr4_define.h>

#define ddr_printf(args...) debug(args)

static inline void poll_pmu_message_ready(void)
{
	unsigned int reg;

	do {
		reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+ 4*0xd0004);
	} while (reg & 0x1);
}

static inline void ack_pmu_message_recieve(void)
{
	unsigned int reg;

	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+ 4*0xd0031, 0x0);

	do {
		reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+ 4*0xd0004);
	} while (!(reg & 0x1));

	reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+ 4*0xd0031, 0x1);
}

static inline unsigned int get_mail(void)
{
	unsigned int reg;

	poll_pmu_message_ready();

	reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+ 4*0xd0032);

	ack_pmu_message_recieve();

	return reg;
}

static inline unsigned int get_stream_message(void)
{
	unsigned int reg, reg2;

	poll_pmu_message_ready();

	reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+ 4*0xd0032);

	reg2 = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0)+ 4*0xd0034);

	reg2 = (reg2 << 16) | reg;

	ack_pmu_message_recieve();

	return reg2;
}

static inline void decode_major_message(unsigned int mail)
{
	ddr_printf("[PMU Major message = 0x%08x]\n", mail);
}

static inline void decode_streaming_message(void)
{
	unsigned int string_index, arg __maybe_unused;
	int i = 0;

	string_index = get_stream_message();
	ddr_printf("PMU String index = 0x%08x\n", string_index);
	while (i < (string_index & 0xffff)){
		arg = get_stream_message();
		ddr_printf("arg[%d] = 0x%08x\n", i, arg);
		i++;
	}

	ddr_printf("\n");
}

void wait_ddrphy_training_complete(void)
{
	unsigned int mail;
	while (1) {
		mail = get_mail();
		decode_major_message(mail);
		if (mail == 0x08) {
			decode_streaming_message();
		} else if (mail == 0x07) {
			printf("Training PASS\n");
			break;
		} else if (mail == 0xff) {
			printf("Training FAILED\n");
			break;
		}
	}
}

void ddrphy_init_set_dfi_clk(unsigned int drate)
{
	switch (drate) {
	case 3200:
		dram_pll_init(DRAM_PLL_OUT_800M);
		dram_disable_bypass();
		break;
	case 3000:
		dram_pll_init(DRAM_PLL_OUT_750M);
		dram_disable_bypass();
		break;
	case 2400:
		dram_pll_init(DRAM_PLL_OUT_600M);
		dram_disable_bypass();
		break;
	case 1600:
		dram_pll_init(DRAM_PLL_OUT_400M);
		dram_disable_bypass();
		break;
	case 667:
		dram_pll_init(DRAM_PLL_OUT_167M);
		dram_disable_bypass();
		break;
	case 400:
		dram_enable_bypass(DRAM_BYPASSCLK_400M);
		break;
	case 100:
		dram_enable_bypass(DRAM_BYPASSCLK_100M);
		break;
	default:
		return;
	}
}

void ddrphy_init_read_msg_block(enum fw_type type)
{

}

void lpddr4_mr_write(unsigned int mr_rank, unsigned int mr_addr, unsigned int mr_data)
{
	unsigned int tmp;
	/*
	 * 1. Poll MRSTAT.mr_wr_busy until it is 0.
	 * This checks that there is no outstanding MR transaction.
	 * No writes should be performed to MRCTRL0 and MRCTRL1 if
	 * MRSTAT.mr_wr_busy = 1.
	 */
	do {
		tmp = reg32_read(DDRC_MRSTAT(0));
	} while (tmp & 0x1);
	/*
	 * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank and
	 * (for MRWs) MRCTRL1.mr_data to define the MR transaction.
	 */
	reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4));
	reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data);
	reg32setbit(DDRC_MRCTRL0(0), 31);
}

unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr)
{
	unsigned int tmp;

	reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x1);
	do {
		tmp = reg32_read(DDRC_MRSTAT(0));
	} while (tmp & 0x1);

	reg32_write(DDRC_MRCTRL0(0), (mr_rank << 4) | 0x1);
	reg32_write(DDRC_MRCTRL1(0), (mr_addr << 8));
	reg32setbit(DDRC_MRCTRL0(0), 31);
	do {
		tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0));
	} while ((tmp & 0x8) == 0);
	tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0));
	tmp = tmp & 0xff;
	reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4);

	return tmp;
}