From a20ca6eb18821ee4d5eab5eec33723e7c61d88b6 Mon Sep 17 00:00:00 2001 From: NĂ©lio Laranjeiro Date: Tue, 12 Jan 2010 23:51:46 +0100 Subject: digital/avr/modules/flash: add flash ATMEL driver --- digital/avr/modules/flash/Makefile.module | 3 +- digital/avr/modules/flash/flash.avr.c | 6 + digital/avr/modules/flash/flash.c | 15 ++ digital/avr/modules/flash/flash.h | 5 + digital/avr/modules/flash/flash_at.avr.c | 340 ++++++++++++++++++++++++++++++ digital/avr/modules/flash/flash_at.c | 37 ++++ digital/avr/modules/flash/flash_at.h | 163 ++++++++++++++ digital/avr/modules/flash/flash_at.host.c | 108 ++++++++++ 8 files changed, 676 insertions(+), 1 deletion(-) create mode 100644 digital/avr/modules/flash/flash_at.avr.c create mode 100644 digital/avr/modules/flash/flash_at.c create mode 100644 digital/avr/modules/flash/flash_at.h create mode 100644 digital/avr/modules/flash/flash_at.host.c (limited to 'digital') diff --git a/digital/avr/modules/flash/Makefile.module b/digital/avr/modules/flash/Makefile.module index 07eed434..8b573ea7 100644 --- a/digital/avr/modules/flash/Makefile.module +++ b/digital/avr/modules/flash/Makefile.module @@ -1,2 +1,3 @@ flash_SOURCES=flash.avr.c flash.host.c flash.c flash_io.host.c \ - flash_sst.avr.c flash_sst.host.c flash_sst.c + flash_sst.avr.c flash_sst.host.c flash_sst.c \ + flash_at.avr.c flash_at.host.c flash_at.c diff --git a/digital/avr/modules/flash/flash.avr.c b/digital/avr/modules/flash/flash.avr.c index bcc81fa6..f97c7ed8 100644 --- a/digital/avr/modules/flash/flash.avr.c +++ b/digital/avr/modules/flash/flash.avr.c @@ -24,6 +24,7 @@ * }}} */ #include "flash.h" #include "flash_sst.h" +#include "flash_at.h" #include "modules/spi/spi.h" uint8_t @@ -53,6 +54,11 @@ flash_init (void) flash_init_sst (); res = 1; break; + case FLASH_AT_MANUFACTURER_ID: + flash_at_init (); + flash_init_at (); + res = 1; + break; default: res = 0; } diff --git a/digital/avr/modules/flash/flash.c b/digital/avr/modules/flash/flash.c index bd84b4e4..05151800 100644 --- a/digital/avr/modules/flash/flash.c +++ b/digital/avr/modules/flash/flash.c @@ -247,3 +247,18 @@ flash_init_sst (void) flash.flash_size_func = flash_sst_size; flash.flash_block_size_func = flash_sst_block_size; } + +void +flash_init_at (void) +{ + flash.erase_func = flash_at_erase; + flash.send_cmd_func = flash_at_send_command; + flash.read_status_func = flash_at_read_status; + flash.is_busy_func = flash_at_is_busy; + flash.write_func = flash_at_write; + flash.read_func = flash_at_read; + flash.read_array_func = flash_at_read_array; + flash.write_array_func = flash_at_write_array; + flash.flash_size_func = flash_at_size; + flash.flash_block_size_func = flash_at_block_size; +} diff --git a/digital/avr/modules/flash/flash.h b/digital/avr/modules/flash/flash.h index 0ac87596..4bbdfd2b 100644 --- a/digital/avr/modules/flash/flash.h +++ b/digital/avr/modules/flash/flash.h @@ -148,4 +148,9 @@ flash_block_size (void); void flash_init_sst (void); +/** Initialise all the function pointer for ATMEL flash memory. + */ +void +flash_init_at (void); + #endif /* flash_h */ diff --git a/digital/avr/modules/flash/flash_at.avr.c b/digital/avr/modules/flash/flash_at.avr.c new file mode 100644 index 00000000..510dadcd --- /dev/null +++ b/digital/avr/modules/flash/flash_at.avr.c @@ -0,0 +1,340 @@ +/* flash_at.avr.c */ +/* avr.flash - AVR Flash SPI use. {{{ + * + * Copyright (C) 2009 Nelio Laranjeiro + * + * APBTeam: + * Web: http://apbteam.org/ + * Email: team AT apbteam DOT org + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * }}} */ +#include "flash_at.h" +#include "modules/spi/spi.h" + +enum flash_at_comp_t +{ + FLASH_AT_COMP_OK, + FLASH_AT_COMP_NOK, + FLASH_AT_COMP_NB +}; + +enum flash_at_sector_protection_t +{ + FLASH_AT_SECTOR_PROTECTION_ENABLE, + FLASH_AT_SECTOR_PROTECTION_DISABLE, + FLASH_AT_SECTOR_PROTECTION_NB +}; + +enum flash_at_page_size_t +{ + FLASH_AT_PAGE_SIZE_512, + FLASH_AT_PAGE_SIZE_528, + FLASH_AT_PAGE_SIZE_NB +}; + +struct flash_at_buffer_t +{ + /* Buffer loaded. */ + uint8_t loaded; + /* Buffer page. */ + uint16_t page; + /* Position in page. */ + uint16_t position; + /* Load command. */ + uint8_t load_cmd; + /* Store command. */ + uint8_t store_cmd; + /* To acknowledge. */ + uint8_t toack; +}; + +struct flash_at_t +{ + /** Buffer 1. */ + struct flash_at_buffer_t buffer1; + /** Buffer 2. */ + struct flash_at_buffer_t buffer2; +}; + +/* Flash at context. */ +static struct flash_at_t flash_at; + +/** Verify if the main memory page correspond to the buffer page. + * \return 1 on success i.e. buffer == main memory page. + */ +static inline enum flash_at_comp_t +flash_at_mmp_to_buff (void) +{ + return !((flash_at_read_status () >> 6) & 0x1); +} + +/** Read the sector protection status. + * \return 1 sector protection enabled. + */ +static inline enum flash_at_sector_protection_t +flash_at_sector_protection (void) +{ + return ((flash_at_read_status () >> 1) & 0x1); +} + +/** Read the page size configuration. + * \return 1 if configured as 512 bytes page, 0 for 528 bytes. + */ +static inline enum flash_at_page_size_t +flash_at_page_size (void) +{ + return flash_at_read_status () & 0x1; +} + +/** Disable flash protection. +*/ +static inline void +flash_at_sector_protection_disable (void) +{ + FLASH_CS_ENABLE; + spi_send (0x3D); + spi_send (0x2A); + spi_send (0x7F); + spi_send (0x9A); + FLASH_CS_DISABLE; + /* FIXME: WP Disable ? */ +} + +void +flash_at_init (void) +{ + /* Initialise context. */ + flash_at.buffer1.loaded = 0; + flash_at.buffer1.load_cmd = FLASH_AT_CMD_WRITE_BUFF1; + flash_at.buffer1.store_cmd = FLASH_AT_CMD_BUFF1_STORE; + flash_at.buffer2.loaded = 0; + flash_at.buffer2.load_cmd = FLASH_AT_CMD_WRITE_BUFF2; + flash_at.buffer2.store_cmd = FLASH_AT_CMD_BUFF2_STORE; + /* Get status register value. */ + uint8_t status = flash_at_read_status (); + /* Is flash protected ? */ + if ((status >> 1) & 0x1) + flash_at_sector_protection_disable (); + /* FIXME: Erase a part of the flash to use it. */ +} + +void +flash_at_erase (flash_erase_cmd_t cmd, uint32_t start_addr) +{ + uint16_t memory; + switch (cmd) + { + case FLASH_ERASE_PAGE: + memory = FLASH_AT_ADDR_TO_PAGE (start_addr); + FLASH_CS_ENABLE; + spi_send (FLASH_AT_ERASE_PAGE); + spi_send (memory >> 3); + spi_send ((memory << 1) & 0xff); + spi_send (0); + FLASH_CS_DISABLE; + break; + case FLASH_ERASE_BLOCK: + memory = FLASH_AT_ADDR_TO_BLOCK (start_addr); + FLASH_CS_ENABLE; + spi_send (FLASH_AT_ERASE_BLOCK); + spi_send (memory >> 3); + spi_send ((memory << 4) & 0xff); + spi_send (0); + FLASH_CS_DISABLE; + break; + case FLASH_ERASE_SECTOR: + memory = FLASH_AT_ADDR_TO_SECTOR (start_addr); + FLASH_CS_ENABLE; + spi_send (FLASH_AT_ERASE_SECTOR); + spi_send (memory >> 3); + spi_send (0); + spi_send (0); + FLASH_CS_DISABLE; + break; + case FLASH_ERASE_FULL: + FLASH_CS_ENABLE; + spi_send (0x7C); + spi_send (0x94); + spi_send (0x80); + spi_send (0x9A); + FLASH_CS_DISABLE; + break; + default: + return; + } + while (flash_at_is_busy ()); +} + +void +flash_at_send_command (flash_cmd_t cmd) +{ + /* FIXME: Useful ? */ +} + +uint8_t +flash_at_read_status (void) +{ + uint8_t status; + /* Read status. */ + FLASH_CS_ENABLE; + spi_send (FLASH_AT_CMD_STATUS); + status = spi_recv (); + FLASH_CS_DISABLE; + return status; +} + +uint8_t +flash_at_is_busy (void) +{ + return !(flash_at_read_status () >> 7); +} + +/** Store the buffer into the main memory. + * \param buffer the buffer context. + */ +static inline void +flash_at_write_buffer_into_memory (struct flash_at_buffer_t *buffer) +{ + if (buffer->position == FLASH_AT_PAGE_SIZE_528) + { + while (flash_at_is_busy ()); + /* Store buffer in main memory. */ + FLASH_CS_ENABLE; + /* Send opcode. */ + spi_send (buffer->store_cmd); + /* Send page address. */ + spi_send (buffer->page >> 7); + spi_send (buffer->page << 1); + spi_send (0); + FLASH_CS_DISABLE; + buffer->loaded = 0; + buffer->toack = 1; + } +} + +/** Write data into buffer. + * \param buffer the buffer context. + * \param addr the address to store the data. + * \param data the data value to store. + */ +static inline void +flash_at_write_into_buffer (struct flash_at_buffer_t *buffer, + uint32_t addr, uint8_t data) +{ + while (flash_at_is_busy ()); + buffer->page = FLASH_AT_ADDR_TO_PAGE (addr); + buffer->position = addr % buffer->page; + FLASH_CS_ENABLE; + /* Send opcode. */ + spi_send (buffer->load_cmd); + /* Address in the buffer. */ + spi_send (0); + spi_send (buffer->position >> 8); + spi_send (buffer->position); + /* Store data. */ + spi_send (data); + FLASH_CS_DISABLE; + buffer->position ++; + flash_at_write_buffer_into_memory (buffer); +} + +/** Acknowledge memory copy. + * \param buffer the buffer context. + * Client should only call this function after verification of the toack + * value. + */ +static inline void +flash_at_buffer_ack (struct flash_at_buffer_t *buffer) +{ + if (flash_at_mmp_to_buff () == FLASH_AT_COMP_OK) + buffer->toack = 0; + else + flash_at_write_buffer_into_memory (buffer); +} + +/** Check acknowledge on the buffers. + */ +static inline void +flash_at_buffers_ack (void) +{ + if (flash_at.buffer1.toack) + flash_at_buffer_ack (&flash_at.buffer1); + if (flash_at.buffer2.toack) + flash_at_buffer_ack (&flash_at.buffer2); +} + +void +flash_at_write (uint32_t addr, uint8_t data) +{ + flash_at_buffers_ack (); + if (!flash_at.buffer1.loaded + || (flash_at.buffer1.loaded + && flash_at.buffer1.page == FLASH_AT_ADDR_TO_PAGE (addr))) + { + flash_at.buffer1.loaded = 1; + flash_at_write_into_buffer (&flash_at.buffer1, addr, data); + } + else if (!flash_at.buffer2.loaded + || (flash_at.buffer2.loaded + && flash_at.buffer2.page == FLASH_AT_ADDR_TO_PAGE (addr))) + { + flash_at.buffer2.loaded = 1; + flash_at_write_into_buffer (&flash_at.buffer2, addr, data); + } +} + +uint8_t +flash_at_read (uint32_t addr) +{ + uint8_t recv; + flash_at_buffers_ack (); + /* Read from main memory. */ + FLASH_CS_ENABLE; + spi_send (FLASH_AT_CMD_READ_MAIN_MEMORY); + spi_send ((addr >> 16) & 0x1F); + spi_send ((addr & 0xFF00) >> 8); + spi_send (addr & 0xFF); + recv = spi_recv (); + FLASH_CS_DISABLE; + return recv; +} + +void +flash_at_read_array (uint32_t addr, uint8_t *buffer, uint32_t length) +{ + uint8_t i; + flash_at_buffers_ack (); + /* Read from main memory. */ + FLASH_CS_ENABLE; + spi_send (FLASH_AT_CMD_READ_MAIN_MEMORY); + spi_send ((addr >> 16) & 0x1F); + spi_send ((addr & 0xFF00) >> 8); + spi_send (addr & 0xFF); + for (i = 0; i < length; i++) + buffer[i] = spi_recv (); + FLASH_CS_DISABLE; +} + +void +flash_at_write_array (uint32_t addr, uint8_t *data, uint32_t length) +{ + uint8_t i; + flash_at_buffers_ack (); + /* FIXME: Use buffer to avoid multiple address access. */ + for (i = 0; i < length; i++) + flash_at_write (addr, data[i]); +} diff --git a/digital/avr/modules/flash/flash_at.c b/digital/avr/modules/flash/flash_at.c new file mode 100644 index 00000000..7dc128e4 --- /dev/null +++ b/digital/avr/modules/flash/flash_at.c @@ -0,0 +1,37 @@ +/* flash_at.c */ +/* avr.flash - AVR Flash SPI use. {{{ + * + * Copyright (C) 2010 Nelio Laranjeiro + * + * APBTeam: + * Web: http://apbteam.org/ + * Email: team AT apbteam DOT org + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * }}} */ +#include "flash_at.h" + +uint32_t +flash_at_size (void) +{ + return FLASH_AT_SIZE; +} + +uint32_t +flash_at_block_size (void) +{ + return FLASH_AT_PAGE_SIZE; +} diff --git a/digital/avr/modules/flash/flash_at.h b/digital/avr/modules/flash/flash_at.h new file mode 100644 index 00000000..2aed7d09 --- /dev/null +++ b/digital/avr/modules/flash/flash_at.h @@ -0,0 +1,163 @@ +#ifndef flash_at_h +#define flash_at_h +/* flash_at.h */ +/* avr.flash - AVR Flash SPI use. {{{ + * + * Copyright (C) 2009 Nelio Laranjeiro + * + * APBTeam: + * Web: http://apbteam.org/ + * Email: team AT apbteam DOT org + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * }}} */ +#include "common.h" +#include "flash.h" + +#define FLASH_AT_PAGE_SIZE 0x200 +#define FLASH_AT_BLOCK_SIZE 0x1000 +#define FLASH_AT_SECTOR_SIZE 0x20000 +#define FLASH_AT_SIZE 0x200000 +#define FLASH_AT_ADDRESS_HIGH \ + (FLASH_AT_SIZE - 1) + +#define FLASH_AT_ADDR_IS_VALID(addr) \ + ((addr) < FLASH_AT_SIZE) + +#define FLASH_AT_MANUFACTURER_ID 0x1F + +#define FLASH_AT_ADDR_TO_PAGE(addr) \ + ((addr) / FLASH_AT_PAGE_SIZE) + +#define FLASH_AT_ADDR_TO_BLOCK(addr) \ + ((addr) / FLASH_AT_BLOCK_SIZE) + +#define FLASH_AT_ADDR_TO_SECTOR(addr) \ + ((addr) / FLASH_AT_SECTOR_SIZE) + +enum flash_at_erase_t +{ + FLASH_AT_ERASE_PAGE = 0x81, + FLASH_AT_ERASE_BLOCK = 0x50, + FLASH_AT_ERASE_SECTOR = 0x7C, + FLASH_AT_ERASE_NB +}; +typedef enum flash_at_erase_t flash_at_erase_t; + +enum flash_at_cmd_t +{ + FLASH_AT_CMD_JDEC = 0x9F, + FLASH_AT_CMD_STATUS = 0xD7, + FLASH_AT_CMD_WRITE_BUFF1 = 0x84, + FLASH_AT_CMD_WRITE_BUFF2 = 0x87, + FLASH_AT_CMD_BUFF1_STORE = 0x83, + FLASH_AT_CMD_BUFF2_STORE = 0x86, + FLASH_AT_CMD_READ_MAIN_MEMORY = 0xD2, + FLASH_AT_CMD_READ_BUFF1 = 0xD4, + FLASH_AT_CMD_READ_BUFF2 = 0xD6, + FLASH_AT_CMD_DEEP_POWER_DOWN = 0xB9, + FLASH_AT_CMD_DEEP_POWER_DOWN_RESUME = 0xAB, + FLASH_AT_CMD_NB +}; +typedef enum flash_at_cmd_t flash_at_cmd_t; + +/** Initialise the flash memory. + */ +void +flash_at_init (void); + +/** Flash access. + * The flash contains an address of 21 bits in a range from 0x0-0x1fffff. + * This function shall access the memory directly by the SPI. + * \param addr the address to provide to the flash memory. + */ +void +flash_at_address (uint32_t addr); + +/** Erase the memory. + * \param erase_type the erase type.. + * \param start_addr the start address. + */ +void +flash_at_erase (flash_erase_cmd_t cmd, uint32_t start_addr); + +/* Send a flash command to the flash memory (only a command). + * \param cmd the command to send. + */ +void +flash_at_send_command (flash_cmd_t cmd); + +/* Send a flash command to the flash memory (only a command). + * \param cmd the command to send. + */ +void +flash_at_send_command (flash_cmd_t cmd); + +/** Read the busy bit in the Software Status Register of the flash memory. + * \return the status register. + */ +uint8_t +flash_at_read_status (void); + +/** Read the busy bit in the Software Status Register of the flash memory. + * \return the busy bit state. + */ +uint8_t +flash_at_is_busy (void); + +/** Write in the flash byte provided in parameter. + * \param data the buffer to store the data. + */ +void +flash_at_write (uint32_t addr, uint8_t data); + +/** Read the data at the address provided. + * \param addr the address of the data to read. + * \return the data read. + */ +uint8_t +flash_at_read (uint32_t addr); + +/** Read a data from the flash memory from the address provided and for a + * length of the number of bytes provided. + * \param address at which the data should be read. + * \param buffer the buffer to fill with the read data. + * \param length the length of the data to read. + */ +void +flash_at_read_array (uint32_t addr, uint8_t *buffer, uint32_t length); + +/** Write in the flash byte provided in parameter. + * \param addr the address to store the data. + * \param data the array to store. + * \param length the array length + */ +void +flash_at_write_array (uint32_t addr, uint8_t *data, uint32_t length); + +/** Get the flash size. + * \return the flash size. + */ +uint32_t +flash_at_size (void); + +/** Get the flash block size. + * \return the flash block size. + */ +uint32_t +flash_at_block_size (void); + +#endif /* flash_at_h */ diff --git a/digital/avr/modules/flash/flash_at.host.c b/digital/avr/modules/flash/flash_at.host.c new file mode 100644 index 00000000..a29bc3e2 --- /dev/null +++ b/digital/avr/modules/flash/flash_at.host.c @@ -0,0 +1,108 @@ +/* flash_at.host.c */ +/* avr.flash - AVR Flash SPI use. {{{ + * + * Copyright (C) 2009 Nelio Laranjeiro + * + * APBTeam: + * Web: http://apbteam.org/ + * Email: team AT apbteam DOT org + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * }}} */ +#include "flash_at.h" +#include "flash_io.host.h" + +void +flash_at_init (void) +{ + flash_io_init (FLASH_AT_SIZE); +} + +void +flash_at_address (uint32_t addr) +{ } + +void +flash_at_erase (flash_erase_cmd_t cmd, uint32_t start_addr) +{ + if (FLASH_AT_ADDR_IS_VALID (start_addr)) + { + uint32_t length; + switch (cmd) + { + case FLASH_ERASE_PAGE: + length = FLASH_AT_PAGE_SIZE; + break; + case FLASH_ERASE_SECTOR: + length = FLASH_AT_SECTOR_SIZE; + break; + case FLASH_ERASE_BLOCK: + length = FLASH_AT_BLOCK_SIZE; + break; + case FLASH_ERASE_FULL: + length = FLASH_AT_SIZE; + default: + return; + } + flash_io_erase (start_addr, length); + } +} + +void +flash_at_send_command (flash_cmd_t cmd) +{ } + +uint8_t +flash_at_read_status (void) +{ + return 0; +} + +uint8_t +flash_at_is_busy (void) +{ + /* Not busy. */ + return 0; +} + +void +flash_at_write (uint32_t addr, uint8_t data) +{ + if (FLASH_AT_ADDR_IS_VALID (addr)) + flash_io_write (addr, data); +} + +uint8_t +flash_at_read (uint32_t addr) +{ + if (FLASH_AT_ADDR_IS_VALID (addr)) + return flash_io_read (addr); + return 0xff; +} + +void +flash_at_read_array (uint32_t addr, uint8_t *buffer, uint32_t length) +{ + if (FLASH_AT_ADDR_IS_VALID (addr)) + flash_io_read_array (addr, buffer, length); +} + +void +flash_at_write_array (uint32_t addr, uint8_t *data, uint32_t length) +{ + if (FLASH_AT_ADDR_IS_VALID (addr)) + flash_io_write_array (addr, data, length); +} -- cgit v1.2.3