xref: /openbmc/u-boot/drivers/ddr/marvell/a38x/xor.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
2f1df9364SStefan Roese /*
3f1df9364SStefan Roese  * Copyright (C) Marvell International Ltd. and its affiliates
4f1df9364SStefan Roese  */
5f1df9364SStefan Roese 
6f1df9364SStefan Roese #include <common.h>
7f1df9364SStefan Roese #include <i2c.h>
8f1df9364SStefan Roese #include <spl.h>
9f1df9364SStefan Roese #include <asm/io.h>
10f1df9364SStefan Roese #include <asm/arch/cpu.h>
11f1df9364SStefan Roese #include <asm/arch/soc.h>
12f1df9364SStefan Roese 
13f1df9364SStefan Roese #include "ddr3_init.h"
14f1df9364SStefan Roese #include "xor_regs.h"
15f1df9364SStefan Roese 
16f1df9364SStefan Roese /* defines  */
17f1df9364SStefan Roese #ifdef MV_DEBUG
18f1df9364SStefan Roese #define DB(x)	x
19f1df9364SStefan Roese #else
20f1df9364SStefan Roese #define DB(x)
21f1df9364SStefan Roese #endif
22f1df9364SStefan Roese 
23f1df9364SStefan Roese static u32 ui_xor_regs_ctrl_backup;
24f1df9364SStefan Roese static u32 ui_xor_regs_base_backup[MAX_CS];
25f1df9364SStefan Roese static u32 ui_xor_regs_mask_backup[MAX_CS];
26f1df9364SStefan Roese 
27f1df9364SStefan Roese void mv_sys_xor_init(u32 num_of_cs, u32 cs_ena, u32 cs_size, u32 base_delta)
28f1df9364SStefan Roese {
29f1df9364SStefan Roese 	u32 reg, ui, base, cs_count;
30f1df9364SStefan Roese 
31f1df9364SStefan Roese 	ui_xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
32f1df9364SStefan Roese 	for (ui = 0; ui < MAX_CS; ui++)
33f1df9364SStefan Roese 		ui_xor_regs_base_backup[ui] =
34f1df9364SStefan Roese 			reg_read(XOR_BASE_ADDR_REG(0, ui));
35f1df9364SStefan Roese 	for (ui = 0; ui < MAX_CS; ui++)
36f1df9364SStefan Roese 		ui_xor_regs_mask_backup[ui] =
37f1df9364SStefan Roese 			reg_read(XOR_SIZE_MASK_REG(0, ui));
38f1df9364SStefan Roese 
39f1df9364SStefan Roese 	reg = 0;
40f1df9364SStefan Roese 	for (ui = 0; ui < (num_of_cs); ui++) {
41f1df9364SStefan Roese 		/* Enable Window x for each CS */
42f1df9364SStefan Roese 		reg |= (0x1 << (ui));
43f1df9364SStefan Roese 		/* Enable Window x for each CS */
44f1df9364SStefan Roese 		reg |= (0x3 << ((ui * 2) + 16));
45f1df9364SStefan Roese 	}
46f1df9364SStefan Roese 
47f1df9364SStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg);
48f1df9364SStefan Roese 
49f1df9364SStefan Roese 	cs_count = 0;
50f1df9364SStefan Roese 	for (ui = 0; ui < num_of_cs; ui++) {
51f1df9364SStefan Roese 		if (cs_ena & (1 << ui)) {
52f1df9364SStefan Roese 			/*
53f1df9364SStefan Roese 			 * window x - Base - 0x00000000,
54f1df9364SStefan Roese 			 * Attribute 0x0e - DRAM
55f1df9364SStefan Roese 			 */
56f1df9364SStefan Roese 			base = cs_size * ui + base_delta;
57f1df9364SStefan Roese 			switch (ui) {
58f1df9364SStefan Roese 			case 0:
59f1df9364SStefan Roese 				base |= 0xe00;
60f1df9364SStefan Roese 				break;
61f1df9364SStefan Roese 			case 1:
62f1df9364SStefan Roese 				base |= 0xd00;
63f1df9364SStefan Roese 				break;
64f1df9364SStefan Roese 			case 2:
65f1df9364SStefan Roese 				base |= 0xb00;
66f1df9364SStefan Roese 				break;
67f1df9364SStefan Roese 			case 3:
68f1df9364SStefan Roese 				base |= 0x700;
69f1df9364SStefan Roese 				break;
70f1df9364SStefan Roese 			}
71f1df9364SStefan Roese 
72f1df9364SStefan Roese 			reg_write(XOR_BASE_ADDR_REG(0, cs_count), base);
73f1df9364SStefan Roese 
74f1df9364SStefan Roese 			/* window x - Size */
75f1df9364SStefan Roese 			reg_write(XOR_SIZE_MASK_REG(0, cs_count), 0x7fff0000);
76f1df9364SStefan Roese 			cs_count++;
77f1df9364SStefan Roese 		}
78f1df9364SStefan Roese 	}
79f1df9364SStefan Roese 
80f1df9364SStefan Roese 	mv_xor_hal_init(1);
81f1df9364SStefan Roese 
82f1df9364SStefan Roese 	return;
83f1df9364SStefan Roese }
84f1df9364SStefan Roese 
85f1df9364SStefan Roese void mv_sys_xor_finish(void)
86f1df9364SStefan Roese {
87f1df9364SStefan Roese 	u32 ui;
88f1df9364SStefan Roese 
89f1df9364SStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(0, 0), ui_xor_regs_ctrl_backup);
90f1df9364SStefan Roese 	for (ui = 0; ui < MAX_CS; ui++)
91f1df9364SStefan Roese 		reg_write(XOR_BASE_ADDR_REG(0, ui),
92f1df9364SStefan Roese 			  ui_xor_regs_base_backup[ui]);
93f1df9364SStefan Roese 	for (ui = 0; ui < MAX_CS; ui++)
94f1df9364SStefan Roese 		reg_write(XOR_SIZE_MASK_REG(0, ui),
95f1df9364SStefan Roese 			  ui_xor_regs_mask_backup[ui]);
96f1df9364SStefan Roese 
97f1df9364SStefan Roese 	reg_write(XOR_ADDR_OVRD_REG(0, 0), 0);
98f1df9364SStefan Roese }
99f1df9364SStefan Roese 
100f1df9364SStefan Roese /*
101f1df9364SStefan Roese  * mv_xor_hal_init - Initialize XOR engine
102f1df9364SStefan Roese  *
103f1df9364SStefan Roese  * DESCRIPTION:
104f1df9364SStefan Roese  *               This function initialize XOR unit.
105f1df9364SStefan Roese  * INPUT:
106f1df9364SStefan Roese  *       None.
107f1df9364SStefan Roese  *
108f1df9364SStefan Roese  * OUTPUT:
109f1df9364SStefan Roese  *       None.
110f1df9364SStefan Roese  *
111f1df9364SStefan Roese  * RETURN:
112f1df9364SStefan Roese  *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
113f1df9364SStefan Roese  */
114f1df9364SStefan Roese void mv_xor_hal_init(u32 xor_chan_num)
115f1df9364SStefan Roese {
116f1df9364SStefan Roese 	u32 i;
117f1df9364SStefan Roese 
118f1df9364SStefan Roese 	/* Abort any XOR activity & set default configuration */
119f1df9364SStefan Roese 	for (i = 0; i < xor_chan_num; i++) {
120f1df9364SStefan Roese 		mv_xor_command_set(i, MV_STOP);
121f1df9364SStefan Roese 		mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) |
122f1df9364SStefan Roese 				(4 << XEXCR_DST_BURST_LIMIT_OFFS) |
123f1df9364SStefan Roese 				(4 << XEXCR_SRC_BURST_LIMIT_OFFS));
124f1df9364SStefan Roese 	}
125f1df9364SStefan Roese }
126f1df9364SStefan Roese 
127f1df9364SStefan Roese /*
128f1df9364SStefan Roese  * mv_xor_ctrl_set - Set XOR channel control registers
129f1df9364SStefan Roese  *
130f1df9364SStefan Roese  * DESCRIPTION:
131f1df9364SStefan Roese  *
132f1df9364SStefan Roese  * INPUT:
133f1df9364SStefan Roese  *
134f1df9364SStefan Roese  * OUTPUT:
135f1df9364SStefan Roese  *       None.
136f1df9364SStefan Roese  *
137f1df9364SStefan Roese  * RETURN:
138f1df9364SStefan Roese  *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
139f1df9364SStefan Roese  * NOTE:
140f1df9364SStefan Roese  *  This function does not modify the Operation_mode field of control register.
141f1df9364SStefan Roese  */
142f1df9364SStefan Roese int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
143f1df9364SStefan Roese {
144f1df9364SStefan Roese 	u32 old_value;
145f1df9364SStefan Roese 
146f1df9364SStefan Roese 	/* update the XOR Engine [0..1] Configuration Registers (XEx_c_r) */
147f1df9364SStefan Roese 	old_value = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))) &
148f1df9364SStefan Roese 		XEXCR_OPERATION_MODE_MASK;
149f1df9364SStefan Roese 	xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
150f1df9364SStefan Roese 	xor_ctrl |= old_value;
151f1df9364SStefan Roese 	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl);
152f1df9364SStefan Roese 
153f1df9364SStefan Roese 	return MV_OK;
154f1df9364SStefan Roese }
155f1df9364SStefan Roese 
156f1df9364SStefan Roese int mv_xor_mem_init(u32 chan, u32 start_ptr, u32 block_size,
157f1df9364SStefan Roese 		    u32 init_val_high, u32 init_val_low)
158f1df9364SStefan Roese {
159f1df9364SStefan Roese 	u32 temp;
160f1df9364SStefan Roese 
161f1df9364SStefan Roese 	/* Parameter checking */
162f1df9364SStefan Roese 	if (chan >= MV_XOR_MAX_CHAN)
163f1df9364SStefan Roese 		return MV_BAD_PARAM;
164f1df9364SStefan Roese 
165f1df9364SStefan Roese 	if (MV_ACTIVE == mv_xor_state_get(chan))
166f1df9364SStefan Roese 		return MV_BUSY;
167f1df9364SStefan Roese 
168f1df9364SStefan Roese 	if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) ||
169f1df9364SStefan Roese 	    (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE))
170f1df9364SStefan Roese 		return MV_BAD_PARAM;
171f1df9364SStefan Roese 
172f1df9364SStefan Roese 	/* set the operation mode to Memory Init */
173f1df9364SStefan Roese 	temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
174f1df9364SStefan Roese 	temp &= ~XEXCR_OPERATION_MODE_MASK;
175f1df9364SStefan Roese 	temp |= XEXCR_OPERATION_MODE_MEM_INIT;
176f1df9364SStefan Roese 	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp);
177f1df9364SStefan Roese 
178f1df9364SStefan Roese 	/*
179f1df9364SStefan Roese 	 * update the start_ptr field in XOR Engine [0..1] Destination Pointer
180f1df9364SStefan Roese 	 * Register
181f1df9364SStefan Roese 	 */
182f1df9364SStefan Roese 	reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
183f1df9364SStefan Roese 
184f1df9364SStefan Roese 	/*
185f1df9364SStefan Roese 	 * update the Block_size field in the XOR Engine[0..1] Block Size
186f1df9364SStefan Roese 	 * Registers
187f1df9364SStefan Roese 	 */
188f1df9364SStefan Roese 	reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
189f1df9364SStefan Roese 		  block_size);
190f1df9364SStefan Roese 
191f1df9364SStefan Roese 	/*
192f1df9364SStefan Roese 	 * update the field Init_val_l in the XOR Engine Initial Value Register
193f1df9364SStefan Roese 	 * Low (XEIVRL)
194f1df9364SStefan Roese 	 */
195f1df9364SStefan Roese 	reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low);
196f1df9364SStefan Roese 
197f1df9364SStefan Roese 	/*
198f1df9364SStefan Roese 	 * update the field Init_val_h in the XOR Engine Initial Value Register
199f1df9364SStefan Roese 	 * High (XEIVRH)
200f1df9364SStefan Roese 	 */
201f1df9364SStefan Roese 	reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high);
202f1df9364SStefan Roese 
203f1df9364SStefan Roese 	/* start transfer */
204f1df9364SStefan Roese 	reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
205f1df9364SStefan Roese 		    XEXACTR_XESTART_MASK);
206f1df9364SStefan Roese 
207f1df9364SStefan Roese 	return MV_OK;
208f1df9364SStefan Roese }
209f1df9364SStefan Roese 
210f1df9364SStefan Roese /*
211f1df9364SStefan Roese  * mv_xor_state_get - Get XOR channel state.
212f1df9364SStefan Roese  *
213f1df9364SStefan Roese  * DESCRIPTION:
214f1df9364SStefan Roese  *       XOR channel activity state can be active, idle, paused.
215f1df9364SStefan Roese  *       This function retrunes the channel activity state.
216f1df9364SStefan Roese  *
217f1df9364SStefan Roese  * INPUT:
218f1df9364SStefan Roese  *       chan     - the channel number
219f1df9364SStefan Roese  *
220f1df9364SStefan Roese  * OUTPUT:
221f1df9364SStefan Roese  *       None.
222f1df9364SStefan Roese  *
223f1df9364SStefan Roese  * RETURN:
224f1df9364SStefan Roese  *       XOR_CHANNEL_IDLE    - If the engine is idle.
225f1df9364SStefan Roese  *       XOR_CHANNEL_ACTIVE  - If the engine is busy.
226f1df9364SStefan Roese  *       XOR_CHANNEL_PAUSED  - If the engine is paused.
227f1df9364SStefan Roese  *       MV_UNDEFINED_STATE  - If the engine state is undefind or there is no
228f1df9364SStefan Roese  *                             such engine
229f1df9364SStefan Roese  */
230f1df9364SStefan Roese enum mv_state mv_xor_state_get(u32 chan)
231f1df9364SStefan Roese {
232f1df9364SStefan Roese 	u32 state;
233f1df9364SStefan Roese 
234f1df9364SStefan Roese 	/* Parameter checking   */
235f1df9364SStefan Roese 	if (chan >= MV_XOR_MAX_CHAN) {
236f1df9364SStefan Roese 		DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
237f1df9364SStefan Roese 		return MV_UNDEFINED_STATE;
238f1df9364SStefan Roese 	}
239f1df9364SStefan Roese 
240f1df9364SStefan Roese 	/* read the current state */
241f1df9364SStefan Roese 	state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
242f1df9364SStefan Roese 	state &= XEXACTR_XESTATUS_MASK;
243f1df9364SStefan Roese 
244f1df9364SStefan Roese 	/* return the state */
245f1df9364SStefan Roese 	switch (state) {
246f1df9364SStefan Roese 	case XEXACTR_XESTATUS_IDLE:
247f1df9364SStefan Roese 		return MV_IDLE;
248f1df9364SStefan Roese 	case XEXACTR_XESTATUS_ACTIVE:
249f1df9364SStefan Roese 		return MV_ACTIVE;
250f1df9364SStefan Roese 	case XEXACTR_XESTATUS_PAUSED:
251f1df9364SStefan Roese 		return MV_PAUSED;
252f1df9364SStefan Roese 	}
253f1df9364SStefan Roese 
254f1df9364SStefan Roese 	return MV_UNDEFINED_STATE;
255f1df9364SStefan Roese }
256f1df9364SStefan Roese 
257f1df9364SStefan Roese /*
258f1df9364SStefan Roese  * mv_xor_command_set - Set command of XOR channel
259f1df9364SStefan Roese  *
260f1df9364SStefan Roese  * DESCRIPTION:
261f1df9364SStefan Roese  *       XOR channel can be started, idle, paused and restarted.
262f1df9364SStefan Roese  *       Paused can be set only if channel is active.
263f1df9364SStefan Roese  *       Start can be set only if channel is idle or paused.
264f1df9364SStefan Roese  *       Restart can be set only if channel is paused.
265f1df9364SStefan Roese  *       Stop can be set only if channel is active.
266f1df9364SStefan Roese  *
267f1df9364SStefan Roese  * INPUT:
268f1df9364SStefan Roese  *       chan     - The channel number
269f1df9364SStefan Roese  *       command  - The command type (start, stop, restart, pause)
270f1df9364SStefan Roese  *
271f1df9364SStefan Roese  * OUTPUT:
272f1df9364SStefan Roese  *       None.
273f1df9364SStefan Roese  *
274f1df9364SStefan Roese  * RETURN:
275f1df9364SStefan Roese  *       MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on
276f1df9364SStefan Roese  *       undefind XOR engine mode
277f1df9364SStefan Roese  */
278f1df9364SStefan Roese int mv_xor_command_set(u32 chan, enum mv_command command)
279f1df9364SStefan Roese {
280f1df9364SStefan Roese 	enum mv_state state;
281f1df9364SStefan Roese 
282f1df9364SStefan Roese 	/* Parameter checking */
283f1df9364SStefan Roese 	if (chan >= MV_XOR_MAX_CHAN) {
284f1df9364SStefan Roese 		DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
285f1df9364SStefan Roese 		return MV_BAD_PARAM;
286f1df9364SStefan Roese 	}
287f1df9364SStefan Roese 
288f1df9364SStefan Roese 	/* get the current state */
289f1df9364SStefan Roese 	state = mv_xor_state_get(chan);
290f1df9364SStefan Roese 
291f1df9364SStefan Roese 	if ((command == MV_START) && (state == MV_IDLE)) {
292f1df9364SStefan Roese 		/* command is start and current state is idle */
293f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
294f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
295f1df9364SStefan Roese 			    XEXACTR_XESTART_MASK);
296f1df9364SStefan Roese 		return MV_OK;
297f1df9364SStefan Roese 	} else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
298f1df9364SStefan Roese 		/* command is stop and current state is active */
299f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
300f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
301f1df9364SStefan Roese 			    XEXACTR_XESTOP_MASK);
302f1df9364SStefan Roese 		return MV_OK;
303f1df9364SStefan Roese 	} else if (((enum mv_state)command == MV_PAUSED) &&
304f1df9364SStefan Roese 		   (state == MV_ACTIVE)) {
305f1df9364SStefan Roese 		/* command is paused and current state is active */
306f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
307f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
308f1df9364SStefan Roese 			    XEXACTR_XEPAUSE_MASK);
309f1df9364SStefan Roese 		return MV_OK;
310f1df9364SStefan Roese 	} else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
311f1df9364SStefan Roese 		/* command is restart and current state is paused */
312f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
313f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
314f1df9364SStefan Roese 			    XEXACTR_XERESTART_MASK);
315f1df9364SStefan Roese 		return MV_OK;
316f1df9364SStefan Roese 	} else if ((command == MV_STOP) && (state == MV_IDLE)) {
317f1df9364SStefan Roese 		/* command is stop and current state is active */
318f1df9364SStefan Roese 		return MV_OK;
319f1df9364SStefan Roese 	}
320f1df9364SStefan Roese 
321f1df9364SStefan Roese 	/* illegal command */
322f1df9364SStefan Roese 	DB(printf("%s: ERR. Illegal command\n", __func__));
323f1df9364SStefan Roese 
324f1df9364SStefan Roese 	return MV_BAD_PARAM;
325f1df9364SStefan Roese }
326f1df9364SStefan Roese 
327f1df9364SStefan Roese void ddr3_new_tip_ecc_scrub(void)
328f1df9364SStefan Roese {
329f1df9364SStefan Roese 	u32 cs_c, max_cs;
330f1df9364SStefan Roese 	u32 cs_ena = 0;
331f1df9364SStefan Roese 
332f1df9364SStefan Roese 	printf("DDR3 Training Sequence - Start scrubbing\n");
333f1df9364SStefan Roese 
334f1df9364SStefan Roese 	max_cs = hws_ddr3_tip_max_cs_get();
335f1df9364SStefan Roese 	for (cs_c = 0; cs_c < max_cs; cs_c++)
336f1df9364SStefan Roese 		cs_ena |= 1 << cs_c;
337f1df9364SStefan Roese 
338f1df9364SStefan Roese 	mv_sys_xor_init(max_cs, cs_ena, 0x80000000, 0);
339f1df9364SStefan Roese 
340f1df9364SStefan Roese 	mv_xor_mem_init(0, 0x00000000, 0x80000000, 0xdeadbeef, 0xdeadbeef);
341f1df9364SStefan Roese 	/* wait for previous transfer completion */
342f1df9364SStefan Roese 	while (mv_xor_state_get(0) != MV_IDLE)
343f1df9364SStefan Roese 		;
344f1df9364SStefan Roese 
345f1df9364SStefan Roese 	mv_xor_mem_init(0, 0x80000000, 0x40000000, 0xdeadbeef, 0xdeadbeef);
346f1df9364SStefan Roese 
347f1df9364SStefan Roese 	/* wait for previous transfer completion */
348f1df9364SStefan Roese 	while (mv_xor_state_get(0) != MV_IDLE)
349f1df9364SStefan Roese 		;
350f1df9364SStefan Roese 
351f1df9364SStefan Roese 	/* Return XOR State */
352f1df9364SStefan Roese 	mv_sys_xor_finish();
353f1df9364SStefan Roese 
354f1df9364SStefan Roese 	printf("DDR3 Training Sequence - End scrubbing\n");
355f1df9364SStefan Roese }
356