aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-baldeagle/recipes-applications/spi-test/files/spirom-test.c765
-rw-r--r--meta-baldeagle/recipes-applications/spi-test/files/spirom.h20
-rw-r--r--meta-baldeagle/recipes-applications/spi-test/spi-test_1.0.bb4
-rw-r--r--meta-baldeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb8
-rw-r--r--meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.c51
-rw-r--r--meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.h2
-rw-r--r--meta-baldeagle/recipes-kernel/amd-spi/files/spirom.c79
-rw-r--r--meta-baldeagle/recipes-kernel/amd-spi/files/spirom.h20
-rw-r--r--meta-baldeagle/recipes-kernel/linux/linux-yocto/0046-yocto-poky-dora-10.0.0-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch455
-rw-r--r--meta-baldeagle/recipes-kernel/linux/linux-yocto/0047-yocto-poky-dora-10.0.0-amd-i2c-dev-add-calls-to-enable-and-disable-IMC-from-fetching-BIOS-code.patch51
-rw-r--r--meta-baldeagle/recipes-kernel/linux/linux-yocto/defconfig57
-rw-r--r--meta-baldeagle/recipes-kernel/linux/linux-yocto_3.12.bb4
-rw-r--r--meta-steppeeagle/recipes-applications/spi-test/files/spirom-test.c737
-rw-r--r--meta-steppeeagle/recipes-applications/spi-test/files/spirom.h10
-rw-r--r--meta-steppeeagle/recipes-applications/spi-test/spi-test_1.0.bb4
-rw-r--r--meta-steppeeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb6
-rw-r--r--meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.c51
-rw-r--r--meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.h2
-rw-r--r--meta-steppeeagle/recipes-kernel/amd-spi/files/spirom.h10
19 files changed, 1532 insertions, 804 deletions
diff --git a/meta-baldeagle/recipes-applications/spi-test/files/spirom-test.c b/meta-baldeagle/recipes-applications/spi-test/files/spirom-test.c
index e7dfe6f1..9006c130 100644
--- a/meta-baldeagle/recipes-applications/spi-test/files/spirom-test.c
+++ b/meta-baldeagle/recipes-applications/spi-test/files/spirom-test.c
@@ -31,39 +31,34 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
-#include <getopt.h>
#include <fcntl.h>
#include <string.h>
-#include <errno.h>
+#include <dirent.h>
+#include <signal.h>
+
+#include <sys/types.h>
#include <sys/ioctl.h>
-#include <linux/types.h>
+#include <sys/stat.h>
+
+#include <readline/readline.h>
#include "spirom.h"
-#define SPI_APP_VERSION "0.1"
+#define SPI_APP_VERSION "1.0"
-#define WREN 0x06
-#define WRDI 0x04
-#define RDSR 0x05
-#define RDID 0x9F
-#define CHIP_ERASE 0x60
-#define SECTOR_ERASE 0x20
-#define BLOCK_ERASE 0xD8
-#define READ 0x03
-#define WRITE 0x02
+static int device_opened = 0;
+static char filename[20];
+static int fd = -1;
-static void pabort(const char *s)
+char *show_prompt(void)
{
- perror(s);
- abort();
+ return "$ ";
}
-static const char *device = "/dev/spirom0.0";
-static char command[20];
-static int inputfile_fd;
-static int outfile_fd;;
-static unsigned long address;
-static unsigned int num_bytes;
+void sighandler(int sig)
+{
+ /* Do nothing. That is the idea. */
+}
void show_license(void)
{
@@ -72,7 +67,7 @@ void show_license(void)
"* 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"
+ "* 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"
@@ -98,188 +93,302 @@ void show_license(void)
"***************************************************************************/\n");
}
-void parse_command(int fd)
+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)
{
- uint8_t cmd_byte;
struct spi_ioc_transfer tr;
unsigned int bytes_chunks;
unsigned int remaining_bytes;
+ int addr;
int ret;
- /* Zero initialize spi_ioc_transfer */
- memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- if ((strncmp(command, "WREN", 4) == 0) ||
- (strncmp(command, "wren", 4) == 0)) {
- /* Command without data */
- tr.buf[0] = WREN;
+ 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)
- pabort("can't send spi message");
- } else if ((strncmp(command, "WRDI", 4) == 0) ||
- (strncmp(command, "wrdi", 4) == 0)) {
- /* Command without data */
- tr.buf[0] = WRDI;
+ 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)
- pabort("can't send spi message");
- } else if ((strncmp(command, "CHIPERASE", 4) == 0) ||
- (strncmp(command, "chiperase", 4) == 0)) {
+ 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] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");;
+ return;
+ } else if ((tr.buf[1] & 0x02) == 0x00) {
+ printf("\nCannot execute RDSR command, write is disabled\n\n");
+ return;
}
/* Command without data */
- tr.buf[0] = CHIP_ERASE;
+ 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) {
- if (errno == EPERM)
- printf("\n\nIMC is enabled in your platform. "
- "Trying to perform CHIPERASE is not "
- "safe. If you really want to perform "
- "this operation, either disable IMC in "
- "BIOS, or set jumper JU105 to 2-3 "
- "position to disable IMC and then "
- "try again. Do not forget to remove "
- "power to the platform before changing "
- "jumper settings\n\n");
-
- pabort("can't send spi message");
+ 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] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
- } else if ((strncmp(command, "RDSR", 4) == 0) ||
- (strncmp(command, "rdsr", 4) == 0)) {
+
+ 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] = RDSR;
+ 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)
- pabort("can't send spi message");
+ 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("command: 0x%.2x response: 0x%.2x\n", tr.buf[0],
- tr.buf[1]);
- } else if ((strncmp(command, "RDID", 4) == 0) ||
- (strncmp(command, "rdid", 4) == 0)) {
+ 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] = RDID;
+ 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)
- pabort("can't send spi message");
+ 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("command: 0x%.2x response: 0x%.2x%.2x%.2x\n", tr.buf[0],
- tr.buf[1], tr.buf[2], tr.buf[3]);
- } else if ((strncmp(command, "SECTORERASE", 6) ==0) ||
- (strncmp(command, "sectorerase", 6) ==0)) {
+ 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;
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ 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;
}
- /*
- * num_bytes here is a little bit of misnomer, it indicates the
- * number of sectors to be erased, rather than the number of
- * bytes to be erased.
- */
- for (i = 0; i < num_bytes; i++) {
+ 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] = WREN;
+ 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)
- pabort("can't send spi message");
+ 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] = SECTOR_ERASE;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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) {
- if (errno == EPERM)
- printf("\n\nIMC is enabled in your "
- "platform. Trying to perform "
- "SECTORERASE is not safe. If you "
- "really want to perform this "
- "operation, either disable IMC "
- "in BIOS, or set jumper JU105 "
- "to 2-3 position to disable IMC "
- "and then try again. Do not "
- "forget to remove power to the "
- "platform before changing jumper "
- "settings.\n\n");
-
- pabort("can't send spi message");
+ printf("\nError executing SECTORERASE command\n\n");
+ return;
}
- /* point to the next 4k block */
- address += 4 * 1024;
+ /* point to the next 4k sector */
+ addr += 4 * 1024;
/*
* Before the next loop, we need to make sure that WIP
@@ -287,80 +396,86 @@ void parse_command(int fd)
*/
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
}
- } else if ((strncmp(command, "BLOCKERASE", 5) == 0) ||
- (strncmp(command, "blockerase", 5) == 0)) {
+
+ printf("\n\n...SECTORERASE completed successfully\n\n");
+ } else if (strncmp(cmdline, "blockerase", 10) == 0) {
+ int nblocks;
int i;
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ 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;
}
- /*
- * num_bytes indicates the number of blocks to be erased,
- * rather than the number of bytes to be erased.
- */
- for (i = 0; i < num_bytes; i++) {
+ 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] = WREN;
+ 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)
- pabort("can't send spi message");
+ 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] = BLOCK_ERASE;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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) {
- if (errno == EPERM)
- printf("\n\nIMC is enabled in your "
- "platform. Trying to perform "
- "BLOCKERASE is not safe. If "
- "you really want to perform "
- "this operation, either disable "
- "IMC in BIOS, or set jumper "
- "JU105 to 2-3 position to "
- "disable IMC and then try "
- "again. Do not forget to remove "
- "power to the platform before "
- "changing jumper settings.\n\n");
-
- pabort("can't send spi message");
+ printf("\nError executing BLOCKERASE command\n\n");
+ return;
}
/* point to the next 64k block */
- address += 64 * 1024;
+ addr += 64 * 1024;
/*
* Before the next loop, we need to make sure that WIP
@@ -368,151 +483,205 @@ void parse_command(int fd)
*/
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
}
- } else if ((strncmp(command, "READ", 4) == 0) ||
- (strncmp(command, "read", 4) ==0)) {
+
+ 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 4-bytes. Data might not be a even multiple of 4. So
* in that case, we will have some remaining bytes <4. We
* handle that separately.
*/
- bytes_chunks = num_bytes / 4;
- remaining_bytes = num_bytes % 4;
+ bytes_chunks = nbytes / 4;
+ remaining_bytes = nbytes % 4;
+
+ 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] = READ;
+ tr.buf[0] = ROM_READ;
tr.direction = RECEIVE;
/*
* We will store the address into the buffer in little
* endian order.
*/
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
tr.len = 4;
tr.addr_present = 1;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
- if (ret < 1)
- pabort("can't send spi message");
+ 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) {
- perror("write error");
- exit(1);
+ printf("\nError writing to file %s\n\n", filename);
+ return;
}
- address += 4;
+ addr += 4;
}
if (remaining_bytes) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = READ;
+ tr.buf[0] = ROM_READ;
tr.direction = RECEIVE;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing READ command\n\n");
+ return;
+ }
if (write(outfile_fd, &tr.buf[4], tr.len) < 0) {
- perror("write error");
- exit(1);
+ printf("\nError writing to file %s\n\n", filename);
+ return;
}
}
- } else if ((strncmp(command, "WRITE", 5) == 0) ||
- (strncmp(command, "write", 5) ==0)) {
+
+ 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 4-bytes. Like for read, we might not have data in an
* even multiple of 4 bytes. So we will handle the remaining
* bytes in the end.
*/
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ 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 = num_bytes / 4;
- remaining_bytes = num_bytes % 4;
+ bytes_chunks = nbytes / 4;
+ remaining_bytes = nbytes % 4;
+
+ printf("\n\nWRITE operation in progress, please do not "
+ " stop in between.\n\n");
for (i = 0; i < bytes_chunks; i++) {
- tr.buf[0] = WREN;
+ 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)
- pabort("can't send spi message");
+ 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] = WRITE;
+ tr.buf[0] = ROM_WRITE;
tr.direction = TRANSMIT;
/*
* We will store the address into the buffer in little
* endian order.
*/
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
tr.len = 4;
tr.addr_present = 1;
- /* Read 4 bytes from inputfile to buffer */
- if (read(inputfile_fd, &tr.buf[4], tr.len) < 0) {
- perror("read error");
- exit(1);
+ /* Read 4 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) {
- if (errno == EPERM)
- printf("\n\nIMC is enabled in your "
- "platform. Trying to perform "
- "WRITE is not safe. If you "
- "really want to perform this "
- "operation, either disable IMC "
- "in BIOS, or set jumper JU105 "
- "to 2-3 position to disable IMC "
- "and then try again. Do not "
- "forget to remove power to the "
- "platform before changing jumper "
- "settings.\n\n");
-
- pabort("can't send spi message");
+ printf("\nError executing WRITE command\n\n");
+ return;
}
- address += 4;
+ addr += 4;
/*
* Before the next loop, we need to make sure that WIP
@@ -520,14 +689,16 @@ void parse_command(int fd)
*/
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
@@ -535,161 +706,93 @@ void parse_command(int fd)
}
if (remaining_bytes) {
- tr.buf[0] = WREN;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing WREN command\n\n");
+ return;
+ }
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = WRITE;
+ tr.buf[0] = ROM_WRITE;
tr.direction = TRANSMIT;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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(inputfile_fd, &tr.buf[4], tr.len) < 0) {
- perror("read error");
- exit(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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing WRITE command\n\n");
+ return;
+ }
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
}
- } else
- pabort("Unrecognized command, please try again.\n");
-}
-
-static void print_usage(const char *prog)
-{
- printf("\nUsage: sudo %s [-DCAnio] [arguments]\n\n", prog);
- puts(" -D --device SPI ROM device to use\n"
- " (default /dev/spirom0.0)\n\n"
- " -C --command command to send to the device\n"
- " (WREN/WRDI/RDSR/RDID/CHIPERASE/SECTORERASE/\n"
- " BLOCKERASE/READ/WRITE)\n\n"
- " -A --address offset in decimal, into the device to read\n"
- " from or write to. For a ROM size of 8MB,\n"
- " address can go from 0 to 8388608. Negative\n"
- " offsets are not valid, but the program\n"
- " won't complain and convert it to its\n"
- " unsigned equivalent.\n\n"
- " -n --num-bytes number of bytes to be read from or written\n"
- " to. Depending on the address, this can\n"
- " take values from 0 to 8388608 for a ROM\n"
- " size of 8MB.\n\n"
- " In case of SECTORERASE and BLOCKERASE\n"
- " commands, num-bytes actually takes the\n"
- " number of sectors and blocks to be erased\n"
- " respectively, rather than the number of\n"
- " bytes.\n\n"
- " -i --input-file file to be used as input.\n\n"
- " -o --output-file file to be used for output. Remember that if\n"
- " an existing filename is given, its contents\n"
- " will be overwritten.\n"
- " -l --license displays the terms of LICENSE for this application\n\n");
- exit(1);
-}
-
-static void parse_opts(int argc, char *argv[])
-{
- if (argc == 1)
- print_usage(argv[0]);
- while (1) {
- static const struct option lopts[] = {
- { "device", 1, 0, 'D' },
- { "command", 1, 0, 'C' },
- { "address", 1, 0, 'A' },
- { "num-bytes", 1, 0, 'n' },
- { "input-file", 1, 0, 'i' },
- { "output-file", 1, 0, 'o' },
- { "license", 0, 0, 'l' },
- { NULL, 0, 0, 0 },
- };
- int c;
-
- c = getopt_long(argc, argv, "D:C:A:n:i:o:l", lopts, NULL);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'D':
- device = optarg;
- break;
- case 'C':
- memset(command, sizeof(command), 0);
- strncpy(command, optarg, sizeof(command));
- break;
- case 'A':
- address = atol(optarg);
- break;
- case 'n':
- num_bytes = atoi(optarg);
- break;
- case 'i':
- inputfile_fd = open(optarg, O_RDONLY);
- if (inputfile_fd < 0) {
- printf("Error opening %s\n", optarg);
- exit(1);
- }
- break;
- case 'o':
- outfile_fd = open(optarg, O_WRONLY | O_CREAT |
- O_TRUNC, 0644);
- if(outfile_fd < 0) {
- printf("Error opening %s\n", optarg);
- exit(1);
- }
- break;
- case 'l':
- show_license();
- exit(0);;
- default:
- print_usage(argv[0]);
- 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(int argc, char *argv[])
+int main(void)
{
- int ret = 0;
- int fd;
+ 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");
+ "under certain conditions; type `license` for details.\n\n");
- parse_opts(argc, argv);
+ /* Set the signal handler */
+ signal(SIGINT, sighandler);
- fd = open(device, O_RDWR);
- if (fd < 0)
- pabort("can't open device");
+ while (1) {
+ cmdline = readline(show_prompt());
+ parse_cmd(cmdline);
+ /* Free the memory malloc'ed by readline */
+ free(cmdline);
+ }
- parse_command(fd);
+ /* Restore the default signal handler */
+ signal(SIGINT, SIG_DFL);
- return ret;
+ /* Should never reach here */
+ return 0;
}
diff --git a/meta-baldeagle/recipes-applications/spi-test/files/spirom.h b/meta-baldeagle/recipes-applications/spi-test/files/spirom.h
index fe142a31..1b0caafa 100644
--- a/meta-baldeagle/recipes-applications/spi-test/files/spirom.h
+++ b/meta-baldeagle/recipes-applications/spi-test/files/spirom.h
@@ -39,24 +39,6 @@ struct spi_ioc_transfer {
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
-#ifdef __KERNEL__
-
-/* IO port address for indirect access using the ACPI PM registers */
-#define AMD_IO_PM_INDEX_REG 0xCD6
-#define AMD_IO_PM_DATA_REG 0xCD7
-
-#define AMD_PM_ACPI_MMIO_BASE0 0x24
-#define AMD_PM_ACPI_MMIO_BASE1 0x25
-#define AMD_PM_ACPI_MMIO_BASE2 0x26
-#define AMD_PM_ACPI_MMIO_BASE3 0x27
-
-#define AMD_ACPI_MMIO_ADDR_MASK ~0x1FFF
-
-/* Offset of IMC Strap Status register in the ACPI MMIO region */
-#define AMD_IMC_STRAP_STATUS_OFFSET 0xE80
- #define AMD_IMC_ENABLED 0x4
-#define AMD_IMC_STRAP_STATUS_SIZE 4
-
/* SPI ROM command codes */
#define ROM_WREN 0x06
#define ROM_WRDI 0x04
@@ -68,6 +50,4 @@ struct spi_ioc_transfer {
#define ROM_READ 0x03
#define ROM_WRITE 0x02
-#endif /* __KERNEL__ */
-
#endif /* SPIROM_H */
diff --git a/meta-baldeagle/recipes-applications/spi-test/spi-test_1.0.bb b/meta-baldeagle/recipes-applications/spi-test/spi-test_1.0.bb
index 8cb251c9..2d75661b 100644
--- a/meta-baldeagle/recipes-applications/spi-test/spi-test_1.0.bb
+++ b/meta-baldeagle/recipes-applications/spi-test/spi-test_1.0.bb
@@ -2,8 +2,8 @@ DESCRIPTION = "Sample application for AMD SPI driver"
SECTION = "applications"
LICENSE = "BSD"
DEPENDS = "readline"
-LIC_FILES_CHKSUM = "file://spirom-test.c;md5=a8b8f295bacb7eaffb0981efe09ca1bb \
- file://spirom.h;md5=332ef940b1cb318fc8ecd9b1ba5940be \
+LIC_FILES_CHKSUM = "file://spirom-test.c;md5=3065341fac5fc1255711c219f00f7324 \
+ file://spirom.h;md5=dad84d1bbdd9852dde1fdf1ea3a014d6 \
"
PR = "r1"
diff --git a/meta-baldeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb b/meta-baldeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb
index c25a9a81..850a0e42 100644
--- a/meta-baldeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb
+++ b/meta-baldeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb
@@ -1,9 +1,9 @@
DESCRIPTION = "This kernel module provides support for AMD SPI controller driver"
LICENSE = "BSD | GPLv2"
-LIC_FILES_CHKSUM = "file://spi_amd.c;md5=e70d62038c566061b8fea14bb3d31c39 \
- file://spi_amd.h;md5=5400c6b24b00e86e5930fdccc058dabb \
- file://spirom.c;md5=558c5e03489d2d7792c03dcf7e2539ab \
- file://spirom.h;md5=332ef940b1cb318fc8ecd9b1ba5940be \
+LIC_FILES_CHKSUM = "file://spi_amd.c;md5=bca93a3bd8cbdabafd4089daf5109768 \
+ file://spi_amd.h;md5=67ba12b2bcfda1402435aebf18cda6bd \
+ file://spirom.c;md5=f1cd805abcc598247c197aed08ec4a5d \
+ file://spirom.h;md5=dad84d1bbdd9852dde1fdf1ea3a014d6 \
file://Makefile;md5=8ea80a6d4ae15bcf922d090df6cfdd4c \
"
diff --git a/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.c b/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.c
index 6af2c6db..1ca9b69a 100644
--- a/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.c
+++ b/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.c
@@ -45,9 +45,9 @@ struct amd_spi {
u32 rom_addr;
struct spi_master *master;
struct amd_platform_data controller_data;
- spinlock_t lock;
struct task_struct *kthread_spi;
struct list_head msg_queue;
+ wait_queue_head_t wq;
};
static struct pci_device_id amd_spi_pci_device_id[] = {
@@ -155,7 +155,9 @@ static void amd_spi_execute_opcode(struct spi_master *master)
spi_busy = (ioread32((u8 *)amd_spi->io_remap_addr +
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
while (spi_busy) {
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
+ set_current_state(TASK_RUNNING);
spi_busy = (ioread32((u8 *)amd_spi->io_remap_addr +
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
}
@@ -199,29 +201,17 @@ static int amd_spi_master_setup(struct spi_device *spi)
return 0;
}
-static int amd_spi_master_transfer(struct spi_device *spi,
+static int amd_spi_master_transfer(struct spi_master *master,
struct spi_message *msg)
{
- struct spi_master *master = spi->master;
struct amd_spi *amd_spi = spi_master_get_devdata(master);
/*
- * We will just add this message to the message queue set up by
- * the controller, and let the kernel thread handle it later.
- */
- msg->status = -EINPROGRESS;
- msg->actual_length = 0;
- msg->spi = spi;
- /*
- * There could be a situation when we are running on this processor
- * and trying to add element to the end of the message queue, but
- * at the same time the kernel thread is running on another processor
- * and trying to find out if the list is empty or not. So protect
- * against such contention. Simple spin_lock() should do.
+ * Add new message to the queue and let the kernel thread know
+ * about it.
*/
- spin_lock(&amd_spi->lock);
list_add_tail(&msg->queue, &amd_spi->msg_queue);
- spin_unlock(&amd_spi->lock);
+ wake_up_interruptible(&amd_spi->wq);
return 0;
}
@@ -249,25 +239,19 @@ static int amd_spi_thread(void *t)
* 4-bytes of data and 3-bytes of address.
*/
while (1) {
- /* break condition */
+ /*
+ * Let us wait on a wait queue till the message queue is empty.
+ */
+ wait_event_interruptible(amd_spi->wq,
+ !list_empty(&amd_spi->msg_queue));
+
+ /* stop condition */
if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
break;
}
/*
- * If the message queue is empty, then there is no need to waste
- * CPU cycles. So we let other processes execute, and continue
- * from the beginning of the loop when we next get to run.
- */
- spin_lock(&amd_spi->lock);
- if (list_empty(&amd_spi->msg_queue)) {
- spin_unlock(&amd_spi->lock);
- schedule();
- continue;
- }
-
- /*
* Else, pull the very first message from the queue and process
* all transfers within that message. And process the messages
* in a pure linear fashion. We also remove the spi_message
@@ -276,7 +260,6 @@ static int amd_spi_thread(void *t)
message = list_entry(amd_spi->msg_queue.next,
struct spi_message, queue);
list_del_init(&message->queue);
- spin_unlock(&amd_spi->lock);
/* We store the CS# line to be used for this spi_message */
amd_spi->controller_data.chip_select =
@@ -396,7 +379,7 @@ static int amd_spi_thread(void *t)
message->actual_length = tx_len + rx_len + 1;
/* complete the transaction */
message->status = 0;
- message->complete(message->context);
+ spi_finalize_current_message(master);
}
return 0;
@@ -441,8 +424,8 @@ static int amd_spi_pci_probe(struct pci_dev *pdev,
dev_dbg(dev, "io_base_addr: 0x%.8lx, io_remap_address: %p\n",
amd_spi->io_base_addr, amd_spi->io_remap_addr);
- spin_lock_init(&amd_spi->lock);
INIT_LIST_HEAD(&amd_spi->msg_queue);
+ init_waitqueue_head(&amd_spi->wq);
amd_spi->kthread_spi = kthread_run(amd_spi_thread, amd_spi,
"amd_spi_thread");
@@ -455,7 +438,7 @@ static int amd_spi_pci_probe(struct pci_dev *pdev,
master->mode_bits = 0;
master->flags = 0;
master->setup = amd_spi_master_setup;
- master->transfer = amd_spi_master_transfer;
+ master->transfer_one_message = amd_spi_master_transfer;
/* Register the controller with SPI framework */
err = spi_register_master(master);
if (err) {
diff --git a/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.h b/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.h
index bc0bd6e8..b766d15c 100644
--- a/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.h
+++ b/meta-baldeagle/recipes-kernel/amd-spi/files/spi_amd.h
@@ -2,7 +2,7 @@
#define SPI_AMD_H
#define DRIVER_NAME "spi_amd"
-#define SPI_VERSION "0.1"
+#define SPI_VERSION "1.0"
#define PCI_DEVICE_ID_AMD_LPC_BRIDGE 0x780E
diff --git a/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.c b/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.c
index 99d28d31..4df6c70c 100644
--- a/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.c
+++ b/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.c
@@ -32,11 +32,13 @@
#include <linux/spi/spi.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/amd_imc.h>
+
#include <asm/uaccess.h>
#include "spirom.h"
-#define SPIROM_VERSION "0.1"
+#define SPIROM_VERSION "0.2"
/*
* SPI has a character major number assigned. We allocate minor numbers
@@ -52,7 +54,6 @@
#define SPI_BUS_CS1 0
static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
-static int imc_enabled;
struct spirom_data {
dev_t devt;
@@ -84,7 +85,6 @@ spirom_sync(struct spirom_data *spirom, struct spi_message *message)
{
int status;
- INIT_COMPLETION(spirom->done);
message->complete = spirom_complete;
message->context = &spirom->done;
@@ -128,18 +128,6 @@ static int spirom_message(struct spirom_data *spirom,
return -ENOMEM;
transfer->tx_buf = buffer;
-
- /*
- * In case IMC is enabled, and an erase or write operation is requested
- * on the ROM, we simply print a message and return from here. Rather
- * than letting the user corrupt his system never to boot again, it is
- * better to play safe.
- */
- if (imc_enabled && ((*buffer == ROM_CHIP_ERASE) ||
- (*buffer == ROM_SECTOR_ERASE) || (*buffer == ROM_BLOCK_ERASE) ||
- (*buffer == ROM_WRITE)))
- return -EPERM;
-
transfer->len = 1;
buffer += transfer->len;
spi_message_add_tail(transfer, &msg);
@@ -318,6 +306,14 @@ static int spirom_open(struct inode *inode, struct file *filp)
mutex_unlock(&device_list_lock);
+ /*
+ * In case IMC is enabled, we need to inform IMC to stop
+ * fetching code from the BIOS ROM. We will inform IMC when
+ * it is safe to start fetching from ROM again once we are
+ * done with our SPI transactions.
+ */
+ amd_imc_enter_scratch_ram();
+
return status;
}
@@ -345,6 +341,14 @@ static int spirom_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&device_list_lock);
+ /*
+ * In case IMC is enabled, we would have instructed IMC to stop
+ * fetching from ROM BIOS earlier in the code path. Now that we
+ * are done, we can safely inform IMC to start fetching from ROM
+ * again.
+ */
+ amd_imc_exit_scratch_ram();
+
return status;
}
@@ -396,57 +400,12 @@ static int spirom_probe(struct spi_device *spi)
struct spirom_data *spirom;
int status;
unsigned long minor;
- u32 val;
- u8 *byte;
- u32 imc_strap_status_phys;
- void __iomem *imcstrapstatus;
/* Allocate driver data */
spirom = kzalloc(sizeof(*spirom), GFP_KERNEL);
if (!spirom)
return -ENOMEM;
- /* Locate ACPI MMIO Base Address */
- byte = (u8 *)&val;
-
- outb(AMD_PM_ACPI_MMIO_BASE0, AMD_IO_PM_INDEX_REG);
- byte[0] = inb(AMD_IO_PM_DATA_REG);
- outb(AMD_PM_ACPI_MMIO_BASE1, AMD_IO_PM_INDEX_REG);
- byte[1] = inb(AMD_IO_PM_DATA_REG);
- outb(AMD_PM_ACPI_MMIO_BASE2, AMD_IO_PM_INDEX_REG);
- byte[2] = inb(AMD_IO_PM_DATA_REG);
- outb(AMD_PM_ACPI_MMIO_BASE3, AMD_IO_PM_INDEX_REG);
- byte[3] = inb(AMD_IO_PM_DATA_REG);
-
- /* Bits 31:13 is the actual ACPI MMIO Base Address */
- val &= AMD_ACPI_MMIO_ADDR_MASK;
-
- /* IMCStrapStatus is located at ACPI MMIO Base Address + 0xE80 */
- if (!request_mem_region_exclusive(val + AMD_IMC_STRAP_STATUS_OFFSET,
- AMD_IMC_STRAP_STATUS_SIZE, "IMC Strap Status"))
- pr_err("spirom: MMIO address 0x%04x already in use\n", val +
- AMD_IMC_STRAP_STATUS_OFFSET);
-
- imc_strap_status_phys = val + AMD_IMC_STRAP_STATUS_OFFSET;
-
- imcstrapstatus = ioremap(imc_strap_status_phys, AMD_IMC_STRAP_STATUS_SIZE);
- if (!imcstrapstatus)
- pr_err("spirom: failed to map IMC Strap Status address\n");
-
- /* Check if IMC is enabled */
- val = ioread32(imcstrapstatus);
- if ((val & AMD_IMC_ENABLED) == AMD_IMC_ENABLED) {
- pr_info("spirom: IMC is enabled\n");
- imc_enabled = 1;
- } else {
- pr_info("spirom: IMC is disabled\n");
- imc_enabled = 0;
- }
-
- /* Release the region occupied by IMC Strap Status register */
- iounmap(imcstrapstatus);
- release_mem_region(imc_strap_status_phys, AMD_IMC_STRAP_STATUS_SIZE);
-
/* Initialize the driver data */
spirom->spi = spi;
spin_lock_init(&spirom->spi_lock);
diff --git a/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.h b/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.h
index fe142a31..1b0caafa 100644
--- a/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.h
+++ b/meta-baldeagle/recipes-kernel/amd-spi/files/spirom.h
@@ -39,24 +39,6 @@ struct spi_ioc_transfer {
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
-#ifdef __KERNEL__
-
-/* IO port address for indirect access using the ACPI PM registers */
-#define AMD_IO_PM_INDEX_REG 0xCD6
-#define AMD_IO_PM_DATA_REG 0xCD7
-
-#define AMD_PM_ACPI_MMIO_BASE0 0x24
-#define AMD_PM_ACPI_MMIO_BASE1 0x25
-#define AMD_PM_ACPI_MMIO_BASE2 0x26
-#define AMD_PM_ACPI_MMIO_BASE3 0x27
-
-#define AMD_ACPI_MMIO_ADDR_MASK ~0x1FFF
-
-/* Offset of IMC Strap Status register in the ACPI MMIO region */
-#define AMD_IMC_STRAP_STATUS_OFFSET 0xE80
- #define AMD_IMC_ENABLED 0x4
-#define AMD_IMC_STRAP_STATUS_SIZE 4
-
/* SPI ROM command codes */
#define ROM_WREN 0x06
#define ROM_WRDI 0x04
@@ -68,6 +50,4 @@ struct spi_ioc_transfer {
#define ROM_READ 0x03
#define ROM_WRITE 0x02
-#endif /* __KERNEL__ */
-
#endif /* SPIROM_H */
diff --git a/meta-baldeagle/recipes-kernel/linux/linux-yocto/0046-yocto-poky-dora-10.0.0-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch b/meta-baldeagle/recipes-kernel/linux/linux-yocto/0046-yocto-poky-dora-10.0.0-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch
new file mode 100644
index 00000000..5b4cb7a2
--- /dev/null
+++ b/meta-baldeagle/recipes-kernel/linux/linux-yocto/0046-yocto-poky-dora-10.0.0-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch
@@ -0,0 +1,455 @@
+From 370d48b29a69a2e38d3092058413b22f040203de Mon Sep 17 00:00:00 2001
+From: Arindam Nath <arindam.nath@amd.com>
+Date: Mon, 4 Aug 2014 19:16:53 +0530
+Subject: [PATCH 1/2] yocto: amd: staging: add support to enable and disable
+ IMC to fetch BIOS code
+
+The patch essentially adds support for two functions:
+amd_imc_enter_scratch_ram() and amd_imc_exit_scratch_ram(). These
+functions instruct IMC to stop and start fetching code from BIOS
+ROM respectively. These functions are needed where IMC is trying
+to fetch code on a shared bus when some other transaction is already
+occuring. To prevent IMC to fetch incorrect data from ROM while it
+is still being updated, we instruct IMC to temporarily stop fetching
+code from BIOS, and then start fetching again when it is safe to do
+so.
+
+Upstream Status: None
+
+Signed-off-by: Arindam Nath <arindam.nath@amd.com>
+---
+ drivers/staging/Kconfig | 2 +
+ drivers/staging/Makefile | 1 +
+ drivers/staging/amd_imc/Kconfig | 9 ++
+ drivers/staging/amd_imc/Makefile | 1 +
+ drivers/staging/amd_imc/amd_imc.c | 298 ++++++++++++++++++++++++++++++++++++++
+ include/linux/amd_imc.h | 68 +++++++++
+ 6 files changed, 379 insertions(+)
+ create mode 100644 drivers/staging/amd_imc/Kconfig
+ create mode 100644 drivers/staging/amd_imc/Makefile
+ create mode 100644 drivers/staging/amd_imc/amd_imc.c
+ create mode 100644 include/linux/amd_imc.h
+
+diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
+index 3626dbc8..0a95d6d 100644
+--- a/drivers/staging/Kconfig
++++ b/drivers/staging/Kconfig
+@@ -148,4 +148,6 @@ source "drivers/staging/dgnc/Kconfig"
+
+ source "drivers/staging/dgap/Kconfig"
+
++source "drivers/staging/amd_imc/Kconfig"
++
+ endif # STAGING
+diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
+index d1b4b80..2be3a91 100644
+--- a/drivers/staging/Makefile
++++ b/drivers/staging/Makefile
+@@ -66,3 +66,4 @@ obj-$(CONFIG_USB_BTMTK) += btmtk_usb/
+ obj-$(CONFIG_XILLYBUS) += xillybus/
+ obj-$(CONFIG_DGNC) += dgnc/
+ obj-$(CONFIG_DGAP) += dgap/
++obj-$(CONFIG_AMD_IMC) += amd_imc/
+diff --git a/drivers/staging/amd_imc/Kconfig b/drivers/staging/amd_imc/Kconfig
+new file mode 100644
+index 0000000..abfb724
+--- /dev/null
++++ b/drivers/staging/amd_imc/Kconfig
+@@ -0,0 +1,9 @@
++config AMD_IMC
++ bool "AMD Integrated Micro Controller support"
++ depends on PCI && X86_64
++ default y
++ ---help---
++ This driver supports AMD Integrated Micro Controller.
++
++ To compile this driver as a module, choose M here. The module
++ will be called amd_imc.
+diff --git a/drivers/staging/amd_imc/Makefile b/drivers/staging/amd_imc/Makefile
+new file mode 100644
+index 0000000..c4837f8
+--- /dev/null
++++ b/drivers/staging/amd_imc/Makefile
+@@ -0,0 +1 @@
++obj-$(CONFIG_AMD_IMC) += amd_imc.o
+diff --git a/drivers/staging/amd_imc/amd_imc.c b/drivers/staging/amd_imc/amd_imc.c
+new file mode 100644
+index 0000000..c6c6074
+--- /dev/null
++++ b/drivers/staging/amd_imc/amd_imc.c
+@@ -0,0 +1,298 @@
++/*****************************************************************************
++*
++* 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 <linux/init.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/uaccess.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/amd_imc.h>
++
++static int imc_enabled;
++static u16 imc_port_addr;
++static u8 msg_reg_base_hi;
++static u8 msg_reg_base_lo;
++static u16 msg_reg_base;
++
++static struct pci_dev *amd_imc_pci;
++static struct platform_device *amd_imc_platform_device;
++
++static DEFINE_PCI_DEVICE_TABLE(amd_lpc_pci_tbl) = {
++ {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LPC_BRIDGE, PCI_ANY_ID,
++ PCI_ANY_ID,},
++ {}
++};
++
++void amd_imc_enter_scratch_ram(void)
++{
++ u8 byte;
++
++ if (!imc_enabled)
++ return;
++
++ /* Instruct IMC to enter scratch RAM */
++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ outb(0, msg_reg_base + AMD_MSG_DATA_REG_OFFSET);
++
++ outb(AMD_MSG_REG1, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ outb(AMD_IMC_ENTER_SCRATCH_RAM, msg_reg_base + AMD_MSG_DATA_REG_OFFSET);
++
++ outb(AMD_MSG_SYS_TO_IMC, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ outb(AMD_IMC_ROM_OWNERSHIP_SEM, msg_reg_base +
++ AMD_MSG_DATA_REG_OFFSET);
++
++ /* As per the spec, the firmware may take up to 50ms */
++ msleep(50);
++
++ /* read message registger 0 to confirm function completion */
++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ byte = inb(msg_reg_base + AMD_MSG_DATA_REG_OFFSET);
++
++ if (byte == AMD_IMC_FUNC_NOT_SUPP)
++ pr_info("amd_imc: %s not supported\n", __func__);
++ else if (byte == AMD_IMC_FUNC_COMPLETED)
++ pr_info("amd_imc: %s completed\n", __func__);
++}
++EXPORT_SYMBOL_GPL(amd_imc_enter_scratch_ram);
++
++void amd_imc_exit_scratch_ram(void)
++{
++ u8 byte;
++
++ if (!imc_enabled)
++ return;
++
++ /* Instruct IMC to exit scratch RAM */
++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ outb(0, msg_reg_base + AMD_MSG_DATA_REG_OFFSET);
++
++ outb(AMD_MSG_REG1, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ outb(AMD_IMC_ENTER_SCRATCH_RAM, msg_reg_base + AMD_MSG_DATA_REG_OFFSET);
++
++ outb(AMD_MSG_SYS_TO_IMC, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ outb(AMD_IMC_ROM_OWNERSHIP_SEM, msg_reg_base +
++ AMD_MSG_DATA_REG_OFFSET);
++
++ /* As per the spec, the firmware may take up to 50ms */
++ msleep(50);
++
++ /* read message registger 0 to confirm function completion */
++ outb(AMD_MSG_REG0, msg_reg_base + AMD_MSG_INDEX_REG_OFFSET);
++ byte = inb(msg_reg_base + AMD_MSG_DATA_REG_OFFSET);
++
++ if (byte == AMD_IMC_FUNC_NOT_SUPP)
++ pr_info("amd_imc: %s not supported\n", __func__);
++ else if (byte == AMD_IMC_FUNC_COMPLETED)
++ pr_info("amd_imc: %s completed\n", __func__);
++}
++EXPORT_SYMBOL_GPL(amd_imc_exit_scratch_ram);
++
++/*
++* The PCI Device ID table below is used to identify the platform
++* the driver is supposed to work for. Since this is a platform
++* driver, we need a way for us to be able to find the correct
++* platform when the driver gets loaded, otherwise we should
++* bail out.
++*/
++static DEFINE_PCI_DEVICE_TABLE(amd_imc_pci_tbl) = {
++ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, PCI_ANY_ID,
++ PCI_ANY_ID, },
++ { 0, },
++};
++
++static int amd_imc_init(struct platform_device *pdev)
++{
++ struct pci_dev *dev = NULL;
++ static u32 imc_strap_status_phys;
++ void __iomem *imcstrapstatus;
++ u32 val;
++ u8 *byte;
++
++ /* Match the PCI device */
++ for_each_pci_dev(dev) {
++ if (pci_match_id(amd_imc_pci_tbl, dev) != NULL) {
++ amd_imc_pci = dev;
++ break;
++ }
++ }
++
++ if (!amd_imc_pci)
++ return -ENODEV;
++
++ /* Locate ACPI MMIO Base Address. */
++ byte = (u8 *)&val;
++
++ outb(AMD_PM_ACPI_MMIO_BASE0, AMD_IO_PM_INDEX_REG);
++ byte[0] = inb(AMD_IO_PM_DATA_REG);
++ outb(AMD_PM_ACPI_MMIO_BASE1, AMD_IO_PM_INDEX_REG);
++ byte[1] = inb(AMD_IO_PM_DATA_REG);
++ outb(AMD_PM_ACPI_MMIO_BASE2, AMD_IO_PM_INDEX_REG);
++ byte[2] = inb(AMD_IO_PM_DATA_REG);
++ outb(AMD_PM_ACPI_MMIO_BASE3, AMD_IO_PM_INDEX_REG);
++ byte[3] = inb(AMD_IO_PM_DATA_REG);
++
++ /* Bits 31:13 is the actual ACPI MMIO Base Address */
++ val &= AMD_ACPI_MMIO_ADDR_MASK;
++
++ /* IMCStrapStatus is located at ACPI MMIO Base Address + 0xE80 */
++ if (!request_mem_region_exclusive(val + AMD_IMC_STRAP_STATUS_OFFSET,
++ AMD_IMC_STRAP_STATUS_SIZE, "IMC Strap Status")) {
++ pr_err("amd_imc: MMIO address 0x%04x already in use\n",
++ val + AMD_IMC_STRAP_STATUS_OFFSET);
++ goto exit;
++ }
++
++ imc_strap_status_phys = val + AMD_IMC_STRAP_STATUS_OFFSET;
++
++ imcstrapstatus = ioremap(imc_strap_status_phys,
++ AMD_IMC_STRAP_STATUS_SIZE);
++ if (!imcstrapstatus) {
++ pr_err("amd_imc: failed to get IMC Strap Status address\n");
++ goto unreg_imc_region;
++ }
++
++ /* Check if IMC is enabled */
++ val = ioread32(imcstrapstatus);
++ if ((val & AMD_IMC_ENABLED) == AMD_IMC_ENABLED) {
++ struct pci_dev *pdev = NULL;
++
++ pr_info("amd_imc: IMC is enabled\n");
++ imc_enabled = 1;
++
++ /*
++ * In case IMC is enabled, we need to find the IMC port address
++ * which will be used to send messages to the IMC. The IMC port
++ * address is stored in bits 1:15 of PCI device 20, function 3,
++ * offset 0xA4. PCI device 20, function 3 is actually the LPC
++ * ISA bridge.
++ */
++ for_each_pci_dev(pdev) {
++ if (pci_match_id(amd_lpc_pci_tbl, pdev) != NULL)
++ break;
++ }
++
++ /* Match found. Get the IMC port address */
++ if (pdev) {
++ pci_read_config_word(pdev, AMD_PCI_IMC_PORT_ADDR_REG,
++ &imc_port_addr);
++
++ /* The actual IMC port address has bit 0 masked out */
++ imc_port_addr &= ~AMD_IMC_PORT_ACTIVE;
++ }
++
++ /* Put device into configuration state */
++ outb(AMD_DEVICE_ENTER_CONFIG_STATE, imc_port_addr +
++ AMD_IMC_INDEX_REG_OFFSET);
++
++ /* Select logical device number 9 */
++ outb(AMD_SET_LOGICAL_DEVICE, imc_port_addr +
++ AMD_IMC_INDEX_REG_OFFSET);
++ outb(AMD_SET_DEVICE_9, imc_port_addr +
++ AMD_IMC_DATA_REG_OFFSET);
++
++ /* read high byte of message register base address */
++ outb(AMD_MSG_REG_HIGH, imc_port_addr +
++ AMD_IMC_INDEX_REG_OFFSET);
++ msg_reg_base_hi = inb(imc_port_addr + AMD_IMC_DATA_REG_OFFSET);
++
++ /* read low byte of message register base address */
++ outb(AMD_MSG_REG_LOW, imc_port_addr +
++ AMD_IMC_INDEX_REG_OFFSET);
++ msg_reg_base_lo = inb(imc_port_addr + AMD_IMC_DATA_REG_OFFSET);
++
++ msg_reg_base = msg_reg_base_lo | (msg_reg_base_hi << 8);
++
++ /* Get device out of configuration state */
++ outb(AMD_DEVICE_EXIT_CONFIG_STATE, imc_port_addr +
++ AMD_IMC_INDEX_REG_OFFSET);
++ } else {
++ pr_info("amd_imc: IMC is disabled\n");
++ imc_enabled = 0;
++ }
++
++ /* Release the region occupied by IMC Strap Status register */
++ iounmap(imcstrapstatus);
++ release_mem_region(imc_strap_status_phys, AMD_IMC_STRAP_STATUS_SIZE);
++
++ return 0;
++
++unreg_imc_region:
++ release_mem_region(imc_strap_status_phys, AMD_IMC_STRAP_STATUS_SIZE);
++exit:
++ return -ENODEV;
++}
++
++static struct platform_driver amd_imc_driver = {
++ .probe = amd_imc_init,
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = IMC_MODULE_NAME,
++ },
++};
++
++static int __init amd_imc_init_module(void)
++{
++ int err;
++
++ pr_info("AMD IMC Driver v%s\n", IMC_VERSION);
++
++ err = platform_driver_register(&amd_imc_driver);
++ if (err)
++ return err;
++
++ amd_imc_platform_device = platform_device_register_simple(
++ IMC_MODULE_NAME, -1, NULL, 0);
++ if (IS_ERR(amd_imc_platform_device)) {
++ err = PTR_ERR(amd_imc_platform_device);
++ goto unreg_platform_driver;
++ }
++
++ return 0;
++
++unreg_platform_driver:
++ platform_driver_unregister(&amd_imc_driver);
++ return err;
++}
++
++static void __exit amd_imc_cleanup_module(void)
++{
++ platform_device_unregister(amd_imc_platform_device);
++ platform_driver_unregister(&amd_imc_driver);
++ pr_info("AMD IMC Module Unloaded\n");
++}
++
++module_init(amd_imc_init_module);
++module_exit(amd_imc_cleanup_module);
++
++MODULE_AUTHOR("Arindam Nath <arindam.nath@amd.com>");
++MODULE_DESCRIPTION("AMD IMC driver");
++MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/include/linux/amd_imc.h b/include/linux/amd_imc.h
+new file mode 100644
+index 0000000..4b4b7b8
+--- /dev/null
++++ b/include/linux/amd_imc.h
+@@ -0,0 +1,68 @@
++#ifndef _AMD_IMC_H_
++#define _AMD_IMC_H_
++
++/* Module and version information */
++#define IMC_VERSION "0.1"
++#define IMC_MODULE_NAME "AMD IMC"
++#define IMC_DRIVER_NAME IMC_MODULE_NAME ", v" IMC_VERSION
++
++#define DRV_NAME "amd_imc"
++
++/* IO port address for indirect access using the ACPI PM registers */
++#define AMD_IO_PM_INDEX_REG 0xCD6
++#define AMD_IO_PM_DATA_REG 0xCD7
++
++#define AMD_PM_ACPI_MMIO_BASE0 0x24
++#define AMD_PM_ACPI_MMIO_BASE1 0x25
++#define AMD_PM_ACPI_MMIO_BASE2 0x26
++#define AMD_PM_ACPI_MMIO_BASE3 0x27
++
++#define AMD_ACPI_MMIO_ADDR_MASK ~0x1FFF
++
++/* Offset of IMC Strap Status register in the ACPI MMIO region */
++#define AMD_IMC_STRAP_STATUS_OFFSET 0xE80
++ #define AMD_IMC_ENABLED 0x4
++#define AMD_IMC_STRAP_STATUS_SIZE 4
++
++#define PCI_DEVICE_ID_AMD_LPC_BRIDGE 0x780E
++ #define AMD_PCI_IMC_PORT_ADDR_REG 0xA4
++ #define AMD_IMC_PORT_ACTIVE 0x0001
++
++/* Device configuration state fields */
++#define AMD_DEVICE_ENTER_CONFIG_STATE 0x5A
++#define AMD_DEVICE_EXIT_CONFIG_STATE 0xA5
++
++/* Global configuration registers */
++#define AMD_SET_LOGICAL_DEVICE 0x07
++ #define AMD_SET_DEVICE_9 0x09
++#define AMD_MSG_REG_HIGH 0x60
++#define AMD_MSG_REG_LOW 0x61
++
++/* IMC index and data port offsets for indirect access */
++#define AMD_IMC_INDEX_REG_OFFSET 0x00
++#define AMD_IMC_DATA_REG_OFFSET 0x01
++
++/* Message register index and data port offsets for indirect access */
++#define AMD_MSG_INDEX_REG_OFFSET 0x00
++#define AMD_MSG_DATA_REG_OFFSET 0x01
++
++/* IMC message registers */
++#define AMD_MSG_SYS_TO_IMC 0x80
++ #define AMD_IMC_ROM_OWNERSHIP_SEM 0x96
++#define AMD_MSG_REG0 0x82
++ #define AMD_IMC_FUNC_NOT_SUPP 0x00
++ #define AMD_IMC_FUNC_COMPLETED 0xFA
++#define AMD_MSG_REG1 0x83
++ #define AMD_IMC_ENTER_SCRATCH_RAM 0xB4
++ #define AMD_IMC_EXIT_SCRATCH_RAM 0xB5
++
++/* Extern functions */
++#ifdef CONFIG_AMD_IMC
++extern void amd_imc_enter_scratch_ram(void);
++extern void amd_imc_exit_scratch_ram(void);
++#else
++void amd_imc_enter_scratch_ram(void) {}
++void amd_imc_exit_scratch_ram(void) {}
++#endif
++
++#endif /* _AMD_IMC_H_ */
+--
+1.9.1
+
diff --git a/meta-baldeagle/recipes-kernel/linux/linux-yocto/0047-yocto-poky-dora-10.0.0-amd-i2c-dev-add-calls-to-enable-and-disable-IMC-from-fetching-BIOS-code.patch b/meta-baldeagle/recipes-kernel/linux/linux-yocto/0047-yocto-poky-dora-10.0.0-amd-i2c-dev-add-calls-to-enable-and-disable-IMC-from-fetching-BIOS-code.patch
new file mode 100644
index 00000000..6287c826
--- /dev/null
+++ b/meta-baldeagle/recipes-kernel/linux/linux-yocto/0047-yocto-poky-dora-10.0.0-amd-i2c-dev-add-calls-to-enable-and-disable-IMC-from-fetching-BIOS-code.patch
@@ -0,0 +1,51 @@
+From 38595e633e5a1237bdea9cb0aa9193aea40542a8 Mon Sep 17 00:00:00 2001
+From: Arindam Nath <arindam.nath@amd.com>
+Date: Mon, 4 Aug 2014 19:21:44 +0530
+Subject: [PATCH 2/2] yocto: amd: i2c-dev: add calls to enable and disable IMC
+ from fetching BIOS code
+
+The patch adds support to disable IMC from fetching BIOS code when
+we first open the SMBus device. We can perform SMBus transaction
+safely once IMC is disabled. Then when we close the device after
+the operation, we enable IMC to start fetching from BIOS ROM again.
+
+Upstream Status: None
+
+Signed-off-by: Arindam Nath <arindam.nath@amd.com>
+---
+ drivers/i2c/i2c-dev.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
+index c3ccdea..c92ec4c 100644
+--- a/drivers/i2c/i2c-dev.c
++++ b/drivers/i2c/i2c-dev.c
+@@ -39,6 +39,7 @@
+ #include <linux/i2c-dev.h>
+ #include <linux/jiffies.h>
+ #include <linux/uaccess.h>
++#include <linux/amd_imc.h>
+
+ /*
+ * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
+@@ -512,6 +513,8 @@ static int i2cdev_open(struct inode *inode, struct file *file)
+ client->adapter = adap;
+ file->private_data = client;
+
++ amd_imc_enter_scratch_ram();
++
+ return 0;
+ }
+
+@@ -523,6 +526,8 @@ static int i2cdev_release(struct inode *inode, struct file *file)
+ kfree(client);
+ file->private_data = NULL;
+
++ amd_imc_exit_scratch_ram();
++
+ return 0;
+ }
+
+--
+1.9.1
+
diff --git a/meta-baldeagle/recipes-kernel/linux/linux-yocto/defconfig b/meta-baldeagle/recipes-kernel/linux/linux-yocto/defconfig
index fef542cd..177c63c9 100644
--- a/meta-baldeagle/recipes-kernel/linux/linux-yocto/defconfig
+++ b/meta-baldeagle/recipes-kernel/linux/linux-yocto/defconfig
@@ -3454,7 +3454,61 @@ CONFIG_VIRTIO_MMIO=y
#
# Microsoft Hyper-V guest support
#
-# CONFIG_STAGING is not set
+CONFIG_STAGING=y
+# CONFIG_ET131X is not set
+# CONFIG_SLICOSS is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_W35UND is not set
+# CONFIG_PRISM2_USB is not set
+# CONFIG_ECHO is not set
+# CONFIG_COMEDI is not set
+# CONFIG_PANEL is not set
+# CONFIG_R8187SE is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_R8712U is not set
+# CONFIG_R8188EU is not set
+# CONFIG_RTS5139 is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_IDE_PHISON is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_DX_SEP is not set
+# CONFIG_ZSMALLOC is not set
+# CONFIG_FB_SM7XX is not set
+# CONFIG_CRYSTALHD is not set
+# CONFIG_FB_XGI is not set
+# CONFIG_ACPI_QUICKSTART is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_FT1000 is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_STAGING_MEDIA is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID is not set
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_WIMAX_GDM72XX is not set
+# CONFIG_LTE_GDM724X is not set
+# CONFIG_NET_VENDOR_SILICOM is not set
+# CONFIG_CED1401 is not set
+# CONFIG_DGRP is not set
+# CONFIG_USB_DWC2 is not set
+# CONFIG_LUSTRE_FS is not set
+# CONFIG_XILLYBUS is not set
+# CONFIG_DGNC is not set
+# CONFIG_DGAP is not set
+CONFIG_AMD_IMC=y
CONFIG_X86_PLATFORM_DEVICES=y
# CONFIG_ACERHDF is not set
# CONFIG_ASUS_LAPTOP is not set
@@ -3595,6 +3649,7 @@ CONFIG_BTRFS_FS_POSIX_ACL=y
# CONFIG_BTRFS_ASSERT is not set
# CONFIG_NILFS2_FS is not set
CONFIG_FS_POSIX_ACL=y
+# CONFIG_EXPORTFS is not set
CONFIG_FILE_LOCKING=y
CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
diff --git a/meta-baldeagle/recipes-kernel/linux/linux-yocto_3.12.bb b/meta-baldeagle/recipes-kernel/linux/linux-yocto_3.12.bb
index 7d895ef2..bcb9692e 100644
--- a/meta-baldeagle/recipes-kernel/linux/linux-yocto_3.12.bb
+++ b/meta-baldeagle/recipes-kernel/linux/linux-yocto_3.12.bb
@@ -53,7 +53,9 @@ SRC_URI = "http://git.yoctoproject.org/cgit/cgit.cgi/linux-yocto-dev/snapshot/li
file://0042-yocto-poky-dora-10.0.0-amd-drm-radeon-cik-enable-disable-vce-cg-when-encoding.patch \
file://0043-yocto-poky-dora-10.0.0-amd-drm-radeon-fix-CP-semaphores-on-CIK.patch \
file://0044-yocto-poky-dora-10.0.0-amd-drm-radeon-disable-dynamic-powering-vce.patch \
- file://0045-yocto-poky-dora-10.0.0-amd-clear-exceptions-in-AMD-FXSAVE-workaround.patch"
+ file://0045-yocto-poky-dora-10.0.0-amd-clear-exceptions-in-AMD-FXSAVE-workaround.patch \
+ file://0046-yocto-poky-dora-10.0.0-amd-staging-add-support-to-enable-and-disable-IMC-to-fetch-BIOS-code.patch \
+ file://0047-yocto-poky-dora-10.0.0-amd-i2c-dev-add-calls-to-enable-and-disable-IMC-from-fetching-BIOS-code.patch"
S = "${WORKDIR}/linux-yocto-dev-${PV}"
diff --git a/meta-steppeeagle/recipes-applications/spi-test/files/spirom-test.c b/meta-steppeeagle/recipes-applications/spi-test/files/spirom-test.c
index 1c48f7c4..9006c130 100644
--- a/meta-steppeeagle/recipes-applications/spi-test/files/spirom-test.c
+++ b/meta-steppeeagle/recipes-applications/spi-test/files/spirom-test.c
@@ -31,38 +31,34 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
-#include <getopt.h>
#include <fcntl.h>
#include <string.h>
+#include <dirent.h>
+#include <signal.h>
+
+#include <sys/types.h>
#include <sys/ioctl.h>
-#include <linux/types.h>
+#include <sys/stat.h>
+
+#include <readline/readline.h>
#include "spirom.h"
-#define SPI_APP_VERSION "0.1"
+#define SPI_APP_VERSION "1.0"
-#define WREN 0x06
-#define WRDI 0x04
-#define RDSR 0x05
-#define RDID 0x9F
-#define CHIP_ERASE 0x60
-#define SECTOR_ERASE 0x20
-#define BLOCK_ERASE 0xD8
-#define READ 0x03
-#define WRITE 0x02
+static int device_opened = 0;
+static char filename[20];
+static int fd = -1;
-static void pabort(const char *s)
+char *show_prompt(void)
{
- perror(s);
- abort();
+ return "$ ";
}
-static const char *device = "/dev/spirom0.0";
-static char command[20];
-static int inputfile_fd;
-static int outfile_fd;;
-static unsigned long address;
-static unsigned int num_bytes;
+void sighandler(int sig)
+{
+ /* Do nothing. That is the idea. */
+}
void show_license(void)
{
@@ -97,162 +93,302 @@ void show_license(void)
"***************************************************************************/\n");
}
-void parse_command(int fd)
+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)
{
- uint8_t cmd_byte;
struct spi_ioc_transfer tr;
unsigned int bytes_chunks;
unsigned int remaining_bytes;
+ int addr;
int ret;
- /* Zero initialize spi_ioc_transfer */
- memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- if ((strncmp(command, "WREN", 4) == 0) ||
- (strncmp(command, "wren", 4) == 0)) {
- /* Command without data */
- tr.buf[0] = WREN;
+ 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)
- pabort("can't send spi message");
- } else if ((strncmp(command, "WRDI", 4) == 0) ||
- (strncmp(command, "wrdi", 4) == 0)) {
- /* Command without data */
- tr.buf[0] = WRDI;
+ 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)
- pabort("can't send spi message");
- } else if ((strncmp(command, "CHIPERASE", 4) == 0) ||
- (strncmp(command, "chiperase", 4) == 0)) {
+ 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] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");;
+ return;
+ } else if ((tr.buf[1] & 0x02) == 0x00) {
+ printf("\nCannot execute RDSR command, write is disabled\n\n");
+ return;
}
/* Command without data */
- tr.buf[0] = CHIP_ERASE;
+ 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)
- pabort("can't send spi message");
+ 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] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
- } else if ((strncmp(command, "RDSR", 4) == 0) ||
- (strncmp(command, "rdsr", 4) == 0)) {
+
+ 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] = RDSR;
+ 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)
- pabort("can't send spi message");
+ 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("command: 0x%.2x response: 0x%.2x\n", tr.buf[0],
- tr.buf[1]);
- } else if ((strncmp(command, "RDID", 4) == 0) ||
- (strncmp(command, "rdid", 4) == 0)) {
+ 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] = RDID;
+ 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)
- pabort("can't send spi message");
+ 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("command: 0x%.2x response: 0x%.2x%.2x%.2x\n", tr.buf[0],
- tr.buf[1], tr.buf[2], tr.buf[3]);
- } else if ((strncmp(command, "SECTORERASE", 6) ==0) ||
- (strncmp(command, "sectorerase", 6) ==0)) {
+ 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;
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ 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;
}
- /*
- * num_bytes here is a little bit of misnomer, it indicates the
- * number of sectors to be erased, rather than the number of
- * bytes to be erased.
- */
- for (i = 0; i < num_bytes; i++) {
+ 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] = WREN;
+ 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)
- pabort("can't send spi message");
+ 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] = SECTOR_ERASE;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing SECTORERASE command\n\n");
+ return;
+ }
- /* point to the next 4k block */
- address += 4 * 1024;
+ /* point to the next 4k sector */
+ addr += 4 * 1024;
/*
* Before the next loop, we need to make sure that WIP
@@ -260,66 +396,86 @@ void parse_command(int fd)
*/
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
}
- } else if ((strncmp(command, "BLOCKERASE", 5) == 0) ||
- (strncmp(command, "blockerase", 5) == 0)) {
+
+ printf("\n\n...SECTORERASE completed successfully\n\n");
+ } else if (strncmp(cmdline, "blockerase", 10) == 0) {
+ int nblocks;
int i;
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ 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;
}
- /*
- * num_bytes indicates the number of blocks to be erased,
- * rather than the number of bytes to be erased.
- */
- for (i = 0; i < num_bytes; i++) {
+ 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] = WREN;
+ 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)
- pabort("can't send spi message");
+ 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] = BLOCK_ERASE;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing BLOCKERASE command\n\n");
+ return;
+ }
/* point to the next 64k block */
- address += 64 * 1024;
+ addr += 64 * 1024;
/*
* Before the next loop, we need to make sure that WIP
@@ -327,138 +483,205 @@ void parse_command(int fd)
*/
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
}
- } else if ((strncmp(command, "READ", 4) == 0) ||
- (strncmp(command, "read", 4) ==0)) {
+
+ 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 <64. We
+ * of 4-bytes. Data might not be a even multiple of 4. So
+ * in that case, we will have some remaining bytes <4. We
* handle that separately.
*/
- bytes_chunks = num_bytes / 64;
- remaining_bytes = num_bytes % 64;
+ bytes_chunks = nbytes / 4;
+ remaining_bytes = nbytes % 4;
+
+ 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] = READ;
+ tr.buf[0] = ROM_READ;
tr.direction = RECEIVE;
/*
* We will store the address into the buffer in little
* endian order.
*/
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
- tr.len = 64;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.len = 4;
tr.addr_present = 1;
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
- if (ret < 1)
- pabort("can't send spi message");
+ 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) {
- perror("write error");
- exit(1);
+ printf("\nError writing to file %s\n\n", filename);
+ return;
}
- address += 64;
+ addr += 4;
}
if (remaining_bytes) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = READ;
+ tr.buf[0] = ROM_READ;
tr.direction = RECEIVE;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing READ command\n\n");
+ return;
+ }
if (write(outfile_fd, &tr.buf[4], tr.len) < 0) {
- perror("write error");
- exit(1);
+ printf("\nError writing to file %s\n\n", filename);
+ return;
}
}
- } else if ((strncmp(command, "WRITE", 5) == 0) ||
- (strncmp(command, "write", 5) ==0)) {
+
+ 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
+ * of 4-bytes. Like for read, we might not have data in an
+ * even multiple of 4 bytes. So we will handle the remaining
* bytes in the end.
*/
-
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
- else if ((tr.buf[1] & 0x02) == 0x00) {
- printf("cannot execute command, write is disabled\n");
- exit(1);
+ 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 = num_bytes / 64;
- remaining_bytes = num_bytes % 64;
+ bytes_chunks = nbytes / 4;
+ remaining_bytes = nbytes % 4;
+
+ printf("\n\nWRITE operation in progress, please do not "
+ " stop in between.\n\n");
for (i = 0; i < bytes_chunks; i++) {
- tr.buf[0] = WREN;
+ 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)
- pabort("can't send spi message");
+ 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] = WRITE;
+ tr.buf[0] = ROM_WRITE;
tr.direction = TRANSMIT;
/*
* We will store the address into the buffer in little
* endian order.
*/
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
- tr.len = 64;
+ tr.buf[3] = addr & 0xff;
+ tr.buf[2] = (addr >> 8) & 0xff;
+ tr.buf[1] = (addr >> 16) & 0xff;
+ tr.len = 4;
tr.addr_present = 1;
- /* Read 64 bytes from inputfile to buffer */
- if (read(inputfile_fd, &tr.buf[4], tr.len) < 0) {
- perror("read error");
- exit(1);
+ /* Read 4 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing WRITE command\n\n");
+ return;
+ }
- address += 64;
+ addr += 4;
/*
* Before the next loop, we need to make sure that WIP
@@ -466,14 +689,16 @@ void parse_command(int fd)
*/
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
@@ -481,161 +706,93 @@ void parse_command(int fd)
}
if (remaining_bytes) {
- tr.buf[0] = WREN;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing WREN command\n\n");
+ return;
+ }
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = WRITE;
+ tr.buf[0] = ROM_WRITE;
tr.direction = TRANSMIT;
- tr.buf[3] = address & 0xff;
- tr.buf[2] = (address >> 8) & 0xff;
- tr.buf[1] = (address >> 16) & 0xff;
+ 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(inputfile_fd, &tr.buf[4], tr.len) < 0) {
- perror("read error");
- exit(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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing WRITE command\n\n");
+ return;
+ }
while (1) {
memset(&tr, 0, sizeof(struct spi_ioc_transfer));
- tr.buf[0] = RDSR;
+ 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)
- pabort("can't send spi message");
+ if (ret < 1) {
+ printf("\nError executing RDSR command\n\n");
+ return;
+ }
if ((tr.buf[1] & 0x01) == 0x00)
break;
}
}
- } else
- pabort("Unrecognized command, please try again.\n");
-}
-
-static void print_usage(const char *prog)
-{
- printf("\nUsage: sudo %s [-DCAnio] [arguments]\n\n", prog);
- puts(" -D --device SPI ROM device to use\n"
- " (default /dev/spirom0.0)\n\n"
- " -C --command command to send to the device\n"
- " (WREN/WRDI/RDSR/RDID/CHIPERASE/SECTORERASE/\n"
- " BLOCKERASE/READ/WRITE)\n\n"
- " -A --address offset in decimal, into the device to read\n"
- " from or write to. For a ROM size of 8MB,\n"
- " address can go from 0 to 8388608. Negative\n"
- " offsets are not valid, but the program\n"
- " won't complain and convert it to its\n"
- " unsigned equivalent.\n\n"
- " -n --num-bytes number of bytes to be read from or written\n"
- " to. Depending on the address, this can\n"
- " take values from 0 to 8388608 for a ROM\n"
- " size of 8MB.\n\n"
- " In case of SECTORERASE and BLOCKERASE\n"
- " commands, num-bytes actually takes the\n"
- " number of sectors and blocks to be erased\n"
- " respectively, rather than the number of\n"
- " bytes.\n\n"
- " -i --input-file file to be used as input.\n\n"
- " -o --output-file file to be used for output. Remember that if\n"
- " an existing filename is given, its contents\n"
- " will be overwritten.\n"
- " -l --license displays the terms of LICENSE for this application\n\n");
- exit(1);
-}
-
-static void parse_opts(int argc, char *argv[])
-{
- if (argc == 1)
- print_usage(argv[0]);
- while (1) {
- static const struct option lopts[] = {
- { "device", 1, 0, 'D' },
- { "command", 1, 0, 'C' },
- { "address", 1, 0, 'A' },
- { "num-bytes", 1, 0, 'n' },
- { "input-file", 1, 0, 'i' },
- { "output-file", 1, 0, 'o' },
- { "license", 0, 0, 'l' },
- { NULL, 0, 0, 0 },
- };
- int c;
-
- c = getopt_long(argc, argv, "D:C:A:n:i:o:l", lopts, NULL);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'D':
- device = optarg;
- break;
- case 'C':
- memset(command, sizeof(command), 0);
- strncpy(command, optarg, sizeof(command));
- break;
- case 'A':
- address = atol(optarg);
- break;
- case 'n':
- num_bytes = atoi(optarg);
- break;
- case 'i':
- inputfile_fd = open(optarg, O_RDONLY);
- if (inputfile_fd < 0) {
- printf("Error opening %s\n", optarg);
- exit(1);
- }
- break;
- case 'o':
- outfile_fd = open(optarg, O_WRONLY | O_CREAT |
- O_TRUNC, 0644);
- if(outfile_fd < 0) {
- printf("Error opening %s\n", optarg);
- exit(1);
- }
- break;
- case 'l':
- show_license();
- exit(0);;
- default:
- print_usage(argv[0]);
- 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(int argc, char *argv[])
+int main(void)
{
- int ret = 0;
- int fd;
+ 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");
+ "under certain conditions; type `license` for details.\n\n");
- parse_opts(argc, argv);
+ /* Set the signal handler */
+ signal(SIGINT, sighandler);
- fd = open(device, O_RDWR);
- if (fd < 0)
- pabort("can't open device");
+ while (1) {
+ cmdline = readline(show_prompt());
+ parse_cmd(cmdline);
+ /* Free the memory malloc'ed by readline */
+ free(cmdline);
+ }
- parse_command(fd);
+ /* Restore the default signal handler */
+ signal(SIGINT, SIG_DFL);
- return ret;
+ /* Should never reach here */
+ return 0;
}
diff --git a/meta-steppeeagle/recipes-applications/spi-test/files/spirom.h b/meta-steppeeagle/recipes-applications/spi-test/files/spirom.h
index 750719a6..941b357a 100644
--- a/meta-steppeeagle/recipes-applications/spi-test/files/spirom.h
+++ b/meta-steppeeagle/recipes-applications/spi-test/files/spirom.h
@@ -39,5 +39,15 @@ struct spi_ioc_transfer {
? ((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-steppeeagle/recipes-applications/spi-test/spi-test_1.0.bb b/meta-steppeeagle/recipes-applications/spi-test/spi-test_1.0.bb
index 83593cb4..b374d9f8 100644
--- a/meta-steppeeagle/recipes-applications/spi-test/spi-test_1.0.bb
+++ b/meta-steppeeagle/recipes-applications/spi-test/spi-test_1.0.bb
@@ -2,8 +2,8 @@ DESCRIPTION = "Sample application for AMD SPI driver"
SECTION = "applications"
LICENSE = "BSD"
DEPENDS = "readline"
-LIC_FILES_CHKSUM = "file://spirom-test.c;md5=c6d80587d583668ffbfb5828abd58878 \
- file://spirom.h;md5=56f117ed31b82b02182c7a491364d112 \
+LIC_FILES_CHKSUM = "file://spirom-test.c;md5=3065341fac5fc1255711c219f00f7324 \
+ file://spirom.h;md5=8de0c535224dbd8ecd2f40ef29c15d0a \
"
PR = "r1"
diff --git a/meta-steppeeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb b/meta-steppeeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb
index f4304d4d..608b99c6 100644
--- a/meta-steppeeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb
+++ b/meta-steppeeagle/recipes-kernel/amd-spi/amd-spi_1.0.bb
@@ -1,9 +1,9 @@
DESCRIPTION = "This kernel module provides support for AMD SPI controller driver"
LICENSE = "BSD | GPLv2"
-LIC_FILES_CHKSUM = "file://spi_amd.c;md5=3cbc6410f1e2b6009f1a74731f6fc557 \
- file://spi_amd.h;md5=2233c2a926f120b07153e3ea0ba7474f \
+LIC_FILES_CHKSUM = "file://spi_amd.c;md5=053ef6a02a8242fbb536a45df556c7a7 \
+ file://spi_amd.h;md5=b73106fb4d18369d420b9de1d1406b3a \
file://spirom.c;md5=1f5bba5ab39fb0759286aab09b55bc84 \
- file://spirom.h;md5=56f117ed31b82b02182c7a491364d112 \
+ file://spirom.h;md5=8de0c535224dbd8ecd2f40ef29c15d0a \
file://Makefile;md5=8ea80a6d4ae15bcf922d090df6cfdd4c \
"
diff --git a/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.c b/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.c
index 554bd352..52e1b1a5 100644
--- a/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.c
+++ b/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.c
@@ -45,9 +45,9 @@ struct amd_spi {
u32 rom_addr;
struct spi_master *master;
struct amd_platform_data controller_data;
- spinlock_t lock;
struct task_struct *kthread_spi;
struct list_head msg_queue;
+ wait_queue_head_t wq;
};
static struct pci_device_id amd_spi_pci_device_id[] = {
@@ -149,7 +149,9 @@ static void amd_spi_execute_opcode(struct spi_master *master)
spi_busy = (ioread32((u8 *)amd_spi->io_remap_addr +
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
while (spi_busy) {
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
+ set_current_state(TASK_RUNNING);
spi_busy = (ioread32((u8 *)amd_spi->io_remap_addr +
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
}
@@ -193,29 +195,17 @@ static int amd_spi_master_setup(struct spi_device *spi)
return 0;
}
-static int amd_spi_master_transfer(struct spi_device *spi,
+static int amd_spi_master_transfer(struct spi_master *master,
struct spi_message *msg)
{
- struct spi_master *master = spi->master;
struct amd_spi *amd_spi = spi_master_get_devdata(master);
/*
- * We will just add this message to the message queue set up by
- * the controller, and let the kernel thread handle it later.
- */
- msg->status = -EINPROGRESS;
- msg->actual_length = 0;
- msg->spi = spi;
- /*
- * There could be a situation when we are running on this processor
- * and trying to add element to the end of the message queue, but
- * at the same time the kernel thread is running on another processor
- * and trying to find out if the list is empty or not. So protect
- * against such contention. Simple spin_lock() should do.
+ * Add new message to the queue and let the kernel thread know
+ * about it.
*/
- spin_lock(&amd_spi->lock);
list_add_tail(&msg->queue, &amd_spi->msg_queue);
- spin_unlock(&amd_spi->lock);
+ wake_up_interruptible(&amd_spi->wq);
return 0;
}
@@ -241,25 +231,19 @@ static int amd_spi_thread(void *t)
* 64-bytes of data and 3-bytes of address.
*/
while (1) {
- /* break condition */
+ /*
+ * Let us wait on a wait queue till the message queue is empty.
+ */
+ wait_event_interruptible(amd_spi->wq,
+ !list_empty(&amd_spi->msg_queue));
+
+ /* stop condition */
if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
break;
}
/*
- * If the message queue is empty, then there is no need to waste
- * CPU cycles. So we let other processes execute, and continue
- * from the beginning of the loop when we next get to run.
- */
- spin_lock(&amd_spi->lock);
- if (list_empty(&amd_spi->msg_queue)) {
- spin_unlock(&amd_spi->lock);
- schedule();
- continue;
- }
-
- /*
* Else, pull the very first message from the queue and process
* all transfers within that message. And process the messages
* in a pure linear fashion. We also remove the spi_message
@@ -268,7 +252,6 @@ static int amd_spi_thread(void *t)
message = list_entry(amd_spi->msg_queue.next,
struct spi_message, queue);
list_del_init(&message->queue);
- spin_unlock(&amd_spi->lock);
/* We store the CS# line to be used for this spi_message */
amd_spi->controller_data.chip_select =
@@ -372,7 +355,7 @@ static int amd_spi_thread(void *t)
message->actual_length = tx_len + rx_len + 1 ;
/* complete the transaction */
message->status = 0;
- message->complete(message->context);
+ spi_finalize_current_message(master);
}
return 0;
@@ -416,8 +399,8 @@ static int amd_spi_pci_probe(struct pci_dev *pdev,
}
dev_dbg(dev, "io_base_addr: 0x%.8lx, io_remap_address: %p\n",
amd_spi->io_base_addr, amd_spi->io_remap_addr);
- spin_lock_init(&amd_spi->lock);
INIT_LIST_HEAD(&amd_spi->msg_queue);
+ init_waitqueue_head(&amd_spi->wq);
amd_spi->kthread_spi = kthread_run(amd_spi_thread, amd_spi,
"amd_spi_thread");
@@ -430,7 +413,7 @@ static int amd_spi_pci_probe(struct pci_dev *pdev,
master->mode_bits = 0;
master->flags = 0;
master->setup = amd_spi_master_setup;
- master->transfer = amd_spi_master_transfer;
+ master->transfer_one_message = amd_spi_master_transfer;
/* Register the controller with SPI framework */
err = spi_register_master(master);
if (err) {
diff --git a/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.h b/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.h
index ea5181d7..21fa972f 100644
--- a/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.h
+++ b/meta-steppeeagle/recipes-kernel/amd-spi/files/spi_amd.h
@@ -2,7 +2,7 @@
#define SPI_AMD_H
#define DRIVER_NAME "spi_amd"
-#define SPI_VERSION "0.1"
+#define SPI_VERSION "1.0"
#define AMD_SPI_CTRL0_REG 0x00
#define AMD_SPI_EXEC_CMD (0x1 << 16)
diff --git a/meta-steppeeagle/recipes-kernel/amd-spi/files/spirom.h b/meta-steppeeagle/recipes-kernel/amd-spi/files/spirom.h
index 750719a6..941b357a 100644
--- a/meta-steppeeagle/recipes-kernel/amd-spi/files/spirom.h
+++ b/meta-steppeeagle/recipes-kernel/amd-spi/files/spirom.h
@@ -39,5 +39,15 @@ struct spi_ioc_transfer {
? ((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 */