mxc.c 28.6 KB
Newer Older
1 2 3 4 5 6 7 8
/***************************************************************************
 *   Copyright (C) 2009 by Alexei Babich                                   *
 *   Rezonans plc., Chelyabinsk, Russia                                    *
 *   impatt@mail.ru                                                        *
 *                                                                         *
 *   Copyright (C) 2010 by Gaetan CARLIER                                  *
 *   Trump s.a., Belgium                                                   *
 *                                                                         *
9 10 11
 *   Copyright (C) 2011 by Erik Ahlen                                      *
 *   Avalon Innovation, Sweden                                             *
 *                                                                         *
12 13 14 15 16 17 18 19 20 21 22
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
23
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
24 25 26
 ***************************************************************************/

/*
Erik Ahlén's avatar
Erik Ahlén committed
27 28
 * Freescale iMX OpenOCD NAND Flash controller support.
 * based on Freescale iMX2* and iMX3* OpenOCD NAND Flash controller support.
29 30 31
 */

/*
Erik Ahlén's avatar
Erik Ahlén committed
32
 * driver tested with Samsung K9F2G08UXA and Numonyx/ST NAND02G-B2D @mxc
33
 * tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #",
34 35 36
 * "nand write # file 0", "nand verify"
 *
 * get_next_halfword_from_sram_buffer() not tested
Erik Ahlén's avatar
Erik Ahlén committed
37
 * !! all function only tested with 2k page nand device; mxc_write_page
38 39
 *    writes the 4 MAIN_BUFFER's and is not compatible with < 2k page
 * !! oob must be be used due to NFS bug
Timo Ketola's avatar
Timo Ketola committed
40
 * !! oob must be 64 bytes per 2KiB page
41 42 43 44 45 46
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "imp.h"
47
#include "mxc.h"
48 49
#include <target/target.h>

50
#define OOB_SIZE        64
Timo Ketola's avatar
Timo Ketola committed
51

52
#define nfc_is_v1() (mxc_nf_info->mxc_version == MXC_VERSION_MX27 || \
53
		mxc_nf_info->mxc_version == MXC_VERSION_MX31)
54
#define nfc_is_v2() (mxc_nf_info->mxc_version == MXC_VERSION_MX25 || \
55
		mxc_nf_info->mxc_version == MXC_VERSION_MX35)
56

57 58 59 60 61
/* This permits to print (in LOG_INFO) how much bytes
 * has been written after a page read or write.
 * This is useful when OpenOCD is used with a graphical
 * front-end to estimate progression of the global read/write
 */
Erik Ahlén's avatar
Erik Ahlén committed
62 63
#undef _MXC_PRINT_STAT
/* #define _MXC_PRINT_STAT */
64 65

static const char target_not_halted_err_msg[] =
Erik Ahlén's avatar
Erik Ahlén committed
66
	"target must be halted to use mxc NAND flash controller";
67 68 69 70 71 72
static const char data_block_size_err_msg[] =
	"minimal granularity is one half-word, %" PRId32 " is incorrect";
static const char sram_buffer_bounds_err_msg[] =
	"trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")";
static const char get_status_register_err_msg[] = "can't get NAND status";
static uint32_t in_sram_address;
73
static unsigned char sign_of_sequental_byte_read;
74

75
static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr);
76
static int initialize_nf_controller(struct nand_device *nand);
77 78 79
static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value);
static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value);
static int poll_for_complete_op(struct nand_device *nand, const char *text);
80 81 82
static int validate_target_state(struct nand_device *nand);
static int do_data_output(struct nand_device *nand);

Erik Ahlén's avatar
Erik Ahlén committed
83 84
static int mxc_command(struct nand_device *nand, uint8_t command);
static int mxc_address(struct nand_device *nand, uint8_t address);
85

Erik Ahlén's avatar
Erik Ahlén committed
86
NAND_DEVICE_COMMAND_HANDLER(mxc_nand_device_command)
87
{
Erik Ahlén's avatar
Erik Ahlén committed
88
	struct mxc_nf_controller *mxc_nf_info;
89
	int hwecc_needed;
90

Erik Ahlén's avatar
Erik Ahlén committed
91 92
	mxc_nf_info = malloc(sizeof(struct mxc_nf_controller));
	if (mxc_nf_info == NULL) {
93 94 95
		LOG_ERROR("no memory for nand controller");
		return ERROR_FAIL;
	}
Erik Ahlén's avatar
Erik Ahlén committed
96
	nand->controller_priv = mxc_nf_info;
97

98
	if (CMD_ARGC < 4) {
99
		LOG_ERROR("use \"nand device mxc target mx25|mx27|mx31|mx35 noecc|hwecc [biswap]\"");
100 101
		return ERROR_FAIL;
	}
102

103 104 105
	/*
	 * check board type
	 */
106 107 108 109 110
	if (strcmp(CMD_ARGV[2], "mx25") == 0) {
		mxc_nf_info->mxc_version = MXC_VERSION_MX25;
		mxc_nf_info->mxc_base_addr = 0xBB000000;
		mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00;
	} else if (strcmp(CMD_ARGV[2], "mx27") == 0) {
111
		mxc_nf_info->mxc_version = MXC_VERSION_MX27;
112
		mxc_nf_info->mxc_base_addr = 0xD8000000;
113 114 115
		mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
	} else if (strcmp(CMD_ARGV[2], "mx31") == 0) {
		mxc_nf_info->mxc_version = MXC_VERSION_MX31;
116
		mxc_nf_info->mxc_base_addr = 0xB8000000;
117 118 119
		mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00;
	} else if (strcmp(CMD_ARGV[2], "mx35") == 0) {
		mxc_nf_info->mxc_version = MXC_VERSION_MX35;
120
		mxc_nf_info->mxc_base_addr = 0xBB000000;
121 122
		mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00;
	}
123

124 125 126
	/*
	 * check hwecc requirements
	 */
127
	hwecc_needed = strcmp(CMD_ARGV[3], "hwecc");
128
	if (hwecc_needed == 0)
Erik Ahlén's avatar
Erik Ahlén committed
129
		mxc_nf_info->flags.hw_ecc_enabled = 1;
130
	else
Erik Ahlén's avatar
Erik Ahlén committed
131
		mxc_nf_info->flags.hw_ecc_enabled = 0;
132

Erik Ahlén's avatar
Erik Ahlén committed
133 134 135
	mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
	mxc_nf_info->fin = MXC_NF_FIN_NONE;
	mxc_nf_info->flags.target_little_endian =
136
		(nand->target->endianness == TARGET_LITTLE_ENDIAN);
137

Erik Ahlén's avatar
Erik Ahlén committed
138 139 140 141 142 143 144 145 146
	/*
	 * should factory bad block indicator be swaped
	 * as a workaround for how the nfc handles pages.
	 */
	if (CMD_ARGC > 4 && strcmp(CMD_ARGV[4], "biswap") == 0) {
		LOG_DEBUG("BI-swap enabled");
		mxc_nf_info->flags.biswap_enabled = 1;
	}

147 148 149
	return ERROR_OK;
}

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
COMMAND_HANDLER(handle_mxc_biswap_command)
{
	struct nand_device *nand = NULL;
	struct mxc_nf_controller *mxc_nf_info = NULL;

	if (CMD_ARGC < 1 || CMD_ARGC > 2)
		return ERROR_COMMAND_SYNTAX_ERROR;

	int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand);
	if (retval != ERROR_OK) {
		command_print(CMD_CTX, "invalid nand device number or name: %s", CMD_ARGV[0]);
		return ERROR_COMMAND_ARGUMENT_INVALID;
	}

	mxc_nf_info = nand->controller_priv;
	if (CMD_ARGC == 2) {
		if (strcmp(CMD_ARGV[1], "enable") == 0)
			mxc_nf_info->flags.biswap_enabled = true;
		else
			mxc_nf_info->flags.biswap_enabled = false;
	}
	if (mxc_nf_info->flags.biswap_enabled)
		command_print(CMD_CTX, "BI-swapping enabled on %s", nand->name);
	else
		command_print(CMD_CTX, "BI-swapping disabled on %s", nand->name);

	return ERROR_OK;
}

static const struct command_registration mxc_sub_command_handlers[] = {
	{
		.name = "biswap",
182
		.mode = COMMAND_EXEC,
183
		.handler = handle_mxc_biswap_command,
184
		.help = "Turns on/off bad block information swaping from main area, "
185
			"without parameter query status.",
186 187 188 189 190 191 192 193 194 195
		.usage = "bank_id ['enable'|'disable']",
	},
	COMMAND_REGISTRATION_DONE
};

static const struct command_registration mxc_nand_command_handler[] = {
	{
		.name = "mxc",
		.mode = COMMAND_ANY,
		.help = "MXC NAND flash controller commands",
196 197
		.chain = mxc_sub_command_handlers,
		.usage = "",
198 199 200 201
	},
	COMMAND_REGISTRATION_DONE
};

Erik Ahlén's avatar
Erik Ahlén committed
202
static int mxc_init(struct nand_device *nand)
203
{
Erik Ahlén's avatar
Erik Ahlén committed
204
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
205
	struct target *target = nand->target;
206 207 208

	int validate_target_result;
	uint16_t buffsize_register_content;
209 210 211 212
	uint32_t sreg_content;
	uint32_t SREG = MX2_FMCR;
	uint32_t SEL_16BIT = MX2_FMCR_NF_16BIT_SEL;
	uint32_t SEL_FMS = MX2_FMCR_NF_FMS;
213 214 215 216 217 218 219 220 221
	int retval;
	uint16_t nand_status_content;
	/*
	 * validate target state
	 */
	validate_target_result = validate_target_state(nand);
	if (validate_target_result != ERROR_OK)
		return validate_target_result;

222 223 224 225 226 227 228 229 230 231
	if (nfc_is_v1()) {
		target_read_u16(target, MXC_NF_BUFSIZ, &buffsize_register_content);
		mxc_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f);
	} else
		mxc_nf_info->flags.one_kb_sram = 0;

	if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) {
		SREG = MX3_PCSR;
		SEL_16BIT = MX3_PCSR_NF_16BIT_SEL;
		SEL_FMS = MX3_PCSR_NF_FMS;
232 233 234 235
	} else if (mxc_nf_info->mxc_version == MXC_VERSION_MX25) {
		SREG = MX25_RCSR;
		SEL_16BIT = MX25_RCSR_NF_16BIT_SEL;
		SEL_FMS = MX25_RCSR_NF_FMS;
236 237 238 239 240
	} else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) {
		SREG = MX35_RCSR;
		SEL_16BIT = MX35_RCSR_NF_16BIT_SEL;
		SEL_FMS = MX35_RCSR_NF_FMS;
	}
241

242
	target_read_u32(target, SREG, &sreg_content);
243
	if (!nand->bus_width) {
Erik Ahlén's avatar
Erik Ahlén committed
244
		/* bus_width not yet defined. Read it from MXC_FMCR */
245
		nand->bus_width = (sreg_content & SEL_16BIT) ? 16 : 8;
246
	} else {
Erik Ahlén's avatar
Erik Ahlén committed
247
		/* bus_width forced in soft. Sync it to MXC_FMCR */
248 249
		sreg_content |= ((nand->bus_width == 16) ? SEL_16BIT : 0x00000000);
		target_write_u32(target, SREG, sreg_content);
250 251
	}
	if (nand->bus_width == 16)
Erik Ahlén's avatar
Erik Ahlén committed
252
		LOG_DEBUG("MXC_NF : bus is 16-bit width");
253
	else
Erik Ahlén's avatar
Erik Ahlén committed
254
		LOG_DEBUG("MXC_NF : bus is 8-bit width");
255

256
	if (!nand->page_size)
257
		nand->page_size = (sreg_content & SEL_FMS) ? 2048 : 512;
258
	else {
259 260
		sreg_content |= ((nand->page_size == 2048) ? SEL_FMS : 0x00000000);
		target_write_u32(target, SREG, sreg_content);
261
	}
Erik Ahlén's avatar
Erik Ahlén committed
262
	if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) {
263
		LOG_ERROR("NAND controller have only 1 kb SRAM, so "
264 265
			"pagesize 2048 is incompatible with it");
	} else
Erik Ahlén's avatar
Erik Ahlén committed
266
		LOG_DEBUG("MXC_NF : NAND controller can handle pagesize of 2048");
267

268 269 270
	if (nfc_is_v2() && sreg_content & MX35_RCSR_NF_4K)
		LOG_ERROR("MXC driver does not have support for 4k pagesize.");

271 272 273
	initialize_nf_controller(nand);

	retval = ERROR_OK;
Erik Ahlén's avatar
Erik Ahlén committed
274 275
	retval |= mxc_command(nand, NAND_CMD_STATUS);
	retval |= mxc_address(nand, 0x00);
276 277 278 279 280
	retval |= do_data_output(nand);
	if (retval != ERROR_OK) {
		LOG_ERROR(get_status_register_err_msg);
		return ERROR_FAIL;
	}
Erik Ahlén's avatar
Erik Ahlén committed
281
	target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content);
282 283
	if (!(nand_status_content & 0x0080)) {
		LOG_INFO("NAND read-only");
Erik Ahlén's avatar
Erik Ahlén committed
284
		mxc_nf_info->flags.nand_readonly = 1;
285
	} else
Erik Ahlén's avatar
Erik Ahlén committed
286
		mxc_nf_info->flags.nand_readonly = 0;
287 288 289
	return ERROR_OK;
}

Erik Ahlén's avatar
Erik Ahlén committed
290
static int mxc_read_data(struct nand_device *nand, void *data)
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
{
	int validate_target_result;
	int try_data_output_from_nand_chip;
	/*
	 * validate target state
	 */
	validate_target_result = validate_target_state(nand);
	if (validate_target_result != ERROR_OK)
		return validate_target_result;

	/*
	 * get data from nand chip
	 */
	try_data_output_from_nand_chip = do_data_output(nand);
	if (try_data_output_from_nand_chip != ERROR_OK) {
Erik Ahlén's avatar
Erik Ahlén committed
306
		LOG_ERROR("mxc_read_data : read data failed : '%x'",
307
			try_data_output_from_nand_chip);
308 309 310 311
		return try_data_output_from_nand_chip;
	}

	if (nand->bus_width == 16)
312
		get_next_halfword_from_sram_buffer(nand, data);
313
	else
314
		get_next_byte_from_sram_buffer(nand, data);
315 316 317 318

	return ERROR_OK;
}

Erik Ahlén's avatar
Erik Ahlén committed
319
static int mxc_write_data(struct nand_device *nand, uint16_t data)
320 321 322 323 324
{
	LOG_ERROR("write_data() not implemented");
	return ERROR_NAND_OPERATION_FAILED;
}

Erik Ahlén's avatar
Erik Ahlén committed
325
static int mxc_reset(struct nand_device *nand)
326 327 328 329 330 331 332
{
	/*
	 * validate target state
	 */
	int validate_target_result;
	validate_target_result = validate_target_state(nand);
	if (validate_target_result != ERROR_OK)
333
		return validate_target_result;
334 335 336 337
	initialize_nf_controller(nand);
	return ERROR_OK;
}

Erik Ahlén's avatar
Erik Ahlén committed
338
static int mxc_command(struct nand_device *nand, uint8_t command)
339
{
Erik Ahlén's avatar
Erik Ahlén committed
340
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
341
	struct target *target = nand->target;
342 343 344 345 346 347 348 349 350
	int validate_target_result;
	int poll_result;
	/*
	 * validate target state
	 */
	validate_target_result = validate_target_state(nand);
	if (validate_target_result != ERROR_OK)
		return validate_target_result;

351
	switch (command) {
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
		case NAND_CMD_READOOB:
			command = NAND_CMD_READ0;
			/* set read point for data_read() and read_block_data() to
			 * spare area in SRAM buffer
			 */
			if (nfc_is_v1())
				in_sram_address = MXC_NF_V1_SPARE_BUFFER0;
			else
				in_sram_address = MXC_NF_V2_SPARE_BUFFER0;
			break;
		case NAND_CMD_READ1:
			command = NAND_CMD_READ0;
			/*
			 * offset == one half of page size
			 */
			in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1);
			break;
		default:
			in_sram_address = MXC_NF_MAIN_BUFFER0;
			break;
372 373
	}

Erik Ahlén's avatar
Erik Ahlén committed
374
	target_write_u16(target, MXC_NF_FCMD, command);
375
	/*
Erik Ahlén's avatar
Erik Ahlén committed
376
	 * start command input operation (set MXC_NF_BIT_OP_DONE==0)
377
	 */
Erik Ahlén's avatar
Erik Ahlén committed
378
	target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FCI);
379
	poll_result = poll_for_complete_op(nand, "command");
380 381 382 383 384 385 386
	if (poll_result != ERROR_OK)
		return poll_result;
	/*
	 * reset cursor to begin of the buffer
	 */
	sign_of_sequental_byte_read = 0;
	/* Handle special read command and adjust NF_CFG2(FDO) */
387
	switch (command) {
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
		case NAND_CMD_READID:
			mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID;
			mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
			break;
		case NAND_CMD_STATUS:
			mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS;
			mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
			target_write_u16 (target, MXC_NF_BUFADDR, 0);
			in_sram_address = 0;
			break;
		case NAND_CMD_READ0:
			mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
			mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
			break;
		default:
			/* Ohter command use the default 'One page data out' FDO */
			mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE;
			break;
406 407 408 409
	}
	return ERROR_OK;
}

Erik Ahlén's avatar
Erik Ahlén committed
410
static int mxc_address(struct nand_device *nand, uint8_t address)
411
{
412
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
413
	struct target *target = nand->target;
414 415 416 417 418 419 420 421 422
	int validate_target_result;
	int poll_result;
	/*
	 * validate target state
	 */
	validate_target_result = validate_target_state(nand);
	if (validate_target_result != ERROR_OK)
		return validate_target_result;

Erik Ahlén's avatar
Erik Ahlén committed
423
	target_write_u16(target, MXC_NF_FADDR, address);
424
	/*
Erik Ahlén's avatar
Erik Ahlén committed
425
	 * start address input operation (set MXC_NF_BIT_OP_DONE==0)
426
	 */
Erik Ahlén's avatar
Erik Ahlén committed
427
	target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FAI);
428
	poll_result = poll_for_complete_op(nand, "address");
429 430 431 432 433 434
	if (poll_result != ERROR_OK)
		return poll_result;

	return ERROR_OK;
}

Erik Ahlén's avatar
Erik Ahlén committed
435
static int mxc_nand_ready(struct nand_device *nand, int tout)
436
{
437
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
438
	struct target *target = nand->target;
439
	uint16_t poll_complete_status;
440 441 442 443 444 445 446 447 448 449
	int validate_target_result;

	/*
	 * validate target state
	 */
	validate_target_result = validate_target_state(nand);
	if (validate_target_result != ERROR_OK)
		return validate_target_result;

	do {
Erik Ahlén's avatar
Erik Ahlén committed
450 451
		target_read_u16(target, MXC_NF_CFG2, &poll_complete_status);
		if (poll_complete_status & MXC_NF_BIT_OP_DONE)
452 453 454
			return tout;

		alive_sleep(1);
455
	} while (tout-- > 0);
456 457 458
	return tout;
}

Erik Ahlén's avatar
Erik Ahlén committed
459
static int mxc_write_page(struct nand_device *nand, uint32_t page,
460 461
	uint8_t *data, uint32_t data_size,
	uint8_t *oob, uint32_t oob_size)
462
{
Erik Ahlén's avatar
Erik Ahlén committed
463
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
464
	struct target *target = nand->target;
465 466 467
	int retval;
	uint16_t nand_status_content;
	uint16_t swap1, swap2, new_swap1;
468
	uint8_t bufs;
469
	int poll_result;
470

471 472 473 474 475 476 477 478 479 480 481 482
	if (data_size % 2) {
		LOG_ERROR(data_block_size_err_msg, data_size);
		return ERROR_NAND_OPERATION_FAILED;
	}
	if (oob_size % 2) {
		LOG_ERROR(data_block_size_err_msg, oob_size);
		return ERROR_NAND_OPERATION_FAILED;
	}
	if (!data) {
		LOG_ERROR("nothing to program");
		return ERROR_NAND_OPERATION_FAILED;
	}
483

484 485 486 487 488 489 490
	/*
	 * validate target state
	 */
	retval = validate_target_state(nand);
	if (retval != ERROR_OK)
		return retval;

Erik Ahlén's avatar
Erik Ahlén committed
491
	in_sram_address = MXC_NF_MAIN_BUFFER0;
492 493
	sign_of_sequental_byte_read = 0;
	retval = ERROR_OK;
Erik Ahlén's avatar
Erik Ahlén committed
494
	retval |= mxc_command(nand, NAND_CMD_SEQIN);
495 496 497 498 499
	retval |= mxc_address(nand, 0);	/* col */
	retval |= mxc_address(nand, 0);	/* col */
	retval |= mxc_address(nand, page & 0xff);	/* page address */
	retval |= mxc_address(nand, (page >> 8) & 0xff);/* page address */
	retval |= mxc_address(nand, (page >> 16) & 0xff);	/* page address */
Erik Ahlén's avatar
Erik Ahlén committed
500 501

	target_write_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data);
502
	if (oob) {
Erik Ahlén's avatar
Erik Ahlén committed
503
		if (mxc_nf_info->flags.hw_ecc_enabled) {
504 505 506 507 508
			/*
			 * part of spare block will be overrided by hardware
			 * ECC generator
			 */
			LOG_DEBUG("part of spare block will be overrided "
509
				"by hardware ECC generator");
510
		}
511 512 513 514 515 516 517 518 519 520 521 522
		if (nfc_is_v1())
			target_write_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
		else {
			uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
			while (oob_size > 0) {
				uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
				target_write_buffer(target, addr, len, oob);
				addr = align_address_v2(nand, addr + len);
				oob += len;
				oob_size -= len;
			}
		}
523
	}
Erik Ahlén's avatar
Erik Ahlén committed
524 525 526 527 528 529 530 531

	if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
		/* BI-swap - work-around of i.MX NFC for NAND device with page == 2kb*/
		target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1);
		if (oob) {
			LOG_ERROR("Due to NFC Bug, oob is not correctly implemented in mxc driver");
			return ERROR_NAND_OPERATION_FAILED;
		}
532
		swap2 = 0xffff;	/* Spare buffer unused forced to 0xffff */
Erik Ahlén's avatar
Erik Ahlén committed
533 534 535
		new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
		swap2 = (swap1 << 8) | (swap2 & 0xFF);
		target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
536
		if (nfc_is_v1())
537
			target_write_u16(target, MXC_NF_V1_SPARE_BUFFER3 + 4, swap2);
538 539
		else
			target_write_u16(target, MXC_NF_V2_SPARE_BUFFER3, swap2);
540 541 542
	}

	/*
Erik Ahlén's avatar
Erik Ahlén committed
543
	 * start data input operation (set MXC_NF_BIT_OP_DONE==0)
544
	 */
545 546 547 548
	if (nfc_is_v1() && nand->page_size > 512)
		bufs = 4;
	else
		bufs = 1;
549

550
	for (uint8_t i = 0; i < bufs; ++i) {
551 552 553 554 555 556
		target_write_u16(target, MXC_NF_BUFADDR, i);
		target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI);
		poll_result = poll_for_complete_op(nand, "data input");
		if (poll_result != ERROR_OK)
			return poll_result;
	}
557

Erik Ahlén's avatar
Erik Ahlén committed
558
	retval |= mxc_command(nand, NAND_CMD_PAGEPROG);
559 560 561 562 563 564
	if (retval != ERROR_OK)
		return retval;

	/*
	 * check status register
	 */
565
	retval = ERROR_OK;
Erik Ahlén's avatar
Erik Ahlén committed
566 567 568 569
	retval |= mxc_command(nand, NAND_CMD_STATUS);
	target_write_u16 (target, MXC_NF_BUFADDR, 0);
	mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS;
	mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
570 571 572 573 574
	retval |= do_data_output(nand);
	if (retval != ERROR_OK) {
		LOG_ERROR(get_status_register_err_msg);
		return retval;
	}
Erik Ahlén's avatar
Erik Ahlén committed
575
	target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content);
576 577 578 579 580 581
	if (nand_status_content & 0x0001) {
		/*
		 * page not correctly written
		 */
		return ERROR_NAND_OPERATION_FAILED;
	}
Erik Ahlén's avatar
Erik Ahlén committed
582
#ifdef _MXC_PRINT_STAT
583 584 585 586 587
	LOG_INFO("%d bytes newly written", data_size);
#endif
	return ERROR_OK;
}

Erik Ahlén's avatar
Erik Ahlén committed
588
static int mxc_read_page(struct nand_device *nand, uint32_t page,
589 590
	uint8_t *data, uint32_t data_size,
	uint8_t *oob, uint32_t oob_size)
591
{
Erik Ahlén's avatar
Erik Ahlén committed
592
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
593
	struct target *target = nand->target;
594
	int retval;
595
	uint8_t bufs;
596
	uint16_t swap1, swap2, new_swap1;
597

598
	if (data_size % 2) {
599 600
		LOG_ERROR(data_block_size_err_msg, data_size);
		return ERROR_NAND_OPERATION_FAILED;
601 602
	}
	if (oob_size % 2) {
603 604
		LOG_ERROR(data_block_size_err_msg, oob_size);
		return ERROR_NAND_OPERATION_FAILED;
605 606 607 608 609 610
	}

	/*
	 * validate target state
	 */
	retval = validate_target_state(nand);
611
	if (retval != ERROR_OK)
612
		return retval;
613
				/* Reset address_cycles before mxc_command ?? */
Erik Ahlén's avatar
Erik Ahlén committed
614
	retval = mxc_command(nand, NAND_CMD_READ0);
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
	if (retval != ERROR_OK)
		return retval;
	retval = mxc_address(nand, 0);	/* col */
	if (retval != ERROR_OK)
		return retval;
	retval = mxc_address(nand, 0);	/* col */
	if (retval != ERROR_OK)
		return retval;
	retval = mxc_address(nand, page & 0xff);/* page address */
	if (retval != ERROR_OK)
		return retval;
	retval = mxc_address(nand, (page >> 8) & 0xff);	/* page address */
	if (retval != ERROR_OK)
		return retval;
	retval = mxc_address(nand, (page >> 16) & 0xff);/* page address */
	if (retval != ERROR_OK)
		return retval;
Erik Ahlén's avatar
Erik Ahlén committed
632
	retval = mxc_command(nand, NAND_CMD_READSTART);
633 634
	if (retval != ERROR_OK)
		return retval;
635

636 637 638 639 640
	if (nfc_is_v1() && nand->page_size > 512)
		bufs = 4;
	else
		bufs = 1;

641
	for (uint8_t i = 0; i < bufs; ++i) {
642 643 644 645 646 647 648
		target_write_u16(target, MXC_NF_BUFADDR, i);
		mxc_nf_info->fin = MXC_NF_FIN_DATAOUT;
		retval = do_data_output(nand);
		if (retval != ERROR_OK) {
			LOG_ERROR("MXC_NF : Error reading page %d", i);
			return retval;
		}
649
	}
Erik Ahlén's avatar
Erik Ahlén committed
650 651

	if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) {
652
		uint32_t SPARE_BUFFER3;
Erik Ahlén's avatar
Erik Ahlén committed
653 654
		/* BI-swap -  work-around of mxc NFC for NAND device with page == 2k */
		target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1);
655
		if (nfc_is_v1())
656
			SPARE_BUFFER3 = MXC_NF_V1_SPARE_BUFFER3 + 4;
657 658 659
		else
			SPARE_BUFFER3 = MXC_NF_V2_SPARE_BUFFER3;
		target_read_u16(target, SPARE_BUFFER3, &swap2);
Erik Ahlén's avatar
Erik Ahlén committed
660 661 662
		new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8);
		swap2 = (swap1 << 8) | (swap2 & 0xFF);
		target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1);
663
		target_write_u16(target, SPARE_BUFFER3, swap2);
Erik Ahlén's avatar
Erik Ahlén committed
664
	}
665 666

	if (data)
Erik Ahlén's avatar
Erik Ahlén committed
667
		target_read_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data);
668 669 670 671 672 673 674 675 676 677 678 679 680 681
	if (oob) {
		if (nfc_is_v1())
			target_read_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob);
		else {
			uint32_t addr = MXC_NF_V2_SPARE_BUFFER0;
			while (oob_size > 0) {
				uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN);
				target_read_buffer(target, addr, len, oob);
				addr = align_address_v2(nand, addr + len);
				oob += len;
				oob_size -= len;
			}
		}
	}
682

Erik Ahlén's avatar
Erik Ahlén committed
683
#ifdef _MXC_PRINT_STAT
684 685 686 687 688 689 690 691 692 693
	if (data_size > 0) {
		/* When Operation Status is read (when page is erased),
		 * this function is used but data_size is null.
		 */
		LOG_INFO("%d bytes newly read", data_size);
	}
#endif
	return ERROR_OK;
}

694 695 696 697 698
static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr)
{
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
	uint32_t ret = addr;
	if (addr > MXC_NF_V2_SPARE_BUFFER0 &&
699
			(addr & 0x1F) == MXC_NF_SPARE_BUFFER_LEN)
700
		ret += MXC_NF_SPARE_BUFFER_MAX - MXC_NF_SPARE_BUFFER_LEN;
701
	else if (addr >= (mxc_nf_info->mxc_base_addr + (uint32_t)nand->page_size))
702 703 704 705
		ret = MXC_NF_V2_SPARE_BUFFER0;
	return ret;
}

706 707
static int initialize_nf_controller(struct nand_device *nand)
{
Erik Ahlén's avatar
Erik Ahlén committed
708
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
709
	struct target *target = nand->target;
710
	uint16_t work_mode = 0;
711 712 713 714
	uint16_t temp;
	/*
	 * resets NAND flash controller in zero time ? I dont know.
	 */
Erik Ahlén's avatar
Erik Ahlén committed
715
	target_write_u16(target, MXC_NF_CFG1, MXC_NF_BIT_RESET_EN);
716 717 718
	if (mxc_nf_info->mxc_version == MXC_VERSION_MX27)
		work_mode = MXC_NF_BIT_INT_DIS;	/* disable interrupt */

719
	if (target->endianness == TARGET_BIG_ENDIAN) {
Erik Ahlén's avatar
Erik Ahlén committed
720 721
		LOG_DEBUG("MXC_NF : work in Big Endian mode");
		work_mode |= MXC_NF_BIT_BE_EN;
722
	} else
Erik Ahlén's avatar
Erik Ahlén committed
723 724 725 726
		LOG_DEBUG("MXC_NF : work in Little Endian mode");
	if (mxc_nf_info->flags.hw_ecc_enabled) {
		LOG_DEBUG("MXC_NF : work with ECC mode");
		work_mode |= MXC_NF_BIT_ECC_EN;
727
	} else
Erik Ahlén's avatar
Erik Ahlén committed
728
		LOG_DEBUG("MXC_NF : work without ECC mode");
729
	if (nfc_is_v2()) {
Timo Ketola's avatar
Timo Ketola committed
730
		target_write_u16(target, MXC_NF_V2_SPAS, OOB_SIZE / 2);
731 732 733 734 735 736
		if (nand->page_size) {
			uint16_t pages_per_block = nand->erase_size / nand->page_size;
			work_mode |= MXC_NF_V2_CFG1_PPB(ffs(pages_per_block) - 6);
		}
		work_mode |= MXC_NF_BIT_ECC_4BIT;
	}
Erik Ahlén's avatar
Erik Ahlén committed
737
	target_write_u16(target, MXC_NF_CFG1, work_mode);
738

739 740 741
	/*
	 * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock"
	 */
Erik Ahlén's avatar
Erik Ahlén committed
742 743
	target_write_u16(target, MXC_NF_BUFCFG, 2);
	target_read_u16(target, MXC_NF_FWP, &temp);
744 745 746 747 748 749 750 751
	if ((temp & 0x0007) == 1) {
		LOG_ERROR("NAND flash is tight-locked, reset needed");
		return ERROR_FAIL;
	}

	/*
	 * unlock NAND flash for write
	 */
752 753 754 755 756 757 758 759 760 761 762 763 764
	if (nfc_is_v1()) {
		target_write_u16(target, MXC_NF_V1_UNLOCKSTART, 0x0000);
		target_write_u16(target, MXC_NF_V1_UNLOCKEND, 0xFFFF);
	} else {
		target_write_u16(target, MXC_NF_V2_UNLOCKSTART0, 0x0000);
		target_write_u16(target, MXC_NF_V2_UNLOCKSTART1, 0x0000);
		target_write_u16(target, MXC_NF_V2_UNLOCKSTART2, 0x0000);
		target_write_u16(target, MXC_NF_V2_UNLOCKSTART3, 0x0000);
		target_write_u16(target, MXC_NF_V2_UNLOCKEND0, 0xFFFF);
		target_write_u16(target, MXC_NF_V2_UNLOCKEND1, 0xFFFF);
		target_write_u16(target, MXC_NF_V2_UNLOCKEND2, 0xFFFF);
		target_write_u16(target, MXC_NF_V2_UNLOCKEND3, 0xFFFF);
	}
Erik Ahlén's avatar
Erik Ahlén committed
765
	target_write_u16(target, MXC_NF_FWP, 4);
766

767
	/*
768
	 * 0x0000 means that first SRAM buffer @base_addr will be used
769
	 */
Erik Ahlén's avatar
Erik Ahlén committed
770
	target_write_u16(target, MXC_NF_BUFADDR, 0x0000);
771 772 773
	/*
	 * address of SRAM buffer
	 */
Erik Ahlén's avatar
Erik Ahlén committed
774
	in_sram_address = MXC_NF_MAIN_BUFFER0;
775 776 777 778
	sign_of_sequental_byte_read = 0;
	return ERROR_OK;
}

779
static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value)
780
{
781 782
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
	struct target *target = nand->target;
783
	static uint8_t even_byte;
784 785 786 787 788 789
	uint16_t temp;
	/*
	 * host-big_endian ??
	 */
	if (sign_of_sequental_byte_read == 0)
		even_byte = 0;
790

791
	if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
792 793 794 795 796 797
		LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
		*value = 0;
		sign_of_sequental_byte_read = 0;
		even_byte = 0;
		return ERROR_NAND_OPERATION_FAILED;
	} else {
798 799 800
		if (nfc_is_v2())
			in_sram_address = align_address_v2(nand, in_sram_address);

801 802 803 804 805 806 807 808 809 810 811 812 813 814
		target_read_u16(target, in_sram_address, &temp);
		if (even_byte) {
			*value = temp >> 8;
			even_byte = 0;
			in_sram_address += 2;
		} else {
			*value = temp & 0xff;
			even_byte = 1;
		}
	}
	sign_of_sequental_byte_read = 1;
	return ERROR_OK;
}

815
static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value)
816
{
817 818 819
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
	struct target *target = nand->target;

820
	if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) {
821 822 823 824
		LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address);
		*value = 0;
		return ERROR_NAND_OPERATION_FAILED;
	} else {
825 826 827
		if (nfc_is_v2())
			in_sram_address = align_address_v2(nand, in_sram_address);

828 829 830 831 832 833
		target_read_u16(target, in_sram_address, value);
		in_sram_address += 2;
	}
	return ERROR_OK;
}

834
static int poll_for_complete_op(struct nand_device *nand, const char *text)
835
{
836
	if (mxc_nand_ready(nand, 1000) == -1) {
837 838 839 840 841 842 843 844
		LOG_ERROR("%s sending timeout", text);
		return ERROR_NAND_OPERATION_FAILED;
	}
	return ERROR_OK;
}

static int validate_target_state(struct nand_device *nand)
{
Erik Ahlén's avatar
Erik Ahlén committed
845
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
846
	struct target *target = nand->target;
847 848 849 850 851 852

	if (target->state != TARGET_HALTED) {
		LOG_ERROR(target_not_halted_err_msg);
		return ERROR_NAND_OPERATION_FAILED;
	}

Erik Ahlén's avatar
Erik Ahlén committed
853
	if (mxc_nf_info->flags.target_little_endian !=
854
			(target->endianness == TARGET_LITTLE_ENDIAN)) {
855 856 857 858 859 860 861 862
		/*
		 * endianness changed after NAND controller probed
		 */
		return ERROR_NAND_OPERATION_FAILED;
	}
	return ERROR_OK;
}

863 864 865 866 867 868 869 870
int ecc_status_v1(struct nand_device *nand)
{
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
	struct target *target = nand->target;
	uint16_t ecc_status;

	target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
	switch (ecc_status & 0x000c) {
871 872 873 874 875 876 877
		case 1 << 2:
			LOG_INFO("main area read with 1 (correctable) error");
			break;
		case 2 << 2:
			LOG_INFO("main area read with more than 1 (incorrectable) error");
			return ERROR_NAND_OPERATION_FAILED;
			break;
878 879
	}
	switch (ecc_status & 0x0003) {
880 881 882 883 884 885 886
		case 1:
			LOG_INFO("spare area read with 1 (correctable) error");
			break;
		case 2:
			LOG_INFO("main area read with more than 1 (incorrectable) error");
			return ERROR_NAND_OPERATION_FAILED;
			break;
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
	}
	return ERROR_OK;
}

int ecc_status_v2(struct nand_device *nand)
{
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
	struct target *target = nand->target;
	uint16_t ecc_status;
	uint8_t no_subpages;
	uint8_t err;

	no_subpages = nand->page_size >> 9;

	target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status);
	do {
		err = ecc_status & 0xF;
		if (err > 4) {
			LOG_INFO("UnCorrectable RS-ECC Error");
			return ERROR_NAND_OPERATION_FAILED;
		} else if (err > 0)
			LOG_INFO("%d Symbol Correctable RS-ECC Error", err);
		ecc_status >>= 4;
	} while (--no_subpages);
	return ERROR_OK;
}

914 915
static int do_data_output(struct nand_device *nand)
{
Erik Ahlén's avatar
Erik Ahlén committed
916
	struct mxc_nf_controller *mxc_nf_info = nand->controller_priv;
917
	struct target *target = nand->target;
918
	int poll_result;
Erik Ahlén's avatar
Erik Ahlén committed
919
	switch (mxc_nf_info->fin) {
920 921 922 923 924 925 926 927
		case MXC_NF_FIN_DATAOUT:
			/*
			 * start data output operation (set MXC_NF_BIT_OP_DONE==0)
			 */
			target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype));
			poll_result = poll_for_complete_op(nand, "data output");
			if (poll_result != ERROR_OK)
				return poll_result;
928

929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
			mxc_nf_info->fin = MXC_NF_FIN_NONE;
			/*
			 * ECC stuff
			 */
			if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) {
				int ecc_status;
				if (nfc_is_v1())
					ecc_status = ecc_status_v1(nand);
				else
					ecc_status = ecc_status_v2(nand);
				if (ecc_status != ERROR_OK)
					return ecc_status;
			}
			break;
		case MXC_NF_FIN_NONE:
			break;
945 946 947 948
	}
	return ERROR_OK;
}

Erik Ahlén's avatar
Erik Ahlén committed
949
struct nand_flash_controller mxc_nand_flash_controller = {
950 951 952 953 954 955 956 957 958 959 960 961
	.name = "mxc",
	.nand_device_command = &mxc_nand_device_command,
	.commands = mxc_nand_command_handler,
	.init = &mxc_init,
	.reset = &mxc_reset,
	.command = &mxc_command,
	.address = &mxc_address,
	.write_data = &mxc_write_data,
	.read_data = &mxc_read_data,
	.write_page = &mxc_write_page,
	.read_page = &mxc_read_page,
	.nand_ready = &mxc_nand_ready,
962
};