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