xref: /openbmc/u-boot/drivers/ddr/marvell/a38x/xor.c (revision db363dbc)
183d290c5STom 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 "ddr3_init.h"
7f1df9364SStefan Roese #include "xor_regs.h"
8f1df9364SStefan Roese 
9f1df9364SStefan Roese /* defines  */
10f1df9364SStefan Roese #ifdef MV_DEBUG
11f1df9364SStefan Roese #define DB(x)	x
12f1df9364SStefan Roese #else
13f1df9364SStefan Roese #define DB(x)
14f1df9364SStefan Roese #endif
15f1df9364SStefan Roese 
16f1df9364SStefan Roese static u32 ui_xor_regs_ctrl_backup;
172b4ffbf6SChris Packham static u32 ui_xor_regs_base_backup[MAX_CS_NUM + 1];
182b4ffbf6SChris Packham static u32 ui_xor_regs_mask_backup[MAX_CS_NUM + 1];
19f1df9364SStefan Roese 
202b4ffbf6SChris Packham void mv_sys_xor_init(u32 num_of_cs, u32 cs_ena, uint64_t cs_size, u32 base_delta)
21f1df9364SStefan Roese {
222b4ffbf6SChris Packham 	u32 reg, ui, cs_count;
232b4ffbf6SChris Packham 	uint64_t base, size_mask;
24f1df9364SStefan Roese 
25f1df9364SStefan Roese 	ui_xor_regs_ctrl_backup = reg_read(XOR_WINDOW_CTRL_REG(0, 0));
262b4ffbf6SChris Packham 	for (ui = 0; ui < MAX_CS_NUM + 1; ui++)
27f1df9364SStefan Roese 		ui_xor_regs_base_backup[ui] =
28f1df9364SStefan Roese 			reg_read(XOR_BASE_ADDR_REG(0, ui));
292b4ffbf6SChris Packham 	for (ui = 0; ui < MAX_CS_NUM + 1; ui++)
30f1df9364SStefan Roese 		ui_xor_regs_mask_backup[ui] =
31f1df9364SStefan Roese 			reg_read(XOR_SIZE_MASK_REG(0, ui));
32f1df9364SStefan Roese 
33f1df9364SStefan Roese 	reg = 0;
342b4ffbf6SChris Packham 	for (ui = 0, cs_count = 0;
352b4ffbf6SChris Packham 	     (cs_count < num_of_cs) && (ui < 8);
362b4ffbf6SChris Packham 	     ui++, cs_count++) {
372b4ffbf6SChris Packham 		if (cs_ena & (1 << ui)) {
38f1df9364SStefan Roese 			/* Enable Window x for each CS */
39f1df9364SStefan Roese 			reg |= (0x1 << (ui));
40f1df9364SStefan Roese 			/* Enable Window x for each CS */
41f1df9364SStefan Roese 			reg |= (0x3 << ((ui * 2) + 16));
42f1df9364SStefan Roese 		}
432b4ffbf6SChris Packham 	}
44f1df9364SStefan Roese 
45f1df9364SStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(0, 0), reg);
46f1df9364SStefan Roese 
47f1df9364SStefan Roese 	cs_count = 0;
482b4ffbf6SChris Packham 	for (ui = 0, cs_count = 0;
492b4ffbf6SChris Packham 	     (cs_count < num_of_cs) && (ui < 8);
502b4ffbf6SChris Packham 	     ui++, cs_count++) {
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;
572b4ffbf6SChris Packham 			/* fixed size 2GB for each CS */
582b4ffbf6SChris Packham 			size_mask = 0x7FFF0000;
59f1df9364SStefan Roese 			switch (ui) {
60f1df9364SStefan Roese 			case 0:
61f1df9364SStefan Roese 				base |= 0xe00;
62f1df9364SStefan Roese 				break;
63f1df9364SStefan Roese 			case 1:
64f1df9364SStefan Roese 				base |= 0xd00;
65f1df9364SStefan Roese 				break;
66f1df9364SStefan Roese 			case 2:
67f1df9364SStefan Roese 				base |= 0xb00;
68f1df9364SStefan Roese 				break;
69f1df9364SStefan Roese 			case 3:
70f1df9364SStefan Roese 				base |= 0x700;
71f1df9364SStefan Roese 				break;
722b4ffbf6SChris Packham 			case 4: /* SRAM */
732b4ffbf6SChris Packham 				base = 0x40000000;
742b4ffbf6SChris Packham 				/* configure as shared transaction */
752b4ffbf6SChris Packham 				base |= 0x1F00;
762b4ffbf6SChris Packham 				size_mask = 0xF0000;
772b4ffbf6SChris Packham 				break;
78f1df9364SStefan Roese 			}
79f1df9364SStefan Roese 
802b4ffbf6SChris Packham 			reg_write(XOR_BASE_ADDR_REG(0, ui), (u32)base);
812b4ffbf6SChris Packham 			size_mask = (cs_size / _64K) - 1;
822b4ffbf6SChris Packham 			size_mask = (size_mask << XESMRX_SIZE_MASK_OFFS) & XESMRX_SIZE_MASK_MASK;
83f1df9364SStefan Roese 			/* window x - Size */
842b4ffbf6SChris Packham 			reg_write(XOR_SIZE_MASK_REG(0, ui), (u32)size_mask);
85f1df9364SStefan Roese 		}
86f1df9364SStefan Roese 	}
87f1df9364SStefan Roese 
88f1df9364SStefan Roese 	mv_xor_hal_init(1);
89f1df9364SStefan Roese 
90f1df9364SStefan Roese 	return;
91f1df9364SStefan Roese }
92f1df9364SStefan Roese 
93f1df9364SStefan Roese void mv_sys_xor_finish(void)
94f1df9364SStefan Roese {
95f1df9364SStefan Roese 	u32 ui;
96f1df9364SStefan Roese 
97f1df9364SStefan Roese 	reg_write(XOR_WINDOW_CTRL_REG(0, 0), ui_xor_regs_ctrl_backup);
982b4ffbf6SChris Packham 	for (ui = 0; ui < MAX_CS_NUM + 1; ui++)
99f1df9364SStefan Roese 		reg_write(XOR_BASE_ADDR_REG(0, ui),
100f1df9364SStefan Roese 			  ui_xor_regs_base_backup[ui]);
1012b4ffbf6SChris Packham 	for (ui = 0; ui < MAX_CS_NUM + 1; ui++)
102f1df9364SStefan Roese 		reg_write(XOR_SIZE_MASK_REG(0, ui),
103f1df9364SStefan Roese 			  ui_xor_regs_mask_backup[ui]);
104f1df9364SStefan Roese 
105f1df9364SStefan Roese 	reg_write(XOR_ADDR_OVRD_REG(0, 0), 0);
106f1df9364SStefan Roese }
107f1df9364SStefan Roese 
108f1df9364SStefan Roese /*
109f1df9364SStefan Roese  * mv_xor_hal_init - Initialize XOR engine
110f1df9364SStefan Roese  *
111f1df9364SStefan Roese  * DESCRIPTION:
112f1df9364SStefan Roese  *               This function initialize XOR unit.
113f1df9364SStefan Roese  * INPUT:
114f1df9364SStefan Roese  *       None.
115f1df9364SStefan Roese  *
116f1df9364SStefan Roese  * OUTPUT:
117f1df9364SStefan Roese  *       None.
118f1df9364SStefan Roese  *
119f1df9364SStefan Roese  * RETURN:
120f1df9364SStefan Roese  *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
121f1df9364SStefan Roese  */
122f1df9364SStefan Roese void mv_xor_hal_init(u32 xor_chan_num)
123f1df9364SStefan Roese {
124f1df9364SStefan Roese 	u32 i;
125f1df9364SStefan Roese 
126f1df9364SStefan Roese 	/* Abort any XOR activity & set default configuration */
127f1df9364SStefan Roese 	for (i = 0; i < xor_chan_num; i++) {
128f1df9364SStefan Roese 		mv_xor_command_set(i, MV_STOP);
129f1df9364SStefan Roese 		mv_xor_ctrl_set(i, (1 << XEXCR_REG_ACC_PROTECT_OFFS) |
130f1df9364SStefan Roese 				(4 << XEXCR_DST_BURST_LIMIT_OFFS) |
131f1df9364SStefan Roese 				(4 << XEXCR_SRC_BURST_LIMIT_OFFS));
132f1df9364SStefan Roese 	}
133f1df9364SStefan Roese }
134f1df9364SStefan Roese 
135f1df9364SStefan Roese /*
136f1df9364SStefan Roese  * mv_xor_ctrl_set - Set XOR channel control registers
137f1df9364SStefan Roese  *
138f1df9364SStefan Roese  * DESCRIPTION:
139f1df9364SStefan Roese  *
140f1df9364SStefan Roese  * INPUT:
141f1df9364SStefan Roese  *
142f1df9364SStefan Roese  * OUTPUT:
143f1df9364SStefan Roese  *       None.
144f1df9364SStefan Roese  *
145f1df9364SStefan Roese  * RETURN:
146f1df9364SStefan Roese  *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
147f1df9364SStefan Roese  * NOTE:
148f1df9364SStefan Roese  *  This function does not modify the Operation_mode field of control register.
149f1df9364SStefan Roese  */
150f1df9364SStefan Roese int mv_xor_ctrl_set(u32 chan, u32 xor_ctrl)
151f1df9364SStefan Roese {
152f1df9364SStefan Roese 	u32 old_value;
153f1df9364SStefan Roese 
154f1df9364SStefan Roese 	/* update the XOR Engine [0..1] Configuration Registers (XEx_c_r) */
155f1df9364SStefan Roese 	old_value = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan))) &
156f1df9364SStefan Roese 		XEXCR_OPERATION_MODE_MASK;
157f1df9364SStefan Roese 	xor_ctrl &= ~XEXCR_OPERATION_MODE_MASK;
158f1df9364SStefan Roese 	xor_ctrl |= old_value;
159f1df9364SStefan Roese 	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), xor_ctrl);
160f1df9364SStefan Roese 
161f1df9364SStefan Roese 	return MV_OK;
162f1df9364SStefan Roese }
163f1df9364SStefan Roese 
1642b4ffbf6SChris Packham int mv_xor_mem_init(u32 chan, u32 start_ptr, unsigned long long block_size,
165f1df9364SStefan Roese 		    u32 init_val_high, u32 init_val_low)
166f1df9364SStefan Roese {
167f1df9364SStefan Roese 	u32 temp;
168f1df9364SStefan Roese 
1692b4ffbf6SChris Packham 	if (block_size == _4G)
1702b4ffbf6SChris Packham 		block_size -= 1;
1712b4ffbf6SChris Packham 
172f1df9364SStefan Roese 	/* Parameter checking */
173f1df9364SStefan Roese 	if (chan >= MV_XOR_MAX_CHAN)
174f1df9364SStefan Roese 		return MV_BAD_PARAM;
175f1df9364SStefan Roese 
176f1df9364SStefan Roese 	if (MV_ACTIVE == mv_xor_state_get(chan))
177f1df9364SStefan Roese 		return MV_BUSY;
178f1df9364SStefan Roese 
179f1df9364SStefan Roese 	if ((block_size < XEXBSR_BLOCK_SIZE_MIN_VALUE) ||
180f1df9364SStefan Roese 	    (block_size > XEXBSR_BLOCK_SIZE_MAX_VALUE))
181f1df9364SStefan Roese 		return MV_BAD_PARAM;
182f1df9364SStefan Roese 
183f1df9364SStefan Roese 	/* set the operation mode to Memory Init */
184f1df9364SStefan Roese 	temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
185f1df9364SStefan Roese 	temp &= ~XEXCR_OPERATION_MODE_MASK;
186f1df9364SStefan Roese 	temp |= XEXCR_OPERATION_MODE_MEM_INIT;
187f1df9364SStefan Roese 	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp);
188f1df9364SStefan Roese 
189f1df9364SStefan Roese 	/*
190f1df9364SStefan Roese 	 * update the start_ptr field in XOR Engine [0..1] Destination Pointer
191f1df9364SStefan Roese 	 * Register
192f1df9364SStefan Roese 	 */
193f1df9364SStefan Roese 	reg_write(XOR_DST_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)), start_ptr);
194f1df9364SStefan Roese 
195f1df9364SStefan Roese 	/*
196f1df9364SStefan Roese 	 * update the Block_size field in the XOR Engine[0..1] Block Size
197f1df9364SStefan Roese 	 * Registers
198f1df9364SStefan Roese 	 */
199f1df9364SStefan Roese 	reg_write(XOR_BLOCK_SIZE_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
200f1df9364SStefan Roese 		  block_size);
201f1df9364SStefan Roese 
202f1df9364SStefan Roese 	/*
203f1df9364SStefan Roese 	 * update the field Init_val_l in the XOR Engine Initial Value Register
204f1df9364SStefan Roese 	 * Low (XEIVRL)
205f1df9364SStefan Roese 	 */
206f1df9364SStefan Roese 	reg_write(XOR_INIT_VAL_LOW_REG(XOR_UNIT(chan)), init_val_low);
207f1df9364SStefan Roese 
208f1df9364SStefan Roese 	/*
209f1df9364SStefan Roese 	 * update the field Init_val_h in the XOR Engine Initial Value Register
210f1df9364SStefan Roese 	 * High (XEIVRH)
211f1df9364SStefan Roese 	 */
212f1df9364SStefan Roese 	reg_write(XOR_INIT_VAL_HIGH_REG(XOR_UNIT(chan)), init_val_high);
213f1df9364SStefan Roese 
214f1df9364SStefan Roese 	/* start transfer */
215f1df9364SStefan Roese 	reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
216f1df9364SStefan Roese 		    XEXACTR_XESTART_MASK);
217f1df9364SStefan Roese 
218f1df9364SStefan Roese 	return MV_OK;
219f1df9364SStefan Roese }
220f1df9364SStefan Roese 
221f1df9364SStefan Roese /*
222f1df9364SStefan Roese  * mv_xor_state_get - Get XOR channel state.
223f1df9364SStefan Roese  *
224f1df9364SStefan Roese  * DESCRIPTION:
225f1df9364SStefan Roese  *       XOR channel activity state can be active, idle, paused.
226f1df9364SStefan Roese  *       This function retrunes the channel activity state.
227f1df9364SStefan Roese  *
228f1df9364SStefan Roese  * INPUT:
229f1df9364SStefan Roese  *       chan     - the channel number
230f1df9364SStefan Roese  *
231f1df9364SStefan Roese  * OUTPUT:
232f1df9364SStefan Roese  *       None.
233f1df9364SStefan Roese  *
234f1df9364SStefan Roese  * RETURN:
235f1df9364SStefan Roese  *       XOR_CHANNEL_IDLE    - If the engine is idle.
236f1df9364SStefan Roese  *       XOR_CHANNEL_ACTIVE  - If the engine is busy.
237f1df9364SStefan Roese  *       XOR_CHANNEL_PAUSED  - If the engine is paused.
238f1df9364SStefan Roese  *       MV_UNDEFINED_STATE  - If the engine state is undefind or there is no
239f1df9364SStefan Roese  *                             such engine
240f1df9364SStefan Roese  */
241f1df9364SStefan Roese enum mv_state mv_xor_state_get(u32 chan)
242f1df9364SStefan Roese {
243f1df9364SStefan Roese 	u32 state;
244f1df9364SStefan Roese 
245f1df9364SStefan Roese 	/* Parameter checking   */
246f1df9364SStefan Roese 	if (chan >= MV_XOR_MAX_CHAN) {
247f1df9364SStefan Roese 		DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
248f1df9364SStefan Roese 		return MV_UNDEFINED_STATE;
249f1df9364SStefan Roese 	}
250f1df9364SStefan Roese 
251f1df9364SStefan Roese 	/* read the current state */
252f1df9364SStefan Roese 	state = reg_read(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
253f1df9364SStefan Roese 	state &= XEXACTR_XESTATUS_MASK;
254f1df9364SStefan Roese 
255f1df9364SStefan Roese 	/* return the state */
256f1df9364SStefan Roese 	switch (state) {
257f1df9364SStefan Roese 	case XEXACTR_XESTATUS_IDLE:
258f1df9364SStefan Roese 		return MV_IDLE;
259f1df9364SStefan Roese 	case XEXACTR_XESTATUS_ACTIVE:
260f1df9364SStefan Roese 		return MV_ACTIVE;
261f1df9364SStefan Roese 	case XEXACTR_XESTATUS_PAUSED:
262f1df9364SStefan Roese 		return MV_PAUSED;
263f1df9364SStefan Roese 	}
264f1df9364SStefan Roese 
265f1df9364SStefan Roese 	return MV_UNDEFINED_STATE;
266f1df9364SStefan Roese }
267f1df9364SStefan Roese 
268f1df9364SStefan Roese /*
269f1df9364SStefan Roese  * mv_xor_command_set - Set command of XOR channel
270f1df9364SStefan Roese  *
271f1df9364SStefan Roese  * DESCRIPTION:
272f1df9364SStefan Roese  *       XOR channel can be started, idle, paused and restarted.
273f1df9364SStefan Roese  *       Paused can be set only if channel is active.
274f1df9364SStefan Roese  *       Start can be set only if channel is idle or paused.
275f1df9364SStefan Roese  *       Restart can be set only if channel is paused.
276f1df9364SStefan Roese  *       Stop can be set only if channel is active.
277f1df9364SStefan Roese  *
278f1df9364SStefan Roese  * INPUT:
279f1df9364SStefan Roese  *       chan     - The channel number
280f1df9364SStefan Roese  *       command  - The command type (start, stop, restart, pause)
281f1df9364SStefan Roese  *
282f1df9364SStefan Roese  * OUTPUT:
283f1df9364SStefan Roese  *       None.
284f1df9364SStefan Roese  *
285f1df9364SStefan Roese  * RETURN:
286f1df9364SStefan Roese  *       MV_OK on success , MV_BAD_PARAM on erroneous parameter, MV_ERROR on
287f1df9364SStefan Roese  *       undefind XOR engine mode
288f1df9364SStefan Roese  */
289f1df9364SStefan Roese int mv_xor_command_set(u32 chan, enum mv_command command)
290f1df9364SStefan Roese {
291f1df9364SStefan Roese 	enum mv_state state;
292f1df9364SStefan Roese 
293f1df9364SStefan Roese 	/* Parameter checking */
294f1df9364SStefan Roese 	if (chan >= MV_XOR_MAX_CHAN) {
295f1df9364SStefan Roese 		DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
296f1df9364SStefan Roese 		return MV_BAD_PARAM;
297f1df9364SStefan Roese 	}
298f1df9364SStefan Roese 
299f1df9364SStefan Roese 	/* get the current state */
300f1df9364SStefan Roese 	state = mv_xor_state_get(chan);
301f1df9364SStefan Roese 
302f1df9364SStefan Roese 	if ((command == MV_START) && (state == MV_IDLE)) {
303f1df9364SStefan Roese 		/* command is start and current state is idle */
304f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
305f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
306f1df9364SStefan Roese 			    XEXACTR_XESTART_MASK);
307f1df9364SStefan Roese 		return MV_OK;
308f1df9364SStefan Roese 	} else if ((command == MV_STOP) && (state == MV_ACTIVE)) {
309f1df9364SStefan Roese 		/* command is stop and current state is active */
310f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
311f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
312f1df9364SStefan Roese 			    XEXACTR_XESTOP_MASK);
313f1df9364SStefan Roese 		return MV_OK;
314f1df9364SStefan Roese 	} else if (((enum mv_state)command == MV_PAUSED) &&
315f1df9364SStefan Roese 		   (state == MV_ACTIVE)) {
316f1df9364SStefan Roese 		/* command is paused and current state is active */
317f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
318f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
319f1df9364SStefan Roese 			    XEXACTR_XEPAUSE_MASK);
320f1df9364SStefan Roese 		return MV_OK;
321f1df9364SStefan Roese 	} else if ((command == MV_RESTART) && (state == MV_PAUSED)) {
322f1df9364SStefan Roese 		/* command is restart and current state is paused */
323f1df9364SStefan Roese 		reg_bit_set(XOR_ACTIVATION_REG
324f1df9364SStefan Roese 			    (XOR_UNIT(chan), XOR_CHAN(chan)),
325f1df9364SStefan Roese 			    XEXACTR_XERESTART_MASK);
326f1df9364SStefan Roese 		return MV_OK;
327f1df9364SStefan Roese 	} else if ((command == MV_STOP) && (state == MV_IDLE)) {
328f1df9364SStefan Roese 		/* command is stop and current state is active */
329f1df9364SStefan Roese 		return MV_OK;
330f1df9364SStefan Roese 	}
331f1df9364SStefan Roese 
332f1df9364SStefan Roese 	/* illegal command */
333f1df9364SStefan Roese 	DB(printf("%s: ERR. Illegal command\n", __func__));
334f1df9364SStefan Roese 
335f1df9364SStefan Roese 	return MV_BAD_PARAM;
336f1df9364SStefan Roese }
337f1df9364SStefan Roese 
338f1df9364SStefan Roese void ddr3_new_tip_ecc_scrub(void)
339f1df9364SStefan Roese {
340f1df9364SStefan Roese 	u32 cs_c, max_cs;
341f1df9364SStefan Roese 	u32 cs_ena = 0;
3422b4ffbf6SChris Packham 	u32 dev_num = 0;
3432b4ffbf6SChris Packham 	uint64_t total_mem_size, cs_mem_size = 0;
344f1df9364SStefan Roese 
3452b4ffbf6SChris Packham 	printf("DDR Training Sequence - Start scrubbing\n");
3462b4ffbf6SChris Packham 	max_cs = ddr3_tip_max_cs_get(dev_num);
347f1df9364SStefan Roese 	for (cs_c = 0; cs_c < max_cs; cs_c++)
348f1df9364SStefan Roese 		cs_ena |= 1 << cs_c;
349f1df9364SStefan Roese 
350*db363dbcSChris Packham 	/* assume that all CS have same size */
351*db363dbcSChris Packham 	ddr3_calc_mem_cs_size(0, &cs_mem_size);
352*db363dbcSChris Packham 
3532b4ffbf6SChris Packham 	mv_sys_xor_init(max_cs, cs_ena, cs_mem_size, 0);
3542b4ffbf6SChris Packham 	total_mem_size = max_cs * cs_mem_size;
3552b4ffbf6SChris Packham 	mv_xor_mem_init(0, 0, total_mem_size, 0xdeadbeef, 0xdeadbeef);
356f1df9364SStefan Roese 	/* wait for previous transfer completion */
357f1df9364SStefan Roese 	while (mv_xor_state_get(0) != MV_IDLE)
358f1df9364SStefan Roese 		;
359f1df9364SStefan Roese 	/* Return XOR State */
360f1df9364SStefan Roese 	mv_sys_xor_finish();
361f1df9364SStefan Roese 
362f1df9364SStefan Roese 	printf("DDR3 Training Sequence - End scrubbing\n");
363f1df9364SStefan Roese }
3642b4ffbf6SChris Packham 
3652b4ffbf6SChris Packham /*
3662b4ffbf6SChris Packham * mv_xor_transfer - Transfer data from source to destination in one of
3672b4ffbf6SChris Packham *		    three modes: XOR, CRC32 or DMA
3682b4ffbf6SChris Packham *
3692b4ffbf6SChris Packham * DESCRIPTION:
3702b4ffbf6SChris Packham *	This function initiates XOR channel, according to function parameters,
3712b4ffbf6SChris Packham *	in order to perform XOR, CRC32 or DMA transaction.
3722b4ffbf6SChris Packham *	To gain maximum performance the user is asked to keep the following
3732b4ffbf6SChris Packham *	restrictions:
3742b4ffbf6SChris Packham *	1) Selected engine is available (not busy).
3752b4ffbf6SChris Packham *	2) This module does not take into consideration CPU MMU issues.
3762b4ffbf6SChris Packham *	   In order for the XOR engine to access the appropriate source
3772b4ffbf6SChris Packham *	   and destination, address parameters must be given in system
3782b4ffbf6SChris Packham *	   physical mode.
3792b4ffbf6SChris Packham *	3) This API does not take care of cache coherency issues. The source,
3802b4ffbf6SChris Packham *	   destination and, in case of chain, the descriptor list are assumed
3812b4ffbf6SChris Packham *	   to be cache coherent.
3822b4ffbf6SChris Packham *	4) Parameters validity.
3832b4ffbf6SChris Packham *
3842b4ffbf6SChris Packham * INPUT:
3852b4ffbf6SChris Packham *	chan		- XOR channel number.
3862b4ffbf6SChris Packham *	type	- One of three: XOR, CRC32 and DMA operations.
3872b4ffbf6SChris Packham *	xor_chain_ptr	- address of chain pointer
3882b4ffbf6SChris Packham *
3892b4ffbf6SChris Packham * OUTPUT:
3902b4ffbf6SChris Packham *	None.
3912b4ffbf6SChris Packham *
3922b4ffbf6SChris Packham * RETURN:
3932b4ffbf6SChris Packham *       MV_BAD_PARAM if parameters to function invalid, MV_OK otherwise.
3942b4ffbf6SChris Packham *
3952b4ffbf6SChris Packham *******************************************************************************/
3962b4ffbf6SChris Packham int mv_xor_transfer(u32 chan, enum xor_type type, u32 xor_chain_ptr)
3972b4ffbf6SChris Packham {
3982b4ffbf6SChris Packham 	u32 temp;
3992b4ffbf6SChris Packham 
4002b4ffbf6SChris Packham 	/* Parameter checking */
4012b4ffbf6SChris Packham 	if (chan >= MV_XOR_MAX_CHAN) {
4022b4ffbf6SChris Packham 		DB(printf("%s: ERR. Invalid chan num %d\n", __func__, chan));
4032b4ffbf6SChris Packham 		return MV_BAD_PARAM;
4042b4ffbf6SChris Packham 	}
4052b4ffbf6SChris Packham 	if (mv_xor_state_get(chan) == MV_ACTIVE) {
4062b4ffbf6SChris Packham 		DB(printf("%s: ERR. Channel is already active\n", __func__));
4072b4ffbf6SChris Packham 		return MV_BUSY;
4082b4ffbf6SChris Packham 	}
4092b4ffbf6SChris Packham 	if (xor_chain_ptr == 0x0) {
4102b4ffbf6SChris Packham 		DB(printf("%s: ERR. xor_chain_ptr is NULL pointer\n", __func__));
4112b4ffbf6SChris Packham 		return MV_BAD_PARAM;
4122b4ffbf6SChris Packham 	}
4132b4ffbf6SChris Packham 
4142b4ffbf6SChris Packham 	/* read configuration register and mask the operation mode field */
4152b4ffbf6SChris Packham 	temp = reg_read(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)));
4162b4ffbf6SChris Packham 	temp &= ~XEXCR_OPERATION_MODE_MASK;
4172b4ffbf6SChris Packham 
4182b4ffbf6SChris Packham 	switch (type) {
4192b4ffbf6SChris Packham 	case MV_XOR:
4202b4ffbf6SChris Packham 		if ((xor_chain_ptr & XEXDPR_DST_PTR_XOR_MASK) != 0) {
4212b4ffbf6SChris Packham 			DB(printf("%s: ERR. Invalid chain pointer (bits [5:0] must be cleared)\n",
4222b4ffbf6SChris Packham 				  __func__));
4232b4ffbf6SChris Packham 			return MV_BAD_PARAM;
4242b4ffbf6SChris Packham 		}
4252b4ffbf6SChris Packham 		/* set the operation mode to XOR */
4262b4ffbf6SChris Packham 		temp |= XEXCR_OPERATION_MODE_XOR;
4272b4ffbf6SChris Packham 		break;
4282b4ffbf6SChris Packham 	case MV_DMA:
4292b4ffbf6SChris Packham 		if ((xor_chain_ptr & XEXDPR_DST_PTR_DMA_MASK) != 0) {
4302b4ffbf6SChris Packham 			DB(printf("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
4312b4ffbf6SChris Packham 				  __func__));
4322b4ffbf6SChris Packham 			return MV_BAD_PARAM;
4332b4ffbf6SChris Packham 		}
4342b4ffbf6SChris Packham 		/* set the operation mode to DMA */
4352b4ffbf6SChris Packham 		temp |= XEXCR_OPERATION_MODE_DMA;
4362b4ffbf6SChris Packham 		break;
4372b4ffbf6SChris Packham 	case MV_CRC32:
4382b4ffbf6SChris Packham 		if ((xor_chain_ptr & XEXDPR_DST_PTR_CRC_MASK) != 0) {
4392b4ffbf6SChris Packham 			DB(printf("%s: ERR. Invalid chain pointer (bits [4:0] must be cleared)\n",
4402b4ffbf6SChris Packham 				  __func__));
4412b4ffbf6SChris Packham 			return MV_BAD_PARAM;
4422b4ffbf6SChris Packham 		}
4432b4ffbf6SChris Packham 		/* set the operation mode to CRC32 */
4442b4ffbf6SChris Packham 		temp |= XEXCR_OPERATION_MODE_CRC;
4452b4ffbf6SChris Packham 		break;
4462b4ffbf6SChris Packham 	default:
4472b4ffbf6SChris Packham 		return MV_BAD_PARAM;
4482b4ffbf6SChris Packham 	}
4492b4ffbf6SChris Packham 
4502b4ffbf6SChris Packham 	/* write the operation mode to the register */
4512b4ffbf6SChris Packham 	reg_write(XOR_CONFIG_REG(XOR_UNIT(chan), XOR_CHAN(chan)), temp);
4522b4ffbf6SChris Packham 	/*
4532b4ffbf6SChris Packham 	 * update the NextDescPtr field in the XOR Engine [0..1] Next Descriptor
4542b4ffbf6SChris Packham 	 * Pointer Register (XExNDPR)
4552b4ffbf6SChris Packham 	 */
4562b4ffbf6SChris Packham 	reg_write(XOR_NEXT_DESC_PTR_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
4572b4ffbf6SChris Packham 		  xor_chain_ptr);
4582b4ffbf6SChris Packham 
4592b4ffbf6SChris Packham 	/* start transfer */
4602b4ffbf6SChris Packham 	reg_bit_set(XOR_ACTIVATION_REG(XOR_UNIT(chan), XOR_CHAN(chan)),
4612b4ffbf6SChris Packham 		    XEXACTR_XESTART_MASK);
4622b4ffbf6SChris Packham 
4632b4ffbf6SChris Packham 	return MV_OK;
4642b4ffbf6SChris Packham }
465