Compare commits

..

No commits in common. "master" and "csrmap" have entirely different histories.

11 changed files with 484 additions and 666 deletions

View File

@ -1,141 +0,0 @@
# Fix for bus error issues when compiling cpython extensions in pyrp3 v1.2.0+
# Patch sourced from: https://github.com/linien-org/pyrp3/tree/e6688acf8bd79d2dbe1d192d09c1a1baf1f6c67b (setup.py & monitor/Makefile)
# Reference: https://github.com/elhep/Fast-Servo-Firmware/blob/master/OS/scripts/linien_install_requirements.sh#L28
diff --git a/monitor/Makefile b/monitor/Makefile
new file mode 100644
index 0000000..044d88e
--- /dev/null
+++ b/monitor/Makefile
@@ -0,0 +1,31 @@
+# Makefile for libmonitor
+
+OBJS = monitor.o
+SRCS = $(subst .o,.c, $(OBJS))
+OSOBJS = monitor.os
+TARGETLIB=libmonitor.so
+CFLAGS=-g -std=gnu99 -Wall -Werror
+LIBS=-lm -lpthread
+
+# Use CROSS_COMPILE=arm-linux-gnueabi-
+CC=$(CROSS_COMPILE)gcc
+INSTALL_DIR ?= .
+
+
+all: $(TARGETLIB)
+lib: $(TARGETLIB)
+
+%.os: %.c
+ $(CC) -c -fPIC $(CFLAGS) $< -o $@
+
+$(TARGETLIB): $(OSOBJS)
+ $(CC) -o $@ -shared $^ $(CFLAGS) $(LIBS)
+
+clean:
+ rm -f $(TARGETLIB) *.o *.os
+
+# Install target - creates 'lib/' sub-directory in $(INSTALL_DIR) and copies all
+# executables to that location.
+install:
+ mkdir -p $(INSTALL_DIR)/lib
+ cp $(TARGETLIB) $(INSTALL_DIR)/lib
\ No newline at end of file
diff --git a/pyrp3/raw_memory.py b/pyrp3/raw_memory.py
index ce1b28e..233b82a 100644
--- a/pyrp3/raw_memory.py
+++ b/pyrp3/raw_memory.py
@@ -1,12 +1,9 @@
from ctypes import POINTER, c_uint32, cast, cdll, create_string_buffer, sizeof
-from importlib.machinery import EXTENSION_SUFFIXES
from pathlib import Path
import numpy as np
-libmonitor_file = str(
- Path(__file__).parent / ".." / "monitor{}".format(EXTENSION_SUFFIXES[0])
-)
+libmonitor_file = 'libmonitor.so'
libmonitor = cdll.LoadLibrary(libmonitor_file)
libmonitor.read_value.restype = c_uint32
diff --git a/setup.py b/setup.py
index 98bdaee..b0a8af4 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,10 @@
import re
-from distutils.core import Extension, setup
+import os
+
+from distutils.core import setup
+from distutils.command.build import build
+from distutils.command.install import install
+
from pathlib import Path
# from https://stackoverflow.com/a/7071358/2750945
@@ -11,9 +16,50 @@ if mo:
verstr = mo.group(1)
else:
raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
+
+# Patch from https://github.com/linien-org/pyrp3/blob/e6688acf8bd79d2dbe1d192d09c1a1baf1f6c67b/setup.py#L16-L55
+build_dir = "monitor/"
+
+def compile_libmonitor():
+ cwd = os.getcwd() # get current directory
+ try:
+ os.chdir(build_dir)
+ os.system("make clean")
+ os.system("make all")
+ finally:
+ os.chdir(cwd)
+
+
+def install_libmonitor(prefix=""):
+ cwd = os.getcwd() # get current directory
+ try:
+ os.chdir(build_dir)
+ os.system("make install INSTALL_DIR={prefix}".format(prefix=prefix))
+ finally:
+ os.chdir(cwd)
+
+
+class lib_build(build):
+ def run(self):
+ compile_libmonitor()
+ build.run(self)
+
+
+class lib_install(install):
+ def run(self):
+ compile_libmonitor()
+ install_libmonitor(self.prefix)
+ # install.run(self)
+
+# Will use nix to install libmonitor
+cmdclass = {
+ "build": lib_build
+}
+
this_directory = Path(__file__).parent
long_description = (this_directory / "README.rst").read_text()
+
setup(
name="pyrp3",
version=verstr,
@@ -32,6 +78,7 @@ setup(
"cached_property>=1.5.2",
"numpy>=1.11.0",
],
+ cmdclass=cmdclass,
classifiers=[
"Intended Audience :: Developers",
"Intended Audience :: Education",
@@ -45,5 +92,4 @@ setup(
"Topic :: Software Development :: Libraries :: Python Modules",
],
keywords=["redpitaya", "FPGA", "zynq"],
- ext_modules=[Extension("monitor", ["monitor/monitor.c"])],
)

View File

@ -17,6 +17,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import mmap
import os
import spidev import spidev
from pyfastservo.common import ( from pyfastservo.common import (
@ -31,8 +33,6 @@ from pyfastservo.common import (
AUX_ADC_ADDR, AUX_ADC_ADDR,
MAP_MASK, MAP_MASK,
PAGESIZE, PAGESIZE,
write_to_memory,
read_from_memory
) )
# /dev/spidev1.0 <=> spidev<BUS>.<DEVICE> # /dev/spidev1.0 <=> spidev<BUS>.<DEVICE>
@ -44,118 +44,276 @@ AUX_ADC_PORT_A = 2
AUX_ADC_PORT_B = 3 AUX_ADC_PORT_B = 3
def spi_write(spi, address, value): def main_adc_config(test_pattern):
spi.xfer2([address, value])
def spi_read(spi, address):
rx_buffer = spi.xfer2([0x80 | address, 0x00])
return rx_buffer[1]
def main_adc_config(spi, test_pattern):
high_word = (test_pattern & 0xFF00) >> 8 high_word = (test_pattern & 0xFF00) >> 8
low_word = test_pattern & 0xFF low_word = test_pattern & 0xFF
spi_write(spi, 0x00, 0x80) # reset
spi_write(spi, 0x01, 0x20) # REGISTER A1: set to Two's complement Data Format
spi_write(spi, 0x02, 0x15) # REGISTER A2: set to LVDS output, set 4 data lanes and turn on test mode
spi_write(spi, 0x03, high_word) # REGISTER A3: test pattern high word
spi_write(spi, 0x04, low_word) # REGISTER A4: test pattern low word
def main_adc_test_mode(spi, enable):
reg_contents = 0x15 if enable else 0x11 # set to LVDS output, set 4 data lanes and turn on or off test mode
spi_write(spi, 0x02, reg_contents)
def verify_adc_registers(spi, reg_to_check):
for register, expected_value in reg_to_check.items():
value = spi_read(spi, register)
print(f"Spi readback register 0x{register:02x}: 0x{value:02x}")
if value != expected_value:
print(f"Different value read than sent in reg 0x{register:02x}")
def read_frame():
return read_from_memory(ADC_FRAME_ADDR, 1)[0]
def perform_bitslip():
for i in range(4):
current_frame = read_frame()
if current_frame != 0x0C:
print(f"Performing bitslip (iteration: {i}). Current frame: 0x{current_frame:02x}")
write_to_memory(ADC_BITSLIP_ADDR, 1)
else:
print(f"No bitslip required; Current frame: 0x{current_frame:02x}")
return
def find_edge():
prev_frame = read_frame()
transition = False
for tap_delay in range(32):
write_to_memory(ADC_DELAY_ADDR, tap_delay)
current_frame = read_frame()
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
if current_frame != prev_frame:
if not transition:
transition = True
else:
final_delay = (tap_delay // 2) + 2
print(f"Edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
return
prev_frame = current_frame
# If no edge detected
final_delay = 11
print(f"No edge detected; setting iDelay to: {final_delay}")
write_to_memory(ADC_DELAY_ADDR, final_delay)
def read_adc_channel(high_addr, low_addr):
return (read_from_memory(high_addr, 1)[0] << 8) | read_from_memory(low_addr, 1)[0]
def print_adc_channels():
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def enable_adc_afe(ch1_x10=False, ch2_x10=False):
ctrl_value = (ch2_x10 << 1) | ch1_x10
write_to_memory(ADC_AFE_CTRL_ADDR, ctrl_value)
afe_ctrl = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0]
print(f"ADC_AFE_CTRL: 0x{afe_ctrl:02X}")
return afe_ctrl
def configure_ltc2195():
spi = spidev.SpiDev() spi = spidev.SpiDev()
try: try:
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE) spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
spi.max_speed_hz = 50000 spi.max_speed_hz = 50000
spi.mode = 0b00 # CPOL = 0 CPHA = 0 spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = False spi.cshigh = True
# spi.read0 = False
test_pattern = 0x811F spi_buffer = [0x00, 0x80] # reset
main_adc_config(spi, test_pattern) rx_buffer = [0x00, 0x00]
verify_adc_registers(spi, { spi.xfer2(spi_buffer)
0x01: 0x20,
0x02: 0x15,
0x03: (test_pattern & 0xFF00) >> 8,
0x04: test_pattern & 0xFF
})
# Performing Word Align # REGISTER A1
perform_bitslip() spi_buffer = [0x01, 0x20] # set to Two's complement Data Format
find_edge() spi.xfer2(spi_buffer)
print_adc_channels()
main_adc_test_mode(spi, False) # read values back
verify_adc_registers(spi, {0x02: 0x11}) # Verify test mode is off spi_buffer = [0x81, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x01: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != 0x20:
print("Different value read than sent in reg 0x02")
enable_adc_afe() # REGISTER A2
spi_buffer = [
0x02,
0x15,
] # set to LVDS output, set 4 data lanes and turn on test mode
spi.xfer2(spi_buffer)
# read values back
spi_buffer = [0x82, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x02: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != 0x15:
print("Different value read than sent in reg 0x02")
# REGISTER A3
# test pattern high word
spi_buffer = [0x03, high_word]
spi.xfer2(spi_buffer)
# read balues back
spi_buffer = [0x83, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x03: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != high_word:
print("Different value read than sent in reg 0x03")
# REGISTER A4
# test pattern low word
spi_buffer = [0x04, low_word]
spi.xfer2(spi_buffer)
# read balues back
spi_buffer = [0x84, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x04: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != low_word:
print("Different value read than sent in reg 0x04")
finally:
spi.close()
def main_adc_test_mode(enable):
spi = spidev.SpiDev()
try:
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
spi.max_speed_hz = 50000
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = True
# spi.read0 = True
reg_contents = (
0x15 if enable else 0x11
) # set to LVDS output, set 4 data lanes and turn on or off test mode
spi_buffer = [0x02, reg_contents]
spi.xfer2(spi_buffer)
# read values back
spi_buffer = [0x82, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"Spi readback register 0x02: 0x{rx_buffer[1]:02x}")
if rx_buffer[1] != reg_contents:
print("Different value read than sent in reg 0x02")
finally:
spi.close()
def read_from_memory(address, n_bytes):
assert n_bytes <= 4
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
# print(f"addr: 0x{addr:x}\tstart_addr: 0x{start_addr}\tstop_addr: 0x{stop_addr}")
contents = mem[start_addr:stop_addr]
read_value = list(contents)[:n_bytes]
# print("Read value: ", read_value)
finally:
os.close(f)
return read_value
def write_to_memory(address, value):
value_bytes = value.to_bytes(4, "little")
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
# print(f"addr: 0x{addr:x}\tstart_addr: 0x{start_addr}\tstop_addr: 0x{stop_addr}")
mem[start_addr:stop_addr] = value_bytes
contents = mem[start_addr:stop_addr]
# print("Read value: ", list(contents), " written value: ", list(value_bytes))
finally:
os.close(f)
def word_align():
value = 0
edge_detected = False
transition = False
tap_delay = 0
for i in range(4):
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
if current_frame != 0x0C:
print(
f"Performing bitslip (bitslip iteration: {i}). Reason: current_frame is 0x{current_frame:02x} instead of 0x0C"
)
write_to_memory(ADC_BITSLIP_ADDR, 1)
else:
print(f"No bitslip required; Currernt frame = 0x{current_frame:02x}")
break
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
prev_frame = current_frame
for i in range(32):
write_to_memory(ADC_DELAY_ADDR, tap_delay)
if edge_detected == 1:
break
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
print(f"Tap delay: {tap_delay}")
print(f"Current frame: 0x{current_frame:02x}")
if current_frame == prev_frame:
tap_delay += 1
elif not transition:
tap_delay += 1
transition = True
elif transition:
tap_delay = i // 2
edge_detected = True
prev_frame = current_frame
if not edge_detected:
tap_delay = 11 # empirically tested to work best
write_to_memory(ADC_DELAY_ADDR, tap_delay)
print(f"No edge detected; setting iDelay to: {tap_delay}")
if edge_detected:
write_to_memory(ADC_DELAY_ADDR, tap_delay + 2)
print(f"Edge detected; setting iDelay to (tap_delay + 2): {tap_delay} + 2")
adc_ch0 = read_from_memory(ADC_CH0_HIGH_ADDR, 4)
print(f"ADC_CH0: 0x{adc_ch0}")
adc_ch0 = (read_from_memory(ADC_CH0_HIGH_ADDR, 1)[0] << 8) | read_from_memory(
ADC_CH0_LOW_ADDR, 1
)[0]
adc_ch1 = (read_from_memory(ADC_CH1_HIGH_ADDR, 1)[0] << 8) | read_from_memory(
ADC_CH1_LOW_ADDR, 1
)[0]
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
def modify_bit(original_value, position, bit_value):
mask = 1 << position
return (original_value & ~mask) | (bit_value << position)
def adc_aux_config():
# MSB to LSB
# | RANGE | ADDR [2:0] | DIFF |
# DIFF = 0 => configure as single ended (it is negated in gateware)
# RANGE = 0 => configure as 0-2.5 Vref
to_write = 0b00000
write_to_memory(AUX_ADC_ADDR, to_write)
def adc_aux_read(port, type, pin):
# port:
# 1 - port A
# 2 - port B
# type:
# 0 - single-ended
# 1 - differential
# pin:
# 0b000 - VA1/VB1
# 0b001 - VA2/VB2
# 0b010 - VA3/VB3
# 0b011 - VA4/VB4
assert type in (0, 1)
assert port in (1, 2)
write_buffer = [0, 0]
read_buffer = [0, 0]
aux_config_reg = read_from_memory(AUX_ADC_ADDR, 1)[0]
aux_config = (aux_config_reg & 0b10001) | pin << 1
write_to_memory(AUX_ADC_ADDR, aux_config)
spi = spidev.SpiDev()
try:
spi.open(1, 3) # AUX ADC 1?
spi.max_speed_hz = 5000
spi.mode = 0b00
spi.cshigh = True
read_buffer = spi.xfer2(write_buffer)
mu_voltage = read_buffer[0] << 8 | read_buffer[1] >> 2
print(f"MU_voltage: 0x{mu_voltage:04X}")
print(f"Read_buffer[0]: 0x{read_buffer[0]:02X}")
print(f"Read_buffer[1]: 0x{read_buffer[1]:02X}")
return mu_voltage * 2.5 / 4096
finally: finally:
spi.close() spi.close()
def main():
main_adc_config(0x811F)
word_align()
main_adc_test_mode(False)
write_to_memory(ADC_AFE_CTRL_ADDR, 0b1100) # {-, -, ch2_X10, ch1_X10}
print(read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0])
if __name__ == "__main__": if __name__ == "__main__":
configure_ltc2195() main()

View File

@ -17,9 +17,6 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import os
import mmap
CSR_SIZE = 0x800 CSR_SIZE = 0x800
MAP_SIZE = 0x1000 MAP_SIZE = 0x1000
MAP_MASK = 0xFFF MAP_MASK = 0xFFF
@ -75,46 +72,3 @@ CH0_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH0_HIGH_WORD_OFFSET
CH0_LOW_WORD_ADDR = DAC_BASE_ADDR + CH0_LOW_WORD_OFFSET CH0_LOW_WORD_ADDR = DAC_BASE_ADDR + CH0_LOW_WORD_OFFSET
CH1_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH1_HIGH_WORD_OFFSET CH1_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH1_HIGH_WORD_OFFSET
CH1_LOW_WORD_ADDR = DAC_BASE_ADDR + CH1_LOW_WORD_OFFSET CH1_LOW_WORD_ADDR = DAC_BASE_ADDR + CH1_LOW_WORD_OFFSET
def read_from_memory(address, n_bytes):
assert n_bytes <= 4
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
contents = mem[start_addr:stop_addr]
read_value = list(contents)[:n_bytes]
finally:
os.close(f)
return read_value
def write_to_memory(address, value):
value_bytes = value.to_bytes(4, "little")
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
mem[start_addr:stop_addr] = value_bytes
contents = mem[start_addr:stop_addr]
finally:
os.close(f)

View File

@ -17,7 +17,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
import time import mmap
import os
import spidev import spidev
from pyfastservo.common import ( from pyfastservo.common import (
@ -28,58 +29,108 @@ from pyfastservo.common import (
CTRL_ADDR, CTRL_ADDR,
MAP_MASK, MAP_MASK,
PAGESIZE, PAGESIZE,
write_to_memory,
read_from_memory
) )
# /dev/spidev2.0 <=> spidev<BUS>.<DEVICE> # /dev/spidev2.0 <=> spidev<BUS>.<DEVICE>
MAIN_DAC_BUS = 2 MAIN_DAC_BUS = 2
MAIN_DAC_DEVICE = 0 MAIN_DAC_DEVICE = 0
DAC_VERSION = 0x0A DAC_VERSION = 0x0A
def spi_write(spi, address, value): def main_dac_init():
spi.xfer2([address, value]) spi = spidev.SpiDev()
def spi_read(spi, address): try:
rx_buffer = spi.xfer2([0x80 | address, 0x00]) spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
return rx_buffer[1] spi.max_speed_hz = 5000
spi.mode = 0b00 # CPOL = 0 CPHA = 0
spi.cshigh = True
def hard_reset(spi): spi_buffer = [0x00, 0x10] # software reset
spi_write(spi, 0x00, 0x10) # Software reset spi.xfer2(spi_buffer)
spi_write(spi, 0x00, 0x00) # Release software reset
spi_read(spi, 0x00) # Read reset address (necessary for reset to take effect)
def check_version(spi): spi_buffer = [0x00, 0x00] # release software reset
version = spi_read(spi, 0x1F) spi.xfer2(spi_buffer)
print(f"DAC version: 0x{version:02X}")
return version == DAC_VERSION
def configure_dac(spi): spi_buffer = [
power_down_reg = spi_read(spi, 0x01) 0x80,
spi_write(spi, 0x01, power_down_reg & ~(1 << 0)) # Clear EXTREF bit for internal reference 0x00,
spi_write(spi, 0x0D, 0x00) # Set RREF to 10 kΩ for 1.0V reference ] # for some reason it is needed to read the reset address for reset to actually reset
spi_write(spi, 0x04, 0xA0) # Enable on-chip IRSET (1.6 kΩ for 20mA output) rx_buffer = spi.xfer2(spi_buffer)
spi_write(spi, 0x07, 0xA0) # Enable on-chip QRSET (1.6 kΩ for 20mA output)
spi_write(spi, 0x05, 0x00) # Disable internal IRCML
spi_write(spi, 0x08, 0x00) # Disable internal QRCML
spi_write(spi, 0x02, 0xB4) # Enable 2's complement, LVDS interface, 4 LVDS lanes
def dac_self_calibration(spi): spi_buffer = [0x9F, 0x00] # hardware version
spi_write(spi, 0x12, 0x00) # Reset calibration status rx_buffer = spi.xfer2(spi_buffer)
spi_write(spi, 0x0E, 0x08) # Enable calibration clock, default divide ratio if rx_buffer[1] != DAC_VERSION:
spi_write(spi, 0x0E, 0x38) # CALSELI = 1, CALSELQ = 1, CALCLK = 1 print(f"Unrecognized device: 0x{rx_buffer[1]:02X}")
spi_write(spi, 0x12, 0x10) # Set CALEN bit
while True: print("=== Contents of spi buffer after DAC VERSION read back: ===")
status = spi_read(spi, 0x0F) print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
if status & 0xC0 == 0xC0: # Both CALSTATI and CALSTATQ are 1
break spi_buffer = [0x82, 00]
time.sleep(0.01) rx_buffer = spi.xfer2(spi_buffer)
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
# set to 2's complement and I to be first of pair on data input pads
spi_buffer = [0x02, 0xB4]
rx_buffer = spi.xfer2(spi_buffer)
spi_buffer = [0x82, 00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
for i in range(10):
spi_buffer = [0x94, 0x00]
rx_buffer = spi.xfer2(spi_buffer)
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
finally:
spi.close()
def read_from_memory(address, n_bytes):
assert n_bytes <= 4
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
# print(f"addr: 0x{addr:x}\tstart_addr: 0x{start_addr}\tstop_addr: 0x{stop_addr}")
contents = mem[start_addr:stop_addr]
read_value = list(contents)[:n_bytes]
finally:
os.close(f)
return read_value
def write_to_memory(address, value):
value_bytes = value.to_bytes(4, "little")
addr = address
try:
f = os.open("/dev/mem", os.O_SYNC | os.O_RDWR)
with mmap.mmap(
f,
PAGESIZE,
mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=addr & ~MAP_MASK,
) as mem:
start_addr = addr & MAP_MASK
stop_addr = start_addr + 4
mem[start_addr:stop_addr] = value_bytes
contents = mem[start_addr:stop_addr]
finally:
os.close(f)
spi_write(spi, 0x12, 0x00) # Clear calibration bits
spi_write(spi, 0x0E, 0x30) # Keep CALSELI and CALSELQ set, clear CALCLK
print("DAC self-calibration completed")
def manual_override(enable=True): def manual_override(enable=True):
reg_contents = read_from_memory(CTRL_ADDR, 1)[0] reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
@ -87,6 +138,7 @@ def manual_override(enable=True):
to_write = reg_contents | 0b1 if enable else reg_contents & 0b110 to_write = reg_contents | 0b1 if enable else reg_contents & 0b110
write_to_memory(CTRL_ADDR, to_write) write_to_memory(CTRL_ADDR, to_write)
def power_down(channel, power_down=True): def power_down(channel, power_down=True):
assert channel in (0, 1) assert channel in (0, 1)
@ -100,49 +152,31 @@ def power_down(channel, power_down=True):
reg_contents = read_from_memory(CTRL_ADDR, 1)[0] reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
print(f"REG contents: 0b{reg_contents:03b}") print(f"REG contents: 0b{reg_contents:03b}")
def set_dac_output(value):
value = min(value, 0x3FFF)
low_word = value & 0xFF
high_word = (value >> 8) & 0x3F
write_to_memory(CH0_HIGH_WORD_ADDR, high_word) def write_sample(channel, sample):
write_to_memory(CH0_LOW_WORD_ADDR, low_word) assert channel in (0, 1)
write_to_memory(CH1_HIGH_WORD_ADDR, high_word) if channel == 0:
write_to_memory(CH1_LOW_WORD_ADDR, low_word) addresses = [CH0_HIGH_WORD_ADDR, CH0_LOW_WORD_ADDR]
print(f"DAC output set to: 0x{value:04X}") else:
addresses = [CH1_HIGH_WORD_ADDR, CH1_LOW_WORD_ADDR]
def configure_ad9117(): low_word_value = sample & 0xFF
spi = spidev.SpiDev() high_word_value = (sample >> 8) & 0x3F
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE) values = [high_word_value, low_word_value]
spi.max_speed_hz = 5000 for addr, value in zip(addresses, values):
spi.mode = 0b00 # CPOL = 0 CPHA = 0 write_to_memory(addr, value)
spi.cshigh = False
try:
hard_reset(spi)
if not check_version(spi):
print("Unrecognized DAC version")
return False
configure_dac(spi) def write_ramp():
dac_self_calibration(spi) signal = [i for i in range(16384)]
# Enable DAC outputs for value in signal:
spi_write(spi, 0x01, spi_read(spi, 0x01) & ~((1 << 4) | (1 << 3))) write_sample(0, value)
def main():
main_dac_init()
power_down(0, False) power_down(0, False)
power_down(1, False) power_down(1, False)
manual_override(True)
print("AD9117 configuration completed successfully")
return True
except Exception as e:
print(f"Error configuring AD9117: {e}")
return False
finally:
spi.close()
if __name__ == "__main__": if __name__ == "__main__":
configure_ad9117() main()

View File

@ -21,8 +21,8 @@ from pyfastservo import adc, si5340, dac
def main(): def main():
si5340.configure_si5340() si5340.configure_si5340()
adc.configure_ltc2195() adc.main()
dac.configure_ad9117() dac.main()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -17,264 +17,102 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# Additional Reference:
# https://github.com/torvalds/linux/blob/master/drivers/clk/clk-si5341.c
import time
from smbus2 import SMBus from smbus2 import SMBus
BUS_NO = 0 BUS_NO = 0
IC_ADDR = 0x74 IC_ADDR = 0x74
DEVICE_READY = 0x00FE PAGE_ADDR = 0x1
PLL_M_DEN = 0x023B
STATUS = 0x000C
STATUS_STICKY = 0x0011
STATUS_LOSREF = 0x04 OUT0_MUX_SEL_ADDR = 0x15
STATUS_LOL = 0x08 OUT1_MUX_SEL_ADDR = 0x1A
OUT2_MUX_SEL_ADDR = 0x29
OUT3_MUX_SEL_ADDR = 0x2E
OUT2_AMPL_ADDR = 0x28
OUT3_PDN_ADDR = 0x2B
OUT3_FORMAT_ADDR = 0x2C
OUT3_AMPL_ADDR = 0x2D
def write_register(bus, address, value): N1_DIVIDER_UPDATE_ADDR = 0x17
page = address >> 8
register = address & 0xFF
bus.write_byte_data(IC_ADDR, 0x01, page)
try:
bus.write_byte_data(IC_ADDR, register, value)
except Exception as e:
raise Exception(f"Write failed 0x{value:02X} at 0x{address:04X}: {e}")
def write_preamble(bus): data_to_write = 0
preamble = [ clk_out_addr = [
(0x0B24, 0xC0), OUT0_MUX_SEL_ADDR,
(0x0B25, 0x00), OUT1_MUX_SEL_ADDR,
(0x0502, 0x01), OUT2_MUX_SEL_ADDR,
(0x0505, 0x03), OUT3_MUX_SEL_ADDR,
(0x0957, 0x17), ]
(0x0B4E, 0x1A),
]
for address, value in preamble:
write_register(bus, address, value)
def write_postamble(bus):
postamble = [
(0x001C, 0x01), # Soft reset
(0x0B24, 0xC3),
(0x0B25, 0x02),
]
for address, value in postamble:
write_register(bus, address, value)
def wait_device_ready(bus):
for _ in range(15):
if bus.read_byte_data(IC_ADDR, DEVICE_READY) == 0x0F:
return True
time.sleep(0.02)
return False
def wait_for_lock(bus):
for _ in range(10):
status = bus.read_byte_data(IC_ADDR, STATUS)
if not (status & (STATUS_LOSREF | STATUS_LOL)):
return True
time.sleep(0.01)
return False
def check_pll_status(bus):
pll_status = bus.read_byte_data(IC_ADDR, 0x0C)
pll_locked = not (pll_status & STATUS_LOL)
print(f"PLL {'locked' if pll_locked else 'unlocked'}")
return pll_locked
def check_los_status(bus):
los_status = bus.read_byte_data(IC_ADDR, 0x0D)
xaxb_los = (los_status & 0x10) != 0
print(f"XA/XB LOS {'asserted' if xaxb_los else 'deasserted'}")
return not xaxb_los
def configure_si5340(): def configure_si5340():
with SMBus(BUS_NO) as bus: with SMBus(BUS_NO) as bus:
if not wait_device_ready(bus):
print("Device not ready. Aborting.")
return
# Programming sequence from ClockBuilder Pro, default settings bus.write_byte_data(IC_ADDR, PAGE_ADDR, 0x0) # setting page to page 0
# to initialize system using XTAL input
main_config = [
(0x0006, 0x00), # TOOL_VERSION
(0x0007, 0x00), # Not in datasheet
(0x0008, 0x00), # Not in datasheet
(0x000B, 0x74), # I2C_ADDR
(0x0017, 0xD0), # INT mask (disable interrupts)
(0x0018, 0xFF), # INT mask
(0x0021, 0x0F), # Select XTAL as input
(0x0022, 0x00), # Not in datasheet
(0x002B, 0x02), # SPI config
(0x002C, 0x20), # LOS enable for XTAL
(0x002D, 0x00), # LOS timing
(0x002E, 0x00), # LOS trigger (thresholds)
(0x002F, 0x00),
(0x0030, 0x00),
(0x0031, 0x00),
(0x0032, 0x00),
(0x0033, 0x00),
(0x0034, 0x00),
(0x0035, 0x00), # LOS trigger (thresholds) end
(0x0036, 0x00), # LOS clear (thresholds)
(0x0037, 0x00),
(0x0038, 0x00),
(0x0039, 0x00),
(0x003A, 0x00),
(0x003B, 0x00),
(0x003C, 0x00),
(0x003D, 0x00), # LOS clear (thresholds) end
(0x0041, 0x00), # LOS0_DIV_SEL
(0x0042, 0x00), # LOS1_DIV_SEL
(0x0043, 0x00), # LOS2_DIV_SEL
(0x0044, 0x00), # LOS3_DIV_SEL
(0x009E, 0x00), # LOL_SET_THR
(0x0102, 0x01), # Enable outputs
(0x013F, 0x00), # OUTX_ALWAYS_ON
(0x0140, 0x00), # OUTX_ALWAYS_ON
(0x0141, 0x40), # OUT_DIS_LOL_MSK, OUT_DIS_MSK_LOS_PFD
(0x0202, 0x00), # XAXB_FREQ_OFFSET (=0)
# PLL Configuration # read device id
(0x0235, 0x00), # M_NUM low_word = bus.read_byte_data(IC_ADDR, 0x2)
(0x0236, 0x00), high_word = bus.read_byte_data(IC_ADDR, 0x3)
(0x0237, 0x00),
(0x0238, 0x80),
(0x0239, 0x89),
(0x023A, 0x00),
(0x023B, 0x00), # M_DEN
(0x023C, 0x00),
(0x023D, 0x00),
(0x023E, 0x80),
# Synthesizer configuration print(f"DEV ID: 0x{high_word:2x}{low_word:2x}")
(0x0302, 0x00), # N0_NUM
(0x0303, 0x00),
(0x0304, 0x00),
(0x0305, 0x00),
(0x0306, 0x21),
(0x0307, 0x00),
(0x0308, 0x00), # N0_DEN
(0x0309, 0x00),
(0x030A, 0x00),
(0x030B, 0x80),
(0x030C, 0x01), # N0_UPDATE
# N1 Configuration (1:1 ratio) data_to_write = 0x1
(0x030D, 0x00), # N1_NUM bus.write_byte_data(
(0x030E, 0x00), IC_ADDR, PAGE_ADDR, data_to_write
(0x030F, 0x00), ) # change to page 1 for output settings
(0x0310, 0x00),
(0x0311, 0x00),
(0x0312, 0x01),
(0x0313, 0x00), # N1_DEN
(0x0314, 0x00),
(0x0315, 0x00),
(0x0316, 0x01),
(0x0317, 0x01), # N1_UPDATE
# N2 Configuration (1:1 ratio) readback = bus.read_byte_data(IC_ADDR, PAGE_ADDR)
(0x0318, 0x00), # N2_NUM if data_to_write != readback:
(0x0319, 0x00), raise ValueError(f"Failed to set page.")
(0x031A, 0x00),
(0x031B, 0x00),
(0x031C, 0x00),
(0x031D, 0x01),
(0x031E, 0x00), # N2_DEN
(0x031F, 0x00),
(0x0320, 0x00),
(0x0321, 0x01),
(0x0322, 0x01), # N2_UPDATE
# N3 Configuration (1:1 ratio) for addr in clk_out_addr:
(0x0323, 0x00), # N3_NUM bus.write_byte_data(IC_ADDR, addr, 1) # set source to N1
(0x0324, 0x00),
(0x0325, 0x00),
(0x0326, 0x00),
(0x0327, 0x00),
(0x0328, 0x01),
(0x0329, 0x00), # N3_DEN
(0x032A, 0x00),
(0x032B, 0x00),
(0x032C, 0x01),
(0x032D, 0x01), # N3_UPDATE
# Output configuration bus.write_byte_data(IC_ADDR, OUT2_AMPL_ADDR, 13)
(0x0112, 0x06), # OUT0 config readback = bus.read_byte_data(IC_ADDR, OUT2_AMPL_ADDR)
(0x0113, 0x09), # OUT0 format # if data_to_write != readback:
(0x0114, 0x3B), # OUT0 CM/AMPL # raise ValueError(f"Problematic read: {readback}.")
(0x0115, 0x28), # OUT0 MUX_SEL
(0x0117, 0x06), # OUT1 config bus.write_byte_data(IC_ADDR, OUT2_AMPL_ADDR, 0x6B) # setting OUT2 to LVDS25
(0x0118, 0x09), # OUT1 format
(0x0119, 0x3B), # OUT1 CM/AMPL
(0x011A, 0x28), # OUT1 MUX_SEL
(0x0126, 0x06), # OUT2 config bus.write_byte_data(IC_ADDR, OUT3_FORMAT_ADDR, 0xCC) # SETTING out3 to LVCMOS 18
(0x0127, 0x09), # OUT2 format # bus.write_byte_data(IC_ADDR, 0x2E, 0x09) # SETTING out3 to LVCMOS 33
(0x0128, 0x3B), # OUT2 CM/AMPL
(0x0129, 0x28), # OUT2 MUX_SEL
(0x012B, 0x06), # OUT3 config readback = bus.read_byte_data(IC_ADDR, OUT3_PDN_ADDR)
(0x012C, 0xCC), # OUT3 format print(f"Si5340 OUTx_PDN CLK3: 0x{readback}")
(0x012D, 0x00), # OUT3 CM/AMPL
(0x012E, 0x58), # OUT3 MUX_SEL
# Miscellaneous configuration readback = bus.read_byte_data(IC_ADDR, OUT3_FORMAT_ADDR)
(0x090E, 0x02), # XAXB_EXTCLK_EN=0 XAXB_PDNB=1 (use XTAL) print(f"Si5340 OUTx_FORMAT CLK3: 0x{readback}")
(0x091C, 0x04), # ZDM_EN=4 (Normal mode)
(0x0943, 0x00), # IO_VDD_SEL
(0x0949, 0x00), # IN_EN (disable input clocks)
(0x094A, 0x00), # INx_TO_PFD_EN (disabled)
(0x094E, 0x49), # REFCLK_HYS_SEL (set by CBPro)
(0x094F, 0x02), # Not in datasheet
(0x095E, 0x00), # M_INTEGER (set by CBPro)
(0x0A02, 0x00), # N_ADD_0P5 (set by CBPro)
(0x0A03, 0x01), # N_CLK_TO_OUTX_EN
(0x0A04, 0x01), # N_PIBYP
(0x0A05, 0x01), # N_PDNB
(0x0A14, 0x00), # N0_HIGH_FREQ (set by CBPro)
(0x0A1A, 0x00), # N1_HIGH_FREQ (set by CBPro)
(0x0A20, 0x00), # N2_HIGH_FREQ (set by CBPro)
(0x0A26, 0x00), # N3_HIGH_FREQ (set by CBPro)
(0x0B44, 0x0F), # PDIV_ENB (set by CBPro)
(0x0B4A, 0x0E), # N_CLK_DIS
(0x0B57, 0x0E), # VCO_RESET_CALCODE (set by CBPro)
(0x0B58, 0x01), # VCO_RESET_CALCODE (set by CBPro)
]
write_preamble(bus) readback = bus.read_byte_data(IC_ADDR, OUT3_AMPL_ADDR)
print(f"Si5340 OUTx_AMPL CLK3: 0x{readback}")
time.sleep(0.3) readback = bus.read_byte_data(IC_ADDR, OUT3_MUX_SEL_ADDR)
print(f"Si5340 OUTx_CM CLK3: 0x{readback}")
print("Writing main configuration...") bus.write_byte_data(
for address, value in main_config: IC_ADDR, PAGE_ADDR, 0x3
write_register(bus, address, value) ) # setting page to 3 to change dividers values
print("Main configuration written")
write_postamble(bus) n1_numerator = [0x0, 0x0, 0x0, 0x60, 0x22, 0x0]
n1_numerator_10M = [0x0, 0x0, 0x0, 0xC0, 0x57, 0x1]
n1_num_addr = [0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12]
n1_denom_addr = [0x13, 0x14, 0x15, 0x16]
for addr, value in zip(n1_num_addr, n1_numerator):
bus.write_byte_data(IC_ADDR, addr, value)
if not wait_for_lock(bus): bus.write_byte_data(IC_ADDR, N1_DIVIDER_UPDATE_ADDR, 1)
print("Error waiting for input clock or PLL lock")
else:
print("Input clock present and PLL locked")
bus.write_byte_data(IC_ADDR, STATUS_STICKY, 0) for addr in n1_num_addr:
readback = bus.read_byte_data(IC_ADDR, addr)
print(f"Numerator buffer: 0x{readback:02x}")
# Final status check for addr in n1_denom_addr:
pll_locked = check_pll_status(bus) readback = bus.read_byte_data(IC_ADDR, addr)
xaxb_signal_present = check_los_status(bus) print(f"Denominator buffer: 0x{readback:02x}")
if not pll_locked: bus.write_byte_data(IC_ADDR, PAGE_ADDR, 0x0) # setting page to page 0
print("Error: PLL is not locked")
elif not xaxb_signal_present:
print("Error: XA/XB signal is lost")
else:
print("Si5340 configuration completed successfully")
if __name__ == "__main__": if __name__ == "__main__":
configure_si5340() configure_si5340()

View File

@ -18,16 +18,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1723938990, "lastModified": 1709237383,
"narHash": "sha256-9tUadhnZQbWIiYVXH8ncfGXGvkNq3Hag4RCBEMUk7MI=", "narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c42fcfbdfeae23e68fc520f9182dde9f38ad1890", "rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.05", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -64,11 +64,11 @@
"src-migen": { "src-migen": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1721561053, "lastModified": 1702942348,
"narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=", "narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=",
"owner": "m-labs", "owner": "m-labs",
"repo": "migen", "repo": "migen",
"rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417", "rev": "50934ad10a87ade47219b796535978b9bdf24023",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -80,11 +80,11 @@
"src-misoc": { "src-misoc": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1715647536, "lastModified": 1699352904,
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=", "narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726", "rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4",
"revCount": 2455, "revCount": 2452,
"submodules": true, "submodules": true,
"type": "git", "type": "git",
"url": "https://github.com/m-labs/misoc.git" "url": "https://github.com/m-labs/misoc.git"

View File

@ -1,7 +1,7 @@
{ {
description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien"; description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien";
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-24.05; inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
inputs.not-os.url = github:cleverca22/not-os; inputs.not-os.url = github:cleverca22/not-os;
inputs.not-os.inputs.nixpkgs.follows = "nixpkgs"; inputs.not-os.inputs.nixpkgs.follows = "nixpkgs";
@ -110,23 +110,13 @@
rev = "v${version}"; rev = "v${version}";
hash = "sha256-43TTlpJ5SMAjQM71bNVvrWQyciRXM3zpuA/Dw41AEgU="; hash = "sha256-43TTlpJ5SMAjQM71bNVvrWQyciRXM3zpuA/Dw41AEgU=";
}; };
patches = ./fast-servo/linien-pyrp3-monitor.patch; nativeBuildInputs = with pkgs-armv7l.python3Packages; [ setuptools wheel setuptools-scm ];
nativeBuildInputs = with pkgs-armv7l.python3Packages; [
setuptools wheel setuptools-scm
] ++ (with pkgs-armv7l; [ gcc gnumake ]);
propagatedBuildInputs = with pkgs-armv7l.python3Packages; [ propagatedBuildInputs = with pkgs-armv7l.python3Packages; [
myhdl myhdl
rpyc4 rpyc4
cached-property cached-property
numpy numpy
]; ];
postInstall = ''
cp monitor/libmonitor.so $out/lib
'';
postFixup = ''
substituteInPlace $out/${pkgs.python3.sitePackages}/pyrp3/raw_memory.py \
--replace "libmonitor.so" "$out/lib/libmonitor.so"
'';
}; };
linien-server = pkgs-armv7l.python3Packages.buildPythonPackage rec { linien-server = pkgs-armv7l.python3Packages.buildPythonPackage rec {

View File

@ -1,5 +1,5 @@
diff --git a/configuration.nix b/configuration.nix diff --git a/configuration.nix b/configuration.nix
index 010c487..2d08009 100644 index 010c487..e1e85ba 100644
--- a/configuration.nix --- a/configuration.nix
+++ b/configuration.nix +++ b/configuration.nix
@@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
@ -8,7 +8,7 @@ index 010c487..2d08009 100644
{ {
imports = [ ./qemu.nix ]; imports = [ ./qemu.nix ];
@@ -7,10 +7,16 @@ @@ -7,10 +7,15 @@
environment.etc = { environment.etc = {
"ssh/authorized_keys.d/root" = { "ssh/authorized_keys.d/root" = {
text = '' text = ''
@ -18,7 +18,6 @@ index 010c487..2d08009 100644
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo + ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo
+ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAranL376soiSJ0kxdYNrwElcaZPW1heLFjs8Y7n0jT linuswck
''; '';
mode = "0444"; mode = "0444";
}; };

View File

@ -1,5 +1,5 @@
diff --git a/base.nix b/base.nix diff --git a/base.nix b/base.nix
index 7eaee32..9aa338e 100644 index 7eaee32..3a2a0a9 100644
--- a/base.nix --- a/base.nix
+++ b/base.nix +++ b/base.nix
@@ -27,6 +27,11 @@ with lib; @@ -27,6 +27,11 @@ with lib;
@ -14,12 +14,9 @@ index 7eaee32..9aa338e 100644
not-os.simpleStaticIp = mkOption { not-os.simpleStaticIp = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@@ -84,17 +89,25 @@ with lib; @@ -86,15 +91,25 @@ with lib;
};
environment.etc = {
"nix/nix.conf".source = pkgs.runCommand "nix.conf" {} '' "nix/nix.conf".source = pkgs.runCommand "nix.conf" {} ''
- extraPaths=$(for i in $(cat ${pkgs.writeReferencesToFile pkgs.runtimeShell}); do if test -d $i; then echo $i; fi; done) extraPaths=$(for i in $(cat ${pkgs.writeReferencesToFile pkgs.runtimeShell}); do if test -d $i; then echo $i; fi; done)
+ extraPaths=$(for i in $(cat ${pkgs.writeClosure [ pkgs.bash ]}); do if test -d $i; then echo $i; fi; done)
cat > $out << EOF cat > $out << EOF
- build-use-sandbox = true - build-use-sandbox = true
+ auto-optimise-store = true + auto-optimise-store = true
@ -31,6 +28,8 @@ index 7eaee32..9aa338e 100644
+ extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths) + extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
+ max-jobs = auto + max-jobs = auto
+ sandbox = true + sandbox = true
+ substituters = https://cache.armv7l.xyz
+ trusted-public-keys = cache.armv7l.xyz-1:kBY/eGnBAYiqYfg0fy0inWhshUo+pGFM3Pj7kIkmlBk=
+ trusted-users = root + trusted-users = root
EOF EOF
''; '';
@ -152,7 +151,7 @@ index c61f9d6..fbdf0fd 100644
}; };
} }
diff --git a/zynq_image.nix b/zynq_image.nix diff --git a/zynq_image.nix b/zynq_image.nix
index 3fa23ab..069fe89 100644 index 3fa23ab..9d1621e 100644
--- a/zynq_image.nix --- a/zynq_image.nix
+++ b/zynq_image.nix +++ b/zynq_image.nix
@@ -1,66 +1,89 @@ @@ -1,66 +1,89 @@
@ -164,7 +163,7 @@ index 3fa23ab..069fe89 100644
- # dont use overlays for the qemu, it causes a lot of wasted time on recompiles - # dont use overlays for the qemu, it causes a lot of wasted time on recompiles
- x86pkgs = import pkgs.path { system = "x86_64-linux"; }; - x86pkgs = import pkgs.path { system = "x86_64-linux"; };
- customKernel = pkgs.linux.override { - customKernel = pkgs.linux.override {
+ customKernel = (pkgs.linux_6_6.override { + customKernel = (pkgs.linux.override {
extraConfig = '' extraConfig = ''
OVERLAY_FS y OVERLAY_FS y
+ MEDIA_SUPPORT n + MEDIA_SUPPORT n
@ -250,7 +249,7 @@ index 3fa23ab..069fe89 100644
- environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" '' - environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" ''
- agetty ttyPS0 115200 - agetty ttyPS0 115200
+ environment = { + environment = {
+ systemPackages = with pkgs; [ inetutils wget gnugrep nano vim ]; + systemPackages = with pkgs; [ inetutils wget nano ];
+ etc = { + etc = {
+ "service/getty/run".source = pkgs.writeShellScript "getty" '' + "service/getty/run".source = pkgs.writeShellScript "getty" ''
+ hostname ${config.networking.hostName} + hostname ${config.networking.hostName}

View File

@ -394,10 +394,10 @@ index 0000000..53c5349
\ No newline at end of file \ No newline at end of file
diff --git a/xilinx-fpga-manager.patch b/xilinx-fpga-manager.patch diff --git a/xilinx-fpga-manager.patch b/xilinx-fpga-manager.patch
new file mode 100644 new file mode 100644
index 0000000..33daffe index 0000000..59aa585
--- /dev/null --- /dev/null
+++ b/xilinx-fpga-manager.patch +++ b/xilinx-fpga-manager.patch
@@ -0,0 +1,676 @@ @@ -0,0 +1,663 @@
+# Enable user-space interface for PL programming via Linux FPGA manager +# Enable user-space interface for PL programming via Linux FPGA manager
+# diff cherry-picked from Xilinx/linux-xilinx/tree/xlnx_rebase_v6.6_LTS +# diff cherry-picked from Xilinx/linux-xilinx/tree/xlnx_rebase_v6.6_LTS
+# commit IDs: e61c0a9, 0a38712, dc67651, 89a24e3, 8d224b1, 2a9c05f, 4e94580 +# commit IDs: e61c0a9, 0a38712, dc67651, 89a24e3, 8d224b1, 2a9c05f, 4e94580
@ -425,7 +425,7 @@ index 0000000..33daffe
+ tristate "Altera SOCFPGA FPGA Manager" + tristate "Altera SOCFPGA FPGA Manager"
+ depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST + depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST
+diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c +diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
+index 0f4035b089a2..3aa9f5f041f6 100644 +index 06651389c592..6e8c45974f28 100644
+--- a/drivers/fpga/fpga-mgr.c +--- a/drivers/fpga/fpga-mgr.c
++++ b/drivers/fpga/fpga-mgr.c ++++ b/drivers/fpga/fpga-mgr.c
+@@ -8,6 +8,9 @@ +@@ -8,6 +8,9 @@
@ -673,7 +673,7 @@ index 0000000..33daffe
+ NULL, + NULL,
+ }; + };
+ ATTRIBUTE_GROUPS(fpga_mgr); + ATTRIBUTE_GROUPS(fpga_mgr);
+@@ -739,6 +871,106 @@ void fpga_mgr_put(struct fpga_manager *mgr) +@@ -732,6 +864,106 @@ void fpga_mgr_put(struct fpga_manager *mgr)
+ } + }
+ EXPORT_SYMBOL_GPL(fpga_mgr_put); + EXPORT_SYMBOL_GPL(fpga_mgr_put);
+ +
@ -780,8 +780,8 @@ index 0000000..33daffe
+ /** + /**
+ * fpga_mgr_lock - Lock FPGA manager for exclusive use + * fpga_mgr_lock - Lock FPGA manager for exclusive use
+ * @mgr: fpga manager + * @mgr: fpga manager
+@@ -788,6 +1020,9 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info * +@@ -779,6 +1011,9 @@ struct fpga_manager *
+ struct module *owner) + fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info)
+ { + {
+ const struct fpga_manager_ops *mops = info->mops; + const struct fpga_manager_ops *mops = info->mops;
++#ifdef CONFIG_FPGA_MGR_DEBUG_FS ++#ifdef CONFIG_FPGA_MGR_DEBUG_FS
@ -790,7 +790,7 @@ index 0000000..33daffe
+ struct fpga_manager *mgr; + struct fpga_manager *mgr;
+ int id, ret; + int id, ret;
+ +
+@@ -826,10 +1061,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info * +@@ -815,10 +1050,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
+ mgr->dev.of_node = parent->of_node; + mgr->dev.of_node = parent->of_node;
+ mgr->dev.id = id; + mgr->dev.id = id;
+ +
@ -819,7 +819,7 @@ index 0000000..33daffe
+ /* + /*
+ * Initialize framework state by requesting low level driver read state + * Initialize framework state by requesting low level driver read state
+ * from device. FPGA may be in reset mode or may have been programmed + * from device. FPGA may be in reset mode or may have been programmed
+@@ -843,6 +1096,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info * +@@ -832,6 +1085,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
+ return ERR_PTR(ret); + return ERR_PTR(ret);
+ } + }
+ +
@ -848,7 +848,7 @@ index 0000000..33daffe
+ return mgr; + return mgr;
+ +
+ error_device: + error_device:
+@@ -894,6 +1169,10 @@ void fpga_mgr_unregister(struct fpga_manager *mgr) +@@ -882,6 +1157,10 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
+ { + {
+ dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name); + dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name);
+ +
@ -881,10 +881,10 @@ index 0000000..33daffe
+ &firmware_name)) { + &firmware_name)) {
+ info->firmware_name = devm_kstrdup(dev, firmware_name, + info->firmware_name = devm_kstrdup(dev, firmware_name,
+diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c +diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c
+index f3434e2c487b..d2434ed85eff 100644 +index f3434e2c487b..db923746cac5 100644
+--- a/drivers/fpga/zynqmp-fpga.c +--- a/drivers/fpga/zynqmp-fpga.c
++++ b/drivers/fpga/zynqmp-fpga.c ++++ b/drivers/fpga/zynqmp-fpga.c
+@@ -43,25 +43,47 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, +@@ -43,25 +43,42 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
+ struct zynqmp_fpga_priv *priv; + struct zynqmp_fpga_priv *priv;
+ dma_addr_t dma_addr; + dma_addr_t dma_addr;
+ u32 eemi_flags = 0; + u32 eemi_flags = 0;
@ -915,11 +915,6 @@ index 0000000..33daffe
++ ++
+ wmb(); /* ensure all writes are done before initiate FW call */ + wmb(); /* ensure all writes are done before initiate FW call */
+ +
++ if (priv->flags & FPGA_MGR_DDR_MEM_AUTH_BITSTREAM)
++ eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_DDR;
++ else if (priv->flags & FPGA_MGR_SECURE_MEM_AUTH_BITSTREAM)
++ eemi_flags |= XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_OCM;
++
+ if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG) + if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
+ eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL; + eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
+ +
@ -936,22 +931,20 @@ index 0000000..33daffe
+ return ret; + return ret;
+ } + }
+diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h +diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
+index e8b12ec8b060..ffd2dfdb6abd 100644 +index 9dda7d9898ff..edaf77160746 100644
+--- a/include/linux/firmware/xlnx-zynqmp.h +--- a/include/linux/firmware/xlnx-zynqmp.h
++++ b/include/linux/firmware/xlnx-zynqmp.h ++++ b/include/linux/firmware/xlnx-zynqmp.h
+@@ -83,6 +83,10 @@ +@@ -70,6 +70,8 @@
+ */ + */
+ #define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U + #define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U
+ #define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0) + #define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0)
++#define XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_DDR BIT(1)
++#define XILINX_ZYNQMP_PM_FPGA_AUTHENTICATION_OCM BIT(2)
++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY BIT(3) ++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_USERKEY BIT(3)
++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY BIT(4) ++#define XILINX_ZYNQMP_PM_FPGA_ENCRYPTION_DEVKEY BIT(4)
+ +
+ /* FPGA Status Reg */ + /* FPGA Status Reg */
+ #define XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET 7U + #define XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET 7U
+diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h +diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
+index 0d4fe068f3d8..f884d268c974 100644 +index 54f63459efd6..c96a4405f909 100644
+--- a/include/linux/fpga/fpga-mgr.h +--- a/include/linux/fpga/fpga-mgr.h
++++ b/include/linux/fpga/fpga-mgr.h ++++ b/include/linux/fpga/fpga-mgr.h
+@@ -9,8 +9,11 @@ +@@ -9,8 +9,11 @@
@ -966,7 +959,7 @@ index 0000000..33daffe
+ struct fpga_manager; + struct fpga_manager;
+ struct sg_table; + struct sg_table;
+ +
+@@ -66,17 +69,29 @@ enum fpga_mgr_states { +@@ -66,17 +69,25 @@ enum fpga_mgr_states {
+ * + *
+ * %FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting + * %FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting
+ * + *
@ -980,10 +973,6 @@ index 0000000..33daffe
++ * ++ *
++ * %FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM: indicates bitstream is encrypted with ++ * %FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM: indicates bitstream is encrypted with
++ * user key ++ * user key
++ * %FPGA_MGR_DDR_MEM_AUTH_BITSTREAM: do bitstream authentication using DDR
++ * memory if supported
++ * %FPGA_MGR_SECURE_MEM_AUTH_BITSTREAM: do bitstream authentication using secure
++ * memory if supported
+ */ + */
+ #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) + #define FPGA_MGR_PARTIAL_RECONFIG BIT(0)
+ #define FPGA_MGR_EXTERNAL_CONFIG BIT(1) + #define FPGA_MGR_EXTERNAL_CONFIG BIT(1)
@ -997,7 +986,7 @@ index 0000000..33daffe
+ +
+ /** + /**
+ * struct fpga_image_info - information specific to an FPGA image + * struct fpga_image_info - information specific to an FPGA image
+@@ -86,6 +101,7 @@ enum fpga_mgr_states { +@@ -86,6 +97,7 @@ enum fpga_mgr_states {
+ * @config_complete_timeout_us: maximum time for FPGA to switch to operating + * @config_complete_timeout_us: maximum time for FPGA to switch to operating
+ * status in the write_complete op. + * status in the write_complete op.
+ * @firmware_name: name of FPGA image firmware file + * @firmware_name: name of FPGA image firmware file
@ -1005,7 +994,7 @@ index 0000000..33daffe
+ * @sgt: scatter/gather table containing FPGA image + * @sgt: scatter/gather table containing FPGA image
+ * @buf: contiguous buffer containing FPGA image + * @buf: contiguous buffer containing FPGA image
+ * @count: size of buf + * @count: size of buf
+@@ -102,6 +118,7 @@ struct fpga_image_info { +@@ -102,6 +114,7 @@ struct fpga_image_info {
+ u32 disable_timeout_us; + u32 disable_timeout_us;
+ u32 config_complete_timeout_us; + u32 config_complete_timeout_us;
+ char *firmware_name; + char *firmware_name;
@ -1013,7 +1002,7 @@ index 0000000..33daffe
+ struct sg_table *sgt; + struct sg_table *sgt;
+ const char *buf; + const char *buf;
+ size_t count; + size_t count;
+@@ -160,6 +177,7 @@ struct fpga_manager_info { +@@ -160,6 +173,7 @@ struct fpga_manager_info {
+ * @write: write count bytes of configuration data to the FPGA + * @write: write count bytes of configuration data to the FPGA
+ * @write_sg: write the scatter list of configuration data to the FPGA + * @write_sg: write the scatter list of configuration data to the FPGA
+ * @write_complete: set FPGA to operating state after writing is done + * @write_complete: set FPGA to operating state after writing is done
@ -1021,7 +1010,7 @@ index 0000000..33daffe
+ * @fpga_remove: optional: Set FPGA into a specific state during driver remove + * @fpga_remove: optional: Set FPGA into a specific state during driver remove
+ * @groups: optional attribute groups. + * @groups: optional attribute groups.
+ * + *
+@@ -182,6 +200,7 @@ struct fpga_manager_ops { +@@ -182,6 +196,7 @@ struct fpga_manager_ops {
+ int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt); + int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt);
+ int (*write_complete)(struct fpga_manager *mgr, + int (*write_complete)(struct fpga_manager *mgr,
+ struct fpga_image_info *info); + struct fpga_image_info *info);
@ -1029,7 +1018,7 @@ index 0000000..33daffe
+ void (*fpga_remove)(struct fpga_manager *mgr); + void (*fpga_remove)(struct fpga_manager *mgr);
+ const struct attribute_group **groups; + const struct attribute_group **groups;
+ }; + };
+@@ -196,23 +215,37 @@ struct fpga_manager_ops { +@@ -196,21 +211,35 @@ struct fpga_manager_ops {
+ /** + /**
+ * struct fpga_manager - fpga manager structure + * struct fpga_manager - fpga manager structure
+ * @name: name of low level fpga manager + * @name: name of low level fpga manager
@ -1042,7 +1031,6 @@ index 0000000..33daffe
+ * @state: state of fpga manager + * @state: state of fpga manager
+ * @compat_id: FPGA manager id for compatibility check. + * @compat_id: FPGA manager id for compatibility check.
+ * @mops: pointer to struct of fpga manager ops + * @mops: pointer to struct of fpga manager ops
+ * @mops_owner: module containing the mops
+ * @priv: low level driver private date + * @priv: low level driver private date
++ * @err: low level driver error code ++ * @err: low level driver error code
++ * @dir: debugfs image directory ++ * @dir: debugfs image directory
@ -1058,7 +1046,6 @@ index 0000000..33daffe
+ enum fpga_mgr_states state; + enum fpga_mgr_states state;
+ struct fpga_compat_id *compat_id; + struct fpga_compat_id *compat_id;
+ const struct fpga_manager_ops *mops; + const struct fpga_manager_ops *mops;
+ struct module *mops_owner;
+ void *priv; + void *priv;
++ int err; ++ int err;
++#ifdef CONFIG_FPGA_MGR_DEBUG_FS ++#ifdef CONFIG_FPGA_MGR_DEBUG_FS
@ -1067,21 +1054,21 @@ index 0000000..33daffe
+ }; + };
+ +
+ #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev) + #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)
+@@ -258,4 +291,6 @@ __devm_fpga_mgr_register(struct device *parent, const char *name, +@@ -244,4 +273,6 @@ struct fpga_manager *
+ const struct fpga_manager_ops *mops, void *priv, + devm_fpga_mgr_register(struct device *parent, const char *name,
+ struct module *owner); + const struct fpga_manager_ops *mops, void *priv);
+ +
++#define FPGA_IOCTL_LOAD_DMA_BUFF _IOWR('R', 1, __u32) ++#define FPGA_IOCTL_LOAD_DMA_BUFF _IOWR('R', 1, __u32)
++ ++
+ #endif /*_LINUX_FPGA_MGR_H */ + #endif /*_LINUX_FPGA_MGR_H */
diff --git a/zynq_image.nix b/zynq_image.nix diff --git a/zynq_image.nix b/zynq_image.nix
index d5c5eda..7ede584 100644 index 9d1621e..012e50c 100644
--- a/zynq_image.nix --- a/zynq_image.nix
+++ b/zynq_image.nix +++ b/zynq_image.nix
@@ -3,6 +3,16 @@ @@ -3,6 +3,16 @@
with lib; with lib;
let let
customKernel = (pkgs.linux_6_6.override { customKernel = (pkgs.linux.override {
+ kernelPatches = [ + kernelPatches = [
+ ({ + ({
+ name = "xilinx-configfs-overlays"; + name = "xilinx-configfs-overlays";