Added abstraction layer for a three-wire serial device (e.g. the EEPROM
authorMichael Brown <mcb30@etherboot.org>
Fri, 26 May 2006 15:39:24 +0000 (15:39 +0000)
committerMichael Brown <mcb30@etherboot.org>
Fri, 26 May 2006 15:39:24 +0000 (15:39 +0000)
used on RTL8139 cards).

src/Makefile
src/drivers/nvs/threewire.c [new file with mode: 0644]
src/include/gpxe/nvs/threewire.h [new file with mode: 0644]

index 77d2fc9..4f44c14 100644 (file)
@@ -138,6 +138,7 @@ SRCDIRS             += drivers/bus
 SRCDIRS                += drivers/net
 SRCDIRS                += drivers/block
 SRCDIRS                += drivers/scsi
+SRCDIRS                += drivers/nvs
 SRCDIRS                += interface/pxe
 
 # NON_AUTO_SRCS lists files that are excluded from the normal
diff --git a/src/drivers/nvs/threewire.c b/src/drivers/nvs/threewire.c
new file mode 100644 (file)
index 0000000..4673606
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <timer.h>
+#include <gpxe/nvs/threewire.h>
+
+/** @file
+ *
+ * Three-wire serial interface
+ *
+ */
+
+/**
+ * Read from a three-wire device
+ *
+ * @v three    Three-wire interface
+ * @v address  Address
+ * @ret data   Data
+ */
+unsigned long threewire_read ( struct threewire *three,
+                              unsigned long address ) {
+       struct threewire_operations *ops = three->ops;
+       unsigned long command;
+       unsigned long data;
+       int i;
+
+       ops->setcs ( three, 1 );
+       
+       /* Send command and address */
+       command = threewire_cmd_read ( three, address );
+       for ( i = ( threewire_cmd_len ( three ) - 1 ) ; i >= 0 ; i-- ) {
+               ops->setdi ( three, ( command >> i ) & 0x1 );
+               udelay ( three->udelay );
+               ops->setsk ( three, 1 );
+               udelay ( three->udelay );
+               ops->setsk ( three, 0 );
+       }
+
+       /* Read back data */
+       data = 0;
+       for ( i = three->datasize ; i ; i-- ) {
+               udelay ( three->udelay );
+               ops->setsk ( three, 1 );
+               udelay ( three->udelay );
+               data <<= 1;
+               data |= ops->getdo ( three );
+               ops->setsk ( three, 0 );
+       }
+
+       ops->setcs ( three, 0 );
+
+       return data;
+}
diff --git a/src/include/gpxe/nvs/threewire.h b/src/include/gpxe/nvs/threewire.h
new file mode 100644 (file)
index 0000000..a0bb2fd
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _GPXE_NVS_THREEWIRE_H
+#define _GPXE_NVS_THREEWIRE_H
+
+/** @file
+ *
+ * Three-wire serial interface
+ *
+ */
+
+struct threewire;
+
+/** Three-wire interface methods */
+struct threewire_operations {
+       /**
+        * Set status of Chip Select line
+        *
+        * @v three     Three-wire interface
+        * @v cs        New status for chip select line
+        */
+       void ( * setcs ) ( struct threewire *three, int cs );
+       /**
+        * Set status of Serial Clock line
+        *
+        * @v three     Three-wire interface
+        * @v sk        New status for serial clock line
+        */
+       void ( * setsk ) ( struct threewire *three, int sk );
+       /**
+        * Set status of Data Input line
+        *
+        * @v three     Three-wire interface
+        * @v di        New status for data input line
+        */
+       void ( * setdi ) ( struct threewire *three, int di );
+       /**
+        * Get status of Data Output line
+        *
+        * @v three     Three-wire interface
+        * @ret do      Status of data output line
+        */
+       int ( * getdo ) ( struct threewire *three );
+};
+
+/**
+ * A three-wire serial interface
+ *
+ * This interface consists of a clock line (SK), data input (DI) and
+ * data output (DO).  There is also a chip select line (CS) which is
+ * integral to the operation of the device, but Atmel still calls it a
+ * three-wire interface.
+ *
+ */
+struct threewire {
+       /** Interface methods */
+       struct threewire_operations *ops;
+       /** Address size (in bits) */
+       unsigned int adrsize;
+       /** Data size (in bits) */
+       unsigned int datasize;
+       /** Delay between SK transitions (in us) */
+       unsigned int udelay;
+};
+
+/**
+ * Calculate read command for a specified address
+ *
+ * @v three    Three-wire interface
+ * @v address  Address
+ * @ret cmd    Command
+ */
+static inline __attribute__ (( always_inline )) unsigned long
+threewire_cmd_read ( struct threewire *three, unsigned long address ) {
+       return ( ( 0x6 << three->adrsize ) | address );
+}
+
+/**
+ * Calculate command length
+ *
+ * @v three    Three-wire interface
+ * @ret len    Command length, in bits
+ */
+static inline __attribute__ (( always_inline )) int
+threewire_cmd_len ( struct threewire *three ) {
+       return ( three->adrsize + 3 );
+}
+
+/* Constants for some standard parts */
+#define AT93C46_ORG8_ADRSIZE   7
+#define AT93C46_ORG8_DATASIZE  8
+#define AT93C46_ORG16_ADRSIZE  6
+#define AT93C46_ORG16_DATASIZE 16
+#define AT93C46_UDELAY         1
+#define AT93C56_ORG8_ADRSIZE   9
+#define AT93C56_ORG8_DATASIZE  8
+#define AT93C56_ORG16_ADRSIZE  8
+#define AT93C56_ORG16_DATASIZE 16
+#define AT93C56_UDELAY         1
+
+extern unsigned long threewire_read ( struct threewire *three,
+                                     unsigned long address );
+
+#endif /* _GPXE_NVS_THREEWIRE_H */