flash.c 13.6 KB
Newer Older
W
wdenk 已提交
1
/*
W
wdenk 已提交
2 3
 * (C) Copyright 2002, 2003
 * Daniel Engstrm, Omicron Ceti AB, daniel@omicron.se
W
wdenk 已提交
4
 *
W
wdenk 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Alex Zuepke <azu@sysgo.de>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
W
wdenk 已提交
29 30 31
#include <asm/io.h>
#include <pci.h>
#include <asm/ic/sc520.h>
W
wdenk 已提交
32

W
wdenk 已提交
33 34
#define PROBE_BUFFER_SIZE 1024
static unsigned char buffer[PROBE_BUFFER_SIZE];
W
wdenk 已提交
35

W
wdenk 已提交
36 37 38 39 40
#define SC520_MAX_FLASH_BANKS  3
#define SC520_FLASH_BANK0_BASE 0x38000000  /* BOOTCS */
#define SC520_FLASH_BANK1_BASE 0x30000000  /* ROMCS0 */
#define SC520_FLASH_BANK2_BASE 0x28000000  /* ROMCS1 */
#define SC520_FLASH_BANKSIZE   0x8000000
W
wdenk 已提交
41

W
wdenk 已提交
42 43
#define AMD29LV016B_SIZE        0x200000
#define AMD29LV016B_SECTORS     32
W
wdenk 已提交
44

W
wdenk 已提交
45
flash_info_t    flash_info[SC520_MAX_FLASH_BANKS];
W
wdenk 已提交
46 47 48 49 50 51 52 53

#define READY 1
#define ERR   2
#define TMO   4

/*-----------------------------------------------------------------------
 */

W
wdenk 已提交
54 55

static u32 _probe_flash(u32 addr, u32 bw, int il)
W
wdenk 已提交
56
{
W
wdenk 已提交
57
	u32 result=0;
W
wdenk 已提交
58

W
wdenk 已提交
59 60
	/* First do an unlock cycle for the benefit of
	 * devices that need it */
W
wdenk 已提交
61

W
wdenk 已提交
62
	switch (bw) {
W
wdenk 已提交
63

W
wdenk 已提交
64 65 66 67
	case 1:
		*(volatile u8*)(addr+0x5555) = 0xaa;
		*(volatile u8*)(addr+0x2aaa) = 0x55;
		*(volatile u8*)(addr+0x5555) = 0x90;
W
wdenk 已提交
68

W
wdenk 已提交
69 70 71
		/* Read vendor */
		result = *(volatile u8*)addr;
		result <<= 16;
W
wdenk 已提交
72

W
wdenk 已提交
73 74
		/* Read device */
		result |= *(volatile u8*)(addr+2);
W
wdenk 已提交
75

W
wdenk 已提交
76 77
		/* Return device to data mode */
		*(volatile u8*)addr = 0xff;
W
wdenk 已提交
78
		*(volatile u8*)(addr+0x5555), 0xf0;
W
wdenk 已提交
79
		break;
W
wdenk 已提交
80

W
wdenk 已提交
81 82 83
	case 2:
		*(volatile u16*)(addr+0xaaaa) = 0xaaaa;
		*(volatile u16*)(addr+0x5554) = 0x5555;
W
wdenk 已提交
84

W
wdenk 已提交
85 86 87
		/* Issue identification command */
		if (il == 2) {
			*(volatile u16*)(addr+0xaaaa) = 0x9090;
W
wdenk 已提交
88

W
wdenk 已提交
89 90 91
			/* Read vendor */
			result = *(volatile u8*)addr;
			result <<= 16;
W
wdenk 已提交
92

W
wdenk 已提交
93 94
			/* Read device */
			result |= *(volatile u8*)(addr+2);
W
wdenk 已提交
95

W
wdenk 已提交
96 97
			/* Return device to data mode */
			*(volatile u16*)addr =  0xffff;
W
wdenk 已提交
98 99
			*(volatile u16*)(addr+0xaaaa), 0xf0f0;

W
wdenk 已提交
100 101 102 103 104
		} else {
			*(volatile u8*)(addr+0xaaaa) = 0x90;
			/* Read vendor */
			result = *(volatile u16*)addr;
			result <<= 16;
W
wdenk 已提交
105

W
wdenk 已提交
106 107
			/* Read device */
			result |= *(volatile u16*)(addr+2);
W
wdenk 已提交
108

W
wdenk 已提交
109 110
			/* Return device to data mode */
			*(volatile u8*)addr = 0xff;
W
wdenk 已提交
111
			*(volatile u8*)(addr+0xaaaa), 0xf0;
W
wdenk 已提交
112
		}
W
wdenk 已提交
113

W
wdenk 已提交
114
		break;
W
wdenk 已提交
115

W
wdenk 已提交
116 117 118
	 case 4:
		*(volatile u32*)(addr+0x5554) = 0xaaaaaaaa;
		*(volatile u32*)(addr+0xaaa8) = 0x55555555;
W
wdenk 已提交
119

W
wdenk 已提交
120 121 122 123
		switch (il) {
		case 1:
			/* Issue identification command */
			*(volatile u8*)(addr+0x5554) = 0x90;
W
wdenk 已提交
124

W
wdenk 已提交
125 126 127
			/* Read vendor */
			result = *(volatile u16*)addr;
			result <<= 16;
W
wdenk 已提交
128

W
wdenk 已提交
129 130
			/* Read device */
			result |= *(volatile u16*)(addr+4);
W
wdenk 已提交
131

W
wdenk 已提交
132 133
			/* Return device to data mode */
			*(volatile u8*)addr =  0xff;
W
wdenk 已提交
134
			*(volatile u8*)(addr+0x5554), 0xf0;
W
wdenk 已提交
135
			break;
W
wdenk 已提交
136

W
wdenk 已提交
137 138 139
		case 2:
			/* Issue identification command */
			*(volatile u32*)(addr + 0x5554) = 0x00900090;
W
wdenk 已提交
140

W
wdenk 已提交
141 142 143
			/* Read vendor */
			result = *(volatile u16*)addr;
			result <<= 16;
W
wdenk 已提交
144

W
wdenk 已提交
145 146
			/* Read device */
			result |= *(volatile u16*)(addr+4);
W
wdenk 已提交
147

W
wdenk 已提交
148 149
			/* Return device to data mode */
			*(volatile u32*)addr =  0x00ff00ff;
W
wdenk 已提交
150
			*(volatile u32*)(addr+0x5554), 0x00f000f0;
W
wdenk 已提交
151
			break;
W
wdenk 已提交
152

W
wdenk 已提交
153 154 155
		case 4:
			/* Issue identification command */
			*(volatile u32*)(addr+0x5554) = 0x90909090;
W
wdenk 已提交
156

W
wdenk 已提交
157 158 159
			/* Read vendor */
			result = *(volatile u8*)addr;
			result <<= 16;
W
wdenk 已提交
160

W
wdenk 已提交
161 162
			/* Read device */
			result |= *(volatile u8*)(addr+4);
W
wdenk 已提交
163

W
wdenk 已提交
164 165
			/* Return device to data mode */
			*(volatile u32*)addr =  0xffffffff;
W
wdenk 已提交
166
			*(volatile u32*)(addr+0x5554), 0xf0f0f0f0;
W
wdenk 已提交
167
			break;
W
wdenk 已提交
168
		}
W
wdenk 已提交
169 170
		break;
	}
W
wdenk 已提交
171 172


W
wdenk 已提交
173 174 175 176 177 178
	return result;
}

extern int _probe_flash_end;
asm ("_probe_flash_end:\n"
     ".long 0\n");
W
wdenk 已提交
179

W
wdenk 已提交
180 181
static int identify_flash(unsigned address, int width)
{
W
wdenk 已提交
182
	int is;
W
wdenk 已提交
183
	int device;
W
wdenk 已提交
184
	int vendor;
W
wdenk 已提交
185 186
	int size;
	unsigned res;
W
wdenk 已提交
187

W
wdenk 已提交
188
	u32 (*_probe_flash_ptr)(u32 a, u32 bw, int il);
W
wdenk 已提交
189 190 191

	size = (unsigned)&_probe_flash_end - (unsigned)_probe_flash;

W
wdenk 已提交
192 193 194 195 196
	if (size > PROBE_BUFFER_SIZE) {
		printf("_probe_flash() routine too large (%d) %p - %p\n",
		       size, &_probe_flash_end, _probe_flash);
		return 0;
	}
W
wdenk 已提交
197

W
wdenk 已提交
198 199
	memcpy(buffer, _probe_flash, size);
	_probe_flash_ptr = (void*)buffer;
W
wdenk 已提交
200

W
wdenk 已提交
201 202 203 204 205
	is = disable_interrupts();
	res = _probe_flash_ptr(address, width, 1);
	if (is) {
		enable_interrupts();
	}
W
wdenk 已提交
206 207 208


	vendor = res >> 16;
W
wdenk 已提交
209
	device = res & 0xffff;
W
wdenk 已提交
210 211


W
wdenk 已提交
212 213 214 215 216 217 218
	return res;
}

ulong flash_init(void)
{
	int i, j;
	ulong size = 0;
W
wdenk 已提交
219

W
wdenk 已提交
220 221 222
	for (i = 0; i < SC520_MAX_FLASH_BANKS; i++) {
		unsigned id;
		ulong flashbase = 0;
W
wdenk 已提交
223 224
		int sectsize = 0;

W
wdenk 已提交
225 226 227 228 229 230 231 232 233 234 235 236 237 238
		memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);
		switch (i) {
		case 0:
			flashbase = SC520_FLASH_BANK0_BASE;
			break;
		case 1:
			flashbase = SC520_FLASH_BANK1_BASE;
			break;
		case 2:
			flashbase = SC520_FLASH_BANK2_BASE;
			break;
		default:
			panic("configured to many flash banks!\n");
		}
W
wdenk 已提交
239

W
wdenk 已提交
240 241 242 243 244 245 246
		id = identify_flash(flashbase, 4);
		switch (id & 0x00ff00ff) {
		case 0x000100c8:
			/* 29LV016B/29LV017B */
			flash_info[i].flash_id =
				(AMD_MANUFACT & FLASH_VENDMASK) |
				(AMD_ID_LV016B & FLASH_TYPEMASK);
W
wdenk 已提交
247

W
wdenk 已提交
248 249 250 251 252
			flash_info[i].size = AMD29LV016B_SIZE*4;
			flash_info[i].sector_count = AMD29LV016B_SECTORS;
			sectsize = (AMD29LV016B_SIZE*4)/AMD29LV016B_SECTORS;
			printf("Bank %d: 4 x AMD 29LV017B\n", i);
			break;
W
wdenk 已提交
253 254


W
wdenk 已提交
255 256 257 258 259
		default:
			printf("Bank %d have unknown flash %08x\n", i, id);
			flash_info[i].flash_id = FLASH_UNKNOWN;
			continue;
		}
W
wdenk 已提交
260

W
wdenk 已提交
261 262
		for (j = 0; j < flash_info[i].sector_count; j++) {
			flash_info[i].start[j] = flashbase + j * sectsize;
W
wdenk 已提交
263
		}
W
wdenk 已提交
264
		size += flash_info[i].size;
W
wdenk 已提交
265

W
wdenk 已提交
266 267 268 269
		flash_protect(FLAG_PROTECT_CLEAR,
			      flash_info[i].start[0],
			       flash_info[i].start[0] + flash_info[i].size - 1,
			      &flash_info[i]);
W
wdenk 已提交
270
	}
W
wdenk 已提交
271

W
wdenk 已提交
272 273 274 275 276 277 278 279 280 281 282 283
	/*
	 * Protect monitor and environment sectors
	 */
	flash_protect(FLAG_PROTECT_SET,
		      i386boot_start,
		      i386boot_end,
		      &flash_info[0]);
#ifdef CFG_ENV_ADDR
	flash_protect(FLAG_PROTECT_SET,
		      CFG_ENV_ADDR,
		      CFG_ENV_ADDR + CFG_ENV_SIZE - 1,
		      &flash_info[0]);
W
wdenk 已提交
284
#endif
W
wdenk 已提交
285
	return size;
W
wdenk 已提交
286 287 288 289
}

/*-----------------------------------------------------------------------
 */
W
wdenk 已提交
290
void flash_print_info(flash_info_t *info)
W
wdenk 已提交
291
{
W
wdenk 已提交
292
	int i;
W
wdenk 已提交
293

W
wdenk 已提交
294
	switch (info->flash_id & FLASH_VENDMASK) {
W
wdenk 已提交
295

W
wdenk 已提交
296 297 298 299 300 301 302 303 304 305 306
	case (AMD_MANUFACT & FLASH_VENDMASK):
		printf("AMD:   ");
		switch (info->flash_id & FLASH_TYPEMASK) {
		case (AMD_ID_LV016B & FLASH_TYPEMASK):
			printf("4x AMD29LV017B (4x16Mbit)\n");
			break;
		default:
			printf("Unknown Chip Type\n");
			goto done;
			break;
		}
W
wdenk 已提交
307

W
wdenk 已提交
308 309 310 311
		break;
	default:
		printf("Unknown Vendor ");
		break;
W
wdenk 已提交
312
	}
W
wdenk 已提交
313 314


W
wdenk 已提交
315 316
	printf("  Size: %ld MB in %d Sectors\n",
	       info->size >> 20, info->sector_count);
W
wdenk 已提交
317

W
wdenk 已提交
318 319 320 321 322 323 324 325 326
	printf("  Sector Start Addresses:");
	for (i = 0; i < info->sector_count; i++) {
		if ((i % 5) == 0) {
			printf ("\n   ");
		}
		printf (" %08lX%s", info->start[i],
			info->protect[i] ? " (RO)" : "     ");
	}
	printf ("\n");
W
wdenk 已提交
327

328
done:	;
W
wdenk 已提交
329 330 331 332 333
}

/*-----------------------------------------------------------------------
 */

W
wdenk 已提交
334 335 336 337 338 339 340
/* this needs to be inlined, the SWTMRMMILLI register is reset by each read */
#define __udelay(delay) \
{	\
	unsigned micro; \
	unsigned milli=0; \
	\
	micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
W
wdenk 已提交
341
	 \
W
wdenk 已提交
342 343 344 345 346 347 348 349 350
	for (;;) { \
		\
		milli += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); \
		micro = *(volatile u16*)(0xfffef000+SC520_SWTMRMICRO); \
		\
		if ((delay) <= (micro + (milli * 1000))) { \
			break; \
		} \
	} \
W
wdenk 已提交
351
} while (0)
W
wdenk 已提交
352 353

static u32 _amd_erase_flash(u32 addr, u32 sector)
W
wdenk 已提交
354
{
W
wdenk 已提交
355
	unsigned elapsed;
W
wdenk 已提交
356

W
wdenk 已提交
357 358 359 360 361 362 363 364 365
	/* Issue erase */
	*(volatile u32*)(addr + 0x5554) = 0xAAAAAAAA;
	*(volatile u32*)(addr + 0xaaa8) = 0x55555555;
	*(volatile u32*)(addr + 0x5554) = 0x80808080;
	/* And one unlock */
	*(volatile u32*)(addr + 0x5554) = 0xAAAAAAAA;
	*(volatile u32*)(addr + 0xaaa8) = 0x55555555;
	/* Sector erase command comes last */
	*(volatile u32*)(addr + sector) = 0x30303030;
W
wdenk 已提交
366

W
wdenk 已提交
367 368 369 370
	elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
	elapsed = 0;
	__udelay(50);
	while (((*(volatile u32*)(addr + sector)) & 0x80808080) != 0x80808080) {
W
wdenk 已提交
371

W
wdenk 已提交
372 373 374
		elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
		if (elapsed > ((CFG_FLASH_ERASE_TOUT/CFG_HZ) * 1000)) {
			*(volatile u32*)(addr) = 0xf0f0f0f0;
W
wdenk 已提交
375
			return 1;
W
wdenk 已提交
376 377
		}
	}
W
wdenk 已提交
378

W
wdenk 已提交
379
	*(volatile u32*)(addr) = 0xf0f0f0f0;
W
wdenk 已提交
380

W
wdenk 已提交
381 382
	return 0;
}
W
wdenk 已提交
383

W
wdenk 已提交
384 385 386
extern int _amd_erase_flash_end;
asm ("_amd_erase_flash_end:\n"
     ".long 0\n");
W
wdenk 已提交
387

W
wdenk 已提交
388 389 390 391 392 393
int flash_erase(flash_info_t *info, int s_first, int s_last)
{
	u32 (*_erase_flash_ptr)(u32 a, u32 so);
	int prot;
	int sect;
	unsigned size;
W
wdenk 已提交
394

W
wdenk 已提交
395 396 397 398 399 400 401
	if ((s_first < 0) || (s_first > s_last)) {
		if (info->flash_id == FLASH_UNKNOWN) {
			printf("- missing\n");
		} else {
			printf("- no sectors to erase\n");
		}
		return 1;
W
wdenk 已提交
402
	}
W
wdenk 已提交
403

W
wdenk 已提交
404
	if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
W
wdenk 已提交
405 406
		size = (unsigned)&_amd_erase_flash_end - (unsigned)_amd_erase_flash;

W
wdenk 已提交
407 408 409 410
		if (size > PROBE_BUFFER_SIZE) {
			printf("_amd_erase_flash() routine too large (%d) %p - %p\n",
			       size, &_amd_erase_flash_end, _amd_erase_flash);
			return 0;
W
wdenk 已提交
411
		}
W
wdenk 已提交
412

W
wdenk 已提交
413 414
		memcpy(buffer, _amd_erase_flash, size);
		_erase_flash_ptr = (void*)buffer;
W
wdenk 已提交
415

W
wdenk 已提交
416 417 418
	}  else {
		printf ("Can't erase unknown flash type - aborted\n");
		return 1;
W
wdenk 已提交
419
	}
W
wdenk 已提交
420

W
wdenk 已提交
421 422 423 424 425 426
	prot = 0;
	for (sect=s_first; sect<=s_last; ++sect) {
		if (info->protect[sect]) {
			prot++;
		}
	}
W
wdenk 已提交
427

W
wdenk 已提交
428 429 430 431 432
	if (prot) {
		printf ("- Warning: %d protected sectors will not be erased!\n", prot);
	} else {
		printf ("\n");
	}
W
wdenk 已提交
433 434


W
wdenk 已提交
435 436
	/* Start erase on unprotected sectors */
	for (sect = s_first; sect<=s_last; sect++) {
W
wdenk 已提交
437

W
wdenk 已提交
438 439 440
		if (info->protect[sect] == 0) { /* not protected */
			int res;
			int flag;
W
wdenk 已提交
441

W
wdenk 已提交
442 443
			/* Disable interrupts which might cause a timeout here */
			flag = disable_interrupts();
W
wdenk 已提交
444

W
wdenk 已提交
445
			res = _erase_flash_ptr(info->start[0], info->start[sect]-info->start[0]);
W
wdenk 已提交
446

W
wdenk 已提交
447 448 449 450
			/* re-enable interrupts if necessary */
			if (flag) {
				enable_interrupts();
			}
W
wdenk 已提交
451 452


W
wdenk 已提交
453 454 455 456
			if (res) {
				printf("Erase timed out, sector %d\n", sect);
				return res;
			}
W
wdenk 已提交
457 458 459

			putc('.');
		}
W
wdenk 已提交
460 461
	}

W
wdenk 已提交
462

W
wdenk 已提交
463
	return 0;
W
wdenk 已提交
464 465 466
}

/*-----------------------------------------------------------------------
W
wdenk 已提交
467 468 469 470
 * Write a word to Flash, returns:
 * 0 - OK
 * 1 - write timeout
 * 2 - Flash not erased
W
wdenk 已提交
471
 */
W
wdenk 已提交
472
static int _amd_write_word(unsigned start, unsigned dest, unsigned data)
W
wdenk 已提交
473
{
W
wdenk 已提交
474 475 476 477
	volatile u32 *addr2 = (u32*)start;
	volatile u32 *dest2 = (u32*)dest;
	volatile u32 *data2 = (u32*)&data;
	unsigned elapsed;
W
wdenk 已提交
478

W
wdenk 已提交
479 480 481
	/* Check if Flash is (sufficiently) erased */
	if ((*((volatile u32*)dest) & (u32)data) != (u32)data) {
		return 2;
W
wdenk 已提交
482
	}
W
wdenk 已提交
483

W
wdenk 已提交
484 485 486
	addr2[0x5554] = 0xAAAAAAAA;
	addr2[0xaaa8] = 0x55555555;
	addr2[0x5554] = 0xA0A0A0A0;
W
wdenk 已提交
487

W
wdenk 已提交
488
	dest2[0] = data;
W
wdenk 已提交
489

W
wdenk 已提交
490 491
	elapsed = *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI); /* dummy read */
	elapsed = 0;
W
wdenk 已提交
492

W
wdenk 已提交
493 494 495 496 497
	/* data polling for D7 */
	while ((dest2[0] & 0x80808080) != (data2[0] & 0x80808080)) {
		elapsed += *(volatile u16*)(0xfffef000+SC520_SWTMRMILLI);
		if (elapsed > ((CFG_FLASH_WRITE_TOUT/CFG_HZ) * 1000)) {
			addr2[0] = 0xf0f0f0f0;
W
wdenk 已提交
498
			return 1;
W
wdenk 已提交
499
		}
W
wdenk 已提交
500 501
	}

W
wdenk 已提交
502

W
wdenk 已提交
503
	addr2[0] = 0xf0f0f0f0;
W
wdenk 已提交
504

W
wdenk 已提交
505 506
	return 0;
}
W
wdenk 已提交
507

W
wdenk 已提交
508 509 510
extern int _amd_write_word_end;
asm ("_amd_write_word_end:\n"
     ".long 0\n");
W
wdenk 已提交
511 512 513


/*-----------------------------------------------------------------------
W
wdenk 已提交
514 515 516 517 518
 * Copy memory to flash, returns:
 * 0 - OK
 * 1 - write timeout
 * 2 - Flash not erased
 * 3 - Unsupported flash type
W
wdenk 已提交
519 520
 */

W
wdenk 已提交
521
int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
W
wdenk 已提交
522
{
W
wdenk 已提交
523 524 525 526 527
	ulong cp, wp, data;
	int i, l, rc;
	int flag;
	u32 (*_write_word_ptr)(unsigned start, unsigned dest, unsigned data);
	unsigned size;
W
wdenk 已提交
528

W
wdenk 已提交
529
	if ((info->flash_id & FLASH_VENDMASK) == (AMD_MANUFACT & FLASH_VENDMASK)) {
W
wdenk 已提交
530 531
		size = (unsigned)&_amd_write_word_end - (unsigned)_amd_write_word;

W
wdenk 已提交
532 533 534 535 536
		if (size > PROBE_BUFFER_SIZE) {
			printf("_amd_write_word() routine too large (%d) %p - %p\n",
			       size, &_amd_write_word_end, _amd_write_word);
			return 0;
		}
W
wdenk 已提交
537

W
wdenk 已提交
538 539
		memcpy(buffer, _amd_write_word, size);
		_write_word_ptr = (void*)buffer;
W
wdenk 已提交
540

W
wdenk 已提交
541 542 543 544
	} else {
		printf ("Can't program unknown flash type - aborted\n");
		return 3;
	}
W
wdenk 已提交
545 546


W
wdenk 已提交
547
	wp = (addr & ~3);	/* get lower word aligned address */
W
wdenk 已提交
548

W
wdenk 已提交
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565

	/*
	 * handle unaligned start bytes
	 */
	if ((l = addr - wp) != 0) {
		data = 0;
		for (i=0, cp=wp; i<l; ++i, ++cp) {
			data |= (*(uchar *)cp) << (8*i);
		}
		for (; i<4 && cnt>0; ++i) {
			data |= *src++ << (8*i);
			--cnt;
			++cp;
		}
		for (; cnt==0 && i<4; ++i, ++cp) {
			data |= (*(uchar *)cp)  << (8*i);
		}
W
wdenk 已提交
566

W
wdenk 已提交
567 568
		/* Disable interrupts which might cause a timeout here */
		flag = disable_interrupts();
W
wdenk 已提交
569

W
wdenk 已提交
570
		rc = _write_word_ptr(info->start[0], wp, data);
W
wdenk 已提交
571

W
wdenk 已提交
572 573 574 575 576 577 578 579
		/* re-enable interrupts if necessary */
		if (flag) {
			enable_interrupts();
		}
		if (rc != 0) {
			return rc;
		}
		wp += 4;
W
wdenk 已提交
580
	}
W
wdenk 已提交
581

W
wdenk 已提交
582 583 584 585 586
	/*
	 * handle word aligned part
	 */
	while (cnt >= 4) {
		data = 0;
W
wdenk 已提交
587

W
wdenk 已提交
588 589 590
		for (i=0; i<4; ++i) {
			data |= *src++ << (8*i);
		}
W
wdenk 已提交
591

W
wdenk 已提交
592 593 594 595
		/* Disable interrupts which might cause a timeout here */
		flag = disable_interrupts();

		rc = _write_word_ptr(info->start[0], wp, data);
W
wdenk 已提交
596

W
wdenk 已提交
597 598 599 600 601 602 603 604 605
		/* re-enable interrupts if necessary */
		if (flag) {
			enable_interrupts();
		}
		if (rc != 0) {
			return rc;
		}
		wp  += 4;
		cnt -= 4;
W
wdenk 已提交
606
	}
W
wdenk 已提交
607

W
wdenk 已提交
608 609
	if (cnt == 0) {
		return 0;
W
wdenk 已提交
610
	}
W
wdenk 已提交
611

W
wdenk 已提交
612 613 614 615 616 617 618
	/*
	 * handle unaligned tail bytes
	 */
	data = 0;
	for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
		data |= *src++ << (8*i);
		--cnt;
W
wdenk 已提交
619
	}
W
wdenk 已提交
620

W
wdenk 已提交
621 622
	for (; i<4; ++i, ++cp) {
		data |= (*(uchar *)cp) << (8*i);
W
wdenk 已提交
623
	}
W
wdenk 已提交
624 625 626 627 628

	/* Disable interrupts which might cause a timeout here */
	flag = disable_interrupts();

	rc = _write_word_ptr(info->start[0], wp, data);
W
wdenk 已提交
629

W
wdenk 已提交
630 631 632 633 634
	/* re-enable interrupts if necessary */
	if (flag) {
		enable_interrupts();
	}

W
wdenk 已提交
635
	return rc;
W
wdenk 已提交
636

W
wdenk 已提交
637
}