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.
20 /* Total bytes of available storage */
21 __pdata uint32_t ao_storage_total;
23 /* Block size - device is erased in these units. At least 256 bytes */
24 __pdata uint32_t ao_storage_block;
26 /* Byte offset of config block. Will be ao_storage_block bytes long */
27 __pdata uint32_t ao_storage_config;
29 /* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
30 __pdata uint16_t ao_storage_unit;
33 * Each flash chip is arranged in 64kB sectors; the
34 * chip cannot erase in units smaller than that.
36 * Writing happens in units of 256 byte pages and
37 * can only change bits from 1 to 0. So, you can rewrite
38 * the same contents, or append to an existing page easily enough
41 #define M25_WREN 0x06 /* Write Enable */
42 #define M25_WRDI 0x04 /* Write Disable */
43 #define M25_RDID 0x9f /* Read Identification */
44 #define M25_RDSR 0x05 /* Read Status Register */
45 #define M25_WRSR 0x01 /* Write Status Register */
46 #define M25_READ 0x03 /* Read Data Bytes */
47 #define M25_FAST_READ 0x0b /* Read Data Bytes at Higher Speed */
48 #define M25_PP 0x02 /* Page Program */
49 #define M25_SE 0xd8 /* Sector Erase */
50 #define M25_BE 0xc7 /* Bulk Erase */
51 #define M25_DP 0xb9 /* Deep Power-down */
54 #define M25_MANUF_OFFSET 0
55 #define M25_MEMORY_TYPE_OFFSET 1
56 #define M25_CAPACITY_OFFSET 2
57 #define M25_UID_OFFSET 3
58 #define M25_CFI_OFFSET 4
59 #define M25_RDID_LEN 4 /* that's all we need */
61 #define M25_CAPACITY_128KB 0x11
62 #define M25_CAPACITY_256KB 0x12
63 #define M25_CAPACITY_512KB 0x13
64 #define M25_CAPACITY_1MB 0x14
65 #define M25_CAPACITY_2MB 0x15
68 * Status register bits
71 #define M25_STATUS_SRWD (1 << 7) /* Status register write disable */
72 #define M25_STATUS_BP_MASK (7 << 2) /* Block protect bits */
73 #define M25_STATUS_BP_SHIFT (2)
74 #define M25_STATUS_WEL (1 << 1) /* Write enable latch */
75 #define M25_STATUS_WIP (1 << 0) /* Write in progress */
78 * On teleterra, the m25 chip select pins are
79 * wired on P0_0 through P0_3.
83 static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */
84 static uint8_t ao_m25_pin[M25_MAX_CHIPS]; /* chip select pin for each chip */
85 static uint8_t ao_m25_numchips; /* number of chips detected */
87 static uint8_t ao_m25_total; /* total sectors available */
88 static uint8_t ao_m25_wip; /* write in progress */
90 static __xdata uint8_t ao_m25_mutex;
93 * This little array is abused to send and receive data. A particular
94 * caution -- the read and write addresses are written into the last
95 * three bytes of the array by ao_m25_set_page_address and then the
96 * first byte is used by ao_m25_wait_wip and ao_m25_write_enable, neither
97 * of which touch those last three bytes.
100 static __xdata uint8_t ao_m25_instruction[4];
103 extern uint8_t ao_radio_in_recv;
105 static void ao_boot_radio(void) {
106 if (ao_radio_in_recv)
107 ao_radio_recv_abort();
110 #define ao_boot_radio()
113 #define M25_SELECT(cs) do { ao_boot_radio(); ao_spi_get_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS, AO_SPI_SPEED_FAST); } while (0)
114 #define M25_DESELECT(cs) ao_spi_put_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS)
116 #define M25_BLOCK_SHIFT 16
117 #define M25_BLOCK 65536L
118 #define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT))
119 #define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT)
122 * Block until the specified chip is done writing
125 ao_m25_wait_wip(uint8_t cs)
127 if (ao_m25_wip & cs) {
129 ao_m25_instruction[0] = M25_RDSR;
130 ao_spi_send(ao_m25_instruction, 1, AO_M25_SPI_BUS);
132 ao_spi_recv(ao_m25_instruction, 1, AO_M25_SPI_BUS);
133 } while (ao_m25_instruction[0] & M25_STATUS_WIP);
140 * Set the write enable latch so that page program and sector
141 * erase commands will work. Also mark the chip as busy writing
142 * so that future operations will block until the WIP bit goes off
145 ao_m25_write_enable(uint8_t cs)
148 ao_m25_instruction[0] = M25_WREN;
149 ao_spi_send(&ao_m25_instruction, 1, AO_M25_SPI_BUS);
156 * Returns the number of 64kB sectors
159 ao_m25_read_capacity(uint8_t cs)
163 ao_m25_instruction[0] = M25_RDID;
164 ao_spi_send(ao_m25_instruction, 1, AO_M25_SPI_BUS);
165 ao_spi_recv(ao_m25_instruction, M25_RDID_LEN, AO_M25_SPI_BUS);
168 /* Check to see if the chip is present */
169 if (ao_m25_instruction[0] == 0xff)
171 capacity = ao_m25_instruction[M25_CAPACITY_OFFSET];
173 /* Sanity check capacity number */
174 if (capacity < 0x11 || 0x1f < capacity)
176 return 1 << (capacity - 0x10);
180 ao_m25_set_address(uint32_t pos)
183 #if M25_MAX_CHIPS > 1
186 for (chip = 0; chip < ao_m25_numchips; chip++) {
187 size = ao_m25_size[chip];
188 if (M25_POS_TO_SECTOR(pos) < size)
190 pos -= M25_SECTOR_TO_POS(size);
192 if (chip == ao_m25_numchips)
195 chip = ao_m25_pin[chip];
197 chip = AO_M25_SPI_CS_MASK;
199 ao_m25_wait_wip(chip);
201 ao_m25_instruction[1] = pos >> 16;
202 ao_m25_instruction[2] = pos >> 8;
203 ao_m25_instruction[3] = pos;
208 * Scan the possible chip select lines
209 * to see which flash chips are connected
214 #if M25_MAX_CHIPS > 1
221 #if M25_MAX_CHIPS > 1
223 for (pin = 1; pin != 0; pin <<= 1) {
224 if (AO_M25_SPI_CS_MASK & pin) {
225 size = ao_m25_read_capacity(pin);
227 ao_m25_size[ao_m25_numchips] = size;
228 ao_m25_pin[ao_m25_numchips] = pin;
229 ao_m25_total += size;
235 ao_m25_total = ao_m25_read_capacity(AO_M25_SPI_CS_MASK);
239 ao_storage_total = M25_SECTOR_TO_POS(ao_m25_total);
240 ao_storage_block = M25_BLOCK;
241 ao_storage_config = ao_storage_total - M25_BLOCK;
242 ao_storage_unit = 256;
247 * Erase the specified sector
250 ao_storage_erase(uint32_t pos) __reentrant
254 if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
257 ao_mutex_get(&ao_m25_mutex);
260 cs = ao_m25_set_address(pos);
263 ao_m25_write_enable(cs);
265 ao_m25_instruction[0] = M25_SE;
267 ao_spi_send(ao_m25_instruction, 4, AO_M25_SPI_BUS);
271 ao_mutex_put(&ao_m25_mutex);
279 ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
283 if (pos >= ao_storage_total || pos + len > ao_storage_total)
286 ao_mutex_get(&ao_m25_mutex);
289 cs = ao_m25_set_address(pos);
290 ao_m25_write_enable(cs);
292 ao_m25_instruction[0] = M25_PP;
294 ao_spi_send(ao_m25_instruction, 4, AO_M25_SPI_BUS);
295 ao_spi_send(d, len, AO_M25_SPI_BUS);
298 ao_mutex_put(&ao_m25_mutex);
306 ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
310 if (pos >= ao_storage_total || pos + len > ao_storage_total)
312 ao_mutex_get(&ao_m25_mutex);
315 cs = ao_m25_set_address(pos);
317 /* No need to use the FAST_READ as we're running at only 8MHz */
318 ao_m25_instruction[0] = M25_READ;
320 ao_spi_send(ao_m25_instruction, 4, AO_M25_SPI_BUS);
321 ao_spi_recv(d, len, AO_M25_SPI_BUS);
324 ao_mutex_put(&ao_m25_mutex);
329 ao_storage_flush(void) __reentrant
334 ao_storage_setup(void)
336 ao_mutex_get(&ao_m25_mutex);
338 ao_mutex_put(&ao_m25_mutex);
342 ao_storage_device_info(void) __reentrant
345 #if M25_MAX_CHIPS > 1
349 ao_mutex_get(&ao_m25_mutex);
351 ao_mutex_put(&ao_m25_mutex);
353 #if M25_MAX_CHIPS > 1
354 printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total);
355 for (chip = 0; chip < ao_m25_numchips; chip++)
356 printf ("Flash chip %d select %02x size %d\n",
357 chip, ao_m25_pin[chip], ao_m25_size[chip]);
359 printf ("Detected chips 1 size %d\n", ao_m25_total);
362 printf ("Available chips:\n");
363 for (cs = 1; cs != 0; cs <<= 1) {
364 if ((AO_M25_SPI_CS_MASK & cs) == 0)
367 ao_mutex_get(&ao_m25_mutex);
369 ao_m25_instruction[0] = M25_RDID;
370 ao_spi_send(ao_m25_instruction, 1, AO_M25_SPI_BUS);
371 ao_spi_recv(ao_m25_instruction, M25_RDID_LEN, AO_M25_SPI_BUS);
374 printf ("Select %02x manf %02x type %02x cap %02x uid %02x\n",
376 ao_m25_instruction[M25_MANUF_OFFSET],
377 ao_m25_instruction[M25_MEMORY_TYPE_OFFSET],
378 ao_m25_instruction[M25_CAPACITY_OFFSET],
379 ao_m25_instruction[M25_UID_OFFSET]);
380 ao_mutex_put(&ao_m25_mutex);
385 ao_storage_device_init(void)
387 ao_spi_init_cs (AO_M25_SPI_CS_PORT, AO_M25_SPI_CS_MASK);