Permalink
Browse files

added spi kernel driver patch, added python-spidev, nfc-utils

  • Loading branch information...
greenbreakfast committed Mar 27, 2018
1 parent 0026ddf commit e7deb939abf3014bc26dfc941bdb6491d672a160
Showing with 298 additions and 8 deletions.
  1. +6 −6 .config
  2. +15 −1 CHANGELOG.md
  3. +1 −1 files/etc/uci-defaults/12_onion_version
  4. +276 −0 target/linux/ramips/patches-4.4/9999-spi-mt7621.patch
12 .config
@@ -2887,7 +2887,7 @@ CONFIG_PACKAGE_boost-container=m
# CONFIG_PACKAGE_boost-thread is not set
# CONFIG_PACKAGE_boost-timer is not set
# CONFIG_PACKAGE_boost-wave is not set
# CONFIG_PACKAGE_ccid is not set
CONFIG_PACKAGE_ccid=m
# CONFIG_PACKAGE_check is not set
CONFIG_PACKAGE_classpath=m
CONFIG_PACKAGE_classpath-tools=m
@@ -3081,7 +3081,7 @@ CONFIG_PACKAGE_libncurses=m
# CONFIG_PACKAGE_libnetfilter-queue is not set
# CONFIG_PACKAGE_libnetsnmp is not set
# CONFIG_PACKAGE_libnettle is not set
# CONFIG_PACKAGE_libnfc is not set
CONFIG_PACKAGE_libnfc=m
# CONFIG_PACKAGE_libnfnetlink is not set
# CONFIG_PACKAGE_libnftnl is not set
# CONFIG_PACKAGE_libnl is not set
@@ -3112,7 +3112,7 @@ CONFIG_PACKAGE_libpcap=m
CONFIG_PACKAGE_libpcre=y
# CONFIG_PACKAGE_libpcre16 is not set
# CONFIG_PACKAGE_libpcrecpp is not set
# CONFIG_PACKAGE_libpcsclite is not set
CONFIG_PACKAGE_libpcsclite=m
# CONFIG_PACKAGE_libpkcs11-spy is not set
# CONFIG_PACKAGE_libplist is not set
# CONFIG_PACKAGE_libplistcxx is not set
@@ -4405,7 +4405,7 @@ CONFIG_PACKAGE_pyOnionSpi=m
# CONFIG_PACKAGE_pyOnionSt7735 is not set
CONFIG_PACKAGE_pyPwmExp=m
CONFIG_PACKAGE_pyRelayExp=m
# CONFIG_PACKAGE_python-spidev is not set
CONFIG_PACKAGE_python-spidev=m

#
# Network
@@ -4898,7 +4898,7 @@ CONFIG_PACKAGE_mountd=y
# CONFIG_PACKAGE_mpack is not set
# CONFIG_PACKAGE_mt-st is not set
# CONFIG_PACKAGE_namei is not set
# CONFIG_PACKAGE_nfc-utils is not set
CONFIG_PACKAGE_nfc-utils=m
# CONFIG_PACKAGE_oath-toolkit is not set
# CONFIG_PACKAGE_open-plc-utils is not set
# CONFIG_PACKAGE_open2300 is not set
@@ -4911,7 +4911,7 @@ CONFIG_PACKAGE_mountd=y
# CONFIG_PACKAGE_opus-tools is not set
# CONFIG_PACKAGE_owipcalc is not set
# CONFIG_PACKAGE_pciutils is not set
# CONFIG_PACKAGE_pcscd is not set
CONFIG_PACKAGE_pcscd=m
# CONFIG_PACKAGE_pps-tools is not set
# CONFIG_PACKAGE_prlimit is not set
# CONFIG_PACKAGE_procps-ng is not set
@@ -170,8 +170,22 @@ Initial firmware sent to be flashed at the factory
### Build Notes
Defining the changes in each build. *Note that if a number is missing, that build failed the deployment process.*

#### b176
*Mar 26, 2017*

* SPI kernel driver - integrated patch that alleviates issues
* full-duplex transmissions are replaced with half-duplex
* able to transmit larger "packets" of data at a time (no longer just 16 bytes before CS deasserts
* Added Python `spidev` module
* package updates
* console install tool - updated to work regardless of network configuration, specifically, works with ethernet connectivity now
* i2c exp driver - i2c library updated to fix memory overwrite bug
* python gpio module - updated to alleviate bug with setting output gpios
* avrdude - upped version number to avoid installing broken v6.3
* Added `nfc-utils` and `libnfc` packages

#### b175
*Mar 27, 2017*
*Mar 26, 2017*

* Added WiFi Warp Core
* Integrates `wifisetup` command
@@ -2,7 +2,7 @@

uci -q batch <<-EOF > /dev/null
set onion.@onion[0].version='0.2.0'
set onion.@onion[0].build='175'
set onion.@onion[0].build='176'
commit system
EOF

@@ -0,0 +1,276 @@
From 4d4411a2204fa865647aa33568f20bc8eabdc5a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bernhard=20W=C3=B6rndl-Aichriedler?= <bwa@xdevelop.at>
Date: Thu, 13 Oct 2016 23:52:12 +0200
Subject: [PATCH 1/1] Fixed MT76xx quasi-full duplex SPI support on CS1

Due to a possible silicon bug in the spi module of the MT76,
the MSB of the first bit will be set to MSB-1(bit7) of the first byte,
in full duplex mode.

So this mode falls back to an intelligent half duplex mode.
This allows for most, but not all device drivers to work.
Device drivers that are not supported will be warned about this limitation.
---
drivers/spi/spi-mt7621.c | 212 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 156 insertions(+), 56 deletions(-)

diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c
index 0a7ccc0..0831f38 100644
--- a/drivers/spi/spi-mt7621.c
+++ b/drivers/spi/spi-mt7621.c
@@ -91,10 +91,13 @@ static void mt7621_spi_reset(struct mt7621_spi *rs, int duplex)

master |= 7 << 29;
master |= 1 << 2;
- if (duplex)
- master |= 1 << 10;
- else
- master &= ~(1 << 10);
+ //if (duplex)
+ // master |= 1 << 10;
+ //else
+ // master &= ~(1 << 10);
+
+ //Only half duplex works properly!
+ master &= ~(1 << 10);

mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
}
@@ -266,85 +269,182 @@ msg_done:
return 0;
}

-static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
- struct spi_message *m)
-{
- struct mt7621_spi *rs = spi_master_get_devdata(master);
- struct spi_device *spi = m->spi;
- unsigned int speed = spi->max_speed_hz;
- struct spi_transfer *t = NULL;
- int status = 0;
- int i, len = 0;
- int rx_len = 0;
- u32 data[9] = { 0 };
- u32 val = 0;

- mt7621_spi_wait_till_ready(spi);
+#define MT7621_MAX_TX_BUFFER 36 //Dont change, limited by hardware!
+#define MT7621_MAX_RX_BUFFER 32 //Dont change, limited by hardware!

- list_for_each_entry(t, &m->transfers, transfer_list) {
- const u8 *buf = t->tx_buf;

- if (t->rx_buf)
- rx_len += t->len;
+/**
+ * Write a single byte to a buffer
+ */
+static int mt7621_spi_write_buffer(struct mt7621_spi *rs, int regindex, u32 buf, int bytesused)
+{
+ //We need to write our TX data to the OPCODE register properly
+ if(regindex == 0){
+ buf = swab32(buf);
+ if (bytesused < 4)
+ buf >>= (4 - bytesused) * 8;
+ }
+ mt7621_spi_write(rs, MT7621_SPI_OPCODE+(regindex*4), buf);

- if (!buf)
- continue;
+ return 0;
+}

- if (WARN_ON(len + t->len > 16)) {
- status = -EIO;
- goto msg_done;
+/**
+ * Simple write function
+ * Due to a bug in the silicon of the MT76XX, the MSB of the SPI transmission
+ * needs to be in the "CMD" section aka in the "OPCODE" registers
+ */
+static int mt7621_spi_transmit(struct spi_device *spi, struct mt7621_spi *rs, const u8 *buf, int len)
+{
+ int i, regindex;
+ u32 tmp, val;
+
+ //Too long for us to send
+ if(len > MT7621_MAX_TX_BUFFER) {return -1;}
+
+ //Write all data to the buffer
+ regindex = 0;
+ tmp = 0;
+ for(i = 0; i < len; i++){
+ tmp |= buf[i] << (8 * (i & 3));
+
+ if(i % 4 == 3){
+ mt7621_spi_write_buffer(rs, regindex, tmp, len);
+ regindex++;
+ tmp = 0;
}
-
- for (i = 0; i < t->len; i++, len++)
- data[len / 4] |= buf[i] << (8 * (len & 3));
- if (speed > t->speed_hz)
- speed = t->speed_hz;
}
+ if(len%4 != 0)
+ mt7621_spi_write_buffer(rs, regindex, tmp, len);

- if (WARN_ON(rx_len > 16)) {
- status = -EIO;
- goto msg_done;
- }
+ //Set how many bits should be written
+ val = (min_t(int, len, 4) * 8) << 24;
+ if (len > 4)
+ val |= (len - 4) * 8;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);

- if (mt7621_spi_prepare(spi, speed)) {
- status = -EIO;
- goto msg_done;
- }
+ //Do actual transmission
+ val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
+ val |= SPI_CTL_START;
+ mt7621_spi_write(rs, MT7621_SPI_TRANS, val);

- for (i = 0; i < len; i += 4)
- mt7621_spi_write(rs, MT7621_SPI_DATA0 + i, data[i / 4]);
+ mt7621_spi_wait_till_ready(spi);

- val |= len * 8;
- val |= (rx_len * 8) << 12;
- mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+ return 0;
+}

- mt7621_spi_set_cs(spi, 1);
+static int mt7621_spi_receive(struct spi_device *spi, struct mt7621_spi *rs, u8 *buf, int len)
+{
+ int i;
+ u32 tmp, val;
+
+ //Too long for us to send
+ if(len > MT7621_MAX_RX_BUFFER) {return -1;}
+
+ //Set how many bits should be read

+ val = (len * 8) << 12;
+ //val |= len * 8;
+ mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val);
+
+ //Do actual transmission
val = mt7621_spi_read(rs, MT7621_SPI_TRANS);
val |= SPI_CTL_START;
mt7621_spi_write(rs, MT7621_SPI_TRANS, val);

mt7621_spi_wait_till_ready(spi);

- mt7621_spi_set_cs(spi, 0);
+ //Read the buffer of the SPI module
+ for (i = 0; i < len; i+=4)
+ {
+ tmp = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);

- for (i = 0; i < rx_len; i += 4)
- data[i / 4] = mt7621_spi_read(rs, MT7621_SPI_DATA4 + i);
+ //Yes this could be optimized - Anyone?
+ buf[i+0] = (tmp >> 0) & 0xFF;
+ if(i+1 < len) buf[i+1] = (tmp >> 8) & 0xFF;
+ if(i+2 < len) buf[i+2] = (tmp >> 16) & 0xFF;
+ if(i+3 < len) buf[i+3] = (tmp >> 24) & 0xFF;
+
+ //printk(KERN_INFO "RX Tmp: %08x %02x\n", tmp, buf[i]);
+ }
+/*
+ for (i = 0; i < 8; i++)
+ {
+ tmp = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i);
+ printk(KERN_INFO "RX %i: %08x\n", i, tmp);
+ }
+ */
+
+ return 0;
+}

- m->actual_length = rx_len;

- len = 0;
+/*
+ * The SPI core of the MT76xx is utterly broken,
+ * and a full duplex transfer will mess up the MSB of the transaction
+ * by setting it to the MSB-1 bit aka a 0x40 will be a 0xC0
+ * this means, that "real" full duplex SPI cannot be used
+ *
+ * As most drivers (also the driver we use), only does
+ * "quasi-full-duplex" aka. one transfer in and one transfer out
+ * this function will handle this just fine
+ */
+static int mt7621_spi_transfer_full_duplex(struct spi_master *master,
+ struct spi_message *m)
+{
+ struct mt7621_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL;
+ unsigned int speed = spi->max_speed_hz;
+ int status = 0;
+ int i;
+
+ //Wait until SPI is ready from last transfer
+ mt7621_spi_wait_till_ready(spi);
+
+ //Get the minimum speed for the transmission
list_for_each_entry(t, &m->transfers, transfer_list) {
- u8 *buf = t->rx_buf;
+ if(t->speed_hz < speed){speed = t->speed_hz;}
+ }

- if (!buf)
- continue;
+ if (mt7621_spi_prepare(spi, speed)) {
+ return -1;
+ }

- for (i = 0; i < t->len; i++, len++)
- buf[i] = data[len / 4] >> (8 * (len & 3));
+ m->actual_length = 0;
+
+ mt7621_spi_set_cs(spi, 1);
+
+ //Go trough all transfers
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ //We don't support full duplex
+ //but in most cases, this is not necessary anyay
+ if(t->tx_buf && t->rx_buf){
+ //printk(KERN_ERR "The MT7621-SPI does not support full bidirectional SPI, only doing TX!");
+ //There are ways to overcome this limitation partially, but no really clean solution
+ }
+
+ if(t->tx_buf) {
+ const u8 *buf = t->tx_buf;
+ //printk(KERN_INFO "Doing TX");
+ m->actual_length += t->len;
+
+ for(i = 0; i < t->len; i+=MT7621_MAX_TX_BUFFER)
+ mt7621_spi_transmit(spi, rs, buf+i, min_t(int, t->len-i, MT7621_MAX_TX_BUFFER));
+ }
+ else if(t->rx_buf) {
+ u8 *buf = t->rx_buf;
+ //printk(KERN_INFO "Doing RX");
+ m->actual_length += t->len;
+ for(i = 0; i < t->len; i+=MT7621_MAX_RX_BUFFER)
+ mt7621_spi_receive(spi, rs, buf+i, min_t(int, t->len-i, MT7621_MAX_RX_BUFFER));
+ }
+ //We don't transfer if we neither got read or write buffer, is that ok?!
}

-msg_done:
+ mt7621_spi_set_cs(spi, 0);
+
m->status = status;
spi_finalize_current_message(master);

--
1.9.1

0 comments on commit e7deb93

Please sign in to comment.