Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/spi/driver/linux-uio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# OH Linux generic UIO driver

Modules and devicetree compiled for Pubuntu 2016.3.x

1. Copy `zynq-parallella-oh-spi.dtb` to SD card boot partition, name it `devicetree.dtb`.
2. Reboot Parallella
3. (OPTIONAL) Load bitstream: `sudo dd if=parallella.bit.bin of=/dev/xdevcfg`
3. Load the required modules:
```
sudo insmod uio.ko
sudo insmod uio_pdrv_genirq.ko of_id=oh,mio
sudo rmmod uio_pdrv_genirq.ko
sudo insmod uio_pdrv_genirq.ko of_id=oh,mio
chmod 777 /dev/uio0
```
4. You can now compile and run uio-test in oh.git/src/spi/driver/spilib
Binary file added src/spi/driver/linux-uio/uio.ko
Binary file not shown.
Binary file added src/spi/driver/linux-uio/uio_pdrv_genirq.ko
Binary file not shown.
Binary file not shown.
51 changes: 51 additions & 0 deletions src/spi/driver/linux-uio/zynq-parallella-oh-spi.dts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2016 Parallella Foundation
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
/dts-v1/;
#include "zynq-parallella1.dtsi"

/ {
model = "Adapteva Parallella Board with OH SPI bitstream";
};

&amba {
spi2: spi2@7fe00000 {
compatible = "oh,spi";
reg = <0x7fe00000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <0 53 4>;
};
};

&usb_phy0 {
status = "okay";
};

&usb_phy1 {
status = "okay";
};

&usb0 {
status = "okay";
};

&usb1 {
status = "okay";
};

&elink0 {
status = "disabled";
};

&i2c0 {
status = "disabled";
};
6 changes: 6 additions & 0 deletions src/spi/driver/spilib/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
all: uio-test

clean:
rm -f uio-test

.PHONY: all clean
129 changes: 129 additions & 0 deletions src/spi/driver/spilib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Driver layer for SPI

## User API

```c
/**
* spi_init - SPI init
*
* @param dev uninitialized device structure
* @param arg target argument (depends on target)
*
* @return 0 on success. Negative on error
*/
int spi_init(spi_dev_t *dev, void *arg);

/**
* spi_init - SPI finalize
*
* @param dev uninitialized device structure
*/
void spi_init(spi_dev_t *dev);


/**
* spi_set_config - Set configuration for SPI device
*
* @param dev device structure
* @param config spi configuration
*
*/
void spi_set_config(spi_dev_t *dev, uint8_t config);
#define spi_set_config(dev, config) spi_reg_write((dev), SPI_CONFIG, (config))

/**
* spi_get_config - Get configuration for SPI device
*
* @param dev device structure
*
* @return spi config register
*/
uint8_t spi_get_config(spi_dev_t *dev);
#define spi_get_config(dev) spi_reg_read((dev), SPI_CONFIG)

/**
* spi_get_status - Get status for SPI device
*
* @param dev device structure
*
*/
uint8_t spi_get_status(spi_dev_t *dev);
#define spi_get_status(dev) spi_reg_read((dev), SPI_STATUS)

/**
* spi_set_clkdiv - Set master clock divider
*
* @param dev device structure
* @param config spi configuration
*
*/
void spi_set_clkdiv(spi_dev_t *dev, uint8_t clkdiv);
#define spi_set_clkdiv(dev, clkdiv) spi_reg_write((dev), SPI_CLKDIV, (clkdiv))

/**
* spi_get_clkdiv - Get master clock divider
*
* @param dev device structure
*
* @return clock divider register
*
*/
uint8_t spi_get_clkdiv(spi_dev_t *dev);
#define spi_get_clkdiv(dev) spi_reg_read((dev), SPI_CLKDIV)

/**
* spi_transter - Perform one SPI transfer
*
* @param dev device structure
* @param tx transmit data buffer
* @param rx receive data buffer
* @param count number of bytes
*
*/
void spi_transfer(spi_dev_t *dev, uint8_t *tx, uint8_t *rx, unsigned count);

/*** Raw register access API */

#define SPI_CONFIG 0x00
#define SPI_STATUS 0x01
#define SPI_CLKDIV 0x02
#define SPI_TX 0x08 /* master only */
#define SPI_RX 0x10
#define SPI_USER0 0x20 /* slave only, first user register */

#define SPI_CONFIG_DISABLE (1 << 0)
#define SPI_CONFIG_IRQ_ENABLE (1 << 1)
#define SPI_CONFIG_CPOL (1 << 2)
#define SPI_CONFIG_CPHA (1 << 3)
#define SPI_CONFIG_LSB (1 << 4)
#define SPI_CONFIG_USER_REGS (1 << 5)/* slave only */

#define SPI_STATUS_SPLIT (1 << 0)
#define SPI_STATUS_STATE (3 << 1) /* master only */
#define SPI_STATUS_TX_FIFO_HALF_FULL (1 << 3) /* master only */

#define SPI_STATE_IDLE(status) ((status) & SPI_STATUS_STATE == 0)
#define SPI_STATE_SETUP(status) ((status) & SPI_STATUS_STATE == 1)
#define SPI_STATE_DATA(status) ((status) & SPI_STATUS_STATE == 2)
#define SPI_STATE_HOLD(status) ((status) & SPI_STATUS_STATE == 3)
/**
* spi_reg_write - Set SPI device register
*
* @param dev device structure
* @param reg register
* @param val value
*
*/
void spi_reg_write(spi_dev_t *dev, unsigned reg, uint8_t val);

/**
* spi_reg_read - Get SPI device register
*
* @param dev device structure
* @param reg register
*
* @return register value
*/
uint8_t spi_reg_write(spi_dev_t *dev, unsigned reg);

```
8 changes: 8 additions & 0 deletions src/spi/driver/spilib/spi-epiphany.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once
#ifndef _SPI_INTERNAL
# error "Don't include this file directly"
#endif

#include "spi-generic.h"

#error "Epiphany target not implemented"
149 changes: 149 additions & 0 deletions src/spi/driver/spilib/spi-generic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#pragma once
#ifndef _SPI_INTERNAL
# error "Don't include this file directly"
#endif

#include <stdint.h>
#include <string.h>

struct spi_generic_dev {
volatile uint8_t *regs;
};

__spi_unused
static void _spi_reg_write(struct spi_generic_dev *dev, unsigned reg,
uint32_t val)
{
if (reg & 3)
dev->regs[reg] = (uint8_t) val;
else
*(volatile uint32_t *) &dev->regs[reg] = val;

}

__spi_unused
static uint32_t _spi_reg_read(struct spi_generic_dev *dev, unsigned reg)
{
if (reg & 3)
return (uint32_t) dev->regs[reg];
else
return *(uint32_t *) &dev->regs[reg];
}

__spi_unused
static void _spi_transfer(struct spi_generic_dev *dev, const void *tx,
void *rx, unsigned count)
{
unsigned n;
const uint8_t *u8_tx = (const uint8_t *) tx;
uint8_t *u8_rx = (uint8_t *) rx;
uint8_t config;

/* TODO: Flush queues */

/* TODO: Enable TX */

/* TODO: Tell master to hold SS? */

config = _spi_reg_read(dev, SPI_CONFIG);

while (count) {
union acme {
uint32_t u32;
uint16_t u16[2];
uint8_t u8[4];
} __spi_packed;
union acme rx0, rx1, tx0, tx1;
volatile union acme *txfifo = (union acme *) &dev->regs[SPI_TX];

if (tx)
memcpy(&tx0.u32, u8_tx, count > 4 ? 4 : count);
if (tx && count > 4)
memcpy(&tx1.u32, &u8_tx[4], count - 4 > 4 ? 4 : count - 4);

/* Clear status register */
_spi_reg_write(dev, SPI_STATUS, 0);
while (_spi_reg_read(dev, SPI_STATUS))
;

/* Enable TX */
config &= ~SPI_CONFIG_DISABLE;
_spi_reg_write(dev, SPI_CONFIG, config);

/* Write TX data to TX fifo */
switch (count) {
case 1:
txfifo->u8[0] = tx0.u8[0];
count -= 1; n = 1;
break;
case 2:
txfifo->u16[0] = tx0.u16[0];
count -= 2; n = 2;
break;
case 3:
txfifo->u16[0] = tx0.u16[0];
txfifo->u8[0] = tx0.u8[3];
count -= 3; n = 3;
break;
case 4:
txfifo->u32 = tx0.u32;
count -= 4; n = 4;
break;
case 5:
txfifo->u32 = tx0.u32;
txfifo->u8[0] = tx1.u8[0];
count -= 5; n = 5;
break;
case 6:
txfifo->u32 = tx0.u32;
txfifo->u32 = tx1.u16[0];
count -= 6; n = 6;
break;
case 7:
txfifo->u32 = tx0.u32;
txfifo->u32 = tx1.u16[0];
txfifo->u32 = tx1.u8[3];
count -= 7; n = 7;
break;
default:
txfifo->u32 = tx0.u32;
txfifo->u32 = tx1.u32;
count -= 8; n = 8;
break;
};

/* Wait for transfer to complete */
while (_spi_reg_read(dev, SPI_STATUS) & SPI_STATUS_ACTIVE)
;
while (!(_spi_reg_read(dev, SPI_STATUS) & SPI_STATUS_SPLIT))
;

if (rx) {
uint8_t buf[8] = { 0 };
unsigned i, j;

/* Read deserializer */
rx0.u32 = *(uint32_t *) &dev->regs[SPI_RX0];
rx1.u32 = *(uint32_t *) &dev->regs[SPI_RX1];

memcpy(&buf[0], &rx0, 4);
memcpy(&buf[4], &rx1, 4);

/* Reverse bytes in transfer */
for (i = n - 1, j = 0; i > j; i--, j++) {
uint8_t tmp;
tmp = buf[i];
buf[i] = buf[j];
buf[j] = tmp;
}

memcpy(u8_rx, buf, n);
u8_rx += n;
}

}

_spi_reg_write(dev, SPI_STATUS, 0);

/* TODO: Tell master to release SS */
}
29 changes: 29 additions & 0 deletions src/spi/driver/spilib/spi-simple.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once
#ifndef _SPI_INTERNAL
# error "Don't include this file directly"
#endif

#include "spi-generic.h"

typedef struct spi_generic_dev spi_dev_t;

__spi_unused
static int spi_init(spi_dev_t *dev, void *arg)
{
if (!arg)
#ifdef SPI_SIMPLE_DEFAULT_ADDR
arg = (void *) SPI_SIMPLE_DEFAULT_ADDR;
#else
return -EINVAL;
#endif

dev->regs = (struct spi_registers *) arg;

return 0;
}

#define spi_fini(dev) /* nop */
#define spi_reg_write _spi_reg_write
#define spi_reg_read _spi_reg_read
#define spi_write _spi_write
#define spi_read _spi_read
Loading