sst28sf040.c 4.36 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 27
/*
 * sst28sf040.c: driver for SST28SF040C flash models.
 *
 *
 * 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:
 *	4 MEgabit (512K x 8) SuperFlash EEPROM, SST28SF040 data sheet
 *
 * $Id$
 */

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

#define AUTO_PG_ERASE1		0x20
#define AUTO_PG_ERASE2		0xD0
34
#define AUTO_PGRM		0x10
35 36 37 38
#define CHIP_ERASE		0x30
#define RESET			0xFF
#define READ_ID			0x90

39
static __inline__ void protect_28sf040(volatile char *bios)
40 41 42 43
{
	/* ask compiler not to optimize this */
	volatile unsigned char tmp;

Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
44 45 46 47 48 49 50
	tmp = *(volatile unsigned char *) (bios + 0x1823);
	tmp = *(volatile unsigned char *) (bios + 0x1820);
	tmp = *(volatile unsigned char *) (bios + 0x1822);
	tmp = *(volatile unsigned char *) (bios + 0x0418);
	tmp = *(volatile unsigned char *) (bios + 0x041B);
	tmp = *(volatile unsigned char *) (bios + 0x0419);
	tmp = *(volatile unsigned char *) (bios + 0x040A);
51 52
}

53
static __inline__ void unprotect_28sf040(volatile char *bios)
54 55 56 57
{
	/* ask compiler not to optimize this */
	volatile unsigned char tmp;

Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
58 59 60 61 62 63 64
	tmp = *(volatile unsigned char *) (bios + 0x1823);
	tmp = *(volatile unsigned char *) (bios + 0x1820);
	tmp = *(volatile unsigned char *) (bios + 0x1822);
	tmp = *(volatile unsigned char *) (bios + 0x0418);
	tmp = *(volatile unsigned char *) (bios + 0x041B);
	tmp = *(volatile unsigned char *) (bios + 0x0419);
	tmp = *(volatile unsigned char *) (bios + 0x041A);
65 66
}

67 68
static __inline__ int erase_sector_28sf040(volatile char *bios,
					   unsigned long address)
69 70 71 72 73 74
{
	*bios = AUTO_PG_ERASE1;
	*(bios + address) = AUTO_PG_ERASE2;

	/* wait for Toggle bit ready         */
	toggle_ready_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
75

76
	return (0);
77 78
}

79 80 81 82
static __inline__ int write_sector_28sf040(volatile char *bios,
					   unsigned char *src,
					   volatile unsigned char *dst,
					   unsigned int page_size)
83 84 85 86 87 88 89 90 91 92 93
{
	int i;

	for (i = 0; i < page_size; i++) {
		/* transfer data from source to destination */
		if (*src == 0xFF) {
			dst++, src++;
			/* If the data is 0xFF, don't program it */
			continue;
		}
		/*issue AUTO PROGRAM command */
94
		*dst = AUTO_PGRM;
95 96 97 98 99
		*dst++ = *src++;

		/* wait for Toggle bit ready */
		toggle_ready_jedec(bios);
	}
Ronald G. Minnich's avatar
Ronald G. Minnich committed
100

101
	return (0);
102 103
}

104
int probe_28sf040(struct flashchip *flash)
105
{
106 107
	volatile char *bios = flash->virt_addr;
	unsigned char id1, id2, tmp;
108 109 110 111 112

	/* save the value at the beginning of the Flash */
	tmp = *bios;

	*bios = RESET;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
113
	myusec_delay(10);
114 115

	*bios = READ_ID;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
116 117 118 119
	myusec_delay(10);
	id1 = *(volatile unsigned char *) bios;
	myusec_delay(10);
	id2 = *(volatile unsigned char *) (bios + 0x01);
120 121

	*bios = RESET;
Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
122
	myusec_delay(10);
123

124
	printf("%s: id1 0x%x, id2 0x%x\n", __FUNCTION__, id1, id2);
125 126 127 128 129 130 131 132
	if (id1 == flash->manufacture_id && id2 == flash->model_id)
		return 1;

	/* if there is no SST28SF040, restore the original value */
	*bios = tmp;
	return 0;
}

133
int erase_28sf040(struct flashchip *flash)
134
{
135
	volatile char *bios = flash->virt_addr;
136

137
	unprotect_28sf040(bios);
138 139
	*bios = CHIP_ERASE;
	*bios = CHIP_ERASE;
140
	protect_28sf040(bios);
141

Ronald G. Minnich's avatar
Fixes  
Ronald G. Minnich committed
142
	myusec_delay(10);
143
	toggle_ready_jedec(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
144

145
	return (0);
146 147
}

148
int write_28sf040(struct flashchip *flash, unsigned char *buf)
149 150
{
	int i;
151 152 153
	int total_size = flash->total_size * 1024, page_size =
	    flash->page_size;
	volatile char *bios = flash->virt_addr;
154

155
	unprotect_28sf040(bios);
156

157 158
	printf("Programming Page: ");
	for (i = 0; i < total_size / page_size; i++) {
159 160 161 162
		/* erase the page before programming */
		erase_sector_28sf040(bios, i * page_size);

		/* write to the sector */
163 164 165 166 167
		printf("%04d at address: 0x%08x", i, i * page_size);
		write_sector_28sf040(bios, buf + i * page_size,
				     bios + i * page_size, page_size);
		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");
168 169 170
	}
	printf("\n");

171
	protect_28sf040(bios);
Ronald G. Minnich's avatar
Ronald G. Minnich committed
172

173
	return (0);
174
}