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 * MRAM is entirely random access; no erase operations are required,
34 * nor are reads or writes restricted to a particular alignment.
37 #define MR25_WREN 0x06 /* Write Enable */
38 #define MR25_WRDI 0x04 /* Write Disable */
39 #define MR25_RDSR 0x05 /* Read Status Register */
40 #define MR25_WRSR 0x01 /* Write Status Register */
41 #define MR25_READ 0x03 /* Read Data Bytes */
42 #define MR25_WRITE 0x02 /* Write Data Bytes */
45 * Status register bits
48 #define MR25_STATUS_SRWD (1 << 7) /* Status register write disable */
49 #define MR25_STATUS_BP_MASK (3 << 2) /* Block protect bits */
50 #define MR25_STATUS_BP_SHIFT (2)
51 #define MR25_STATUS_WEL (1 << 1) /* Write enable latch */
53 static __xdata uint8_t ao_mr25_mutex;
56 * This little array is abused to send and receive data. A particular
57 * caution -- the read and write addresses are written into the last
58 * three bytes of the array by ao_mr25_set_page_address and then the
59 * first byte is used by ao_mr25_write_enable, neither of which touch
60 * those last three bytes.
63 static __xdata uint8_t ao_mr25_instruction[4];
65 #define MR25_SELECT() ao_spi_get_mask(AO_MR25_SPI_CS_PORT,(1 << AO_MR25_SPI_CS_PIN),AO_MR25_SPI_BUS, AO_SPI_SPEED_FAST)
66 #define MR25_DESELECT() ao_spi_put_mask(AO_MR25_SPI_CS_PORT,(1 << AO_MR25_SPI_CS_PIN),AO_MR25_SPI_BUS)
69 * Set the write enable latch so that page program and sector
70 * erase commands will work. Also mark the chip as busy writing
71 * so that future operations will block until the WIP bit goes off
74 ao_mr25_write_enable(void)
77 ao_mr25_instruction[0] = MR25_WREN;
78 ao_spi_send(&ao_mr25_instruction, 1, AO_MR25_SPI_BUS);
84 ao_mr25_set_address(uint32_t pos)
86 ao_mr25_instruction[1] = pos >> 16;
87 ao_mr25_instruction[2] = pos >> 8;
88 ao_mr25_instruction[3] = pos;
92 * Erase the specified sector (no-op for MRAM)
95 ao_storage_erase(uint32_t pos) __reentrant
97 if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
106 ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
108 if (pos >= ao_storage_total || pos + len > ao_storage_total)
111 ao_mutex_get(&ao_mr25_mutex);
113 ao_mr25_set_address(pos);
114 ao_mr25_write_enable();
116 ao_mr25_instruction[0] = MR25_WRITE;
118 ao_spi_send(ao_mr25_instruction, 4, AO_MR25_SPI_BUS);
119 ao_spi_send(d, len, AO_MR25_SPI_BUS);
122 ao_mutex_put(&ao_mr25_mutex);
130 ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
132 if (pos >= ao_storage_total || pos + len > ao_storage_total)
134 ao_mutex_get(&ao_mr25_mutex);
136 ao_mr25_set_address(pos);
138 ao_mr25_instruction[0] = MR25_READ;
140 ao_spi_send(ao_mr25_instruction, 4, AO_MR25_SPI_BUS);
141 ao_spi_recv(d, len, AO_MR25_SPI_BUS);
144 ao_mutex_put(&ao_mr25_mutex);
149 ao_storage_flush(void) __reentrant
154 ao_storage_setup(void)
159 ao_storage_device_info(void) __reentrant
161 printf ("Detected chips 1 size %d\n", ao_storage_total >> 8);
165 ao_storage_device_init(void)
167 ao_storage_total = 512 * 1024; /* 4Mb */
168 ao_storage_block = 256;
169 ao_storage_config = ao_storage_total - ao_storage_block;
170 ao_storage_unit = 256;
171 ao_spi_init_cs (AO_MR25_SPI_CS_PORT, (1 << AO_MR25_SPI_CS_PIN));