[flashrom] [PATCH] Add Linux SPI support
Uwe Hermann
uwe at hermann-uwe.de
Sat Sep 3 20:39:46 CEST 2011
On Wed, Mar 02, 2011 at 11:56:43PM +0100, Carl-Daniel Hailfinger wrote:
> > Signed-off-by: Sven Schnelle <svens at stackframe.org>
Thanks, committed as r1427 with a few changes as proposed below, and
with more changes due to forward-porting to current flashrom trunk.
> Thanks for your patch! Review follows.
I addressed some of the issues (but not all, yet). Shouldn't be a big
deal though, as the driver is disabled by default. The rest of the
changes can be in another patch.
Compile-tested, but not tested on hardware by me.
> Cosmetic:
> linux_spi_init() has trailing whitespace in some lines, and spaces
> instead of tabs in some lines.
Fixed.
> Having a man page entry for this would be awesome, but that can be
> postponed until the main patch is in.
Yup, can be extra patch, didn't add something for now.
> > +CONFIG_LINUX_SPI ?= yes
>
> Either set it to no by default, or make the yes conditional on detecting
> a Linux target (not host, because DOS binaries are generated on a Linux
> host). I'd postpone the Linux detection to a later patch.
>
> Adding a short comment why it defaults to no or a comment under which
> circumstances it defaults to yes would be appreciated.
Yup, set to no for now, added comment.
> > +int linux_spi_init(void)
> > +{
> > + char *p, *endp, *dev;
> > + int speed = 0;
> >
>
> int speed, but later you use strtoul which fills an unsigned long.
TODO
> > + dev = extract_programmer_param("dev");
> > + if (!dev || !strlen(dev)) {
> >
>
> strlen(dev) can happen if the user specified no device name:
> -p linux_spi:dev=
> Please handle that case separately (error message, abort).
TODO
> > + msg_perr("No spi device given. Use flashrom -p "
> > + "linux_spi:dev=/dev/spidevX.Y\n");
> > + return 1;
> > + }
> >
>
> Maybe add a msg_dbg or msg_spew about the device name specified by the user.
TODO
> > + p = extract_programmer_param("speed");
> > + if (p && strlen(p)) {
> >
>
>
> Please handle the same problem for speed=
TODO
> > + speed = strtoul(p, &endp, 10) * 1024;
> > + if (p == endp) {
> > + msg_perr("%s: invalid clock: %s\n", __func__, p);
> >
>
> Maybe "%s: invalid clock: %s kHz\n" instead?
Done.
> > + return 1;
> > + }
> >
>
> Print the chosen clock frequency here? Check if the supplied clock
> frequency is nonzero and nonnegative?
TODO
> > + }
> > +
> > + if ((fd = open(dev, O_RDWR)) == -1) {
> > + msg_perr("%s: failed to open %s: %s\n", __func__,
> > + dev, strerror(errno));
> > + return 1;
> > + }
> > +
> > + if (speed > 0 && ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) {
> >
>
> Are you 100% sure that this ioctl wants a signed int?
> http://www.kernel.org/doc/Documentation/spi/spidev says something about
> an u32.
TODO
> > + msg_perr("%s: failed to set speed %dHz: %s\n",
> > + __func__, speed, strerror(errno));
> > + close(fd);
> > + return 1;
> > + }
> >
>
> Not sure if Linux SPI masters use the right CPOL/CPHA and bit ordering
> and bits per word by default, so setting SPI_IOC_WR_MODE and
> SPI_IOC_WR_LSB_FIRST and SPI_IOC_WR_BITS_PER_WORD would probably be a
> very good idea.
TODO
> > +
> > + buses_supported = CHIP_BUSTYPE_SPI;
> > + spi_controller = SPI_CONTROLLER_LINUX;
I changed this, as we now use register_shutdown() in trunk.
I also moved this:
+#if CONFIG_LINUX_SPI == 1
+ { /* SPI_CONTROLLER_LINUX */
+ .command = linux_spi_send_command,
+ .multicommand = default_spi_send_multicommand,
+ .read = linux_spi_read,
+ .write_256 = linux_spi_write_256,
+ },
+#endif
to linux_spi.c and used
static const struct spi_programmer spi_programmer_linux = { ... }
...
register_spi_programmer(&spi_programmer_linux);
as the other SPI programmers do these days.
I also added
.max_data_read = MAX_DATA_UNSPECIFIED, /* TODO? */
.max_data_write = MAX_DATA_UNSPECIFIED, /* TODO? */
in that struct, not sure what the correct values are.
> > +int linux_spi_send_command(unsigned int writecnt, unsigned int readcnt,
> > + const unsigned char *txbuf, unsigned char *rxbuf)
> > +{
> > + struct spi_ioc_transfer msg[2] = {
> > + { .tx_buf = (unsigned long)txbuf, .len = writecnt },
> > + { .rx_buf = (unsigned long)rxbuf, .len = readcnt }
> >
>
> Really unsigned long casts for txbuf and rxbuf?
Required it seems, as otherwise:
linux_spi.c:111:4: error: initialization makes integer from pointer without a cast [-Werror]
linux_spi.c:111:4: error: (near initialization for ‘msg[0].tx_buf’) [-Werror]
etc.
This is due to .tx_buf/.rx_buf being defined as __u64 in linux/spi/spidev.h:
struct spi_ioc_transfer {
__u64 tx_buf;
__u64 rx_buf;
...
}
I changed "unsigned long" to "uint64_t", though.
> > +int linux_spi_read(struct flashchip *flash, uint8_t *buf, int start, int len)
> > +{
> > + return spi_read_chunked(flash, buf, start, len, 12);
> >
>
> Should not be 12, but rather getpagesize()
Fixed.
> and a comment that max transfer size is one page.
?
> > +int linux_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len)
> > +{
> > + return spi_write_chunked(flash, buf, start, len, 12);
>
> Should not be 12, but rather getpagesize()-4 with a similar comment as
> above. We lose 4 bytes at the beginning because we have to write
> command+addr to the SPI line.
Fixed, but no idea what a good comment would look like (same as above).
Sven, can you please check if trunk works for you, and/or fix it if I
broke stuff? Also, do you plan to work on addressing the other TODOs?
I guess I have some board where I can test this driver too, but it will
take a while to setup etc.
Thanks, Uwe.
--
http://hermann-uwe.de | http://sigrok.org
http://randomprojects.org | http://unmaintained-free-software.org
More information about the flashrom
mailing list