modify spi protocol a bit for kernel driver work

This commit is contained in:
Triss 2021-07-15 04:01:42 +02:00
parent bad06fe9b4
commit 7e4bea1a37
6 changed files with 161 additions and 53 deletions

View File

@ -2,6 +2,7 @@
#include <stdio.h>
#include <hardware/clocks.h>
#include <hardware/spi.h>
#include <pico/binary_info.h>
#include <pico/stdlib.h>
@ -11,16 +12,18 @@
#include "m_default/serprog.h"
static bool cs_asserted;
//static bool cs_asserted;
static uint32_t freq;
static enum serprog_flags sflags;
static uint8_t bpw;
void sp_spi_init(void) {
cs_asserted = false;
//cs_asserted = false;
freq = 512*1000; // default to 512 kHz
sflags = 0; // CPOL 0, CPHA 0, 8bit
sflags = 0; // CPOL 0, CPHA 0, MSB first
bpw = 8;
spi_init(PINOUT_SPI_DEV, freq);
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_SPI);
@ -36,9 +39,10 @@ void sp_spi_init(void) {
bi_decl(bi_1pin_with_name(PINOUT_SPI_nCS, "SPI #CS"));
}
void sp_spi_deinit(void) {
cs_asserted = false;
//cs_asserted = false;
sflags = 0;
freq = 512*1000;
bpw = 8;
gpio_set_function(PINOUT_SPI_MISO, GPIO_FUNC_NULL);
gpio_set_function(PINOUT_SPI_MOSI, GPIO_FUNC_NULL);
@ -51,19 +55,61 @@ void sp_spi_deinit(void) {
spi_deinit(PINOUT_SPI_DEV);
}
uint32_t __not_in_flash_func(sp_spi_set_freq)(uint32_t freq_wanted) {
uint32_t sp_spi_set_freq(uint32_t freq_wanted) {
freq = spi_set_baudrate(PINOUT_SPI_DEV, freq_wanted);
return freq;
}
void __not_in_flash_func(sp_spi_set_flags)(enum serprog_flags flags) {
sflags = flags;
spi_set_format(PINOUT_SPI_DEV, (flags & S_FLG_16BIT) ? 16 : 8,
(flags & S_FLG_CPOL) ? SPI_CPOL_1 : SPI_CPOL_0,
(flags & S_FLG_CPHA) ? SPI_CPHA_1 : SPI_CPHA_0,
SPI_MSB_FIRST);
static void apply_settings(void) {
/*spi_set_format(PINOUT_SPI_DEV, bpw,
(sflags & S_FLG_CPOL) ? SPI_CPOL_1 : SPI_CPOL_0,
(sflags & S_FLG_CPHA) ? SPI_CPHA_1 : SPI_CPHA_0,
SPI_MSB_FIRST);*/
hw_write_masked(&spi_get_hw(PINOUT_SPI_DEV)->cr0,
((uint32_t)(bpw - 1) << SPI_SSPCR0_DSS_LSB)
| ((uint32_t)((sflags & S_FLG_CPOL) ? SPI_CPOL_1 : SPI_CPOL_0) << SPI_SSPCR0_SPO_LSB)
| ((uint32_t)((sflags & S_FLG_CPHA) ? SPI_CPHA_1 : SPI_CPHA_0) << SPI_SSPCR0_SPH_LSB)
| ((uint32_t)((sflags >> 2) & 3) << SPI_SSPCR0_FRF_LSB),
SPI_SSPCR0_DSS_BITS | SPI_SSPCR0_SPO_BITS | SPI_SSPCR0_SPH_BITS | SPI_SSPCR0_FRF_BITS
);
}
enum serprog_flags sp_spi_set_flags(enum serprog_flags flags) {
if ((flags & (3<<2)) == (3<<2)) flags &= ~(uint32_t)(3<<2); // change to moto if bad value
sflags = flags & ~S_FLG_LSBFST; // ignore LSB-first flag, we don't support it
apply_settings();
return sflags;
}
uint8_t sp_spi_set_bpw(uint8_t bpw_) {
bpw = bpw_;
if (bpw < 4) bpw = 4;
if (bpw > 16) bpw = 16;
apply_settings();
return bpw;
}
__attribute__((__const__)) const struct sp_spi_caps* sp_spi_get_caps(void) {
static struct sp_spi_caps caps = {
.freq_min = ~(uint32_t)0,
.freq_max = 0,
.num_cs = 1,
.min_bpw = 4,
.max_bpw = 16,
.caps = S_CAP_CPOL_HI | S_CAP_CPOL_LO | S_CAP_CPHA_HI | S_CAP_CPHA_LO
| S_CAP_MOTO | S_CAP_NATSEM | S_CAP_TI | S_CAP_MSBFST | S_CAP_LSBFST
| S_CAP_CSACHI
};
caps.freq_min = clock_get_hz(clk_peri) / 254;
caps.freq_max = clock_get_hz(clk_peri) / 1;
return &caps;
}
__attribute__((__const__))
int __not_in_flash_func(sp_spi_get_num_cs)(void) { return 1; }
void __not_in_flash_func(sp_spi_cs_deselect)(uint8_t csflags) {
(void)csflags;
@ -71,7 +117,7 @@ void __not_in_flash_func(sp_spi_cs_deselect)(uint8_t csflags) {
asm volatile("nop\nnop\nnop"); // idk if this is needed
gpio_put(PINOUT_SPI_nCS, 1);
asm volatile("nop\nnop\nnop"); // idk if this is needed
cs_asserted = false;
//cs_asserted = false;
}
void __not_in_flash_func(sp_spi_cs_select)(uint8_t csflags) {
(void)csflags;
@ -79,14 +125,15 @@ void __not_in_flash_func(sp_spi_cs_select)(uint8_t csflags) {
asm volatile("nop\nnop\nnop"); // idk if this is needed
gpio_put(PINOUT_SPI_nCS, 0);
asm volatile("nop\nnop\nnop"); // idk if this is needed
cs_asserted = true;
//cs_asserted = true;
}
void __not_in_flash_func(sp_spi_op_begin)(uint8_t csflags) {
// sp_spi_cs_select(csflags);
(void)csflags;
if (!cs_asserted) {
//if (!cs_asserted)
{
asm volatile("nop\nnop\nnop"); // idk if this is needed
gpio_put(PINOUT_SPI_nCS, 0);
asm volatile("nop\nnop\nnop"); // idk if this is needed
@ -96,7 +143,8 @@ void __not_in_flash_func(sp_spi_op_end)(uint8_t csflags) {
// sp_spi_cs_deselect(csflags);
(void)csflags;
if (!cs_asserted) { // YES, this condition is the intended one!
//if (!cs_asserted) { // YES, this condition is the intended one!
{
asm volatile("nop\nnop\nnop"); // idk if this is needed
gpio_put(PINOUT_SPI_nCS, 1);
asm volatile("nop\nnop\nnop"); // idk if this is needed
@ -104,24 +152,23 @@ void __not_in_flash_func(sp_spi_op_end)(uint8_t csflags) {
}
// TODO: use dma?
// TODO: routines for non-8/16-bit xfers??
void __not_in_flash_func(sp_spi_op_write)(uint32_t write_len, const void* write_data) {
if (sflags & S_FLG_16BIT) {
void sp_spi_op_write(uint32_t write_len, const void* write_data) {
if (bpw > 8) {
spi_write16_blocking(PINOUT_SPI_DEV, (const uint16_t*)write_data, write_len >> 1);
} else {
spi_write_blocking(PINOUT_SPI_DEV, (const uint8_t*)write_data, write_len);
}
}
void __not_in_flash_func(sp_spi_op_read)(uint32_t read_len, void* read_data) {
if (sflags & S_FLG_16BIT) {
void sp_spi_op_read(uint32_t read_len, void* read_data) {
if (bpw > 8) {
spi_read16_blocking(PINOUT_SPI_DEV, 0, (uint16_t*)read_data, read_len >> 1);
} else {
spi_read_blocking(PINOUT_SPI_DEV, 0, (uint8_t*)read_data, read_len);
}
}
void __not_in_flash_func(sp_spi_op_read_write)(uint32_t len, void* read_data,
void sp_spi_op_read_write(uint32_t len, void* read_data,
const void* write_data) {
if (sflags & S_FLG_16BIT) {
if (bpw > 8) {
spi_write16_read16_blocking(PINOUT_SPI_DEV, (const uint16_t*)write_data,
(uint16_t*)read_data, len >> 1);
} else {

View File

@ -1,5 +1,5 @@
obj-m := dmj.o dmj-char.o i2c-dmj.o
obj-m := dmj.o dmj-char.o i2c-dmj.o spi-dmj.c
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
@ -14,7 +14,10 @@ clean:
load:
sudo insmod ./dmj.ko
sudo insmod ./dmj-char.ko
sudo insmod ./spi-dmj.ko
unload:
sudo rmmod spi-dmj
sudo rmmod i2c-dmj
sudo rmmod dmj-char
sudo rmmod dmj

View File

@ -2,7 +2,7 @@
/*
* Driver for the DapperMime-JTAG USB multitool: base MFD driver
*
* Copyright (c) sys64738 and haskal
* Copyright (c) 2021 sys64738 and haskal
*
* Adapted from:
* dln2.c Copyright (c) 2014 Intel Corporation

View File

@ -2,7 +2,7 @@
/*
* Driver for the DapperMime-JTAG USB multitool: USB-I2C adapter
*
* Copyright (c) sys64738 and haskal
* Copyright (c) 2021 sys64738 and haskal
*
* Adapted from:
* i2c-dln2.c Copyright (c) 2014 Intel Corporation
@ -25,7 +25,7 @@
#define HARDWARE_NAME "DapperMime-JTAG"
#define DMJ_I2C_MAX_XSFER_SIZE 64
#define DMJ_I2C_MAX_XFER_SIZE 64
#define DMJ_I2C_CMD_ECHO 0x00
#define DMJ_I2C_CMD_GET_FUNC 0x01
@ -195,8 +195,8 @@ static const struct i2c_algorithm dmj_i2c_algo = {
.functionality = dmj_i2c_func
};
static const struct i2c_adapter_quirks dmj_i2c_quirks = {
.max_read_len = DMJ_I2C_MAX_XSFER_SIZE,
.max_write_len = DMJ_I2C_MAX_XSFER_SIZE,
.max_read_len = DMJ_I2C_MAX_XFER_SIZE,
.max_write_len = DMJ_I2C_MAX_XFER_SIZE,
};
static int dmj_i2c_check_hw(struct platform_device *pdev)

View File

@ -24,7 +24,7 @@ static const uint8_t serprog_cmdmap[32] = {
0, // 20..27
0, // 28..2f
0, // 30..37
0x3f, // cmd 40..45
0xff, // cmd 40..47
0, // rest is 0
};
// clang-format on
@ -162,7 +162,42 @@ static void handle_cmd(uint8_t cmd, uint8_t ud, uint8_t (*read_byte)(void),
tx_buf[4] = (nfreq >> 24) & 0xff;
nresp = 5;
} break;
case S_CMD_S_PINSTATE: {
case S_CMD_S_PINSTATE:
// that's not what this command is supposed to do, so, aaa
/*if (read_byte() == 0)
sp_spi_cs_deselect(selchip);
else
sp_spi_cs_select(selchip);*/
tx_buf[0] = S_ACK;
nresp = 1;
break;
case S_CMD_Q_SPI_CAPS: {
const struct sp_spi_caps* caps = sp_spi_get_caps();
tx_buf[0] = S_ACK;
tx_buf[1] = caps->freq_min & 0xff;
tx_buf[2] = (caps->freq_min >> 8) & 0xff;
tx_buf[3] = (caps->freq_min >> 16) & 0xff;
tx_buf[4] = (caps->freq_min >> 24) & 0xff;
tx_buf[5] = caps->freq_max & 0xff;
tx_buf[6] = (caps->freq_max >> 8) & 0xff;
tx_buf[7] = (caps->freq_max >> 16) & 0xff;
tx_buf[8] = (caps->freq_max >> 24) & 0xff;
tx_buf[9] = caps->caps & 0xff;
tx_buf[10] = (caps->caps >> 8) & 0xff;
tx_buf[11] = caps->num_cs;
tx_buf[12] = caps->min_bpw;
tx_buf[13] = caps->max_bpw;
nresp = 14;
} break;
case S_CMD_S_SPI_CHIPN:
selchip = read_byte();
tx_buf[0] = S_ACK;
nresp = 1;
break;
case S_CMD_S_SPI_SETCS:
if (read_byte() == 0)
sp_spi_cs_deselect(selchip);
else
@ -170,21 +205,15 @@ static void handle_cmd(uint8_t cmd, uint8_t ud, uint8_t (*read_byte)(void),
tx_buf[0] = S_ACK;
nresp = 1;
} break;
case S_CMD_Q_NUM_CS:
tx_buf[0] = S_ACK;
tx_buf[1] = sp_spi_get_num_cs();
nresp = 2;
break;
break;
case S_CMD_S_SPI_FLAGS:
sp_spi_set_flags(read_byte());
tx_buf[0] = S_ACK;
tx_buf[1] = sp_spi_set_flags(read_byte());
nresp = 1;
break;
case S_CMD_S_SPI_CHIPN:
selchip = read_byte();
case S_CMD_S_SPI_BPW:
tx_buf[0] = S_ACK;
tx_buf[1] = sp_spi_set_bpw(read_byte());
nresp = 1;
break;

View File

@ -28,22 +28,45 @@ enum serprog_cmd {
S_CMD_S_PINSTATE = 0x15,
// TODO: upstream this to flashrom? could be useful to others maybe
S_CMD_Q_NUM_CS = 0x40,
S_CMD_S_SPI_FLAGS = 0x41,
S_CMD_Q_SPI_CAPS = 0x40,
// number of chip (well, bitflags) to use when asserting/deasserting the chip select line
S_CMD_S_SPI_CHIPN = 0x42,
S_CMD_SPI_READ = 0x43,
S_CMD_SPI_WRITE = 0x44,
S_CMD_S_SPI_CHIPN = 0x41,
// sets chip select line high or low (device does no translation wrt. S_FLG_CSACHI!)
S_CMD_S_SPI_SETCS = 0x42,
S_CMD_S_SPI_FLAGS = 0x43,
S_CMD_S_SPI_BPW = 0x44, // set bits per word
S_CMD_SPI_READ = 0x45,
S_CMD_SPI_WRITE = 0x46,
// as opposed to S_CMD_SPIOP, this one is full-duplex instead of half-duplex
S_CMD_SPI_RDWR = 0x45,
S_CMD_SPI_RDWR = 0x47,
};
enum serprog_response { S_ACK = 0x06, S_NAK = 0x15 };
enum serprog_flags {
S_FLG_CPOL = 1<<0, // 1: clock polarity 1, else clkpol 0
S_FLG_CPHA = 1<<1, // 1: clock phase 1, else clkpha 1
S_FLG_16BIT = 1<<2, // 1: 16-bit transfers, else 8-bit xfers
S_FLG_CPHA = 1<<0, // 1: clock phase 1, else clkpha 1
S_FLG_CPOL = 1<<1, // 1: clock polarity 1, else clkpol 0
S_FLG_STDSPI = 0<<2, // frame format
S_FLG_TISSP = 1<<2, // frame format
S_FLG_MICROW = 2<<2, // frame format
S_FLG_MSBFST = 0<<4, // MSBit sent first
S_FLG_LSBFST = 1<<4, // LSBit sent first
S_FLG_CSACLO = 0<<5, // chip select active-low (common)
S_FLG_CSACHI = 1<<5, // chip select active-high
S_FLG_3WIRE = 1<<6,
};
enum serprog_caps {
S_CAP_CPHA_HI = 1<<0,
S_CAP_CPHA_LO = 1<<1,
S_CAP_CPOL_HI = 1<<2,
S_CAP_CPOL_LO = 1<<3,
S_CAP_STDSPI = 1<<4, // standard SPI
S_CAP_TISSP = 1<<5, // synchronous serial protocol from TI
S_CAP_MICROW = 1<<6, // microwire
S_CAP_MSBFST = 1<<7,
S_CAP_LSBFST = 1<<8,
S_CAP_CSACHI = 1<<9,
S_CAP_3WIRE = 1<<10,
};
#define SERPROG_IFACE_VERSION 0x0001
@ -51,9 +74,15 @@ enum serprog_flags {
#ifdef DBOARD_HAS_SPI
/* functions to be implemented by the BSP */
uint32_t /*freq_applied*/ sp_spi_set_freq(uint32_t freq_wanted);
enum serprog_flags sp_spi_set_flags(enum serprog_flags flags);
uint8_t sp_spi_set_bpw(uint8_t bpw);
void sp_spi_set_flags(enum serprog_flags flags);
__attribute__((__const__)) int sp_spi_get_num_cs(void);
struct sp_spi_caps {
uint32_t freq_min, freq_max;
uint16_t caps;
uint8_t num_cs, min_bpw, max_bpw;
};
__attribute__((__const__)) const struct sp_spi_caps* sp_spi_get_caps(void);
void sp_spi_init(void);
void sp_spi_deinit(void);