From 437177b028e7fd39ddf81c22570fa13b6c22c565 Mon Sep 17 00:00:00 2001 From: Thomas Cort Date: Fri, 26 Jul 2013 19:44:52 -0400 Subject: [PATCH] i2c: increase BUFLEN/CMDLEN to 128, add page flag. 128 byte reads are much more common than 32 byte reads. The message passing + setup/teardown for a read is much more expensive, in terms of time, than the reading itself. A slightly bigger struct is well worth the time savings. This reduces read times for /dev/eeprom from 57 seconds per 4KB to 14 seconds. Additionally, make sending the page address in the eeprom driver and utility optional. This can save a little time when reading within the same page and allows support for smaller devices that don't support pages (example: chips containing EDID). Change-Id: Ie48087caee40c11fa241d1555fce9309ddd27b43 --- commands/eepromread/board_info.c | 12 +++--- commands/eepromread/eepromread.1 | 9 +++++ commands/eepromread/eepromread.c | 55 +++++++++++++++----------- commands/eepromread/eepromread.h | 4 +- drivers/cat24c256/cat24c256.c | 68 +++++++++++++++++++------------- include/minix/com.h | 1 + sys/dev/i2c/i2c_io.h | 4 +- 7 files changed, 94 insertions(+), 59 deletions(-) diff --git a/commands/eepromread/board_info.c b/commands/eepromread/board_info.c index 000086837..66d000baa 100644 --- a/commands/eepromread/board_info.c +++ b/commands/eepromread/board_info.c @@ -18,7 +18,7 @@ * In the future, this could be expanded to support cape EEPROMs. */ -static int board_info_beaglebone(int fd, i2c_addr_t address); +static int board_info_beaglebone(int fd, i2c_addr_t address, int flags); /* Memory Layout of the BeagleBone and BeagleBone Black EEPROM */ typedef struct beaglebone_info @@ -32,7 +32,7 @@ typedef struct beaglebone_info } beaglebone_info_t; static int -board_info_beaglebone(int fd, i2c_addr_t address) +board_info_beaglebone(int fd, i2c_addr_t address, int flags) { int r; int i, j; @@ -40,7 +40,7 @@ board_info_beaglebone(int fd, i2c_addr_t address) beaglebone_info_t boneinfo; r = eeprom_read(fd, address, 0x0000, &boneinfo, - sizeof(beaglebone_info_t)); + sizeof(beaglebone_info_t), flags); if (r == -1) { fprintf(stderr, "Failed to read BeagleBone info r=%d\n", r); return -1; @@ -65,12 +65,12 @@ board_info_beaglebone(int fd, i2c_addr_t address) } int -board_info(int fd, i2c_addr_t address) +board_info(int fd, i2c_addr_t address, int flags) { int r; uint8_t magic_number[4]; - r = eeprom_read(fd, address, 0x0000, &magic_number, 4); + r = eeprom_read(fd, address, 0x0000, &magic_number, 4, flags); if (r == -1) { printf("%-16s: %s\n", "BOARD_NAME", "UNKNOWN"); return 0; @@ -78,7 +78,7 @@ board_info(int fd, i2c_addr_t address) if (magic_number[0] == 0xaa && magic_number[1] == 0x55 && magic_number[2] == 0x33 && magic_number[3] == 0xee) { - board_info_beaglebone(fd, address); + board_info_beaglebone(fd, address, flags); } else { printf("%-16s: %s\n", "BOARD_NAME", "UNKNOWN"); } diff --git a/commands/eepromread/eepromread.1 b/commands/eepromread/eepromread.1 index a3bbfc91d..53115ac99 100644 --- a/commands/eepromread/eepromread.1 +++ b/commands/eepromread/eepromread.1 @@ -3,6 +3,7 @@ eepromread \- read data from an EEPROM .SH SYNOPSIS \fBeepromread\fR [\fB\-i\fR] [\fB\-f\fR \fIdev\fR] [\fB\-a\fR \fIslave_addr\fR] +[\fB\-n\fR] .br .de FL .TP @@ -24,6 +25,11 @@ eepromread \- read data from an EEPROM .TP 5 .B \-a # Use \fIslave_address\fR instead of \fI0x50\fR. +.TP 5 +.B \-n +# Do not send the page number when addressing the memory on the EEPROM. Some +smaller EEPROM chips aren't organized into pages and get confused if a page +number is sent with the memory address. Use this when reading EDID. .SH EXAMPLES .TP 20 .B eepromread -i @@ -34,6 +40,9 @@ eepromread \- read data from an EEPROM .TP 20 .B eepromread -f /dev/i2c-3 -a 0x54 # display the first 256 bytes of the EEPROM on I2C bus 3, slave address 0x54. +.TP 20 +.B eepromread -f /dev/i2c-3 -n +# read the EDID info from the display on I2C bus 3 on the BeagleBoard-xM. .SH DESCRIPTION .PP \fIeepromread\fR is a simple tool for viewing the contents of an EEPROM. diff --git a/commands/eepromread/eepromread.c b/commands/eepromread/eepromread.c index 1d9e84f58..4ecee6bdc 100644 --- a/commands/eepromread/eepromread.c +++ b/commands/eepromread/eepromread.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -13,17 +14,17 @@ #include "eepromread.h" -static int __eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr, - void *buf, size_t buflen); -static int eeprom_dump(int fd, i2c_addr_t addr); +static int __eeprom_read128(int fd, i2c_addr_t addr, uint16_t memaddr, + void *buf, size_t buflen, int flags); +static int eeprom_dump(int fd, i2c_addr_t addr, int flags); #define DEFAULT_I2C_DEVICE "/dev/i2c-1" #define DEFAULT_I2C_ADDRESS 0x50 /* - * The /dev interface only supports 32 byte reads/writes and the EEPROM is - * larger, so to read the whole EEPROM, the task is broken down into 32 byte - * chunks in eeprom_read(). __eeprom_read32() does the actual ioctl() to do + * The /dev interface only supports 128 byte reads/writes and the EEPROM is + * larger, so to read the whole EEPROM, the task is broken down into 128 byte + * chunks in eeprom_read(). __eeprom_read128() does the actual ioctl() to do * the read. * * A future enhancement might be to add support for the /dev/eeprom interface @@ -33,8 +34,8 @@ static int eeprom_dump(int fd, i2c_addr_t addr); */ static int -__eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, - size_t buflen) +__eeprom_read128(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, + size_t buflen, int flags) { int r; minix_i2c_ioctl_exec_t ioctl_exec; @@ -51,10 +52,16 @@ __eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, ioctl_exec.iie_addr = addr; /* set the address to read from */ - ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff); - ioctl_exec.iie_cmd[1] = (memaddr & 0xff); - ioctl_exec.iie_cmdlen = 2; - + if ((BDEV_NOPAGE & flags) == BDEV_NOPAGE) { + /* reading within the current page */ + ioctl_exec.iie_cmd[0] = (memaddr & 0xff); + ioctl_exec.iie_cmdlen = 1; + } else { + /* reading from device with multiple pages */ + ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff); + ioctl_exec.iie_cmd[1] = (memaddr & 0xff); + ioctl_exec.iie_cmdlen = 2; + } ioctl_exec.iie_buflen = buflen; r = ioctl(fd, MINIX_I2C_IOCTL_EXEC, &ioctl_exec); @@ -70,7 +77,7 @@ __eeprom_read32(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, int eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, - size_t buflen) + size_t buflen, int flags) { int r; uint16_t i; @@ -80,10 +87,11 @@ eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, return -1; } - for (i = 0; i < buflen; i += 32) { - r = __eeprom_read32(fd, addr, memaddr + i, buf + i, - ((buflen - i) < 32) ? (buflen - i) : 32); + for (i = 0; i < buflen; i += 128) { + + r = __eeprom_read128(fd, addr, memaddr + i, buf + i, + ((buflen - i) < 128) ? (buflen - i) : 128, flags); if (r == -1) { return -1; } @@ -96,14 +104,14 @@ eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, * Read 256 bytes and print it to the screen in HEX and ASCII. */ static int -eeprom_dump(int fd, i2c_addr_t addr) +eeprom_dump(int fd, i2c_addr_t addr, int flags) { int i, j, r; uint8_t buf[256]; memset(buf, '\0', 256); - r = eeprom_read(fd, addr, 0x0000, buf, 256); + r = eeprom_read(fd, addr, 0x0000, buf, 256, flags); if (r == -1) { return r; } @@ -152,13 +160,13 @@ int main(int argc, char *argv[]) { int r, fd; - int ch, iflag = 0; + int ch, iflag = 0, read_flags = 0; char *device = DEFAULT_I2C_DEVICE; i2c_addr_t address = DEFAULT_I2C_ADDRESS; setprogname(*argv); - while ((ch = getopt(argc, argv, "a:f:i")) != -1) { + while ((ch = getopt(argc, argv, "a:f:in")) != -1) { switch (ch) { case 'a': address = strtol(optarg, NULL, 0x10); @@ -169,6 +177,9 @@ main(int argc, char *argv[]) case 'i': iflag = 1; break; + case 'n': + read_flags |= BDEV_NOPAGE; + break; default: break; } @@ -181,13 +192,13 @@ main(int argc, char *argv[]) } if (iflag == 1) { - r = board_info(fd, address); + r = board_info(fd, address, read_flags); if (r == -1) { fprintf(stderr, "board_info(): %s\n", strerror(errno)); return 1; } } else { - r = eeprom_dump(fd, address); + r = eeprom_dump(fd, address, read_flags); if (r == -1) { fprintf(stderr, "eeprom_dump(): %s\n", strerror(errno)); return 1; diff --git a/commands/eepromread/eepromread.h b/commands/eepromread/eepromread.h index ee04677b5..733ba2cf3 100644 --- a/commands/eepromread/eepromread.h +++ b/commands/eepromread/eepromread.h @@ -2,7 +2,7 @@ #define __EEPROMREAD_H int eeprom_read(int fd, i2c_addr_t addr, uint16_t memaddr, void *buf, - size_t buflen); -int board_info(int fd, i2c_addr_t address); + size_t buflen, int flags); +int board_info(int fd, i2c_addr_t address, int flags); #endif /* __EEPROMREAD_H */ diff --git a/drivers/cat24c256/cat24c256.c b/drivers/cat24c256/cat24c256.c index 70942c5d0..b52cb73a8 100644 --- a/drivers/cat24c256/cat24c256.c +++ b/drivers/cat24c256/cat24c256.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -53,10 +54,10 @@ struct blockdriver cat24c256_tab = { .bdr_device = NULL /* 1 insance per bus, threads not needed */ }; -static int cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen); -static int cat24c256_read(uint16_t memaddr, void *buf, size_t buflen); -static int cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen); -static int cat24c256_write(uint16_t memaddr, void *buf, size_t buflen); +static int cat24c256_read128(uint16_t memaddr, void *buf, size_t buflen, int flags); +static int cat24c256_read(uint16_t memaddr, void *buf, size_t buflen, int flags); +static int cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen, int flags); +static int cat24c256_write(uint16_t memaddr, void *buf, size_t buflen, int flags); /* globals */ @@ -176,13 +177,13 @@ cat24c256_blk_transfer(dev_t minor, int do_write, u64_t pos64, return EINVAL; } - r = cat24c256_write(position, copybuf, count); + r = cat24c256_write(position, copybuf, count, flags); if (r != OK) { log_warn(&log, "write failed (r=%d)\n", r); return r; } } else { - r = cat24c256_read(position, copybuf, count); + r = cat24c256_read(position, copybuf, count, flags); if (r != OK) { log_warn(&log, "read failed (r=%d)\n", r); return r; @@ -259,16 +260,16 @@ cat24c256_blk_other(message * m) return r; } -/* The lower level i2c interface can only read/write 32 bytes at a time. +/* The lower level i2c interface can only read/write 128 bytes at a time. * One might want to do more I/O than that at once w/EEPROM, so there is - * cat24c256_read() and cat24c256_read32(). cat24c256_read32() does the - * actual reading in chunks up to 32 bytes. cat24c256_read() splits - * the request up into chunks and repeatedly calls cat24c256_read32() + * cat24c256_read() and cat24c256_read128(). cat24c256_read128() does the + * actual reading in chunks up to 128 bytes. cat24c256_read() splits + * the request up into chunks and repeatedly calls cat24c256_read128() * until all of the requested EEPROM locations have been read. */ static int -cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen) +cat24c256_read128(uint16_t memaddr, void *buf, size_t buflen, int flags) { int r; minix_i2c_ioctl_exec_t ioctl_exec; @@ -286,9 +287,15 @@ cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen) ioctl_exec.iie_addr = address; /* set the memory address to read from */ - ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff); - ioctl_exec.iie_cmd[1] = (memaddr & 0xff); - ioctl_exec.iie_cmdlen = 2; + if ((BDEV_NOPAGE & flags) == BDEV_NOPAGE) { + /* reading within the current page */ + ioctl_exec.iie_cmd[0] = (memaddr & 0xff); + ioctl_exec.iie_cmdlen = 1; + } else { + ioctl_exec.iie_cmd[0] = ((memaddr >> 8) & 0xff); + ioctl_exec.iie_cmd[1] = (memaddr & 0xff); + ioctl_exec.iie_cmdlen = 2; + } ioctl_exec.iie_buflen = buflen; @@ -307,7 +314,7 @@ cat24c256_read32(uint16_t memaddr, void *buf, size_t buflen) } int -cat24c256_read(uint16_t memaddr, void *buf, size_t buflen) +cat24c256_read(uint16_t memaddr, void *buf, size_t buflen, int flags) { int r; uint16_t i; @@ -317,25 +324,26 @@ cat24c256_read(uint16_t memaddr, void *buf, size_t buflen) return -1; } - for (i = 0; i < buflen; i += 32) { + for (i = 0; i < buflen; i += 128) { - r = cat24c256_read32(memaddr + i, buf + i, - ((buflen - i) < 32) ? (buflen - i) : 32); + r = cat24c256_read128(memaddr + i, buf + i, + ((buflen - i) < 128) ? (buflen - i) : 128, flags); if (r != OK) { return r; } log_trace(&log, "read %d bytes starting at 0x%x\n", - ((buflen - i) < 32) ? (buflen - i) : 32, memaddr + i); + ((buflen - i) < 128) ? (buflen - i) : 128, memaddr + i); } return OK; } static int -cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen) +cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen, int flags) { int r; + int addrlen; minix_i2c_ioctl_exec_t ioctl_exec; if (buflen > (I2C_EXEC_MAX_BUFLEN - 2) || buf == NULL @@ -352,11 +360,17 @@ cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen) ioctl_exec.iie_cmdlen = 0; /* set the memory address to write to */ - ioctl_exec.iie_buf[0] = ((memaddr >> 8) & 0xff); - ioctl_exec.iie_buf[1] = (memaddr & 0xff); - - memcpy(ioctl_exec.iie_buf + 2, buf, buflen); - ioctl_exec.iie_buflen = buflen + 2; + if ((BDEV_NOPAGE & flags) == BDEV_NOPAGE) { + /* writing within the current page */ + ioctl_exec.iie_buf[0] = (memaddr & 0xff); /* address */ + addrlen = 1; + } else { + ioctl_exec.iie_buf[0] = ((memaddr >> 8) & 0xff);/* page */ + ioctl_exec.iie_buf[1] = (memaddr & 0xff); /* address */ + addrlen = 2; + } + memcpy(ioctl_exec.iie_buf + addrlen, buf, buflen); + ioctl_exec.iie_buflen = buflen + addrlen; r = i2cdriver_exec(bus_endpoint, &ioctl_exec); if (r != OK) { @@ -371,7 +385,7 @@ cat24c256_write16(uint16_t memaddr, void *buf, size_t buflen) } int -cat24c256_write(uint16_t memaddr, void *buf, size_t buflen) +cat24c256_write(uint16_t memaddr, void *buf, size_t buflen, int flags) { int r; uint16_t i; @@ -384,7 +398,7 @@ cat24c256_write(uint16_t memaddr, void *buf, size_t buflen) for (i = 0; i < buflen; i += 16) { r = cat24c256_write16(memaddr + i, buf + i, - ((buflen - i) < 16) ? (buflen - i) : 16); + ((buflen - i) < 16) ? (buflen - i) : 16, flags); if (r != OK) { return r; } diff --git a/include/minix/com.h b/include/minix/com.h index 4cabf8162..9a2994d00 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -1298,6 +1298,7 @@ /* Bits in 'BDEV_FLAGS' field of block device transfer requests. */ # define BDEV_NOFLAGS 0x00 /* no flags are set */ # define BDEV_FORCEWRITE 0x01 /* force write to disk immediately */ +# define BDEV_NOPAGE 0x02 /* eeprom: don't send page address */ /* Field names for GETRUSAGE related calls */ #define RU_ENDPT m1_i1 /* indicates a process for sys_getrusage */ diff --git a/sys/dev/i2c/i2c_io.h b/sys/dev/i2c/i2c_io.h index 52e916eb1..60af0ea02 100644 --- a/sys/dev/i2c/i2c_io.h +++ b/sys/dev/i2c/i2c_io.h @@ -98,8 +98,8 @@ typedef struct i2c_ioctl_exec { void *iie_buf; /* pointer to data buffer */ size_t iie_buflen; /* length of data buffer */ } i2c_ioctl_exec_t; -#define I2C_EXEC_MAX_CMDLEN 32 -#define I2C_EXEC_MAX_BUFLEN 32 +#define I2C_EXEC_MAX_CMDLEN 128 +#define I2C_EXEC_MAX_BUFLEN 128 #define I2C_IOCTL_EXEC _IOW('I', 0, i2c_ioctl_exec_t)