jedec.c 5.88 KB
Newer Older
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
/*
 * jedec.c: driver for programming JEDEC standard flash parts
 *
 *
 * Copyright 2000 Silicon Integrated System Corporation
 *
 *	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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 * Reference:
 *
 * $Id$
 */

Ronald G. Minnich's avatar
Ronald G. Minnich committed
27
#include <stdio.h>
28 29 30
#include "flash.h"
#include "jedec.h"

31
int probe_jedec(struct flashchip *flash)
32
{
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
	volatile char *bios = flash->virt_addr;
	unsigned char id1, id2;

	/* Issue JEDEC Product ID Entry command */
	*(volatile char *) (bios + 0x5555) = 0xAA;
	myusec_delay(10);
	*(volatile char *) (bios + 0x2AAA) = 0x55;
	myusec_delay(10);
	*(volatile char *) (bios + 0x5555) = 0x90;
	myusec_delay(10);

	/* Read product ID */
	id1 = *(volatile unsigned char *) bios;
	id2 = *(volatile unsigned char *) (bios + 0x01);

	/* Issue JEDEC Product ID Exit command */
	*(volatile char *) (bios + 0x5555) = 0xAA;
	myusec_delay(10);
	*(volatile char *) (bios + 0x2AAA) = 0x55;
	myusec_delay(10);
	*(volatile char *) (bios + 0x5555) = 0xF0;
	myusec_delay(10);
55

Ollie Lho's avatar
Ollie Lho committed
56
	printf("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
57 58
	if (id1 == flash->manufacture_id && id2 == flash->model_id)
		return 1;
59

60
	return 0;
Ollie Lho's avatar
Ollie Lho committed
61
}
62

63
int erase_sector_jedec(volatile char *bios, unsigned int page)
Ollie Lho's avatar
Ollie Lho committed
64 65
{
	volatile unsigned char *Temp;
66

67 68 69 70 71 72
	/*  Issue the Sector Erase command   */
	Temp = bios + 0x5555;	/* set up address to be BASE:5555h      */
	*Temp = 0xAA;		/* write data 0xAA to the address       */
	myusec_delay(10);
	Temp = bios + 0x2AAA;	/* set up address to be BASE:2AAAh      */
	*Temp = 0x55;		/* write data 0x55 to the address       */
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
73
	myusec_delay(10);
74 75
	Temp = bios + 0x5555;	/* set up address to be BASE:5555h      */
	*Temp = 0x80;		/* write data 0x80 to the address       */
Ollie Lho's avatar
Ollie Lho committed
76
	myusec_delay(10);
77 78
	Temp = bios + 0x5555;	/* set up address to be BASE:5555h      */
	*Temp = 0xAA;		/* write data 0xAA to the address       */
Ollie Lho's avatar
Ollie Lho committed
79
	myusec_delay(10);
80 81
	Temp = bios + 0x2AAA;	/* set up address to be BASE:2AAAh      */
	*Temp = 0x55;		/* write data 0x55 to the address       */
Ollie Lho's avatar
Ollie Lho committed
82
	myusec_delay(10);
83 84
	Temp = bios + page;	/* set up address to be the current sector */
	*Temp = 0x30;		/* write data 0x30 to the address       */
Ollie Lho's avatar
Ollie Lho committed
85
	myusec_delay(10);
86

Ollie Lho's avatar
Ollie Lho committed
87 88
	/* wait for Toggle bit ready         */
	toggle_ready_jedec(bios);
89

90
	return (0);
91 92
}

93
int erase_chip_jedec(struct flashchip *flash)
94
{
95
	volatile unsigned char *bios = flash->virt_addr;
Ollie Lho's avatar
Ollie Lho committed
96
	volatile unsigned char *Temp;
97

98 99 100
	/*  Issue the JEDEC Chip Erase command   */
	Temp = bios + 0x5555;	/* set up address to be BASE:5555h      */
	*Temp = 0xAA;		/* write data 0xAA to the address       */
Ollie Lho's avatar
Ollie Lho committed
101
	myusec_delay(10);
102 103
	Temp = bios + 0x2AAA;	/* set up address to be BASE:2AAAh      */
	*Temp = 0x55;		/* write data 0x55 to the address       */
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
104
	myusec_delay(10);
105 106
	Temp = bios + 0x5555;	/* set up address to be BASE:5555h      */
	*Temp = 0x80;		/* write data 0x80 to the address       */
Ollie Lho's avatar
Ollie Lho committed
107
	myusec_delay(10);
108 109
	Temp = bios + 0x5555;	/* set up address to be BASE:5555h      */
	*Temp = 0xAA;		/* write data 0xAA to the address       */
Ollie Lho's avatar
Ollie Lho committed
110
	myusec_delay(10);
111 112
	Temp = bios + 0x2AAA;	/* set up address to be BASE:2AAAh      */
	*Temp = 0x55;		/* write data 0x55 to the address       */
Ollie Lho's avatar
Ollie Lho committed
113
	myusec_delay(10);
114 115
	Temp = bios + 0x5555;	/* set up address to be BASEy:5555h     */
	*Temp = 0x10;		/* write data 0x10 to the address       */
Ollie Lho's avatar
Ollie Lho committed
116 117
	myusec_delay(10);

118
	toggle_ready_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
119

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	return (0);
}

void write_page_jedec(volatile char *bios, char *src, volatile char *dst,
		      int page_size)
{
	int i;

	/* Issue JEDEC Data Unprotect comand */
	*(volatile char *) (bios + 0x5555) = 0xAA;
	*(volatile char *) (bios + 0x2AAA) = 0x55;
	*(volatile char *) (bios + 0x5555) = 0xA0;

	for (i = 0; i < page_size; i++) {
		/* transfer data from source to destination */
		*dst++ = *src++;
	}

	usleep(100);
	toggle_ready_jedec(dst - 1);
}

Ollie Lho's avatar
Ollie Lho committed
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
int wirte_byte_program_jedec(volatile unsigned char *bios, unsigned char *src,
			     volatile unsigned char *dst)
{
	volatile unsigned char *Temp;

	if (*dst != 0xff) {
		printf("FATAL: dst %p not erased (val 0x%x)\n",
		       dst, *dst);
		return (-1);
	}
	/* transfer data from source to destination */
	if (*src == 0xFF) {
		dst++, src++;
		/* If the data is 0xFF, don't program it */
		return 0;
	}
	/* Issue JEDEC Byte Program command */
	Temp = bios + 0x5555;
	*Temp = 0xAA;
	Temp = bios + 0x2AAA;
	*Temp = 0x55;
	Temp = bios + 0x5555;
	*Temp = 0xA0;
	*dst = *src;
	toggle_ready_jedec(bios);
	if (*dst != *src)
		printf("BAD! dst 0x%lx val 0x%x src 0x%x\n",
		       (unsigned long) dst, *dst, *src);
	dst++, src++;
	return 0;
}

int write_sector_jedec(volatile unsigned char *bios, unsigned char *src,
175 176
		       volatile unsigned char *dst,
		       unsigned int page_size)
177 178 179 180
{
	int i;

	for (i = 0; i < page_size; i++) {
Ollie Lho's avatar
Ollie Lho committed
181
		wirte_byte_program_jedec(bios, src, dst);
182 183 184
	}

	return (0);
185 186
}

187
int write_jedec(struct flashchip *flash, unsigned char *buf)
188 189
{
	int i;
Ollie Lho's avatar
Ollie Lho committed
190 191
	int total_size = flash->total_size * 1024;
	int page_size = flash->page_size;
192
	volatile unsigned char *bios = flash->virt_addr;
193

194 195
	erase_chip_jedec(flash);
	if (*bios != (unsigned char) 0xff) {
Ronald G. Minnich's avatar
Ronald G. Minnich committed
196 197 198
		printf("ERASE FAILED\n");
		return -1;
	}
199 200 201 202 203
	printf("Programming Page: ");
	for (i = 0; i < total_size / page_size; i++) {
		printf("%04d at address: 0x%08x", i, i * page_size);
		write_page_jedec(bios, buf + i * page_size,
				 bios + i * page_size, page_size);
Ollie Lho's avatar
Ollie Lho committed
204
		printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
205 206
	}
	printf("\n");
207
	protect_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
208

209
	return (0);
210
}