aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp
diff options
context:
space:
mode:
authorArsalan H. Awan <Arsalan_Awan@mentor.com>2019-08-28 16:06:59 +0500
committerArsalan H. Awan <Arsalan_Awan@mentor.com>2019-08-28 16:06:59 +0500
commit4da3f26875856fc8644599c78d918e74462f2224 (patch)
treecd203fa892582eda4ffa094dac24814f4b2415e2 /meta-amd-bsp
parent48bf14132daf024044418921e02c892d6e3186e9 (diff)
downloadmeta-amd-4da3f26875856fc8644599c78d918e74462f2224.tar.gz
meta-amd-4da3f26875856fc8644599c78d918e74462f2224.tar.bz2
meta-amd-4da3f26875856fc8644599c78d918e74462f2224.zip
meta-amd-bsp: move spi-test recipe here from r1000, v1000 & e3000
Signed-off-by: Arsalan H. Awan <Arsalan_Awan@mentor.com>
Diffstat (limited to 'meta-amd-bsp')
-rw-r--r--meta-amd-bsp/recipes-applications/spi-test/files/0001-Modified-the-spi-driver-test-application-to-support-.patch47
-rw-r--r--meta-amd-bsp/recipes-applications/spi-test/files/spirom-test.c798
-rw-r--r--meta-amd-bsp/recipes-applications/spi-test/files/spirom.h53
-rw-r--r--meta-amd-bsp/recipes-applications/spi-test/spi-test_1.0.bb24
4 files changed, 922 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-applications/spi-test/files/0001-Modified-the-spi-driver-test-application-to-support-.patch b/meta-amd-bsp/recipes-applications/spi-test/files/0001-Modified-the-spi-driver-test-application-to-support-.patch
new file mode 100644
index 00000000..ebc648e0
--- /dev/null
+++ b/meta-amd-bsp/recipes-applications/spi-test/files/0001-Modified-the-spi-driver-test-application-to-support-.patch
@@ -0,0 +1,47 @@
+From a059c0737d9f75ce4e62acf3644708e32dc34fc2 Mon Sep 17 00:00:00 2001
+From: smavila <smavila@wallaby.amd.com>
+Date: Mon, 3 Dec 2018 06:21:04 +0000
+Subject: [PATCH] Modified the spi driver test application to support SPI ROM
+ Flash in Wallaby platform
+
+Signed-off-by: smavila <smavila@wallaby.amd.com>
+Signed-off-by: Arsalan H. Awan <Arsalan_Awan@mentor.com>
+---
+ spirom-test.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+ mode change 100644 => 100755 spirom-test.c
+
+diff --git a/spirom-test.c b/spirom-test.c
+old mode 100644
+new mode 100755
+index 22c9003..2f10309
+--- a/spirom-test.c
++++ b/spirom-test.c
+@@ -243,8 +243,23 @@ void parse_cmd(const char *cmdline)
+ return;
+ }
+
++ /* read device ID Command with response */
++ tr.buf[0] = ROM_RDID;
++ tr.direction = RECEIVE;
++ tr.addr_present = 0;
++ tr.len = 3;
++
++ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
++ if (ret < 1) {
++ printf("\nError executing RDID command\n\n");
++ return;
++ }
++
++ if( (tr.buf[1] == 0x20) && (tr.buf[2] == 0xbb) && (tr.buf[3] == 0x18))
++ tr.buf[0] = 0xC7; /* N25Q128A SPI ROM needs 0xC7 as erase command */
++ else
++ tr.buf[0] = ROM_CHIP_ERASE;
+ /* Command without data */
+- tr.buf[0] = ROM_CHIP_ERASE;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+--
+2.17.1
+
diff --git a/meta-amd-bsp/recipes-applications/spi-test/files/spirom-test.c b/meta-amd-bsp/recipes-applications/spi-test/files/spirom-test.c
new file mode 100644
index 00000000..22c90036
--- /dev/null
+++ b/meta-amd-bsp/recipes-applications/spi-test/files/spirom-test.c
@@ -0,0 +1,798 @@
+/*****************************************************************************
+*
+* Copyright (c) 2014, Advanced Micro Devices, Inc.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* * Neither the name of Advanced Micro Devices, Inc. nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*
+***************************************************************************/
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <dirent.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <readline/readline.h>
+
+#include "spirom.h"
+
+#define SPI_APP_VERSION "1.0"
+
+static int device_opened = 0;
+static char filename[20];
+static int fd = -1;
+
+char *show_prompt(void)
+{
+ return "$ ";
+}
+
+void sighandler(int sig)
+{
+ /* Do nothing. That is the idea. */
+}
+
+void show_license(void)
+{
+ printf("/*****************************************************************************\n"
+ "*\n"
+ "* Copyright (c) 2014, Advanced Micro Devices, Inc.\n"
+ "* All rights reserved.\n"
+ "*\n"
+ "* Redistribution and use in source and binary forms, with or without\n"
+ "* modification, are permitted provided that the following conditions are met:\n"
+ "* * Redistributions of source code must retain the above copyright\n"
+ "* notice, this list of conditions and the following disclaimer.\n"
+ "* * Redistributions in binary form must reproduce the above copyright\n"
+ "* notice, this list of conditions and the following disclaimer in the\n"
+ "* documentation and/or other materials provided with the distribution.\n"
+ "* * Neither the name of Advanced Micro Devices, Inc. nor the names of\n"
+ "* its contributors may be used to endorse or promote products derived\n"
+ "* from this software without specific prior written permission.\n"
+ "*\n"
+ "* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n"
+ "* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
+ "* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"
+ "* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY\n"
+ "* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"
+ "* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"
+ "* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n"
+ "* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+ "* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"
+ "* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+ "*\n"
+ "*\n"
+ "***************************************************************************/\n");
+}
+
+void print_usage(void)
+{
+ printf("\nCommands Supported ->\n");
+ printf(" enumerate : List all SPI device nodes available\n");
+ printf(" setdevice <dev_id> : Set the SPI device number to access\n");
+ printf(" wren : Enable Write operation on SPI device\n");
+ printf(" wrdi : Disable Write operation on SPI device\n");
+ printf(" chiperase : Erase entire ROM chip\n");
+ printf(" rdsr : Read status register of ROM device\n");
+ printf(" rdid : Read device identification string\n");
+ printf(" sectorerase <addr> <num_sectors> : Erase a fixed number of sectors starting at the address\n"
+ " specified\n");
+ printf(" blockerase <addr> <num_blocks> : Erase a fixed number of blocks starting at the address\n"
+ " specified\n");
+ printf(" read <addr> <num_bytes> <filename> : Read a fixed number of bytes starting at address\n"
+ " specified, and output the contents into file\n");
+ printf(" write <addr> <num_bytes> <filename> : Read a fixed number of bytes from file and output\n"
+ " the contents to the device starting at the address\n"
+ " specified\n");
+ printf(" license : Displays the terms of LICENSE for this application\n");
+ printf(" help : Displays help text\n");
+ printf(" exit : Exits the application\n\n");
+}
+
+void parse_cmd(const char *cmdline)
+{
+ struct spi_ioc_transfer tr;
+ unsigned int bytes_chunks;
+ unsigned int remaining_bytes;
+ int addr;
+ int ret;
+
+ if (strncmp(cmdline, "enumerate", 9) == 0) {
+ DIR *dir;
+ struct dirent *dir_entry;
+ int device_found = 0;
+
+ /* Get the directory handle */
+ if ((dir = opendir("/dev")) == NULL) {
+ printf("\n\nFailed to open directory /dev. Probably you "
+ "do not have right privilege!\n\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Iterate over all the directory entries */
+ while ((dir_entry = readdir(dir)) != NULL) {
+ /*
+ * If the file is a character device, and its signature
+ * matches spirom, then we print the corresponding file.
+ */
+ if ((dir_entry->d_type == DT_CHR) &&
+ (strncmp(dir_entry->d_name, "spirom", 6) == 0)) {
+ printf("/dev/%s\n", dir_entry->d_name);
+ device_found = 1;
+ }
+ }
+
+ printf("\n");
+
+ /*
+ * In case we did not find even a single entry, we print a
+ * message and exit.
+ */
+ if (!device_found) {
+ printf("\n\nNo spirom device nodes found, load spirom "
+ "kernel module and try again\n\n");
+ exit(EXIT_FAILURE);
+ }
+ } else if (strncmp(cmdline, "setdevice", 9) == 0) {
+ char input[2 + 1];
+ int file_desc;
+
+ cmdline += 10;
+ memset(input, 0, 3);
+ if (sscanf(cmdline, "%s", input) < 1) {
+ printf("\nInvalid inputs, please try again\n\n");
+ return;
+ }
+
+ memset(filename, 0, 20);
+ snprintf(filename, 19, "/dev/spirom%s", input);
+ file_desc = open(filename, O_RDWR);
+ if (file_desc < 0) {
+ printf("\nError opening file %s\n\n", filename);
+ return;
+ }
+
+ /* Once we have validated inputs, we store them into the global
+ * variables used at other places in the program.
+ */
+ fd = file_desc;
+ device_opened = 1;
+ printf("\nSPI device set to /dev/spirom%s\n\n", input);
+ } else if (strncmp(cmdline, "wren", 4) == 0) {
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ /* command without data */
+ tr.buf[0] = ROM_WREN;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1)
+ printf("\nError executing WREN command\n\n");
+ else
+ printf("\n...WREN completed successfully\n\n");
+ } else if (strncmp(cmdline, "wrdi", 4) == 0) {
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ /* command without data */
+ tr.buf[0] = ROM_WRDI;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1)
+ printf("\nError executing WRDI command\n\n");
+ else
+ printf("\n...WRDI completed successfully\n\n");
+ } else if (strncmp(cmdline, "chiperase", 9) == 0) {
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");;
+ return;
+ } else if ((tr.buf[1] & 0x02) == 0x00) {
+ printf("\nCannot execute CHIPERASE command, write is disabled\n\n");
+ return;
+ }
+
+ /* Command without data */
+ tr.buf[0] = ROM_CHIP_ERASE;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing CHIPERASE command\n\n");
+ return;
+ }
+
+ printf("\n\nCHIPERASE operation in progress, please do not "
+ " stop in between.\n\n");
+
+ /* Make sure WIP has been reset */
+ while (1) {
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
+
+ if ((tr.buf[1] & 0x01) == 0x00)
+ break;
+ }
+
+ printf("\n\n...CHIPERASE completed successfully\n\n");
+ /* Restore signal handler to default */
+ } else if (strncmp(cmdline, "rdsr", 4) == 0) {
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ /* Command with response */
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
+
+ /*
+ * The 1-byte response will be stored in tr.buf,
+ * so print it out
+ */
+ printf("\nRDSR command returned: 0x%.2x\n\n", tr.buf[1]);
+ } else if (strncmp(cmdline, "rdid", 4) == 0) {
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ /* Command with response */
+ tr.buf[0] = ROM_RDID;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 3;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDID command\n\n");
+ return;
+ }
+
+ /*
+ * The 3-bytes response will be stored in tr.buf,
+ * so print it out
+ */
+ printf("\nRDID command returned: 0x%.2x%.2x%.2x\n", tr.buf[1],
+ tr.buf[2], tr.buf[3]);
+ } else if (strncmp(cmdline, "sectorerase", 11) == 0) {
+ int nsectors;
+ int i;
+
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ cmdline += 12;
+ if (sscanf(cmdline, "0x%x 0x%x", &addr, &nsectors) < 2) {
+ printf("\nInvalid inputs, please try again\n\n");
+ return;
+ }
+
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ } else if ((tr.buf[1] & 0x02) == 0x00) {
+ printf("\nCannot execute SECTORERASE command, write is disabled\n\n");
+ return;
+ }
+
+ printf("\n\nSECTORERASE operation in progress, please do not "
+ " stop in between.\n\n");
+
+ for (i = 0; i < nsectors; i++) {
+ /* Write Enable before Sector Erase */
+ tr.buf[0] = ROM_WREN;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing WREN command\n\n");
+ return;
+ }
+
+ /* Command with address but no data */
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_SECTOR_ERASE;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.addr_present = 1;
+ tr.direction = 0;
+ tr.len = 0;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing SECTORERASE command\n\n");
+ return;
+ }
+
+ /* point to the next 4k sector */
+ addr += 4 * 1024;
+
+ /*
+ * Before the next loop, we need to make sure that WIP
+ * bit in the output of RDSR has been reset.
+ */
+ while (1) {
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
+
+ if ((tr.buf[1] & 0x01) == 0x00)
+ break;
+ }
+ }
+
+ printf("\n\n...SECTORERASE completed successfully\n\n");
+ } else if (strncmp(cmdline, "blockerase", 10) == 0) {
+ int nblocks;
+ int i;
+
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ cmdline += 11;
+ if (sscanf(cmdline, "0x%x 0x%x", &addr, &nblocks) < 2) {
+ printf("\nInvalid inputs, please try again\n\n");
+ return;
+ }
+
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ } else if ((tr.buf[1] & 0x02) == 0x00) {
+ printf("\nError executing BLOCKERASE command, write is disabled\n\n");
+ return;
+ }
+
+ printf("\n\nBLOCKERASE operation in progress, please do not "
+ " stop in between.\n\n");
+
+ for (i = 0; i < nblocks; i++) {
+ /* Write Enable before Block Erase */
+ tr.buf[0] = ROM_WREN;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing WREN command\n\n");
+ return;
+ }
+
+ /* Command with address but no data */
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_BLOCK_ERASE;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.addr_present = 1;
+ tr.direction = 0;
+ tr.len = 0;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing BLOCKERASE command\n\n");
+ return;
+ }
+
+ /* point to the next 64k block */
+ addr += 64 * 1024;
+
+ /*
+ * Before the next loop, we need to make sure that WIP
+ * bit in the output of RDSR has been reset.
+ */
+ while (1) {
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
+
+ if ((tr.buf[1] & 0x01) == 0x00)
+ break;
+ }
+ }
+
+ printf("\n\n...BLOCKERASE completed successfully\n\n");
+ } else if (strncmp(cmdline, "read", 4) == 0) {
+ int nbytes;
+ int outfile_fd;
+ int i;
+
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ cmdline += 5;
+ memset(filename, 0, 20);
+ if (sscanf(cmdline, "0x%x 0x%x %s", &addr, &nbytes, filename) < 3) {
+ printf("\nInvalid inputs, please try again\n\n");
+ return;
+ }
+
+ /*
+ * Open the output file for writing. Create a new file if not
+ * there, and empty the file before writing if file already
+ * exists.
+ */
+ outfile_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (outfile_fd < 0) {
+ printf("\nError opening file %s for writing\n\n", filename);
+ return;
+ }
+
+ /*
+ * We will break down the bytes to be received in chunks of
+ * of 64-bytes. Data might not be a even multiple of 64. So
+ * in that case, we will have some remaining bytes <4. We
+ * handle that separately.
+ */
+ bytes_chunks = nbytes / 64;
+ remaining_bytes = nbytes % 64;
+
+ printf("\n\nREAD operation in progress.\n\n");
+
+ for (i = 0; i < bytes_chunks; i++) {
+ /* Command with address and data */
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_READ;
+ tr.direction = RECEIVE;
+ /*
+ * We will store the address into the buffer in little
+ * endian order.
+ */
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.len = 64;
+ tr.addr_present = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing READ command\n\n");
+ return;
+ }
+
+ /* Write the data read to output file */
+ if (write(outfile_fd, &tr.buf[4], tr.len) < 0) {
+ printf("\nError writing to file %s\n\n", filename);
+ return;
+ }
+ addr += 64;
+ }
+
+ if (remaining_bytes) {
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_READ;
+ tr.direction = RECEIVE;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.len = remaining_bytes;
+ tr.addr_present = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing READ command\n\n");
+ return;
+ }
+
+ if (write(outfile_fd, &tr.buf[4], tr.len) < 0) {
+ printf("\nError writing to file %s\n\n", filename);
+ return;
+ }
+ }
+
+ printf("\n\n...READ completed successfully\n\n");
+ close(outfile_fd);
+ } else if (strncmp(cmdline, "write", 5) == 0) {
+ int nbytes;
+ int infile_fd;
+ int i;
+
+ if (!device_opened) {
+ printf("\nSPI device needs to be set before you can "
+ "perform this operation\n\n");
+ return;
+ }
+
+ cmdline += 6;
+ memset(filename, 0, 20);
+ if (sscanf(cmdline, "0x%x 0x%x %s", &addr, &nbytes, filename) < 3) {
+ printf("\nInvalid inputs, please try again\n\n");
+ return;
+ }
+
+ /* Open the input file for reading*/
+ infile_fd = open(filename, O_RDONLY);
+ if (infile_fd < 0) {
+ printf("\nError opening file %s for reading\n\n", filename);
+ return;
+ }
+
+ /*
+ * We will break down the bytes to be transmitted in chunks of
+ * of 64-bytes. Like for read, we might not have data in an
+ * even multiple of 64 bytes. So we will handle the remaining
+ * bytes in the end.
+ */
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ } else if ((tr.buf[1] & 0x02) == 0x00) {
+ printf("\nCannot execute WRITE command, write is disabled\n\n");
+ return;
+ }
+
+ bytes_chunks = nbytes / 64;
+ remaining_bytes = nbytes % 64;
+
+ printf("\n\nWRITE operation in progress, please do not "
+ " stop in between.\n\n");
+
+ for (i = 0; i < bytes_chunks; i++) {
+ tr.buf[0] = ROM_WREN;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing WREN command\n\n");
+ return;
+ }
+
+ /* Command with data and address */
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_WRITE;
+ tr.direction = TRANSMIT;
+ /*
+ * We will store the address into the buffer in little
+ * endian order.
+ */
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.len = 64;
+ tr.addr_present = 1;
+
+ /* Read 64 bytes from input file to buffer */
+ if (read(infile_fd, &tr.buf[4], tr.len) < 0) {
+ printf("\nError reading from file %s\n\n", filename);
+ return;
+ }
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing WRITE command\n\n");
+ return;
+ }
+
+ addr += 64;
+
+ /*
+ * Before the next loop, we need to make sure that WIP
+ * bit in the output of RDSR has been reset.
+ */
+ while (1) {
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
+
+ if ((tr.buf[1] & 0x01) == 0x00)
+ break;
+ }
+ }
+
+ if (remaining_bytes) {
+ tr.buf[0] = ROM_WREN;
+ tr.direction = 0;
+ tr.len = 0;
+ tr.addr_present = 0;
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing WREN command\n\n");
+ return;
+ }
+
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_WRITE;
+ tr.direction = TRANSMIT;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.len = remaining_bytes;
+ tr.addr_present = 1;
+
+ if (read(infile_fd, &tr.buf[4], tr.len) < 0) {
+ printf("\nError reading from file %s\n\n", filename);
+ return;
+ }
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing WRITE command\n\n");
+ return;
+ }
+
+ while (1) {
+ memset(&tr, 0, sizeof(struct spi_ioc_transfer));
+ tr.buf[0] = ROM_RDSR;
+ tr.direction = RECEIVE;
+ tr.addr_present = 0;
+ tr.len = 1;
+
+ ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
+
+ if ((tr.buf[1] & 0x01) == 0x00)
+ break;
+ }
+ }
+
+ printf("\n\n...WRITE completed successfully\n\n");
+ close(infile_fd);
+ } else if (strncmp(cmdline, "license", 7) == 0) {
+ show_license();
+ } else if (strncmp(cmdline, "exit", 4) == 0) {
+ printf("\nExiting...\n");
+ close(fd);
+ exit(EXIT_SUCCESS);
+ } else if (strncmp(cmdline, "help", 4) == 0) {
+ print_usage();
+ } else {
+ printf("\nUnknown command\n");
+ print_usage();
+ }
+}
+
+int main(void)
+{
+ char *cmdline= NULL;
+
+ printf("SPI sample application version: %s\n", SPI_APP_VERSION);
+ printf("Copyright (c) 2014, Advanced Micro Devices, Inc.\n"
+ "This sample application comes with ABSOLUTELY NO WARRANTY;\n"
+ "This is free software, and you are welcome to redistribute it\n"
+ "under certain conditions; type `license` for details.\n\n");
+
+ /* Set the signal handler */
+ signal(SIGINT, sighandler);
+
+ while (1) {
+ cmdline = readline(show_prompt());
+ parse_cmd(cmdline);
+ /* Free the memory malloc'ed by readline */
+ free(cmdline);
+ }
+
+ /* Restore the default signal handler */
+ signal(SIGINT, SIG_DFL);
+
+ /* Should never reach here */
+ return 0;
+}
diff --git a/meta-amd-bsp/recipes-applications/spi-test/files/spirom.h b/meta-amd-bsp/recipes-applications/spi-test/files/spirom.h
new file mode 100644
index 00000000..f599925f
--- /dev/null
+++ b/meta-amd-bsp/recipes-applications/spi-test/files/spirom.h
@@ -0,0 +1,53 @@
+#ifndef SPIROM_H
+#define SPIROM_H
+
+#include <linux/types.h>
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL commands */
+
+#define SPI_IOC_MAGIC 'k'
+
+#define TRANSMIT 1
+#define RECEIVE 2
+
+/*
+ * struct spi_ioc_transfer - interface structure between application and ioctl
+ *
+ * @buf: Buffer to hold 1-byte command, 3-bytes address, and 4-byte data for
+ * transmit or receive. The internal FIFO of our controller can hold a
+ * maximum of 8 bytes, including the address. But here we assume the
+ * maximum data excluding address to be 4-bytes long.
+ *
+ * @direction: Direction of data transfer, either TRANSMIT or RECEIVE.
+ *
+ * @len: Length of data excluding command and address.
+ *
+ * @addr_present: Flag to indicate whether 'buf' above contains an address.
+ */
+struct spi_ioc_transfer {
+ __u8 buf[64 + 1 + 3];
+ __u8 direction;
+ __u8 len;
+ __u8 addr_present;
+};
+
+/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
+#define SPI_MSGSIZE(N) \
+ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
+ ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
+#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+
+/* SPI ROM command codes */
+#define ROM_WREN 0x06
+#define ROM_WRDI 0x04
+#define ROM_RDSR 0x05
+#define ROM_RDID 0x9F
+#define ROM_CHIP_ERASE 0x60
+#define ROM_SECTOR_ERASE 0x20
+#define ROM_BLOCK_ERASE 0xD8
+#define ROM_READ 0x03
+#define ROM_WRITE 0x02
+
+#endif /* SPIROM_H */
diff --git a/meta-amd-bsp/recipes-applications/spi-test/spi-test_1.0.bb b/meta-amd-bsp/recipes-applications/spi-test/spi-test_1.0.bb
new file mode 100644
index 00000000..e56f2c17
--- /dev/null
+++ b/meta-amd-bsp/recipes-applications/spi-test/spi-test_1.0.bb
@@ -0,0 +1,24 @@
+DESCRIPTION = "Sample application for AMD SPI driver"
+SECTION = "applications"
+LICENSE = "BSD"
+DEPENDS = "readline"
+LIC_FILES_CHKSUM = "file://spirom-test.c;endline=29;md5=8e7a9706367d146e5073510a6e176dc2"
+
+SRC_URI = "file://spirom-test.c \
+ file://spirom.h \
+ "
+
+SRC_URI_append_e3000 = "file://0001-Modified-the-spi-driver-test-application-to-support-.patch"
+
+S = "${WORKDIR}"
+
+TARGET_CC_ARCH += "${LDFLAGS}"
+
+do_compile() {
+ ${CC} spirom-test.c -o spirom-test -lreadline
+}
+
+do_install() {
+ install -d ${D}${bindir}
+ install -m 0755 spirom-test ${D}${bindir}
+}