forked from M-Labs/nix-servo
Compare commits
28 Commits
Author | SHA1 | Date |
---|---|---|
linuswck | 77643909ef | |
linuswck | a5dc232be4 | |
linuswck | 87059eef2b | |
linuswck | 8a40bb4f21 | |
linuswck | bbe09de52c | |
linuswck | 9f2e609b6e | |
linuswck | 6705b182d5 | |
linuswck | 51c8b755d2 | |
linuswck | 5d55ab4c9c | |
linuswck | 560b28508c | |
linuswck | b1a9fa0ad4 | |
linuswck | 5343b3d45a | |
linuswck | 4940ee52cc | |
linuswck | 382e8467d9 | |
linuswck | 6cef418756 | |
Florian Agbuya | e708696b5d | |
Florian Agbuya | 3cf9a721cf | |
Florian Agbuya | 8b20379427 | |
Florian Agbuya | 15a66c01fa | |
Sebastien Bourdeauducq | 2d75b4112e | |
Florian Agbuya | ed816517cf | |
Florian Agbuya | f5729d3bdb | |
Florian Agbuya | e3b1525125 | |
Florian Agbuya | b92d401f2b | |
Florian Agbuya | eed43e3fe3 | |
Florian Agbuya | b2dedd77ad | |
Florian Agbuya | 693e301ccf | |
Florian Agbuya | 6fca060256 |
|
@ -20,13 +20,15 @@
|
|||
from migen import *
|
||||
from migen.genlib.cdc import MultiReg
|
||||
from misoc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
|
||||
from misoc.interconnect.stream import AsyncFIFO
|
||||
|
||||
|
||||
class _CRG(Module):
|
||||
class CRG(Module):
|
||||
def __init__(self, platform, dco_clk, dco_freq=200e6):
|
||||
self.clock_domains.cd_dco = ClockDomain()
|
||||
self.clock_domains.cd_dco2x = ClockDomain()
|
||||
self.clock_domains.cd_dco2d = ClockDomain()
|
||||
self.clock_domains.cd_dco2d_45_degree = ClockDomain()
|
||||
dco_clk_p, dco_clk_n = dco_clk
|
||||
|
||||
dco_clk_buf = Signal()
|
||||
|
@ -41,59 +43,83 @@ class _CRG(Module):
|
|||
clk_dco = Signal()
|
||||
clk_dco2x = Signal()
|
||||
clk_dco2d = Signal()
|
||||
clk_dco2d_45_degree = Signal()
|
||||
mmcm_ps_psdone = Signal()
|
||||
|
||||
self.locked = Signal()
|
||||
self.mmcm_rst = Signal()
|
||||
self.ddr_clk_phase_shift_en = Signal()
|
||||
self.ddr_clk_phase_incdec = Signal()
|
||||
|
||||
platform.add_period_constraint(dco_clk_p, 1e9 / dco_freq)
|
||||
self.specials += [
|
||||
Instance(
|
||||
"PLLE2_BASE",
|
||||
"MMCME2_ADV",
|
||||
p_BANDWIDTH="OPTIMIZED",
|
||||
p_DIVCLK_DIVIDE=1,
|
||||
p_CLKFBOUT_PHASE=0.0,
|
||||
p_CLKFBOUT_MULT=4, # VCO @ 800 MHz
|
||||
p_CLKFBOUT_MULT_F=4, # VCO @ 800 MHz
|
||||
p_CLKIN1_PERIOD=(1e9 / dco_freq),
|
||||
p_REF_JITTER1=0.01,
|
||||
p_STARTUP_WAIT="FALSE",
|
||||
i_CLKIN1=dco_clk_buf,
|
||||
i_PWRDWN=0,
|
||||
i_RST=ResetSignal("sys"),
|
||||
i_RST=ResetSignal("sys") | self.mmcm_rst,
|
||||
i_CLKFBIN=clk_feedback_buf,
|
||||
o_CLKFBOUT=clk_feedback,
|
||||
p_CLKOUT0_DIVIDE=4,
|
||||
p_CLKOUT0_PHASE=0.0,
|
||||
|
||||
p_CLKOUT0_USE_FINE_PS="TRUE",
|
||||
p_CLKOUT0_DIVIDE_F=8,
|
||||
p_CLKOUT0_PHASE=45.0,
|
||||
p_CLKOUT0_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT0=clk_dco, # 200 MHz <- dco_clk
|
||||
o_CLKOUT0=clk_dco2d_45_degree, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
|
||||
o_LOCKED=self.locked,
|
||||
|
||||
p_CLKOUT1_DIVIDE=2,
|
||||
p_CLKOUT1_PHASE=0.0,
|
||||
p_CLKOUT1_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT1=clk_dco2x, # 400 MHZ <- 2 * dco_clk = 2*200 MHz
|
||||
|
||||
p_CLKOUT2_DIVIDE=8,
|
||||
p_CLKOUT2_PHASE=0.0,
|
||||
p_CLKOUT2_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT2=clk_dco2d, # 100 MHz <- dco_clk / 2 = 200 MHz / 2
|
||||
o_LOCKED=self.locked,
|
||||
|
||||
p_CLKOUT3_DIVIDE=4,
|
||||
p_CLKOUT3_PHASE=0.0,
|
||||
p_CLKOUT3_DUTY_CYCLE=0.5,
|
||||
o_CLKOUT3=clk_dco, # 200 MHz <- dco_clk
|
||||
|
||||
i_PSCLK=ClockSignal(),
|
||||
i_PSEN=self.ddr_clk_phase_shift_en,
|
||||
i_PSINCDEC=self.ddr_clk_phase_incdec,
|
||||
o_PSDONE=mmcm_ps_psdone,
|
||||
)
|
||||
]
|
||||
|
||||
self.specials += Instance("BUFG", i_I=clk_feedback, o_O=clk_feedback_buf)
|
||||
self.specials += Instance("BUFG", i_I=clk_dco, o_O=self.cd_dco.clk)
|
||||
self.specials += Instance("BUFG", i_I=clk_dco2d, o_O=self.cd_dco2d.clk)
|
||||
self.specials += Instance("BUFG", i_I=clk_dco2d_45_degree, o_O=self.cd_dco2d_45_degree.clk)
|
||||
self.specials += Instance("BUFG", i_I=clk_dco2x, o_O=self.cd_dco2x.clk)
|
||||
|
||||
# Ignore dco2d to mmcm dco_clk path created by SoC's rst.
|
||||
platform.add_false_path_constraints(self.cd_dco2d.clk, dco_clk_buf)
|
||||
self.specials += Instance("FD", p_INIT=1, i_D=~self.locked, i_C=self.cd_dco2d.clk, o_Q=self.cd_dco2d.rst)
|
||||
|
||||
class ADC(Module, AutoCSR):
|
||||
def __init__(self, platform, dco_freq=200e6):
|
||||
adc_pads = platform.request("adc")
|
||||
afe_pads = platform.request("adc_afe")
|
||||
|
||||
self.frame_csr = CSRStatus(4)
|
||||
self.frame_csr = CSRStatus(5)
|
||||
self.data_ch0 = CSRStatus(16)
|
||||
self.data_ch1 = CSRStatus(16)
|
||||
|
||||
self.tap_delay = CSRStorage(5)
|
||||
self.bitslip_csr = CSRStorage(1)
|
||||
|
||||
self.afe_ctrl = CSRStorage(4)
|
||||
self.afe_ctrl = CSRStorage(7)
|
||||
|
||||
tap_delay_val = Signal(5)
|
||||
bitslip = Signal()
|
||||
|
@ -105,7 +131,17 @@ class ADC(Module, AutoCSR):
|
|||
ch2_shdn = Signal()
|
||||
|
||||
self.data_out = [Signal(16, reset_less=True), Signal(16, reset_less=True)]
|
||||
self.data_out_cdc = [Signal(16, reset_less=True), Signal(16, reset_less=True)]
|
||||
self.s_frame = Signal(4)
|
||||
self.s_frame_cdc = Signal(4)
|
||||
|
||||
self.submodules.cdc_fifo = ClockDomainsRenamer({"write": "dco2d", "read": "sys"})(AsyncFIFO([("data", 36)], 4))
|
||||
self.comb += [
|
||||
self.cdc_fifo.sink.data.eq(Cat(self.data_out_cdc[0], self.data_out_cdc[1], self.s_frame_cdc)),
|
||||
self.cdc_fifo.sink.stb.eq(~ResetSignal("dco2d")),
|
||||
Cat(self.data_out[0], self.data_out[1], self.s_frame).eq(self.cdc_fifo.source.data),
|
||||
self.cdc_fifo.source.ack.eq(~ResetSignal("sys")),
|
||||
]
|
||||
|
||||
###
|
||||
|
||||
|
@ -117,11 +153,14 @@ class ADC(Module, AutoCSR):
|
|||
# dco_clk.n.eq(adc_pads.dco_n),
|
||||
tap_delay_val.eq(self.tap_delay.storage),
|
||||
Cat(ch1_gain_x10, ch2_gain_x10, ch1_shdn, ch2_shdn).eq(
|
||||
self.afe_ctrl.storage
|
||||
self.afe_ctrl.storage[0:4]
|
||||
),
|
||||
]
|
||||
|
||||
self.submodules._crg = _CRG(platform, dco_clk, dco_freq)
|
||||
self.submodules.crg = CRG(platform, dco_clk, dco_freq)
|
||||
self.comb += self.afe_ctrl.storage[4].eq(self.crg.mmcm_rst)
|
||||
self.comb += self.afe_ctrl.storage[5].eq(self.crg.ddr_clk_phase_shift_en)
|
||||
self.comb += self.afe_ctrl.storage[6].eq(self.crg.ddr_clk_phase_incdec)
|
||||
|
||||
self.specials += MultiReg(self.bitslip_csr.re, bitslip_re_dco_2d, "dco2d")
|
||||
self.sync.dco2d += [
|
||||
|
@ -129,7 +168,8 @@ class ADC(Module, AutoCSR):
|
|||
]
|
||||
|
||||
self.comb += [
|
||||
self.frame_csr.status.eq(self.s_frame),
|
||||
self.frame_csr.status[0:4].eq(self.s_frame[0:4]),
|
||||
self.frame_csr.status[4].eq(self.crg.locked),
|
||||
self.data_ch0.status.eq(self.data_out[0]),
|
||||
self.data_ch1.status.eq(self.data_out[1]),
|
||||
]
|
||||
|
@ -146,7 +186,7 @@ class ADC(Module, AutoCSR):
|
|||
|
||||
self.specials += Instance(
|
||||
"LTC2195",
|
||||
i_rst_in=ResetSignal("sys"),
|
||||
i_rst_in=ResetSignal("dco2d"),
|
||||
i_clk200=ClockSignal("idelay"),
|
||||
i_DCO=ClockSignal("dco"),
|
||||
i_DCO_2D=ClockSignal("dco2d"),
|
||||
|
@ -158,9 +198,9 @@ class ADC(Module, AutoCSR):
|
|||
i_D1_in_n=adc_pads.data1_n,
|
||||
i_bitslip=bitslip,
|
||||
i_delay_val=tap_delay_val,
|
||||
o_ADC0_out=self.data_out[1], # LANES swapped on hardware
|
||||
o_ADC1_out=self.data_out[0],
|
||||
o_FR_out=self.s_frame,
|
||||
o_ADC0_out=self.data_out_cdc[1], # LANES swapped on hardware
|
||||
o_ADC1_out=self.data_out_cdc[0],
|
||||
o_FR_out=self.s_frame_cdc,
|
||||
o_o_data_from_pins=dummy,
|
||||
o_idelay_rdy=dummy_idelay_rdy,
|
||||
)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
from migen import *
|
||||
from misoc.interconnect.csr import AutoCSR, CSRStorage
|
||||
from migen.genlib.io import DDROutput
|
||||
from misoc.interconnect.stream import AsyncFIFO
|
||||
|
||||
|
||||
class DAC(Module, AutoCSR):
|
||||
|
@ -38,37 +39,51 @@ class DAC(Module, AutoCSR):
|
|||
output_data_ch1 = Signal(14)
|
||||
|
||||
self.data_in = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
|
||||
self.data_in_csr = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
|
||||
|
||||
self.data_in_cdc = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
|
||||
self.data_in_csr_cdc = [Signal(14, reset_less=True), Signal(14, reset_less=True)]
|
||||
platform.add_period_constraint(dac_pads.dclkio, 10.0)
|
||||
|
||||
self.submodules.cdc_fifo = ClockDomainsRenamer({"write": "sys", "read": "dco2d"})(AsyncFIFO([("data", 56)], 4))
|
||||
self.comb += [
|
||||
self.data_in_csr[0].eq(self.output_value_ch0.storage),
|
||||
self.data_in_csr[1].eq(self.output_value_ch1.storage),
|
||||
self.cdc_fifo.sink.data.eq(Cat(self.data_in[0], self.data_in[1], self.data_in_csr[0], self.data_in_csr[1])),
|
||||
self.cdc_fifo.sink.stb.eq(~ResetSignal("sys")),
|
||||
Cat(self.data_in_cdc[0], self.data_in_cdc[1], self.data_in_csr_cdc[0], self.data_in_csr_cdc[1]).eq(self.cdc_fifo.source.data),
|
||||
self.cdc_fifo.source.ack.eq(~ResetSignal("dco2d")),
|
||||
]
|
||||
|
||||
self.comb += [
|
||||
Cat(manual_override, ch0_pd, ch1_pd).eq(self.dac_ctrl.storage),
|
||||
dac_pads.rst.eq(ResetSignal("sys")),
|
||||
dac_pads.rst.eq(ResetSignal("dco2d")),
|
||||
dac_afe_pads.ch1_pd_n.eq(~ch0_pd),
|
||||
dac_afe_pads.ch2_pd_n.eq(~ch1_pd),
|
||||
output_data_ch0.eq(
|
||||
Mux(manual_override, self.output_value_ch0.storage, self.data_in[0])
|
||||
Mux(manual_override, self.data_in_csr_cdc[0], self.data_in_cdc[0])
|
||||
),
|
||||
output_data_ch1.eq(
|
||||
Mux(manual_override, self.output_value_ch1.storage, self.data_in[1])
|
||||
Mux(manual_override, self.data_in_csr_cdc[1], self.data_in_cdc[1])
|
||||
),
|
||||
]
|
||||
|
||||
# data
|
||||
for lane in range(14):
|
||||
self.specials += DDROutput(
|
||||
i1 = output_data_ch0[lane],
|
||||
i2 = output_data_ch1[lane],
|
||||
o = dac_pads.data[lane],
|
||||
clk = ClockSignal("dco2d")
|
||||
)
|
||||
|
||||
# clock forwarding
|
||||
self.specials += DDROutput(
|
||||
i1 = 0b0,
|
||||
i2 = 0b1,
|
||||
o = dac_pads.dclkio,
|
||||
clk = ClockSignal("dco2d"),
|
||||
)
|
||||
self.specials += [
|
||||
Instance("ODDR",
|
||||
i_C=ClockSignal("dco2d"),
|
||||
i_CE=~ResetSignal("dco2d"),
|
||||
i_D1=output_data_ch0[lane], # DDR CLK Rising Edge
|
||||
i_D2=output_data_ch1[lane], # DDR CLK Falling Edge
|
||||
o_Q=dac_pads.data[lane],
|
||||
p_DDR_CLK_EDGE="SAME_EDGE")
|
||||
for lane in range(14)]
|
||||
self.specials += Instance("ODDR",
|
||||
i_C=ClockSignal("dco2d_45_degree"),
|
||||
i_CE=~ResetSignal("dco2d"),
|
||||
i_D1=0,
|
||||
i_D2=1,
|
||||
o_Q=dac_pads.dclkio,
|
||||
p_DDR_CLK_EDGE="SAME_EDGE")
|
||||
|
||||
|
||||
class AUX_DAC_CTRL(Module, AutoCSR):
|
||||
|
|
|
@ -147,6 +147,7 @@ class BaseSoC(PS7, AutoCSR):
|
|||
# self.add_main_adc(platform)
|
||||
self.submodules.adc = ADC(platform)
|
||||
self.csr_devices.append("adc")
|
||||
platform.add_false_path_constraints(self.crg.cd_sys.clk, self.adc.crg.cd_dco2d.clk)
|
||||
|
||||
# self.add_main_dac(platform)
|
||||
self.submodules.dac = DAC(platform)
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import mmap
|
||||
import os
|
||||
|
||||
import time
|
||||
import spidev
|
||||
from pyfastservo.common import (
|
||||
ADC_AFE_CTRL_ADDR,
|
||||
|
@ -33,6 +31,8 @@ from pyfastservo.common import (
|
|||
AUX_ADC_ADDR,
|
||||
MAP_MASK,
|
||||
PAGESIZE,
|
||||
write_to_memory,
|
||||
read_from_memory
|
||||
)
|
||||
|
||||
# /dev/spidev1.0 <=> spidev<BUS>.<DEVICE>
|
||||
|
@ -44,276 +44,181 @@ AUX_ADC_PORT_A = 2
|
|||
AUX_ADC_PORT_B = 3
|
||||
|
||||
|
||||
def main_adc_config(test_pattern):
|
||||
def spi_write(spi, address, value):
|
||||
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
|
||||
low_word = test_pattern & 0xFF
|
||||
|
||||
spi = spidev.SpiDev()
|
||||
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
|
||||
|
||||
try:
|
||||
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
|
||||
spi.max_speed_hz = 50000
|
||||
spi.mode = 0b00 # CPOL = 0 CPHA = 0
|
||||
spi.cshigh = False
|
||||
# spi.read0 = False
|
||||
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)
|
||||
|
||||
spi_buffer = [0x00, 0x80] # reset
|
||||
rx_buffer = [0x00, 0x00]
|
||||
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}")
|
||||
|
||||
spi.xfer2(spi_buffer)
|
||||
|
||||
# REGISTER A1
|
||||
spi_buffer = [0x01, 0x20] # set to Two's complement Data Format
|
||||
spi.xfer2(spi_buffer)
|
||||
|
||||
# read values back
|
||||
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")
|
||||
|
||||
# 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 = False
|
||||
# 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
|
||||
def read_frame():
|
||||
return read_from_memory(ADC_FRAME_ADDR, 1)[0]
|
||||
|
||||
def perform_bitslip():
|
||||
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"
|
||||
)
|
||||
current_frame = read_frame()
|
||||
if current_frame & 0x0F != 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; Currernt frame = 0x{current_frame:02x}")
|
||||
break
|
||||
print(f"No bitslip required; Current frame: 0x{current_frame:02x}")
|
||||
return
|
||||
|
||||
current_frame = read_from_memory(ADC_FRAME_ADDR, 1)[0]
|
||||
prev_frame = current_frame
|
||||
def mmcm_rst():
|
||||
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x0F
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, 0x10 | curr_cfg) # Reset MMCM
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Release MMCM Reset
|
||||
while not(read_frame() & 0x10):
|
||||
print(f"Waiting for MMCM to lock")
|
||||
time.sleep(0.001)
|
||||
|
||||
for i in range(32):
|
||||
def inc_ddr_clk_phase():
|
||||
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, 0x40 | curr_cfg) # Set MMCM Phase Shift to be INC
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, 0x60 | curr_cfg) # Assert MMCM Phase Shift EN High
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
|
||||
|
||||
def dec_ddr_clk_phase():
|
||||
curr_cfg = read_from_memory(ADC_AFE_CTRL_ADDR, 1)[0] & 0x1F
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, 0x00 | curr_cfg) # Set MMCM Phase Shift to be DEC
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, 0x20 | curr_cfg) # Assert MMCM Phase Shift EN High
|
||||
write_to_memory(ADC_AFE_CTRL_ADDR, curr_cfg) # Deassert MMCM Phase Shift EN High
|
||||
|
||||
def find_edge():
|
||||
prev_frame = read_frame()
|
||||
for tap_delay 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]
|
||||
current_frame = read_frame()
|
||||
|
||||
print(f"Tap delay: {tap_delay}")
|
||||
print(f"Current frame: 0x{current_frame:02x}")
|
||||
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
|
||||
print(f"prev_frame: 0x{prev_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
|
||||
if current_frame != prev_frame:
|
||||
final_delay = ((tap_delay+1) // 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 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")
|
||||
# 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)
|
||||
|
||||
adc_ch0 = read_from_memory(ADC_CH0_HIGH_ADDR, 4)
|
||||
print(f"ADC_CH0: 0x{adc_ch0}")
|
||||
def read_adc_channel(high_addr, low_addr):
|
||||
return (read_from_memory(high_addr, 1)[0] << 8) | read_from_memory(low_addr, 1)[0]
|
||||
|
||||
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]
|
||||
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 modify_bit(original_value, position, bit_value):
|
||||
mask = 1 << position
|
||||
return (original_value & ~mask) | (bit_value << position)
|
||||
def search_edge():
|
||||
for tap_delay in range(32):
|
||||
print(f"iDelay to: {tap_delay}")
|
||||
write_to_memory(ADC_DELAY_ADDR, tap_delay)
|
||||
time.sleep(1)
|
||||
current_frame = read_frame()
|
||||
print(f"Tap delay: {tap_delay}, Current frame: 0x{current_frame:02x}")
|
||||
print_adc_channels()
|
||||
|
||||
def print_adc_channel(ch):
|
||||
if ch == 0:
|
||||
adc_ch0 = read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR)
|
||||
print(f"Final ADC_CH0: 0x{adc_ch0:04x}")
|
||||
if ch == 1:
|
||||
adc_ch1 = read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR)
|
||||
print(f"Final ADC_CH1: 0x{adc_ch1:04x}")
|
||||
|
||||
def find_min_max_ch(ch):
|
||||
test = []
|
||||
for i in range(100):
|
||||
if ch == 0:
|
||||
test.append(read_adc_channel(ADC_CH0_HIGH_ADDR, ADC_CH0_LOW_ADDR))
|
||||
else:
|
||||
test.append(read_adc_channel(ADC_CH1_HIGH_ADDR, ADC_CH1_LOW_ADDR))
|
||||
print("ch", ch, hex(test[-1]))
|
||||
print("Min:", hex(min(test)))
|
||||
print("Max:", hex(max(test)))
|
||||
print("Diff:", hex(max(test)-min(test)))
|
||||
|
||||
|
||||
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)
|
||||
|
||||
def configure_ltc2195():
|
||||
spi = spidev.SpiDev()
|
||||
try:
|
||||
spi.open(1, 3) # AUX ADC 1?
|
||||
spi.max_speed_hz = 5000
|
||||
spi.mode = 0b00
|
||||
spi.open(MAIN_ADC_BUS, MAIN_ADC_DEVICE)
|
||||
spi.max_speed_hz = 50000
|
||||
spi.mode = 0b00 # CPOL = 0 CPHA = 0
|
||||
spi.cshigh = False
|
||||
|
||||
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
|
||||
test_pattern = 0x811F
|
||||
main_adc_config(spi, test_pattern)
|
||||
|
||||
verify_adc_registers(spi, {
|
||||
0x01: 0x20,
|
||||
0x02: 0x15,
|
||||
0x03: (test_pattern & 0xFF00) >> 8,
|
||||
0x04: test_pattern & 0xFF
|
||||
})
|
||||
|
||||
# ADC software reset put its PLL to sleep momentarily. Thus, MMCM needs to be reset as well.
|
||||
mmcm_rst()
|
||||
|
||||
# Performing Word Align
|
||||
perform_bitslip()
|
||||
find_edge()
|
||||
|
||||
# Printing it once is not enough to check whether the alignment is correct.
|
||||
for i in range(100):
|
||||
print_adc_channels()
|
||||
|
||||
main_adc_test_mode(spi, False)
|
||||
verify_adc_registers(spi, {0x02: 0x11}) # Verify test mode is off
|
||||
|
||||
# FIXME: AFE Gain 1x is not functional on that batch of fast servo under development
|
||||
enable_adc_afe(ch1_x10=1, ch2_x10=1)
|
||||
|
||||
#find_min_max_ch(0)
|
||||
#find_min_max_ch(1)
|
||||
|
||||
#for i in range(10):
|
||||
# print_adc_channel(0)
|
||||
|
||||
#for i in range(10):
|
||||
# print_adc_channel(1)
|
||||
|
||||
finally:
|
||||
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__":
|
||||
main()
|
||||
configure_ltc2195()
|
|
@ -17,6 +17,9 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import mmap
|
||||
|
||||
CSR_SIZE = 0x800
|
||||
MAP_SIZE = 0x1000
|
||||
MAP_MASK = 0xFFF
|
||||
|
@ -71,4 +74,47 @@ CTRL_ADDR = DAC_BASE_ADDR + CTRL_OFFSET
|
|||
CH0_HIGH_WORD_ADDR = DAC_BASE_ADDR + CH0_HIGH_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_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)
|
|
@ -17,8 +17,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import mmap
|
||||
import os
|
||||
import time
|
||||
|
||||
import spidev
|
||||
from pyfastservo.common import (
|
||||
|
@ -29,117 +28,69 @@ from pyfastservo.common import (
|
|||
CTRL_ADDR,
|
||||
MAP_MASK,
|
||||
PAGESIZE,
|
||||
write_to_memory,
|
||||
read_from_memory
|
||||
)
|
||||
|
||||
# /dev/spidev2.0 <=> spidev<BUS>.<DEVICE>
|
||||
MAIN_DAC_BUS = 2
|
||||
MAIN_DAC_DEVICE = 0
|
||||
|
||||
DAC_VERSION = 0x0A
|
||||
|
||||
|
||||
def main_dac_init():
|
||||
spi = spidev.SpiDev()
|
||||
def spi_write(spi, address, value):
|
||||
spi.xfer2([address, value])
|
||||
|
||||
try:
|
||||
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
|
||||
spi.max_speed_hz = 5000
|
||||
spi.mode = 0b00 # CPOL = 0 CPHA = 0
|
||||
spi.cshigh = False
|
||||
def spi_read(spi, address):
|
||||
rx_buffer = spi.xfer2([0x80 | address, 0x00])
|
||||
return rx_buffer[1]
|
||||
|
||||
spi_buffer = [0x00, 0x10] # software reset
|
||||
spi.xfer2(spi_buffer)
|
||||
def soft_reset(spi):
|
||||
spi_write(spi, 0x00, 0x10) # Software reset
|
||||
spi_write(spi, 0x00, 0x00) # Release software reset
|
||||
spi_read(spi, 0x00) # Read reset address (necessary for reset to take effect)
|
||||
|
||||
spi_buffer = [0x00, 0x00] # release software reset
|
||||
spi.xfer2(spi_buffer)
|
||||
def check_version(spi):
|
||||
version = spi_read(spi, 0x1F)
|
||||
print(f"DAC version: 0x{version:02X}")
|
||||
return version == DAC_VERSION
|
||||
|
||||
spi_buffer = [
|
||||
0x80,
|
||||
0x00,
|
||||
] # for some reason it is needed to read the reset address for reset to actually reset
|
||||
rx_buffer = spi.xfer2(spi_buffer)
|
||||
def configure_dac(spi):
|
||||
power_down_reg = spi_read(spi, 0x01)
|
||||
spi_write(spi, 0x01, power_down_reg & ~(1 << 0)) # Clear EXTREF bit for internal reference
|
||||
spi_write(spi, 0x0D, 0x00) # Set RREF to 10 kΩ for 1.0V reference
|
||||
spi_write(spi, 0x04, 0xA0) # Enable on-chip IRSET (1.6 kΩ for 20mA output)
|
||||
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, IFirst: True, IRising: True, DCI_EN: Enabled
|
||||
spi_write(spi, 0x14, 0x00)
|
||||
spi_write(spi, 0x14, 0x08) # Trigger the retimer to reacquire the clock relationship
|
||||
spi_write(spi, 0x14, 0x00)
|
||||
|
||||
spi_buffer = [0x9F, 0x00] # hardware version
|
||||
rx_buffer = spi.xfer2(spi_buffer)
|
||||
if rx_buffer[1] != DAC_VERSION:
|
||||
print(f"Unrecognized device: 0x{rx_buffer[1]:02X}")
|
||||
def dac_self_calibration(spi):
|
||||
spi_write(spi, 0x12, 0x00) # Reset calibration status
|
||||
spi_write(spi, 0x0E, 0x08) # Enable calibration clock, default divide ratio
|
||||
spi_write(spi, 0x0E, 0x38) # CALSELI = 1, CALSELQ = 1, CALCLK = 1
|
||||
spi_write(spi, 0x12, 0x10) # Set CALEN bit
|
||||
|
||||
print("=== Contents of spi buffer after DAC VERSION read back: ===")
|
||||
print(f"0x{rx_buffer[0]:02X}{rx_buffer[1]:02X}")
|
||||
|
||||
spi_buffer = [0x82, 00]
|
||||
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)
|
||||
while True:
|
||||
status = spi_read(spi, 0x0F)
|
||||
if status & 0xC0 == 0xC0: # Both CALSTATI and CALSTATQ are 1
|
||||
break
|
||||
time.sleep(0.01)
|
||||
|
||||
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):
|
||||
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
|
||||
print(f"REG contents: 0b{reg_contents:03b}")
|
||||
to_write = reg_contents | 0b1 if enable else reg_contents & 0b110
|
||||
write_to_memory(CTRL_ADDR, to_write)
|
||||
print(f"Set DAC Output Manual Override: {enable}")
|
||||
|
||||
|
||||
def power_down(channel, power_down=True):
|
||||
def power_down_afe(channel, power_down=True):
|
||||
assert channel in (0, 1)
|
||||
|
||||
bitmask = 1 << (channel + 1) & 0b111
|
||||
|
@ -150,33 +101,68 @@ def power_down(channel, power_down=True):
|
|||
to_write = reg_contents | value
|
||||
write_to_memory(CTRL_ADDR, to_write)
|
||||
reg_contents = read_from_memory(CTRL_ADDR, 1)[0]
|
||||
print(f"REG contents: 0b{reg_contents:03b}")
|
||||
print(f"Power Down DAC AFE Ch{channel}: {power_down}")
|
||||
|
||||
def set_dac_output(value):
|
||||
value = min(value, 0x3FFF)
|
||||
low_word = value & 0xFF
|
||||
high_word = (value >> 8) & 0x3F
|
||||
|
||||
def write_sample(channel, sample):
|
||||
assert channel in (0, 1)
|
||||
if channel == 0:
|
||||
addresses = [CH0_HIGH_WORD_ADDR, CH0_LOW_WORD_ADDR]
|
||||
# Note: DAC HIGH word and LOW word output are not updated
|
||||
# at the same time. On scope, you will see more than one step
|
||||
# of value changed.
|
||||
write_to_memory(CH0_HIGH_WORD_ADDR, high_word)
|
||||
write_to_memory(CH0_LOW_WORD_ADDR, low_word)
|
||||
write_to_memory(CH1_HIGH_WORD_ADDR, high_word)
|
||||
write_to_memory(CH1_LOW_WORD_ADDR, low_word)
|
||||
print(f"DAC output set to: 0x{value:04X}")
|
||||
|
||||
def check_clk_relationship(spi):
|
||||
clkmode_reg = spi_read(spi, 0x14)
|
||||
print(f"CLKMODE reg: 0x{clkmode_reg:02X}")
|
||||
if clkmode_reg & 0b00010000:
|
||||
print("Clock relationship is not found")
|
||||
return False
|
||||
else:
|
||||
addresses = [CH1_HIGH_WORD_ADDR, CH1_LOW_WORD_ADDR]
|
||||
print("Clock relationship is found")
|
||||
return True
|
||||
|
||||
low_word_value = sample & 0xFF
|
||||
high_word_value = (sample >> 8) & 0x3F
|
||||
values = [high_word_value, low_word_value]
|
||||
for addr, value in zip(addresses, values):
|
||||
write_to_memory(addr, value)
|
||||
def configure_ad9117():
|
||||
spi = spidev.SpiDev()
|
||||
spi.open(MAIN_DAC_BUS, MAIN_DAC_DEVICE)
|
||||
spi.max_speed_hz = 5000
|
||||
spi.mode = 0b00 # CPOL = 0 CPHA = 0
|
||||
spi.cshigh = False
|
||||
|
||||
try:
|
||||
soft_reset(spi)
|
||||
if not check_version(spi):
|
||||
print("Unrecognized DAC version")
|
||||
return False
|
||||
|
||||
def write_ramp():
|
||||
signal = [i for i in range(16384)]
|
||||
power_down_afe(0, True)
|
||||
power_down_afe(1, True)
|
||||
|
||||
for value in signal:
|
||||
write_sample(0, value)
|
||||
configure_dac(spi)
|
||||
check_clk_relationship(spi)
|
||||
dac_self_calibration(spi)
|
||||
|
||||
# Enable DAC outputs
|
||||
spi_write(spi, 0x01, spi_read(spi, 0x01) & ~((1 << 4) | (1 << 3)))
|
||||
|
||||
power_down_afe(0, False)
|
||||
power_down_afe(1, False)
|
||||
manual_override(False)
|
||||
|
||||
print("AD9117 configuration completed successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error configuring AD9117: {e}")
|
||||
return False
|
||||
|
||||
finally:
|
||||
spi.close()
|
||||
|
||||
def main():
|
||||
main_dac_init()
|
||||
power_down(0, False)
|
||||
power_down(1, False)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
configure_ad9117()
|
|
@ -21,8 +21,8 @@ from pyfastservo import adc, si5340, dac
|
|||
|
||||
def main():
|
||||
si5340.configure_si5340()
|
||||
adc.main()
|
||||
dac.main()
|
||||
adc.configure_ltc2195()
|
||||
dac.configure_ad9117()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -35,6 +35,15 @@ STATUS_LOSREF = 0x04
|
|||
STATUS_LOL = 0x08
|
||||
|
||||
|
||||
def write_register(bus, address, value):
|
||||
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):
|
||||
preamble = [
|
||||
(0x0B24, 0xC0),
|
||||
|
@ -45,7 +54,7 @@ def write_preamble(bus):
|
|||
(0x0B4E, 0x1A),
|
||||
]
|
||||
for address, value in preamble:
|
||||
bus.write_byte_data(IC_ADDR, address, value)
|
||||
write_register(bus, address, value)
|
||||
|
||||
def write_postamble(bus):
|
||||
postamble = [
|
||||
|
@ -54,7 +63,7 @@ def write_postamble(bus):
|
|||
(0x0B25, 0x02),
|
||||
]
|
||||
for address, value in postamble:
|
||||
bus.write_byte_data(IC_ADDR, address, value)
|
||||
write_register(bus, address, value)
|
||||
|
||||
def wait_device_ready(bus):
|
||||
for _ in range(15):
|
||||
|
@ -244,7 +253,7 @@ def configure_si5340():
|
|||
|
||||
print("Writing main configuration...")
|
||||
for address, value in main_config:
|
||||
bus.write_byte_data(IC_ADDR, address, value)
|
||||
write_register(bus, address, value)
|
||||
print("Main configuration written")
|
||||
|
||||
write_postamble(bus)
|
||||
|
|
22
flake.lock
22
flake.lock
|
@ -18,16 +18,16 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709237383,
|
||||
"narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=",
|
||||
"lastModified": 1723938990,
|
||||
"narHash": "sha256-9tUadhnZQbWIiYVXH8ncfGXGvkNq3Hag4RCBEMUk7MI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1536926ef5621b09bba54035ae2bb6d806d72ac8",
|
||||
"rev": "c42fcfbdfeae23e68fc520f9182dde9f38ad1890",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
|
@ -64,11 +64,11 @@
|
|||
"src-migen": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1702942348,
|
||||
"narHash": "sha256-gKIfHZxsv+jcgDFRW9mPqmwqbZXuRvXefkZcSFjOGHw=",
|
||||
"lastModified": 1721561053,
|
||||
"narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=",
|
||||
"owner": "m-labs",
|
||||
"repo": "migen",
|
||||
"rev": "50934ad10a87ade47219b796535978b9bdf24023",
|
||||
"rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -80,11 +80,11 @@
|
|||
"src-misoc": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1699352904,
|
||||
"narHash": "sha256-SglyTmXOPv8jJOjwAjJrj/WhAkItQfUbvKfUqrynwRg=",
|
||||
"lastModified": 1715647536,
|
||||
"narHash": "sha256-q+USDcaKHABwW56Jzq8u94iGPWlyLXMyVt0j/Gyg+IE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "a53859f2167c31ab5225b6c09f30cf05527b94f4",
|
||||
"revCount": 2452,
|
||||
"rev": "fea9de558c730bc394a5936094ae95bb9d6fa726",
|
||||
"revCount": 2455,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/m-labs/misoc.git"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
description = "Firmware for Sinara Fast-Servo based on Not-OS and Linien";
|
||||
|
||||
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
|
||||
inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-24.05;
|
||||
inputs.not-os.url = github:cleverca22/not-os;
|
||||
inputs.not-os.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
diff --git a/configuration.nix b/configuration.nix
|
||||
index 010c487..e1e85ba 100644
|
||||
index 010c487..2d08009 100644
|
||||
--- a/configuration.nix
|
||||
+++ b/configuration.nix
|
||||
@@ -1,4 +1,4 @@
|
||||
|
@ -8,7 +8,7 @@ index 010c487..e1e85ba 100644
|
|||
|
||||
{
|
||||
imports = [ ./qemu.nix ];
|
||||
@@ -7,10 +7,15 @@
|
||||
@@ -7,10 +7,16 @@
|
||||
environment.etc = {
|
||||
"ssh/authorized_keys.d/root" = {
|
||||
text = ''
|
||||
|
@ -18,6 +18,7 @@ index 010c487..e1e85ba 100644
|
|||
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBNdIiLvP2hmDUFyyE0oLOIXrjrMdWWpBV9/gPR5m4AiARx4JkufIDZzmptdYQ5FhJORJ4lluPqp7dAmahoSwg4lv9Di0iNQpHMJvNGZLHYKM1H1FWCCFIEDJ8bD4SVfrDg== root
|
||||
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBF/YybP+fQ0J+bNqM5Vgx5vDmVqVWsgUdF1moUxghv7d73GZAFaM6IFBdrXTAa33AwnWwDPMrTgP1V6SXBkb3ciJo/lD1urJGbydbSI5Ksq9d59wvOeANvyWYrQw6+eqTQ== sb
|
||||
+ ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFkmOCQ3BQh3qUjLtfdqyeBsx8rkk/QYlzB0TMrnfn6waLN6yKfPC3WVFv4zN5kNKb/OayvqDa+zfkKe85e/oIPQQKflF7GrCHdssz33DCnW90cz532E6iqG1pjeZjID2A== flo
|
||||
+ ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICAranL376soiSJ0kxdYNrwElcaZPW1heLFjs8Y7n0jT linuswck
|
||||
'';
|
||||
mode = "0444";
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
diff --git a/base.nix b/base.nix
|
||||
index 7eaee32..3a2a0a9 100644
|
||||
index 7eaee32..9aa338e 100644
|
||||
--- a/base.nix
|
||||
+++ b/base.nix
|
||||
@@ -27,6 +27,11 @@ with lib;
|
||||
|
@ -14,9 +14,12 @@ index 7eaee32..3a2a0a9 100644
|
|||
not-os.simpleStaticIp = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -86,15 +91,25 @@ with lib;
|
||||
@@ -84,17 +89,25 @@ with lib;
|
||||
};
|
||||
environment.etc = {
|
||||
"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
|
||||
- build-use-sandbox = true
|
||||
+ auto-optimise-store = true
|
||||
|
@ -28,8 +31,6 @@ index 7eaee32..3a2a0a9 100644
|
|||
+ extra-sandbox-paths = /bin/sh=${pkgs.runtimeShell} $(echo $extraPaths)
|
||||
+ max-jobs = auto
|
||||
+ sandbox = true
|
||||
+ substituters = https://cache.armv7l.xyz
|
||||
+ trusted-public-keys = cache.armv7l.xyz-1:kBY/eGnBAYiqYfg0fy0inWhshUo+pGFM3Pj7kIkmlBk=
|
||||
+ trusted-users = root
|
||||
EOF
|
||||
'';
|
||||
|
@ -151,7 +152,7 @@ index c61f9d6..fbdf0fd 100644
|
|||
};
|
||||
}
|
||||
diff --git a/zynq_image.nix b/zynq_image.nix
|
||||
index 3fa23ab..9d1621e 100644
|
||||
index 3fa23ab..069fe89 100644
|
||||
--- a/zynq_image.nix
|
||||
+++ b/zynq_image.nix
|
||||
@@ -1,66 +1,89 @@
|
||||
|
@ -163,7 +164,7 @@ index 3fa23ab..9d1621e 100644
|
|||
- # dont use overlays for the qemu, it causes a lot of wasted time on recompiles
|
||||
- x86pkgs = import pkgs.path { system = "x86_64-linux"; };
|
||||
- customKernel = pkgs.linux.override {
|
||||
+ customKernel = (pkgs.linux.override {
|
||||
+ customKernel = (pkgs.linux_6_6.override {
|
||||
extraConfig = ''
|
||||
OVERLAY_FS y
|
||||
+ MEDIA_SUPPORT n
|
||||
|
@ -249,7 +250,7 @@ index 3fa23ab..9d1621e 100644
|
|||
- environment.etc."service/getty/run".source = pkgs.writeShellScript "getty" ''
|
||||
- agetty ttyPS0 115200
|
||||
+ environment = {
|
||||
+ systemPackages = with pkgs; [ inetutils wget nano ];
|
||||
+ systemPackages = with pkgs; [ inetutils wget gnugrep nano vim ];
|
||||
+ etc = {
|
||||
+ "service/getty/run".source = pkgs.writeShellScript "getty" ''
|
||||
+ hostname ${config.networking.hostName}
|
||||
|
|
|
@ -394,10 +394,10 @@ index 0000000..53c5349
|
|||
\ No newline at end of file
|
||||
diff --git a/xilinx-fpga-manager.patch b/xilinx-fpga-manager.patch
|
||||
new file mode 100644
|
||||
index 0000000..59aa585
|
||||
index 0000000..33daffe
|
||||
--- /dev/null
|
||||
+++ b/xilinx-fpga-manager.patch
|
||||
@@ -0,0 +1,663 @@
|
||||
@@ -0,0 +1,676 @@
|
||||
+# Enable user-space interface for PL programming via Linux FPGA manager
|
||||
+# diff cherry-picked from Xilinx/linux-xilinx/tree/xlnx_rebase_v6.6_LTS
|
||||
+# commit IDs: e61c0a9, 0a38712, dc67651, 89a24e3, 8d224b1, 2a9c05f, 4e94580
|
||||
|
@ -425,7 +425,7 @@ index 0000000..59aa585
|
|||
+ tristate "Altera SOCFPGA FPGA Manager"
|
||||
+ depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST
|
||||
+diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
|
||||
+index 06651389c592..6e8c45974f28 100644
|
||||
+index 0f4035b089a2..3aa9f5f041f6 100644
|
||||
+--- a/drivers/fpga/fpga-mgr.c
|
||||
++++ b/drivers/fpga/fpga-mgr.c
|
||||
+@@ -8,6 +8,9 @@
|
||||
|
@ -673,7 +673,7 @@ index 0000000..59aa585
|
|||
+ NULL,
|
||||
+ };
|
||||
+ ATTRIBUTE_GROUPS(fpga_mgr);
|
||||
+@@ -732,6 +864,106 @@ void fpga_mgr_put(struct fpga_manager *mgr)
|
||||
+@@ -739,6 +871,106 @@ void fpga_mgr_put(struct fpga_manager *mgr)
|
||||
+ }
|
||||
+ EXPORT_SYMBOL_GPL(fpga_mgr_put);
|
||||
+
|
||||
|
@ -780,8 +780,8 @@ index 0000000..59aa585
|
|||
+ /**
|
||||
+ * fpga_mgr_lock - Lock FPGA manager for exclusive use
|
||||
+ * @mgr: fpga manager
|
||||
+@@ -779,6 +1011,9 @@ struct fpga_manager *
|
||||
+ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *info)
|
||||
+@@ -788,6 +1020,9 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *
|
||||
+ struct module *owner)
|
||||
+ {
|
||||
+ const struct fpga_manager_ops *mops = info->mops;
|
||||
++#ifdef CONFIG_FPGA_MGR_DEBUG_FS
|
||||
|
@ -790,7 +790,7 @@ index 0000000..59aa585
|
|||
+ struct fpga_manager *mgr;
|
||||
+ int id, ret;
|
||||
+
|
||||
+@@ -815,10 +1050,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
|
||||
+@@ -826,10 +1061,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *
|
||||
+ mgr->dev.of_node = parent->of_node;
|
||||
+ mgr->dev.id = id;
|
||||
+
|
||||
|
@ -819,7 +819,7 @@ index 0000000..59aa585
|
|||
+ /*
|
||||
+ * Initialize framework state by requesting low level driver read state
|
||||
+ * from device. FPGA may be in reset mode or may have been programmed
|
||||
+@@ -832,6 +1085,28 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
|
||||
+@@ -843,6 +1096,28 @@ __fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+
|
||||
|
@ -848,7 +848,7 @@ index 0000000..59aa585
|
|||
+ return mgr;
|
||||
+
|
||||
+ error_device:
|
||||
+@@ -882,6 +1157,10 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
|
||||
+@@ -894,6 +1169,10 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
|
||||
+ {
|
||||
+ dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name);
|
||||
+
|
||||
|
@ -881,10 +881,10 @@ index 0000000..59aa585
|
|||
+ &firmware_name)) {
|
||||
+ info->firmware_name = devm_kstrdup(dev, firmware_name,
|
||||
+diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c
|
||||
+index f3434e2c487b..db923746cac5 100644
|
||||
+index f3434e2c487b..d2434ed85eff 100644
|
||||
+--- a/drivers/fpga/zynqmp-fpga.c
|
||||
++++ b/drivers/fpga/zynqmp-fpga.c
|
||||
+@@ -43,25 +43,42 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
|
||||
+@@ -43,25 +43,47 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
|
||||
+ struct zynqmp_fpga_priv *priv;
|
||||
+ dma_addr_t dma_addr;
|
||||
+ u32 eemi_flags = 0;
|
||||
|
@ -915,6 +915,11 @@ index 0000000..59aa585
|
|||
++
|
||||
+ 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)
|
||||
+ eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
|
||||
+
|
||||
|
@ -931,20 +936,22 @@ index 0000000..59aa585
|
|||
+ return ret;
|
||||
+ }
|
||||
+diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
|
||||
+index 9dda7d9898ff..edaf77160746 100644
|
||||
+index e8b12ec8b060..ffd2dfdb6abd 100644
|
||||
+--- a/include/linux/firmware/xlnx-zynqmp.h
|
||||
++++ b/include/linux/firmware/xlnx-zynqmp.h
|
||||
+@@ -70,6 +70,8 @@
|
||||
+@@ -83,6 +83,10 @@
|
||||
+ */
|
||||
+ #define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U
|
||||
+ #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_DEVKEY BIT(4)
|
||||
+
|
||||
+ /* FPGA Status Reg */
|
||||
+ #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
|
||||
+index 54f63459efd6..c96a4405f909 100644
|
||||
+index 0d4fe068f3d8..f884d268c974 100644
|
||||
+--- a/include/linux/fpga/fpga-mgr.h
|
||||
++++ b/include/linux/fpga/fpga-mgr.h
|
||||
+@@ -9,8 +9,11 @@
|
||||
|
@ -959,7 +966,7 @@ index 0000000..59aa585
|
|||
+ struct fpga_manager;
|
||||
+ struct sg_table;
|
||||
+
|
||||
+@@ -66,17 +69,25 @@ enum fpga_mgr_states {
|
||||
+@@ -66,17 +69,29 @@ enum fpga_mgr_states {
|
||||
+ *
|
||||
+ * %FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting
|
||||
+ *
|
||||
|
@ -973,6 +980,10 @@ index 0000000..59aa585
|
|||
++ *
|
||||
++ * %FPGA_MGR_USERKEY_ENCRYPTED_BITSTREAM: indicates bitstream is encrypted with
|
||||
++ * 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_EXTERNAL_CONFIG BIT(1)
|
||||
|
@ -986,7 +997,7 @@ index 0000000..59aa585
|
|||
+
|
||||
+ /**
|
||||
+ * struct fpga_image_info - information specific to an FPGA image
|
||||
+@@ -86,6 +97,7 @@ enum fpga_mgr_states {
|
||||
+@@ -86,6 +101,7 @@ enum fpga_mgr_states {
|
||||
+ * @config_complete_timeout_us: maximum time for FPGA to switch to operating
|
||||
+ * status in the write_complete op.
|
||||
+ * @firmware_name: name of FPGA image firmware file
|
||||
|
@ -994,7 +1005,7 @@ index 0000000..59aa585
|
|||
+ * @sgt: scatter/gather table containing FPGA image
|
||||
+ * @buf: contiguous buffer containing FPGA image
|
||||
+ * @count: size of buf
|
||||
+@@ -102,6 +114,7 @@ struct fpga_image_info {
|
||||
+@@ -102,6 +118,7 @@ struct fpga_image_info {
|
||||
+ u32 disable_timeout_us;
|
||||
+ u32 config_complete_timeout_us;
|
||||
+ char *firmware_name;
|
||||
|
@ -1002,7 +1013,7 @@ index 0000000..59aa585
|
|||
+ struct sg_table *sgt;
|
||||
+ const char *buf;
|
||||
+ size_t count;
|
||||
+@@ -160,6 +173,7 @@ struct fpga_manager_info {
|
||||
+@@ -160,6 +177,7 @@ struct fpga_manager_info {
|
||||
+ * @write: write count bytes 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
|
||||
|
@ -1010,7 +1021,7 @@ index 0000000..59aa585
|
|||
+ * @fpga_remove: optional: Set FPGA into a specific state during driver remove
|
||||
+ * @groups: optional attribute groups.
|
||||
+ *
|
||||
+@@ -182,6 +196,7 @@ struct fpga_manager_ops {
|
||||
+@@ -182,6 +200,7 @@ struct fpga_manager_ops {
|
||||
+ int (*write_sg)(struct fpga_manager *mgr, struct sg_table *sgt);
|
||||
+ int (*write_complete)(struct fpga_manager *mgr,
|
||||
+ struct fpga_image_info *info);
|
||||
|
@ -1018,7 +1029,7 @@ index 0000000..59aa585
|
|||
+ void (*fpga_remove)(struct fpga_manager *mgr);
|
||||
+ const struct attribute_group **groups;
|
||||
+ };
|
||||
+@@ -196,21 +211,35 @@ struct fpga_manager_ops {
|
||||
+@@ -196,23 +215,37 @@ struct fpga_manager_ops {
|
||||
+ /**
|
||||
+ * struct fpga_manager - fpga manager structure
|
||||
+ * @name: name of low level fpga manager
|
||||
|
@ -1031,6 +1042,7 @@ index 0000000..59aa585
|
|||
+ * @state: state of fpga manager
|
||||
+ * @compat_id: FPGA manager id for compatibility check.
|
||||
+ * @mops: pointer to struct of fpga manager ops
|
||||
+ * @mops_owner: module containing the mops
|
||||
+ * @priv: low level driver private date
|
||||
++ * @err: low level driver error code
|
||||
++ * @dir: debugfs image directory
|
||||
|
@ -1046,6 +1058,7 @@ index 0000000..59aa585
|
|||
+ enum fpga_mgr_states state;
|
||||
+ struct fpga_compat_id *compat_id;
|
||||
+ const struct fpga_manager_ops *mops;
|
||||
+ struct module *mops_owner;
|
||||
+ void *priv;
|
||||
++ int err;
|
||||
++#ifdef CONFIG_FPGA_MGR_DEBUG_FS
|
||||
|
@ -1054,21 +1067,21 @@ index 0000000..59aa585
|
|||
+ };
|
||||
+
|
||||
+ #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)
|
||||
+@@ -244,4 +273,6 @@ struct fpga_manager *
|
||||
+ devm_fpga_mgr_register(struct device *parent, const char *name,
|
||||
+ const struct fpga_manager_ops *mops, void *priv);
|
||||
+@@ -258,4 +291,6 @@ __devm_fpga_mgr_register(struct device *parent, const char *name,
|
||||
+ const struct fpga_manager_ops *mops, void *priv,
|
||||
+ struct module *owner);
|
||||
+
|
||||
++#define FPGA_IOCTL_LOAD_DMA_BUFF _IOWR('R', 1, __u32)
|
||||
++
|
||||
+ #endif /*_LINUX_FPGA_MGR_H */
|
||||
diff --git a/zynq_image.nix b/zynq_image.nix
|
||||
index 9d1621e..012e50c 100644
|
||||
index d5c5eda..7ede584 100644
|
||||
--- a/zynq_image.nix
|
||||
+++ b/zynq_image.nix
|
||||
@@ -3,6 +3,16 @@
|
||||
with lib;
|
||||
let
|
||||
customKernel = (pkgs.linux.override {
|
||||
customKernel = (pkgs.linux_6_6.override {
|
||||
+ kernelPatches = [
|
||||
+ ({
|
||||
+ name = "xilinx-configfs-overlays";
|
||||
|
|
Loading…
Reference in New Issue