forked from M-Labs/artiq
add kernel access to non-realtime SPI buses (#740)
This commit is contained in:
parent
424b2bfbd8
commit
8399f8893d
@ -30,6 +30,9 @@ def i2c_read(busno: TInt32, ack: TBool) -> TInt32:
|
||||
class PCA9548:
|
||||
"""Driver for the PCA9548 I2C bus switch.
|
||||
|
||||
I2C transactions not real-time, and are performed by the CPU without
|
||||
involving RTIO.
|
||||
|
||||
On the KC705, this chip is used for selecting the I2C buses on the two FMC
|
||||
connectors. HPC=1, LPC=2.
|
||||
"""
|
||||
@ -72,6 +75,9 @@ class PCA9548:
|
||||
class TCA6424A:
|
||||
"""Driver for the TCA6424A I2C I/O expander.
|
||||
|
||||
I2C transactions not real-time, and are performed by the CPU without
|
||||
involving RTIO.
|
||||
|
||||
On the NIST QC2 hardware, this chip is used for switching the directions
|
||||
of TTL buffers."""
|
||||
def __init__(self, dmgr, busno=0, address=0x44, core_device="core"):
|
||||
|
@ -1,10 +1,20 @@
|
||||
import numpy
|
||||
|
||||
from artiq.language.core import kernel, portable, now_mu, delay_mu
|
||||
from artiq.language.core import syscall, kernel, portable, now_mu, delay_mu
|
||||
from artiq.language.types import TInt32, TNone
|
||||
from artiq.language.units import MHz
|
||||
from artiq.coredevice.rtio import rtio_output, rtio_input_data
|
||||
|
||||
|
||||
__all__ = [
|
||||
"SPI_DATA_ADDR", "SPI_XFER_ADDR", "SPI_CONFIG_ADDR",
|
||||
"SPI_OFFLINE", "SPI_ACTIVE", "SPI_PENDING",
|
||||
"SPI_CS_POLARITY", "SPI_CLK_POLARITY", "SPI_CLK_PHASE",
|
||||
"SPI_LSB_FIRST", "SPI_HALF_DUPLEX",
|
||||
"SPIMaster", "NRTSPIMaster"
|
||||
]
|
||||
|
||||
|
||||
SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3)
|
||||
(
|
||||
SPI_OFFLINE,
|
||||
@ -262,3 +272,65 @@ class SPIMaster:
|
||||
rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR | SPI_RT2WB_READ,
|
||||
0)
|
||||
return rtio_input_data(self.channel)
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def spi_set_config(busno: TInt32, flags: TInt32, write_div: TInt32, read_div: TInt32) -> TNone:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def spi_set_xfer(busno: TInt32, chip_select: TInt32, write_length: TInt32, read_length: TInt32) -> TNone:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def spi_write(busno: TInt32, data: TInt32) -> TNone:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
@syscall(flags={"nounwind", "nowrite"})
|
||||
def spi_read(busno: TInt32) -> TInt32:
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
||||
|
||||
class NRTSPIMaster:
|
||||
"""Core device non-realtime Serial Peripheral Interface (SPI) bus master.
|
||||
Owns one non-realtime SPI bus.
|
||||
|
||||
With this driver, SPI transactions and are performed by the CPU without
|
||||
involving RTIO.
|
||||
|
||||
Realtime and non-realtime buses are separate and defined at bitstream
|
||||
compilation time.
|
||||
|
||||
See :class:`SPIMaster` for a description of the methods.
|
||||
"""
|
||||
def __init__(self, dmgr, busno, core_device="core"):
|
||||
self.core = dmgr.get(core_device)
|
||||
self.busno = busno
|
||||
|
||||
@kernel
|
||||
def set_config_mu(self, flags=0, write_div=6, read_div=6):
|
||||
"""Set the ``config`` register.
|
||||
|
||||
Note that the non-realtime SPI cores are usually clocked by the system
|
||||
clock and not the RTIO clock. In many cases, the SPI configuration is
|
||||
already set by the firmware and you do not need to call this method.
|
||||
|
||||
The offline bit cannot be set using this method.
|
||||
The SPI bus is briefly taken offline when this method is called.
|
||||
"""
|
||||
spi_set_config(self.busno, flags, write_div, read_div)
|
||||
|
||||
@kernel
|
||||
def set_xfer(self, chip_select=0, write_length=0, read_length=0):
|
||||
spi_set_xfer(self.busno, chip_select, write_length, read_length)
|
||||
|
||||
@kernel
|
||||
def write(self, data=0):
|
||||
spi_write(self.busno, data)
|
||||
|
||||
@kernel
|
||||
def read(self):
|
||||
return spi_read(self.busno)
|
||||
|
@ -117,8 +117,13 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||
api!(drtio_get_packet_counts = ::rtio::drtio_dbg::get_packet_counts),
|
||||
api!(drtio_get_fifo_space_req_count = ::rtio::drtio_dbg::get_fifo_space_req_count),
|
||||
|
||||
api!(i2c_start = ::i2c_start),
|
||||
api!(i2c_stop = ::i2c_stop),
|
||||
api!(i2c_write = ::i2c_write),
|
||||
api!(i2c_read = ::i2c_read),
|
||||
api!(i2c_start = ::nrt_bus::i2c::start),
|
||||
api!(i2c_stop = ::nrt_bus::i2c::stop),
|
||||
api!(i2c_write = ::nrt_bus::i2c::write),
|
||||
api!(i2c_read = ::nrt_bus::i2c::read),
|
||||
|
||||
api!(spi_set_config = ::nrt_bus::spi::set_config),
|
||||
api!(spi_set_xfer = ::nrt_bus::spi::set_xfer),
|
||||
api!(spi_write = ::nrt_bus::spi::write),
|
||||
api!(spi_read = ::nrt_bus::spi::read),
|
||||
];
|
||||
|
@ -89,6 +89,7 @@ macro_rules! raise {
|
||||
pub mod eh;
|
||||
mod api;
|
||||
mod rtio;
|
||||
mod nrt_bus;
|
||||
|
||||
static mut NOW: u64 = 0;
|
||||
static mut LIBRARY: Option<Library<'static>> = None;
|
||||
@ -220,24 +221,6 @@ extern fn cache_put(key: CSlice<u8>, list: CSlice<i32>) {
|
||||
})
|
||||
}
|
||||
|
||||
extern fn i2c_start(busno: i32) {
|
||||
send(&I2cStartRequest { busno: busno as u8 });
|
||||
}
|
||||
|
||||
extern fn i2c_stop(busno: i32) {
|
||||
send(&I2cStopRequest { busno: busno as u8 });
|
||||
}
|
||||
|
||||
extern fn i2c_write(busno: i32, data: i32) -> bool {
|
||||
send(&I2cWriteRequest { busno: busno as u8, data: data as u8 });
|
||||
recv!(&I2cWriteReply { ack } => ack)
|
||||
}
|
||||
|
||||
extern fn i2c_read(busno: i32, ack: bool) -> i32 {
|
||||
send(&I2cReadRequest { busno: busno as u8, ack: ack });
|
||||
recv!(&I2cReadReply { data } => data) as i32
|
||||
}
|
||||
|
||||
const DMA_BUFFER_SIZE: usize = 64 * 1024;
|
||||
|
||||
struct DmaRecorder {
|
||||
|
48
artiq/firmware/ksupport/nrt_bus.rs
Normal file
48
artiq/firmware/ksupport/nrt_bus.rs
Normal file
@ -0,0 +1,48 @@
|
||||
pub mod i2c {
|
||||
use ::send;
|
||||
use ::recv;
|
||||
use kernel_proto::*;
|
||||
|
||||
pub extern fn start(busno: i32) {
|
||||
send(&I2cStartRequest { busno: busno as u8 });
|
||||
}
|
||||
|
||||
pub extern fn stop(busno: i32) {
|
||||
send(&I2cStopRequest { busno: busno as u8 });
|
||||
}
|
||||
|
||||
pub extern fn write(busno: i32, data: i32) -> bool {
|
||||
send(&I2cWriteRequest { busno: busno as u8, data: data as u8 });
|
||||
recv!(&I2cWriteReply { ack } => ack)
|
||||
}
|
||||
|
||||
pub extern fn read(busno: i32, ack: bool) -> i32 {
|
||||
send(&I2cReadRequest { busno: busno as u8, ack: ack });
|
||||
recv!(&I2cReadReply { data } => data) as i32
|
||||
}
|
||||
}
|
||||
|
||||
pub mod spi {
|
||||
use ::send;
|
||||
use ::recv;
|
||||
use kernel_proto::*;
|
||||
|
||||
pub extern fn set_config(busno: i32, flags: i32, write_div: i32, read_div: i32) {
|
||||
send(&SpiSetConfigRequest { busno: busno as u32, flags: flags as u8,
|
||||
write_div: write_div as u8, read_div: read_div as u8 });
|
||||
}
|
||||
|
||||
pub extern fn set_xfer(busno: i32, chip_select: i32, write_length: i32, read_length: i32) {
|
||||
send(&SpiSetXferRequest { busno: busno as u32, chip_select: chip_select as u16,
|
||||
write_length: write_length as u8, read_length: read_length as u8 });
|
||||
}
|
||||
|
||||
pub extern fn write(busno: i32, data: i32) {
|
||||
send(&SpiWriteRequest { busno: busno as u32, data: data as u32 });
|
||||
}
|
||||
|
||||
pub extern fn read(busno: i32) -> i32 {
|
||||
send(&SpiReadRequest { busno: busno as u32 });
|
||||
recv!(&SpiReadReply { data } => data) as i32
|
||||
}
|
||||
}
|
@ -1,147 +1,171 @@
|
||||
use csr;
|
||||
use clock;
|
||||
|
||||
fn half_period() { clock::spin_us(100) }
|
||||
fn sda_bit(busno: u8) -> u8 { 1 << (2 * busno + 1) }
|
||||
fn scl_bit(busno: u8) -> u8 { 1 << (2 * busno) }
|
||||
#[cfg(has_i2c)]
|
||||
mod io {
|
||||
use csr;
|
||||
use clock;
|
||||
|
||||
fn sda_i(busno: u8) -> bool {
|
||||
unsafe {
|
||||
csr::i2c::in_read() & sda_bit(busno) != 0
|
||||
}
|
||||
}
|
||||
|
||||
fn sda_oe(busno: u8, oe: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::oe_read();
|
||||
let reg = if oe { reg | sda_bit(busno) } else { reg & !sda_bit(busno) };
|
||||
csr::i2c::oe_write(reg)
|
||||
}
|
||||
}
|
||||
|
||||
fn sda_o(busno: u8, o: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::out_read();
|
||||
let reg = if o { reg | sda_bit(busno) } else { reg & !sda_bit(busno) };
|
||||
csr::i2c::out_write(reg)
|
||||
}
|
||||
}
|
||||
|
||||
fn scl_oe(busno: u8, oe: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::oe_read();
|
||||
let reg = if oe { reg | scl_bit(busno) } else { reg & !scl_bit(busno) };
|
||||
csr::i2c::oe_write(reg)
|
||||
}
|
||||
}
|
||||
|
||||
fn scl_o(busno: u8, o: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::out_read();
|
||||
let reg = if o { reg | scl_bit(busno) } else { reg & !scl_bit(busno) };
|
||||
csr::i2c::out_write(reg)
|
||||
pub fn half_period() { clock::spin_us(100) }
|
||||
fn sda_bit(busno: u8) -> u8 { 1 << (2 * busno + 1) }
|
||||
fn scl_bit(busno: u8) -> u8 { 1 << (2 * busno) }
|
||||
|
||||
pub fn sda_i(busno: u8) -> bool {
|
||||
unsafe {
|
||||
csr::i2c::in_read() & sda_bit(busno) != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sda_oe(busno: u8, oe: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::oe_read();
|
||||
let reg = if oe { reg | sda_bit(busno) } else { reg & !sda_bit(busno) };
|
||||
csr::i2c::oe_write(reg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sda_o(busno: u8, o: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::out_read();
|
||||
let reg = if o { reg | sda_bit(busno) } else { reg & !sda_bit(busno) };
|
||||
csr::i2c::out_write(reg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scl_oe(busno: u8, oe: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::oe_read();
|
||||
let reg = if oe { reg | scl_bit(busno) } else { reg & !scl_bit(busno) };
|
||||
csr::i2c::oe_write(reg)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scl_o(busno: u8, o: bool) {
|
||||
unsafe {
|
||||
let reg = csr::i2c::out_read();
|
||||
let reg = if o { reg | scl_bit(busno) } else { reg & !scl_bit(busno) };
|
||||
csr::i2c::out_write(reg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
pub fn init() {
|
||||
for busno in 0..csr::CONFIG_I2C_BUS_COUNT {
|
||||
let busno = busno as u8;
|
||||
// Set SCL as output, and high level
|
||||
scl_o(busno, true);
|
||||
scl_oe(busno, true);
|
||||
io::scl_o(busno, true);
|
||||
io::scl_oe(busno, true);
|
||||
// Prepare a zero level on SDA so that sda_oe pulls it down
|
||||
sda_o(busno, false);
|
||||
io::sda_o(busno, false);
|
||||
// Release SDA
|
||||
sda_oe(busno, false);
|
||||
io::sda_oe(busno, false);
|
||||
|
||||
// Check the I2C bus is ready
|
||||
half_period();
|
||||
half_period();
|
||||
if !sda_i(busno) {
|
||||
io::half_period();
|
||||
io::half_period();
|
||||
if !io::sda_i(busno) {
|
||||
error!("SDA is stuck low on bus #{}", busno)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
pub fn start(busno: u8) {
|
||||
// Set SCL high then SDA low
|
||||
scl_o(busno, true);
|
||||
half_period();
|
||||
sda_oe(busno, true);
|
||||
half_period();
|
||||
io::scl_o(busno, true);
|
||||
io::half_period();
|
||||
io::sda_oe(busno, true);
|
||||
io::half_period();
|
||||
}
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
pub fn restart(busno: u8) {
|
||||
// Set SCL low then SDA high */
|
||||
scl_o(busno, false);
|
||||
half_period();
|
||||
sda_oe(busno, false);
|
||||
half_period();
|
||||
io::scl_o(busno, false);
|
||||
io::half_period();
|
||||
io::sda_oe(busno, false);
|
||||
io::half_period();
|
||||
// Do a regular start
|
||||
start(busno);
|
||||
}
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
pub fn stop(busno: u8) {
|
||||
// First, make sure SCL is low, so that the target releases the SDA line
|
||||
scl_o(busno, false);
|
||||
half_period();
|
||||
io::scl_o(busno, false);
|
||||
io::half_period();
|
||||
// Set SCL high then SDA high
|
||||
sda_oe(busno, true);
|
||||
scl_o(busno, true);
|
||||
half_period();
|
||||
sda_oe(busno, false);
|
||||
half_period();
|
||||
io::sda_oe(busno, true);
|
||||
io::scl_o(busno, true);
|
||||
io::half_period();
|
||||
io::sda_oe(busno, false);
|
||||
io::half_period();
|
||||
}
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
pub fn write(busno: u8, data: u8) -> bool {
|
||||
// MSB first
|
||||
for bit in (0..8).rev() {
|
||||
// Set SCL low and set our bit on SDA
|
||||
scl_o(busno, false);
|
||||
sda_oe(busno, data & (1 << bit) == 0);
|
||||
half_period();
|
||||
io::scl_o(busno, false);
|
||||
io::sda_oe(busno, data & (1 << bit) == 0);
|
||||
io::half_period();
|
||||
// Set SCL high ; data is shifted on the rising edge of SCL
|
||||
scl_o(busno, true);
|
||||
half_period();
|
||||
io::scl_o(busno, true);
|
||||
io::half_period();
|
||||
}
|
||||
// Check ack
|
||||
// Set SCL low, then release SDA so that the I2C target can respond
|
||||
scl_o(busno, false);
|
||||
half_period();
|
||||
sda_oe(busno, false);
|
||||
io::scl_o(busno, false);
|
||||
io::half_period();
|
||||
io::sda_oe(busno, false);
|
||||
// Set SCL high and check for ack
|
||||
scl_o(busno, true);
|
||||
half_period();
|
||||
io::scl_o(busno, true);
|
||||
io::half_period();
|
||||
// returns true if acked (I2C target pulled SDA low)
|
||||
!sda_i(busno)
|
||||
!io::sda_i(busno)
|
||||
}
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
pub fn read(busno: u8, ack: bool) -> u8 {
|
||||
// Set SCL low first, otherwise setting SDA as input may cause a transition
|
||||
// on SDA with SCL high which will be interpreted as START/STOP condition.
|
||||
scl_o(busno, false);
|
||||
half_period(); // make sure SCL has settled low
|
||||
sda_oe(busno, false);
|
||||
io::scl_o(busno, false);
|
||||
io::half_period(); // make sure SCL has settled low
|
||||
io::sda_oe(busno, false);
|
||||
|
||||
let mut data: u8 = 0;
|
||||
|
||||
// MSB first
|
||||
for bit in (0..8).rev() {
|
||||
scl_o(busno, false);
|
||||
half_period();
|
||||
io::scl_o(busno, false);
|
||||
io::half_period();
|
||||
// Set SCL high and shift data
|
||||
scl_o(busno, true);
|
||||
half_period();
|
||||
if sda_i(busno) { data |= 1 << bit }
|
||||
io::scl_o(busno, true);
|
||||
io::half_period();
|
||||
if io::sda_i(busno) { data |= 1 << bit }
|
||||
}
|
||||
// Send ack
|
||||
// Set SCL low and pull SDA low when acking
|
||||
scl_o(busno, false);
|
||||
if ack { sda_oe(busno, true) }
|
||||
half_period();
|
||||
io::scl_o(busno, false);
|
||||
if ack { io::sda_oe(busno, true) }
|
||||
io::half_period();
|
||||
// then set SCL high
|
||||
scl_o(busno, true);
|
||||
half_period();
|
||||
io::scl_o(busno, true);
|
||||
io::half_period();
|
||||
|
||||
data
|
||||
}
|
||||
|
||||
#[cfg(not(has_i2c))]
|
||||
pub fn init() {}
|
||||
#[cfg(not(has_i2c))]
|
||||
pub fn start(_busno: u8) {}
|
||||
#[cfg(not(has_i2c))]
|
||||
pub fn restart(_busno: u8) {}
|
||||
#[cfg(not(has_i2c))]
|
||||
pub fn stop(_busno: u8) {}
|
||||
#[cfg(not(has_i2c))]
|
||||
pub fn write(_busno: u8, _data: u8) -> bool { false }
|
||||
#[cfg(not(has_i2c))]
|
||||
pub fn read(_busno: u8, _ack: bool) { 0xff }
|
||||
|
@ -19,8 +19,9 @@ pub mod uart_console;
|
||||
#[cfg(has_spiflash)]
|
||||
pub mod spiflash;
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
pub mod i2c;
|
||||
pub mod spi;
|
||||
|
||||
#[cfg(has_si5324)]
|
||||
pub mod si5324;
|
||||
|
||||
|
54
artiq/firmware/libboard/spi.rs
Normal file
54
artiq/firmware/libboard/spi.rs
Normal file
@ -0,0 +1,54 @@
|
||||
#[cfg(has_converter_spi)]
|
||||
use csr;
|
||||
|
||||
// Later this module should support other buses than the converter SPI bus,
|
||||
// and add a busno parameter to differentiate them.
|
||||
|
||||
#[cfg(has_converter_spi)]
|
||||
pub fn set_config(flags: u8, write_div: u8, read_div: u8) {
|
||||
unsafe {
|
||||
csr::converter_spi::offline_write(1);
|
||||
csr::converter_spi::cs_polarity_write(flags >> 3 & 1);
|
||||
csr::converter_spi::clk_polarity_write(flags >> 4 & 1);
|
||||
csr::converter_spi::clk_phase_write(flags >> 5 & 1);
|
||||
csr::converter_spi::lsb_first_write(flags >> 6 & 1);
|
||||
csr::converter_spi::half_duplex_write(flags >> 7 & 1);
|
||||
csr::converter_spi::clk_div_write_write(write_div);
|
||||
csr::converter_spi::clk_div_read_write(read_div);
|
||||
csr::converter_spi::offline_write(0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_converter_spi)]
|
||||
pub fn set_xfer(chip_select: u16, write_length: u8, read_length: u8) {
|
||||
unsafe {
|
||||
csr::converter_spi::cs_write(chip_select as _);
|
||||
csr::converter_spi::xfer_len_write_write(write_length);
|
||||
csr::converter_spi::xfer_len_read_write(read_length);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_converter_spi)]
|
||||
pub fn write(data: u32) {
|
||||
unsafe {
|
||||
csr::converter_spi::data_write_write(data);
|
||||
while csr::converter_spi::pending_read() != 0 {}
|
||||
while csr::converter_spi::active_read() != 0 {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(has_converter_spi)]
|
||||
pub fn read() -> u32 {
|
||||
unsafe {
|
||||
csr::converter_spi::data_read_read()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(has_converter_spi))]
|
||||
pub fn set_config(_flags: u8, _write_div: u8, _read_div: u8) {}
|
||||
#[cfg(not(has_converter_spi))]
|
||||
pub fn set_xfer(_chip_select: u16, _write_length: u8, _read_length: u8) {}
|
||||
#[cfg(not(has_converter_spi))]
|
||||
pub fn write(_data: u32) {}
|
||||
#[cfg(not(has_converter_spi))]
|
||||
pub fn read() -> u32 { 0 }
|
@ -87,6 +87,12 @@ pub enum Message<'a> {
|
||||
I2cReadRequest { busno: u8, ack: bool },
|
||||
I2cReadReply { data: u8 },
|
||||
|
||||
SpiSetConfigRequest { busno: u32, flags: u8, write_div: u8, read_div: u8 },
|
||||
SpiSetXferRequest { busno: u32, chip_select: u16, write_length: u8, read_length: u8 },
|
||||
SpiWriteRequest { busno: u32, data: u32 },
|
||||
SpiReadRequest { busno: u32 },
|
||||
SpiReadReply { data: u32 },
|
||||
|
||||
Log(fmt::Arguments<'a>),
|
||||
LogSlice(&'a str)
|
||||
}
|
||||
|
123
artiq/firmware/runtime/kern_hwreq.rs
Normal file
123
artiq/firmware/runtime/kern_hwreq.rs
Normal file
@ -0,0 +1,123 @@
|
||||
use session::{kern_acknowledge, kern_send};
|
||||
use rtio_mgt;
|
||||
use board;
|
||||
use kernel_proto as kern;
|
||||
use std::io;
|
||||
use sched::Io;
|
||||
|
||||
// TODO
|
||||
mod drtio_spi {
|
||||
pub fn set_config(_busno: u32, _flags: u8, _write_div: u8, _read_div: u8) {}
|
||||
pub fn set_xfer(_busno: u32, _chip_select: u16, _write_length: u8, _read_length: u8) {}
|
||||
pub fn write(_busno: u32, _data: u32) {}
|
||||
pub fn read(_busno: u32) -> u32 { 0 }
|
||||
}
|
||||
|
||||
mod spi {
|
||||
use board;
|
||||
use super::drtio_spi;
|
||||
|
||||
pub fn set_config(busno: u32, flags: u8, write_div: u8, read_div: u8) {
|
||||
let drtio = busno >> 16;
|
||||
if drtio == 0 {
|
||||
board::spi::set_config(flags, write_div, read_div)
|
||||
} else {
|
||||
drtio_spi::set_config(busno, flags, write_div, read_div)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_xfer(busno: u32, chip_select: u16, write_length: u8, read_length: u8) {
|
||||
let drtio = busno >> 16;
|
||||
if drtio == 0 {
|
||||
board::spi::set_xfer(chip_select, write_length, read_length)
|
||||
} else {
|
||||
drtio_spi::set_xfer(busno, chip_select, write_length, read_length)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(busno: u32, data: u32) {
|
||||
let drtio = busno >> 16;
|
||||
if drtio == 0 {
|
||||
board::spi::write(data)
|
||||
} else {
|
||||
drtio_spi::write(busno, data)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(busno: u32) -> u32 {
|
||||
let drtio = busno >> 16;
|
||||
if drtio == 0 {
|
||||
board::spi::read()
|
||||
} else {
|
||||
drtio_spi::read(busno)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result<bool> {
|
||||
match request {
|
||||
&kern::RtioInitRequest => {
|
||||
info!("resetting RTIO");
|
||||
rtio_mgt::init_core();
|
||||
kern_acknowledge()
|
||||
}
|
||||
|
||||
&kern::DrtioChannelStateRequest { channel } => {
|
||||
let (fifo_space, last_timestamp) = rtio_mgt::drtio_dbg::get_channel_state(channel);
|
||||
kern_send(io, &kern::DrtioChannelStateReply { fifo_space: fifo_space,
|
||||
last_timestamp: last_timestamp })
|
||||
}
|
||||
&kern::DrtioResetChannelStateRequest { channel } => {
|
||||
rtio_mgt::drtio_dbg::reset_channel_state(channel);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::DrtioGetFifoSpaceRequest { channel } => {
|
||||
rtio_mgt::drtio_dbg::get_fifo_space(channel);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::DrtioPacketCountRequest => {
|
||||
let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts();
|
||||
kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt })
|
||||
}
|
||||
&kern::DrtioFifoSpaceReqCountRequest => {
|
||||
let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count();
|
||||
kern_send(io, &kern::DrtioFifoSpaceReqCountReply { cnt: cnt })
|
||||
}
|
||||
|
||||
&kern::I2cStartRequest { busno } => {
|
||||
board::i2c::start(busno);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::I2cStopRequest { busno } => {
|
||||
board::i2c::stop(busno);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::I2cWriteRequest { busno, data } => {
|
||||
let ack = board::i2c::write(busno, data);
|
||||
kern_send(io, &kern::I2cWriteReply { ack: ack })
|
||||
}
|
||||
&kern::I2cReadRequest { busno, ack } => {
|
||||
let data = board::i2c::read(busno, ack);
|
||||
kern_send(io, &kern::I2cReadReply { data: data })
|
||||
},
|
||||
|
||||
&kern::SpiSetConfigRequest { busno, flags, write_div, read_div } => {
|
||||
spi::set_config(busno, flags, write_div, read_div);
|
||||
kern_acknowledge()
|
||||
},
|
||||
&kern::SpiSetXferRequest { busno, chip_select, write_length, read_length } => {
|
||||
spi::set_xfer(busno, chip_select, write_length, read_length);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::SpiWriteRequest { busno, data } => {
|
||||
spi::write(busno, data);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::SpiReadRequest { busno } => {
|
||||
let data = spi::read(busno);
|
||||
kern_send(io, &kern::SpiReadReply { data: data })
|
||||
},
|
||||
|
||||
_ => return Ok(false)
|
||||
}.and(Ok(true))
|
||||
}
|
@ -47,6 +47,7 @@ mod rtio_dma;
|
||||
|
||||
mod mgmt;
|
||||
mod kernel;
|
||||
mod kern_hwreq;
|
||||
mod session;
|
||||
#[cfg(any(has_rtio_moninj, has_drtio))]
|
||||
mod moninj;
|
||||
|
@ -15,6 +15,7 @@ use board;
|
||||
use rpc_proto as rpc;
|
||||
use session_proto as host;
|
||||
use kernel_proto as kern;
|
||||
use kern_hwreq;
|
||||
|
||||
macro_rules! unexpected {
|
||||
($($arg:tt)*) => {
|
||||
@ -125,7 +126,7 @@ fn host_write(stream: &mut Write, reply: host::Reply) -> io::Result<()> {
|
||||
reply.write_to(stream)
|
||||
}
|
||||
|
||||
fn kern_send(io: &Io, request: &kern::Message) -> io::Result<()> {
|
||||
pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<()> {
|
||||
match request {
|
||||
&kern::LoadRequest(_) => debug!("comm->kern LoadRequest(...)"),
|
||||
&kern::DmaRetrieveReply { trace, duration } => {
|
||||
@ -176,7 +177,7 @@ fn kern_recv<R, F>(io: &Io, f: F) -> io::Result<R>
|
||||
})
|
||||
}
|
||||
|
||||
fn kern_acknowledge() -> io::Result<()> {
|
||||
pub fn kern_acknowledge() -> io::Result<()> {
|
||||
mailbox::acknowledge();
|
||||
Ok(())
|
||||
}
|
||||
@ -364,6 +365,9 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>,
|
||||
}
|
||||
|
||||
kern_recv_dotrace(request);
|
||||
if kern_hwreq::process_kern_hwreq(io, request)? {
|
||||
return Ok(false)
|
||||
}
|
||||
match request {
|
||||
&kern::Log(args) => {
|
||||
use std::fmt::Write;
|
||||
@ -387,12 +391,6 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>,
|
||||
kern_acknowledge()
|
||||
}
|
||||
|
||||
&kern::RtioInitRequest => {
|
||||
info!("resetting RTIO");
|
||||
rtio_mgt::init_core();
|
||||
kern_acknowledge()
|
||||
}
|
||||
|
||||
&kern::DmaRecordStart(name) => {
|
||||
session.congress.dma_manager.record_start(name);
|
||||
kern_acknowledge()
|
||||
@ -419,28 +417,6 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>,
|
||||
})
|
||||
}
|
||||
|
||||
&kern::DrtioChannelStateRequest { channel } => {
|
||||
let (fifo_space, last_timestamp) = rtio_mgt::drtio_dbg::get_channel_state(channel);
|
||||
kern_send(io, &kern::DrtioChannelStateReply { fifo_space: fifo_space,
|
||||
last_timestamp: last_timestamp })
|
||||
}
|
||||
&kern::DrtioResetChannelStateRequest { channel } => {
|
||||
rtio_mgt::drtio_dbg::reset_channel_state(channel);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::DrtioGetFifoSpaceRequest { channel } => {
|
||||
rtio_mgt::drtio_dbg::get_fifo_space(channel);
|
||||
kern_acknowledge()
|
||||
}
|
||||
&kern::DrtioPacketCountRequest => {
|
||||
let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts();
|
||||
kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt })
|
||||
}
|
||||
&kern::DrtioFifoSpaceReqCountRequest => {
|
||||
let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count();
|
||||
kern_send(io, &kern::DrtioFifoSpaceReqCountReply { cnt: cnt })
|
||||
}
|
||||
|
||||
&kern::WatchdogSetRequest { ms } => {
|
||||
let id = session.watchdog_set.set_ms(ms)
|
||||
.map_err(|()| io_error("out of watchdogs"))?;
|
||||
@ -478,44 +454,6 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>,
|
||||
kern_send(io, &kern::CachePutReply { succeeded: succeeded })
|
||||
}
|
||||
|
||||
#[cfg(has_i2c)]
|
||||
&kern::I2cStartRequest { busno } => {
|
||||
board::i2c::start(busno);
|
||||
kern_acknowledge()
|
||||
}
|
||||
#[cfg(has_i2c)]
|
||||
&kern::I2cStopRequest { busno } => {
|
||||
board::i2c::stop(busno);
|
||||
kern_acknowledge()
|
||||
}
|
||||
#[cfg(has_i2c)]
|
||||
&kern::I2cWriteRequest { busno, data } => {
|
||||
let ack = board::i2c::write(busno, data);
|
||||
kern_send(io, &kern::I2cWriteReply { ack: ack })
|
||||
}
|
||||
#[cfg(has_i2c)]
|
||||
&kern::I2cReadRequest { busno, ack } => {
|
||||
let data = board::i2c::read(busno, ack);
|
||||
kern_send(io, &kern::I2cReadReply { data: data })
|
||||
}
|
||||
|
||||
#[cfg(not(has_i2c))]
|
||||
&kern::I2cStartRequest { .. } => {
|
||||
kern_acknowledge()
|
||||
}
|
||||
#[cfg(not(has_i2c))]
|
||||
&kern::I2cStopRequest { .. } => {
|
||||
kern_acknowledge()
|
||||
}
|
||||
#[cfg(not(has_i2c))]
|
||||
&kern::I2cWriteRequest { .. } => {
|
||||
kern_send(io, &kern::I2cWriteReply { ack: false })
|
||||
}
|
||||
#[cfg(not(has_i2c))]
|
||||
&kern::I2cReadRequest { .. } => {
|
||||
kern_send(io, &kern::I2cReadReply { data: 0xff })
|
||||
}
|
||||
|
||||
&kern::RunFinished => {
|
||||
unsafe { kernel::stop() }
|
||||
session.kernel_state = KernelState::Absent;
|
||||
|
Loading…
Reference in New Issue
Block a user