summaryrefslogtreecommitdiffstats
path: root/bsps/shared/dev/spi/xqspipsu_control.c
blob: af2400bf4c346d2700709b61d35917f7bda91aa3 (plain) (blame)
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/******************************************************************************
* Copyright (C) 2020 - 2022 Xilinx, Inc.  All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/


/*****************************************************************************/
/**
 *
 * @file xqspipsu_control.c
 * @addtogroup Overview
 * @{
 *
 * This file contains intermediate control functions used by functions
 * in xqspipsu.c and xqspipsu_options.c files.
 *
 * <pre>
 * MODIFICATION HISTORY:
 *
 * Ver   Who Date     Changes
 * ----- --- -------- -----------------------------------------------
 * 1.11   akm  03/09/20 First release
 * 1.13   akm  01/04/21 Fix MISRA-C violations.
 * 1.15   akm  10/21/21 Fix MISRA-C violations.
 * 1.15   akm  03/03/22 Enable tapdelay settings for applications on
 * 			 Microblaze platform.
 * </pre>
 *
 ******************************************************************************/

/***************************** Include Files *********************************/

#include "xqspipsu_control.h"

/************************** Constant Definitions *****************************/

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

/************************** Variable Definitions *****************************/

/*****************************************************************************/

/*****************************************************************************/
/**
 *
 * This function writes the GENFIFO entries to transmit the messages requested.
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 * @param	Msg is a pointer to the structure containing transfer data.
 *
 * @return
 *		- XST_SUCCESS if successful.
 *		- XST_FAILURE if transfer fails.
 *		- XST_DEVICE_BUSY if a transfer is already in progress.
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_GenFifoEntryData(XQspiPsu *InstancePtr, XQspiPsu_Msg *Msg)
{
	u32 GenFifoEntry;

	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(Msg != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_GenFifoEntryData\r\n");
#endif

	GenFifoEntry = 0x0U;
	/* Bus width */
	GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_MODE_MASK;
	GenFifoEntry |= XQspiPsu_SelectSpiMode((u8)Msg->BusWidth);

	GenFifoEntry |= InstancePtr->GenFifoCS;
	GenFifoEntry &= ~(u32)XQSPIPSU_GENFIFO_BUS_MASK;
	GenFifoEntry |= InstancePtr->GenFifoBus;

	/* Data */
	if (((Msg->Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != (u32)FALSE) {
		GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE;
	} else {
		GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE;
	}
	/* If Byte Count is less than 8 bytes do the transfer in IO mode */
	if ((Msg->ByteCount < 8U) &&
		(InstancePtr->ReadMode == XQSPIPSU_READMODE_DMA)) {
		InstancePtr->ReadMode = XQSPIPSU_READMODE_IO;
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
			(XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET) &
					~XQSPIPSU_CFG_MODE_EN_MASK));
		InstancePtr->IsUnaligned = 1;
	}

	XQspiPsu_TXRXSetup(InstancePtr, Msg, &GenFifoEntry);

	XQspiPsu_GenFifoEntryDataLen(InstancePtr, Msg, &GenFifoEntry);

	/* One dummy GenFifo entry in case of IO mode */
	if ((InstancePtr->ReadMode == XQSPIPSU_READMODE_IO) &&
			((Msg->Flags & XQSPIPSU_MSG_FLAG_RX) != (u32)FALSE)) {
		GenFifoEntry = 0x0U;
#ifdef DEBUG
		xil_printf("\nDummy FifoEntry=%08x\r\n", GenFifoEntry);
#endif
		XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);
	}
}

/*****************************************************************************/
/**
 *
 * This function enables the polling functionality of controller
 *
 * @param	InstancePtr is a pointer to the XQspiPsu instance.
 *
 *
 * @param	FlashMsg is a pointer to the structure containing transfer data
 *
 * @return	None
 *
 * @note	None.
 *
 ******************************************************************************/
void XQspiPsu_PollDataConfig(XQspiPsu *InstancePtr, XQspiPsu_Msg *FlashMsg)
{

	u32 GenFifoEntry;
	u32 Value;

	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(FlashMsg != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
#ifdef DEBUG
	xil_printf("\nXQspiPsu_PollDataConfig\r\n");
#endif

	Value = XQspiPsu_CreatePollDataConfig(InstancePtr, FlashMsg);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_POLL_CFG_OFFSET, Value);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_P_TO_OFFSET, FlashMsg->PollTimeout);

	XQspiPsu_GenFifoEntryCSAssert(InstancePtr);

	GenFifoEntry = (u32)0;
	GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_TX;
	GenFifoEntry |= InstancePtr->GenFifoBus;
	GenFifoEntry |= InstancePtr->GenFifoCS;
	GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI;
	GenFifoEntry |= (u32)FlashMsg->PollStatusCmd;

	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress,
		XQSPIPSU_GEN_FIFO_OFFSET, GenFifoEntry);

	GenFifoEntry = (u32)0;
	GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_POLL;
	GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_RX;
	GenFifoEntry |= InstancePtr->GenFifoBus;
	GenFifoEntry |= InstancePtr->GenFifoCS;
	GenFifoEntry |= (u32)XQSPIPSU_GENFIFO_MODE_SPI;
	if (((FlashMsg->Flags) & XQSPIPSU_MSG_FLAG_STRIPE) != (u32)FALSE) {
		GenFifoEntry |= XQSPIPSU_GENFIFO_STRIPE;
	} else {
		GenFifoEntry &= ~XQSPIPSU_GENFIFO_STRIPE;
	}
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET,
			GenFifoEntry);

	/* One Dummy entry required for IO mode */
	GenFifoEntry = 0x0U;
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_GEN_FIFO_OFFSET,
			GenFifoEntry);

	InstancePtr->Msg = FlashMsg;
	InstancePtr->NumMsg = (s32)1;
	InstancePtr->MsgCnt = 0;

	Value = XQspiPsu_ReadReg(InstancePtr->Config.BaseAddress,
			XQSPIPSU_CFG_OFFSET);
	Value &= ~XQSPIPSU_CFG_MODE_EN_MASK;
	Value |= (XQSPIPSU_CFG_START_GEN_FIFO_MASK |
			XQSPIPSU_CFG_GEN_FIFO_START_MODE_MASK |
			XQSPIPSU_CFG_EN_POLL_TO_MASK);
	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_CFG_OFFSET,
			Value);

	/* Enable interrupts */
	Value = ((u32)XQSPIPSU_IER_RXNEMPTY_MASK |
		(u32)XQSPIPSU_IER_POLL_TIME_EXPIRE_MASK);

	XQspiPsu_WriteReg(InstancePtr->Config.BaseAddress, XQSPIPSU_IER_OFFSET,
			Value);

}

#if defined (ARMR5) || defined (__aarch64__) || defined (__MICROBLAZE__)
/*****************************************************************************/
/**
*
* Configures the clock according to the prescaler passed.
*
*
* @param	InstancePtr is a pointer to the XQspiPsu instance.
* @param	Prescaler - clock prescaler.
*
* @return
*		- XST_SUCCESS if successful.
*		- XST_DEVICE_BUSY if the device is currently transferring data.
*		The transfer must complete or be aborted before setting Tapdelay.
*
* @note		None.
*
******************************************************************************/
s32 XQspipsu_Calculate_Tapdelay(const XQspiPsu *InstancePtr, u8 Prescaler)
{
	u32 FreqDiv, Divider;
	u32 Tapdelay = 0;
	u32 LBkModeReg = 0;
	u32 delayReg = 0;
	s32 Status;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid(Prescaler <= XQSPIPSU_CR_PRESC_MAXIMUM);

	/*
	 * Do not allow the slave select to change while a transfer is in
	 * progress. Not thread-safe.
	 */
	if (InstancePtr->IsBusy == (u32)TRUE) {
		Status = (s32)XST_DEVICE_BUSY;
		goto END;
	} else {

		Divider = (u32)1U << (Prescaler+1U);

		FreqDiv = (InstancePtr->Config.InputClockHz)/Divider;

#if defined (versal)
		if (FreqDiv <= XQSPIPSU_FREQ_37_5MHZ) {
#else
		if (FreqDiv <= XQSPIPSU_FREQ_40MHZ) {
#endif
			Tapdelay |= (TAPDLY_BYPASS_VALVE_40MHZ <<
					 IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT);
		} else if (FreqDiv <= XQSPIPSU_FREQ_100MHZ) {
			Tapdelay |= (TAPDLY_BYPASS_VALVE_100MHZ <<
					 IOU_TAPDLY_BYPASS_LQSPI_RX_SHIFT);
			LBkModeReg |= (USE_DLY_LPBK << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT);
#if defined (versal)
			delayReg |= (u32)USE_DATA_DLY_ADJ  <<
					XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT;
#else
			delayReg |= ((u32)USE_DATA_DLY_ADJ  <<
					XQSPIPSU_DATA_DLY_ADJ_USE_DATA_DLY_SHIFT) |
							((u32)DATA_DLY_ADJ_DLY  << XQSPIPSU_DATA_DLY_ADJ_DLY_SHIFT);
#endif
		} else if (FreqDiv <= XQSPIPSU_FREQ_150MHZ) {
#if defined (versal)
			LBkModeReg |= (USE_DLY_LPBK  << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT) |
					(LPBK_DLY_ADJ_DLY1 << XQSPIPSU_LPBK_DLY_ADJ_DLY1_SHIFT);
#else
			LBkModeReg |= USE_DLY_LPBK  << XQSPIPSU_LPBK_DLY_ADJ_USE_LPBK_SHIFT;
#endif
		} else {
			Status = (s32)XST_FAILURE;
			goto END;
		}

		Status =  XQspipsu_Set_TapDelay(InstancePtr, Tapdelay, LBkModeReg, delayReg);
	}

	END:
	return Status;
}
#endif
/** @} */