~ruther/vhdl-spi-2

ref: 04a39363e493df3803fd4efe091cf8458e3bc074 vhdl-spi-2/vitis/spi_peripheral/zynq_fsbl/nand.c -rw-r--r-- 6.8 KiB
04a39363 — Rutherther feat: add vitis and vivado projects 3 months ago
                                                                                
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
/******************************************************************************
* Copyright (c) 2012 - 2020 Xilinx, Inc.  All rights reserved.
* Copyright (c) 2022 - 2023, Advanced Micro Devices, Inc. All Rights Reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/

/*****************************************************************************/
/**
*
* @file nand.c
*
* Contains code for the NAND FLASH functionality. Bad Block management
* is simple: skip the bad blocks and keep going.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver	Who	Date		Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a ecm	01/10/10 Initial release
* 2.00a  mb	25/05/12 fsbl changes for standalone bsp based
* 3.00a sgd	30/01/13 Code cleanup
* 5.00a sgd	17/05/13 Support for Multi Boot
* 21.2  ng  07/25/23 Add SDT support
* </pre>
*
* @note
*
******************************************************************************/

/***************************** Include Files *********************************/
#include "xparameters.h"
#include "fsbl.h"
#if defined(XPAR_PS7_NAND_0_BASEADDR) || defined(XPAR_XNANDPS_0_FLASHBASE)
#include "nand.h"
#include "xnandps_bbm.h"


/************************** Constant Definitions *****************************/
#ifndef SDT
	#define NAND_DEVICE		XPAR_XNANDPS_0_DEVICE_ID
#else
	#define NAND_DEVICE		XPAR_XNANDPS_0_BASEADDR
#endif

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

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

/************************** Function Prototypes ******************************/
static u32 XNandPs_CalculateLength(XNandPs *NandInstPtr,
										u64 Offset,
										u32 Length);

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

extern u32 FlashReadBaseAddress;
extern u32 FlashOffsetAddress;

XNandPs *NandInstPtr;
XNandPs NandInstance; /* XNand Instance. */

/******************************************************************************/
/**
*
* This function initializes the controller for the NAND FLASH interface.
*
* @param	none
*
* @return
*		- XST_SUCCESS if the controller initializes correctly
*		- XST_FAILURE if the controller fails to initializes correctly
*
* @note		none.
*
****************************************************************************/
u32 InitNand(void)
{

	u32 Status;
	XNandPs_Config *ConfigPtr;

	/*
	 * Set up pointers to instance and the config structure
	 */
	NandInstPtr = &NandInstance;

	/*
	 * Initialize the flash driver.
	 */
	ConfigPtr = XNandPs_LookupConfig(NAND_DEVICE);

	if (ConfigPtr == NULL) {
		fsbl_printf(DEBUG_GENERAL,"Nand Driver failed \n \r");
		return XST_FAILURE;
	}

	Status = XNandPs_CfgInitialize(NandInstPtr, ConfigPtr,
			ConfigPtr->SmcBase,ConfigPtr->FlashBase);
	if (Status != XST_SUCCESS) {
		fsbl_printf(DEBUG_GENERAL,"NAND initialization failed \n \r");
		return XST_FAILURE;
	}

	/*
	 * Set up base address for access
	 */
	FlashReadBaseAddress = XPS_NAND_BASEADDR;

	fsbl_printf(DEBUG_INFO,"InitNand: Geometry = 0x%x\r\n",
		NandInstPtr->Geometry.FlashWidth);

	if (Status != XST_SUCCESS) {
		fsbl_printf(DEBUG_GENERAL,"InitNand: Status = 0x%.8x\r\n", 
				Status);
		return XST_FAILURE;
	}

	/*
	 * set up the FLASH access pointers
	 */
	fsbl_printf(DEBUG_INFO,"Nand driver initialized \n\r");

	return XST_SUCCESS;
}

/******************************************************************************/
/**
*
* This function provides the NAND FLASH interface for the Simplified header
* functionality. This function handles bad blocks.
*
* The source address is the absolute good address, bad blocks are skipped
* without incrementing the source address.
*
* @param	SourceAddress is address in FLASH data space, absolute good address
* @param	DestinationAddress is address in OCM data space
*
* @return	XST_SUCCESS if the transfer completes correctly
*		XST_FAILURE if the transfer fails to completes correctly
*
* @note	none.
*
****************************************************************************/
u32 NandAccess(u32 SourceAddress, u32 DestinationAddress, u32 LengthBytes)
{
	u32 ActLen;
	u32 BlockOffset;
	u32 Block;
	u32 Status;
	u32 BytesLeft = LengthBytes;
	u32 BlockSize = NandInstPtr->Geometry.BlockSize;
	u8 *BufPtr = (u8 *)DestinationAddress;
	u32 ReadLen;
	u32 BlockReadLen;
	u32 Offset;
	u32 TmpAddress = 0 ;
	u32 BlockCount = 0;
	u32 BadBlocks = 0;

	/*
	 * First get bad blocks before the source address
	 */
	while (TmpAddress < SourceAddress) {
		while (XNandPs_IsBlockBad(NandInstPtr, BlockCount) ==
				XST_SUCCESS) {
			BlockCount ++;
			BadBlocks ++;
		}

		TmpAddress += BlockSize;
		BlockCount ++;
	}

	Offset = SourceAddress + BadBlocks * BlockSize;

	/*
	 * Calculate the actual length including bad blocks
	 */
	ActLen = XNandPs_CalculateLength(NandInstPtr, Offset, LengthBytes);

	/*
	 *  Check if the actual length cross flash size
	 */
	if (Offset + ActLen > NandInstPtr->Geometry.DeviceSize) {
		return XST_FAILURE;
	}

	while (BytesLeft > 0) {
		BlockOffset = Offset & (BlockSize - 1);
		Block = (Offset & ~(BlockSize - 1))/BlockSize;
		BlockReadLen = BlockSize - BlockOffset;

		Status = XNandPs_IsBlockBad(NandInstPtr, Block);
		if (Status == XST_SUCCESS) {
			/* Move to next block */
			Offset += BlockReadLen;
			continue;
		}

		/*
		 * Check if we cross block boundary
		 */
		if (BytesLeft < BlockReadLen) {
			ReadLen = BytesLeft;
		} else {
			ReadLen = BlockReadLen;
		}

		/*
		 * Read from the NAND flash
		 */
		Status = XNandPs_Read(NandInstPtr, Offset, ReadLen, BufPtr, NULL);
		if (Status != XST_SUCCESS) {
			return Status;
		}
		BytesLeft -= ReadLen;
		Offset += ReadLen;
		BufPtr += ReadLen;
	}

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function returns the length including bad blocks from a given offset and
* length.
*
* @param	NandInstPtr is the pointer to the XNandPs instance.
* @param	Offset is the flash data address to read from.
* @param	Length is number of bytes to read.
*
* @return
*		- Return actual length including bad blocks.
*
* @note		None.
*
******************************************************************************/
static u32 XNandPs_CalculateLength(XNandPs *NandInstPtr,
									u64 Offset,
									u32 Length)
{
	u32 BlockSize = NandInstPtr->Geometry.BlockSize;
	u32 CurBlockLen;
	u32 CurBlock;
	u32 Status;
	u32 TempLen = 0;
	u32 ActLen = 0;

	while (TempLen < Length) {
		CurBlockLen = BlockSize - (Offset & (BlockSize - 1));
		CurBlock = (Offset & ~(BlockSize - 1))/BlockSize;

		/*
		 * Check if the block is bad
		 */
		Status = XNandPs_IsBlockBad(NandInstPtr, CurBlock);
		if (Status != XST_SUCCESS) {
			/* Good Block */
			TempLen += CurBlockLen;
		}
		ActLen += CurBlockLen;
		Offset += CurBlockLen;
		if (Offset >= NandInstPtr->Geometry.DeviceSize) {
			break;
		}
	}

	return ActLen;
}

#endif
Do not follow this link