blob: afd051f617bd16a493f024e9a5e243c572326193 [file] [log] [blame]
/*
* Copyright (C) 2013-2014 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __BBSI_H
#define __BBSI_H
/*
* Resources:
* BCM6803 Data Sheet (Document ID: 6803-DS205-R), Chapter 5: Host Interface and CPU
* BBVLSI Serial Interface (BBSI) (Document ID: BBSI-UM200-R)
*/
#include <linux/netdevice.h>
#include <linux/spi/spi.h>
#ifndef KSEG1
#define KSEG1 0 // just to appease non-MIPS CPUs. Not really used.
#endif
#define BP_MOCA_MAX_NUM 1
#define SPI_FIFO_LEN 32
#define BBSI_COMMAND_BYTE 0x80
#define STATUS_REGISTER_ADDR 0x06
#define CONFIG_REGISTER_ADDR 0x07
#define DATA0_REGISTER_ADDR 0x0c
#define READ_RBUS (1<<0)
#define SPECULATIVE_READ_EN (1<<1)
#define NO_RBUS_ADDR_INC (1<<2)
#define STATUS_BUSY (1<<4)
enum bbsi_operation_state {
START,
COMMAND_STATE,
DATA_STATE,
POLLSTATUS_STATE,
DONE,
FAIL,
};
struct bbsi_operation {
enum bbsi_operation_state state;
struct spi_device *spi;
struct spi_message sm;
struct spi_transfer st[2];
/* address on MoCA chip we want to read from/write to */
uint32_t addr;
/* len must be a multiple of 4 */
size_t len;
uint8_t *data;
/* number of bytes already read or written. data_len <= len */
size_t data_len;
uint8_t tx_buf[8];
uint8_t rx_buf[SPI_FIFO_LEN - 2];
/* See interpret_data() for a definition of rx_state */
int rx_state;
struct completion done;
};
/*
* The exact values here don't matter, as they're translated into "real"
* values before talking to mocad. This is just for the device registration
* tables.
*/
enum {
BP_MOCA_TYPE_WAN,
BP_MOCA_TYPE_LAN,
};
enum {
BP_MOCA_RF_BAND_D_LOW,
BP_MOCA_RF_BAND_D_HIGH,
BP_MOCA_RF_BAND_EXT_D,
BP_MOCA_RF_BAND_E,
BP_MOCA_RF_BAND_F,
};
typedef struct BpMocaInfo {
int type;
int rfBand;
} BP_MOCA_INFO;
static void BpGetMocaInfo(BP_MOCA_INFO *chips, int *nchips) {
if (*nchips >= 1) {
*nchips = 1;
chips[0].type = BP_MOCA_TYPE_LAN;
chips[0].rfBand = BP_MOCA_RF_BAND_E;
}
}
// TODO(apenwarr): don't make this global.
// Or fix the driver to just only enable/disable interrupts at the right
// times.
static int irq_disabled = 0;
static void kerSysMocaHostIntrEnable(struct spi_device *spi) {
if (irq_disabled == 1) {
irq_disabled = 0;
enable_irq(spi->irq);
}
}
static void kerSysMocaHostIntrDisable(struct spi_device *spi) {
if (irq_disabled == 0) {
disable_irq_nosync(spi->irq);
irq_disabled = 1;
}
}
static void state_machine_read(void *context);
static void state_machine_write(void *context);
static void bbsi_op_fail(struct bbsi_operation *t) {
t->state = FAIL;
complete(&t->done);
}
static int send_readcmd(struct bbsi_operation *t, int burst) {
int ret;
spi_message_init(&t->sm);
t->sm.complete = state_machine_read;
t->sm.context = t;
t->tx_buf[0] = BBSI_COMMAND_BYTE | 0x01;
t->tx_buf[1] = CONFIG_REGISTER_ADDR;
t->tx_buf[2] = READ_RBUS |
(burst ? SPECULATIVE_READ_EN : NO_RBUS_ADDR_INC);
writel(cpu_to_be32(t->addr), t->tx_buf + 3);
t->st[0] = ((struct spi_transfer) { .tx_buf = t->tx_buf, .len = 7 });
spi_message_add_tail(&t->st[0], &t->sm);
ret = spi_async_locked(t->spi, &t->sm);
if (ret) {
pr_err("%s: spi_async failed with %d\n", __func__, ret);
bbsi_op_fail(t);
}
return ret;
}
static int send_writecmd(struct bbsi_operation *t) {
int ret;
spi_message_init(&t->sm);
t->sm.complete = state_machine_write;
t->sm.context = t;
t->tx_buf[0] = BBSI_COMMAND_BYTE | 0x01;
t->tx_buf[1] = CONFIG_REGISTER_ADDR;
t->tx_buf[2] = 0;
writel(cpu_to_be32(t->addr), t->tx_buf + 3);
t->st[0] = ((struct spi_transfer) { .tx_buf = t->tx_buf, .len = 7 });
spi_message_add_tail(&t->st[0], &t->sm);
ret = spi_async_locked(t->spi, &t->sm);
if (ret) {
pr_err("%s: spi_async failed with %d\n", __func__, ret);
bbsi_op_fail(t);
}
return ret;
}
static int send_pollstatuscmd(struct bbsi_operation *t, void (*complete)(void *context)) {
int ret;
spi_message_init(&t->sm);
t->sm.complete = complete;
t->sm.context = t;
t->tx_buf[0] = BBSI_COMMAND_BYTE;
t->tx_buf[1] = STATUS_REGISTER_ADDR;
t->st[0] = ((struct spi_transfer) { .tx_buf = t->tx_buf, .len = 2 });
t->st[1] = ((struct spi_transfer) { .rx_buf = t->rx_buf, .len = 1 });
spi_message_add_tail(&t->st[0], &t->sm);
spi_message_add_tail(&t->st[1], &t->sm);
ret = spi_async_locked(t->spi, &t->sm);
if (ret) {
pr_err("%s: spi_async failed with %d\n", __func__, ret);
bbsi_op_fail(t);
}
return ret;
}
static int read_data(struct bbsi_operation *t) {
int ret;
spi_message_init(&t->sm);
t->sm.complete = state_machine_read;
t->sm.context = t;
t->tx_buf[0] = BBSI_COMMAND_BYTE;
/* We want to continue reading where we left off. See interpret_data()
* for the definition of t->rx_state */
if (t->rx_state == 0) {
t->tx_buf[1] = STATUS_REGISTER_ADDR;
} else {
t->tx_buf[1] = DATA0_REGISTER_ADDR + t->rx_state - 1;
}
t->st[0] = ((struct spi_transfer) { .tx_buf = t->tx_buf, .len = 2 });
t->st[1] = ((struct spi_transfer) { .rx_buf = t->rx_buf,
.len = sizeof(t->rx_buf)});
spi_message_add_tail(&t->st[0], &t->sm);
spi_message_add_tail(&t->st[1], &t->sm);
ret = spi_async_locked(t->spi, &t->sm);
if (ret) {
pr_err("%s: spi_async failed with %d\n", __func__, ret);
bbsi_op_fail(t);
}
return ret;
}
static int write_data(struct bbsi_operation *t) {
int ret;
size_t len;
len = min(t->len - t->data_len, sizeof(t->rx_buf));
spi_message_init(&t->sm);
t->sm.complete = state_machine_write;
t->sm.context = t;
t->tx_buf[0] = BBSI_COMMAND_BYTE | 0x01;
t->tx_buf[1] = DATA0_REGISTER_ADDR + (t->data_len & 3);
t->st[0] = ((struct spi_transfer) { .tx_buf = t->tx_buf, .len = 2 });
t->st[1] = ((struct spi_transfer) { .tx_buf = t->data + t->data_len,
.len = len});
spi_message_add_tail(&t->st[0], &t->sm);
spi_message_add_tail(&t->st[1], &t->sm);
ret = spi_async_locked(t->spi, &t->sm);
if (ret) {
pr_err("%s: spi_async failed with %d\n", __func__, ret);
bbsi_op_fail(t);
}
t->data_len += len;
return ret;
}
static int interpret_data(struct bbsi_operation *t) {
/* The bytes we are receiving over the SPI bus are the values of
* registers in the BBSI interface on the BCM6803. The register csrAddr
* points to the register that we are going to read next. It cycles
* through the following registers:
* - STATUS (t->rx_state==0)
* - DATA0 (t->rx_state==1)
* - DATA1 (t->rx_state==2)
* - DATA2 (t->rx_state==3)
* - DATA3 (t->rx_state==4)
*
* If csrAddr points to the status register, csrAddr is not incremented
* if the busy bit in the status register is set. As a result, we might
* read the status register multiple times before we get to DATA0. We
* therefore might have to skip over multiple status bytes.
*
* t->rx_state defines the register that we are going to read next: 0
* stands for STATUS, 1 stands for DATA0, 2 for DATA1 and so on.
*/
uint8_t *r;
r = t->rx_buf;
for(r = t->rx_buf;r < t->rx_buf + sizeof(t->rx_buf);r++) {
if (t->rx_state == 0) {
if (*r & STATUS_BUSY)
/* t->rx_state stays at 0 because the next byte
* will be another status byte */
continue;
else if (*r) {
pr_err("rbus error 0x%02x while trying to read %u "
"bytes from 0x%08x\n",
(unsigned) *r, t->len, t->addr);
bbsi_op_fail(t);
return -1;
} else
/* The busy bit is not set which means that the next byte will be DATA0. */
t->rx_state = 1;
} else {
BUG_ON(t->data_len >= t->len);
t->data[t->data_len++] = *r;
/* t->rx_state==4 means that we just read DATA3. The
* next byte will be a status byte (t->rx_state==0) */
t->rx_state++;
t->rx_state%=5;
if (t->data_len == t->len) return 0;
}
}
return 0;
}
static void state_machine_read(void *context) {
struct bbsi_operation *t = (struct bbsi_operation *) context;
int ret;
BUG_ON(t->len&3);
switch (t->state) {
case START:
t->state = COMMAND_STATE;
ret = send_readcmd(t, t->len>4);
if (ret) return;
break;
case COMMAND_STATE:
if (t->sm.status) {
pr_err("readcmd returned bad status %d\n", t->sm.status);
bbsi_op_fail(t);
return;
}
t->state = DATA_STATE;
ret = read_data(t);
if (ret) return;
break;
case DATA_STATE:
if (t->sm.status) {
pr_err("read_data returned bad status %d\n", t->sm.status);
bbsi_op_fail(t);
return;
}
if (interpret_data(t)) return;
if (t->data_len == t->len) {
t->state = DONE;
complete(&t->done);
} else {
/* Stay in this state */
ret = read_data(t);
if (ret) return;
}
break;
default:
BUG();
break;
}
}
static void state_machine_write(void *context) {
struct bbsi_operation *t = (struct bbsi_operation *) context;
int ret;
BUG_ON(t->len&3);
switch (t->state) {
case START:
t->state = COMMAND_STATE;
ret = send_writecmd(t);
if (ret) return;
break;
case COMMAND_STATE:
if (t->sm.status) {
pr_err("writecmd returned bad status %d\n", t->sm.status);
bbsi_op_fail(t);
return;
}
t->state = DATA_STATE;
ret = write_data(t);
if (ret) return;
break;
case DATA_STATE:
if (t->sm.status) {
pr_err("write_data returned bad status %d\n", t->sm.status);
bbsi_op_fail(t);
return;
}
if (t->data_len == t->len) {
t->state = POLLSTATUS_STATE;
ret = send_pollstatuscmd(t, state_machine_write);
if (ret) return;
} else {
/* Stay in this state */
ret = write_data(t);
if (ret) return;
}
break;
case POLLSTATUS_STATE:
if (t->sm.status) {
pr_err("pollstatuscmd returned bad status %d\n", t->sm.status);
bbsi_op_fail(t);
return;
}
if (*t->rx_buf & STATUS_BUSY) {
/* Stay in this state */
ret = send_pollstatuscmd(t, state_machine_write);
if (ret) return;
} else if (*t->rx_buf) {
pr_err("rbus error 0x%02x while trying to write %u "
"bytes to 0x%08x\n",
(unsigned) *t->rx_buf, t->len, t->addr);
bbsi_op_fail(t);
} else {
t->state = DONE;
complete(&t->done);
}
break;
default:
BUG();
break;
}
}
static uint32_t bbsi_read(struct spi_device *spi, uint32_t addr, void *dst, size_t len) {
struct bbsi_operation *t;
t = kmalloc(sizeof(*t), GFP_KERNEL);
t->state = START;
t->spi = spi;
t->addr = addr;
t->len = len;
t->data = dst;
t->data_len = 0;
t->rx_state = 0;
init_completion(&t->done);
state_machine_read((void*) t);
wait_for_completion(&t->done);
kfree(t);
return 0;
}
static uint32_t bbsi_write(struct spi_device *spi, uint32_t addr, const void *src, size_t len) {
struct bbsi_operation *t;
t = kmalloc(sizeof(*t), GFP_KERNEL);
t->state = START;
t->spi = spi;
t->addr = addr;
t->len = len;
t->data = (void*) src;
t->data_len = 0;
init_completion(&t->done);
state_machine_write((void*) t);
wait_for_completion(&t->done);
kfree(t);
return 0;
}
static uint32_t _spi_read32(struct spi_device *spi, uint32_t addr) {
uint32_t retval = 0;
spi_bus_lock(spi->master);
bbsi_read(spi, addr, &retval, sizeof(retval));
spi_bus_unlock(spi->master);
return be32_to_cpu(retval);
}
static void _spi_write32(struct spi_device *spi, uint32_t addr, uint32_t value) {
spi_bus_lock(spi->master);
value = cpu_to_be32(value);
bbsi_write(spi, addr, &value, sizeof(value));
spi_bus_unlock(spi->master);
}
static uint32_t kerSysBcmSpiSlaveReadReg32(struct spi_device *spi, uint32_t addr) {
return _spi_read32(spi, addr);
}
static void kerSysBcmSpiSlaveWriteReg32(struct spi_device *spi, uint32_t addr, uint32_t value) {
_spi_write32(spi, addr, value);
}
static void kerSysBcmSpiSlaveReadBuf(struct spi_device *spi, uint32_t addr, void *dst, int len, int wordsize) {
if (len == 0) {
pr_warn("spi readbuf: buffer size 0 invalid\n");
return;
}
if (wordsize != 4) {
pr_info("SPI readbuf: only word size == 4 bytes is supported!\n");
return;
}
spi_bus_lock(spi->master);
bbsi_read(spi, addr, dst, len);
spi_bus_unlock(spi->master);
}
static void kerSysBcmSpiSlaveWriteBuf(struct spi_device *spi, uint32_t addr, const void *src, int len, int wordsize) {
if (len > 8192) {
pr_warn("spi writebuf: buffer size %d is too large\n", len);
return;
}
if (wordsize != 4 || len&3) {
pr_err("SPI writebuf: only word size == 4 bytes is supported!\n");
return;
}
spi_bus_lock(spi->master);
bbsi_write(spi, addr, src, len);
spi_bus_unlock(spi->master);
}
#endif // __BBSI_H