/* * SPI testing program (using spidev driver) * * Copyright (c) 2007 MontaVista Software, Inc. * Copyright (c) 2007 Anton Vorontsov * * 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. * * Cross-compile with cross-gcc -I/path/to/cross-kernel/include */ /* IOBOARD SST25WF020A SPI Flash Test (Use spidev driver) */ /*---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------*/ #define FLASH_SECTOR_4K (4 * 1024) #define FLASH_TEST_SIZE 256 const char *SPIDEV_NODE = "/dev/spidev1.0"; /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Read Flash ID */ #define CMD_READ_ID 0xAB /* 0x90 or 0xAB */ /* Read memory */ #define CMD_READ 0x03 #define CMD_HIGH_SPEED_READ 0x0B #define CMD_READ_STATUS 0x05 /* Erase memory */ #define CMD_ERASE_4KB 0x20 #define CMD_ERASE_32KB 0x52 #define CMD_ERASE_64KB 0xD8 #define CMD_ERASE_ALL 0xC7 /* 0xC7 or 0x60 */ /* BYTE write command */ #define CMD_BYTE_WRITE 0x02 /* Write Enable/Disable CMD */ #define CMD_WRITE_ENABLE 0x06 #define CMD_WRITE_DISABLE 0x04 #define CMD_WRITE_PROTECT 0x01 /* BUSY 1 : internal write operation is in progress 0 : no internal write operation is in progress */ #define STATUS_BUSY 0x01 /* (Read) */ /* WEL 1 : Device is memory write enabled 0 : Device is not memory write enabled */ #define STATUS_WEL 0x02 /* (Read) */ /* BP1 BP0 0 0 : none protected memory 0 1 : 030000H-03FFFFH protected 1 0 : 020000H-03FFFFH protected 1 1 : 000000H-03FFFFH protected (Power-up default value) */ #define STATUS_BP0 0x04 /* (R/W) */ #define STATUS_BP1 0x08 /* (R/W) */ /* BPL 1 : BP1 and BP0 are read-only bits 0 : BP1 and BP0 are read/writable (Power-up default value) */ #define STATUS_BPL 0x80 /* (R/W) */ /*---------------------------------------------------------------------------*/ #define FLASH_SPI_MODE 0 #define FLASH_SPI_SPEED 500000 #define FLASH_SPI_BITS 8 struct spi_flash { /* spidev file descriptor */ int fd; /* SPI mode H/W control */ unsigned char mode; /* SPI_MODE */ unsigned char bits; /* SPI Data bits */ unsigned int speed; /* SPI Control Speed */ /* Flash control variable */ unsigned char cmd; union { unsigned int addr; unsigned char data[sizeof(unsigned int)]; }; unsigned char tx_data[10]; unsigned int tx_len; unsigned char rx_data[FLASH_SECTOR_4K]; unsigned int rx_len; }; /*---------------------------------------------------------------------------*/ static void pabort(const char *s) { perror(s); abort(); } /*---------------------------------------------------------------------------*/ static void transfer (struct spi_flash *flash) { struct spi_ioc_transfer tr[2]; memset(tr, 0, sizeof(tr)); memset(flash->rx_data, 0x00, sizeof(flash->rx_data)); flash->tx_data[0] = flash->cmd; flash->tx_data[1] = (flash->addr & 0x00FF0000) >> 16; flash->tx_data[2] = (flash->addr & 0x0000FF00) >> 8; flash->tx_data[3] = (flash->addr & 0x000000FF); flash->tx_data[4] = flash->data[3]; /* Dummy Cycle */ tr[0].tx_buf = (unsigned long)flash->tx_data; tr[0].len = flash->tx_len < 5 ? flash->tx_len : 5; if (flash->rx_len) { tr[1].rx_buf = (unsigned long)flash->rx_data; tr[1].len = flash->rx_len; if (ioctl(flash->fd, SPI_IOC_MESSAGE(2), &tr[0]) < 2) pabort("can't send SPI message"); flash->rx_len = 0; } else { if (ioctl(flash->fd, SPI_IOC_MESSAGE(1), &tr[0]) < 1) pabort("can't send SPI message"); } } /*---------------------------------------------------------------------------*/ static void spidev_init (struct spi_flash *flash) { int ret; flash->fd = open(SPIDEV_NODE, O_RDWR); if (flash->fd < 0) pabort("can't open /dev/spidev1.0"); /* SPI H/W Init SPI Mode = 0, Data bits = 8, Speed = 500Kbps */ flash->mode = FLASH_SPI_MODE; flash->bits = FLASH_SPI_BITS; flash->speed = FLASH_SPI_SPEED; /* SPI mode */ ret = ioctl(flash->fd, SPI_IOC_WR_MODE, &flash->mode); if (ret == -1) pabort("can't set SPI mode"); ret = ioctl(flash->fd, SPI_IOC_RD_MODE, &flash->mode); if (ret == -1) pabort("can't get SPI mode"); /* bits per word */ ret = ioctl(flash->fd, SPI_IOC_WR_BITS_PER_WORD, &flash->bits); if (ret == -1) pabort("can't set bits per word"); ret = ioctl(flash->fd, SPI_IOC_RD_BITS_PER_WORD, &flash->bits); if (ret == -1) pabort("can't get bits per word"); /* max speed hz */ ret = ioctl(flash->fd, SPI_IOC_WR_MAX_SPEED_HZ, &flash->speed); if (ret == -1) pabort("can't set max speed Hz"); ret = ioctl(flash->fd, SPI_IOC_RD_MAX_SPEED_HZ, &flash->speed); if (ret == -1) pabort("can't get max speed Hz"); /* H/W Setup Info Display */ printf("SPI mode: %d\n", flash->mode); printf("bits per word: %d\n", flash->bits); printf("max speed: %d Hz (%d KHz)\n" , flash->speed , flash->speed/1000); } /*---------------------------------------------------------------------------*/ static int flash_read_id (struct spi_flash *flash) { flash->cmd = CMD_READ_ID; flash->addr = 0; flash->tx_len = 4; flash->rx_len = 2; transfer (flash); printf("%s : rdata[0] = 0x%02X, rdata[1] = 0x%02X\n", __func__, flash->rx_data[0], flash->rx_data[1]); if ((flash->rx_data[0] == 0xBF) && (flash->rx_data[1] == 0x03)) { printf("Flash Memory Product is SST(SST25WF020)\n"); return 0; } if (flash->rx_data[0] == 0x34) { printf("Flash Memory Product is Microcphis(SST25WF020A)\n"); return 0; } pabort("Unknown Flash Memory Product!\n"); return -1; } /*---------------------------------------------------------------------------*/ static int flash_busy_check(int spi_fd, int udelay) { struct spi_flash flash; unsigned char retry_cnt = 0; do { flash.fd = spi_fd; flash.cmd = CMD_READ_STATUS; flash.tx_len = 1; /* Status read len */ flash.rx_len = 1; transfer(&flash); usleep(udelay); if (retry_cnt++ > 1000) { printf("%s : Timeout Error!\n", __func__); return -1; } } while(flash.rx_data[0] & STATUS_BUSY); return 0; } /*---------------------------------------------------------------------------*/ static void flash_access_enable(int spi_fd, unsigned char enable) { struct spi_flash flash; flash.fd = spi_fd; flash.cmd = enable ? CMD_WRITE_ENABLE : CMD_WRITE_DISABLE; flash.tx_len = 1; flash.rx_len = 0; transfer(&flash); if (flash_busy_check(spi_fd, 100) != 0) { pabort("Busy check Error!\n"); } } /*---------------------------------------------------------------------------*/ static void flash_data_erase(struct spi_flash *flash) { flash->cmd = CMD_ERASE_4KB; flash->addr = 0; flash->tx_len = 4; flash->rx_len = 0; flash_access_enable(flash->fd, 1); transfer(flash); flash_access_enable(flash->fd, 0); if (flash_busy_check(flash->fd, 100) != 0) { pabort("Busy check Error!\n"); } } /*---------------------------------------------------------------------------*/ static void flash_data_write(struct spi_flash *flash) { int i; flash->cmd = CMD_BYTE_WRITE; flash->addr = 0; flash->tx_len = 5; flash->rx_len = 0; for (i = 0; i < FLASH_TEST_SIZE; i++) { flash->addr = i; flash->data[3] = i; flash_access_enable(flash->fd, 1); transfer(flash); flash_access_enable(flash->fd, 0); if (flash_busy_check(flash->fd, 100) != 0) { pabort("Busy check Error!\n"); } } } /*---------------------------------------------------------------------------*/ static void flash_data_dump(struct spi_flash *flash) { int i; flash->cmd = CMD_READ; flash->addr = 0; flash->tx_len = 4; flash->rx_len = FLASH_TEST_SIZE; transfer(flash); if (flash_busy_check(flash->fd, 100) != 0) { pabort("Busy check Error!\n"); } for (i = 0; i < FLASH_TEST_SIZE; i++) { if((i % 16) == 0) printf("\n"); printf("0x%02X ", flash->rx_data[i]); } printf("\n"); } /*---------------------------------------------------------------------------*/ static void flash_write_protect(int spi_fd, unsigned char status) { struct spi_flash flash; flash_access_enable(spi_fd, 1); flash.fd = spi_fd; flash.cmd = CMD_WRITE_PROTECT; flash.data[2] = status; flash.tx_len = 2; flash.rx_len = 0; transfer(&flash); flash_access_enable(spi_fd, 0); } /*---------------------------------------------------------------------------*/ int main (void) { struct spi_flash *flash; flash = (struct spi_flash *)malloc(sizeof(struct spi_flash)); if (flash == NULL) pabort("Can't allocation for spi flash!\n"); spidev_init(flash); /* flash id read */ flash_read_id(flash); /* software write protect disable */ flash_write_protect(flash->fd, 0); printf("\nFlash Memory Dump : Size = %d\n", FLASH_TEST_SIZE); flash_data_dump(flash); flash_data_erase(flash); printf("\nFlash Memory Dump (after erase) : Size = %d\n", FLASH_TEST_SIZE); flash_data_dump(flash); flash_data_write(flash); printf("\nFlash Memory Dump (after write) : Size = %d\n", FLASH_TEST_SIZE); flash_data_dump(flash); close(flash->fd); free(flash); return 0; } /*---------------------------------------------------------------------------*/