summaryrefslogtreecommitdiff
path: root/board/xilinx/common/xipif_v1_23_b.c
blob: c7311ab9be52dfafdcb0c65857f99b48ae2b33d2 (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
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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/* $Id: xipif_v1_23_b.c,v 1.1 2002/03/18 23:24:52 linnj Exp $ */
/******************************************************************************
*
*       XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
*       AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
*       SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
*       OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
*       APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
*       THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
*       AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
*       FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
*       WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
*       IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
*       REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
*       INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*       FOR A PARTICULAR PURPOSE.
*
*       (c) Copyright 2002 Xilinx Inc.
*       All rights reserved.
*
******************************************************************************/
/******************************************************************************
*
* FILENAME:
*
* xipif.c
*
* DESCRIPTION:
*
* This file contains the implementation of the XIpIf component. The
* XIpIf component encapsulates the IPIF, which is the standard interface
* that IP must adhere to when connecting to a bus.  The purpose of this
* component is to encapsulate the IPIF processing such that maintainability
* is increased.  This component does not provide a lot of abstraction from
* from the details of the IPIF as it is considered a building block for
* device drivers.  A device driver designer must be familiar with the
* details of the IPIF hardware to use this component.
*
* The IPIF hardware provides a building block for all hardware devices such
* that each device does not need to reimplement these building blocks. The
* IPIF contains other building blocks, such as FIFOs and DMA channels, which
* are also common to many devices.  These blocks are implemented as separate
* hardware blocks and instantiated within the IPIF.  The primary hardware of
* the IPIF which is implemented by this software component is the interrupt
* architecture.  Since there are many blocks of a device which may generate
* interrupts, all the interrupt processing is contained in the common part
* of the device, the IPIF.  This interrupt processing is for the device level
* only and does not include any processing for the interrupt controller.
*
* A device is a mechanism such as an Ethernet MAC.  The device is made
* up of several parts which include an IPIF and the IP.  The IPIF contains most
* of the device infrastructure which is common to all devices, such as
* interrupt processing, DMA channels, and FIFOs.  The infrastructure may also
* be referred to as IPIF internal blocks since they are part of the IPIF and
* are separate blocks that can be selected based upon the needs of the device.
* The IP of the device is the logic that is unique to the device and interfaces
* to the IPIF of the device.
*
* In general, there are two levels of registers within the IPIF.  The first
* level, referred to as the device level, contains registers which are for the
* entire device.  The second level, referred to as the IP level, contains
* registers which are specific to the IP of the device.  The two levels of
* registers are designed to be hierarchical such that the device level is
* is a more general register set above the more specific registers of the IP.
* The IP level of registers provides functionality which is typically common
* across all devices and allows IP designers to focus on the unique aspects
* of the IP.
*
* The interrupt registers of the IPIF are parameterizable such that the only
* the number of bits necessary for the device are implemented. The functions
* of this component do not attempt to validate that the passed in arguments are
* valid based upon the number of implemented bits.  This is necessary to
* maintain the level of performance required for the common components.  Bits
* of the registers are assigned starting at the least significant bit of the
* registers.
*
* Critical Sections
*
* It is the responsibility of the device driver designer to use critical
* sections as necessary when calling functions of the IPIF.  This component
* does not use critical sections and it does access registers using
* read-modify-write operations.  Calls to IPIF functions from a main thread
* and from an interrupt context could produce unpredictable behavior such that
* the caller must provide the appropriate critical sections.
*
* Mutual Exclusion
*
* The functions of the IPIF are not thread safe such that the caller of all
* functions is responsible for ensuring mutual exclusion for an IPIF.  Mutual
* exclusion across multiple IPIF components is not necessary.
*
* NOTES:
*
* None.
*
* MODIFICATION HISTORY:
*
* Ver   Who  Date     Changes
* ----- ---- -------- -----------------------------------------------
* 1.23b jhl  02/27/01 Repartioned to reduce size
*
******************************************************************************/

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

#include "xipif_v1_23_b.h"
#include "xio.h"

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

/* the following constant is used to generate bit masks for register testing
 * in the self test functions, it defines the starting bit mask that is to be
 * shifted from the LSB to MSB in creating a register test mask
 */
#define XIIF_V123B_FIRST_BIT_MASK     1UL

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

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

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

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

static XStatus IpIntrSelfTest(u32 RegBaseAddress, u32 IpRegistersWidth);

/******************************************************************************
*
* FUNCTION:
*
* XIpIf_SelfTest
*
* DESCRIPTION:
*
* This function performs a self test on the specified IPIF component.  Many
* of the registers in the IPIF are tested to ensure proper operation.  This
* function is destructive because the IPIF is reset at the start of the test
* and at the end of the test to ensure predictable results.  The IPIF reset
* also resets the entire device that uses the IPIF.  This function exits with
* all interrupts for the device disabled.
*
* ARGUMENTS:
*
* InstancePtr points to the XIpIf to operate on.
*
* DeviceRegistersWidth contains the number of bits in the device interrupt
* registers. The hardware is parameterizable such that only the number of bits
* necessary to support a device are implemented.  This value must be between 0
* and 32 with 0 indicating there are no device interrupt registers used.
*
* IpRegistersWidth contains the number of bits in the IP interrupt registers
* of the device.  The hardware is parameterizable such that only the number of
* bits necessary to support a device are implemented.  This value must be
* between 0 and 32 with 0 indicating there are no IP interrupt registers used.
*
* RETURN VALUE:
*
* A value of XST_SUCCESS indicates the test was successful with no errors.
* Any one of the following error values may also be returned.
*
*   XST_IPIF_RESET_REGISTER_ERROR       The value of a register at reset was
*                                       not valid
*   XST_IPIF_IP_STATUS_ERROR            A write to the IP interrupt status
*                                       register did not read back correctly
*   XST_IPIF_IP_ACK_ERROR               One or more bits in the IP interrupt
*                                       status register did not reset when acked
*   XST_IPIF_IP_ENABLE_ERROR            The IP interrupt enable register
*                                       did not read back correctly based upon
*                                       what was written to it
*
* NOTES:
*
* None.
*
******************************************************************************/

/* the following constant defines the maximum number of bits which may be
 * used in the registers at the device and IP levels, this is based upon the
 * number of bits available in the registers
 */
#define XIIF_V123B_MAX_REG_BIT_COUNT 32

XStatus
XIpIfV123b_SelfTest(u32 RegBaseAddress, u8 IpRegistersWidth)
{
	XStatus Status;

	/* assert to verify arguments are valid */

	XASSERT_NONVOID(IpRegistersWidth <= XIIF_V123B_MAX_REG_BIT_COUNT);

	/* reset the IPIF such that it's in a known state before the test
	 * and interrupts are globally disabled
	 */
	XIIF_V123B_RESET(RegBaseAddress);

	/* perform the self test on the IP interrupt registers, if
	 * it is not successful exit with the status
	 */
	Status = IpIntrSelfTest(RegBaseAddress, IpRegistersWidth);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	/* reset the IPIF such that it's in a known state before exiting test */

	XIIF_V123B_RESET(RegBaseAddress);

	/* reaching this point means there were no errors, return success */

	return XST_SUCCESS;
}

/******************************************************************************
*
* FUNCTION:
*
* IpIntrSelfTest
*
* DESCRIPTION:
*
* Perform a self test on the IP interrupt registers of the IPIF. This
* function modifies registers of the IPIF such that they are not guaranteed
* to be in the same state when it returns.  Any bits in the IP interrupt
* status register which are set are assumed to be set by default after a reset
* and are not tested in the test.
*
* ARGUMENTS:
*
* InstancePtr points to the XIpIf to operate on.
*
* IpRegistersWidth contains the number of bits in the IP interrupt registers
* of the device.  The hardware is parameterizable such that only the number of
* bits necessary to support a device are implemented.  This value must be
* between 0 and 32 with 0 indicating there are no IP interrupt registers used.
*
* RETURN VALUE:
*
* A status indicating XST_SUCCESS if the test was successful.  Otherwise, one
* of the following values is returned.
*
*   XST_IPIF_RESET_REGISTER_ERROR       The value of a register at reset was
*                                       not valid
*   XST_IPIF_IP_STATUS_ERROR            A write to the IP interrupt status
*                                       register did not read back correctly
*   XST_IPIF_IP_ACK_ERROR               One or more bits in the IP status
*                                       register did not reset when acked
*   XST_IPIF_IP_ENABLE_ERROR            The IP interrupt enable register
*                                       did not read back correctly based upon
*                                       what was written to it
* NOTES:
*
* None.
*
******************************************************************************/
static XStatus
IpIntrSelfTest(u32 RegBaseAddress, u32 IpRegistersWidth)
{
	/* ensure that the IP interrupt interrupt enable register is  zero
	 * as it should be at reset, the interrupt status is dependent upon the
	 * IP such that it's reset value is not known
	 */
	if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) {
		return XST_IPIF_RESET_REGISTER_ERROR;
	}

	/* if there are any used IP interrupts, then test all of the interrupt
	 * bits in all testable registers
	 */
	if (IpRegistersWidth > 0) {
		u32 BitCount;
		u32 IpInterruptMask = XIIF_V123B_FIRST_BIT_MASK;
		u32 Mask = XIIF_V123B_FIRST_BIT_MASK;	/* bits assigned MSB to LSB */
		u32 InterruptStatus;

		/* generate the register masks to be used for IP register tests, the
		 * number of bits supported by the hardware is parameterizable such
		 * that only that number of bits are implemented in the registers, the
		 * bits are allocated starting at the MSB of the registers
		 */
		for (BitCount = 1; BitCount < IpRegistersWidth; BitCount++) {
			Mask = Mask << 1;
			IpInterruptMask |= Mask;
		}

		/* get the current IP interrupt status register contents, any bits
		 * already set must default to 1 at reset in the device and these
		 * bits can't be tested in the following test, remove these bits from
		 * the mask that was generated for the test
		 */
		InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress);
		IpInterruptMask &= ~InterruptStatus;

		/* set the bits in the device status register and verify them by reading
		 * the register again, all bits of the register are latched
		 */
		XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask);
		InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress);
		if ((InterruptStatus & IpInterruptMask) != IpInterruptMask)
		{
			return XST_IPIF_IP_STATUS_ERROR;
		}

		/* test to ensure that the bits set in the IP interrupt status register
		 * can be cleared by acknowledging them in the IP interrupt status
		 * register then read it again and verify it was cleared
		 */
		XIIF_V123B_WRITE_IISR(RegBaseAddress, IpInterruptMask);
		InterruptStatus = XIIF_V123B_READ_IISR(RegBaseAddress);
		if ((InterruptStatus & IpInterruptMask) != 0) {
			return XST_IPIF_IP_ACK_ERROR;
		}

		/* set the IP interrupt enable set register and then read the IP
		 * interrupt enable register and verify the interrupts were enabled
		 */
		XIIF_V123B_WRITE_IIER(RegBaseAddress, IpInterruptMask);
		if (XIIF_V123B_READ_IIER(RegBaseAddress) != IpInterruptMask) {
			return XST_IPIF_IP_ENABLE_ERROR;
		}

		/* clear the IP interrupt enable register and then read the
		 * IP interrupt enable register and verify the interrupts were disabled
		 */
		XIIF_V123B_WRITE_IIER(RegBaseAddress, 0);
		if (XIIF_V123B_READ_IIER(RegBaseAddress) != 0) {
			return XST_IPIF_IP_ENABLE_ERROR;
		}
	}
	return XST_SUCCESS;
}