2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 * Each flash chip is arranged in 64kB sectors; the
22 * chip cannot erase in units smaller than that.
24 * Writing happens in units of 256 byte pages and
25 * can only change bits from 1 to 0. So, you can rewrite
26 * the same contents, or append to an existing page easily enough
29 #define M25_WREN 0x06 /* Write Enable */
30 #define M25_WRDI 0x04 /* Write Disable */
31 #define M25_RDID 0x9f /* Read Identification */
32 #define M25_RDSR 0x05 /* Read Status Register */
33 #define M25_WRSR 0x01 /* Write Status Register */
34 #define M25_READ 0x03 /* Read Data Bytes */
35 #define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
36 #define M25_PP 0x02 /* Page Program */
37 #define M25_SE 0xd8 /* Sector Erase */
38 #define M25_BE 0xc7 /* Bulk Erase */
39 #define M25_DP 0xb9 /* Deep Power-down */
42 #define M25_MANUF_OFFSET 0
43 #define M25_MEMORY_TYPE_OFFSET 1
44 #define M25_CAPACITY_OFFSET 2
45 #define M25_UID_OFFSET 3
46 #define M25_CFI_OFFSET 4
47 #define M25_RDID_LEN 4 /* that's all we need */
49 #define M25_CAPACITY_128KB 0x11
50 #define M25_CAPACITY_256KB 0x12
51 #define M25_CAPACITY_512KB 0x13
52 #define M25_CAPACITY_1MB 0x14
53 #define M25_CAPACITY_2MB 0x15
56 * Status register bits
59 #define M25_STATUS_SRWD (1 << 7) /* Status register write disable */
60 #define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */
61 #define M25_STATUS_BP_SHIFT (2)
62 #define M25_STATUS_WEL (1 << 1) /* Write enable latch */
63 #define M25_STATUS_WIP (1 << 0) /* Write in progress */
66 * On teleterra, the m25 chip select pins are
67 * wired on P0_0 through P0_3.
70 #define AO_M25_MAX_CHIPS 4
72 static uint8_t ao_m25_size[AO_M25_MAX_CHIPS]; /* number of sectors in each chip */
73 static uint8_t ao_m25_pin[AO_M25_MAX_CHIPS]; /* chip select pin for each chip */
74 static uint8_t ao_m25_numchips; /* number of chips detected */
75 static uint8_t ao_m25_total; /* total sectors available */
76 static uint8_t ao_m25_wip; /* write in progress */
78 static __xdata uint8_t ao_m25_mutex;
81 * This little array is abused to send and receive data. A particular
82 * caution -- the read and write addresses are written into the last
83 * three bytes of the array by ao_m25_set_page_address and then the
84 * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither
85 * of which touch those last three bytes.
88 static __xdata uint8_t ao_m25_instruction[4];
90 #define AO_M25_SELECT(cs) (SPI_CS_PORT &= ~(cs))
91 #define AO_M25_DESELECT(cs) (SPI_CS_PORT |= (cs))
92 #define AO_M25_PAGE_TO_SECTOR(page) ((page) >> 8)
93 #define AO_M25_SECTOR_TO_PAGE(sector) (((uint16_t) (sector)) << 8)
96 * Block until the specified chip is done writing
99 ao_m25_wait_wip(uint8_t cs)
101 if (ao_m25_wip & cs) {
103 ao_m25_instruction[0] = M25_RDSR;
104 ao_spi_send(ao_m25_instruction, 1);
106 ao_spi_recv(ao_m25_instruction, 1);
107 } while (ao_m25_instruction[0] & M25_STATUS_WIP);
114 * Set the write enable latch so that page program and sector
115 * erase commands will work. Also mark the chip as busy writing
116 * so that future operations will block until the WIP bit goes off
119 ao_m25_write_enable(uint8_t cs)
122 ao_m25_instruction[0] = M25_WREN;
123 ao_spi_send(&ao_m25_instruction, 1);
130 * Returns the number of 64kB sectors
133 ao_m25_read_capacity(uint8_t cs)
137 ao_m25_instruction[0] = M25_RDID;
138 ao_spi_send(ao_m25_instruction, 1);
139 ao_spi_recv(ao_m25_instruction, M25_RDID_LEN);
142 /* Check to see if the chip is present */
143 if (ao_m25_instruction[0] == 0xff)
145 capacity = ao_m25_instruction[M25_CAPACITY_OFFSET];
147 /* Sanity check capacity number */
148 if (capacity < 0x11 || 0x1f < capacity)
150 return 1 << (capacity - 0x10);
154 ao_m25_set_page_address(uint16_t page)
158 for (chip = 0; chip < ao_m25_numchips; chip++) {
159 size = ao_m25_size[chip];
160 if (AO_M25_PAGE_TO_SECTOR(page) < size)
162 page -= AO_M25_SECTOR_TO_PAGE(size);
164 if (chip == ao_m25_numchips)
165 ao_panic(AO_PANIC_EE);
167 chip = ao_m25_pin[chip];
168 ao_m25_wait_wip(chip);
170 ao_m25_instruction[1] = page >> 8;
171 ao_m25_instruction[2] = page;
172 ao_m25_instruction[3] = 0;
177 * Scan the possible chip select lines
178 * to see which flash chips are connected
189 for (pin = 1; pin != 0; pin <<= 1) {
190 if (M25_CS_MASK & pin) {
191 size = ao_m25_read_capacity(pin);
193 ao_m25_size[ao_m25_numchips] = size;
194 ao_m25_pin[ao_m25_numchips] = pin;
195 ao_m25_total += size;
203 * Erase the specified sector
206 ao_flash_erase_sector(uint8_t sector) __reentrant
209 uint16_t page = AO_M25_SECTOR_TO_PAGE(sector);
211 ao_mutex_get(&ao_m25_mutex);
214 cs = ao_m25_set_page_address(page);
216 ao_m25_write_enable(cs);
218 ao_m25_instruction[0] = M25_SE;
220 ao_spi_send(ao_m25_instruction, 4);
224 ao_mutex_put(&ao_m25_mutex);
231 ao_flash_write_page(uint16_t page, uint8_t __xdata *d) __reentrant
235 ao_mutex_get(&ao_m25_mutex);
238 cs = ao_m25_set_page_address(page);
239 ao_m25_write_enable(cs);
241 ao_m25_instruction[0] = M25_PP;
243 ao_spi_send(ao_m25_instruction, 4);
247 ao_mutex_put(&ao_m25_mutex);
254 ao_flash_read_page(uint16_t page, __xdata uint8_t *d) __reentrant
258 ao_mutex_get(&ao_m25_mutex);
261 cs = ao_m25_set_page_address(page);
263 /* No need to use the FAST_READ as we're running at only 8MHz */
264 ao_m25_instruction[0] = M25_READ;
266 ao_spi_send(ao_m25_instruction, 4);
270 ao_mutex_put(&ao_m25_mutex);
273 static __xdata uint8_t ao_flash_block[256];
276 ao_flash_dump(void) __reentrant
281 if (ao_cmd_status != ao_cmd_success)
283 ao_flash_read_page(ao_cmd_lex_i, ao_flash_block);
289 ao_cmd_put16((uint16_t) i);
292 ao_cmd_put8(ao_flash_block[i]);
299 ao_flash_store(void) __reentrant
307 block = ao_cmd_lex_i;
312 if (ao_cmd_status != ao_cmd_success)
314 ao_flash_read_page(block, ao_flash_block);
317 if (ao_cmd_status != ao_cmd_success)
320 ao_flash_block[i] = ao_cmd_lex_i;
323 ao_flash_write_page(block, ao_flash_block);
327 ao_flash_info(void) __reentrant
331 ao_mutex_get(&ao_m25_mutex);
333 ao_mutex_put(&ao_m25_mutex);
335 printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total);
336 for (chip = 0; chip < ao_m25_numchips; chip++)
337 printf ("Flash chip %d select %02x size %d manf %02x type %02x cap %02x uid %02x\n",
338 chip, ao_m25_pin[chip], ao_m25_size[chip]);
340 printf ("Available chips:\n");
341 for (cs = 1; cs != 0; cs <<= 1) {
342 if ((M25_CS_MASK & cs) == 0)
345 ao_mutex_get(&ao_m25_mutex);
347 ao_m25_instruction[0] = M25_RDID;
348 ao_spi_send(ao_m25_instruction, 1);
349 ao_spi_recv(ao_m25_instruction, M25_RDID_LEN);
352 printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n",
354 ao_m25_instruction[M25_MANUF_OFFSET],
355 ao_m25_instruction[M25_MEMORY_TYPE_OFFSET],
356 ao_m25_instruction[M25_CAPACITY_OFFSET],
357 ao_m25_instruction[M25_UID_OFFSET]);
358 ao_mutex_put(&ao_m25_mutex);
362 __code struct ao_cmds ao_flash_cmds[] = {
363 { 'e', ao_flash_dump, "e <block> Dump a block of EEPROM data" },
364 { 'w', ao_flash_store, "w <block> <start> <len> <data> ... Write data to EEPROM" },
365 { 'F', ao_flash_info, "F Display flash info" },
366 { 0, ao_flash_store, NULL },
372 /* Set up chip select wires */
373 SPI_CS_PORT |= M25_CS_MASK; /* raise all CS pins */
374 SPI_CS_DIR |= M25_CS_MASK; /* set CS pins as outputs */
375 SPI_CS_SEL &= ~M25_CS_MASK; /* set CS pins as GPIO */
376 ao_cmd_register(&ao_flash_cmds[0]);