From 39d77d4c27c366a7dfe37e4df49ff4721dc4c52d Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 6 Dec 2024 15:10:19 +0300 Subject: [PATCH 001/397] add xo & apll1 settings --- src/lib/hw/lmk05318/lmk05318.c | 114 +++++++++++++++++++++++++++++++-- src/lib/hw/lmk05318/lmk05318.h | 14 ++++ 2 files changed, 122 insertions(+), 6 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 1101f245..fec496d5 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -5,13 +5,15 @@ #include #include "lmk05318.h" -#include "def_lmk05318.h" #include "lmk05318_rom.h" #include enum { VCO_APLL1 = 2500000000ull, + VCO_APLL1_MIN = 2499750000ull, + VCO_APLL1_MAX = 2500250000ull, + VCO_APLL2_MIN = 5500000000ull, VCO_APLL2_MAX = 6250000000ull, @@ -22,6 +24,12 @@ enum { APLL2_PD_MAX = 150000000, OUT_FREQ_MAX = 800000000ull, + + XO_FREF_MAX = 100000000ull, + XO_FREF_MIN = 10000000ull, + + APLL1_DIVIDER_MIN = 1, + APLL1_DIVIDER_MAX = 32, }; @@ -103,6 +111,12 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmk05318_stat out->fref_pll2_div_rp = 3; out->fref_pll2_div_rs = (((VCO_APLL1 + APLL2_PD_MAX - 1) / APLL2_PD_MAX) + out->fref_pll2_div_rp - 1) / out->fref_pll2_div_rp; + + out->xo.fref = 0; + out->xo.doubler_enabled = false; + out->xo.fdet_bypass = false; + out->xo.type = XO_TYPE_DC_DIFF_EXT; + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); return 0; } @@ -110,7 +124,8 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmk05318_stat int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) { - const unsigned pre_div = 2; + const unsigned apll2_post_div = 2; + unsigned fref = VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; if (fref < APLL2_PD_MIN || fref > APLL2_PD_MAX) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 PFD should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", @@ -125,17 +140,17 @@ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs));; } - unsigned div = ((VCO_APLL2_MAX / pre_div)) / freq; - uint64_t fvco = (uint64_t)freq * div * pre_div; + unsigned div = ((VCO_APLL2_MAX / apll2_post_div)) / freq; + uint64_t fvco = (uint64_t)freq * div * apll2_post_div; unsigned n = fvco / fref; unsigned num = (fvco - n * (uint64_t)fref) * (1ull << 24) / fref; int res; - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 FREQ=%u FVCO=%lld N=%d NUM=%d DIV=%d\n", freq, (long long)fvco, n, num, div); + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 FREQ=%u FVCO=%" PRIu64 " N=%d NUM=%d DIV=%d\n", freq, fvco, n, num, div); uint32_t regs[] = { MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), - MAKE_LMK05318_PLL2_CTRL2(pre_div - 1, pre_div - 1), + MAKE_LMK05318_PLL2_CTRL2(apll2_post_div - 1, apll2_post_div - 1), MAKE_LMK05318_PLL2_NDIV_BY0(n), MAKE_LMK05318_PLL2_NDIV_BY1(n), MAKE_LMK05318_PLL2_NUM_BY0(num), @@ -152,6 +167,93 @@ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) return 0; } +int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, enum xo_type_options xo_type, + bool xo_doubler_enabled, bool xo_fdet_bypass) +{ + if(xo_fref < XO_FREF_MIN || xo_fref > XO_FREF_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 XO input fref should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", + (uint64_t)XO_FREF_MIN, (uint64_t)XO_FREF_MAX, xo_fref); + return -EINVAL; + } + + switch((int)xo_type) + { + case XO_TYPE_DC_DIFF_EXT: + case XO_TYPE_AC_DIFF_EXT: + case XO_TYPE_AC_DIFF_INT_100: + case XO_TYPE_HCSL_INT_50: + case XO_TYPE_CMOS: + case XO_TYPE_SE_INT_50: + break; + default: + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 XO input type %d is not supported!\n", (int)xo_type); + return -EINVAL; + } + + uint32_t regs[] = { + MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0), + MAKE_LMK05318_XO_CLKCTL2(xo_type) + }; + + int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + if(res) + return res; + + d->xo.fref = xo_fref; + d->xo.doubler_enabled = xo_doubler_enabled; + d->xo.type = xo_type; + d->xo.fdet_bypass = xo_fdet_bypass; + + return 0; +} + +int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, + uint32_t xo_fref, enum xo_type_options xo_type, + bool xo_doubler_enabled, bool xo_fdet_bypass, + unsigned *last_div) +{ + if (freq < 1e6) { + // Disable + uint32_t regs[] = { + MAKE_LMK05318_PLL1_CTRL0(1), + }; + return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs));; + } + + int res = lmk05318_set_xo_fref(d, xo_fref, xo_type, xo_doubler_enabled, xo_fdet_bypass); + if(res) + return res; + + unsigned fref = (d->xo.fref / APLL1_DIVIDER_MAX) * (d->xo.doubler_enabled ? 2 : 1); + unsigned div = VCO_APLL1_MAX / freq; + uint64_t fvco = (uint64_t)freq * div; + unsigned n = fvco / fref; + uint64_t num = (fvco - n * (uint64_t)fref) * (1ull << 40) / fref; + + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FREQ=%u FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 " DIV=%d\n", freq, fvco, n, num, div); + + uint32_t regs[] = { + MAKE_LMK05318_PLL1_CTRL0(1), + MAKE_LMK05318_XO_CONFIG(APLL1_DIVIDER_MAX), + MAKE_LMK05318_PLL1_NDIV_BY0(n), + MAKE_LMK05318_PLL1_NDIV_BY1(n), + MAKE_LMK05318_PLL1_NUM_BY0(num), + MAKE_LMK05318_PLL1_NUM_BY1(num), + MAKE_LMK05318_PLL1_NUM_BY2(num), + MAKE_LMK05318_PLL1_NUM_BY3(num), + MAKE_LMK05318_PLL1_NUM_BY4(num), + MAKE_LMK05318_PLL1_CTRL0(0), + }; + + res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + if (res) + return res; + + *last_div = div; + return 0; +} + int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, unsigned udiv) { diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index baa8e41f..af1c4179 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -5,6 +5,7 @@ #define LMK05318_H #include +#include "def_lmk05318.h" struct lmk05318_state { lldev_t dev; @@ -17,6 +18,13 @@ struct lmk05318_state { // VCO2 freq uint64_t vco2_freq; + + struct { + uint32_t fref; + enum xo_type_options type; + bool doubler_enabled; + bool fdet_bypass; + } xo; }; enum lmk05318_type { @@ -40,4 +48,10 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); +int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, enum xo_type_options xo_type, + bool xo_doubler_enabled, bool xo_fdet_bypass); +int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, + uint32_t xo_fref, enum xo_type_options xo_type, + bool xo_doubler_enabled, bool xo_fdet_bypass, + unsigned *last_div); #endif From d0e88ea17403e3744f100a5efd3b8b1dd8da0901 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 6 Dec 2024 15:45:27 +0300 Subject: [PATCH 002/397] add dpll_mode --- src/lib/hw/lmk05318/lmk05318.c | 3 ++- src/lib/hw/lmk05318/lmk05318.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index fec496d5..dbd1f4f5 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -210,7 +210,7 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, enum xo_type_opt int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, uint32_t xo_fref, enum xo_type_options xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass, + bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode, unsigned *last_div) { if (freq < 1e6) { @@ -236,6 +236,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, uint32_t regs[] = { MAKE_LMK05318_PLL1_CTRL0(1), MAKE_LMK05318_XO_CONFIG(APLL1_DIVIDER_MAX), + MAKE_LMK05318_PLL1_MODE(dpll_mode ? 1 : 0), MAKE_LMK05318_PLL1_NDIV_BY0(n), MAKE_LMK05318_PLL1_NDIV_BY1(n), MAKE_LMK05318_PLL1_NUM_BY0(num), diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index af1c4179..3c04c7c2 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -52,6 +52,6 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, enum xo_type_opt bool xo_doubler_enabled, bool xo_fdet_bypass); int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, uint32_t xo_fref, enum xo_type_options xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass, + bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode, unsigned *last_div); #endif From 00a698f5d840bb6365d1028d053bd80cf7aedbe4 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 6 Dec 2024 16:24:15 +0300 Subject: [PATCH 003/397] fix in apll1 divider setting --- src/lib/hw/lmk05318/lmk05318.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index dbd1f4f5..8dd7295a 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -235,7 +235,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, uint32_t regs[] = { MAKE_LMK05318_PLL1_CTRL0(1), - MAKE_LMK05318_XO_CONFIG(APLL1_DIVIDER_MAX), + MAKE_LMK05318_XO_CONFIG(APLL1_DIVIDER_MAX - 1), MAKE_LMK05318_PLL1_MODE(dpll_mode ? 1 : 0), MAKE_LMK05318_PLL1_NDIV_BY0(n), MAKE_LMK05318_PLL1_NDIV_BY1(n), From fa9753cb8e23173c9ef42ca3e488c7cc8670aad5 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 12 Dec 2024 09:51:41 +0300 Subject: [PATCH 004/397] solver stage#1 --- src/lib/hw/lmk05318/lmk05318.c | 152 ++++++++++++++++++++++++++++++++- src/lib/hw/lmk05318/lmk05318.h | 27 +++++- 2 files changed, 177 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 8dd7295a..d01a9d07 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -3,6 +3,8 @@ #include #include +#include +#include #include "lmk05318.h" #include "lmk05318_rom.h" @@ -30,6 +32,9 @@ enum { APLL1_DIVIDER_MIN = 1, APLL1_DIVIDER_MAX = 32, + + APLL2_PDIV_MIN = 2, + APLL2_PDIV_MAX = 7, }; @@ -256,7 +261,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, } -int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, unsigned udiv) +int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) { if (port > 7) return -EINVAL; @@ -301,3 +306,148 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } +static unsigned max_odiv(unsigned port) +{ + switch(port) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: return 256; + case 7: return 4 * 256; + } + return 1; +} + +#define MAX(a, b) (a) > (b) ? (a) : (b) +#define MIN(a, b) (a) < (b) ? (a) : (b) + +int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* outs, unsigned n_outs) +{ + struct range + { + uint64_t min, max; + }; + typedef struct range range_t; + + int res = 0; + + if(!outs || !n_outs || n_outs > MAX_OUT_PORTS) + return -EINVAL; + + //validate dup ports + { + bool p[MAX_OUT_PORTS] = {0,0,0,0,0,0,0,0}; + for(unsigned i = 0; i < n_outs; ++i) + { + lmk05318_out_config_t* out = outs + i; + if(out->port > MAX_OUT_PORTS - 1) + return -EINVAL; + if(p[out->port]) + return -EINVAL; + p[out->port] = true; + } + } + + //validate port0/port1 & port2/port3 have equal freqs + { + range_t* port[4] = {NULL, NULL, NULL, NULL}; + for(unsigned i = 0; i < n_outs; ++i) + { + lmk05318_out_config_t* out = outs + i; + const range_t r = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; + switch(out->port) + { + case 0: + case 1: + case 2: + case 3: + port[out->port] = malloc(sizeof(range_t)); *port[out->port] = r; break; + } + } + + res = (port[0] && port[1] && memcmp(port[0], port[1], 16)) || (port[2] && port[3] && memcmp(port[2], port[3], 16)) ? + -EINVAL : 0; + + for(unsigned i = 0; i < 4; ++i) free(port[i]); + if(res) + return res; + } + + //first we try routing ports to APLL1 + for(unsigned i = 0; i < n_outs; ++i) + { + lmk05318_out_config_t* out = outs + i; + out->solved = false; + + const range_t out_freq = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; + const range_t out_pre_div_freq = {out_freq.min, out_freq.max * max_odiv(out->port)}; + + if(VCO_APLL1 >= out_pre_div_freq.min && VCO_APLL1 <= out_pre_div_freq.max) + { + const uint64_t div = (uint64_t)VCO_APLL1 / out->wanted.freq; + const uint32_t freq = VCO_APLL1 / div; + if(freq >= out_freq.min && freq <= out_freq.max) + { + out->solved = true; + out->result.out_div = div; + out->result.freq = freq; + out->result.mux = out->wanted.revert_phase ? OUT_PLL_SEL_APLL1_P1_INV : OUT_PLL_SEL_APLL1_P1; + } + } + + //we cannot revert phase for ports NOT linked to APLL1 + if(!out->solved && out->wanted.revert_phase) + return -EINVAL; + } + + //second - try routing to APLL2 + + //check if all the requested freqs can be potentially solved + range_t f_vco2[MAX_OUT_PORTS] = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; + + for(unsigned i = 0; i < n_outs; ++i) + { + lmk05318_out_config_t* out = outs + i; + if(out->solved) + continue; + + const range_t out_freq = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; + const range_t out_pre_div_freq = {out_freq.min * APLL2_PDIV_MIN, out_freq.max * max_odiv(out->port) * APLL2_PDIV_MAX}; + + uint64_t eff_min = MAX(out_pre_div_freq.min, VCO_APLL2_MIN); + uint64_t eff_max = MIN(out_pre_div_freq.max, VCO_APLL2_MAX); + + if(eff_min > eff_max) + return -EINVAL; + + //narrow fvco2 band + f_vco2[out->port].min = eff_min; + f_vco2[out->port].max = eff_max; + } + + //now we find the complete fvco2 intersection + uint64_t f_vco2_min = VCO_APLL2_MIN; + uint64_t f_vco2_max = VCO_APLL2_MAX; + + for(unsigned i = 0; i < n_outs; ++i) + { + if(!f_vco2[i].min && !f_vco2[i].min) + continue; + + f_vco2_min = MAX(f_vco2_min, f_vco2[i].min); + f_vco2_max = MIN(f_vco2_max, f_vco2[i].max); + } + + if(f_vco2_min > f_vco2_max) + return -EINVAL; + + //next we go to bisect, first with PD1, second - with PD2 + + + return res; +} + diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 3c04c7c2..04068029 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -7,6 +7,8 @@ #include #include "def_lmk05318.h" +#define MAX_OUT_PORTS 8 + struct lmk05318_state { lldev_t dev; unsigned subdev; @@ -36,11 +38,34 @@ enum lmk05318_type { }; typedef struct lmk05318_state lmk05318_state_t; +typedef enum lmk05318_type lmk05318_type_t; + +struct lmk05318_out_config +{ + unsigned port; //0..7 + bool solved; + + struct + { + uint32_t freq; + unsigned freq_delta_plus, freq_delta_minus; + bool revert_phase; + lmk05318_type_t type; + } wanted; + + struct + { + uint32_t freq; + uint64_t out_div; + enum lmk05318_out_pll_sel_t mux; + } result; +}; +typedef struct lmk05318_out_config lmk05318_out_config_t; int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmk05318_state_t* out); int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div); -int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, unsigned div); +int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t div); int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype); From 88c811611d13c8724569d508b5d2dfebd9329d23 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 13 Dec 2024 23:01:28 +0300 Subject: [PATCH 005/397] solver stage#2 --- src/lib/hw/lmk05318/lmk05318.c | 402 +++++++++++++++++++++----- src/lib/hw/lmk05318/lmk05318.h | 9 +- src/lib/hw/lmk05318/lmk05318_solver.h | 32 ++ 3 files changed, 372 insertions(+), 71 deletions(-) create mode 100644 src/lib/hw/lmk05318/lmk05318_solver.h diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index d01a9d07..a63ded3b 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1,13 +1,17 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +#include #include #include #include #include +#include +#include "def_lmk05318.h" #include "lmk05318.h" #include "lmk05318_rom.h" +#include "lmk05318_solver.h" #include @@ -172,7 +176,7 @@ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) return 0; } -int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, enum xo_type_options xo_type, +int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, bool xo_doubler_enabled, bool xo_fdet_bypass) { if(xo_fref < XO_FREF_MIN || xo_fref > XO_FREF_MAX) @@ -214,7 +218,7 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, enum xo_type_opt } int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, - uint32_t xo_fref, enum xo_type_options xo_type, + uint32_t xo_fref, int xo_type, bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode, unsigned *last_div) { @@ -306,83 +310,309 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -static unsigned max_odiv(unsigned port) +//idx is NOT a port but OD index (0..5) +static unsigned max_odiv(unsigned idx) { - switch(port) + assert(idx < 6); + + switch(idx) { case 0: case 1: case 2: case 3: - case 4: - case 5: - case 6: return 256; - case 7: return 4 * 256; + case 4: return 256; + case 5: return 4 * 256; } return 1; } -#define MAX(a, b) (a) > (b) ? (a) : (b) -#define MIN(a, b) (a) < (b) ? (a) : (b) +/***************************************************************************************************************************/ + +static int comp_u64(const void * elem1, const void * elem2) +{ + const uint64_t* f = (uint64_t*)elem1; + const uint64_t* s = (uint64_t*)elem2; + + if(*f < *s) return -1; + if(*f > *s) return 1; + return 0; +} -int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* outs, unsigned n_outs) +static int comp_intersection_desc(const void * elem1, const void * elem2) { - struct range + const intersection_t* f = (intersection_t*)elem1; + const intersection_t* s = (intersection_t*)elem2; + + if(f->count < s->count) return 1; + if(f->count > s->count) return -1; + return 0; +} + +int lmk05318_range_solver(const range_t* diaps, unsigned diaps_num, range_solution_t* solution) +{ + assert(diaps_num <= DIAP_MAX); + char logtmp[2048]; + unsigned loglen; + + USDR_LOG("5318", USDR_LOG_DEBUG, "input ranges:->"); + for(unsigned i = 0; i < diaps_num; ++i) { - uint64_t min, max; - }; - typedef struct range range_t; + USDR_LOG("5318", USDR_LOG_DEBUG, "%d -> %lu : %lu", i, diaps[i].min, diaps[i].max); + } - int res = 0; + // get wrapper points (ends of our diaps) + uint64_t wrapper_points[diaps_num * 2]; + for(unsigned i = 0; i < diaps_num * 2; i += 2) + { + wrapper_points[i + 0] = diaps[i >> 1].min; + wrapper_points[i + 1] = diaps[i >> 1].max; + } + + qsort(wrapper_points, diaps_num * 2, sizeof(uint64_t), comp_u64); - if(!outs || !n_outs || n_outs > MAX_OUT_PORTS) - return -EINVAL; - //validate dup ports + USDR_LOG("5318", USDR_LOG_DEBUG, "wrap points:-> "); + for(unsigned i = 0; i < diaps_num * 2; ++i) { - bool p[MAX_OUT_PORTS] = {0,0,0,0,0,0,0,0}; - for(unsigned i = 0; i < n_outs; ++i) + USDR_LOG("5318", USDR_LOG_DEBUG, "%lu, ", wrapper_points[i]); + } + + //and remove dups + uint64_t uniq_wrapper_points[diaps_num * 2]; + unsigned uniq_wrapper_points_num = 0; + for(unsigned i = 0; i < diaps_num * 2; ++i) + { + if(i == 0 || wrapper_points[i] != wrapper_points[i-1]) { - lmk05318_out_config_t* out = outs + i; - if(out->port > MAX_OUT_PORTS - 1) - return -EINVAL; - if(p[out->port]) - return -EINVAL; - p[out->port] = true; + uniq_wrapper_points[uniq_wrapper_points_num++] = wrapper_points[i]; } } - //validate port0/port1 & port2/port3 have equal freqs + loglen = snprintf(logtmp, sizeof(logtmp), "uniq wrap points:-> "); + for(unsigned i = 0; i < uniq_wrapper_points_num; ++i) { - range_t* port[4] = {NULL, NULL, NULL, NULL}; - for(unsigned i = 0; i < n_outs; ++i) + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%lu, ", uniq_wrapper_points[i]); + } + USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); + + //build intersections within the intervals between wrapper points + const unsigned intervals_count = uniq_wrapper_points_num - 1; + intersection_t intersections[intervals_count]; + for(unsigned i = 0; i < intervals_count; ++i) + { + intersection_t* is = intersections + i; + const uint64_t min = uniq_wrapper_points[i + 0]; + const uint64_t max = uniq_wrapper_points[i + 1]; + + //initialize the insersection struct + is->count = 0; + memset(is->diap_idxs, 0, sizeof(is->diap_idxs)); + is->range.min = min; + is->range.max = max; + + //here is our moving point - in the middle of the diapason + const uint64_t point = (max + min) >> 1; + + //check how many diaps it intersects + for(unsigned j = 0; j < diaps_num; ++j) { - lmk05318_out_config_t* out = outs + i; - const range_t r = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; - switch(out->port) + if(point >= diaps[j].min && point <= diaps[j].max) { - case 0: - case 1: - case 2: - case 3: - port[out->port] = malloc(sizeof(range_t)); *port[out->port] = r; break; + is->diap_idxs[is->count++] = j; } } + } - res = (port[0] && port[1] && memcmp(port[0], port[1], 16)) || (port[2] && port[3] && memcmp(port[2], port[3], 16)) ? - -EINVAL : 0; + //sort it desc to get the most massive intersection on the top + qsort(intersections, intervals_count, sizeof(intersection_t), comp_intersection_desc); - for(unsigned i = 0; i < 4; ++i) free(port[i]); - if(res) - return res; + USDR_LOG("5318", USDR_LOG_DEBUG, "intersects:->"); + loglen = 0; + for(unsigned i = 0; i < intervals_count; ++i) + { + intersection_t* is = intersections + i; + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "diaps {"); + for(unsigned j = 0; j < is->count; ++j) + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%d,", is->diap_idxs[j]); + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen,"} have %d intersections in range[%lu, %lu]", is->count, is->range.min, is->range.max); + USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); } - //first we try routing ports to APLL1 + //reduce to find a complete solution + for(unsigned z = 0; z < intervals_count; ++z) + { + intersection_t* main_is = intersections + z; + + if(!main_is->count) + break; + + //after sort assume the first intersect is the best, and exclude these diaps from the others + unsigned excludes[diaps_num]; + unsigned excludes_count = main_is->count; + memcpy(excludes, intersections + z, excludes_count * sizeof(unsigned)); + + for(unsigned i = z + 1; i < intervals_count; ++i) + { + intersection_t* is = intersections + i; + unsigned tmp_arr[diaps_num]; + unsigned tmp_n = 0; + + for(unsigned j = 0; j < is->count; ++j) + { + bool is_in = false; + for(unsigned k = 0; k < excludes_count; ++k) + { + if(excludes[k] == is->diap_idxs[j]) + { + is_in = true; + break; + } + } + if(!is_in) + tmp_arr[tmp_n++] = is->diap_idxs[j]; + } + + //hint - if we going to collapse this intersection part, and we see it is == to the current + if(!tmp_n && main_is->count == is->count) + { + //and the diap ranges of them are adjacent + if(main_is->range.min == is->range.max || main_is->range.max == is->range.min) + { + //merge them to one diapason + main_is->range.min = MIN(main_is->range.min, is->range.min); + main_is->range.max = MAX(main_is->range.max, is->range.max); + } + } + + is->count = tmp_n; + memcpy(is->diap_idxs, tmp_arr, tmp_n * sizeof(unsigned)); + } + + //sort it again to proceed for the next loop + qsort(intersections + z, intervals_count - z, sizeof(intersection_t), comp_intersection_desc); + + USDR_LOG("5318", USDR_LOG_DEBUG, "intersects(%d):->", z); + loglen = 0; + for(unsigned i = 0; i < intervals_count; ++i) + { + intersection_t* is = intersections + i; + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "diaps {"); + for(unsigned j = 0; j < is->count; ++j) + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%d,", is->diap_idxs[j]); + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen,"} have %d intersections in range[%lu, %lu]", + is->count, is->range.min, is->range.max); + + USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); + } + } + + //we need only 2 effective diapasons due to only 2 PDs - PD1 and PD2 + static const unsigned MAX_RANGES_IN_SOLUTION = 2; + + solution->count = 0; + unsigned total = 0; + + for(unsigned i = 0; i < MAX_RANGES_IN_SOLUTION; ++i) + { + intersection_t* is = intersections + i; + solution->is[i] = *is; + ++solution->count; + + total += is->count; + if(total >= diaps_num) + break; + } + + assert(total <= diaps_num); + + if(total == diaps_num) + { + USDR_LOG("5318", USDR_LOG_DEBUG, "SOLUTION FOUND!->"); + loglen = 0; + for(unsigned j = 0; j < solution->count; ++j) + { + intersection_t* is = solution->is + j; + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "diaps {"); + for(unsigned k = 0; k < is->count; ++k) + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%d,", is->diap_idxs[k]); + loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen,"} have %d intersections in range[%lu, %lu]", + is->count, is->range.min, is->range.max); + + USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); + } + return 0; + } + + USDR_LOG("5318", USDR_LOG_DEBUG, "NO SOLUTION FOUND!"); + return -EINVAL; +} + +/***************************************************************************************************************************/ + +static int lmk05318_check_solution(lmk05318_out_config_t* out, uint64_t fvco2, unsigned pdiv, uint64_t odiv) +{ + const range_t wanted = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; + const uint32_t freq = fvco2 / pdiv / odiv; + + if(freq < wanted.min) + return -1; + else if(freq > wanted.max) + return 1; + else + return 0; +} + +int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs) +{ + int res = 0; + + if(!_outs || !n_outs || n_outs > MAX_OUT_PORTS) + return -EINVAL; + + // internally we have only _6_ out divs and freqs (0==1 and 2==3), except output type, but it does not matter here + lmk05318_out_config_t outs[MAX_OUT_PORTS - 2]; + memset(outs, 0, sizeof(outs)); + for(unsigned i = 0; i < n_outs; ++i) { - lmk05318_out_config_t* out = outs + i; - out->solved = false; + lmk05318_out_config_t* out = _outs + i; + + if(out->port > MAX_OUT_PORTS - 1) + return -EINVAL; + + unsigned port; + if(out->port < 2) + port = 0; + else if(out->port < 4) + port = 1; + else + port = out->port - 2; + + lmk05318_out_config_t* norm_out = outs + port; + + // check dup ports and 0-1 2-3 equality + if(norm_out->wanted.freq && + (norm_out->wanted.freq != out->wanted.freq || + norm_out->wanted.freq_delta_plus != out->wanted.freq_delta_plus || + norm_out->wanted.freq_delta_minus != out->wanted.freq_delta_minus || + norm_out->wanted.revert_phase != out->wanted.revert_phase + )) + return -EINVAL; + + *norm_out = *out; + norm_out->solved = false; + } + + //now outs[] contains effective ports ordered (0..5) config. + //some elems may be not initialized (wanted.freq == 0) and should not be processed. + for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + outs[i].solved = outs[i].wanted.freq == 0; + //first we try routing ports to APLL1 + for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + { + lmk05318_out_config_t* out = outs + i; const range_t out_freq = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; const range_t out_pre_div_freq = {out_freq.min, out_freq.max * max_odiv(out->port)}; @@ -404,10 +634,44 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* outs, unsigned n return -EINVAL; } + /* + Now we have up to 6 equations with 6 + 1 + 1 = 8 vars (6 * OD + PD + Fvco2) + The base equation: Fout_i = Fvco2 / PD1_2 / ODi + + We'll have 2 large iterations - one for PD1 and second for PD2 + So 1) we find out all the possible solutions for PD1(/2../7) and Fvco2(VCO_APLL2_MIN..VCO_APLL2_MAX) + if we have the whole solution -> return OK + if we have NO new solutions -> abort, because PD1 and PD2 have equal params, and it's quite useless to continue + if we have a partial solution -> commit Fvco2 and go to PD2 + 2) we find out all the possible solutions for PD2(/2../7). Fvco2 is fixed. + if we solved all the outs -> return ok + abort otherwise + */ + + + uint64_t fvco2_max = VCO_APLL2_MAX; + uint64_t fvco2_min = VCO_APLL2_MIN; + uint64_t fvco2 = VCO_APLL2_MAX; + unsigned pdiv = APLL2_PDIV_MAX; + + for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + { + if(outs[i].solved) + continue; + + int res = lmk05318_check_solution(&outs[i], fvco2, pdiv, max_odiv(i)); + if(res > 0) + { + fvco2 = (fvco2_max - fvco2_min) / 2; + } + } + //second - try routing to APLL2 //check if all the requested freqs can be potentially solved - range_t f_vco2[MAX_OUT_PORTS] = {{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; + //and narrow up Fvco2 effective range + uint64_t f_vco2_min = VCO_APLL2_MIN; + uint64_t f_vco2_max = VCO_APLL2_MAX; for(unsigned i = 0; i < n_outs; ++i) { @@ -418,34 +682,40 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* outs, unsigned n const range_t out_freq = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; const range_t out_pre_div_freq = {out_freq.min * APLL2_PDIV_MIN, out_freq.max * max_odiv(out->port) * APLL2_PDIV_MAX}; - uint64_t eff_min = MAX(out_pre_div_freq.min, VCO_APLL2_MIN); - uint64_t eff_max = MIN(out_pre_div_freq.max, VCO_APLL2_MAX); + f_vco2_min = MAX(out_pre_div_freq.min, f_vco2_min); + f_vco2_max = MIN(out_pre_div_freq.max, f_vco2_max); - if(eff_min > eff_max) + if(f_vco2_min > f_vco2_max) return -EINVAL; - - //narrow fvco2 band - f_vco2[out->port].min = eff_min; - f_vco2[out->port].max = eff_max; } - //now we find the complete fvco2 intersection - uint64_t f_vco2_min = VCO_APLL2_MIN; - uint64_t f_vco2_max = VCO_APLL2_MAX; + uint64_t fvco = f_vco2_min; + unsigned pdiv1 = APLL2_PDIV_MIN; - for(unsigned i = 0; i < n_outs; ++i) + for(; fvco <= f_vco2_max; ++fvco) { - if(!f_vco2[i].min && !f_vco2[i].min) - continue; + int res[MAX_OUT_PORTS - 2]; - f_vco2_min = MAX(f_vco2_min, f_vco2[i].min); - f_vco2_max = MIN(f_vco2_max, f_vco2[i].max); - } + for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + { + lmk05318_out_config_t* out = outs + i; + if(out->solved) + continue; - if(f_vco2_min > f_vco2_max) - return -EINVAL; + unsigned odiv = 1; + for(; odiv <= max_odiv(i); ++odiv) + { + res[i] = lmk05318_check_solution(&outs[i], fvco, pdiv1, odiv); + if(res[i] <= 0) //fvco2 matches or too low + break; + } + + bool need_increase_pd1 = res[i] > 0; //fvco2 too high + } - //next we go to bisect, first with PD1, second - with PD2 + + + } return res; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 04068029..1ee4e144 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -5,7 +5,6 @@ #define LMK05318_H #include -#include "def_lmk05318.h" #define MAX_OUT_PORTS 8 @@ -23,7 +22,7 @@ struct lmk05318_state { struct { uint32_t fref; - enum xo_type_options type; + int type; bool doubler_enabled; bool fdet_bypass; } xo; @@ -57,7 +56,7 @@ struct lmk05318_out_config { uint32_t freq; uint64_t out_div; - enum lmk05318_out_pll_sel_t mux; + int mux; } result; }; typedef struct lmk05318_out_config lmk05318_out_config_t; @@ -73,10 +72,10 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); -int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, enum xo_type_options xo_type, +int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, bool xo_doubler_enabled, bool xo_fdet_bypass); int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, - uint32_t xo_fref, enum xo_type_options xo_type, + uint32_t xo_fref, int xo_type, bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode, unsigned *last_div); #endif diff --git a/src/lib/hw/lmk05318/lmk05318_solver.h b/src/lib/hw/lmk05318/lmk05318_solver.h new file mode 100644 index 00000000..c8d64b21 --- /dev/null +++ b/src/lib/hw/lmk05318/lmk05318_solver.h @@ -0,0 +1,32 @@ +#ifndef LMK05318_SOLVER_H +#define LMK05318_SOLVER_H + +#include + +#define DIAP_MAX 6 + +#define MAX(a, b) (a) > (b) ? (a) : (b) +#define MIN(a, b) (a) < (b) ? (a) : (b) + +struct range +{ + uint64_t min, max; +}; +typedef struct range range_t; + +struct intersection +{ + unsigned diap_idxs[DIAP_MAX]; + unsigned count; + range_t range; +}; +typedef struct intersection intersection_t; + +struct range_solution +{ + unsigned count; + intersection_t is[DIAP_MAX * 2]; +}; +typedef struct range_solution range_solution_t; + +#endif // LMK05318_SOLVER_H From 2570cc743f1c2342d00f5b1a013abfd789837dca Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 16 Dec 2024 20:05:57 +0300 Subject: [PATCH 006/397] mk05318 solver is working.. sometimes... beta-version --- src/lib/hw/lmk05318/lmk05318.c | 708 ++++++++++++++++---------- src/lib/hw/lmk05318/lmk05318.h | 19 +- src/lib/hw/lmk05318/lmk05318_solver.h | 15 - src/utests/CMakeLists.txt | 5 + src/utests/lmk05318_test.c | 83 +++ 5 files changed, 530 insertions(+), 300 deletions(-) create mode 100644 src/utests/lmk05318_test.c diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index a63ded3b..94f60d44 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -11,9 +11,9 @@ #include "def_lmk05318.h" #include "lmk05318.h" #include "lmk05318_rom.h" -#include "lmk05318_solver.h" #include +#include "../../xdsp/attribute_switch.h" enum { VCO_APLL1 = 2500000000ull, @@ -217,30 +217,20 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, return 0; } -int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, +int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode, - unsigned *last_div) + bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode) { - if (freq < 1e6) { - // Disable - uint32_t regs[] = { - MAKE_LMK05318_PLL1_CTRL0(1), - }; - return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs));; - } - int res = lmk05318_set_xo_fref(d, xo_fref, xo_type, xo_doubler_enabled, xo_fdet_bypass); if(res) return res; unsigned fref = (d->xo.fref / APLL1_DIVIDER_MAX) * (d->xo.doubler_enabled ? 2 : 1); - unsigned div = VCO_APLL1_MAX / freq; - uint64_t fvco = (uint64_t)freq * div; + uint64_t fvco = VCO_APLL1; unsigned n = fvco / fref; uint64_t num = (fvco - n * (uint64_t)fref) * (1ull << 40) / fref; - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FREQ=%u FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 " DIV=%d\n", freq, fvco, n, num, div); + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 "\n", fvco, n, num); uint32_t regs[] = { MAKE_LMK05318_PLL1_CTRL0(1), @@ -260,7 +250,6 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, if (res) return res; - *last_div = div; return 0; } @@ -310,263 +299,193 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -//idx is NOT a port but OD index (0..5) -static unsigned max_odiv(unsigned idx) + + + + +static int lmk05318_comp_port(const void * elem1, const void * elem2) { - assert(idx < 6); + const lmk05318_out_config_t* f = (lmk05318_out_config_t*)elem1; + const lmk05318_out_config_t* s = (lmk05318_out_config_t*)elem2; - switch(idx) + if(f->port < s->port) return -1; + if(f->port > s->port) return 1; + return 0; +} + + +static uint64_t lmk05318_max_odiv(unsigned port) +{ + assert(port < MAX_OUT_PORTS); + + switch(port) { case 0: case 1: case 2: case 3: - case 4: return 256; - case 5: return 4 * 256; + case 4: + case 5: + case 6: return 256ull; + case 7: return 256ull * 256 * 256 * 256; } return 1; } -/***************************************************************************************************************************/ - -static int comp_u64(const void * elem1, const void * elem2) +static range_t lmk05318_get_freq_range(const lmk05318_out_config_t* cfg) { - const uint64_t* f = (uint64_t*)elem1; - const uint64_t* s = (uint64_t*)elem2; + range_t r; - if(*f < *s) return -1; - if(*f > *s) return 1; - return 0; -} + if(cfg->wanted.freq >= cfg->wanted.freq_delta_minus) + r.min = cfg->wanted.freq - cfg->wanted.freq_delta_minus; + else + r.min = 1; -static int comp_intersection_desc(const void * elem1, const void * elem2) -{ - const intersection_t* f = (intersection_t*)elem1; - const intersection_t* s = (intersection_t*)elem2; + r.max = cfg->wanted.freq + cfg->wanted.freq_delta_plus; - if(f->count < s->count) return 1; - if(f->count > s->count) return -1; - return 0; + return r; } -int lmk05318_range_solver(const range_t* diaps, unsigned diaps_num, range_solution_t* solution) -{ - assert(diaps_num <= DIAP_MAX); - char logtmp[2048]; - unsigned loglen; +/* + * The main formula for the valid div: + * (int)[f_in/(f_out + eps) != (int)[f_in/(f_out - eps)] + * it means that we have a natural int divider value somewhere between [f-eps; f+eps] - the most obvious it's (int)(f_out + eps) + 1 + * + * This function returns: + * odiv value - if it can be solved + * 0 - otherwise + */ - USDR_LOG("5318", USDR_LOG_DEBUG, "input ranges:->"); - for(unsigned i = 0; i < diaps_num; ++i) - { - USDR_LOG("5318", USDR_LOG_DEBUG, "%d -> %lu : %lu", i, diaps[i].min, diaps[i].max); - } +enum { + freq_too_low = -1, + freq_too_high = 1, + freq_ok = 0, + freq_invalid = 42, +}; - // get wrapper points (ends of our diaps) - uint64_t wrapper_points[diaps_num * 2]; - for(unsigned i = 0; i < diaps_num * 2; i += 2) +VWLT_ATTRIBUTE(optimize("-Ofast")) +static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, uint64_t ifreq, uint64_t* div) +{ + if(cfg->freq_min == cfg->freq_max) { - wrapper_points[i + 0] = diaps[i >> 1].min; - wrapper_points[i + 1] = diaps[i >> 1].max; - } + const uint32_t f = cfg->freq_min; - qsort(wrapper_points, diaps_num * 2, sizeof(uint64_t), comp_u64); + *div = ifreq / f; + if(*div > cfg->max_odiv) + return freq_too_high; - USDR_LOG("5318", USDR_LOG_DEBUG, "wrap points:-> "); - for(unsigned i = 0; i < diaps_num * 2; ++i) - { - USDR_LOG("5318", USDR_LOG_DEBUG, "%lu, ", wrapper_points[i]); - } + if(*div < 1) + return freq_too_low; - //and remove dups - uint64_t uniq_wrapper_points[diaps_num * 2]; - unsigned uniq_wrapper_points_num = 0; - for(unsigned i = 0; i < diaps_num * 2; ++i) - { - if(i == 0 || wrapper_points[i] != wrapper_points[i-1]) - { - uniq_wrapper_points[uniq_wrapper_points_num++] = wrapper_points[i]; - } - } + if(*div * f == ifreq) + return freq_ok; - loglen = snprintf(logtmp, sizeof(logtmp), "uniq wrap points:-> "); - for(unsigned i = 0; i < uniq_wrapper_points_num; ++i) - { - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%lu, ", uniq_wrapper_points[i]); + return freq_invalid; } - USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); - //build intersections within the intervals between wrapper points - const unsigned intervals_count = uniq_wrapper_points_num - 1; - intersection_t intersections[intervals_count]; - for(unsigned i = 0; i < intervals_count; ++i) - { - intersection_t* is = intersections + i; - const uint64_t min = uniq_wrapper_points[i + 0]; - const uint64_t max = uniq_wrapper_points[i + 1]; - - //initialize the insersection struct - is->count = 0; - memset(is->diap_idxs, 0, sizeof(is->diap_idxs)); - is->range.min = min; - is->range.max = max; + const uint64_t div_min = ifreq / cfg->freq_max; + const uint64_t div_max = ifreq / cfg->freq_min; - //here is our moving point - in the middle of the diapason - const uint64_t point = (max + min) >> 1; + if(div_min > cfg->max_odiv) + return freq_too_high; + if(div_max < 1) + return freq_too_low; - //check how many diaps it intersects - for(unsigned j = 0; j < diaps_num; ++j) - { - if(point >= diaps[j].min && point <= diaps[j].max) - { - is->diap_idxs[is->count++] = j; - } - } - } - - //sort it desc to get the most massive intersection on the top - qsort(intersections, intervals_count, sizeof(intersection_t), comp_intersection_desc); - - USDR_LOG("5318", USDR_LOG_DEBUG, "intersects:->"); - loglen = 0; - for(unsigned i = 0; i < intervals_count; ++i) + if(div_min != div_max) { - intersection_t* is = intersections + i; - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "diaps {"); - for(unsigned j = 0; j < is->count; ++j) - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%d,", is->diap_idxs[j]); - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen,"} have %d intersections in range[%lu, %lu]", is->count, is->range.min, is->range.max); - USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); + *div = div_min + 1; + return freq_ok; } - //reduce to find a complete solution - for(unsigned z = 0; z < intervals_count; ++z) - { - intersection_t* main_is = intersections + z; + return freq_invalid; +} - if(!main_is->count) - break; +struct pd_array +{ + range_t pd_range; + unsigned port_count; + unsigned port_ids[MAX_REAL_PORTS]; +}; +typedef struct pd_array pd_array_t; - //after sort assume the first intersect is the best, and exclude these diaps from the others - unsigned excludes[diaps_num]; - unsigned excludes_count = main_is->count; - memcpy(excludes, intersections + z, excludes_count * sizeof(unsigned)); +VWLT_ATTRIBUTE(optimize("-Ofast")) +static inline int bisect_finder(lmk05318_out_config_t* outs, + pd_array_t* pd_arr, unsigned pd_arr_num, unsigned pd1, unsigned* pd2, + uint64_t f_in, + bool* all_freqs_invalid) +{ + int direction_flag = 0; + bool invalid_freq = false; - for(unsigned i = z + 1; i < intervals_count; ++i) - { - intersection_t* is = intersections + i; - unsigned tmp_arr[diaps_num]; - unsigned tmp_n = 0; + pd_array_t* p1 = pd_arr + 0; + pd_array_t* p2 = pd_arr_num == 2 ? pd_arr + 1 : NULL; - for(unsigned j = 0; j < is->count; ++j) - { - bool is_in = false; - for(unsigned k = 0; k < excludes_count; ++k) - { - if(excludes[k] == is->diap_idxs[j]) - { - is_in = true; - break; - } - } - if(!is_in) - tmp_arr[tmp_n++] = is->diap_idxs[j]; - } + for(unsigned i = 0; i < p1->port_count; ++i) + { + lmk05318_out_config_t* out = outs + p1->port_ids[i]; - //hint - if we going to collapse this intersection part, and we see it is == to the current - if(!tmp_n && main_is->count == is->count) - { - //and the diap ranges of them are adjacent - if(main_is->range.min == is->range.max || main_is->range.max == is->range.min) - { - //merge them to one diapason - main_is->range.min = MIN(main_is->range.min, is->range.min); - main_is->range.max = MAX(main_is->range.max, is->range.max); - } - } + uint64_t odiv = 0; + int res = lmk05318_get_output_divider(out, f_in, &odiv); - is->count = tmp_n; - memcpy(is->diap_idxs, tmp_arr, tmp_n * sizeof(unsigned)); + if(res == freq_invalid) + { + invalid_freq = true; } + else + direction_flag += res; - //sort it again to proceed for the next loop - qsort(intersections + z, intervals_count - z, sizeof(intersection_t), comp_intersection_desc); - - USDR_LOG("5318", USDR_LOG_DEBUG, "intersects(%d):->", z); - loglen = 0; - for(unsigned i = 0; i < intervals_count; ++i) + if(!res) { - intersection_t* is = intersections + i; - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "diaps {"); - for(unsigned j = 0; j < is->count; ++j) - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%d,", is->diap_idxs[j]); - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen,"} have %d intersections in range[%lu, %lu]", - is->count, is->range.min, is->range.max); - - USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); + out->result.out_div = odiv; + out->result.freq = (double)f_in / odiv; + out->result.mux = OUT_PLL_SEL_APLL2_P1; + +// USDR_LOG("5318", USDR_LOG_WARNING, "found PD1 port:%d solution freq:%.2f OD:%lu PD1:%d VCO2:%lu", +// out->port, out->result.freq, odiv, pd1, f_in * pd1); } } - //we need only 2 effective diapasons due to only 2 PDs - PD1 and PD2 - static const unsigned MAX_RANGES_IN_SOLUTION = 2; - - solution->count = 0; - unsigned total = 0; - - for(unsigned i = 0; i < MAX_RANGES_IN_SOLUTION; ++i) + //found solution for PD1 -> check PD2 + if(direction_flag == 0 && !invalid_freq && p2) { - intersection_t* is = intersections + i; - solution->is[i] = *is; - ++solution->count; + const uint32_t fvco2 = f_in * pd1; + for(unsigned _pd2 = p2->pd_range.min; _pd2 <= p2->pd_range.max; ++_pd2) + { + for(unsigned j = 0; j < p2->port_count; ++j) + { + lmk05318_out_config_t* out = outs + p2->port_ids[j]; - total += is->count; - if(total >= diaps_num) - break; - } + uint64_t odiv = 0; + uint32_t f = fvco2 / _pd2; + int res = lmk05318_get_output_divider(out, f, &odiv); - assert(total <= diaps_num); +// USDR_LOG("5318", USDR_LOG_WARNING, "\tsearch PD2 port:%d solution freq:%d PD2:%d VCO2:%lu... RES=%d", +// out->port, out->wanted.freq, _pd2, f_in * pd1, res); - if(total == diaps_num) - { - USDR_LOG("5318", USDR_LOG_DEBUG, "SOLUTION FOUND!->"); - loglen = 0; - for(unsigned j = 0; j < solution->count; ++j) - { - intersection_t* is = solution->is + j; - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "diaps {"); - for(unsigned k = 0; k < is->count; ++k) - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen, "%d,", is->diap_idxs[k]); - loglen += snprintf(logtmp + loglen, sizeof(logtmp) - loglen,"} have %d intersections in range[%lu, %lu]", - is->count, is->range.min, is->range.max); - - USDR_LOG("5318", USDR_LOG_DEBUG, "%s", logtmp); + if(res == freq_invalid) + { + invalid_freq = true; + } + + if(!res) + { + *pd2 = _pd2; + out->result.out_div = odiv; + out->result.freq = (double)f / odiv; + out->result.mux = OUT_PLL_SEL_APLL2_P2; + } + } } - return 0; } - USDR_LOG("5318", USDR_LOG_DEBUG, "NO SOLUTION FOUND!"); - return -EINVAL; -} - -/***************************************************************************************************************************/ - -static int lmk05318_check_solution(lmk05318_out_config_t* out, uint64_t fvco2, unsigned pdiv, uint64_t odiv) -{ - const range_t wanted = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; - const uint32_t freq = fvco2 / pdiv / odiv; - - if(freq < wanted.min) - return -1; - else if(freq > wanted.max) - return 1; - else - return 0; + *all_freqs_invalid = (direction_flag == 0 && invalid_freq); + return direction_flag; } +VWLT_ATTRIBUTE(optimize("-Ofast")) int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs) { - int res = 0; - if(!_outs || !n_outs || n_outs > MAX_OUT_PORTS) return -EINVAL; @@ -600,33 +519,48 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned )) return -EINVAL; + range_t r = lmk05318_get_freq_range(out); + out->freq_min = r.min; + out->freq_max = r.max; + out->max_odiv = lmk05318_max_odiv(out->port); + *norm_out = *out; norm_out->solved = false; } //now outs[] contains effective ports ordered (0..5) config. //some elems may be not initialized (wanted.freq == 0) and should not be processed. - for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) + { outs[i].solved = outs[i].wanted.freq == 0; + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d freq:%d (-%d, +%d) *%s*", + outs[i].port, outs[i].wanted.freq, outs[i].wanted.freq_delta_minus, outs[i].wanted.freq_delta_plus, + outs[i].solved ? "not used" : "active"); + } //first we try routing ports to APLL1 - for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + //it's easy + for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) { lmk05318_out_config_t* out = outs + i; - const range_t out_freq = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; - const range_t out_pre_div_freq = {out_freq.min, out_freq.max * max_odiv(out->port)}; + if(out->solved) + continue; - if(VCO_APLL1 >= out_pre_div_freq.min && VCO_APLL1 <= out_pre_div_freq.max) + uint64_t odiv = 0; + int res = lmk05318_get_output_divider(out, VCO_APLL1, &odiv); + if(!res) { - const uint64_t div = (uint64_t)VCO_APLL1 / out->wanted.freq; - const uint32_t freq = VCO_APLL1 / div; - if(freq >= out_freq.min && freq <= out_freq.max) - { - out->solved = true; - out->result.out_div = div; - out->result.freq = freq; - out->result.mux = out->wanted.revert_phase ? OUT_PLL_SEL_APLL1_P1_INV : OUT_PLL_SEL_APLL1_P1; - } + out->solved = true; + out->result.out_div = odiv; + out->result.freq = (double)VCO_APLL1 / odiv; + out->result.mux = out->wanted.revert_phase ? OUT_PLL_SEL_APLL1_P1_INV : OUT_PLL_SEL_APLL1_P1; + + USDR_LOG("5318", USDR_LOG_ERROR, "port:%d solved via APLL1 [OD:%" PRIu64 " freq:%.2f mux:%d]", + out->port, out->result.out_div, out->result.freq, out->result.mux); + } + else + { + USDR_LOG("5318", USDR_LOG_WARNING, "port:%d cannot solve it via APLL1, will try APLL2", out->port); } //we cannot revert phase for ports NOT linked to APLL1 @@ -634,90 +568,302 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned return -EINVAL; } - /* - Now we have up to 6 equations with 6 + 1 + 1 = 8 vars (6 * OD + PD + Fvco2) - The base equation: Fout_i = Fvco2 / PD1_2 / ODi - We'll have 2 large iterations - one for PD1 and second for PD2 - So 1) we find out all the possible solutions for PD1(/2../7) and Fvco2(VCO_APLL2_MIN..VCO_APLL2_MAX) - if we have the whole solution -> return OK - if we have NO new solutions -> abort, because PD1 and PD2 have equal params, and it's quite useless to continue - if we have a partial solution -> commit Fvco2 and go to PD2 - 2) we find out all the possible solutions for PD2(/2../7). Fvco2 is fixed. - if we solved all the outs -> return ok - abort otherwise - */ + //second - try routing to APLL2 + //it's HELL + unsigned cnt_to_solve = 0; + USDR_LOG("5318", USDR_LOG_DEBUG,"Need to solve via APLL2:"); + for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) + { + if(outs[i].solved) + continue; + + ++cnt_to_solve; + + USDR_LOG("5318", USDR_LOG_DEBUG, "\tport:%d freq:%d (-%d, +%d)", + outs[i].port, outs[i].wanted.freq, outs[i].wanted.freq_delta_minus, outs[i].wanted.freq_delta_plus); + } + if(!cnt_to_solve) + return 0; - uint64_t fvco2_max = VCO_APLL2_MAX; - uint64_t fvco2_min = VCO_APLL2_MIN; - uint64_t fvco2 = VCO_APLL2_MAX; - unsigned pdiv = APLL2_PDIV_MAX; + static const uint64_t fvco2_pd_min = VCO_APLL2_MIN / APLL2_PDIV_MAX; + static const uint64_t fvco2_pd_max = VCO_APLL2_MAX / APLL2_PDIV_MIN; - for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + //try to determine valid PD ranges for our frequencies + for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) { - if(outs[i].solved) + lmk05318_out_config_t* out = outs + i; + if(out->solved) continue; - int res = lmk05318_check_solution(&outs[i], fvco2, pdiv, max_odiv(i)); - if(res > 0) - { - fvco2 = (fvco2_max - fvco2_min) / 2; - } + const range_t r = lmk05318_get_freq_range(out); + const range_t ifreq = {MAX(r.min, fvco2_pd_min) , MIN(r.max * lmk05318_max_odiv(out->port), fvco2_pd_max)}; + + if(ifreq.min > ifreq.max) + return -EINVAL; + + const int pd_min = VCO_APLL2_MAX / ifreq.max; + const int pd_max = VCO_APLL2_MAX / ifreq.min; + + out->pd_min = pd_min; + out->pd_max = pd_max; + + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d pre-OD freq range:[%" PRIu64", %" PRIu64"], PD:[%d, %d]", + out->port, ifreq.min, ifreq.max, pd_min, pd_max); } - //second - try routing to APLL2 + int pd1_index = -1; + bool found_sect = true; + range_t section; - //check if all the requested freqs can be potentially solved - //and narrow up Fvco2 effective range - uint64_t f_vco2_min = VCO_APLL2_MIN; - uint64_t f_vco2_max = VCO_APLL2_MAX; + unsigned pd2_ids[MAX_REAL_PORTS]; + unsigned num_pd2 = 0; - for(unsigned i = 0; i < n_outs; ++i) + //then we make an intersection of these PD ranges + for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) { lmk05318_out_config_t* out = outs + i; if(out->solved) continue; - const range_t out_freq = {out->wanted.freq - out->wanted.freq_delta_minus, out->wanted.freq + out->wanted.freq_delta_plus}; - const range_t out_pre_div_freq = {out_freq.min * APLL2_PDIV_MIN, out_freq.max * max_odiv(out->port) * APLL2_PDIV_MAX}; + section.min = 0; + section.max = -1; - f_vco2_min = MAX(out_pre_div_freq.min, f_vco2_min); - f_vco2_max = MIN(out_pre_div_freq.max, f_vco2_max); + USDR_LOG("5318", USDR_LOG_DEBUG,"Assume PD1=%d [%d, %d]", out->port, out->pd_min, out->pd_max); - if(f_vco2_min > f_vco2_max) - return -EINVAL; + unsigned j; + found_sect = true; + num_pd2 = 0; + + for(j = 0; j < MAX_REAL_PORTS; ++j) + { + if(i == j) + continue; + + lmk05318_out_config_t* out2 = outs + j; + if(out2->solved) + continue; + + section.min = MAX(section.min, out2->pd_min); + section.max = MIN(section.max, out2->pd_max); + + USDR_LOG("5318", USDR_LOG_DEBUG,"\t port %d [%d, %d] -> section:[%lu, %lu]", + out2->port, out2->pd_min, out2->pd_max, section.min, section.max); + + if(section.min > section.max) + { + found_sect = false; + break; + } + + pd2_ids[num_pd2++] = j; + } + + if(found_sect) + { + pd1_index = i; + break; + } + } + + //means we need more than 2 post-dividers for our setup + if(!found_sect) + { + USDR_LOG("5318", USDR_LOG_ERROR, "No possible solutions for 2 PDs"); + return -EINVAL; + } + + pd_array_t pd_group[2]; + unsigned pd_group_count = 0; + + //and fill the PD groups. the count of PD groups must be 1 or 2. + if(num_pd2) + { + range_t r = {MAX(outs[pd1_index].pd_min, section.min), MIN(outs[pd1_index].pd_max, section.max)}; + if(r.max >= r.min) + { + pd_array_t* pd1 = &pd_group[pd_group_count++]; + pd1->pd_range = r; + pd1->port_count = 0; + pd1->port_ids[pd1->port_count++] = pd1_index; + + for(unsigned i = 0; i < num_pd2; ++i) + { + pd1->port_ids[pd1->port_count++] = pd2_ids[i]; + } + } + else + { + pd_array_t* pd1 = &pd_group[pd_group_count++]; + pd1->pd_range.min = outs[pd1_index].pd_min; + pd1->pd_range.max = outs[pd1_index].pd_max; + pd1->port_count = 0; + pd1->port_ids[pd1->port_count++] = pd1_index; + + pd_array_t* pd2 = &pd_group[pd_group_count++]; + pd2->pd_range = section; + pd2->port_count = 0; + for(unsigned i = 0; i < num_pd2; ++i) + { + pd2->port_ids[pd2->port_count++] = pd2_ids[i]; + } + } + } + else + { + pd_array_t* pd1 = &pd_group[pd_group_count++]; + pd1->pd_range.min = outs[pd1_index].pd_min; + pd1->pd_range.max = outs[pd1_index].pd_max; + pd1->port_count = 0; + pd1->port_ids[pd1->port_count++] = pd1_index; + } + + for(unsigned i = 0; i < pd_group_count; ++i) + { + pd_array_t* pd = pd_group + i; + USDR_LOG("5318", USDR_LOG_DEBUG, "PD%d:[%lu, %lu]", i + 1, pd->pd_range.min, pd->pd_range.max); + for(unsigned j = 0; j < pd->port_count; ++j) + USDR_LOG("5318", USDR_LOG_DEBUG, "\t port:%d", outs[pd->port_ids[j]].port); + } + + if(pd_group_count > 1) + { + USDR_LOG("5318", USDR_LOG_ERROR, "Solution via two PDs is not yet supported properly!"); + } + + + bool all_done = false; + uint64_t f_in; + unsigned pd1 = 0; + unsigned pd2 = 0; + + // Bisect search for PD1 + // Here is the Abyss + pd_array_t* pPD1 = &pd_group[0]; + + for(pd1 = pPD1->pd_range.min; !all_done && pd1 <= pPD1->pd_range.max; ++pd1) + { + uint64_t f_in_min = VCO_APLL2_MIN / pd1; + uint64_t f_in_max = VCO_APLL2_MAX / pd1; + + USDR_LOG("5318", USDR_LOG_DEBUG, "***** PD:%d f_in:[%" PRIu64 ", %" PRIu64 "] *****", pd1, f_in_min, f_in_max); + + while (f_in_min <= f_in_max) + { + f_in = f_in_min + ((f_in_max - f_in_min) >> 1); + USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT f_mid:%" PRIu64 " fvco2:%" PRIu64 "", f_in, f_in * pd1); + + int direction_flag = 0; + bool all_freqs_invalid = false; + + direction_flag = bisect_finder(outs, pd_group, pd_group_count, pd1, &pd2, f_in, &all_freqs_invalid); + + USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT direction_flag:%d, %s", direction_flag, + all_freqs_invalid ? "invalid point!" : (direction_flag == 0 ? "all found" : (direction_flag > 0 ? "go left(down)" : "go right(up)"))); + + uint64_t f = 0; + if(all_freqs_invalid) + { + USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT we're near, gonna do spiral search in [%" PRIu64 " <- %" PRIu64 " -> %" PRIu64 "]", + f_in_min, f_in, f_in_max); + + int cnt = 2; + while(1) + { + // +1 -1 +2 -2 +3 -3 etc + f = f_in + (cnt % 2 ? (-1) : (1)) * (cnt >> 1); + + if(f > f_in_max || f < f_in_min) + break; + + direction_flag = bisect_finder(outs, pd_group, pd_group_count, pd1, &pd2, f, &all_freqs_invalid); + + if(!all_freqs_invalid) + break; + + ++cnt; + } + } + + if(all_freqs_invalid) + break; // go to the next PD + + //all solved + if(direction_flag == 0) + { + f_in = f; + all_done = true; + break; + } + + //too high, go to the left (down) + if(direction_flag > 0) + { + f_in_max = f_in - 1; + } + + //too low, go to the right (up) + if(direction_flag < 0) + { + f_in_min = f_in + 1; + } + } } - uint64_t fvco = f_vco2_min; - unsigned pdiv1 = APLL2_PDIV_MIN; + uint64_t fvco2 = f_in * (--pd1); + - for(; fvco <= f_vco2_max; ++fvco) + if(all_done) { - int res[MAX_OUT_PORTS - 2]; + USDR_LOG("5318", USDR_LOG_WARNING, "=== SOLUTION via APLL2 FOUND @ VCO2:%" PRIu64 " and PD1:%d PD2:%d ===", + fvco2, pd1, pd2); - for(unsigned i = 0; i < MAX_OUT_PORTS - 2; ++i) + for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) { lmk05318_out_config_t* out = outs + i; if(out->solved) continue; - unsigned odiv = 1; - for(; odiv <= max_odiv(i); ++odiv) - { - res[i] = lmk05318_check_solution(&outs[i], fvco, pdiv1, odiv); - if(res[i] <= 0) //fvco2 matches or too low - break; - } + USDR_LOG("5318", USDR_LOG_WARNING, "port:%d solved via APLL2 [OD:%" PRIu64 " freq:%.2f mux:%d]", + out->port, out->result.out_div, out->result.freq, out->result.mux); - bool need_increase_pd1 = res[i] > 0; //fvco2 too high + out->solved = true; + --cnt_to_solve; } + } + else + { + return -EINVAL; + } + //and the FINAL solution + assert(cnt_to_solve == 0); + qsort(outs, MAX_REAL_PORTS, sizeof(lmk05318_out_config_t), lmk05318_comp_port); + qsort(_outs, n_outs, sizeof(lmk05318_out_config_t), lmk05318_comp_port); + USDR_LOG("5318", USDR_LOG_ERROR, "=== COMPLETE SOLUTION @ VCO2:%" PRIu64 " and PD1:%d PD2:%d ===", fvco2, pd1, pd2); + for(unsigned i = 0; i < n_outs; ++i) + { + lmk05318_out_config_t* out_dst = _outs + i; + lmk05318_out_config_t* out_src = NULL; + + if(out_dst->port < 2) + out_src = outs + 0; + else if(out_dst->port < 4) + out_src = outs + 1; + else + out_src = outs + (out_dst->port - 2); + + out_dst->solved = out_src->solved; + out_dst->result = out_src->result; + + USDR_LOG("5318", USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.2f mux:%d]", + out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux); } - return res; + return 0; } diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 1ee4e144..4d4a0fd0 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -5,8 +5,10 @@ #define LMK05318_H #include +#include "lmk05318_solver.h" #define MAX_OUT_PORTS 8 +#define MAX_REAL_PORTS (MAX_OUT_PORTS - 2) struct lmk05318_state { lldev_t dev; @@ -54,10 +56,16 @@ struct lmk05318_out_config struct { - uint32_t freq; + double freq; uint64_t out_div; int mux; } result; + + // + uint64_t max_odiv; + uint32_t freq_min, freq_max; + uint32_t pd_min, pd_max; + // }; typedef struct lmk05318_out_config lmk05318_out_config_t; @@ -74,8 +82,11 @@ int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, bool xo_doubler_enabled, bool xo_fdet_bypass); -int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t freq, + +int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode, - unsigned *last_div); + bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode); + +int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs); + #endif diff --git a/src/lib/hw/lmk05318/lmk05318_solver.h b/src/lib/hw/lmk05318/lmk05318_solver.h index c8d64b21..54862eb7 100644 --- a/src/lib/hw/lmk05318/lmk05318_solver.h +++ b/src/lib/hw/lmk05318/lmk05318_solver.h @@ -14,19 +14,4 @@ struct range }; typedef struct range range_t; -struct intersection -{ - unsigned diap_idxs[DIAP_MAX]; - unsigned count; - range_t range; -}; -typedef struct intersection intersection_t; - -struct range_solution -{ - unsigned count; - intersection_t is[DIAP_MAX * 2]; -}; -typedef struct range_solution range_solution_t; - #endif // LMK05318_SOLVER_H diff --git a/src/utests/CMakeLists.txt b/src/utests/CMakeLists.txt index 5468ec63..dbaa19ab 100644 --- a/src/utests/CMakeLists.txt +++ b/src/utests/CMakeLists.txt @@ -3,6 +3,8 @@ include_directories(../lib/port) include_directories(../lib/lowlevel) +include_directories(../lib/hw) + add_library(mock_lowlevel STATIC mock_lowlevel.c) @@ -18,3 +20,6 @@ include_directories(../lib/common) add_executable(usdr_testsuit ${TEST_SUIT_SRCS}) target_link_libraries(usdr_testsuit usdr mock_lowlevel usdr-dsp check subunit m rt pthread) + +add_executable(lmk05318_test lmk05318_test.c) +target_link_libraries(lmk05318_test usdr check subunit m rt pthread) diff --git a/src/utests/lmk05318_test.c b/src/utests/lmk05318_test.c new file mode 100644 index 00000000..72a187a0 --- /dev/null +++ b/src/utests/lmk05318_test.c @@ -0,0 +1,83 @@ +#include "stdio.h" +#include "lmk05318/lmk05318.h" +#include "usdr_logging.h" + +#define OUTS_LEN 8 +#define DELTA_PLUS 2 +#define DELTA_MINUS 2 + +int main() +{ + fprintf(stderr, "LMK05318 solver test\n"); + + usdrlog_setlevel(NULL, USDR_LOG_DEBUG); + usdrlog_enablecolorize(NULL); + + lmk05318_out_config_t cfg[OUTS_LEN]; + + cfg[0].port = 0; + cfg[0].wanted.freq = 100000000; + cfg[0].wanted.freq_delta_minus = DELTA_MINUS; + cfg[0].wanted.freq_delta_plus = DELTA_PLUS; + cfg[0].wanted.revert_phase = false; + cfg[0].wanted.type = OUT_OFF; + + cfg[1].port = 1; + cfg[1].wanted.freq = 100000000; + cfg[1].wanted.freq_delta_minus = DELTA_MINUS; + cfg[1].wanted.freq_delta_plus = DELTA_PLUS; + cfg[1].wanted.revert_phase = false; + cfg[1].wanted.type = OUT_OFF; + + cfg[2].port = 2; + cfg[2].wanted.freq = 122880000; + cfg[2].wanted.freq_delta_minus = DELTA_MINUS; + cfg[2].wanted.freq_delta_plus = DELTA_PLUS; + cfg[2].wanted.revert_phase = false; + cfg[2].wanted.type = OUT_OFF; + + cfg[3].port = 3; + cfg[3].wanted.freq = 122880000; + cfg[3].wanted.freq_delta_minus = DELTA_MINUS; + cfg[3].wanted.freq_delta_plus = DELTA_PLUS; + cfg[3].wanted.revert_phase = false; + cfg[3].wanted.type = OUT_OFF; + + cfg[4].port = 4; + cfg[4].wanted.freq = 312500000; + cfg[4].wanted.freq_delta_minus = DELTA_MINUS; + cfg[4].wanted.freq_delta_plus = DELTA_PLUS; + cfg[4].wanted.revert_phase = false; + cfg[4].wanted.type = OUT_OFF; + + cfg[5].port = 5; + cfg[5].wanted.freq = 3840000; + cfg[5].wanted.freq_delta_minus = DELTA_MINUS; + cfg[5].wanted.freq_delta_plus = DELTA_PLUS; + cfg[5].wanted.revert_phase = false; + cfg[5].wanted.type = OUT_OFF; + + cfg[6].port = 6; + cfg[6].wanted.freq = 491520000; + cfg[6].wanted.freq_delta_minus = DELTA_MINUS; + cfg[6].wanted.freq_delta_plus = DELTA_PLUS; + cfg[6].wanted.revert_phase = false; + cfg[6].wanted.type = OUT_OFF; + + cfg[7].port = 7; + cfg[7].wanted.freq = 1; + cfg[7].wanted.freq_delta_minus = DELTA_MINUS; + cfg[7].wanted.freq_delta_plus = DELTA_PLUS; + cfg[7].wanted.revert_phase = true; + cfg[7].wanted.type = OUT_OFF; + + int res = lmk05318_solver(NULL, cfg, 8); + if(res) + { + fprintf(stderr, "lmk05318_solver() error:%d\n", res); + return res; + } + + fprintf(stderr, "lmk05318_solver() OK\n"); + return 0; +} From b2ce1030eaa88d6fc940e867ce70b61e8a815cfb Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 21 Jan 2025 19:53:27 +0300 Subject: [PATCH 007/397] pd2 temporarily disabled + minor changes --- src/lib/hw/lmk05318/lmk05318.c | 58 ++++++++++------------------------ 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 94f60d44..3ccff264 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -346,16 +346,6 @@ static range_t lmk05318_get_freq_range(const lmk05318_out_config_t* cfg) return r; } -/* - * The main formula for the valid div: - * (int)[f_in/(f_out + eps) != (int)[f_in/(f_out - eps)] - * it means that we have a natural int divider value somewhere between [f-eps; f+eps] - the most obvious it's (int)(f_out + eps) + 1 - * - * This function returns: - * odiv value - if it can be solved - * 0 - otherwise - */ - enum { freq_too_low = -1, freq_too_high = 1, @@ -366,36 +356,24 @@ enum { VWLT_ATTRIBUTE(optimize("-Ofast")) static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, uint64_t ifreq, uint64_t* div) { - if(cfg->freq_min == cfg->freq_max) - { - const uint32_t f = cfg->freq_min; - - *div = ifreq / f; - - if(*div > cfg->max_odiv) - return freq_too_high; + *div = ifreq / cfg->wanted.freq; - if(*div < 1) - return freq_too_low; - - if(*div * f == ifreq) - return freq_ok; + if(*div > cfg->max_odiv) + return freq_too_high; - return freq_invalid; - } + if(*div < 1) + return freq_too_low; - const uint64_t div_min = ifreq / cfg->freq_max; - const uint64_t div_max = ifreq / cfg->freq_min; + double f = (double)ifreq / *div; - if(div_min > cfg->max_odiv) - return freq_too_high; - if(div_max < 1) - return freq_too_low; + if(f <= cfg->freq_max && f >= cfg->freq_min) + return freq_ok; - if(div_min != div_max) + if(*div <= cfg->max_odiv - 1) { - *div = div_min + 1; - return freq_ok; + f = (double)ifreq / ++(*div); + if(f <= cfg->freq_max && f >= cfg->freq_min) + return freq_ok; } return freq_invalid; @@ -570,7 +548,6 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned //second - try routing to APLL2 - //it's HELL unsigned cnt_to_solve = 0; USDR_LOG("5318", USDR_LOG_DEBUG,"Need to solve via APLL2:"); for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) @@ -729,17 +706,16 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(pd_group_count > 1) { - USDR_LOG("5318", USDR_LOG_ERROR, "Solution via two PDs is not yet supported properly!"); + USDR_LOG("5318", USDR_LOG_ERROR, "Solution via two PDs is not yet supported yet!"); + return -EINVAL; } - bool all_done = false; uint64_t f_in; unsigned pd1 = 0; unsigned pd2 = 0; // Bisect search for PD1 - // Here is the Abyss pd_array_t* pPD1 = &pd_group[0]; for(pd1 = pPD1->pd_range.min; !all_done && pd1 <= pPD1->pd_range.max; ++pd1) @@ -752,15 +728,15 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned while (f_in_min <= f_in_max) { f_in = f_in_min + ((f_in_max - f_in_min) >> 1); - USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT f_mid:%" PRIu64 " fvco2:%" PRIu64 "", f_in, f_in * pd1); + //USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT f_mid:%" PRIu64 " fvco2:%" PRIu64 "", f_in, f_in * pd1); int direction_flag = 0; bool all_freqs_invalid = false; direction_flag = bisect_finder(outs, pd_group, pd_group_count, pd1, &pd2, f_in, &all_freqs_invalid); - USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT direction_flag:%d, %s", direction_flag, - all_freqs_invalid ? "invalid point!" : (direction_flag == 0 ? "all found" : (direction_flag > 0 ? "go left(down)" : "go right(up)"))); + //USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT direction_flag:%d, %s", direction_flag, + // all_freqs_invalid ? "invalid point!" : (direction_flag == 0 ? "all found" : (direction_flag > 0 ? "go left(down)" : "go right(up)"))); uint64_t f = 0; if(all_freqs_invalid) From f9ed07a3bffeb2532d12f8a815e28c9e5ac1b78c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 26 Jan 2025 22:28:58 +0300 Subject: [PATCH 008/397] another lmk05318 version, elaborate but seems to be perfect. Need testing --- src/lib/hw/lmk05318/lmk05318.c | 770 +++++++++++++++++++++------------ src/lib/hw/lmk05318/lmk05318.h | 9 +- src/utests/lmk05318_test.c | 11 +- 3 files changed, 508 insertions(+), 282 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 3ccff264..225cd414 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -39,6 +39,7 @@ enum { APLL2_PDIV_MIN = 2, APLL2_PDIV_MAX = 7, + APLL2_PDIV_COUNT = 2, //PD1 & PD2 }; @@ -300,20 +301,6 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned } - - - -static int lmk05318_comp_port(const void * elem1, const void * elem2) -{ - const lmk05318_out_config_t* f = (lmk05318_out_config_t*)elem1; - const lmk05318_out_config_t* s = (lmk05318_out_config_t*)elem2; - - if(f->port < s->port) return -1; - if(f->port > s->port) return 1; - return 0; -} - - static uint64_t lmk05318_max_odiv(unsigned port) { assert(port < MAX_OUT_PORTS); @@ -379,96 +366,480 @@ static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, return freq_invalid; } -struct pd_array -{ - range_t pd_range; - unsigned port_count; - unsigned port_ids[MAX_REAL_PORTS]; -}; -typedef struct pd_array pd_array_t; +//#define LMK05318_SOLVER_DEBUG VWLT_ATTRIBUTE(optimize("-Ofast")) -static inline int bisect_finder(lmk05318_out_config_t* outs, - pd_array_t* pd_arr, unsigned pd_arr_num, unsigned pd1, unsigned* pd2, - uint64_t f_in, - bool* all_freqs_invalid) +static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned cnt_to_solve, uint64_t f_in, + uint64_t* res_fvco2, int* res_pd1, int* res_pd2) { - int direction_flag = 0; - bool invalid_freq = false; +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_DEBUG, "Solver iteration FVCO2:%" PRIu64 "", f_in); +#endif + + struct fvco2_range + { + int port_idx; + int pd; + uint64_t od; + range_t fvco2; + }; + typedef struct fvco2_range fvco2_range_t; - pd_array_t* p1 = pd_arr + 0; - pd_array_t* p2 = pd_arr_num == 2 ? pd_arr + 1 : NULL; + fvco2_range_t fvco2_ranges[(APLL2_PDIV_MAX - APLL2_PDIV_MIN + 1) * 2 * MAX_REAL_PORTS]; + int fvco2_ranges_count = 0; - for(unsigned i = 0; i < p1->port_count; ++i) + // find FVCO2 ranges for all PDs and all ports + for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) { - lmk05318_out_config_t* out = outs + p1->port_ids[i]; + lmk05318_out_config_t* out = outs + i; + if(out->solved) + continue; - uint64_t odiv = 0; - int res = lmk05318_get_output_divider(out, f_in, &odiv); + for(int pd = out->pd_min; pd <= out->pd_max; ++pd) + { + uint64_t f_pd = f_in / pd; + uint64_t divs[2]; + + lmk05318_get_output_divider(out, f_pd, &divs[0]); + divs[1] = (divs[0] < out->max_odiv) ? divs[0] + 1 : 0; + + for(int d = 0; d < 2; ++d) + { + const uint64_t div = divs[d]; + if(!div) + continue; - if(res == freq_invalid) + if(div <= out->max_odiv) + { + uint64_t fvco2_min = MAX(pd * div * out->freq_min, VCO_APLL2_MIN); + uint64_t fvco2_max = MIN(pd * div * out->freq_max, VCO_APLL2_MAX); + + if(fvco2_min <= fvco2_max) + { + fvco2_range_t* rr = &fvco2_ranges[fvco2_ranges_count++]; + rr->port_idx = i; + rr->pd = pd; + rr->od = div; + rr->fvco2.min = fvco2_min; + rr->fvco2.max = fvco2_max; + } + } + } + } + } + + if(!fvco2_ranges_count) + { +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_ERROR, "For FVCO2:%" PRIu64 " all possible bands are out of range", f_in); +#endif + return -EINVAL; + } + +#ifdef LMK05318_SOLVER_DEBUG + for(int i = 0; i < fvco2_ranges_count; ++i) + { + fvco2_range_t* rr = &fvco2_ranges[i]; + + USDR_LOG("5318", USDR_LOG_DEBUG, "\t[%d]\tPort#%d PD:%d OD:%" PRIu64 " FVCO2 range:[%" PRIu64 "; %" PRIu64 "]", + i, outs[rr->port_idx].port, rr->pd, rr->od, rr->fvco2.min, rr->fvco2.max); + } +#endif + + struct intersects + { + int prim_idx; + range_t intersection; + int sect_counter; + int sects[(APLL2_PDIV_MAX - APLL2_PDIV_MIN + 1) * 2 * MAX_REAL_PORTS]; + }; + typedef struct intersects intersects_t; + + int intersects_array_count = 0; + intersects_t intersects_array[fvco2_ranges_count]; + + // find FVCO2 ranges intersections + for(int i = 0; i < fvco2_ranges_count; ++i) + { + fvco2_range_t* rr_prim = &fvco2_ranges[i]; + range_t intersection = rr_prim->fvco2; + + int sect_counter = 0; + int sects[fvco2_ranges_count]; + + for(int j = i + 1; j < fvco2_ranges_count; ++j) { - invalid_freq = true; + fvco2_range_t* rr_sec = &fvco2_ranges[j]; + + //ignore equal port variants with different PDs + if(outs[rr_sec->port_idx].port == outs[rr_prim->port_idx].port) + continue; + + uint64_t nmin = MAX(intersection.min, rr_sec->fvco2.min); + uint64_t nmax = MIN(intersection.max, rr_sec->fvco2.max); + + //ignore not-intersected ranges + if(nmin > nmax) + continue; + + intersection.min = nmin; + intersection.max = nmax; + sects[sect_counter++] = j; } - else - direction_flag += res; - if(!res) + if(sect_counter) { - out->result.out_div = odiv; - out->result.freq = (double)f_in / odiv; - out->result.mux = OUT_PLL_SEL_APLL2_P1; + intersects_t* isect = &intersects_array[intersects_array_count++]; + isect->sect_counter = 0; + isect->prim_idx = i; + isect->intersection = intersection; -// USDR_LOG("5318", USDR_LOG_WARNING, "found PD1 port:%d solution freq:%.2f OD:%lu PD1:%d VCO2:%lu", -// out->port, out->result.freq, odiv, pd1, f_in * pd1); + for(int i = 0; i < sect_counter; ++i) + isect->sects[isect->sect_counter++] = sects[i]; } } - //found solution for PD1 -> check PD2 - if(direction_flag == 0 && !invalid_freq && p2) + if(!intersects_array_count) { - const uint32_t fvco2 = f_in * pd1; - for(unsigned _pd2 = p2->pd_range.min; _pd2 <= p2->pd_range.max; ++_pd2) +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_ERROR, "FVCO2 bands have no intersections"); +#endif + return -EINVAL; + } + +#ifdef LMK05318_SOLVER_DEBUG + for(int i = 0; i < intersects_array_count; ++i) + { + const intersects_t* isect = &intersects_array[i]; + fvco2_range_t* rr_prim = &fvco2_ranges[isect->prim_idx]; + + USDR_LOG("5318", USDR_LOG_DEBUG, "Found sects for [%d]\tPort#%d PD:%d OD:%" PRIu64 " FVCO2 range:[%" PRIu64 "; %" PRIu64 "]:", + isect->prim_idx, outs[rr_prim->port_idx].port, rr_prim->pd, rr_prim->od, isect->intersection.min, isect->intersection.max); + + for(int j = 0; j < isect->sect_counter; ++j) { - for(unsigned j = 0; j < p2->port_count; ++j) + const fvco2_range_t* rr = &fvco2_ranges[isect->sects[j]]; + USDR_LOG("5318", USDR_LOG_DEBUG, "\twith [%d] port#%d PD:%d OD:%" PRIu64 "", + isect->sects[j], outs[rr->port_idx].port, rr->pd, rr->od); + } + } +#endif + + struct solution_var_div + { + int pd; + uint64_t od; + }; + typedef struct solution_var_div solution_var_div_t; + + struct solution_var + { + int port_idx; + solution_var_div_t divs[(APLL2_PDIV_MAX - APLL2_PDIV_MIN + 1)]; + int divs_count; + }; + typedef struct solution_var solution_var_t; + + struct solution + { + range_t fvco2; + solution_var_t vars[MAX_REAL_PORTS]; + int vars_count; + bool is_valid; + }; + typedef struct solution solution_t; + + + solution_t solutions[intersects_array_count]; + int solutions_count = 0; + bool has_valid_solution = false; + + // reduce intersections to solutions, filtering out invalid ones + for(int i = 0; i < intersects_array_count; ++i) + { + intersects_t* isect = &intersects_array[i]; + solution_t* sol = &solutions[solutions_count++]; + fvco2_range_t* rr = &fvco2_ranges[isect->prim_idx]; + + sol->vars_count = 0; + sol->is_valid = false; + sol->fvco2 = isect->intersection; + + solution_var_t* var = &sol->vars[sol->vars_count++]; + var->port_idx = rr->port_idx; + var->divs_count = 0; + + solution_var_div_t* div = &var->divs[var->divs_count++]; + div->pd = rr->pd; + div->od = rr->od; + + for(int j = 0; j < isect->sect_counter; ++j) + { + rr = &fvco2_ranges[isect->sects[j]]; + var = NULL; + + for(int k = 0; k < sol->vars_count; ++k) + { + solution_var_t* vv = &sol->vars[k]; + if(vv->port_idx == rr->port_idx) + { + var = vv; + break; + } + } + + if(!var) + { + var = &sol->vars[sol->vars_count++]; + var->port_idx = rr->port_idx; + var->divs_count = 0; + } + + div = NULL; + for(int k = 0; k < var->divs_count; ++k) + { + solution_var_div_t* dd = &var->divs[k]; + if(dd->pd == rr->pd) + { + div = dd; + break; + } + } + + if(!div) + { + div = &var->divs[var->divs_count++]; + div->pd = rr->pd; + div->od = rr->od; + } + } + + sol->is_valid = (sol->vars_count == cnt_to_solve); + if(sol->is_valid) + has_valid_solution = true; + } + +#ifdef LMK05318_SOLVER_DEBUG + for(int i = 0; i < solutions_count; ++i) + { + const solution_t* sol = &solutions[i]; + if(!sol->is_valid) + continue; + + USDR_LOG("5318", USDR_LOG_DEBUG, "Solution [%d] in FVCO2 range [%" PRIu64 "; %" PRIu64 "]:", + i, sol->fvco2.min, sol->fvco2.max); + + for(int j = 0; j < sol->vars_count; ++j) + { + const solution_var_t* var = &sol->vars[j]; + char tmp[1024]; + int tmp_len = sprintf(tmp, "\t Port#%d PD:[", outs[var->port_idx].port); + + for(int k = 0; k < var->divs_count; ++k) { - lmk05318_out_config_t* out = outs + p2->port_ids[j]; + const solution_var_div_t* div = &var->divs[k]; + tmp_len += sprintf(tmp + tmp_len, "%d(OD:%" PRIu64 "),", div->pd, div->od); + } + + tmp_len += sprintf(tmp + tmp_len, "]"); + + USDR_LOG("5318", USDR_LOG_DEBUG, "%s", tmp); + } + } +#endif - uint64_t odiv = 0; - uint32_t f = fvco2 / _pd2; - int res = lmk05318_get_output_divider(out, f, &odiv); + if(!has_valid_solution) + { +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_ERROR, "We have NO solutions containing all ports required"); +#endif + return -EINVAL; + } -// USDR_LOG("5318", USDR_LOG_WARNING, "\tsearch PD2 port:%d solution freq:%d PD2:%d VCO2:%lu... RES=%d", -// out->port, out->wanted.freq, _pd2, f_in * pd1, res); + struct pd_bind + { + int pd; + int ports[MAX_REAL_PORTS]; + uint64_t odivs[MAX_REAL_PORTS]; + int ports_count; + }; + typedef struct pd_bind pd_bind_t; - if(res == freq_invalid) + //transform solitions to PD bindings -> PD1:[ports:ODs], PD2:[ports:ODs] + for(int i = 0; i < solutions_count; ++i) + { + solution_t* sol = &solutions[i]; + if(!sol->is_valid) + continue; + + pd_bind_t pd_binds[APLL2_PDIV_COUNT]; + memset(pd_binds, 0, sizeof(pd_binds)); + int pd_binds_count = 0; + int pd1 = 0, pd2 = 0; + + //first var is always one, assume it's PD1 + pd1 = sol->vars[0].divs[0].pd; + pd_binds[0].pd = pd1; + pd_binds[0].ports_count = 1; + pd_binds[0].ports[0] = sol->vars[0].port_idx; + pd_binds[0].odivs[0] = sol->vars[0].divs[0].od; + pd_binds_count = 1; + + int unmapped_ports[MAX_REAL_PORTS]; + int unmapped_ports_count = 0; + + //scan all other vars, try to find variants with PD==PD1 and add them to PD1 binding + //otherwise - add var to an unmapped_ports[] + for(int j = 1; j < sol->vars_count; ++j) + { + const solution_var_t* var = &sol->vars[j]; + bool port_mapped = false; + for(int k = 0; k < var->divs_count; ++k) + { + const solution_var_div_t* div = &var->divs[k]; + if(div->pd == pd1) { - invalid_freq = true; + pd_binds[0].ports[pd_binds[0].ports_count] = var->port_idx; + pd_binds[0].odivs[pd_binds[0].ports_count] = div->od; + pd_binds[0].ports_count++; + port_mapped = true; + break; } + } - if(!res) + if(!port_mapped) + { + unmapped_ports[unmapped_ports_count++] = j; + } + } + + if(unmapped_ports_count) + { + //step on first unmapped_ports[] var + const solution_var_t* var = &sol->vars[unmapped_ports[0]]; + + //iterate through its' divs and try to find equal PDs in the unmapped_ports[] below + for(int d = 0; d < var->divs_count; ++d) + { + const solution_var_div_t* div = &var->divs[d]; + + //assume it is PD2 + pd2 = div->pd; + pd_binds[1].pd = pd2; + pd_binds[1].ports[0] = var->port_idx; + pd_binds[1].odivs[0] = div->od; + pd_binds[1].ports_count = 1; + + //iterate unmapped ports below and try to find vars with PD==PD2 and add them to PD2 binding + for(int u = 1; u < unmapped_ports_count; ++u) + { + const solution_var_t* var2 = &sol->vars[unmapped_ports[u]]; + bool found = false; + for(int dd = 0; dd < var2->divs_count; ++dd) + { + const solution_var_div_t* div2 = &var2->divs[dd]; + if(div2->pd == pd2) + { + pd_binds[1].ports[pd_binds[1].ports_count] = var2->port_idx; + pd_binds[1].odivs[pd_binds[1].ports_count] = div2->od; + pd_binds[1].ports_count++; + + found = true; + break; + } + } + + //if this var does not contain the assumed PD2, no need to continue - break and try next PD2 + if(!found) + { + break; + } + } + + //check if we mapped all the ports needed + int binded_ports = pd_binds[0].ports_count + pd_binds[1].ports_count; + if(binded_ports == cnt_to_solve) + { + pd_binds_count = pd_binds[1].ports_count ? 2 : 1; + sol->is_valid = true; + } + else { - *pd2 = _pd2; - out->result.out_div = odiv; - out->result.freq = (double)f / odiv; - out->result.mux = OUT_PLL_SEL_APLL2_P2; + sol->is_valid = false; + continue; } } } + + if(!sol->is_valid) + continue; + + // use the first valid solution and return + + USDR_LOG("5318", USDR_LOG_DEBUG, "SOLUTION#%d valid:%d FVCO2[%" PRIu64 "; %" PRIu64 "]->", i, sol->is_valid, sol->fvco2.min, sol->fvco2.max); + + *res_fvco2 = (sol->fvco2.min + sol->fvco2.max) >> 1; + *res_pd1 = pd1; + *res_pd2 = pd2; + + for(int ii = 0; ii < pd_binds_count; ++ii) + { + const pd_bind_t* b = &pd_binds[ii]; + char tmp[1024]; + int tmp_len = sprintf(tmp, "\tPD%d=%d ports[", (ii+1), b->pd); + + for(int j = 0; j < b->ports_count; ++j) + { + tmp_len += sprintf(tmp + tmp_len, "%d(OD:%" PRIu64 ")),", outs[b->ports[j]].port, b->odivs[j]); + } + + tmp_len += sprintf(tmp + tmp_len, "]"); + USDR_LOG("5318", USDR_LOG_DEBUG, "%s", tmp); + + //set results + for(int j = 0; j < b->ports_count; ++j) + { + lmk05318_out_config_t* out = &outs[b->ports[j]]; + + out->result.out_div = b->odivs[j]; + out->result.freq = *res_fvco2 / b->pd / b->odivs[j]; + out->result.mux = (b->pd == pd1) ? OUT_PLL_SEL_APLL2_P1 : OUT_PLL_SEL_APLL2_P2; + out->solved = true; + } + } + + return 0; } - *all_freqs_invalid = (direction_flag == 0 && invalid_freq); - return direction_flag; +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_ERROR, "We have NO solutions using 2 PDs (need more pre-dividers)"); +#endif + return -EINVAL; +} + + +static int lmk05318_comp_port(const void * elem1, const void * elem2) +{ + const lmk05318_out_config_t* f = (lmk05318_out_config_t*)elem1; + const lmk05318_out_config_t* s = (lmk05318_out_config_t*)elem2; + + if(f->port < s->port) return -1; + if(f->port > s->port) return 1; + return 0; } + VWLT_ATTRIBUTE(optimize("-Ofast")) int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs) { if(!_outs || !n_outs || n_outs > MAX_OUT_PORTS) + { + USDR_LOG("5318", USDR_LOG_ERROR, "input data is incorrect"); return -EINVAL; + } // internally we have only _6_ out divs and freqs (0==1 and 2==3), except output type, but it does not matter here - lmk05318_out_config_t outs[MAX_OUT_PORTS - 2]; + lmk05318_out_config_t outs[MAX_REAL_PORTS]; memset(outs, 0, sizeof(outs)); for(unsigned i = 0; i < n_outs; ++i) @@ -476,7 +847,10 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned lmk05318_out_config_t* out = _outs + i; if(out->port > MAX_OUT_PORTS - 1) + { + USDR_LOG("5318", USDR_LOG_ERROR, "port value should be in [0; %d] diap", (MAX_OUT_PORTS - 1)); return -EINVAL; + } unsigned port; if(out->port < 2) @@ -495,7 +869,10 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned norm_out->wanted.freq_delta_minus != out->wanted.freq_delta_minus || norm_out->wanted.revert_phase != out->wanted.revert_phase )) + { + USDR_LOG("5318", USDR_LOG_ERROR, "dup ports values detected, or ports #0:1 & #2:3 differ"); return -EINVAL; + } range_t r = lmk05318_get_freq_range(out); out->freq_min = r.min; @@ -516,6 +893,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned outs[i].solved ? "not used" : "active"); } + //first we try routing ports to APLL1 //it's easy for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) @@ -533,7 +911,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned out->result.freq = (double)VCO_APLL1 / odiv; out->result.mux = out->wanted.revert_phase ? OUT_PLL_SEL_APLL1_P1_INV : OUT_PLL_SEL_APLL1_P1; - USDR_LOG("5318", USDR_LOG_ERROR, "port:%d solved via APLL1 [OD:%" PRIu64 " freq:%.2f mux:%d]", + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d solved via APLL1 [OD:%" PRIu64 " freq:%.2f mux:%d]", out->port, out->result.out_div, out->result.freq, out->result.mux); } else @@ -543,7 +921,10 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned //we cannot revert phase for ports NOT linked to APLL1 if(!out->solved && out->wanted.revert_phase) + { + USDR_LOG("5318", USDR_LOG_ERROR, "port#%d specified as phase-reverted and cannot be solved via APLL1", out->port); return -EINVAL; + } } @@ -567,7 +948,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned static const uint64_t fvco2_pd_min = VCO_APLL2_MIN / APLL2_PDIV_MAX; static const uint64_t fvco2_pd_max = VCO_APLL2_MAX / APLL2_PDIV_MIN; - //try to determine valid PD ranges for our frequencies + //determine valid PD ranges for our frequencies for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) { lmk05318_out_config_t* out = outs + i; @@ -578,7 +959,11 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned const range_t ifreq = {MAX(r.min, fvco2_pd_min) , MIN(r.max * lmk05318_max_odiv(out->port), fvco2_pd_max)}; if(ifreq.min > ifreq.max) + { + USDR_LOG("5318", USDR_LOG_ERROR, "port#%d freq:%d (-%d, +%d) is totally out of available range", + out->port, out->wanted.freq, out->wanted.freq_delta_minus, out->wanted.freq_delta_plus); return -EINVAL; + } const int pd_min = VCO_APLL2_MAX / ifreq.max; const int pd_max = VCO_APLL2_MAX / ifreq.min; @@ -590,236 +975,58 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned out->port, ifreq.min, ifreq.max, pd_min, pd_max); } - int pd1_index = -1; - bool found_sect = true; - range_t section; - - unsigned pd2_ids[MAX_REAL_PORTS]; - unsigned num_pd2 = 0; - - //then we make an intersection of these PD ranges - for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) - { - lmk05318_out_config_t* out = outs + i; - if(out->solved) - continue; - - section.min = 0; - section.max = -1; - USDR_LOG("5318", USDR_LOG_DEBUG,"Assume PD1=%d [%d, %d]", out->port, out->pd_min, out->pd_max); + int pd1 = 0, pd2 = 0; + uint64_t fvco2 = 0; - unsigned j; - found_sect = true; - num_pd2 = 0; + const uint64_t f_mid = (VCO_APLL2_MAX + VCO_APLL2_MIN) / 2; + const uint64_t half_band = (VCO_APLL2_MAX - VCO_APLL2_MIN) / 2; - for(j = 0; j < MAX_REAL_PORTS; ++j) - { - if(i == j) - continue; - - lmk05318_out_config_t* out2 = outs + j; - if(out2->solved) - continue; + //first try the center + int res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, &fvco2, &pd1, &pd2); - section.min = MAX(section.min, out2->pd_min); - section.max = MIN(section.max, out2->pd_max); - - USDR_LOG("5318", USDR_LOG_DEBUG,"\t port %d [%d, %d] -> section:[%lu, %lu]", - out2->port, out2->pd_min, out2->pd_max, section.min, section.max); - - if(section.min > section.max) - { - found_sect = false; - break; - } - - pd2_ids[num_pd2++] = j; - } - - if(found_sect) - { - pd1_index = i; - break; - } - } - - //means we need more than 2 post-dividers for our setup - if(!found_sect) - { - USDR_LOG("5318", USDR_LOG_ERROR, "No possible solutions for 2 PDs"); - return -EINVAL; - } - - pd_array_t pd_group[2]; - unsigned pd_group_count = 0; - - //and fill the PD groups. the count of PD groups must be 1 or 2. - if(num_pd2) - { - range_t r = {MAX(outs[pd1_index].pd_min, section.min), MIN(outs[pd1_index].pd_max, section.max)}; - if(r.max >= r.min) - { - pd_array_t* pd1 = &pd_group[pd_group_count++]; - pd1->pd_range = r; - pd1->port_count = 0; - pd1->port_ids[pd1->port_count++] = pd1_index; - - for(unsigned i = 0; i < num_pd2; ++i) - { - pd1->port_ids[pd1->port_count++] = pd2_ids[i]; - } - } - else - { - pd_array_t* pd1 = &pd_group[pd_group_count++]; - pd1->pd_range.min = outs[pd1_index].pd_min; - pd1->pd_range.max = outs[pd1_index].pd_max; - pd1->port_count = 0; - pd1->port_ids[pd1->port_count++] = pd1_index; - - pd_array_t* pd2 = &pd_group[pd_group_count++]; - pd2->pd_range = section; - pd2->port_count = 0; - for(unsigned i = 0; i < num_pd2; ++i) - { - pd2->port_ids[pd2->port_count++] = pd2_ids[i]; - } - } - } - else - { - pd_array_t* pd1 = &pd_group[pd_group_count++]; - pd1->pd_range.min = outs[pd1_index].pd_min; - pd1->pd_range.max = outs[pd1_index].pd_max; - pd1->port_count = 0; - pd1->port_ids[pd1->port_count++] = pd1_index; - } - - for(unsigned i = 0; i < pd_group_count; ++i) - { - pd_array_t* pd = pd_group + i; - USDR_LOG("5318", USDR_LOG_DEBUG, "PD%d:[%lu, %lu]", i + 1, pd->pd_range.min, pd->pd_range.max); - for(unsigned j = 0; j < pd->port_count; ++j) - USDR_LOG("5318", USDR_LOG_DEBUG, "\t port:%d", outs[pd->port_ids[j]].port); - } - - if(pd_group_count > 1) - { - USDR_LOG("5318", USDR_LOG_ERROR, "Solution via two PDs is not yet supported yet!"); - return -EINVAL; - } - - bool all_done = false; - uint64_t f_in; - unsigned pd1 = 0; - unsigned pd2 = 0; - - // Bisect search for PD1 - pd_array_t* pPD1 = &pd_group[0]; - - for(pd1 = pPD1->pd_range.min; !all_done && pd1 <= pPD1->pd_range.max; ++pd1) + //if not - do circular search + if(res) { - uint64_t f_in_min = VCO_APLL2_MIN / pd1; - uint64_t f_in_max = VCO_APLL2_MAX / pd1; + uint64_t step = half_band; - USDR_LOG("5318", USDR_LOG_DEBUG, "***** PD:%d f_in:[%" PRIu64 ", %" PRIu64 "] *****", pd1, f_in_min, f_in_max); - - while (f_in_min <= f_in_max) + //max search granularity hardcoded here + while(step > 10000) { - f_in = f_in_min + ((f_in_max - f_in_min) >> 1); - //USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT f_mid:%" PRIu64 " fvco2:%" PRIu64 "", f_in, f_in * pd1); - - int direction_flag = 0; - bool all_freqs_invalid = false; + uint64_t n = half_band / step; - direction_flag = bisect_finder(outs, pd_group, pd_group_count, pd1, &pd2, f_in, &all_freqs_invalid); - - //USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT direction_flag:%d, %s", direction_flag, - // all_freqs_invalid ? "invalid point!" : (direction_flag == 0 ? "all found" : (direction_flag > 0 ? "go left(down)" : "go right(up)"))); - - uint64_t f = 0; - if(all_freqs_invalid) + for(uint64_t i = 1; i <= n; ++i) { - USDR_LOG("5318", USDR_LOG_DEBUG, "BISECT we're near, gonna do spiral search in [%" PRIu64 " <- %" PRIu64 " -> %" PRIu64 "]", - f_in_min, f_in, f_in_max); - - int cnt = 2; - while(1) + res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid + i * step, &fvco2, &pd1, &pd2); + if(!res) { - // +1 -1 +2 -2 +3 -3 etc - f = f_in + (cnt % 2 ? (-1) : (1)) * (cnt >> 1); - - if(f > f_in_max || f < f_in_min) - break; - - direction_flag = bisect_finder(outs, pd_group, pd_group_count, pd1, &pd2, f, &all_freqs_invalid); - - if(!all_freqs_invalid) - break; - - ++cnt; + step = 0; + break; } - } - if(all_freqs_invalid) - break; // go to the next PD - - //all solved - if(direction_flag == 0) - { - f_in = f; - all_done = true; - break; - } - - //too high, go to the left (down) - if(direction_flag > 0) - { - f_in_max = f_in - 1; + res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid - i * step, &fvco2, &pd1, &pd2); + if(!res) + { + step = 0; + break; + } } - //too low, go to the right (up) - if(direction_flag < 0) - { - f_in_min = f_in + 1; - } + step /= 2; } } - uint64_t fvco2 = f_in * (--pd1); - - - if(all_done) - { - USDR_LOG("5318", USDR_LOG_WARNING, "=== SOLUTION via APLL2 FOUND @ VCO2:%" PRIu64 " and PD1:%d PD2:%d ===", - fvco2, pd1, pd2); - - for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) - { - lmk05318_out_config_t* out = outs + i; - if(out->solved) - continue; - - USDR_LOG("5318", USDR_LOG_WARNING, "port:%d solved via APLL2 [OD:%" PRIu64 " freq:%.2f mux:%d]", - out->port, out->result.out_div, out->result.freq, out->result.mux); - - out->solved = true; - --cnt_to_solve; - } - } - else - { - return -EINVAL; - } + if(res) + return res; - //and the FINAL solution - assert(cnt_to_solve == 0); + //if ok - update the results qsort(outs, MAX_REAL_PORTS, sizeof(lmk05318_out_config_t), lmk05318_comp_port); qsort(_outs, n_outs, sizeof(lmk05318_out_config_t), lmk05318_comp_port); - USDR_LOG("5318", USDR_LOG_ERROR, "=== COMPLETE SOLUTION @ VCO2:%" PRIu64 " and PD1:%d PD2:%d ===", fvco2, pd1, pd2); + bool complete_solution_check = true; + + USDR_LOG("5318", USDR_LOG_DEBUG, "=== COMPLETE SOLUTION @ VCO2:%" PRIu64 " and PD1:%d PD2:%d ===", fvco2, pd1, pd2); for(unsigned i = 0; i < n_outs; ++i) { lmk05318_out_config_t* out_dst = _outs + i; @@ -835,11 +1042,18 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned out_dst->solved = out_src->solved; out_dst->result = out_src->result; - USDR_LOG("5318", USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.2f mux:%d]", - out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux); - } + //check it + const range_t r = lmk05318_get_freq_range(out_dst); + const double f = out_dst->result.freq; + const bool is_freq_ok = f >= r.min && f <= r.max; + if(!is_freq_ok) + complete_solution_check = false; + USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.2f mux:%d] %s", + out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux, + is_freq_ok ? "**OK**" : "**BAD**"); + } - return 0; + return complete_solution_check ? 0 : -EINVAL; } diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 4d4a0fd0..3938dbe7 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -44,8 +44,8 @@ typedef enum lmk05318_type lmk05318_type_t; struct lmk05318_out_config { unsigned port; //0..7 - bool solved; + // these fields are inputs struct { uint32_t freq; @@ -54,6 +54,7 @@ struct lmk05318_out_config lmk05318_type_t type; } wanted; + // these fields are results struct { double freq; @@ -61,11 +62,13 @@ struct lmk05318_out_config int mux; } result; - // + //* + // these fields are for internal use, do not fill them + bool solved; uint64_t max_odiv; uint32_t freq_min, freq_max; uint32_t pd_min, pd_max; - // + //* }; typedef struct lmk05318_out_config lmk05318_out_config_t; diff --git a/src/utests/lmk05318_test.c b/src/utests/lmk05318_test.c index 72a187a0..d6f7b123 100644 --- a/src/utests/lmk05318_test.c +++ b/src/utests/lmk05318_test.c @@ -44,7 +44,7 @@ int main() cfg[3].wanted.type = OUT_OFF; cfg[4].port = 4; - cfg[4].wanted.freq = 312500000; + cfg[4].wanted.freq = 31250000; cfg[4].wanted.freq_delta_minus = DELTA_MINUS; cfg[4].wanted.freq_delta_plus = DELTA_PLUS; cfg[4].wanted.revert_phase = false; @@ -71,6 +71,15 @@ int main() cfg[7].wanted.revert_phase = true; cfg[7].wanted.type = OUT_OFF; +// VCO_APLL2_MIN = 5500000000ull, +// VCO_APLL2_MAX = 6250000000ull, +/* + uint64_t f = 5659995555ull; + cfg[2].wanted.freq = cfg[3].wanted.freq = f/7/256; + cfg[5].wanted.freq = f/2/4; + cfg[6].wanted.freq = f/7/17; +*/ + int res = lmk05318_solver(NULL, cfg, 8); if(res) { From 5e21945270c758b25b8548212931a354919a9ebb Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 24 Feb 2025 15:31:46 +0300 Subject: [PATCH 009/397] headers refact (lost #include) --- src/lib/hw/lmk05318/lmk05318.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 8fb48f99..18beff42 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -5,7 +5,6 @@ #define LMK05318_H #include -#include "lmk05318_solver.h" #define MAX_OUT_PORTS 8 #define MAX_REAL_PORTS (MAX_OUT_PORTS - 2) From b1a6540b81a778d98b84dccb032724f80a989e8c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 24 Feb 2025 16:14:48 +0300 Subject: [PATCH 010/397] lmk05318 solver test rewritten to CHECK and added to the test suite --- src/lib/hw/lmk05318/lmk05318.c | 2 +- src/utests/CMakeLists.txt | 4 +- ...lmk05318_test.c => lmk05318_solver_test.c} | 57 ++++++++++++------- src/utests/test_suite.c | 8 ++- 4 files changed, 43 insertions(+), 28 deletions(-) rename src/utests/{lmk05318_test.c => lmk05318_solver_test.c} (73%) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 366df9bb..3c263861 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -923,7 +923,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } else { - USDR_LOG("5318", USDR_LOG_WARNING, "port:%d cannot solve it via APLL1, will try APLL2", out->port); + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d cannot solve it via APLL1, will try APLL2", out->port); } //we cannot revert phase for ports NOT linked to APLL1 diff --git a/src/utests/CMakeLists.txt b/src/utests/CMakeLists.txt index dbaa19ab..d3cc30b6 100644 --- a/src/utests/CMakeLists.txt +++ b/src/utests/CMakeLists.txt @@ -13,6 +13,7 @@ set(TEST_SUIT_SRCS ring_buffer_test.c trig_test.c clockgen_test.c + lmk05318_solver_test.c ) include_directories(../lib/xdsp) @@ -20,6 +21,3 @@ include_directories(../lib/common) add_executable(usdr_testsuit ${TEST_SUIT_SRCS}) target_link_libraries(usdr_testsuit usdr mock_lowlevel usdr-dsp check subunit m rt pthread) - -add_executable(lmk05318_test lmk05318_test.c) -target_link_libraries(lmk05318_test usdr check subunit m rt pthread) diff --git a/src/utests/lmk05318_test.c b/src/utests/lmk05318_solver_test.c similarity index 73% rename from src/utests/lmk05318_test.c rename to src/utests/lmk05318_solver_test.c index d6f7b123..273055b5 100644 --- a/src/utests/lmk05318_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -1,19 +1,15 @@ -#include "stdio.h" +#include #include "lmk05318/lmk05318.h" -#include "usdr_logging.h" #define OUTS_LEN 8 #define DELTA_PLUS 2 #define DELTA_MINUS 2 -int main() -{ - fprintf(stderr, "LMK05318 solver test\n"); - - usdrlog_setlevel(NULL, USDR_LOG_DEBUG); - usdrlog_enablecolorize(NULL); +static lmk05318_out_config_t cfg[OUTS_LEN]; - lmk05318_out_config_t cfg[OUTS_LEN]; +static void setup() +{ + memset(cfg, 0, sizeof(cfg)); cfg[0].port = 0; cfg[0].wanted.freq = 100000000; @@ -70,23 +66,40 @@ int main() cfg[7].wanted.freq_delta_plus = DELTA_PLUS; cfg[7].wanted.revert_phase = true; cfg[7].wanted.type = OUT_OFF; +} + +static void teardown() +{ +} + +START_TEST(lmk05318_solver_test1) +{ + int res = lmk05318_solver(NULL, cfg, 8); + ck_assert_int_eq( res, 0 ); +} -// VCO_APLL2_MIN = 5500000000ull, -// VCO_APLL2_MAX = 6250000000ull, -/* - uint64_t f = 5659995555ull; +START_TEST(lmk05318_solver_test2) +{ + const uint64_t f = 5659995555ull; cfg[2].wanted.freq = cfg[3].wanted.freq = f/7/256; cfg[5].wanted.freq = f/2/4; cfg[6].wanted.freq = f/7/17; -*/ int res = lmk05318_solver(NULL, cfg, 8); - if(res) - { - fprintf(stderr, "lmk05318_solver() error:%d\n", res); - return res; - } - - fprintf(stderr, "lmk05318_solver() OK\n"); - return 0; + ck_assert_int_eq( res, 0 ); +} + +Suite * lmk05318_solver_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("lmk05318_solver"); + tc_core = tcase_create("HW"); + tcase_set_timeout(tc_core, 1); + tcase_add_checked_fixture(tc_core, setup, teardown); + tcase_add_test(tc_core, lmk05318_solver_test1); + tcase_add_test(tc_core, lmk05318_solver_test2); + suite_add_tcase(s, tc_core); + return s; } diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index 043afe29..d802597f 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -11,6 +11,7 @@ Suite * ring_buffer_suite(void); Suite * trig_suite(void); Suite * clockgen_suite(void); +Suite * lmk05318_solver_suite(void); int main(int argc, char** argv) { @@ -24,11 +25,14 @@ int main(int argc, char** argv) fprintf(stderr, "Running with %s CPU features\n", buffer); usdrlog_setlevel(NULL, (argc > 1) ? USDR_LOG_TRACE : USDR_LOG_INFO); usdrlog_enablecolorize(NULL); - +#if 1 sr = srunner_create(ring_buffer_suite()); srunner_add_suite(sr, trig_suite()); srunner_add_suite(sr, clockgen_suite()); - + srunner_add_suite(sr, lmk05318_solver_suite()); +#else + sr = srunner_create(lmk05318_solver_suite()); +#endif srunner_run_all(sr, (argc > 1) ? CK_VERBOSE : CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); From 61c34b7b88f1965946b243799c0ffe4d231253e1 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 24 Feb 2025 18:46:53 +0300 Subject: [PATCH 011/397] refactoring + add hw registers set to solver --- src/lib/hw/lmk05318/lmk05318.c | 124 +++++++++++++++++++++++++----- src/lib/hw/lmk05318/lmk05318.h | 30 +++++++- src/utests/lmk05318_solver_test.c | 83 +++++--------------- src/utests/test_suite.c | 2 +- 4 files changed, 150 insertions(+), 89 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 3c263861..5caaaaeb 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -185,6 +185,52 @@ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) return 0; } +static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned pd1, unsigned pd2) +{ + unsigned fref = VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; + if (fref < APLL2_PD_MIN || fref > APLL2_PD_MAX) { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 PFD should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", + (uint64_t)APLL2_PD_MIN, (uint64_t)APLL2_PD_MAX, fref); + return -EINVAL; + } + + if(fvco2 < VCO_APLL2_MIN || fvco2 > VCO_APLL2_MAX || + pd1 < APLL2_PDIV_MIN || pd1 > APLL2_PDIV_MAX || + pd2 < APLL2_PDIV_MIN || pd2 > APLL2_PDIV_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2: either FVCO2[%" PRIu64"] or PD1[%d] or PD2[%d] is out of range", + fvco2, pd1, pd2); + // Disable + uint32_t regs[] = { + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), + }; + return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs));; + } + + unsigned n = fvco2 / fref; + unsigned num = (fvco2 - n * (uint64_t)fref) * (1ull << 24) / fref; + int res; + + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 FVCO=%" PRIu64 " N=%d NUM=%d PD1=%d PD2=%d\n", fvco2, n, num, pd1, pd2); + + uint32_t regs[] = { + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), + MAKE_LMK05318_PLL2_CTRL2(pd2 - 1, pd1 - 1), + MAKE_LMK05318_PLL2_NDIV_BY0(n), + MAKE_LMK05318_PLL2_NDIV_BY1(n), + MAKE_LMK05318_PLL2_NUM_BY0(num), + MAKE_LMK05318_PLL2_NUM_BY1(num), + MAKE_LMK05318_PLL2_NUM_BY2(num), + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), + }; + + res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + if (res) + return res; + + return 0; +} + int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, bool xo_doubler_enabled, bool xo_fdet_bypass) { @@ -281,7 +327,7 @@ int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype) +static int lmk05318_set_out_mux_ex(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) { unsigned ot; switch (otype) { @@ -291,7 +337,6 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned case LVCMOS: ot = OUT_OPTS_LVCMOS_P_N; break; default: ot = OUT_OPTS_Disabled; break; } - unsigned mux = (pll1) ? OUT_PLL_SEL_APLL1_P1 : OUT_PLL_SEL_APLL2_P1; if (port > 7) return -EINVAL; @@ -308,9 +353,14 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } +int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype) +{ + return lmk05318_set_out_mux_ex(d, port, (pll1 ? OUT_PLL_SEL_APLL1_P1 : OUT_PLL_SEL_APLL2_P1), otype); +} + static uint64_t lmk05318_max_odiv(unsigned port) { - assert(port < MAX_OUT_PORTS); + assert(port < LMK05318_MAX_OUT_PORTS); switch(port) { @@ -392,11 +442,11 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c }; typedef struct fvco2_range fvco2_range_t; - fvco2_range_t fvco2_ranges[(APLL2_PDIV_MAX - APLL2_PDIV_MIN + 1) * 2 * MAX_REAL_PORTS]; + fvco2_range_t fvco2_ranges[(APLL2_PDIV_MAX - APLL2_PDIV_MIN + 1) * 2 * LMK05318_MAX_REAL_PORTS]; int fvco2_ranges_count = 0; // find FVCO2 ranges for all PDs and all ports - for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) + for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) { lmk05318_out_config_t* out = outs + i; if(out->solved) @@ -458,7 +508,7 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c int prim_idx; range_t intersection; int sect_counter; - int sects[(APLL2_PDIV_MAX - APLL2_PDIV_MIN + 1) * 2 * MAX_REAL_PORTS]; + int sects[(APLL2_PDIV_MAX - APLL2_PDIV_MIN + 1) * 2 * LMK05318_MAX_REAL_PORTS]; }; typedef struct intersects intersects_t; @@ -550,7 +600,7 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c struct solution { range_t fvco2; - solution_var_t vars[MAX_REAL_PORTS]; + solution_var_t vars[LMK05318_MAX_REAL_PORTS]; int vars_count; bool is_valid; }; @@ -666,8 +716,8 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c struct pd_bind { int pd; - int ports[MAX_REAL_PORTS]; - uint64_t odivs[MAX_REAL_PORTS]; + int ports[LMK05318_MAX_REAL_PORTS]; + uint64_t odivs[LMK05318_MAX_REAL_PORTS]; int ports_count; }; typedef struct pd_bind pd_bind_t; @@ -692,7 +742,7 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c pd_binds[0].odivs[0] = sol->vars[0].divs[0].od; pd_binds_count = 1; - int unmapped_ports[MAX_REAL_PORTS]; + int unmapped_ports[LMK05318_MAX_REAL_PORTS]; int unmapped_ports_count = 0; //scan all other vars, try to find variants with PD==PD1 and add them to PD1 binding @@ -837,25 +887,31 @@ static int lmk05318_comp_port(const void * elem1, const void * elem2) VWLT_ATTRIBUTE(optimize("-Ofast")) -int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs) +int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run) { - if(!_outs || !n_outs || n_outs > MAX_OUT_PORTS) + if(!_outs || !n_outs || n_outs > LMK05318_MAX_OUT_PORTS) { USDR_LOG("5318", USDR_LOG_ERROR, "input data is incorrect"); return -EINVAL; } // internally we have only _6_ out divs and freqs (0==1 and 2==3), except output type, but it does not matter here - lmk05318_out_config_t outs[MAX_REAL_PORTS]; + lmk05318_out_config_t outs[LMK05318_MAX_REAL_PORTS]; memset(outs, 0, sizeof(outs)); for(unsigned i = 0; i < n_outs; ++i) { lmk05318_out_config_t* out = _outs + i; - if(out->port > MAX_OUT_PORTS - 1) + if(out->port > LMK05318_MAX_OUT_PORTS - 1) { - USDR_LOG("5318", USDR_LOG_ERROR, "port value should be in [0; %d] diap", (MAX_OUT_PORTS - 1)); + USDR_LOG("5318", USDR_LOG_ERROR, "port value should be in [0; %d] diap", (LMK05318_MAX_OUT_PORTS - 1)); + return -EINVAL; + } + + if(out->wanted.type == LVCMOS && out->port < 4) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LVCMOS output type supported for ports# 4..7 only"); return -EINVAL; } @@ -892,7 +948,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned //now outs[] contains effective ports ordered (0..5) config. //some elems may be not initialized (wanted.freq == 0) and should not be processed. - for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) + for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) { outs[i].solved = outs[i].wanted.freq == 0; USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d freq:%d (-%d, +%d) *%s*", @@ -903,7 +959,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned //first we try routing ports to APLL1 //it's easy - for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) + for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) { lmk05318_out_config_t* out = outs + i; if(out->solved) @@ -938,7 +994,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned //second - try routing to APLL2 unsigned cnt_to_solve = 0; USDR_LOG("5318", USDR_LOG_DEBUG,"Need to solve via APLL2:"); - for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) + for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) { if(outs[i].solved) continue; @@ -956,7 +1012,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned static const uint64_t fvco2_pd_max = VCO_APLL2_MAX / APLL2_PDIV_MIN; //determine valid PD ranges for our frequencies - for(unsigned i = 0; i < MAX_REAL_PORTS; ++i) + for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) { lmk05318_out_config_t* out = outs + i; if(out->solved) @@ -1028,7 +1084,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned //if ok - update the results - qsort(outs, MAX_REAL_PORTS, sizeof(lmk05318_out_config_t), lmk05318_comp_port); + qsort(outs, LMK05318_MAX_REAL_PORTS, sizeof(lmk05318_out_config_t), lmk05318_comp_port); qsort(_outs, n_outs, sizeof(lmk05318_out_config_t), lmk05318_comp_port); bool complete_solution_check = true; @@ -1061,7 +1117,33 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned is_freq_ok ? "**OK**" : "**BAD**"); } - return complete_solution_check ? 0 : -EINVAL; + if(complete_solution_check == false) + return -EINVAL; + + //update hw registers + if(!dry_run) + { + //tune APLL2 + int res = lmk05318_tune_apll2_ex(d, fvco2, pd1, pd2); + if(res) + return res; + + //set output ports + for(unsigned i = 0; i < n_outs; ++i) + { + const lmk05318_out_config_t* out = _outs + i; + + res = lmk05318_set_out_mux_ex(d, out->port, out->result.mux, out->wanted.type); + res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "error %d setting hw parameters for port#%d", res, out->port); + return res; + } + } + } + + return 0; } int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk) diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 18beff42..ae22cae2 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -6,8 +6,8 @@ #include -#define MAX_OUT_PORTS 8 -#define MAX_REAL_PORTS (MAX_OUT_PORTS - 2) +#define LMK05318_MAX_OUT_PORTS 8 +#define LMK05318_MAX_REAL_PORTS (LMK05318_MAX_OUT_PORTS - 2) struct lmk05318_state { lldev_t dev; @@ -62,7 +62,7 @@ struct lmk05318_out_config } result; //* - // these fields are for internal use, do not fill them + // these fields are for internal use, do not touch them. Use lmk05318_port_request(). bool solved; uint64_t max_odiv; uint32_t freq_min, freq_max; @@ -71,6 +71,28 @@ struct lmk05318_out_config }; typedef struct lmk05318_out_config lmk05318_out_config_t; +static inline int lmk05318_port_request(lmk05318_out_config_t* cfg, + unsigned port, + uint32_t freq, + unsigned freq_delta_plus, unsigned freq_delta_minus, + bool revert_phase, + lmk05318_type_t type) +{ + if(port > LMK05318_MAX_OUT_PORTS - 1) + return -EINVAL; + + lmk05318_out_config_t* p = cfg + port; + memset(p, 0, sizeof(*p)); + p->port = port; + p->wanted.freq = freq; + p->wanted.freq_delta_plus = freq_delta_plus; + p->wanted.freq_delta_minus = freq_delta_minus; + p->wanted.revert_phase = revert_phase; + p->wanted.type = type; + p->solved = false; + return 0; +} + int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned flags, lmk05318_state_t* out); int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div); @@ -100,6 +122,6 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode); -int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs); +int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run); #endif diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 273055b5..4112fe85 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -1,7 +1,7 @@ #include #include "lmk05318/lmk05318.h" -#define OUTS_LEN 8 +#define OUTS_LEN LMK05318_MAX_OUT_PORTS #define DELTA_PLUS 2 #define DELTA_MINUS 2 @@ -9,63 +9,16 @@ static lmk05318_out_config_t cfg[OUTS_LEN]; static void setup() { - memset(cfg, 0, sizeof(cfg)); - - cfg[0].port = 0; - cfg[0].wanted.freq = 100000000; - cfg[0].wanted.freq_delta_minus = DELTA_MINUS; - cfg[0].wanted.freq_delta_plus = DELTA_PLUS; - cfg[0].wanted.revert_phase = false; - cfg[0].wanted.type = OUT_OFF; - - cfg[1].port = 1; - cfg[1].wanted.freq = 100000000; - cfg[1].wanted.freq_delta_minus = DELTA_MINUS; - cfg[1].wanted.freq_delta_plus = DELTA_PLUS; - cfg[1].wanted.revert_phase = false; - cfg[1].wanted.type = OUT_OFF; - - cfg[2].port = 2; - cfg[2].wanted.freq = 122880000; - cfg[2].wanted.freq_delta_minus = DELTA_MINUS; - cfg[2].wanted.freq_delta_plus = DELTA_PLUS; - cfg[2].wanted.revert_phase = false; - cfg[2].wanted.type = OUT_OFF; - - cfg[3].port = 3; - cfg[3].wanted.freq = 122880000; - cfg[3].wanted.freq_delta_minus = DELTA_MINUS; - cfg[3].wanted.freq_delta_plus = DELTA_PLUS; - cfg[3].wanted.revert_phase = false; - cfg[3].wanted.type = OUT_OFF; - - cfg[4].port = 4; - cfg[4].wanted.freq = 31250000; - cfg[4].wanted.freq_delta_minus = DELTA_MINUS; - cfg[4].wanted.freq_delta_plus = DELTA_PLUS; - cfg[4].wanted.revert_phase = false; - cfg[4].wanted.type = OUT_OFF; - - cfg[5].port = 5; - cfg[5].wanted.freq = 3840000; - cfg[5].wanted.freq_delta_minus = DELTA_MINUS; - cfg[5].wanted.freq_delta_plus = DELTA_PLUS; - cfg[5].wanted.revert_phase = false; - cfg[5].wanted.type = OUT_OFF; - - cfg[6].port = 6; - cfg[6].wanted.freq = 491520000; - cfg[6].wanted.freq_delta_minus = DELTA_MINUS; - cfg[6].wanted.freq_delta_plus = DELTA_PLUS; - cfg[6].wanted.revert_phase = false; - cfg[6].wanted.type = OUT_OFF; - - cfg[7].port = 7; - cfg[7].wanted.freq = 1; - cfg[7].wanted.freq_delta_minus = DELTA_MINUS; - cfg[7].wanted.freq_delta_plus = DELTA_PLUS; - cfg[7].wanted.revert_phase = true; - cfg[7].wanted.type = OUT_OFF; + int res = 0; + res = res ? res : lmk05318_port_request(cfg, 0, 100000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, 100000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 2, 122880000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, 122880000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, 31250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 3840000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 491520000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, true, OUT_OFF); + ck_assert_int_eq( res, 0 ); } static void teardown() @@ -74,18 +27,22 @@ static void teardown() START_TEST(lmk05318_solver_test1) { - int res = lmk05318_solver(NULL, cfg, 8); + int res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); ck_assert_int_eq( res, 0 ); } START_TEST(lmk05318_solver_test2) { + int res = 0; const uint64_t f = 5659995555ull; - cfg[2].wanted.freq = cfg[3].wanted.freq = f/7/256; - cfg[5].wanted.freq = f/2/4; - cfg[6].wanted.freq = f/7/17; - int res = lmk05318_solver(NULL, cfg, 8); + res = res ? res : lmk05318_port_request(cfg, 2, f/7/256, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, f/7/256, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, f/2/4, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, f/7/17, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + ck_assert_int_eq( res, 0 ); + + res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); ck_assert_int_eq( res, 0 ); } diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index d802597f..c1a7a027 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -25,7 +25,7 @@ int main(int argc, char** argv) fprintf(stderr, "Running with %s CPU features\n", buffer); usdrlog_setlevel(NULL, (argc > 1) ? USDR_LOG_TRACE : USDR_LOG_INFO); usdrlog_enablecolorize(NULL); -#if 1 +#if 0 sr = srunner_create(ring_buffer_suite()); srunner_add_suite(sr, trig_suite()); srunner_add_suite(sr, clockgen_suite()); From a0750f44b86ae5e4131e12ae54debc2785610630 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 25 Feb 2025 15:16:19 +0300 Subject: [PATCH 012/397] intermediate commit --- src/lib/hw/lmk05318/lmk05318.c | 102 +++++++++++++++++++++++------- src/lib/hw/lmk05318/lmk05318.h | 28 ++++++++ src/utests/lmk05318_solver_test.c | 71 ++++++++++++++++++++- 3 files changed, 175 insertions(+), 26 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 5caaaaeb..4d2cb1fc 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -95,6 +95,9 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int out->dev = dev; out->subdev = subdev; out->lsaddr = lsaddr; + out->vco2_freq = 0; + out->pd1 = 0; + out->pd2 = 0; res = lmk05318_reg_get_u32(out, 0, &dummy[0]); if (res) @@ -195,10 +198,10 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned } if(fvco2 < VCO_APLL2_MIN || fvco2 > VCO_APLL2_MAX || - pd1 < APLL2_PDIV_MIN || pd1 > APLL2_PDIV_MAX || - pd2 < APLL2_PDIV_MIN || pd2 > APLL2_PDIV_MAX) + ((pd1 < APLL2_PDIV_MIN || pd1 > APLL2_PDIV_MAX) && (pd2 < APLL2_PDIV_MIN || pd2 > APLL2_PDIV_MAX)) + ) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2: either FVCO2[%" PRIu64"] or PD1[%d] or PD2[%d] is out of range", + USDR_LOG("5318", USDR_LOG_WARNING, "LMK05318 APLL2: either FVCO2[%" PRIu64"] or (PD1[%d] && PD2[%d]) is out of range, APLL2 will be disabled", fvco2, pd1, pd2); // Disable uint32_t regs[] = { @@ -211,7 +214,17 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned unsigned num = (fvco2 - n * (uint64_t)fref) * (1ull << 24) / fref; int res; - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 FVCO=%" PRIu64 " N=%d NUM=%d PD1=%d PD2=%d\n", fvco2, n, num, pd1, pd2); + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 FVCO=%" PRIu64 " N=%d NUM=%d PD1=%d PD2=%d\n", fvco2, n, num, pd1, pd2); + + // one of PDs may be unused (==0) -> we should fix it before registers set + if(pd1 < APLL2_PDIV_MIN || pd1 > APLL2_PDIV_MAX) + { + pd1 = pd2; + } + else if(pd2 < APLL2_PDIV_MIN || pd2 > APLL2_PDIV_MAX) + { + pd2 = pd1; + } uint32_t regs[] = { MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), @@ -886,16 +899,31 @@ static int lmk05318_comp_port(const void * elem1, const void * elem2) } +static const char* lmk05318_decode_mux(enum lmk05318_out_pll_sel_t mux) +{ + switch(mux) + { + case OUT_PLL_SEL_APLL1_P1: return "APLL1"; + case OUT_PLL_SEL_APLL1_P1_INV: return "APLL1 inv"; + case OUT_PLL_SEL_APLL2_P1: return "APLL2 PD1"; + case OUT_PLL_SEL_APLL2_P2: return "APLL2 PD2"; + } + return "UNKNOWN"; +} + VWLT_ATTRIBUTE(optimize("-Ofast")) int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run) { + int pd1 = 0, pd2 = 0; + uint64_t fvco2 = 0; + if(!_outs || !n_outs || n_outs > LMK05318_MAX_OUT_PORTS) { USDR_LOG("5318", USDR_LOG_ERROR, "input data is incorrect"); return -EINVAL; } - // internally we have only _6_ out divs and freqs (0==1 and 2==3), except output type, but it does not matter here + // internally we have only _6_ out divs and freqs (0==1 and 2==3) - except the output type, but it does not matter here lmk05318_out_config_t outs[LMK05318_MAX_REAL_PORTS]; memset(outs, 0, sizeof(outs)); @@ -930,7 +958,8 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned (norm_out->wanted.freq != out->wanted.freq || norm_out->wanted.freq_delta_plus != out->wanted.freq_delta_plus || norm_out->wanted.freq_delta_minus != out->wanted.freq_delta_minus || - norm_out->wanted.revert_phase != out->wanted.revert_phase + norm_out->wanted.revert_phase != out->wanted.revert_phase || + norm_out->wanted.pll_affinity != out->wanted.pll_affinity )) { USDR_LOG("5318", USDR_LOG_ERROR, "dup ports values detected, or ports #0:1 & #2:3 differ"); @@ -965,21 +994,28 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(out->solved) continue; - uint64_t odiv = 0; - int res = lmk05318_get_output_divider(out, VCO_APLL1, &odiv); - if(!res) + if(out->wanted.pll_affinity == AFF_ANY || out->wanted.pll_affinity == AFF_APLL1) { - out->solved = true; - out->result.out_div = odiv; - out->result.freq = (double)VCO_APLL1 / odiv; - out->result.mux = out->wanted.revert_phase ? OUT_PLL_SEL_APLL1_P1_INV : OUT_PLL_SEL_APLL1_P1; + uint64_t odiv = 0; + int res = lmk05318_get_output_divider(out, VCO_APLL1, &odiv); + if(!res) + { + out->solved = true; + out->result.out_div = odiv; + out->result.freq = (double)VCO_APLL1 / odiv; + out->result.mux = out->wanted.revert_phase ? OUT_PLL_SEL_APLL1_P1_INV : OUT_PLL_SEL_APLL1_P1; - USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d solved via APLL1 [OD:%" PRIu64 " freq:%.2f mux:%d]", - out->port, out->result.out_div, out->result.freq, out->result.mux); + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d solved via APLL1 [OD:%" PRIu64 " freq:%.2f mux:%d]", + out->port, out->result.out_div, out->result.freq, out->result.mux); + } + else + { + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d cannot solve it via APLL1, will try APLL2", out->port); + } } else { - USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d cannot solve it via APLL1, will try APLL2", out->port); + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d forbidden to solve via APLL1 by config, will try APLL2", out->port); } //we cannot revert phase for ports NOT linked to APLL1 @@ -990,7 +1026,6 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } } - //second - try routing to APLL2 unsigned cnt_to_solve = 0; USDR_LOG("5318", USDR_LOG_DEBUG,"Need to solve via APLL2:"); @@ -1006,7 +1041,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } if(!cnt_to_solve) - return 0; + goto have_complete_solution; static const uint64_t fvco2_pd_min = VCO_APLL2_MIN / APLL2_PDIV_MAX; static const uint64_t fvco2_pd_max = VCO_APLL2_MAX / APLL2_PDIV_MIN; @@ -1038,10 +1073,6 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned out->port, ifreq.min, ifreq.max, pd_min, pd_max); } - - int pd1 = 0, pd2 = 0; - uint64_t fvco2 = 0; - const uint64_t f_mid = (VCO_APLL2_MAX + VCO_APLL2_MIN) / 2; const uint64_t half_band = (VCO_APLL2_MAX - VCO_APLL2_MIN) / 2; @@ -1082,6 +1113,9 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(res) return res; + +have_complete_solution: + //if ok - update the results qsort(outs, LMK05318_MAX_REAL_PORTS, sizeof(lmk05318_out_config_t), lmk05318_comp_port); @@ -1089,7 +1123,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned bool complete_solution_check = true; - USDR_LOG("5318", USDR_LOG_DEBUG, "=== COMPLETE SOLUTION @ VCO2:%" PRIu64 " and PD1:%d PD2:%d ===", fvco2, pd1, pd2); + USDR_LOG("5318", USDR_LOG_DEBUG, "=== COMPLETE SOLUTION @ VCO1:%" PRIu64 " VCO2:%" PRIu64 " PD1:%d PD2:%d ===", VCO_APLL1, fvco2, pd1, pd2); for(unsigned i = 0; i < n_outs; ++i) { lmk05318_out_config_t* out_dst = _outs + i; @@ -1112,21 +1146,41 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(!is_freq_ok) complete_solution_check = false; - USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.2f mux:%d] %s", + USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.2f mux:%d(%s)] %s", out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux, + lmk05318_decode_mux(out_dst->result.mux), is_freq_ok ? "**OK**" : "**BAD**"); } if(complete_solution_check == false) return -EINVAL; + if(d) + { + //update params in context + d->vco2_freq = fvco2; + d->pd1 = pd1; + d->pd2 = pd2; + + for(unsigned i = 0; i < n_outs; ++i) + { + const lmk05318_out_config_t* out = _outs + i; + d->outputs[out->port].freq = out->result.freq; + d->outputs[out->port].odiv = out->result.out_div; + d->outputs[out->port].mux = out->result.mux; + } + } + //update hw registers if(!dry_run) { //tune APLL2 int res = lmk05318_tune_apll2_ex(d, fvco2, pd1, pd2); if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "error %d tuning APLL2", res); return res; + } //set output ports for(unsigned i = 0; i < n_outs; ++i) diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index ae22cae2..a69e6881 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -20,6 +20,13 @@ struct lmk05318_state { // VCO2 freq uint64_t vco2_freq; + unsigned pd1, pd2; + + struct { + double freq; + uint64_t odiv; + int mux; + } outputs[LMK05318_MAX_OUT_PORTS]; struct { uint32_t fref; @@ -40,6 +47,14 @@ enum lmk05318_type { typedef struct lmk05318_state lmk05318_state_t; typedef enum lmk05318_type lmk05318_type_t; +enum lmk05318_port_affinity +{ + AFF_ANY = 0, + AFF_APLL1, + AFF_APLL2 +}; +typedef enum lmk05318_port_affinity lmk05318_port_affinity_t; + struct lmk05318_out_config { unsigned port; //0..7 @@ -51,6 +66,7 @@ struct lmk05318_out_config unsigned freq_delta_plus, freq_delta_minus; bool revert_phase; lmk05318_type_t type; + lmk05318_port_affinity_t pll_affinity; } wanted; // these fields are results @@ -89,10 +105,22 @@ static inline int lmk05318_port_request(lmk05318_out_config_t* cfg, p->wanted.freq_delta_minus = freq_delta_minus; p->wanted.revert_phase = revert_phase; p->wanted.type = type; + p->wanted.pll_affinity = AFF_ANY; p->solved = false; return 0; } +static inline int lmk05318_set_port_affinity(lmk05318_out_config_t* cfg, unsigned port, lmk05318_port_affinity_t aff) +{ + if(port > LMK05318_MAX_OUT_PORTS - 1) + return -EINVAL; + + lmk05318_out_config_t* p = cfg + port; + p->wanted.pll_affinity = aff; + + return 0; +} + int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned flags, lmk05318_state_t* out); int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 4112fe85..ef384267 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -46,6 +46,69 @@ START_TEST(lmk05318_solver_test2) ck_assert_int_eq( res, 0 ); } + +START_TEST(lmk05318_solver_test3) +{ + uint64_t fvco1 = 2500000000ull; + uint64_t f0_3 = fvco1 / 123; + uint64_t f4_7 = 12500000; //3840000; + + int res = 0; + res = res ? res : lmk05318_port_request(cfg, 0, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 2, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 7, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + ck_assert_int_eq( res, 0 ); + + res = res ? res : lmk05318_set_port_affinity(cfg, 0, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 1, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 2, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 3, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 4, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(cfg, 5, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(cfg, 6, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); + ck_assert_int_eq( res, 0 ); + + res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmk05318_solver_test4) +{ + uint64_t fvco1 = 2500000000ull; + uint64_t f0_3 = fvco1 / 123; + uint64_t f4_7 = 12500000; //3840000; + + int res = 0; + res = res ? res : lmk05318_port_request(cfg, 0, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 2, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 7, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + ck_assert_int_eq( res, 0 ); + + res = res ? res : lmk05318_set_port_affinity(cfg, 0, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 1, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 2, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 3, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(cfg, 4, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(cfg, 5, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(cfg, 6, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); + ck_assert_int_eq( res, 0 ); + + res = lmk05318_solver(NULL, cfg, 4, true); + ck_assert_int_eq( res, 0 ); +} + Suite * lmk05318_solver_suite(void) { Suite *s; @@ -55,8 +118,12 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, lmk05318_solver_test1); - tcase_add_test(tc_core, lmk05318_solver_test2); + + //tcase_add_test(tc_core, lmk05318_solver_test1); + //tcase_add_test(tc_core, lmk05318_solver_test2); + //tcase_add_test(tc_core, lmk05318_solver_test3); + tcase_add_test(tc_core, lmk05318_solver_test4); + suite_add_tcase(s, tc_core); return s; } From 0f705de12af8f01ed94eba3d0e4bd5e674975199 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 25 Feb 2025 18:45:54 +0300 Subject: [PATCH 013/397] enforcing solver - now it can work with incomplete set of ports --- src/lib/hw/lmk05318/lmk05318.c | 15 ++++++++++++--- src/utests/lmk05318_solver_test.c | 11 +++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 4d2cb1fc..f26dd865 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -931,6 +931,12 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned { lmk05318_out_config_t* out = _outs + i; + if(out->wanted.freq == 0) + { + USDR_LOG("5318", USDR_LOG_DEBUG, "skipping port#%d freq=0", out->port); + continue; + } + if(out->port > LMK05318_MAX_OUT_PORTS - 1) { USDR_LOG("5318", USDR_LOG_ERROR, "port value should be in [0; %d] diap", (LMK05318_MAX_OUT_PORTS - 1)); @@ -985,7 +991,6 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned outs[i].solved ? "not used" : "active"); } - //first we try routing ports to APLL1 //it's easy for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) @@ -1118,9 +1123,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned //if ok - update the results - qsort(outs, LMK05318_MAX_REAL_PORTS, sizeof(lmk05318_out_config_t), lmk05318_comp_port); qsort(_outs, n_outs, sizeof(lmk05318_out_config_t), lmk05318_comp_port); - bool complete_solution_check = true; USDR_LOG("5318", USDR_LOG_DEBUG, "=== COMPLETE SOLUTION @ VCO1:%" PRIu64 " VCO2:%" PRIu64 " PD1:%d PD2:%d ===", VCO_APLL1, fvco2, pd1, pd2); @@ -1129,6 +1132,9 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned lmk05318_out_config_t* out_dst = _outs + i; lmk05318_out_config_t* out_src = NULL; + if(out_dst->wanted.freq == 0) + continue; + if(out_dst->port < 2) out_src = outs + 0; else if(out_dst->port < 4) @@ -1187,6 +1193,9 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned { const lmk05318_out_config_t* out = _outs + i; + if(out->wanted.freq == 0) + continue; + res = lmk05318_set_out_mux_ex(d, out->port, out->result.mux, out->wanted.type); res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); if(res) diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index ef384267..c8cdf7b8 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -9,6 +9,8 @@ static lmk05318_out_config_t cfg[OUTS_LEN]; static void setup() { + memset(cfg, 0, sizeof(cfg)); + int res = 0; res = res ? res : lmk05318_port_request(cfg, 0, 100000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 1, 100000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); @@ -84,14 +86,16 @@ START_TEST(lmk05318_solver_test4) uint64_t f0_3 = fvco1 / 123; uint64_t f4_7 = 12500000; //3840000; + memset(cfg, 0, sizeof(cfg)); + int res = 0; res = res ? res : lmk05318_port_request(cfg, 0, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 1, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 2, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + //res = res ? res : lmk05318_port_request(cfg, 2, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 3, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 4, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 5, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + //res = res ? res : lmk05318_port_request(cfg, 6, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 7, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); ck_assert_int_eq( res, 0 ); @@ -107,6 +111,9 @@ START_TEST(lmk05318_solver_test4) res = lmk05318_solver(NULL, cfg, 4, true); ck_assert_int_eq( res, 0 ); + + res = lmk05318_solver(NULL, cfg + 4, 4, true); + ck_assert_int_eq( res, 0 ); } Suite * lmk05318_solver_suite(void) From 101ec3fc74c2aee01e8428c1165a5aa685d35853 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 25 Feb 2025 20:36:14 +0300 Subject: [PATCH 014/397] try to use solver in ext_simplesync (needs testing) --- .../device/ext_simplesync/ext_simplesync.c | 42 ++++++- src/lib/hw/lmk05318/lmk05318.c | 106 ++++++++++++++---- src/lib/hw/lmk05318/lmk05318.h | 41 +++++-- 3 files changed, 157 insertions(+), 32 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 87d3485a..9bd95894 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -41,6 +41,10 @@ enum { I2C_ADDR_LMK = 0x65, }; +enum { + FREQ_DELTA_HZ = 2, +}; + int board_ext_simplesync_init(lldev_t dev, unsigned subdev, unsigned gpio_base, @@ -77,7 +81,29 @@ int board_ext_simplesync_init(lldev_t dev, // Wait for power up usleep(50000); +#if 0 res = lmk05318_create(dev, subdev, i2ca, 0, &ob->lmk); +#else + lmk05318_xo_settings_t xo; + xo.doubler_enabled = true; + xo.fdet_bypass = true; + xo.fref = 26000000; + xo.input_divider_flag = 0; + xo.type = XO_CMOS; + + lmk05318_out_config_t cfg[4]; + lmk05318_port_request(cfg, 4, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); + lmk05318_port_request(cfg, 5, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); + lmk05318_port_request(cfg, 6, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); + lmk05318_port_request(cfg, 7, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); + lmk05318_set_port_affinity(cfg, 4, AFF_APLL1); + lmk05318_set_port_affinity(cfg, 5, AFF_APLL1); + lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); + lmk05318_set_port_affinity(cfg, 7, AFF_APLL1); + + res = lmk05318_create_ex(dev, subdev, i2ca, &xo, false, cfg, 4, &ob->lmk); +#endif + if (res) return res; @@ -89,6 +115,8 @@ int board_ext_simplesync_init(lldev_t dev, int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) { + +#if 0 unsigned div = 255; int res = lmk05318_tune_apll2(&ob->lmk, meas_lo, &div); @@ -96,6 +124,18 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) res = (res) ? res : lmk05318_set_out_div(&ob->lmk, p, div); res = (res) ? res : lmk05318_set_out_mux(&ob->lmk, p, false, meas_lo < 1e6 ? OUT_OFF : LVDS); } - +#else + lmk05318_out_config_t cfg[4]; + lmk05318_port_request(cfg, 0, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_port_request(cfg, 1, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_port_request(cfg, 2, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_port_request(cfg, 3, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_set_port_affinity(cfg, 4, AFF_APLL1); + lmk05318_set_port_affinity(cfg, 5, AFF_APLL1); + lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); + lmk05318_set_port_affinity(cfg, 7, AFF_APLL1); + + int res = lmk05318_solver(&ob->lmk, cfg, 4, false); +#endif return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index f26dd865..87c31144 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -84,6 +84,77 @@ int lmk05318_reg_wr_n(lmk05318_state_t* d, const uint32_t* regs, unsigned count) return 0; } +int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, + const lmk05318_xo_settings_t* xo, bool dpll_mode, + lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, + lmk05318_state_t* out) +{ + int res; + uint8_t dummy[4]; + + out->dev = dev; + out->subdev = subdev; + out->lsaddr = lsaddr; + out->vco2_freq = 0; + out->pd1 = 0; + out->pd2 = 0; + out->fref_pll2_div_rp = 3; + out->fref_pll2_div_rs = (((VCO_APLL1 + APLL2_PD_MAX - 1) / APLL2_PD_MAX) + out->fref_pll2_div_rp - 1) / out->fref_pll2_div_rp; + out->xo = *xo; + + res = lmk05318_reg_get_u32(out, 0, &dummy[0]); + if (res) + return res; + + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 DEVID[0/1/2/3] = %02x %02x %02x %02x\n", dummy[3], dummy[2], dummy[1], dummy[0]); + + if ( dummy[3] != 0x10 || dummy[2] != 0x0b || dummy[1] != 0x35 || dummy[0] != 0x42 ) { + return -ENODEV; + } + + // + res = lmk05318_set_xo_fref(out); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d setting XO", res); + return res; + } + + res = lmk05318_tune_apll1(out, dpll_mode); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d tuning APLL1", res); + return res; + } + + res = lmk05318_solver(out, out_ports_cfg, out_ports_len, false); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d solving output frequencies", res); + return res; + } + + // Reset + uint32_t regs[] = { + lmk05318_rom[0] | (1 << RESET_SW_OFF), + lmk05318_rom[0] | (0 << RESET_SW_OFF), + + MAKE_LMK05318_XO_CONFIG(xo->input_divider_flag > 1 ? 1 : 0), + + MAKE_LMK05318_PLL1_CTRL0(0), + MAKE_LMK05318_PLL1_CTRL0(1), + MAKE_LMK05318_PLL1_CTRL0(0), + + }; + res = lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs)); + if (res) + return res; + + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); + return 0; +} + + int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int flags, lmk05318_state_t* out) { int res; @@ -244,9 +315,13 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned return 0; } -int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass) +int lmk05318_set_xo_fref(lmk05318_state_t* d) { + const uint32_t xo_fref = d->xo.fref; + const int xo_type = d->xo.type; + const bool xo_doubler_enabled = d->xo.doubler_enabled; + const bool xo_fdet_bypass = d->xo.fdet_bypass; + if(xo_fref < XO_FREF_MIN || xo_fref > XO_FREF_MAX) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 XO input fref should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", @@ -254,15 +329,15 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, return -EINVAL; } + int xo_type_raw; switch((int)xo_type) { - case XO_TYPE_DC_DIFF_EXT: - case XO_TYPE_AC_DIFF_EXT: - case XO_TYPE_AC_DIFF_INT_100: - case XO_TYPE_HCSL_INT_50: - case XO_TYPE_CMOS: - case XO_TYPE_SE_INT_50: - break; + case XO_DC_DIFF_EXT: xo_type_raw = XO_TYPE_DC_DIFF_EXT; break; + case XO_AC_DIFF_EXT: xo_type_raw = XO_TYPE_AC_DIFF_EXT; break; + case XO_AC_DIFF_INT_100: xo_type_raw = XO_TYPE_AC_DIFF_INT_100; break; + case XO_HCSL_INT_50: xo_type_raw = XO_TYPE_HCSL_INT_50; break; + case XO_CMOS: xo_type_raw = XO_TYPE_CMOS; break; + case XO_SE_INT_50: xo_type_raw = XO_TYPE_SE_INT_50; break; default: USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 XO input type %d is not supported!\n", (int)xo_type); return -EINVAL; @@ -270,26 +345,19 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, uint32_t regs[] = { MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0), - MAKE_LMK05318_XO_CLKCTL2(xo_type) + MAKE_LMK05318_XO_CLKCTL2(xo_type_raw) }; int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); if(res) return res; - d->xo.fref = xo_fref; - d->xo.doubler_enabled = xo_doubler_enabled; - d->xo.type = xo_type; - d->xo.fdet_bypass = xo_fdet_bypass; - return 0; } -int lmk05318_tune_apll1(lmk05318_state_t* d, - uint32_t xo_fref, int xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode) +int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) { - int res = lmk05318_set_xo_fref(d, xo_fref, xo_type, xo_doubler_enabled, xo_fdet_bypass); + int res = lmk05318_set_xo_fref(d); if(res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index a69e6881..be7cf79d 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -9,6 +9,27 @@ #define LMK05318_MAX_OUT_PORTS 8 #define LMK05318_MAX_REAL_PORTS (LMK05318_MAX_OUT_PORTS - 2) +enum xo_input_type +{ + XO_DC_DIFF_EXT = 0, + XO_AC_DIFF_EXT, + XO_AC_DIFF_INT_100, + XO_HCSL_INT_50, + XO_CMOS, + XO_SE_INT_50, +}; +typedef enum xo_input_type xo_input_type_t; + +struct lmk05318_xo_settings +{ + unsigned input_divider_flag; + uint32_t fref; + xo_input_type_t type; + bool doubler_enabled; + bool fdet_bypass; +}; +typedef struct lmk05318_xo_settings lmk05318_xo_settings_t; + struct lmk05318_state { lldev_t dev; unsigned subdev; @@ -28,12 +49,7 @@ struct lmk05318_state { int mux; } outputs[LMK05318_MAX_OUT_PORTS]; - struct { - uint32_t fref; - int type; - bool doubler_enabled; - bool fdet_bypass; - } xo; + lmk05318_xo_settings_t xo; }; enum lmk05318_type { @@ -143,13 +159,14 @@ int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk); int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); -int lmk05318_set_xo_fref(lmk05318_state_t* d, uint32_t xo_fref, int xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass); - -int lmk05318_tune_apll1(lmk05318_state_t* d, - uint32_t xo_fref, int xo_type, - bool xo_doubler_enabled, bool xo_fdet_bypass, bool dpll_mode); +int lmk05318_set_xo_fref(lmk05318_state_t* d); +int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode); int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run); +int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, + const lmk05318_xo_settings_t* xo, bool dpll_mode, + lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, + lmk05318_state_t* out); + #endif From c4dad3feb8066462b0ffd519c321d27fc0ce5007 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 25 Feb 2025 20:41:06 +0300 Subject: [PATCH 015/397] fix typo: --- src/lib/device/ext_simplesync/ext_simplesync.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 9bd95894..e2693c8f 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -130,10 +130,10 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) lmk05318_port_request(cfg, 1, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); lmk05318_port_request(cfg, 2, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); lmk05318_port_request(cfg, 3, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_set_port_affinity(cfg, 4, AFF_APLL1); - lmk05318_set_port_affinity(cfg, 5, AFF_APLL1); - lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); - lmk05318_set_port_affinity(cfg, 7, AFF_APLL1); + lmk05318_set_port_affinity(cfg, 0, AFF_APLL2); + lmk05318_set_port_affinity(cfg, 1, AFF_APLL2); + lmk05318_set_port_affinity(cfg, 2, AFF_APLL2); + lmk05318_set_port_affinity(cfg, 3, AFF_APLL2); int res = lmk05318_solver(&ob->lmk, cfg, 4, false); #endif From ddb01284445415de8b9e1d2e508452570ed0b5fc Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 21 Mar 2025 22:37:54 +0300 Subject: [PATCH 016/397] Initial commit --- src/lib/hw/CMakeLists.txt | 4 +- src/lib/hw/lmx2820/lmx2820.c | 90 ++ src/lib/hw/lmx2820/lmx2820.h | 8 + src/lib/hw/lmx2820/lmx2820.yaml | 1713 +++++++++++++++++++++++++++++++ 4 files changed, 1813 insertions(+), 2 deletions(-) create mode 100644 src/lib/hw/lmx2820/lmx2820.c create mode 100644 src/lib/hw/lmx2820/lmx2820.h create mode 100644 src/lib/hw/lmx2820/lmx2820.yaml diff --git a/src/lib/hw/CMakeLists.txt b/src/lib/hw/CMakeLists.txt index f8c7d417..4b9ca0a7 100644 --- a/src/lib/hw/CMakeLists.txt +++ b/src/lib/hw/CMakeLists.txt @@ -1,9 +1,9 @@ # Copyright (c) 2023-2024 Wavelet Lab # SPDX-License-Identifier: MIT -set(HW_FILES si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 lmk04832 tca6424a adf4002b lp875484 afe79xx) +set(HW_FILES si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 lmk04832 tca6424a adf4002b lp875484 afe79xx lmx2820) # YAML registers generators -set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 lmk04832 xra1405 tca6424a adf4002b lp875484) +set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 lmk04832 xra1405 tca6424a adf4002b lp875484 lmx2820) foreach(I ${HW_FILES}) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/${I} HW_DIR_FILES) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c new file mode 100644 index 00000000..5f19debf --- /dev/null +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -0,0 +1,90 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include + +#include "lmx2820.h" +#include "def_lmx2820.h" +#include + +enum { + OUT_FREQ_MIN = 45000000ul, + OUT_FREQ_MAX = 22600000000ul, + + VCO_MIN = 5650000000ul, + VCO_MAX = 11300000000ul, + + PLL_R_PRE_DIV_MIN = 1, + PLL_R_PRE_DIV_MAX = 4095, + + MULT_MIN = 3, + MULT_MAX = 7, + + PLL_R_DIV_MIN = 1, + PLL_R_DIV_MAX = 255, + + OUT_DIV_LOG2_MIN = 1, + OUT_DIV_LOG2_MAX = 7, +}; + +enum { + VCO_CORE1 = 0, + VCO_CORE2, + VCO_CORE3, + VCO_CORE4, + VCO_CORE5, + VCO_CORE6, + VCO_CORE7, +}; + +enum { + MASH_ORDER0 = 0, + MASH_ORDER1, + MASH_ORDER2, + MASH_ORDER3, +}; + +struct vco_core { + uint64_t fmin, fmax; + unsigned ndiv_min[MASH_ORDER3 + 1]; +}; +typedef struct vco_core vco_core_t; + +static vco_core_t vco_cores[VCO_CORE7 + 1] = +{ + {VCO_MIN, 6350000000ul, {12,18,19,24}}, + { 6350000000ul, 7300000000ul, {14,21,22,26}}, + { 7300000000ul, 8100000000ul, {16,23,24,26}}, + { 8100000000ul, 9000000000ul, {16,26,27,29}}, + { 9000000000ul, 9800000000ul, {18,28,29,31}}, + { 9800000000ul, 10600000000ul, {18,30,31,33}}, + {10600000000ul, (VCO_MAX + 1), {20,33,34,36}} +}; + +static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, unsigned* vco_core, unsigned* ndiv_min) +{ + if(!vco_core || !ndiv_min || + vco_freq < VCO_MIN || vco_freq > OUT_FREQ_MAX || + mash_order > MASH_ORDER3) + { + return -EINVAL; + } + + for(unsigned i = 0; i <= VCO_CORE7; ++i) + { + const vco_core_t r = vco_cores[i]; + if(vco_freq >= r.fmin && vco_freq < r.fmax) + { + *vco_core = i; + *ndiv_min = r.ndiv_min[mash_order]; + return 0; + } + } + + assert(1); // should never reach this line + return -EINVAL; +} + + diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h new file mode 100644 index 00000000..b6d2ecc9 --- /dev/null +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -0,0 +1,8 @@ +#ifndef LMX2820_H +#define LMX2820_H + +#include + + + +#endif // LMX2820_H diff --git a/src/lib/hw/lmx2820/lmx2820.yaml b/src/lib/hw/lmx2820/lmx2820.yaml new file mode 100644 index 00000000..6be758c4 --- /dev/null +++ b/src/lib/hw/lmx2820/lmx2820.yaml @@ -0,0 +1,1713 @@ +name: LMX2820 +revision: 0.0.1 +addr_width: 16 +data_width: 16 + +pages: +- name: Main + regs: + - addr: 0x0 + name: R0 + fields: + - bits: 0 + name: POWERDOWN + mode: RW + dflt: 0x0 + desc: Powers down the device. + opts: + 0b0: Normal operation + 0b1: Power down + - bits: 1 + name: RESET + mode: RW + dflt: 0x0 + desc: Resets all registers to silicon default values. This bit is self-clearing. + opts: + 0b0: Normal operation + 0b1: Reset + - bits: '3:2' + name: R0_RESERVED_3 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 4 + name: FCAL_EN + mode: RW + dflt: 0x1 + desc: Enables and activates VCO calibration. Writing register R0 with this bit set to a 1 enables and triggers VCO calibration. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: 5 + name: R0_RESERVED_2 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - bits: 6 + name: DBLR_CAL_EN + mode: RW + dflt: 0x1 + desc: Enables VCO doubler calibration. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '8:7' + name: FCAL_LPFD_ADJ + mode: RW + dflt: 0x0 + desc: "Set this field in accordance to the phase detector frequency for optimal VCO calibration." + opts: + 0x0: fPD >= 10 MHz + 0x1: 10 MHz > fPD >= 5 MHz + 0x2: 5 MHz > fPD >= 2.5 MHz + 0x3: fPD < 2.5 MHz + - bits: '10:9' + name: FCAL_HPFD_ADJ + mode: RW + dflt: 0x0 + desc: "Set this field in accordance to the phase detector frequency for optimal VCO calibration." + opts: + 0x0: fPD <= 100 MHz + 0x1: 100 MHz < fPD <= 150 MHz + 0x2: 150 MHz < fPD <= 200 MHz + 0x3: fPD > 200 MHz + - bits: '12:11' + name: R0_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 13 + name: INSTCAL_SKIP_ACAL + mode: RW + dflt: 0x0 + desc: Disable this bit when doing instant calibration. When not using instant calibration, it is recommended to enable it for faster VCO Calibration. + - bits: '15:14' + name: R0_RESERVED_0 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - addr: 0x1 + name: R1 + fields: + - bits: 0 + name: INSTCAL_EN + mode: RW + dflt: 0x0 + desc: Enables instant calibration. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: 1 + name: INSTCAL_DBLR_EN + mode: RW + dflt: 0x0 + desc: Sets this bit to 1 if VCO doubler is engaged. + opts: + 0b0: Normal operation + 0b1: VCO doubler is engaged + - bits: '4:2' + name: R1_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 5 + name: LD_VTUNE_EN + mode: RW + dflt: 0x1 + desc: Selects lock detect type. VCOCal lock detect asserts a HIGH output after the VCO has finished calibration and the LD_DLY timeout counter is finished. VCOCal and Vtune lock detect asserts a HIGH output when VCOCal lock detect would assert a signal and the tuning voltage to the VCO is within acceptable limits. + opts: + 0b0: VCOCal lock detect + 0b1: VCOCal and Vtune lock detect + - bits: '14:6' + name: R1_RESERVED_0 + mode: RW + dflt: 0x15E + desc: Program 0x15E to this field. + - bits: 15 + name: PHASE_SYNC_EN + mode: RW + dflt: 0x0 + desc: Enables phase synchronization. A Low-High-Low pulse is required at the PSYNC pin to trigger synchronization. Enable SYSREF requires PHASE_SYNC_EN = 1. + opts: + 0b0: Normal operation + 0b1: Phase synchronization enabled + - addr: 0x2 + name: R2 + fields: + - bits: 0 + name: QUICK_RECAL_EN + mode: RW + dflt: 0x0 + desc: Starts VCO calibration with the current VCO_SEL, VCO_CAPCTRL and VCO_DACISET values. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '11:1' + name: INSTCAL_DLY + mode: RW + dflt: 0x1F4 + desc: "Sets the wait time for instant calibration. INSTCAL_DLY = T x fOSCIN / (2CAL_CLK_DIV). T = 2.5 x CBIASVCO / 4.7 \xB5F. CBIASVCO is the bypass capacitor at pin 3." + - bits: '14:12' + name: CAL_CLK_DIV + mode: RW + dflt: 0x3 + desc: "Divides down the state machine clock (fsm) during VCO calibration. Maximum fsm is 200 MHz. fsm = fOSCIN / (2CAL_CLK_DIV)." + opts: + 0x0: fOSCIN <= 200 MHz + 0x1: fOSCIN <= 400 MHz + 0x2: fOSCIN <= 800 MHz + 0x3: All other fOSCIN values + - bits: 15 + name: R2_RESERVED_0 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - addr: 0x3 + name: R3 + fields: + - bits: '15:0' + name: R3_RESERVED_0 + mode: RW + dflt: 0x41 + desc: Program 0x41 to this field. + - addr: 0x4 + name: R4 + fields: + - bits: '15:0' + name: R4_RESERVED_0 + mode: RW + dflt: 0x4204 + desc: Program 0x4204 to this field. + - addr: 0x5 + name: R5 + fields: + - bits: '15:0' + name: R5_RESERVED_0 + mode: RW + dflt: 0x3832 + desc: Program 0x32 to this field. + - addr: 0x6 + name: R6 + fields: + - bits: '7:0' + name: R6_RESERVED_0 + mode: RW + dflt: 0x43 + desc: Program 0x43 to this field. + - bits: '15:8' + name: ACAL_CMP_DLY + mode: RW + dflt: 0xA + desc: VCO amplitude calibration delay. Lowering this value can speed up calibration time. If too low, phase noise may not be optimal due to insufficient time to reach final calibrated amplitude. Delay time = ACAL_CMP_DLY x 2 x state machine clock cycle. + - addr: 0x7 + name: R7 + fields: + - bits: '15:0' + name: R7_RESERVED_0 + mode: RW + dflt: 0xC8 + desc: Program 0x0 to this field. + - addr: 0x8 + name: R8 + fields: + - bits: '15:0' + name: R8_RESERVED_0 + mode: RW + dflt: 0xC802 + desc: Program 0xC802 to this field. + - addr: 0x9 + name: R9 + fields: + - bits: '15:0' + name: R9_RESERVED_0 + mode: RW + dflt: 0x5 + desc: Program 0x5 to this field. + - addr: 0xA + name: R10 + fields: + - bits: '6:0' + name: R10_RESERVED_2 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 7 + name: VCO_CAPCTRL_FORCE + mode: RW + dflt: 0x0 + desc: Forces the VCO to use the sub-band specified by VCO_CAPCTRL. Useful for full-assisted VCO calibration and debugging purposes. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '10:8' + name: R10_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 11 + name: VCO_DACISET_FORCE + mode: RW + dflt: 0x0 + desc: Forces the VCO to use the current setting specified by VCO_DACISET. Useful for full-assisted VCO calibration and debugging purposes. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: 12 + name: PFD_DLY_MANUAL + mode: RW + dflt: 0x0 + desc: Enables manual PFD_DLY adjustment. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '15:13' + name: R10_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0xB + name: R11 + fields: + - bits: '3:0' + name: R11_RESERVED_1 + mode: RW + dflt: 0x3 + desc: Program 0x2 to this field. + - bits: 4 + name: OSC_2X + mode: RW + dflt: 0x0 + desc: Enables reference input doubler. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '15:5' + name: R11_RESERVED_0 + mode: RW + dflt: 0x30 + desc: Program 0x30 to this field. + - addr: 0xC + name: R12 + fields: + - bits: '9:0' + name: R12_RESERVED_1 + mode: RW + dflt: 0x8 + desc: Program 0x8 to this field. + - bits: '12:10' + name: MULT + mode: RW + dflt: 0x1 + desc: Sets reference path frequency multiplier value. + opts: + 0x1: Bypassed + 0x3: x3 + 0x4: x4 + 0x5: x5 + 0x6: x6 + 0x7: x7 + - bits: '15:13' + name: R12_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0xD + name: R13 + fields: + - bits: '4:0' + name: R13_RESERVED_1 + mode: RW + dflt: 0x18 + desc: Program 0x18 to this field. + - bits: '12:5' + name: PLL_R + mode: RW + dflt: 0x1 + desc: Sets reference path Post-R divider value. + - bits: '15:13' + name: R13_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0xE + name: R14 + fields: + - bits: '11:0' + name: PLL_R_PRE + mode: RW + dflt: 0x1 + desc: Sets reference path Pre-R divider value. + - bits: '15:12' + name: R14_RESERVED_0 + mode: RW + dflt: 0x3 + desc: Program 0x3 to this field. + - addr: 0xF + name: R15 + fields: + - bits: '8:0' + name: R15_RESERVED_1 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - bits: '10:9' + name: PFD_SINGLE + mode: RW + dflt: 0x0 + desc: Uses single PFD when PFDIN input is enabled. The actual charge pump current is equal to half the current setting made in CPG. + opts: + 0x0: Normal operation + 0x1: Not used + 0x2: Not used + 0x3: Single PFD + - bits: 11 + name: PFD_POL + mode: RW + dflt: 0x0 + desc: Sets the polarity of phase detector. Internal VCO operation requires negative Vtune with non-inverting loop filter. + opts: + 0b0: Negative Vtune + 0b1: Positive Vtune + - bits: '15:12' + name: R15_RESERVED_0 + mode: RW + dflt: 0x2 + desc: Program 0x2 to this field. + - addr: 0x10 + name: R16 + fields: + - bits: 0 + name: R16_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: '4:1' + name: CPG + mode: RW + dflt: 0xE + desc: Sets charge pump gain value. +# opts: +# 0x0: Tri-state +# 0x1: 1.4 mA +# 0x4: 5.6 mA +# 0x5: 7 mA +# 0x6: 11.2 mA +# 0x7: 12.6 mA +# 0x8: 2.8 mA +# 0x9: 4.2 mA +# 0x12: 8.4 mA +# 0x13: 9.8 mA +# 0x14: 14 mA +# 0x15: 15.4 mA + - bits: '15:5' + name: R16_RESERVED_0 + mode: RW + dflt: 0x138 + desc: Program 0xB8 to this field. + - addr: 0x11 + name: R17 + fields: + - bits: '15:7' + name: R17_RESERVED_1 + mode: RW + dflt: 0x28 + desc: Program 0x2B to this field. + - bits: 6 + name: LD_TYPE + mode: RW + dflt: 0x1 + desc: Defines lock detect monitor type. One-Shot detects lock only after the VCO calibrates and the LD_DLY timeout counter is finished. Continuous lock detect checks for lock all the time, including when the input reference is removed. + opts: + 0b0: One-Shot + 0b1: Continuous + - bits: '5:0' + name: R17_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x12 + name: R18 + fields: + - bits: '15:0' + name: LD_DLY + mode: RW + dflt: 0x3E8 + desc: Lock detect assertion delay. This is the delay that is added after the VCO calibration is completed before indicating lock. This delay is only applied if LD_VTUNE_EN = 1. Delay time = LD_DLY / fPD. + - addr: 0x13 + name: R19 + fields: + - bits: '2:0' + name: R19_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: '4:3' + name: TEMPSENSE_EN + mode: RW + dflt: 0x0 + desc: Enables temperature sensor. + opts: + 0x0: Disabled + 0x3: Enabled + - bits: '15:5' + name: R19_RESERVED_0 + mode: RW + dflt: 0x109 + desc: Program 0x109 to this field. + - addr: 0x14 + name: R20 + fields: + - bits: '8:0' + name: VCO_DACISET + mode: RW + dflt: 0x12C + desc: User specified start VCO current setting for calibration. Unless QUICK_RECAL_EN = 1, VCO calibration will always start with the VCO current setting that is specified in this field. + - bits: '15:9' + name: R20_RESERVED_0 + mode: RW + dflt: 0x13 + desc: Program 0x13 to this field. + - addr: 0x15 + name: R21 + fields: + - bits: '15:0' + name: R21_RESERVED_0 + mode: RW + dflt: 0x1C64 + desc: Program 0x1C64 to this field. + - addr: 0x16 + name: R22 + fields: + - bits: '7:0' + name: VCO_CAPCTRL + mode: RW + dflt: 0xBF + desc: User specified start VCO sub-band for calibration. Valid values are 191 to 0, where the higher number represents a lower frequency band. Unless QUICK_RECAL_EN = 1, VCO calibration will always start with the VCO sub-band that is specified in this field. + - bits: '12:8' + name: R22_RESERVED_0 + mode: RW + dflt: 0x2 + desc: Program 0x2 to this field. + - bits: '15:13' + name: VCO_SEL + mode: RW + dflt: 0x7 + desc: User specified start VCO core for calibration. Unless QUICK_RECAL_EN = 1, VCO calibration will always start with the VCO core that is specified in this field. + opts: + 0x1: VCO1 + 0x2: VCO2 + 0x3: VCO3 + 0x4: VCO4 + 0x5: VCO5 + 0x6: VCO6 + 0x7: VCO7 + - addr: 0x17 + name: R23 + fields: + - bits: 0 + name: VCO_SEL_FORCE + mode: RW + dflt: 0x0 + desc: Forces the VCO to use the core specified by VCO_SEL. Useful for full-assisted VCO calibration and debugging purposes. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '15:1' + name: R23_RESERVED_0 + mode: RW + dflt: 0x881 + desc: Program 0x881 to this field. + - addr: 0x18 + name: R24 + fields: + - bits: '15:0' + name: R24_RESERVED_0 + mode: RW + dflt: 0xE34 + desc: Program 0xE34 to this field. + - addr: 0x19 + name: R25 + fields: + - bits: '15:0' + name: R25_RESERVED_0 + mode: RW + dflt: 0x624 + desc: Program 0x624 to this field. + - addr: 0x1A + name: R26 + fields: + - bits: '15:0' + name: R26_RESERVED_0 + mode: RW + dflt: 0xDB0 + desc: Program 0xDB0 to this field. + - addr: 0x1B + name: R27 + fields: + - bits: '15:0' + name: R27_RESERVED_0 + mode: RW + dflt: 0x8001 + desc: Program 0x8001 to this field. + - addr: 0x1C + name: R28 + fields: + - bits: '15:0' + name: R28_RESERVED_0 + mode: RW + dflt: 0x639 + desc: Program 0x639 to this field. + - addr: 0x1D + name: R29 + fields: + - bits: '15:0' + name: R29_RESERVED_0 + mode: RW + dflt: 0x318C + desc: Program 0x318C to this field. + - addr: 0x1E + name: R30 + fields: + - bits: '15:0' + name: R30_RESERVED_0 + mode: RW + dflt: 0xB18C + desc: Program 0xB18C to this field. + - addr: 0x1F + name: R31 + fields: + - bits: '15:0' + name: R31_RESERVED_0 + mode: RW + dflt: 0x401 + desc: Program 0x401 to this field. + - addr: 0x20 + name: R32 + fields: + - bits: '5:0' + name: R32_RESERVED_1 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - bits: '8:6' + name: CHDIVA + mode: RW + dflt: 0x0 + desc: Sets divider value for RFOUTA. + opts: + 0x0: 0x0 = Divide by 2 + 0x1: 0x1 = Divide by 4 + 0x2: 0x2 = Divide by 8 + 0x3: 0x3 = Divide by 16 + 0x4: 0x4 = Divide by 32 + 0x5: 0x5 = Divide by 64 + 0x6: 0x6 = Divide by 128 + - bits: '11:9' + name: CHDIVB + mode: RW + dflt: 0x0 + desc: Sets divider value for RFOUTB. + opts: + 0x0: 0x0 = Divide by 2 + 0x1: 0x1 = Divide by 4 + 0x2: 0x2 = Divide by 8 + 0x3: 0x3 = Divide by 16 + 0x4: 0x4 = Divide by 32 + 0x5: 0x5 = Divide by 64 + 0x6: 0x6 = Divide by 128 + - bits: '15:12' + name: R32_RESERVED_0 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - addr: 0x21 + name: R33 + fields: + - bits: '15:0' + name: R33_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x22 + name: R34 + fields: + - bits: 0 + name: EXTVCO_EN + mode: RW + dflt: 0x0 + desc: Enables external VCO mode. Set this bit to 1 will enables RFIN input path but disables internal VCO, the synthesizer will try to lock to an external source appear at RFIN pin. In loop back mode, this bit has to be set to 0, RFIN input path will be enabled by the LOOPBACK_EN bit. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '3:1' + name: R34_RESERVED_2 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 4 + name: EXTVCO_DIV + mode: RW + dflt: 0x1 + desc: Sets external VCO input divider value. + opts: + 0b0: Divide by 2 + 0b1: Bypassed + - bits: '10:5' + name: R34_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 11 + name: LOOPBACK_EN + mode: RW + dflt: 0x0 + desc: Enables loop back mode. In this mode, both RFIN input path and internal VCO are active, the synthesizer will try to lock to the internal VCO. EXTVCO_EN must be set to 0 in this mode. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '15:12' + name: R34_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x23 + name: R35 + fields: + - bits: '5:0' + name: R35_RESERVED_2 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 6 + name: MASHSEED_EN + mode: RW + dflt: 0x0 + desc: Enables MASHSEED for phase adjustment. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '8:7' + name: MASH_ORDER + mode: RW + dflt: 0x2 + desc: Sets the MASH order. + opts: + 0x0: Integer mode + 0x1: First order + 0x2: Second order + 0x3: Third order + - bits: '11:9' + name: R35_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 12 + name: MASH_RESET_N + mode: RW + dflt: 0x1 + desc: Resets the MASH (active LOW). + opts: + 0b0: Reset + 0b1: Normal operation + - bits: '15:13' + name: R35_RESERVED_0 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - addr: 0x24 + name: R36 + fields: + - bits: '14:0' + name: PLL_N + mode: RW + dflt: 0x38 + desc: Sets N divider value (integer portion). + - bits: 15 + name: R36_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x25 + name: R37 + fields: + - bits: '8:0' + name: R37_RESERVED_1 + mode: RW + dflt: 0x100 + desc: Program 0x100 to this field. + - bits: '14:9' + name: PFD_DLY + mode: RW + dflt: 0x2 + desc: Sets N divider delay time in phase detector. Effective only when PFD_DLY_MANUAL = 1. 0x0 = Reserved All other values must be set in accordance to the N divider value + - bits: 15 + name: R37_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x26 + name: R38 + fields: + - bits: '15:0' + name: PLL_DEN_U + mode: RW + dflt: 0x0 + desc: Sets the upper 16 bits of fractional denominator (DEN). + - addr: 0x27 + name: R39 + fields: + - bits: '15:0' + name: PLL_DEN_L + mode: RW + dflt: 0x3E8 + desc: Sets the lower 16 bits of fractional denominator (DEN). + - addr: 0x28 + name: R40 + fields: + - bits: '15:0' + name: MASH_SEED_U + mode: RW + dflt: 0x0 + desc: Sets the upper 16 bits of MASH_SEED. + - addr: 0x29 + name: R41 + fields: + - bits: '15:0' + name: MASH_SEED_L + mode: RW + dflt: 0x0 + desc: Sets the lower 16 bits of MASH SEED. + - addr: 0x2A + name: R42 + fields: + - bits: '15:0' + name: PLL_NUM_U + mode: RW + dflt: 0x0 + desc: Sets the upper 16 bits of fractional numerator (NUM). + - addr: 0x2B + name: R43 + fields: + - bits: '15:0' + name: PLL_NUM_L + mode: RW + dflt: 0x0 + desc: Sets the lower 16 bits of fractional numerator (NUM). + - addr: 0x2C + name: R44 + fields: + - bits: '15:0' + name: INSTCAL_PLL_NUM_U + mode: RW + dflt: 0x0 + desc: Sets the upper 16 bits of INSTCAL_PLL_NUM. INSTCAL_PLL_NUM = 232 x (PLL_NUM / PLL_DEN). + - addr: 0x2D + name: R45 + fields: + - bits: '15:0' + name: INSTCAL_PLL_NUM_L + mode: RW + dflt: 0x0 + desc: Sets the lower 16 bits of INSTCAL_PLL_NUM. INSTCAL_PLL_NUM = 232 x (PLL_NUM / PLL_DEN). + - addr: 0x2E + name: R46 + fields: + - bits: '15:0' + name: R46_RESERVED_0 + mode: RW + dflt: 0x300 + desc: Program 0x300 to this field. + - addr: 0x2F + name: R47 + fields: + - bits: '15:0' + name: R47_RESERVED_0 + mode: RW + dflt: 0x300 + desc: Program 0x300 to this field. + - addr: 0x30 + name: R48 + fields: + - bits: '15:0' + name: R48_RESERVED_0 + mode: RW + dflt: 0x4180 + desc: Program 0x4180 to this field. + - addr: 0x31 + name: R49 + fields: + - bits: '15:0' + name: R49_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x32 + name: R50 + fields: + - bits: '15:0' + name: R50_RESERVED_0 + mode: RW + dflt: 0x80 + desc: Program 0x80 to this field. + - addr: 0x33 + name: R51 + fields: + - bits: '15:0' + name: R51_RESERVED_0 + mode: RW + dflt: 0x203F + desc: Program 0x203F to this field. + - addr: 0x34 + name: R52 + fields: + - bits: '15:0' + name: R52_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x35 + name: R53 + fields: + - bits: '15:0' + name: R53_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x36 + name: R54 + fields: + - bits: '15:0' + name: R54_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x37 + name: R55 + fields: + - bits: '15:0' + name: R55_RESERVED_0 + mode: RW + dflt: 0x2 + desc: Program 0x2 to this field. + - addr: 0x38 + name: R56 + fields: + - bits: '5:0' + name: EXTPFD_DIV + mode: RW + dflt: 0x1 + desc: Sets external PFD input divider value. Set this field to 0 is not allowed. A value of 1 means bypassed. + - bits: '15:6' + name: R56_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x39 + name: R57 + fields: + - bits: 0 + name: PFD_SEL + mode: RW + dflt: 0x1 + desc: Enables PFDIN input. When using PFDIN input, the charge pump has to be set to single PFD by setting PFD_SINGLE = 0x3. + opts: + 0b0: Enabled + 0b1: Disabled + - bits: '15:1' + name: R57_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x3A + name: R58 + fields: + - bits: '15:0' + name: R58_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x3B + name: R59 + fields: + - bits: '15:0' + name: R59_RESERVED_0 + mode: RW + dflt: 0x1388 + desc: Program 0x1388 to this field. + - addr: 0x3C + name: R60 + fields: + - bits: '15:0' + name: R60_RESERVED_0 + mode: RW + dflt: 0x1F4 + desc: Program 0x1F4 to this field. + - addr: 0x3D + name: R61 + fields: + - bits: '15:0' + name: R61_RESERVED_0 + mode: RW + dflt: 0x3E8 + desc: Program 0x3E8 to this field. + - addr: 0x3E + name: R62 + fields: + - bits: '15:0' + name: MASH_RST_COUNT_U + mode: RW + dflt: 0x0 + desc: ' Sets the upper 16 bits of MASH reset delay. This is the delay that is necessary after the MASH engine is reset during phase synchronization when PLL_NUM is not equal to zero. The delay time must be set to greater than the lock time of the PLL. Delay time = MASH_RST_COUNT x (2CAL_CLK_DIV) / fOSCIN. This field can be set to 0 when PLL_NUM = 0.' + - addr: 0x3F + name: R63 + fields: + - bits: '15:0' + name: MASH_RST_COUNT_L + mode: RW + dflt: 0xC350 + desc: Sets the lower 16 bits of MASH reset delay. + - addr: 0x40 + name: R64 + fields: + - bits: 0 + name: R64_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 1 + name: SYSREF_REPEAT + mode: RW + dflt: 0x0 + desc: Defines SYSREF mode. In master mode, SYSREF pulses are generated internally. In repeater mode, SYSREF pulses are generated in response to the SRREQ pins. + opts: + 0b0: Master mode + 0b1: Repeater mode + - bits: 2 + name: SYSREF_EN + mode: RW + dflt: 0x0 + desc: Enables SYSREF mode. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: 3 + name: SYSREF_PULSE + mode: RW + dflt: 0x0 + desc: Defines SYSREF master mode. In continuous mode, SYSREF pulses are generated continuously. Pulsed mode allows multiple pulses (as determined by SYSREF_PULSE_CNT) to be sent out whenever the SRREQ pins go HIGH. + opts: + 0b0: Continuous mode + 0b1: Pulsed mode + - bits: 4 + name: SYSREF_REPEAT_NS + mode: RW + dflt: 0x0 + desc: Enables asynchronous SYSREF repeater mode. In this mode, the SYSREF signal coming from the SRREQ pin will be passed through to the SROUT pin without reclocking. + opts: + 0b0: If SYSREF_REPEAT = 1 + 0b1: Enabled + - bits: '7:5' + name: SYSREF_DIV_PRE + mode: RW + dflt: 0x4 + desc: This divider is used to get the frequency input to SYSREF_DIV within acceptable limits. + opts: + 0x1: Divide by 2 + 0x2: Divide by 4 + 0x4: Divide by 8 + - bits: '9:8' + name: SYSREF_INP_FMT + mode: RW + dflt: 0x0 + desc: "Sets SRREQ pin input format." + opts: + 0x0: CMOS input at SRREQ_P pin, 1.8-V to 3.3-V logic + 0x1: AC-couple CMOS input at SRREQ_P pin + 0x2: AC-coupled differential LVDS input, requires external 100-Ohm differential termination + 0x3: DC-coupled differential LVDS input, requires external 100-Ohm differential termination + - bits: '15:10' + name: R64_RESERVED_0 + mode: RW + dflt: 0x10 + desc: Program 0x10 to this field. + - addr: 0x41 + name: R65 + fields: + - bits: '10:0' + name: SYSREF_DIV + mode: RW + dflt: 0x1 + desc: This divider further divides the output frequency for the SYSREF. + - bits: '15:11' + name: R65_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x42 + name: R66 + fields: + - bits: '5:0' + name: JESD_DAC1_CTRL + mode: RW + dflt: 0x3F + desc: Programmable delay adjustment for SYSREF mode. + - bits: '11:6' + name: JESD_DAC2_CTRL + mode: RW + dflt: 0x0 + desc: Programmable delay adjustment for SYSREF mode. + - bits: '15:12' + name: R66_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x43 + name: R67 + fields: + - bits: '5:0' + name: JESD_DAC3_CTRL + mode: RW + dflt: 0x0 + desc: Programmable delay adjustment for SYSREF mode. + - bits: '11:6' + name: JESD_DAC4_CTRL + mode: RW + dflt: 0x0 + desc: Programmable delay adjustment for SYSREF mode. + - bits: '15:12' + name: SYSREF_PULSE_CNT + mode: RW + dflt: 0x0 + desc: Defines how many pulses are sent in SYSREF pulsed mode. + - addr: 0x44 + name: R68 + fields: + - bits: 0 + name: PSYNC_INP_FMT + mode: RW + dflt: 0x0 + desc: "Sets PSYNC pin input format." + opts: + 0b0: CMOS input, 1.8-V to 3.3-V logic + 0b1: AC-coupled differential LVDS input, requires external 100-Ohm differential termination + - bits: '4:1' + name: R68_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 5 + name: INPIN_IGNORE + mode: RW + dflt: 0x0 + desc: Disables PSYNC pin. Keep this bit equals 1 unless phase sync is required. + opts: + 0b0: Enables + 0b1: Disables pin + - bits: '15:6' + name: R68_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x45 + name: R69 + fields: + - bits: '3:0' + name: R69_RESERVED_1 + mode: RW + dflt: 0x1 + desc: Program 0x1 to this field. + - bits: 4 + name: SROUT_PD + mode: RW + dflt: 0x1 + desc: Powerdowns SYSREF output buffer. + opts: + 0b0: Normal operation + 0b1: Power down + - bits: '15:5' + name: R69_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x46 + name: R70 + fields: + - bits: '3:0' + name: R70_RESERVED_1 + mode: RW + dflt: 0xE + desc: Program 0xE to this field. + - bits: 4 + name: DBLBUF_PLL_EN + mode: RW + dflt: 0x1 + desc: Enables double buffering for PLL_N, PLL_NUM, PLL_DEN, MULT, PLL_R, PLL_R_PRE, MASH_ORDER and PFD_DLY. Changes of these registers will only be effective after R0 is programmed. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: 5 + name: DBLBUF_CHDIV_EN + mode: RW + dflt: 0x0 + desc: Enables double buffering for CHDIVA and CHDIVB. Changes of these registers will only be effective after R0 is programmed. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: 6 + name: DBLBUF_OUTBUF_EN + mode: RW + dflt: 0x0 + desc: Enables double buffering for OUTA_PD and OUTB_PD. Changes of these registers will only be effective after R0 is programmed. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: 7 + name: DBLBUF_OUTMUX_EN + mode: RW + dflt: 0x0 + desc: Enables double buffering for OUTA_MUX and OUTB_MUX. Changes of these registers will only be effective after R0 is programmed. + opts: + 0b0: Disabled + 0b1: Enabled + - bits: '15:8' + name: R70_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x47 + name: R71 + fields: + - bits: '15:0' + name: R71_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x48 + name: R72 + fields: + - bits: '15:0' + name: R72_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x49 + name: R73 + fields: + - bits: '15:0' + name: R73_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x4A + name: R74 + fields: + - bits: '1:0' + name: R74_RESERVED_1 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - bits: '4:2' + name: RB_VCO_SEL + mode: R + dflt: 0x0 + desc: Reads back the actual VCO that the VCO calibration has selected. + opts: + 0x0: Invalid + 0x1: VCO1 + 0x2: VCO2 + 0x3: VCO3 + 0x4: VCO4 + 0x5: VCO5 + 0x6: VCO6 + 0x7: VCO7 + - bits: '12:5' + name: RB_VCO_CAPCTRL + mode: R + dflt: 0x0 + desc: Reads back the actual CAPCTRL value that the VCO calibration has chosen. + - bits: 13 + name: R74_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - bits: '15:14' + name: RB_LD + mode: R + dflt: 0x0 + desc: Reads back lock detect status. + opts: + 0x0: Unlocked + 0x1: Unlocked + 0x2: Locked + 0x3: Invalid + - addr: 0x4B + name: R75 + fields: + - bits: '8:0' + name: RB_VCO_DACISET + mode: R + dflt: 0x0 + desc: Reads back the actual DACISET value that the VCO calibration has chosen. + - bits: '15:9' + name: R75_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x4C + name: R76 + fields: + - bits: '10:0' + name: RB_TEMP_SENS + mode: R + dflt: 0x0 + desc: "Reads back temperature sensor code. Temperature in \xB0C = 0.85 x code - 415. Resolution is 0.6\xB0C per code. Measurement accuracy is \xB15 degrees." + - bits: '15:11' + name: R76_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x4D + name: R77 + fields: + - bits: '7:0' + name: R77_RESERVED_1 + mode: RW + dflt: 0xCC + desc: Program 0x8 to this field. + - bits: 8 + name: PINMUTE_POL + mode: RW + dflt: 0x0 + desc: Sets the polarity of mute control for MUTE pin. + opts: + 0b0: Active HIGH + 0b1: Active LOW + - bits: '15:9' + name: R77_RESERVED_0 + mode: RW + dflt: 0x2B + desc: Program 0x3 to this field. + - addr: 0x4E + name: R78 + fields: + - bits: '1:0' + name: OUTA_MUX + mode: RW + dflt: 0x1 + desc: Selects the input source to RFOUTA. + opts: + 0x0: Channel divider + 0x1: VCO + 0x2: VCO doubler + - bits: '3:2' + name: R78_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 4 + name: OUTA_PD + mode: RW + dflt: 0x0 + desc: Power downs RFOUTA. + opts: + 0b0: Normal operation + 0b1: Power down + - bits: '15:5' + name: R78_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x4F + name: R79 + fields: + - bits: 0 + name: R79_RESERVED_2 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: '3:1' + name: OUTA_PWR + mode: RW + dflt: 0x7 + desc: Adjusts RFOUTA output power. Higher numbers give more output power. + - bits: '5:4' + name: OUTB_MUX + mode: RW + dflt: 0x1 + desc: Selects the input source to RFOUTB. + opts: + 0x0: Channel divider + 0x1: VCO + 0x2: VCO doubler + - bits: '7:6' + name: R79_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: 8 + name: OUTB_PD + mode: RW + dflt: 0x1 + desc: Power downs RFOUTB. + opts: + 0b0: Normal operation + 0b1: Power down + - bits: '15:9' + name: R79_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x50 + name: R80 + fields: + - bits: '5:0' + name: R80_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - bits: '8:6' + name: OUTB_PWR + mode: RW + dflt: 0x7 + desc: Adjusts RFOUTB output power. Higher numbers give more output power. + - bits: '15:9' + name: R80_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x51 + name: R81 + fields: + - bits: '15:0' + name: R81_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x52 + name: R82 + fields: + - bits: '15:0' + name: R82_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x53 + name: R83 + fields: + - bits: '15:0' + name: R83_RESERVED_0 + mode: RW + dflt: 0xF00 + desc: Program 0xF00 to this field. + - addr: 0x54 + name: R84 + fields: + - bits: '15:0' + name: R84_RESERVED_0 + mode: RW + dflt: 0x40 + desc: Program 0x40 to this field. + - addr: 0x55 + name: R85 + fields: + - bits: '15:0' + name: R85_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x56 + name: R86 + fields: + - bits: '15:0' + name: R86_RESERVED_0 + mode: RW + dflt: 0x40 + desc: Program 0x40 to this field. + - addr: 0x57 + name: R87 + fields: + - bits: '15:0' + name: R87_RESERVED_0 + mode: RW + dflt: 0xFF00 + desc: Program 0xFF00 to this field. + - addr: 0x58 + name: R88 + fields: + - bits: '15:0' + name: R88_RESERVED_0 + mode: RW + dflt: 0x3FF + desc: Program 0x3FF to this field. + - addr: 0x59 + name: R89 + fields: + - bits: '15:0' + name: R89_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x5A + name: R90 + fields: + - bits: '15:0' + name: R90_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x5B + name: R91 + fields: + - bits: '15:0' + name: R91_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x5C + name: R92 + fields: + - bits: '15:0' + name: R92_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x5D + name: R93 + fields: + - bits: '15:0' + name: R93_RESERVED_0 + mode: RW + dflt: 0x1000 + desc: Program 0x1000 to this field. + - addr: 0x5E + name: R94 + fields: + - bits: '15:0' + name: R94_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x5F + name: R95 + fields: + - bits: '15:0' + name: R95_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x60 + name: R96 + fields: + - bits: '15:0' + name: R96_RESERVED_0 + mode: RW + dflt: 0x17F8 + desc: Program 0x17F8 to this field. + - addr: 0x61 + name: R97 + fields: + - bits: '15:0' + name: R97_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x62 + name: R98 + fields: + - bits: '15:0' + name: R98_RESERVED_0 + mode: RW + dflt: 0x1C80 + desc: Program 0x1C80 to this field. + - addr: 0x63 + name: R99 + fields: + - bits: '15:0' + name: R99_RESERVED_0 + mode: RW + dflt: 0x19B9 + desc: Program 0x19B9 to this field. + - addr: 0x64 + name: R100 + fields: + - bits: '15:0' + name: R100_RESERVED_0 + mode: RW + dflt: 0x533 + desc: Program 0x533 to this field. + - addr: 0x65 + name: R101 + fields: + - bits: '15:0' + name: R101_RESERVED_0 + mode: RW + dflt: 0x3E8 + desc: Program 0x3E8 to this field. + - addr: 0x66 + name: R102 + fields: + - bits: '15:0' + name: R102_RESERVED_0 + mode: RW + dflt: 0x28 + desc: Program 0x28 to this field. + - addr: 0x67 + name: R103 + fields: + - bits: '15:0' + name: R103_RESERVED_0 + mode: RW + dflt: 0x14 + desc: Program 0x14 to this field. + - addr: 0x68 + name: R104 + fields: + - bits: '15:0' + name: R104_RESERVED_0 + mode: RW + dflt: 0x14 + desc: Program 0x14 to this field. + - addr: 0x69 + name: R105 + fields: + - bits: '15:0' + name: R105_RESERVED_0 + mode: RW + dflt: 0xA + desc: Program 0xA to this field. + - addr: 0x6A + name: R106 + fields: + - bits: '15:0' + name: R106_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x6B + name: R107 + fields: + - bits: '15:0' + name: R107_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x6C + name: R108 + fields: + - bits: '15:0' + name: R108_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x6D + name: R109 + fields: + - bits: '15:0' + name: R109_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x6E + name: R110 + fields: + - bits: '15:0' + name: R110_RESERVED_0 + mode: RW + dflt: 0x1F + desc: Program 0x1F to this field. + - addr: 0x6F + name: R111 + fields: + - bits: '15:0' + name: R111_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Program 0x0 to this field. + - addr: 0x70 + name: R112 + fields: + - bits: '15:0' + name: R112_RESERVED_0 + mode: RW + dflt: 0xFFFF + desc: Program 0xFFFF to this field. + - addr: 0x71 + name: R113 + fields: + - bits: '15:0' + name: R113_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x72 + name: R114 + fields: + - bits: '15:0' + name: R114_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x73 + name: R115 + fields: + - bits: '15:0' + name: R115_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x74 + name: R116 + fields: + - bits: '15:0' + name: R116_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x75 + name: R117 + fields: + - bits: '15:0' + name: R117_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x76 + name: R118 + fields: + - bits: '15:0' + name: R118_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x77 + name: R119 + fields: + - bits: '15:0' + name: R119_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x78 + name: R120 + fields: + - bits: '15:0' + name: R120_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x79 + name: R121 + fields: + - bits: '15:0' + name: R121_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. + - addr: 0x7A + name: R122 + fields: + - bits: '15:0' + name: R122_RESERVED_0 + mode: R + dflt: 0x0 + desc: Not used. Read back only. From 1a327ff2295e93af267700c568e489944faf68cf Mon Sep 17 00:00:00 2001 From: vd <33198864+vd2org@users.noreply.github.com> Date: Sat, 22 Mar 2025 00:04:05 +0400 Subject: [PATCH 017/397] Fixed lmx2820 yaml. --- src/hwparser/gen_h.py | 5 +++++ src/lib/hw/lmx2820/lmx2820.yaml | 36 ++++++++++++++++----------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/hwparser/gen_h.py b/src/hwparser/gen_h.py index 665caf09..0ce6f553 100755 --- a/src/hwparser/gen_h.py +++ b/src/hwparser/gen_h.py @@ -77,6 +77,11 @@ def fieldName(self, field: reg_parser.ParserFields) -> str: def normalize(self, name: str) -> str: return (name.replace('-', '_') + .replace('<=', 'LE') + .replace('>=', 'GE') + .replace('>', 'GT') + .replace('<', 'LT') + .replace('=', 'EQ') .replace('.', '_') .replace(',', '_') .replace(' ', '_') diff --git a/src/lib/hw/lmx2820/lmx2820.yaml b/src/lib/hw/lmx2820/lmx2820.yaml index 6be758c4..7f123581 100644 --- a/src/lib/hw/lmx2820/lmx2820.yaml +++ b/src/lib/hw/lmx2820/lmx2820.yaml @@ -146,7 +146,7 @@ pages: name: INSTCAL_DLY mode: RW dflt: 0x1F4 - desc: "Sets the wait time for instant calibration. INSTCAL_DLY = T x fOSCIN / (2CAL_CLK_DIV). T = 2.5 x CBIASVCO / 4.7 \xB5F. CBIASVCO is the bypass capacitor at pin 3." + desc: "Sets the wait time for instant calibration. INSTCAL_DLY = T x fOSCIN / (2CAL_CLK_DIV). T = 2.5 x CBIASVCO / 4.7 mcF. CBIASVCO is the bypass capacitor at pin 3." - bits: '14:12' name: CAL_CLK_DIV mode: RW @@ -357,8 +357,6 @@ pages: desc: Uses single PFD when PFDIN input is enabled. The actual charge pump current is equal to half the current setting made in CPG. opts: 0x0: Normal operation - 0x1: Not used - 0x2: Not used 0x3: Single PFD - bits: 11 name: PFD_POL @@ -386,19 +384,19 @@ pages: mode: RW dflt: 0xE desc: Sets charge pump gain value. -# opts: -# 0x0: Tri-state -# 0x1: 1.4 mA -# 0x4: 5.6 mA -# 0x5: 7 mA -# 0x6: 11.2 mA -# 0x7: 12.6 mA -# 0x8: 2.8 mA -# 0x9: 4.2 mA -# 0x12: 8.4 mA -# 0x13: 9.8 mA -# 0x14: 14 mA -# 0x15: 15.4 mA + opts: + 0: Tri-state + 1: 1.4 mA + 4: 5.6 mA + 5: 7 mA + 6: 11.2 mA + 7: 12.6 mA + 8: 2.8 mA + 9: 4.2 mA + 12: 8.4 mA + 13: 9.8 mA + 14: 14 mA + 15: 15.4 mA - bits: '15:5' name: R16_RESERVED_0 mode: RW @@ -1236,8 +1234,8 @@ pages: dflt: 0x0 desc: Reads back lock detect status. opts: - 0x0: Unlocked - 0x1: Unlocked + 0x0: Unlocked0 + 0x1: Unlocked1 0x2: Locked 0x3: Invalid - addr: 0x4B @@ -1260,7 +1258,7 @@ pages: name: RB_TEMP_SENS mode: R dflt: 0x0 - desc: "Reads back temperature sensor code. Temperature in \xB0C = 0.85 x code - 415. Resolution is 0.6\xB0C per code. Measurement accuracy is \xB15 degrees." + desc: "Reads back temperature sensor code. Temperature in C = 0.85 x code - 415. Resolution is 0.6C per code. Measurement accuracy is 5 degrees." - bits: '15:11' name: R76_RESERVED_0 mode: R From 8a193280ffe004c54ed3aab387aac4fa3543a9af Mon Sep 17 00:00:00 2001 From: vd <33198864+vd2org@users.noreply.github.com> Date: Sat, 22 Mar 2025 00:45:01 +0400 Subject: [PATCH 018/397] Fixed lmx2820 yaml. --- src/hwparser/gen_h.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hwparser/gen_h.py b/src/hwparser/gen_h.py index 0ce6f553..210e4bf0 100755 --- a/src/hwparser/gen_h.py +++ b/src/hwparser/gen_h.py @@ -82,6 +82,7 @@ def normalize(self, name: str) -> str: .replace('>', 'GT') .replace('<', 'LT') .replace('=', 'EQ') + .replace('+', 'PL') .replace('.', '_') .replace(',', '_') .replace(' ', '_') From 66dcd7a83bfb06db2b0cdb8c42d6e0909be6c1b7 Mon Sep 17 00:00:00 2001 From: vd <33198864+vd2org@users.noreply.github.com> Date: Mon, 24 Mar 2025 20:25:03 +0400 Subject: [PATCH 019/397] Updated gen_h.py. --- src/hwparser/gen_h.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hwparser/gen_h.py b/src/hwparser/gen_h.py index 210e4bf0..8a627b9f 100755 --- a/src/hwparser/gen_h.py +++ b/src/hwparser/gen_h.py @@ -83,6 +83,7 @@ def normalize(self, name: str) -> str: .replace('<', 'LT') .replace('=', 'EQ') .replace('+', 'PL') + .replace("'", 'MARK') .replace('.', '_') .replace(',', '_') .replace(' ', '_') From 9438bd539f0e1735edf06f56fe67c87d36e2d59e Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 26 Mar 2025 19:17:14 +0300 Subject: [PATCH 020/397] lmx2820 solver & tuner --- src/lib/hw/lmx2820/lmx2820.c | 658 +++++++++++++++++++++++++++++++++-- src/lib/hw/lmx2820/lmx2820.h | 42 +++ src/utests/CMakeLists.txt | 2 + src/utests/test_suite.c | 6 + 4 files changed, 673 insertions(+), 35 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 5f19debf..66be95bf 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -4,23 +4,36 @@ #include #include #include +#include #include "lmx2820.h" #include "def_lmx2820.h" #include enum { - OUT_FREQ_MIN = 45000000ul, - OUT_FREQ_MAX = 22600000000ul, - VCO_MIN = 5650000000ul, - VCO_MAX = 11300000000ul, + OSC_IN_MIN = 5000000ull, + OSC_IN_MAX = 1400000000ull, + OSC_IN_MAX_DBLR = 250000000ull, + + OUT_FREQ_MIN = 45000000ull, + OUT_FREQ_MAX = 22600000000ull, + + VCO_MIN = 5650000000ull, + VCO_MAX = 11300000000ull, PLL_R_PRE_DIV_MIN = 1, PLL_R_PRE_DIV_MAX = 4095, - MULT_MIN = 3, - MULT_MAX = 7, + MULT_IN_FREQ_MIN = 30000000ull, + MULT_IN_FREQ_MAX = 70000000ull, + MULT_OUT_FREQ_MIN = 180000000ull, + MULT_OUT_FREQ_MAX = 250000000ull, + + MULT_MIN = MULT_X3, + MULT_MAX = MULT_X7, + + FPD_MIN = 5000000ull, PLL_R_DIV_MIN = 1, PLL_R_DIV_MAX = 255, @@ -29,55 +42,87 @@ enum { OUT_DIV_LOG2_MAX = 7, }; +#define VCO_ACCURACY 0.1f +#define RF_ACCURACY 1.0f +#define OUT_DIV_DIAP_MAX (OUT_DIV_LOG2_MAX - OUT_DIV_LOG2_MIN + 1 + 1) + enum { - VCO_CORE1 = 0, - VCO_CORE2, - VCO_CORE3, - VCO_CORE4, - VCO_CORE5, - VCO_CORE6, - VCO_CORE7, + PLL_N_MIN = 12, + PLL_N_MAX = 32767, }; -enum { - MASH_ORDER0 = 0, - MASH_ORDER1, - MASH_ORDER2, - MASH_ORDER3, +struct range { + uint64_t min, max; }; +typedef struct range range_t; struct vco_core { - uint64_t fmin, fmax; - unsigned ndiv_min[MASH_ORDER3 + 1]; + range_t freq; + uint16_t ndiv_min[MASH_ORDER_THIRD_ORDER + 1]; }; typedef struct vco_core vco_core_t; -static vco_core_t vco_cores[VCO_CORE7 + 1] = +static vco_core_t VCO_CORES[VCO_SEL_VCO7] = { - {VCO_MIN, 6350000000ul, {12,18,19,24}}, - { 6350000000ul, 7300000000ul, {14,21,22,26}}, - { 7300000000ul, 8100000000ul, {16,23,24,26}}, - { 8100000000ul, 9000000000ul, {16,26,27,29}}, - { 9000000000ul, 9800000000ul, {18,28,29,31}}, - { 9800000000ul, 10600000000ul, {18,30,31,33}}, - {10600000000ul, (VCO_MAX + 1), {20,33,34,36}} + {{VCO_MIN, 6350000000}, {12,18,19,24}}, + {{6350000000, 7300000000}, {14,21,22,26}}, + {{7300000000, 8100000000}, {16,23,24,26}}, + {{8100000000, 9000000000}, {16,26,27,29}}, + {{9000000000, 9800000000}, {18,28,29,31}}, + {{9800000000, 10600000000}, {18,30,31,33}}, + {{10600000000, VCO_MAX + 1}, {20,33,34,36}} }; -static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, unsigned* vco_core, unsigned* ndiv_min) +static uint64_t FPD_MAX[MASH_ORDER_THIRD_ORDER + 1] = +{ + 400000000, 300000000, 300000000, 250000000 +}; + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count) +{ + int res; + for (unsigned i = 0; i < count; i++) { + res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); + if (res) + return res; + + USDR_LOG("2820", USDR_LOG_NOTE, "[%d/%d] reg wr %08x\n", i, count, regs[i]); + } + + return 0; +} + +static int lmx2820_spi_get(lmx2820_state_t* obj, uint16_t addr, uint16_t* out) +{ + uint32_t v; + int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, addr << 16, &v); + if (res) + return res; + + USDR_LOG("2820", USDR_LOG_NOTE, " reg rd %04x => %08x\n", addr, v); + *out = v; + return 0; +} + + +static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, unsigned* vco_core, uint16_t* ndiv_min) { if(!vco_core || !ndiv_min || - vco_freq < VCO_MIN || vco_freq > OUT_FREQ_MAX || - mash_order > MASH_ORDER3) + vco_freq < VCO_MIN || vco_freq > VCO_MAX || + mash_order > MASH_ORDER_THIRD_ORDER) { return -EINVAL; } - for(unsigned i = 0; i <= VCO_CORE7; ++i) + for(unsigned i = 0; i < VCO_SEL_VCO7; ++i) { - const vco_core_t r = vco_cores[i]; - if(vco_freq >= r.fmin && vco_freq < r.fmax) + const vco_core_t r = VCO_CORES[i]; + if(vco_freq >= r.freq.min && vco_freq < r.freq.max) { - *vco_core = i; + *vco_core = i + 1; *ndiv_min = r.ndiv_min[mash_order]; return 0; } @@ -88,3 +133,546 @@ static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, un } +static int lmx2820_reset(lmx2820_state_t* st) +{ + memset(st, 0, sizeof(*st)); + + uint16_t r0; + + int res = lmx2820_spi_get(st, R0, &r0); + if(res) + return res; + + r0 |= (uint16_t)1 << RESET_OFF; + + uint32_t reg = MAKE_LMX2820_REG_WR(R0, r0); + + return lmx2820_spi_post(st, ®, 1); +} + +static int lmx2820_calibrate(lmx2820_state_t* st) +{ + uint16_t r0; + + int res = lmx2820_spi_get(st, R0, &r0); + if(res) + return res; + + r0 |= (uint16_t)1 << FCAL_EN_OFF; + + uint32_t reg = MAKE_LMX2820_REG_WR(R0, r0); + + return lmx2820_spi_post(st, ®, 1); +} + +static int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) +{ + int res = 0; + unsigned elapsed = 0; + + uint16_t r74; + while(timeout == 0 || elapsed < timeout) + { + res = lmx2820_spi_get(st, R74, &r74); + if(res) + return res; + + const uint16_t lock_detect_status = (r74 & RB_LD_MSK) >> RB_LD_OFF; + switch(lock_detect_status) + { + case RB_LD_INVALID: return -EINVAL; + case RB_LD_LOCKED: return 0; + default: + usleep(100); + elapsed += 100; + } + } + + return 0; +} + +int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st) +{ + st->dev = dev; + st->subdev = subdev; + st->lsaddr = lsaddr; + + return lmx2820_reset(st); +} + +static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, uint64_t vco, unsigned mash_order, unsigned force_mult) +{ + int res = 0; + + unsigned mult, pll_r_pre, pll_r; + + uint16_t min_pll_n; + unsigned vco_core; + res = lmx2820_get_worst_vco_core(vco, mash_order, &vco_core, &min_pll_n); + if(res) + return res; + + USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " -> VCO_CORE%d PLL_N_MIN:%d", vco, vco_core, min_pll_n); + + const double min_n_total = min_pll_n; + const double max_n_total = PLL_N_MAX + 1; + + uint64_t fpd_max = FPD_MAX[mash_order]; + uint64_t fpd_min = FPD_MIN; + + fpd_max = MIN(fpd_max, vco / min_n_total); + fpd_min = MAX(fpd_min, vco / max_n_total); + USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " NMIN:%.0f NMAX:%.0f FPD_MIN:%" PRIu64 " FPD_MAX:%" PRIu64, + vco, min_n_total, max_n_total, fpd_min, fpd_max); + + const bool osc_2x = (fosc_in <= OSC_IN_MAX_DBLR); + uint64_t osc_in = fosc_in * (osc_2x ? 2 : 1); + USDR_LOG("2820", USDR_LOG_DEBUG, "OSC_2X:%d -> effective OSC_IN:%" PRIu64, osc_2x, osc_in); + + //Do we need mult? + if(osc_in < fpd_min || force_mult) + { + USDR_LOG("2820", USDR_LOG_DEBUG, "Need mult"); + + //need mult + mult = MAX(force_mult ? force_mult : (unsigned)ceil((double)fpd_min / osc_in), MULT_MIN); + if(mult > MULT_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Mult:%d out of range", mult); + return -EINVAL; + } + + pll_r_pre = 1; + pll_r = 1; + + if(osc_in < MULT_IN_FREQ_MIN) + { + USDR_LOG("2820", USDR_LOG_ERROR, "OSC_IN:%" PRIu64" too low for mult, set %" PRIu64 " at least", fosc_in, (uint64_t)MULT_IN_FREQ_MIN/2); + return -EINVAL; + } + + if(osc_in > MULT_IN_FREQ_MAX) + { + pll_r_pre = (unsigned)ceil((double)osc_in / MULT_IN_FREQ_MAX); + } + + uint64_t freq_pre = osc_in / pll_r_pre; + uint64_t freq_mult = freq_pre * mult; + + while(freq_mult < MULT_OUT_FREQ_MIN) + { + if(mult == MULT_MAX) + return -EINVAL; + freq_mult = freq_pre * (++mult); + if(freq_mult > MULT_OUT_FREQ_MAX) + return -EINVAL; + } + + while(freq_mult > MULT_OUT_FREQ_MAX) + { + if(mult == MULT_MIN) + return -EINVAL; + freq_mult = freq_pre * (--mult); + if(freq_mult < MULT_OUT_FREQ_MIN) + return -EINVAL; + } + + if(freq_mult > fpd_max) + { + pll_r = (unsigned)ceil((double)freq_mult / fpd_max); + } + } + else if(osc_in > fpd_max) + { + USDR_LOG("2820", USDR_LOG_DEBUG, "Need divs"); + + //no need for mult, but need for divs + mult = 1; + unsigned div = (unsigned)ceil((double)osc_in / fpd_max); + if(div > PLL_R_PRE_DIV_MAX * PLL_R_DIV_MAX) + return -EINVAL; + + + if(div <= PLL_R_PRE_DIV_MAX) + { + pll_r_pre = div; + pll_r = 1; + } + else + { + pll_r_pre = PLL_R_PRE_DIV_MAX; + pll_r = (unsigned)ceil((double)div / PLL_R_PRE_DIV_MAX); + } + + USDR_LOG("2820", USDR_LOG_DEBUG, "TOTAL_DIV:%u PLL_R_PRE:%u PLL_R:%u", div, pll_r_pre, pll_r); + } + else + { + //no need neither for mult or for divs + mult = 1; + pll_r_pre = 1; + pll_r = 1; + } + + uint64_t fpd = osc_in * mult / (pll_r_pre * pll_r); + USDR_LOG("2820", USDR_LOG_DEBUG, "For VCO:%" PRIu64 " -> FPD:%" PRIu64, vco, fpd); + + if(fpd < fpd_min || fpd > fpd_max) + { + USDR_LOG("2820", USDR_LOG_ERROR, "FPD:%" PRIu64 " out of range: should never be happen!", fpd); + return -EINVAL; + } + + double n_total = (double)vco / fpd; + USDR_LOG("2820", USDR_LOG_DEBUG, "N_total:%.6f", n_total); + + if(n_total < min_n_total || n_total > max_n_total) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Ntotal:%.6f out of range [%.0f;%0.f): should never be happen!", n_total, min_n_total, max_n_total); + return -EINVAL; + } + + + uint16_t pll_n = (uint16_t)n_total; + double pll_frac = n_total - pll_n; + USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_FRAC:%.8f", pll_n, pll_frac); + + uint32_t pll_den = UINT32_MAX; + uint32_t pll_num = pll_frac * pll_den; + double vco_fact = (double)fpd * (pll_n + (double)pll_num / pll_den); + + double delta = fabs(vco_fact - vco); + USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f Deviation:%.8fHz", pll_n, pll_num, pll_den, vco_fact, delta); + + if(delta > VCO_ACCURACY) + { + USDR_LOG("2820", USDR_LOG_ERROR, "VCO tuning too rough"); + return -EINVAL; + } + + lmx2820_input_chain_t * settings = &st->lmx2820_input_chain; + settings->mash_order = mash_order; + settings->vco_core = vco_core; + settings->fosc_in = fosc_in; + settings->osc_2x = osc_2x; + settings->pll_r_pre = pll_r_pre; + settings->mult = mult; + settings->pll_r = pll_r; + settings->pll_n = pll_n; + settings->pll_num = pll_num; + settings->pll_den = pll_den; + settings->fvco = vco_fact; + settings->fpd = fpd; + + USDR_LOG("2820", USDR_LOG_WARNING, "Input circuit res: OSC_IN:%" PRIu64 " OSC_2X:%d PLL_R_PRE:%d MULT:%d PLL_R:%d FPD:%" PRIu64 " PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f", + fosc_in, osc_2x, pll_r_pre, mult, pll_r, fpd, pll_n, pll_num, pll_den, vco_fact); + + return 0; + +} + +int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, uint64_t rfouta, uint64_t rfoutb) +{ + if(osc_in < OSC_IN_MIN || osc_in > OSC_IN_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "OSC_IN %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", osc_in, (uint64_t)OSC_IN_MIN, (uint64_t)OSC_IN_MAX); + return -EINVAL; + } + + switch(mash_order) + { + case MASH_ORDER_INTEGER_MODE: + case MASH_ORDER_FIRST_ORDER: + case MASH_ORDER_SECOND_ORDER: + case MASH_ORDER_THIRD_ORDER: break; + default: { + USDR_LOG("2820", USDR_LOG_ERROR, "MASH_ORDER %u out of range [%u;%u]", mash_order, (unsigned)MASH_ORDER_INTEGER_MODE, (unsigned)MASH_ORDER_THIRD_ORDER); + return -EINVAL; + } + } + + if(rfouta < OUT_FREQ_MIN || rfouta > OUT_FREQ_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RF_OUTA %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", rfouta, (uint64_t)OUT_FREQ_MIN, (uint64_t)OUT_FREQ_MAX); + return -EINVAL; + } + if(rfoutb < OUT_FREQ_MIN || rfoutb > OUT_FREQ_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RF_OUTB %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", rfoutb, (uint64_t)OUT_FREQ_MIN, (uint64_t)OUT_FREQ_MAX); + return -EINVAL; + } + + uint64_t *rf_max, *rf_min; + unsigned mux_max, mux_min; + + if(rfouta > rfoutb) + { + rf_max = &rfouta; + rf_min = &rfoutb; + } + else + { + rf_max = &rfoutb; + rf_min = &rfouta; + } + + double rf_ratio = log2((double)(*rf_max)/(*rf_min)); + unsigned rf_ratio_n = (unsigned)rf_ratio; + + if(fabs(rf_ratio - rf_ratio_n) > 1E-8) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT A/B ratio must be == 2^N"); + return -EINVAL; + } + + + if(rf_ratio_n > OUT_DIV_DIAP_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT ratio:%d > %d, out of range", rf_ratio_n, (int)OUT_DIV_DIAP_MAX); + return -EINVAL; + } + + UNUSED uint64_t vco, rf_max_fact, rf_min_fact; + uint8_t div_max = 1, div_min = 1; + + if(*rf_max > VCO_MAX) + { + //rf_max is doubled VCO + //rf_min may be VCO or VCO/2..7 + + mux_max = OUTA_MUX_VCO_DOUBLER; + vco = (uint64_t)((double)(*rf_max) / 2 + 0.5); + rf_max_fact = vco << 1; + + switch(rf_ratio_n) + { + case 0: rf_min_fact = rf_max_fact; mux_min = OUTA_MUX_VCO_DOUBLER; break; + case 1: rf_min_fact = vco; mux_min = OUTA_MUX_VCO; break; + default: + div_min = rf_ratio_n - 1; + rf_min_fact = vco >> div_min; + mux_min = OUTA_MUX_CHANNEL_DIVIDER; + if(div_min == OUT_DIV_LOG2_MAX) + { + div_max = div_min; + } + } + } + else if(*rf_max < VCO_MIN) + { + //both rf_max & rf_min are VCO/2..7 + //rf_ratio_n must be <=6 + + if(rf_ratio_n > OUT_DIV_DIAP_MAX - 2) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT ratio:%d > %d, out of range", rf_ratio_n, (int)OUT_DIV_DIAP_MAX - 2); + return -EINVAL; + } + + vco = MAX((*rf_max) << OUT_DIV_LOG2_MIN, VCO_MIN); + div_max = (uint8_t)ceil(log2((double)vco / (*rf_max))); + div_max = MAX(div_max, OUT_DIV_LOG2_MIN); + div_min = div_max + rf_ratio_n; + + if(div_max < OUT_DIV_LOG2_MIN || div_max > OUT_DIV_LOG2_MAX || div_min < OUT_DIV_LOG2_MIN || div_min > OUT_DIV_LOG2_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Cannot calculate dividers for RFs specified (DIV_MIN:%d DIV_MAX:%d)", div_min, div_max); + return -EINVAL; + } + + if((div_min == OUT_DIV_LOG2_MAX || div_max == OUT_DIV_LOG2_MAX) && div_min != div_max) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Invalid RF dividers configuration (DIV_MIN:%d DIV_MAX:%d)", div_min, div_max); + return -EINVAL; + } + + vco = (*rf_max) << div_max; + rf_max_fact = vco >> div_max; + rf_min_fact = vco >> div_min; + mux_min = mux_max = OUTA_MUX_CHANNEL_DIVIDER; + } + else + { + //rf_max == VCO + //rf_min - VCO if rfa==rfb, or VCO/2..7 + //rf_ratio_n must be <=7 + + if(rf_ratio_n > OUT_DIV_DIAP_MAX - 1) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT ratio:%d > %d, out of range", rf_ratio_n, (int)OUT_DIV_DIAP_MAX - 1); + return -EINVAL; + } + + vco = *rf_max; + rf_max_fact = vco; + mux_max = OUTA_MUX_VCO; + + switch(rf_ratio_n) + { + case 0: rf_min_fact = rf_max_fact; mux_min = OUTA_MUX_VCO; break; + default: + div_min = rf_ratio_n; + rf_min_fact = vco >> div_min; + mux_min = OUTA_MUX_CHANNEL_DIVIDER; + if(div_min == OUT_DIV_LOG2_MAX) + { + div_max = div_min; + } + } + } + + USDR_LOG("2820", USDR_LOG_DEBUG, "Will tune for VCO:%" PRIu64, vco); + + int res = lmx2820_calculate_input_chain(st, osc_in, vco, mash_order, 0); + if(res) + return res; + + double fvco = st->lmx2820_input_chain.fvco; + double rf_min_res, rf_max_res; + + switch(mux_min) + { + case OUTA_MUX_VCO_DOUBLER: rf_min_res = fvco * 2.0; break; + case OUTA_MUX_VCO: rf_min_res = fvco; break; + case OUTA_MUX_CHANNEL_DIVIDER: rf_min_res = fvco / ((unsigned)1 << div_min); break; + default: + return -EINVAL; + } + switch(mux_max) + { + case OUTA_MUX_VCO_DOUBLER: rf_max_res = fvco * 2.0; break; + case OUTA_MUX_VCO: rf_max_res = fvco; break; + case OUTA_MUX_CHANNEL_DIVIDER: rf_max_res = fvco / ((unsigned)1 << div_max); break; + default: + return -EINVAL; + } + + double rfmin_delta = fabs(*rf_min - rf_min_res); + double rfmax_delta = fabs(*rf_max - rf_max_res); + + USDR_LOG("2820", USDR_LOG_DEBUG, "RF_MIN:%" PRIu64 "->%.6f Deviation:%f.8Hz", *rf_min, rf_min_res, rfmin_delta); + USDR_LOG("2820", USDR_LOG_DEBUG, "RF_MAX:%" PRIu64 "->%.6f Deviation:%f.8Hz", *rf_max, rf_max_res, rfmax_delta); + + if(rfmin_delta > RF_ACCURACY || rfmax_delta > RF_ACCURACY) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RF tuning too rough"); + return -EINVAL; + } + + if(div_max < OUT_DIV_LOG2_MIN || div_max > OUT_DIV_LOG2_MAX || div_min < OUT_DIV_LOG2_MIN || div_min > OUT_DIV_LOG2_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT dividers out of range (DIV_MIN:%d DIV_MAX:%d) [should never happen]", div_min, div_max); + return -EINVAL; + } + + lmx2820_output_chain_t * outs = &st->lmx2820_output_chain; + outs->chdiva = (&rfouta == rf_min) ? div_min : div_max; + outs->chdivb = (&rfoutb == rf_min) ? div_min : div_max; + outs->rfouta = (&rfouta == rf_min) ? rf_min_res : rf_max_res; + outs->rfoutb = (&rfoutb == rf_min) ? rf_min_res : rf_max_res; + outs->outa_mux = (&rfouta == rf_min) ? mux_min : mux_max; + outs->outb_mux = (&rfoutb == rf_min) ? mux_min : mux_max; + + USDR_LOG("2820", USDR_LOG_WARNING, "***** SOLUTION *****"); + USDR_LOG("2820", USDR_LOG_WARNING, "VCO:%.2f OSC_IN:%" PRIu64 " MASH_ORDER:%u VCO_CORE%u", fvco, osc_in, mash_order, st->lmx2820_input_chain.vco_core); + USDR_LOG("2820", USDR_LOG_WARNING, "CH_A - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfouta, outs->chdiva - 1, (1 << outs->chdiva), + outs->outa_mux == OUTA_MUX_VCO_DOUBLER ? "OUTA_MUX_VCO_DOUBLER" : (outs->outa_mux == OUTA_MUX_VCO ? "OUTA_MUX_VCO": "OUTA_MUX_CHANNEL_DIVIDER")); + USDR_LOG("2820", USDR_LOG_WARNING, "CH_B - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfoutb, outs->chdivb - 1, (1 << outs->chdivb), + outs->outb_mux == OUTB_MUX_VCO_DOUBLER ? "OUTB_MUX_VCO_DOUBLER" : (outs->outb_mux == OUTB_MUX_VCO ? "OUTB_MUX_VCO": "OUTB_MUX_CHANNEL_DIVIDER")); + + return 0; +} + +int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, uint64_t rfouta, uint64_t rfoutb) +{ + int res = lmx2820_solver(st, osc_in, mash_order, rfouta, rfoutb); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_solver() failed, err:%d", res); + return res; + } + + uint8_t HP_fd_adj, LP_fd_adj; + double fpd = st->lmx2820_input_chain.fpd; + + if(fpd < 2500000) + LP_fd_adj = FCAL_LPFD_ADJ_FPD_LT_2_5_MHZ; + else if(fpd < 5000000) + LP_fd_adj = FCAL_LPFD_ADJ_5_MHZ_GT_FPD_GE_2_5_MHZ; + else if(fpd < 10000000) + LP_fd_adj = FCAL_LPFD_ADJ_10_MHZ_GT_FPD_GE_5_MHZ; + else + LP_fd_adj = FCAL_LPFD_ADJ_FPD_GE_10_MHZ; + + if(fpd <= 100000000) + HP_fd_adj = FCAL_HPFD_ADJ_FPD_LE_100_MHZ; + else if(fpd <= 150000000) + HP_fd_adj = FCAL_HPFD_ADJ_100_MHZ_LT_FPD_LE_150_MHZ; + else if(fpd <= 200000000) + HP_fd_adj = FCAL_HPFD_ADJ_150_MHZ_LT_FPD_LE_200_MHZ; + else + HP_fd_adj = FCAL_HPFD_ADJ_FPD_GT_200_MHZ; + + bool vco_dblr_engaged = st->lmx2820_output_chain.outa_mux == OUTA_MUX_VCO_DOUBLER || st->lmx2820_output_chain.outb_mux == OUTB_MUX_VCO_DOUBLER; + + uint8_t cal_clk_div; + if(osc_in <= 200000000) + cal_clk_div = CAL_CLK_DIV_FOSCIN_LE_200_MHZ; + else if(osc_in <= 400000000) + cal_clk_div = CAL_CLK_DIV_FOSCIN_LE_400_MHZ; + else if(osc_in <= 800000000) + cal_clk_div = CAL_CLK_DIV_FOSCIN_LE_800_MHZ; + else + cal_clk_div = CAL_CLK_DIV_ALL_OTHER_FOSCIN_VALUES; + + uint32_t regs[] = + { + MAKE_LMX2820_R79(0, OUTB_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outb_mux, 0x7, 0), + MAKE_LMX2820_R78(0, OUTA_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outa_mux), + MAKE_LMX2820_R43((uint16_t)st->lmx2820_input_chain.pll_num), + MAKE_LMX2820_R42((uint16_t)(st->lmx2820_input_chain.pll_num >> 16)), + MAKE_LMX2820_R39((uint16_t)st->lmx2820_input_chain.pll_den), + MAKE_LMX2820_R38((uint16_t)(st->lmx2820_input_chain.pll_den >> 16)), + MAKE_LMX2820_R36(0, st->lmx2820_input_chain.pll_n), + MAKE_LMX2820_R35(1, MASH_RESET_N_NORMAL_OPERATION, 0, st->lmx2820_input_chain.mash_order, MASHSEED_EN_DISABLED, 0), + MAKE_LMX2820_R32(1, st->lmx2820_output_chain.chdivb - 1, st->lmx2820_output_chain.chdiva - 1, 1), + MAKE_LMX2820_R22(st->lmx2820_input_chain.vco_core, 0x2, 0xBF), + MAKE_LMX2820_R14(0x3, st->lmx2820_input_chain.pll_r_pre), + MAKE_LMX2820_R13(0, st->lmx2820_input_chain.pll_r, 0x18), + MAKE_LMX2820_R12(0, st->lmx2820_input_chain.mult, 0x8), + MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x3), + MAKE_LMX2820_R2 (1, cal_clk_div, 0x1F4, QUICK_RECAL_EN_DISABLED), + MAKE_LMX2820_R1 (0, 0x15E, 1, 0, vco_dblr_engaged ? 1 : 0, 0), + MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_DISABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) + }; + + res = lmx2820_spi_post(st, regs, sizeof(regs)); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); + return res; + } + + usleep(10000); + + res = lmx2820_calibrate(st); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_calibrate() failed, err:%d", res); + return res; + } + + res = lmx2820_wait_pll_lock(st, 10000); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_wait_pll_lock() failed, err:%d", res); + return res; + } + + return 0; +} + +int lmx2820_destroy(lmx2820_state_t* st) +{ + return 0; +} diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index b6d2ecc9..36946eeb 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -4,5 +4,47 @@ #include +struct lmx2820_input_chain_st +{ + uint8_t mash_order; + uint8_t vco_core; + uint64_t fosc_in; + bool osc_2x; + uint16_t pll_r_pre; + uint8_t mult; + uint8_t pll_r; + uint16_t pll_n; + uint32_t pll_num; + uint32_t pll_den; + double fvco; + double fpd; +}; +typedef struct lmx2820_input_chain_st lmx2820_input_chain_t; + +struct lmx2820_output_chain_st +{ + uint8_t chdiva; + uint8_t chdivb; + uint8_t outa_mux; + uint8_t outb_mux; + double rfouta; + double rfoutb; +}; +typedef struct lmx2820_output_chain_st lmx2820_output_chain_t; + +struct lmx2820_state { + lldev_t dev; + unsigned subdev; + unsigned lsaddr; + + lmx2820_input_chain_t lmx2820_input_chain; + lmx2820_output_chain_t lmx2820_output_chain; +}; +typedef struct lmx2820_state lmx2820_state_t; + + +int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st); +int lmx2820_destroy(lmx2820_state_t* st); +int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, uint64_t rfouta, uint64_t rfoutb); #endif // LMX2820_H diff --git a/src/utests/CMakeLists.txt b/src/utests/CMakeLists.txt index 5468ec63..472fe855 100644 --- a/src/utests/CMakeLists.txt +++ b/src/utests/CMakeLists.txt @@ -3,6 +3,7 @@ include_directories(../lib/port) include_directories(../lib/lowlevel) +include_directories(../lib/hw) add_library(mock_lowlevel STATIC mock_lowlevel.c) @@ -11,6 +12,7 @@ set(TEST_SUIT_SRCS ring_buffer_test.c trig_test.c clockgen_test.c + lmx2820_solver_test.c ) include_directories(../lib/xdsp) diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index 043afe29..22cbecb7 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -11,6 +11,7 @@ Suite * ring_buffer_suite(void); Suite * trig_suite(void); Suite * clockgen_suite(void); +Suite * lmx2820_solver_suite(void); int main(int argc, char** argv) { @@ -25,10 +26,15 @@ int main(int argc, char** argv) usdrlog_setlevel(NULL, (argc > 1) ? USDR_LOG_TRACE : USDR_LOG_INFO); usdrlog_enablecolorize(NULL); +#if 1 + sr = srunner_create(lmx2820_solver_suite()); +#else sr = srunner_create(ring_buffer_suite()); srunner_add_suite(sr, trig_suite()); srunner_add_suite(sr, clockgen_suite()); +#endif + srunner_set_fork_status (sr, CK_NOFORK); srunner_run_all(sr, (argc > 1) ? CK_VERBOSE : CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); From b2da96c40ea8c19507ea487f2cde07852342aec1 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 26 Mar 2025 19:32:39 +0300 Subject: [PATCH 021/397] ++lmx2820 unit test --- src/utests/lmx2820_solver_test.c | 123 +++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/utests/lmx2820_solver_test.c diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c new file mode 100644 index 00000000..29d37190 --- /dev/null +++ b/src/utests/lmx2820_solver_test.c @@ -0,0 +1,123 @@ +#include +#include "lmx2820/lmx2820.h" + +static lmx2820_state_t st; + +static void setup() +{ + memset(&st, 0, sizeof(st)); +} + +static void teardown() {} + +START_TEST(lmx2820_solver_test1) +{ + const uint64_t osc_in = 5000000; + const int mash_order = 0; + uint64_t out_freq1 = 45000000; + uint64_t out_freq2 = out_freq1; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test2) +{ + const uint64_t osc_in = 1400000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 45000000; + uint64_t out_freq2 = out_freq1; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test3) +{ + const uint64_t osc_in = 5000000; + const int mash_order = 0; + uint64_t out_freq1 = 22600000000ull; + uint64_t out_freq2 = out_freq1; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + + +START_TEST(lmx2820_solver_test4) +{ + const uint64_t osc_in = 1400000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 22600000000ull; + uint64_t out_freq2 = out_freq1; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test5) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 5600000000ull; + uint64_t out_freq2 = out_freq1 >> 3; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test6) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 5600000000ull; + uint64_t out_freq2 = out_freq1 << 1; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test7) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 5800000000ull; + uint64_t out_freq2 = out_freq1 << 1; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test8) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 20000987000ull; + uint64_t out_freq2 = out_freq1 >> 4; + + int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +Suite * lmx2820_solver_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("lmx2820_solver"); + tc_core = tcase_create("HW"); + tcase_set_timeout(tc_core, 1); + tcase_add_checked_fixture(tc_core, setup, teardown); + + tcase_add_test(tc_core, lmx2820_solver_test1); + tcase_add_test(tc_core, lmx2820_solver_test2); + tcase_add_test(tc_core, lmx2820_solver_test3); + tcase_add_test(tc_core, lmx2820_solver_test4); + tcase_add_test(tc_core, lmx2820_solver_test5); + tcase_add_test(tc_core, lmx2820_solver_test6); + tcase_add_test(tc_core, lmx2820_solver_test7); + tcase_add_test(tc_core, lmx2820_solver_test8); + + suite_add_tcase(s, tc_core); + return s; +} From 859411db65ee9dd3a200aac68b6efaa10402ba73 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 27 Mar 2025 14:13:17 +0300 Subject: [PATCH 022/397] minor fixes/ench + additional test cases --- src/lib/hw/lmx2820/lmx2820.c | 37 ++++++++++++++++------ src/lib/hw/lmx2820/lmx2820.h | 3 +- src/utests/lmx2820_solver_test.c | 53 ++++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 66be95bf..101aa204 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -37,6 +37,8 @@ enum { PLL_R_DIV_MIN = 1, PLL_R_DIV_MAX = 255, + PLL_R_DIV_2_IN_FREQ_MAX = 500000000ull, + PLL_R_DIV_GT2_IN_FREQ_MAX = 250000000ull, OUT_DIV_LOG2_MIN = 1, OUT_DIV_LOG2_MAX = 7, @@ -225,14 +227,17 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " NMIN:%.0f NMAX:%.0f FPD_MIN:%" PRIu64 " FPD_MAX:%" PRIu64, vco, min_n_total, max_n_total, fpd_min, fpd_max); - const bool osc_2x = (fosc_in <= OSC_IN_MAX_DBLR); + bool need_mult = (fosc_in < fpd_min) || force_mult; + const bool osc_2x = (fosc_in <= OSC_IN_MAX_DBLR && !need_mult); uint64_t osc_in = fosc_in * (osc_2x ? 2 : 1); USDR_LOG("2820", USDR_LOG_DEBUG, "OSC_2X:%d -> effective OSC_IN:%" PRIu64, osc_2x, osc_in); - //Do we need mult? - if(osc_in < fpd_min || force_mult) + if((osc_in < fpd_min) || force_mult) { - USDR_LOG("2820", USDR_LOG_DEBUG, "Need mult"); + if(force_mult) + USDR_LOG("2820", USDR_LOG_DEBUG, "Mult:%d forced by user", force_mult); + else + USDR_LOG("2820", USDR_LOG_DEBUG, "Need mult"); //need mult mult = MAX(force_mult ? force_mult : (unsigned)ceil((double)fpd_min / osc_in), MULT_MIN); @@ -314,7 +319,21 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, pll_r = 1; } - uint64_t fpd = osc_in * mult / (pll_r_pre * pll_r); + if(pll_r > PLL_R_DIV_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "PLL_R:%d out of range", pll_r); + return -EINVAL; + } + + uint64_t f_in_pll_r = osc_in * mult / pll_r_pre; + uint64_t max_f_in_pll_r = (pll_r <= 2) ? PLL_R_DIV_2_IN_FREQ_MAX : PLL_R_DIV_GT2_IN_FREQ_MAX; + if(f_in_pll_r > max_f_in_pll_r) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Input freq for PLL_R:%d is out of range, %" PRIu64 " > %" PRIu64, pll_r, f_in_pll_r, max_f_in_pll_r); + return -EINVAL; + } + + uint64_t fpd = (uint64_t)((double)osc_in * mult / (pll_r_pre * pll_r) + 0.5); USDR_LOG("2820", USDR_LOG_DEBUG, "For VCO:%" PRIu64 " -> FPD:%" PRIu64, vco, fpd); if(fpd < fpd_min || fpd > fpd_max) @@ -371,7 +390,7 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, } -int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, uint64_t rfouta, uint64_t rfoutb) +int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb) { if(osc_in < OSC_IN_MIN || osc_in > OSC_IN_MAX) { @@ -523,7 +542,7 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, ui USDR_LOG("2820", USDR_LOG_DEBUG, "Will tune for VCO:%" PRIu64, vco); - int res = lmx2820_calculate_input_chain(st, osc_in, vco, mash_order, 0); + int res = lmx2820_calculate_input_chain(st, osc_in, vco, mash_order, force_mult); if(res) return res; @@ -583,9 +602,9 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, ui return 0; } -int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, uint64_t rfouta, uint64_t rfoutb) +int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb) { - int res = lmx2820_solver(st, osc_in, mash_order, rfouta, rfoutb); + int res = lmx2820_solver(st, osc_in, mash_order, force_mult, rfouta, rfoutb); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_solver() failed, err:%d", res); diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index 36946eeb..6fffd4d2 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -45,6 +45,7 @@ typedef struct lmx2820_state lmx2820_state_t; int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st); int lmx2820_destroy(lmx2820_state_t* st); -int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, uint64_t rfouta, uint64_t rfoutb); +int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); +int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); #endif // LMX2820_H diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index 29d37190..092bef86 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -17,7 +17,7 @@ START_TEST(lmx2820_solver_test1) uint64_t out_freq1 = 45000000; uint64_t out_freq2 = out_freq1; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -28,7 +28,7 @@ START_TEST(lmx2820_solver_test2) uint64_t out_freq1 = 45000000; uint64_t out_freq2 = out_freq1; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -39,11 +39,10 @@ START_TEST(lmx2820_solver_test3) uint64_t out_freq1 = 22600000000ull; uint64_t out_freq2 = out_freq1; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } - START_TEST(lmx2820_solver_test4) { const uint64_t osc_in = 1400000000ull; @@ -51,7 +50,7 @@ START_TEST(lmx2820_solver_test4) uint64_t out_freq1 = 22600000000ull; uint64_t out_freq2 = out_freq1; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -62,7 +61,7 @@ START_TEST(lmx2820_solver_test5) uint64_t out_freq1 = 5600000000ull; uint64_t out_freq2 = out_freq1 >> 3; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -73,7 +72,7 @@ START_TEST(lmx2820_solver_test6) uint64_t out_freq1 = 5600000000ull; uint64_t out_freq2 = out_freq1 << 1; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -84,7 +83,7 @@ START_TEST(lmx2820_solver_test7) uint64_t out_freq1 = 5800000000ull; uint64_t out_freq2 = out_freq1 << 1; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -95,7 +94,40 @@ START_TEST(lmx2820_solver_test8) uint64_t out_freq1 = 20000987000ull; uint64_t out_freq2 = out_freq1 >> 4; - int res = lmx2820_solver(&st, osc_in, mash_order, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test9_force_mult) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 20000987000ull; + uint64_t out_freq2 = out_freq1 >> 4; + + int res = lmx2820_solver(&st, osc_in, mash_order, _i, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test10_mash_order) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 5600000000ull; + uint64_t out_freq2 = out_freq1 >> 3; + + int res = lmx2820_solver(&st, osc_in, _i, 0, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx2820_solver_test11_mash_order) +{ + const uint64_t osc_in = 1400000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 45000000; + uint64_t out_freq2 = out_freq1; + + int res = lmx2820_solver(&st, osc_in, _i, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -117,6 +149,9 @@ Suite * lmx2820_solver_suite(void) tcase_add_test(tc_core, lmx2820_solver_test6); tcase_add_test(tc_core, lmx2820_solver_test7); tcase_add_test(tc_core, lmx2820_solver_test8); + tcase_add_loop_test(tc_core, lmx2820_solver_test9_force_mult, 3, 8); + tcase_add_loop_test(tc_core, lmx2820_solver_test10_mash_order, 0, 4); + tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 0, 4); suite_add_tcase(s, tc_core); return s; From e51c6cda9e7c4a5457fe6aa6b34e5d72f3a2fded Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 27 Mar 2025 18:13:57 +0300 Subject: [PATCH 023/397] Fixes & emprovements + instcal (not not completely ready) --- src/lib/hw/lmx2820/lmx2820.c | 168 ++++++++++++++++++++++++++++++++--- src/lib/hw/lmx2820/lmx2820.h | 14 ++- 2 files changed, 169 insertions(+), 13 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 101aa204..ac664767 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -48,6 +48,9 @@ enum { #define RF_ACCURACY 1.0f #define OUT_DIV_DIAP_MAX (OUT_DIV_LOG2_MAX - OUT_DIV_LOG2_MIN + 1 + 1) +//Pin3 bias capacitor, uF +#define C_BIAS 4.7f + enum { PLL_N_MIN = 12, PLL_N_MAX = 32767, @@ -130,7 +133,6 @@ static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, un } } - assert(1); // should never reach this line return -EINVAL; } @@ -149,10 +151,15 @@ static int lmx2820_reset(lmx2820_state_t* st) uint32_t reg = MAKE_LMX2820_REG_WR(R0, r0); - return lmx2820_spi_post(st, ®, 1); + res = lmx2820_spi_post(st, ®, 1); + if(res) + return res; + + usleep(5); //reset takes <1us + return 0; } -static int lmx2820_calibrate(lmx2820_state_t* st) +static int lmx2820_calibrate(lmx2820_state_t* st, bool set_flag) { uint16_t r0; @@ -160,7 +167,10 @@ static int lmx2820_calibrate(lmx2820_state_t* st) if(res) return res; - r0 |= (uint16_t)1 << FCAL_EN_OFF; + if(set_flag) + r0 |= (uint16_t)1 << FCAL_EN_OFF; + else + r0 &= ~((uint16_t)1 << FCAL_EN_OFF); uint32_t reg = MAKE_LMX2820_REG_WR(R0, r0); @@ -190,6 +200,62 @@ static int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) } } + return -ETIMEDOUT; +} + +int lmx2820_get_temperature(lmx2820_state_t* st, float* value) +{ + if(!value) + return -EINVAL; + + uint16_t r76; + + int res = lmx2820_spi_get(st, R76, &r76); + if(res) + return res; + + int16_t code = (r76 & RB_TEMP_SENS_MSK) >> RB_TEMP_SENS_OFF; + *value = 0.85f * code - 415.0f; + + return 0; +} + +static inline const char* lmx2820_decode_lock_status(uint8_t ld) +{ + switch(ld) + { + case RB_LD_UNLOCKED0: + case RB_LD_UNLOCKED1: return "UNLOCKED"; + case RB_LD_LOCKED: return "LOCKED"; + case RB_LD_INVALID: return "INVALID"; + } + return "UNKNOWN"; +} + +int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status) +{ + if(!status) + return -EINVAL; + + uint16_t r74, r75; + + int res = lmx2820_get_temperature(st, &status->temperature); + res = res ? res : lmx2820_spi_get(st, R74, &r74); + res = res ? res : lmx2820_spi_get(st, R75, &r75); + if(res) + return res; + + status->lock_detect_status = (r74 & RB_LD_MSK) >> RB_LD_OFF; + status->vco_capctrl = (r74 & RB_VCO_CAPCTRL_MSK) >> RB_VCO_CAPCTRL_OFF; + status->vco_sel = (r74 & RB_VCO_SEL_MSK) >> RB_VCO_SEL_OFF; + status->vco_daciset = (r75 & RB_VCO_DACISET_MSK) >> RB_VCO_DACISET_OFF; + + USDR_LOG("2820", USDR_LOG_DEBUG, "STATUS> Temp:%.2fC LOCK:%d(%s) VCO_CAPCTRL:%d VCO_SEL:%d VCO_DACISET:%d", + status->temperature, status->lock_detect_status, + lmx2820_decode_lock_status(status->lock_detect_status), + status->vco_capctrl, status->vco_sel, status->vco_daciset + ); + return 0; } @@ -199,7 +265,41 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ st->subdev = subdev; st->lsaddr = lsaddr; - return lmx2820_reset(st); + int res = lmx2820_reset(st); + if(res) + return res; + + //this list is incompleted + uint32_t regs[] = + { + MAKE_LMX2820_R19(0x109, TEMPSENSE_EN_ENABLED, 0x0), //enable temperature sensor + }; + + res = lmx2820_spi_post(st, regs, sizeof(regs)); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); + return res; + } + + usleep(10); + + lmx2820_stats_t status; + res = lmx2820_read_status(st, &status); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Status check failed, err:%d", res); + return res; + } + + USDR_LOG("2820", USDR_LOG_DEBUG, "Create OK"); + return 0; +} + +int lmx2820_destroy(lmx2820_state_t* st) +{ + USDR_LOG("2820", USDR_LOG_DEBUG, "Destroy OK"); + return 0; } static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, uint64_t vco, unsigned mash_order, unsigned force_mult) @@ -212,7 +312,10 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, unsigned vco_core; res = lmx2820_get_worst_vco_core(vco, mash_order, &vco_core, &min_pll_n); if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "VCO core detection failed [VCO:%" PRIu64 " MASH_ORDER:%d], res=%d", vco, mash_order, res); return res; + } USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " -> VCO_CORE%d PLL_N_MIN:%d", vco, vco_core, min_pll_n); @@ -602,7 +705,7 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un return 0; } -int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb) +static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb, bool use_instcal) { int res = lmx2820_solver(st, osc_in, mash_order, force_mult, rfouta, rfoutb); if(res) @@ -644,10 +747,23 @@ int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsi else cal_clk_div = CAL_CLK_DIV_ALL_OTHER_FOSCIN_VALUES; + uint16_t instcal_dly = 0x1f4; + uint32_t instcal_pll_num = 0; + + if(use_instcal) + { + instcal_dly = (2.5f * C_BIAS / 0.47) * ((double)osc_in / 1E6) / (1 << cal_clk_div); + instcal_pll_num = (double)((uint64_t)1 << 32) * (double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den; + } + + USDR_LOG("2820", USDR_LOG_DEBUG, "REGS> LP_FD_ADJ:%d HP_FD_ADJ:%d CAL_CLK_DIV:%d INSTCAL_DLY:%d INSTCAL_PLL_NUM:%u", LP_fd_adj, HP_fd_adj, cal_clk_div, instcal_dly, instcal_pll_num); + uint32_t regs[] = { MAKE_LMX2820_R79(0, OUTB_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outb_mux, 0x7, 0), MAKE_LMX2820_R78(0, OUTA_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outa_mux), + MAKE_LMX2820_R45(instcal_pll_num), + MAKE_LMX2820_R44(instcal_pll_num >> 16), MAKE_LMX2820_R43((uint16_t)st->lmx2820_input_chain.pll_num), MAKE_LMX2820_R42((uint16_t)(st->lmx2820_input_chain.pll_num >> 16)), MAKE_LMX2820_R39((uint16_t)st->lmx2820_input_chain.pll_den), @@ -660,8 +776,10 @@ int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsi MAKE_LMX2820_R13(0, st->lmx2820_input_chain.pll_r, 0x18), MAKE_LMX2820_R12(0, st->lmx2820_input_chain.mult, 0x8), MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x3), - MAKE_LMX2820_R2 (1, cal_clk_div, 0x1F4, QUICK_RECAL_EN_DISABLED), - MAKE_LMX2820_R1 (0, 0x15E, 1, 0, vco_dblr_engaged ? 1 : 0, 0), + MAKE_LMX2820_R2 (1, cal_clk_div, instcal_dly, QUICK_RECAL_EN_DISABLED), + MAKE_LMX2820_R1 (PHASE_SYNC_EN_NORMAL_OPERATION, 0x15E, LD_VTUNE_EN_VCOCAL_AND_VTUNE_LOCK_DETECT, 0, + vco_dblr_engaged ? INSTCAL_DBLR_EN_VCO_DOUBLER_IS_ENGAGED : INSTCAL_DBLR_EN_NORMAL_OPERATION, + use_instcal ? INSTCAL_EN_ENABLED : INSTCAL_EN_DISABLED), MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_DISABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) }; @@ -674,13 +792,23 @@ int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsi usleep(10000); - res = lmx2820_calibrate(st); + res = lmx2820_calibrate(st, true); if(res) { - USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_calibrate() failed, err:%d", res); + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_calibrate(1) failed, err:%d", res); return res; } + if(use_instcal) + { + res = lmx2820_calibrate(st, false); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_calibrate(0) failed, err:%d", res); + return res; + } + } + res = lmx2820_wait_pll_lock(st, 10000); if(res) { @@ -691,7 +819,25 @@ int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsi return 0; } -int lmx2820_destroy(lmx2820_state_t* st) +/* + * Full tuning, including input circuit calculation OSC_IN->FPD->VCO->RFOUT + */ +int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb) +{ + return lmx2820_tune_internal(st, osc_in, mash_order, force_mult, rfouta, rfoutb, false); +} + + +/* + * Initialize LMX for instant calibration + */ +int lmx2820_instant_calibration_init(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult) { + int res = lmx2820_tune_internal(st, osc_in, mash_order, force_mult, VCO_MIN, VCO_MIN, true); + if(res) + return res; + + USDR_LOG("2820", USDR_LOG_DEBUG, "Device is initialized for the particular phase detector frequency = %.2f", st->lmx2820_input_chain.fpd); + return 0; } diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index 6fffd4d2..1154e1f8 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -3,7 +3,6 @@ #include - struct lmx2820_input_chain_st { uint8_t mash_order; @@ -32,6 +31,15 @@ struct lmx2820_output_chain_st }; typedef struct lmx2820_output_chain_st lmx2820_output_chain_t; +struct lmx2820_stats { + float temperature; + uint16_t vco_sel; + uint16_t vco_capctrl; + uint16_t vco_daciset; + uint16_t lock_detect_status; +}; +typedef struct lmx2820_stats lmx2820_stats_t; + struct lmx2820_state { lldev_t dev; unsigned subdev; @@ -42,10 +50,12 @@ struct lmx2820_state { }; typedef struct lmx2820_state lmx2820_state_t; - int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st); int lmx2820_destroy(lmx2820_state_t* st); +int lmx2820_get_temperature(lmx2820_state_t* st, float* value); +int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status); int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); +int lmx2820_instant_calibration_init(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult); #endif // LMX2820_H From 927048d92ee8e97aa88019fef61eed09c80cb162 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 27 Mar 2025 18:23:44 +0300 Subject: [PATCH 024/397] minor changes --- src/lib/hw/lmx2820/lmx2820.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index ac664767..623ed9b1 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -735,8 +735,6 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned else HP_fd_adj = FCAL_HPFD_ADJ_FPD_GT_200_MHZ; - bool vco_dblr_engaged = st->lmx2820_output_chain.outa_mux == OUTA_MUX_VCO_DOUBLER || st->lmx2820_output_chain.outb_mux == OUTB_MUX_VCO_DOUBLER; - uint8_t cal_clk_div; if(osc_in <= 200000000) cal_clk_div = CAL_CLK_DIV_FOSCIN_LE_200_MHZ; @@ -749,14 +747,21 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned uint16_t instcal_dly = 0x1f4; uint32_t instcal_pll_num = 0; + uint8_t instcal_dblr_en = INSTCAL_DBLR_EN_NORMAL_OPERATION; if(use_instcal) { instcal_dly = (2.5f * C_BIAS / 0.47) * ((double)osc_in / 1E6) / (1 << cal_clk_div); instcal_pll_num = (double)((uint64_t)1 << 32) * (double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den; + + if(st->lmx2820_output_chain.outa_mux == OUTA_MUX_VCO_DOUBLER || st->lmx2820_output_chain.outb_mux == OUTB_MUX_VCO_DOUBLER) + { + instcal_dblr_en = INSTCAL_DBLR_EN_VCO_DOUBLER_IS_ENGAGED; + } } - USDR_LOG("2820", USDR_LOG_DEBUG, "REGS> LP_FD_ADJ:%d HP_FD_ADJ:%d CAL_CLK_DIV:%d INSTCAL_DLY:%d INSTCAL_PLL_NUM:%u", LP_fd_adj, HP_fd_adj, cal_clk_div, instcal_dly, instcal_pll_num); + USDR_LOG("2820", USDR_LOG_DEBUG, "REGS> LP_FD_ADJ:%d HP_FD_ADJ:%d CAL_CLK_DIV:%d INSTCAL_DLY:%d INSTCAL_PLL_NUM:%u INSTCAL_DBLR_EN:%d", + LP_fd_adj, HP_fd_adj, cal_clk_div, instcal_dly, instcal_pll_num, instcal_dblr_en); uint32_t regs[] = { @@ -778,7 +783,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x3), MAKE_LMX2820_R2 (1, cal_clk_div, instcal_dly, QUICK_RECAL_EN_DISABLED), MAKE_LMX2820_R1 (PHASE_SYNC_EN_NORMAL_OPERATION, 0x15E, LD_VTUNE_EN_VCOCAL_AND_VTUNE_LOCK_DETECT, 0, - vco_dblr_engaged ? INSTCAL_DBLR_EN_VCO_DOUBLER_IS_ENGAGED : INSTCAL_DBLR_EN_NORMAL_OPERATION, + instcal_dblr_en, use_instcal ? INSTCAL_EN_ENABLED : INSTCAL_EN_DISABLED), MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_DISABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) }; From d12c9095079e75eb40d84c8baae590f20b0bc6f4 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 28 Mar 2025 18:37:44 +0300 Subject: [PATCH 025/397] instcal implemented. need to test on hardware --- src/lib/hw/lmx2820/lmx2820.c | 415 +++++++++++++++++++++---------- src/lib/hw/lmx2820/lmx2820.h | 6 +- src/utests/lmx2820_solver_test.c | 20 +- 3 files changed, 311 insertions(+), 130 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 623ed9b1..7838aba3 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -86,6 +86,8 @@ static uint64_t FPD_MAX[MASH_ORDER_THIRD_ORDER + 1] = #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define INSTCAL_R0_MASK (((uint16_t)1 << FCAL_EN_OFF) | ((uint16_t)1 << DBLR_CAL_EN_OFF)) + static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count) { int res; @@ -113,12 +115,12 @@ static int lmx2820_spi_get(lmx2820_state_t* obj, uint16_t addr, uint16_t* out) } -static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, unsigned* vco_core, uint16_t* ndiv_min) +static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, unsigned* vco_core, uint16_t* min_pll_n) { - if(!vco_core || !ndiv_min || - vco_freq < VCO_MIN || vco_freq > VCO_MAX || + if( vco_freq < VCO_MIN || vco_freq > VCO_MAX || mash_order > MASH_ORDER_THIRD_ORDER) { + USDR_LOG("2820", USDR_LOG_ERROR, "VCO core detection failed [VCO:%" PRIu64 " MASH_ORDER:%d]", vco_freq, mash_order); return -EINVAL; } @@ -127,8 +129,11 @@ static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, un const vco_core_t r = VCO_CORES[i]; if(vco_freq >= r.freq.min && vco_freq < r.freq.max) { - *vco_core = i + 1; - *ndiv_min = r.ndiv_min[mash_order]; + if(vco_core) + *vco_core = i + 1; + if(min_pll_n) + *min_pll_n = r.ndiv_min[mash_order]; + USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " -> VCO_CORE%d PLL_N_MIN:%d", vco_freq, (i + 1), r.ndiv_min[mash_order]); return 0; } } @@ -302,32 +307,73 @@ int lmx2820_destroy(lmx2820_state_t* st) return 0; } -static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, uint64_t vco, unsigned mash_order, unsigned force_mult) + +static int lmx2820_tune_vco(lmx2820_state_t* st, uint64_t vco) { int res = 0; + lmx2820_input_chain_t * settings = &st->lmx2820_input_chain; - unsigned mult, pll_r_pre, pll_r; + uint16_t min_n_total; + uint16_t max_n_total = PLL_N_MAX + 1; - uint16_t min_pll_n; unsigned vco_core; - res = lmx2820_get_worst_vco_core(vco, mash_order, &vco_core, &min_pll_n); + res = lmx2820_get_worst_vco_core(vco, settings->mash_order, &vco_core, &min_n_total); if(res) - { - USDR_LOG("2820", USDR_LOG_ERROR, "VCO core detection failed [VCO:%" PRIu64 " MASH_ORDER:%d], res=%d", vco, mash_order, res); return res; + + double n_total = (double)vco / settings->fpd; + USDR_LOG("2820", USDR_LOG_DEBUG, "N_total:%.6f", n_total); + + if(n_total < min_n_total || n_total > max_n_total) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Ntotal:%.6f out of range [%u;%u)", n_total, min_n_total, max_n_total); + return -EINVAL; } - USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " -> VCO_CORE%d PLL_N_MIN:%d", vco, vco_core, min_pll_n); + uint16_t pll_n = (uint16_t)n_total; + double pll_frac = n_total - pll_n; + USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_FRAC:%.8f", pll_n, pll_frac); + + uint32_t pll_den = UINT32_MAX; + uint32_t pll_num = pll_frac * pll_den; + double vco_fact = (double)settings->fpd * (pll_n + (double)pll_num / pll_den); - const double min_n_total = min_pll_n; - const double max_n_total = PLL_N_MAX + 1; + double delta = fabs(vco_fact - vco); + USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f Deviation:%.8fHz", pll_n, pll_num, pll_den, vco_fact, delta); + + if(delta > VCO_ACCURACY) + { + USDR_LOG("2820", USDR_LOG_ERROR, "VCO tuning too rough"); + return -EINVAL; + } + + settings->vco_core = vco_core; + settings->pll_n = pll_n; + settings->pll_num = pll_num; + settings->pll_den = pll_den; + settings->fvco = vco_fact; + + return 0; +} + +static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, uint64_t vco, unsigned mash_order, unsigned force_mult) +{ + int res = 0; + unsigned mult, pll_r_pre, pll_r; + + uint16_t min_n_total; + uint16_t max_n_total = PLL_N_MAX + 1; + + res = lmx2820_get_worst_vco_core(vco, mash_order, NULL, &min_n_total); + if(res) + return res; uint64_t fpd_max = FPD_MAX[mash_order]; uint64_t fpd_min = FPD_MIN; fpd_max = MIN(fpd_max, vco / min_n_total); fpd_min = MAX(fpd_min, vco / max_n_total); - USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " NMIN:%.0f NMAX:%.0f FPD_MIN:%" PRIu64 " FPD_MAX:%" PRIu64, + USDR_LOG("2820", USDR_LOG_DEBUG, "VCO:%" PRIu64 " NMIN:%u NMAX:%u FPD_MIN:%" PRIu64 " FPD_MAX:%" PRIu64, vco, min_n_total, max_n_total, fpd_min, fpd_max); bool need_mult = (fosc_in < fpd_min) || force_mult; @@ -445,85 +491,38 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, return -EINVAL; } - double n_total = (double)vco / fpd; - USDR_LOG("2820", USDR_LOG_DEBUG, "N_total:%.6f", n_total); - - if(n_total < min_n_total || n_total > max_n_total) - { - USDR_LOG("2820", USDR_LOG_ERROR, "Ntotal:%.6f out of range [%.0f;%0.f): should never be happen!", n_total, min_n_total, max_n_total); - return -EINVAL; - } - - - uint16_t pll_n = (uint16_t)n_total; - double pll_frac = n_total - pll_n; - USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_FRAC:%.8f", pll_n, pll_frac); - - uint32_t pll_den = UINT32_MAX; - uint32_t pll_num = pll_frac * pll_den; - double vco_fact = (double)fpd * (pll_n + (double)pll_num / pll_den); - - double delta = fabs(vco_fact - vco); - USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f Deviation:%.8fHz", pll_n, pll_num, pll_den, vco_fact, delta); - - if(delta > VCO_ACCURACY) - { - USDR_LOG("2820", USDR_LOG_ERROR, "VCO tuning too rough"); - return -EINVAL; - } - lmx2820_input_chain_t * settings = &st->lmx2820_input_chain; - settings->mash_order = mash_order; - settings->vco_core = vco_core; + settings->fosc_in = fosc_in; settings->osc_2x = osc_2x; + settings->mash_order = mash_order; settings->pll_r_pre = pll_r_pre; settings->mult = mult; settings->pll_r = pll_r; - settings->pll_n = pll_n; - settings->pll_num = pll_num; - settings->pll_den = pll_den; - settings->fvco = vco_fact; settings->fpd = fpd; - USDR_LOG("2820", USDR_LOG_WARNING, "Input circuit res: OSC_IN:%" PRIu64 " OSC_2X:%d PLL_R_PRE:%d MULT:%d PLL_R:%d FPD:%" PRIu64 " PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f", - fosc_in, osc_2x, pll_r_pre, mult, pll_r, fpd, pll_n, pll_num, pll_den, vco_fact); + res = lmx2820_tune_vco(st, vco); + if(res) + return res; + + USDR_LOG("2820", USDR_LOG_WARNING, "Input circuit res: OSC_IN:%" PRIu64 " OSC_2X:%d PLL_R_PRE:%d MULT:%d PLL_R:%d FPD:%.0f PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f", + settings->fosc_in, + settings->osc_2x, + settings->pll_r_pre, + settings->mult, + settings->pll_r, + settings->fpd, + settings->pll_n, + settings->pll_num, + settings->pll_den, + settings->fvco); return 0; - } -int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb) -{ - if(osc_in < OSC_IN_MIN || osc_in > OSC_IN_MAX) - { - USDR_LOG("2820", USDR_LOG_ERROR, "OSC_IN %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", osc_in, (uint64_t)OSC_IN_MIN, (uint64_t)OSC_IN_MAX); - return -EINVAL; - } - - switch(mash_order) - { - case MASH_ORDER_INTEGER_MODE: - case MASH_ORDER_FIRST_ORDER: - case MASH_ORDER_SECOND_ORDER: - case MASH_ORDER_THIRD_ORDER: break; - default: { - USDR_LOG("2820", USDR_LOG_ERROR, "MASH_ORDER %u out of range [%u;%u]", mash_order, (unsigned)MASH_ORDER_INTEGER_MODE, (unsigned)MASH_ORDER_THIRD_ORDER); - return -EINVAL; - } - } - - if(rfouta < OUT_FREQ_MIN || rfouta > OUT_FREQ_MAX) - { - USDR_LOG("2820", USDR_LOG_ERROR, "RF_OUTA %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", rfouta, (uint64_t)OUT_FREQ_MIN, (uint64_t)OUT_FREQ_MAX); - return -EINVAL; - } - if(rfoutb < OUT_FREQ_MIN || rfoutb > OUT_FREQ_MAX) - { - USDR_LOG("2820", USDR_LOG_ERROR, "RF_OUTB %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", rfoutb, (uint64_t)OUT_FREQ_MIN, (uint64_t)OUT_FREQ_MAX); - return -EINVAL; - } +static int lmx2820_solver_prepare(uint64_t rfouta, uint64_t rfoutb, uint64_t* vco, uint8_t* diva, uint8_t* divb, uint8_t* muxa, uint8_t* muxb) +{ uint64_t *rf_max, *rf_min; unsigned mux_max, mux_min; @@ -547,14 +546,13 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un return -EINVAL; } - if(rf_ratio_n > OUT_DIV_DIAP_MAX) { USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT ratio:%d > %d, out of range", rf_ratio_n, (int)OUT_DIV_DIAP_MAX); return -EINVAL; } - UNUSED uint64_t vco, rf_max_fact, rf_min_fact; + UNUSED uint64_t rf_max_fact, rf_min_fact; uint8_t div_max = 1, div_min = 1; if(*rf_max > VCO_MAX) @@ -563,16 +561,16 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un //rf_min may be VCO or VCO/2..7 mux_max = OUTA_MUX_VCO_DOUBLER; - vco = (uint64_t)((double)(*rf_max) / 2 + 0.5); - rf_max_fact = vco << 1; + *vco = (uint64_t)((double)(*rf_max) / 2 + 0.5); + rf_max_fact = *vco << 1; switch(rf_ratio_n) { case 0: rf_min_fact = rf_max_fact; mux_min = OUTA_MUX_VCO_DOUBLER; break; - case 1: rf_min_fact = vco; mux_min = OUTA_MUX_VCO; break; + case 1: rf_min_fact = *vco; mux_min = OUTA_MUX_VCO; break; default: div_min = rf_ratio_n - 1; - rf_min_fact = vco >> div_min; + rf_min_fact = *vco >> div_min; mux_min = OUTA_MUX_CHANNEL_DIVIDER; if(div_min == OUT_DIV_LOG2_MAX) { @@ -591,8 +589,8 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un return -EINVAL; } - vco = MAX((*rf_max) << OUT_DIV_LOG2_MIN, VCO_MIN); - div_max = (uint8_t)ceil(log2((double)vco / (*rf_max))); + *vco = MAX((*rf_max) << OUT_DIV_LOG2_MIN, VCO_MIN); + div_max = (uint8_t)ceil(log2((double)(*vco) / (*rf_max))); div_max = MAX(div_max, OUT_DIV_LOG2_MIN); div_min = div_max + rf_ratio_n; @@ -608,9 +606,9 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un return -EINVAL; } - vco = (*rf_max) << div_max; - rf_max_fact = vco >> div_max; - rf_min_fact = vco >> div_min; + *vco = (*rf_max) << div_max; + rf_max_fact = *vco >> div_max; + rf_min_fact = *vco >> div_min; mux_min = mux_max = OUTA_MUX_CHANNEL_DIVIDER; } else @@ -625,8 +623,8 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un return -EINVAL; } - vco = *rf_max; - rf_max_fact = vco; + *vco = *rf_max; + rf_max_fact = *vco; mux_max = OUTA_MUX_VCO; switch(rf_ratio_n) @@ -634,7 +632,7 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un case 0: rf_min_fact = rf_max_fact; mux_min = OUTA_MUX_VCO; break; default: div_min = rf_ratio_n; - rf_min_fact = vco >> div_min; + rf_min_fact = *vco >> div_min; mux_min = OUTA_MUX_CHANNEL_DIVIDER; if(div_min == OUT_DIV_LOG2_MAX) { @@ -643,60 +641,176 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un } } - USDR_LOG("2820", USDR_LOG_DEBUG, "Will tune for VCO:%" PRIu64, vco); + *diva = (&rfouta == rf_min) ? div_min : div_max; + *divb = (&rfoutb == rf_min) ? div_min : div_max; + *muxa = (&rfouta == rf_min) ? mux_min : mux_max; + *muxb = (&rfoutb == rf_min) ? mux_min : mux_max; - int res = lmx2820_calculate_input_chain(st, osc_in, vco, mash_order, force_mult); - if(res) - return res; + if(*diva < OUT_DIV_LOG2_MIN || *diva > OUT_DIV_LOG2_MAX || *divb < OUT_DIV_LOG2_MIN || *divb > OUT_DIV_LOG2_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT dividers out of range (DIV_A:%d DIV_B:%d) [should never happen]", *diva, *divb); + return -EINVAL; + } + return 0; +} + +static int lmx2820_solver_validate_and_save(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb, uint8_t diva, uint8_t divb, uint8_t muxa, uint8_t muxb) +{ double fvco = st->lmx2820_input_chain.fvco; - double rf_min_res, rf_max_res; + double rfa, rfb; - switch(mux_min) + switch(muxa) { - case OUTA_MUX_VCO_DOUBLER: rf_min_res = fvco * 2.0; break; - case OUTA_MUX_VCO: rf_min_res = fvco; break; - case OUTA_MUX_CHANNEL_DIVIDER: rf_min_res = fvco / ((unsigned)1 << div_min); break; + case OUTA_MUX_VCO_DOUBLER: rfa = fvco * 2.0; break; + case OUTA_MUX_VCO: rfa = fvco; break; + case OUTA_MUX_CHANNEL_DIVIDER: rfa = fvco / ((unsigned)1 << diva); break; default: return -EINVAL; } - switch(mux_max) + switch(muxb) { - case OUTA_MUX_VCO_DOUBLER: rf_max_res = fvco * 2.0; break; - case OUTA_MUX_VCO: rf_max_res = fvco; break; - case OUTA_MUX_CHANNEL_DIVIDER: rf_max_res = fvco / ((unsigned)1 << div_max); break; + case OUTA_MUX_VCO_DOUBLER: rfb = fvco * 2.0; break; + case OUTA_MUX_VCO: rfb = fvco; break; + case OUTA_MUX_CHANNEL_DIVIDER: rfb = fvco / ((unsigned)1 << divb); break; default: return -EINVAL; } - double rfmin_delta = fabs(*rf_min - rf_min_res); - double rfmax_delta = fabs(*rf_max - rf_max_res); + double rfa_delta = fabs(rfouta - rfa); + double rfb_delta = fabs(rfoutb - rfb); - USDR_LOG("2820", USDR_LOG_DEBUG, "RF_MIN:%" PRIu64 "->%.6f Deviation:%f.8Hz", *rf_min, rf_min_res, rfmin_delta); - USDR_LOG("2820", USDR_LOG_DEBUG, "RF_MAX:%" PRIu64 "->%.6f Deviation:%f.8Hz", *rf_max, rf_max_res, rfmax_delta); + USDR_LOG("2820", USDR_LOG_DEBUG, "RF_A:%" PRIu64 "->%.6f Deviation:%.8fHz", rfouta, rfa, rfa_delta); + USDR_LOG("2820", USDR_LOG_DEBUG, "RF_B:%" PRIu64 "->%.6f Deviation:%.8fHz", rfoutb, rfb, rfb_delta); - if(rfmin_delta > RF_ACCURACY || rfmax_delta > RF_ACCURACY) + if(rfa_delta > RF_ACCURACY || rfb_delta > RF_ACCURACY) { USDR_LOG("2820", USDR_LOG_ERROR, "RF tuning too rough"); return -EINVAL; } - if(div_max < OUT_DIV_LOG2_MIN || div_max > OUT_DIV_LOG2_MAX || div_min < OUT_DIV_LOG2_MIN || div_min > OUT_DIV_LOG2_MAX) + lmx2820_output_chain_t * outs = &st->lmx2820_output_chain; + outs->chdiva = diva; + outs->chdivb = divb; + outs->rfouta = rfa; + outs->rfoutb = rfb; + outs->outa_mux = muxa; + outs->outb_mux = muxb; + + return 0; +} + +int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb) +{ + int res = 0; + + if(osc_in < OSC_IN_MIN || osc_in > OSC_IN_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "OSC_IN %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", osc_in, (uint64_t)OSC_IN_MIN, (uint64_t)OSC_IN_MAX); + return -EINVAL; + } + + switch(mash_order) { - USDR_LOG("2820", USDR_LOG_ERROR, "RFOUT dividers out of range (DIV_MIN:%d DIV_MAX:%d) [should never happen]", div_min, div_max); + case MASH_ORDER_INTEGER_MODE: + case MASH_ORDER_FIRST_ORDER: + case MASH_ORDER_SECOND_ORDER: + case MASH_ORDER_THIRD_ORDER: break; + default: { + USDR_LOG("2820", USDR_LOG_ERROR, "MASH_ORDER %u out of range [%u;%u]", mash_order, (unsigned)MASH_ORDER_INTEGER_MODE, (unsigned)MASH_ORDER_THIRD_ORDER); return -EINVAL; } + } + + if(rfouta < OUT_FREQ_MIN || rfouta > OUT_FREQ_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RF_OUTA %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", rfouta, (uint64_t)OUT_FREQ_MIN, (uint64_t)OUT_FREQ_MAX); + return -EINVAL; + } + if(rfoutb < OUT_FREQ_MIN || rfoutb > OUT_FREQ_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RF_OUTB %" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", rfoutb, (uint64_t)OUT_FREQ_MIN, (uint64_t)OUT_FREQ_MAX); + return -EINVAL; + } + + uint64_t vco; + uint8_t diva, divb, muxa, muxb; + + res = lmx2820_solver_prepare(rfouta, rfoutb, &vco, &diva, &divb, &muxa, &muxb); + if(res) + return res; + + res = lmx2820_calculate_input_chain(st, osc_in, vco, mash_order, force_mult); + if(res) + return res; + + res = lmx2820_solver_validate_and_save(st, rfouta, rfoutb, diva, divb, muxa, muxb); + if(res) + return res; lmx2820_output_chain_t * outs = &st->lmx2820_output_chain; - outs->chdiva = (&rfouta == rf_min) ? div_min : div_max; - outs->chdivb = (&rfoutb == rf_min) ? div_min : div_max; - outs->rfouta = (&rfouta == rf_min) ? rf_min_res : rf_max_res; - outs->rfoutb = (&rfoutb == rf_min) ? rf_min_res : rf_max_res; - outs->outa_mux = (&rfouta == rf_min) ? mux_min : mux_max; - outs->outb_mux = (&rfoutb == rf_min) ? mux_min : mux_max; USDR_LOG("2820", USDR_LOG_WARNING, "***** SOLUTION *****"); - USDR_LOG("2820", USDR_LOG_WARNING, "VCO:%.2f OSC_IN:%" PRIu64 " MASH_ORDER:%u VCO_CORE%u", fvco, osc_in, mash_order, st->lmx2820_input_chain.vco_core); + USDR_LOG("2820", USDR_LOG_WARNING, "VCO:%.2f OSC_IN:%" PRIu64 " MASH_ORDER:%u VCO_CORE%u", st->lmx2820_input_chain.fvco, osc_in, mash_order, st->lmx2820_input_chain.vco_core); + USDR_LOG("2820", USDR_LOG_WARNING, "CH_A - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfouta, outs->chdiva - 1, (1 << outs->chdiva), + outs->outa_mux == OUTA_MUX_VCO_DOUBLER ? "OUTA_MUX_VCO_DOUBLER" : (outs->outa_mux == OUTA_MUX_VCO ? "OUTA_MUX_VCO": "OUTA_MUX_CHANNEL_DIVIDER")); + USDR_LOG("2820", USDR_LOG_WARNING, "CH_B - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfoutb, outs->chdivb - 1, (1 << outs->chdivb), + outs->outb_mux == OUTB_MUX_VCO_DOUBLER ? "OUTB_MUX_VCO_DOUBLER" : (outs->outb_mux == OUTB_MUX_VCO ? "OUTB_MUX_VCO": "OUTB_MUX_CHANNEL_DIVIDER")); + + return 0; +} + +int lmx2820_solver_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb) +{ + int res = 0; + + unsigned mash_order = st->lmx2820_input_chain.mash_order; + if(mash_order > MASH_ORDER_THIRD_ORDER) + { + USDR_LOG("2820", USDR_LOG_ERROR, "MASH_ORDER:%u out of range, maybe uninitialized", mash_order); + return -EINVAL; + } + + double fpd = st->lmx2820_input_chain.fpd; + if(fpd < FPD_MIN || fpd > FPD_MAX[mash_order]) + { + USDR_LOG("2820", USDR_LOG_ERROR, "FPD:%.2f out of range, maybe uninitialized", fpd); + return -EINVAL; + } + + const double rfmax = MIN(fpd * (PLL_N_MAX + 1) * 2.0, OUT_FREQ_MAX); + const double rfmin = MAX(fpd * PLL_N_MIN / (1 << OUT_DIV_LOG2_MAX), OUT_FREQ_MIN); + + if(rfouta < rfmin || rfouta > rfmax) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RF_A:%" PRIu64 " out of range [%.2f;%.2f] for FPD:%.2f", rfouta, rfmin, rfmax, fpd); + return -EINVAL; + } + if(rfoutb < rfmin || rfoutb > rfmax) + { + USDR_LOG("2820", USDR_LOG_ERROR, "RF_B:%" PRIu64 " out of range [%.2f;%.2f] for FPD:%.2f", rfoutb, rfmin, rfmax, fpd); + return -EINVAL; + } + + uint64_t vco; + uint8_t diva, divb, muxa, muxb; + + res = lmx2820_solver_prepare(rfouta, rfoutb, &vco, &diva, &divb, &muxa, &muxb); + if(res) + return res; + + res = lmx2820_tune_vco(st, vco); + if(res) + return res; + + res = lmx2820_solver_validate_and_save(st, rfouta, rfoutb, diva, divb, muxa, muxb); + if(res) + return res; + + lmx2820_output_chain_t * outs = &st->lmx2820_output_chain; + + USDR_LOG("2820", USDR_LOG_WARNING, "***** INSTCAL SOLUTION *****"); + USDR_LOG("2820", USDR_LOG_WARNING, "VCO:%.2f", st->lmx2820_input_chain.fvco); USDR_LOG("2820", USDR_LOG_WARNING, "CH_A - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfouta, outs->chdiva - 1, (1 << outs->chdiva), outs->outa_mux == OUTA_MUX_VCO_DOUBLER ? "OUTA_MUX_VCO_DOUBLER" : (outs->outa_mux == OUTA_MUX_VCO ? "OUTA_MUX_VCO": "OUTA_MUX_CHANNEL_DIVIDER")); USDR_LOG("2820", USDR_LOG_WARNING, "CH_B - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfoutb, outs->chdivb - 1, (1 << outs->chdivb), @@ -751,15 +865,13 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned if(use_instcal) { - instcal_dly = (2.5f * C_BIAS / 0.47) * ((double)osc_in / 1E6) / (1 << cal_clk_div); + instcal_dly = (uint16_t)((2.5f * C_BIAS / 0.47) * ((double)osc_in / 1E6) / (1 << cal_clk_div) + 0.5); instcal_pll_num = (double)((uint64_t)1 << 32) * (double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den; - - if(st->lmx2820_output_chain.outa_mux == OUTA_MUX_VCO_DOUBLER || st->lmx2820_output_chain.outb_mux == OUTB_MUX_VCO_DOUBLER) - { - instcal_dblr_en = INSTCAL_DBLR_EN_VCO_DOUBLER_IS_ENGAGED; - } + instcal_dblr_en = INSTCAL_DBLR_EN_VCO_DOUBLER_IS_ENGAGED; } + st->instcal_dly = instcal_dly; //store it for instcal triggering + USDR_LOG("2820", USDR_LOG_DEBUG, "REGS> LP_FD_ADJ:%d HP_FD_ADJ:%d CAL_CLK_DIV:%d INSTCAL_DLY:%d INSTCAL_PLL_NUM:%u INSTCAL_DBLR_EN:%d", LP_fd_adj, HP_fd_adj, cal_clk_div, instcal_dly, instcal_pll_num, instcal_dblr_en); @@ -846,3 +958,50 @@ int lmx2820_instant_calibration_init(lmx2820_state_t* st, uint64_t osc_in, unsig return 0; } + +/* + * Instant tuning - phase detector freq == invar. + * Func lmx2820_instant_calibration_init MUST be called formerly. + */ +int lmx2820_tune_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb) +{ + int res = lmx2820_solver_instcal(st, rfouta, rfoutb); + if(res) + return res; + + const uint32_t instcal_pll_num = (double)((uint64_t)1 << 32) * (double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den; + + uint16_t r0; + res = lmx2820_spi_get(st, R0, &r0); + if(res) + return res; + + r0 &= ~INSTCAL_R0_MASK; + + uint32_t regs[] = + { + MAKE_LMX2820_R79(0, OUTB_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outb_mux, 0x7, 0), + MAKE_LMX2820_R78(0, OUTA_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outa_mux), + MAKE_LMX2820_R45(instcal_pll_num), + MAKE_LMX2820_R44(instcal_pll_num >> 16), + MAKE_LMX2820_R43((uint16_t)st->lmx2820_input_chain.pll_num), + MAKE_LMX2820_R42((uint16_t)(st->lmx2820_input_chain.pll_num >> 16)), + MAKE_LMX2820_R39((uint16_t)st->lmx2820_input_chain.pll_den), + MAKE_LMX2820_R38((uint16_t)(st->lmx2820_input_chain.pll_den >> 16)), + MAKE_LMX2820_R36(0, st->lmx2820_input_chain.pll_n), + MAKE_LMX2820_R32(1, st->lmx2820_output_chain.chdivb - 1, st->lmx2820_output_chain.chdiva - 1, 1), + MAKE_LMX2820_REG_WR(R0, r0) + }; + + res = lmx2820_spi_post(st, regs, sizeof(regs)); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); + return res; + } + + //no need to wait PLL lock, but should wait instcal_dly us + usleep(st->instcal_dly); + + return 0; +} diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index 1154e1f8..2fd6f784 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -45,17 +45,21 @@ struct lmx2820_state { unsigned subdev; unsigned lsaddr; + uint16_t instcal_dly; lmx2820_input_chain_t lmx2820_input_chain; lmx2820_output_chain_t lmx2820_output_chain; }; typedef struct lmx2820_state lmx2820_state_t; +int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); +int lmx2820_solver_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb); + int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st); int lmx2820_destroy(lmx2820_state_t* st); int lmx2820_get_temperature(lmx2820_state_t* st, float* value); int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status); -int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); int lmx2820_instant_calibration_init(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult); +int lmx2820_tune_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb); #endif // LMX2820_H diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index 092bef86..5eab6301 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -1,3 +1,4 @@ +#include #include #include "lmx2820/lmx2820.h" @@ -131,6 +132,23 @@ START_TEST(lmx2820_solver_test11_mash_order) ck_assert_int_eq( res, 0 ); } +START_TEST(lmx2820_solver_test12_instcal) +{ + const uint64_t osc_in = 1400000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 45000000ull << 8; + uint64_t out_freq2 = out_freq1 >> 3; + + int res = lmx2820_solver(&st, osc_in, 0, 0, 5650000000ull, 5650000000ull); + ck_assert_int_eq( res, 0 ); + + fprintf(stderr, "Calibrating for INSTCAL, fixing at FPD:%.2f\n", st.lmx2820_input_chain.fpd); + + res = lmx2820_solver_instcal(&st, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + + Suite * lmx2820_solver_suite(void) { Suite *s; @@ -140,7 +158,6 @@ Suite * lmx2820_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, lmx2820_solver_test1); tcase_add_test(tc_core, lmx2820_solver_test2); tcase_add_test(tc_core, lmx2820_solver_test3); @@ -152,6 +169,7 @@ Suite * lmx2820_solver_suite(void) tcase_add_loop_test(tc_core, lmx2820_solver_test9_force_mult, 3, 8); tcase_add_loop_test(tc_core, lmx2820_solver_test10_mash_order, 0, 4); tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 0, 4); + tcase_add_test(tc_core, lmx2820_solver_test12_instcal); suite_add_tcase(s, tc_core); return s; From 4a8f6f221b0404003f417c5461c6f5045c3a08b6 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 28 Mar 2025 18:48:11 +0300 Subject: [PATCH 026/397] minor change --- src/lib/hw/lmx2820/lmx2820.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 7838aba3..f51e3ede 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -866,7 +866,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned if(use_instcal) { instcal_dly = (uint16_t)((2.5f * C_BIAS / 0.47) * ((double)osc_in / 1E6) / (1 << cal_clk_div) + 0.5); - instcal_pll_num = (double)((uint64_t)1 << 32) * (double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den; + instcal_pll_num = (double)((uint64_t)1 << 32) * ((double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den); instcal_dblr_en = INSTCAL_DBLR_EN_VCO_DOUBLER_IS_ENGAGED; } @@ -879,8 +879,8 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned { MAKE_LMX2820_R79(0, OUTB_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outb_mux, 0x7, 0), MAKE_LMX2820_R78(0, OUTA_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outa_mux), - MAKE_LMX2820_R45(instcal_pll_num), - MAKE_LMX2820_R44(instcal_pll_num >> 16), + MAKE_LMX2820_R45((uint16_t)instcal_pll_num), + MAKE_LMX2820_R44((uint16_t)(instcal_pll_num >> 16)), MAKE_LMX2820_R43((uint16_t)st->lmx2820_input_chain.pll_num), MAKE_LMX2820_R42((uint16_t)(st->lmx2820_input_chain.pll_num >> 16)), MAKE_LMX2820_R39((uint16_t)st->lmx2820_input_chain.pll_den), @@ -969,7 +969,7 @@ int lmx2820_tune_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb) if(res) return res; - const uint32_t instcal_pll_num = (double)((uint64_t)1 << 32) * (double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den; + const uint32_t instcal_pll_num = (double)((uint64_t)1 << 32) * ((double)st->lmx2820_input_chain.pll_num / st->lmx2820_input_chain.pll_den); uint16_t r0; res = lmx2820_spi_get(st, R0, &r0); @@ -982,8 +982,8 @@ int lmx2820_tune_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb) { MAKE_LMX2820_R79(0, OUTB_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outb_mux, 0x7, 0), MAKE_LMX2820_R78(0, OUTA_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outa_mux), - MAKE_LMX2820_R45(instcal_pll_num), - MAKE_LMX2820_R44(instcal_pll_num >> 16), + MAKE_LMX2820_R45((uint16_t)instcal_pll_num), + MAKE_LMX2820_R44((uint16_t)(instcal_pll_num >> 16)), MAKE_LMX2820_R43((uint16_t)st->lmx2820_input_chain.pll_num), MAKE_LMX2820_R42((uint16_t)(st->lmx2820_input_chain.pll_num >> 16)), MAKE_LMX2820_R39((uint16_t)st->lmx2820_input_chain.pll_den), From bd429aaaeae1760e65cbc5230944c9b7ddbab2a8 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 28 Mar 2025 19:14:26 +0300 Subject: [PATCH 027/397] fix R0 reg mask for instcal --- src/lib/hw/lmx2820/lmx2820.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index f51e3ede..26f20955 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -86,7 +86,7 @@ static uint64_t FPD_MAX[MASH_ORDER_THIRD_ORDER + 1] = #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define INSTCAL_R0_MASK (((uint16_t)1 << FCAL_EN_OFF) | ((uint16_t)1 << DBLR_CAL_EN_OFF)) +#define INSTCAL_R0_MASK (((uint16_t)1 << FCAL_EN_OFF) | ((uint16_t)1 << DBLR_CAL_EN_OFF) | ((uint16_t)1 << INSTCAL_SKIP_ACAL_OFF)) static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count) { From 33d3010fb2ba900e2cd83206450bac8c841fe2d3 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 31 Mar 2025 18:02:13 +0300 Subject: [PATCH 028/397] ++comments (intermediate commit, amend it later) --- src/lib/hw/lmx2820/lmx2820.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 26f20955..6cb8876a 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -907,6 +907,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned return res; } + //Wait 10 ms to allow the internal LDOs to power up. usleep(10000); res = lmx2820_calibrate(st, true); From 4002c620c72be99948168c7fd009aa9c8e349a6f Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 31 Mar 2025 19:42:49 +0300 Subject: [PATCH 029/397] First try to tune LMK05318 --- .../device/ext_simplesync/ext_simplesync.c | 2 +- src/lib/device/pe_sync/pe_sync.c | 23 +++++++++ src/lib/hw/lmk05318/lmk05318.c | 48 +++++++++---------- src/lib/hw/lmk05318/lmk05318.h | 2 +- src/utests/lmk05318_solver_test.c | 35 +++++++++++++- 5 files changed, 83 insertions(+), 27 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index e2693c8f..19c339cc 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -88,7 +88,7 @@ int board_ext_simplesync_init(lldev_t dev, xo.doubler_enabled = true; xo.fdet_bypass = true; xo.fref = 26000000; - xo.input_divider_flag = 0; + xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_out_config_t cfg[4]; diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 3a73dcd0..1b8f1123 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -223,6 +223,29 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // OUT7: Dual CMOS 1 Hz // res = res ? res : lmk05318_create() + if(res) + return res; + + lmk05318_xo_settings_t xo; + xo.fref = 25000000; + xo.doubler_enabled = true; + xo.fdet_bypass = false; + xo.pll1_fref_rdiv = 1; + xo.type = XO_CMOS; + + const int out_accuracy = 2; + lmk05318_out_config_t lmk05318_outs_cfg[8]; + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 0, 125000000, out_accuracy, out_accuracy, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 1, 125000000, out_accuracy, out_accuracy, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 2, 250000000, out_accuracy, out_accuracy, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 3, 250000000, out_accuracy, out_accuracy, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 4, 156250000, out_accuracy, out_accuracy, false, OUT_OFF); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 5, 156250000, out_accuracy, out_accuracy, false, OUT_OFF); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, 10000000, out_accuracy, out_accuracy, false, LVCMOS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, 1, out_accuracy, out_accuracy, false, LVCMOS); + + res = res ? res : lmk05318_create_ex(dev, 0, I2C_ADDR_LMK05318B, &xo, false, lmk05318_outs_cfg, 8, &d->gen); + return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 87c31144..9c4cf9f0 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -112,6 +112,20 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } + // Reset + uint32_t regs[] = { + lmk05318_rom[0] | (1 << RESET_SW_OFF), + lmk05318_rom[0] | (0 << RESET_SW_OFF), + + MAKE_LMK05318_PLL1_CTRL0(0), + MAKE_LMK05318_PLL1_CTRL0(1), + MAKE_LMK05318_PLL1_CTRL0(0), + + }; + res = lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs)); + if (res) + return res; + // res = lmk05318_set_xo_fref(out); if(res) @@ -127,29 +141,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } - res = lmk05318_solver(out, out_ports_cfg, out_ports_len, false); + res = lmk05318_solver(out, out_ports_cfg, out_ports_len, false /*dry_run*/); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d solving output frequencies", res); return res; } - // Reset - uint32_t regs[] = { - lmk05318_rom[0] | (1 << RESET_SW_OFF), - lmk05318_rom[0] | (0 << RESET_SW_OFF), - - MAKE_LMK05318_XO_CONFIG(xo->input_divider_flag > 1 ? 1 : 0), - - MAKE_LMK05318_PLL1_CTRL0(0), - MAKE_LMK05318_PLL1_CTRL0(1), - MAKE_LMK05318_PLL1_CTRL0(0), - - }; - res = lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); return 0; } @@ -207,7 +205,7 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int out->xo.fref = 0; out->xo.doubler_enabled = false; out->xo.fdet_bypass = false; - out->xo.type = XO_TYPE_DC_DIFF_EXT; + out->xo.type = XO_CMOS; USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); return 0; @@ -357,11 +355,13 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) { - int res = lmk05318_set_xo_fref(d); - if(res) - return res; + if(d->xo.pll1_fref_rdiv < APLL1_DIVIDER_MIN || d->xo.pll1_fref_rdiv > APLL1_DIVIDER_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APPL1_RDIV:%d out of range [%d;%d]", d->xo.pll1_fref_rdiv, (int)APLL1_DIVIDER_MIN, (int)APLL1_DIVIDER_MAX); + return -EINVAL; + } - unsigned fref = (d->xo.fref / APLL1_DIVIDER_MAX) * (d->xo.doubler_enabled ? 2 : 1); + unsigned fref = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); uint64_t fvco = VCO_APLL1; unsigned n = fvco / fref; uint64_t num = (fvco - n * (uint64_t)fref) * (1ull << 40) / fref; @@ -370,7 +370,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) uint32_t regs[] = { MAKE_LMK05318_PLL1_CTRL0(1), - MAKE_LMK05318_XO_CONFIG(APLL1_DIVIDER_MAX - 1), + MAKE_LMK05318_XO_CONFIG(d->xo.pll1_fref_rdiv - 1), MAKE_LMK05318_PLL1_MODE(dpll_mode ? 1 : 0), MAKE_LMK05318_PLL1_NDIV_BY0(n), MAKE_LMK05318_PLL1_NDIV_BY1(n), @@ -382,7 +382,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) MAKE_LMK05318_PLL1_CTRL0(0), }; - res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); if (res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index be7cf79d..97b92a60 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -22,7 +22,7 @@ typedef enum xo_input_type xo_input_type_t; struct lmk05318_xo_settings { - unsigned input_divider_flag; + unsigned pll1_fref_rdiv; uint32_t fref; xo_input_type_t type; bool doubler_enabled; diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index c8cdf7b8..e82f3237 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -116,6 +116,38 @@ START_TEST(lmk05318_solver_test4) ck_assert_int_eq( res, 0 ); } +START_TEST(lmk05318_solver_test5) +{ +/* // TODO: Initialize LMK05318B + // XO: 25Mhz + // + // OUT0: LVDS 125.000 Mhz + // OUT1: LVDS 125.000 Mhz + // OUT2: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 + // OUT3: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 + // OUT4: LVDS OFF 156.250 Mhz | OFF by default + // OUT5: LVDS OFF 156.250 Mhz | OFF by default + // OUT6: Dual CMOS 10.000 Mhz + // OUT7: Dual CMOS 1 Hz + // res = res ? res : lmk05318_create() + */ + + int res = 0; + res = res ? res : lmk05318_port_request(cfg, 0, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 1, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 2, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 3, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 4, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 10000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); + ck_assert_int_eq( res, 0 ); + + res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); + ck_assert_int_eq( res, 0 ); + +} + Suite * lmk05318_solver_suite(void) { Suite *s; @@ -129,7 +161,8 @@ Suite * lmk05318_solver_suite(void) //tcase_add_test(tc_core, lmk05318_solver_test1); //tcase_add_test(tc_core, lmk05318_solver_test2); //tcase_add_test(tc_core, lmk05318_solver_test3); - tcase_add_test(tc_core, lmk05318_solver_test4); + //tcase_add_test(tc_core, lmk05318_solver_test4); + tcase_add_test(tc_core, lmk05318_solver_test5); suite_add_tcase(s, tc_core); return s; From 216a1ce7d8ee7236c90e9cf55bd7c5ed5d9f7348 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 31 Mar 2025 20:35:28 +0300 Subject: [PATCH 030/397] reset() added --- src/lib/hw/lmk05318/lmk05318.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 9c4cf9f0..f8d94a16 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -84,6 +84,24 @@ int lmk05318_reg_wr_n(lmk05318_state_t* d, const uint32_t* regs, unsigned count) return 0; } +static int lmk05318_reset(lmk05318_state_t* out) +{ + uint8_t reg_ctrl; + const uint8_t mask = ((uint8_t)1 << RESET_SW_OFF); + + int res = lmk05318_reg_rd(out, DEV_CTL, ®_ctrl); + if(res) + return res; + + uint32_t regs[] = + { + MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl | mask), + MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl & ~mask), + }; + + return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; +} + int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk05318_xo_settings_t* xo, bool dpll_mode, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, @@ -111,7 +129,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, if ( dummy[3] != 0x10 || dummy[2] != 0x0b || dummy[1] != 0x35 || dummy[0] != 0x42 ) { return -ENODEV; } - +/* // Reset uint32_t regs[] = { lmk05318_rom[0] | (1 << RESET_SW_OFF), @@ -125,8 +143,14 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, res = lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs)); if (res) return res; +*/ + res = lmk05318_reset(out); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_reset()", res); + return res; + } - // res = lmk05318_set_xo_fref(out); if(res) { From 96e1211f56cb7348705aa9e92222c567e4543063 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 31 Mar 2025 23:09:30 +0300 Subject: [PATCH 031/397] minor but valueable changes --- src/lib/hw/lmk05318/lmk05318.c | 85 ++++++++++++++-------------------- 1 file changed, 36 insertions(+), 49 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index f8d94a16..bf5e8267 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -84,7 +84,7 @@ int lmk05318_reg_wr_n(lmk05318_state_t* d, const uint32_t* regs, unsigned count) return 0; } -static int lmk05318_reset(lmk05318_state_t* out) +static int lmk05318_softreset(lmk05318_state_t* out) { uint8_t reg_ctrl; const uint8_t mask = ((uint8_t)1 << RESET_SW_OFF); @@ -129,27 +129,6 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, if ( dummy[3] != 0x10 || dummy[2] != 0x0b || dummy[1] != 0x35 || dummy[0] != 0x42 ) { return -ENODEV; } -/* - // Reset - uint32_t regs[] = { - lmk05318_rom[0] | (1 << RESET_SW_OFF), - lmk05318_rom[0] | (0 << RESET_SW_OFF), - - MAKE_LMK05318_PLL1_CTRL0(0), - MAKE_LMK05318_PLL1_CTRL0(1), - MAKE_LMK05318_PLL1_CTRL0(0), - - }; - res = lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; -*/ - res = lmk05318_reset(out); - if(res) - { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_reset()", res); - return res; - } res = lmk05318_set_xo_fref(out); if(res) @@ -172,6 +151,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } + res = lmk05318_softreset(out); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_softreset()", res); + return res; + } + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); return 0; } @@ -320,14 +306,14 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned } uint32_t regs[] = { - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), - MAKE_LMK05318_PLL2_CTRL2(pd2 - 1, pd1 - 1), - MAKE_LMK05318_PLL2_NDIV_BY0(n), - MAKE_LMK05318_PLL2_NDIV_BY1(n), - MAKE_LMK05318_PLL2_NUM_BY0(num), - MAKE_LMK05318_PLL2_NUM_BY1(num), - MAKE_LMK05318_PLL2_NUM_BY2(num), - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), //R100 + MAKE_LMK05318_PLL2_CTRL2(pd2 - 1, pd1 - 1), //R102 + MAKE_LMK05318_PLL2_NDIV_BY0(n), //R135 + MAKE_LMK05318_PLL2_NDIV_BY1(n), //R134 + MAKE_LMK05318_PLL2_NUM_BY0(num), //R138 + MAKE_LMK05318_PLL2_NUM_BY1(num), //R137 + MAKE_LMK05318_PLL2_NUM_BY2(num), //R136 + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), //R100 }; res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); @@ -351,6 +337,12 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) return -EINVAL; } + if(d->xo.pll1_fref_rdiv < APLL1_DIVIDER_MIN || d->xo.pll1_fref_rdiv > APLL1_DIVIDER_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APPL1_RDIV:%d out of range [%d;%d]", d->xo.pll1_fref_rdiv, (int)APLL1_DIVIDER_MIN, (int)APLL1_DIVIDER_MAX); + return -EINVAL; + } + int xo_type_raw; switch((int)xo_type) { @@ -366,8 +358,9 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) } uint32_t regs[] = { - MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0), - MAKE_LMK05318_XO_CLKCTL2(xo_type_raw) + MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0), //R42 + MAKE_LMK05318_XO_CLKCTL2(xo_type_raw), //R43 + MAKE_LMK05318_XO_CONFIG(d->xo.pll1_fref_rdiv - 1), //R44 }; int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); @@ -377,14 +370,9 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) return 0; } +//R74, int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) { - if(d->xo.pll1_fref_rdiv < APLL1_DIVIDER_MIN || d->xo.pll1_fref_rdiv > APLL1_DIVIDER_MAX) - { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APPL1_RDIV:%d out of range [%d;%d]", d->xo.pll1_fref_rdiv, (int)APLL1_DIVIDER_MIN, (int)APLL1_DIVIDER_MAX); - return -EINVAL; - } - unsigned fref = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); uint64_t fvco = VCO_APLL1; unsigned n = fvco / fref; @@ -393,17 +381,16 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 "\n", fvco, n, num); uint32_t regs[] = { - MAKE_LMK05318_PLL1_CTRL0(1), - MAKE_LMK05318_XO_CONFIG(d->xo.pll1_fref_rdiv - 1), - MAKE_LMK05318_PLL1_MODE(dpll_mode ? 1 : 0), - MAKE_LMK05318_PLL1_NDIV_BY0(n), - MAKE_LMK05318_PLL1_NDIV_BY1(n), - MAKE_LMK05318_PLL1_NUM_BY0(num), - MAKE_LMK05318_PLL1_NUM_BY1(num), - MAKE_LMK05318_PLL1_NUM_BY2(num), - MAKE_LMK05318_PLL1_NUM_BY3(num), - MAKE_LMK05318_PLL1_NUM_BY4(num), - MAKE_LMK05318_PLL1_CTRL0(0), + MAKE_LMK05318_PLL1_CTRL0(1), //R74 + MAKE_LMK05318_PLL1_MODE(dpll_mode ? 1 : 0), //R116 + MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 + MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 + MAKE_LMK05318_PLL1_NUM_BY0(num), //R114 + MAKE_LMK05318_PLL1_NUM_BY1(num), //R113 + MAKE_LMK05318_PLL1_NUM_BY2(num), //R112 + MAKE_LMK05318_PLL1_NUM_BY3(num), //R111 + MAKE_LMK05318_PLL1_NUM_BY4(num), //R110 + MAKE_LMK05318_PLL1_CTRL0(0), //R74 }; int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); From f4e82f801f3681bece00eff1eca07c9a3ea953a5 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 1 Apr 2025 13:04:32 +0400 Subject: [PATCH 032/397] pe_sync: fix SPI / I2C settings --- src/lib/device/pe_sync/pe_sync.c | 60 +++++++++++++++++++++++------ src/lib/device/pe_sync/sync_const.h | 4 +- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 1b8f1123..c53c6d8d 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -28,11 +28,17 @@ // [6] 24bit 20Mhz AD5662 WR DAC enum i2c_addrs { - I2C_ADDR_LMK05318B = 0x65, + I2C_ADDR_LMK05318B = 0x64, + I2C_ADDR_LP87524 = 0x60, }; enum BUSIDX_I2C { - I2C_BUS_LMK05318B = MAKE_LSOP_I2C_ADDR(0, 0, 0x67), + I2C_BUS_LMK05318B = MAKE_LSOP_I2C_ADDR(0, 0, I2C_ADDR_LMK05318B), + + I2C_BUS_LMK1D1208I_LCK = MAKE_LSOP_I2C_ADDR(0, 1, 0x68), + I2C_BUS_LMK1D1208I_LRF = MAKE_LSOP_I2C_ADDR(0, 1, 0x69), + + I2C_BUS_LP87524 = MAKE_LSOP_I2C_ADDR(1, 0, I2C_ADDR_LP87524), SPI_INREF_DAC = 0, SPI_OCXO_DAC = 1, @@ -53,7 +59,7 @@ const usdr_dev_param_constant_t s_params_pe_sync_rev000[] = { { DNLL_RFE_COUNT, 0 }, { DNLL_TFE_COUNT, 0 }, { DNLL_IDX_REGSP_COUNT, 0 }, - { DNLL_IRQ_COUNT, 16 }, + { DNLL_IRQ_COUNT, 10 }, // low level buses { "/ll/irq/0/core", USDR_MAKE_COREID(USDR_CS_AUX, USDR_AC_PIC32_PCI) }, @@ -157,12 +163,19 @@ static void usdr_device_pe_sync_destroy(pdevice_t udev) usdr_device_base_destroy(udev); } +static int i2c_reg_rd8(lldev_t dev, unsigned lsaddr, uint8_t reg, uint8_t* val) +{ + uint8_t addr[1] = { reg }; + return lowlevel_ls_op(dev, 0, USDR_LSOP_I2C_DEV, lsaddr, 1, val, 1, addr); +} + static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const char** devparam, const char** devval) { struct dev_pe_sync *d = (struct dev_pe_sync *)udev; lldev_t dev = d->base.dev; int res = 0; - uint32_t v = 0; + uint32_t v = 0, s0 = 0, s1 = 0, s2 = 0, s3 = 0; + uint8_t r = 0, r4 = 0, r5 = 0; if (getenv("USDR_BARE_DEV")) { USDR_LOG("SYNC", USDR_LOG_WARNING, "USDR_BARE_DEV is set, skipping initialization!\n"); @@ -182,18 +195,28 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : dev_gpo_set(dev, IGPO_SY1_CTRL, 3); // Enable LMX2820 1 // gpo_gen_ctrl[0] -- En LDO for LMK05318B - // gpo_gen_ctrl[1] -- PD for LMK05318B + // gpo_gen_ctrl[1] -- PDN for LMK05318B // gpo_gen_ctrl[2] -- En LDO for OCXO and OCXO DAC // gpo_gen_ctrl[3] -- En distribution buffer REFCLK // gpo_gen_ctrl[4] -- En distribution buffer 1PPS - res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (1 << 0) | (1 << 2)); + // gpo_gen_ctrl[5] -- clk_gpio[0] + // gpo_gen_ctrl[6] -- clk_gpio[1] + // gpo_gen_ctrl[7] -- clk_gpio[2] + // res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (0 << 0) | (0 << 1) | (1 << 2) | (0 << 5)); + // usleep(1000); + // res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (1 << 0) | (0 << 1) | (1 << 2) | (1 << 5)); + // usleep(25000); + res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 5) | (1 << 3) | (1 << 4)); // gpo_distrib_ctrl[0] -- En global LDO for all distribution logic // gpo_distrib_ctrl[2:1] -- En LDO for LMX1204/LMX1214 // gpo_distrib_ctrl[3] -- 0 - buffers LMK1D1208I disable, 1 - en // gpo_distrib_ctrl[4] -- En LDO FCLK4..0 CMOS buffers // gpo_distrib_ctrl[5] -- 0 - internal path, 1 - external LO/REFCLK/SYSREF - res = res ? res : dev_gpo_set(dev, IGPO_DISTRIB_CTRL, (1 << 0)); + res = res ? res : dev_gpo_set(dev, IGPO_DISTRIB_CTRL, (1 << 0) /* | (15 << 1) */ ); + + // Wait for all LDOs to settle + usleep(200000); // gpo_led_ctrl[0] -- LEDG[0] // gpo_led_ctrl[1] -- LEDR[0] @@ -205,10 +228,25 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // gpo_led_ctrl[7] -- LEDR[3] res = res ? res : dev_gpo_set(dev, IGPO_LED_CTRL, 0xff); - usleep(1000); - res = res ? res : dev_gpi_get32(dev, IGPI_STAT, &v); - USDR_LOG("SYNC", USDR_LOG_WARNING, "STAT = %08x\n", v); + res = res ? res : i2c_reg_rd8(dev, I2C_BUS_LP87524, 0x01, &r); + + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX2820_0, 0x9c0000, &s0); + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX2820_1, 0x9c0000, &s1); + + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1204, 0x176040, NULL); //Enable MUXOUT as SPI readback + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1204, 0xA10000, &s2); + + // TODO check LMX1214 readback settings + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1214, 0x560004, NULL); //Enable MUXOUT_EN_OVRD + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1214, 0x176000, NULL); //Enable MUXOUT + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1214, 0xCF0000, &s3); + + res = res ? res : i2c_reg_rd8(dev, I2C_BUS_LMK1D1208I_LCK, 0x05, &r4); + res = res ? res : i2c_reg_rd8(dev, I2C_BUS_LMK1D1208I_LRF, 0x05, &r5); + + USDR_LOG("SYNC", USDR_LOG_WARNING, "STAT=%08x LP87524_OTP=%02x LMS2820[0/1]=%04x/%04x LMX1204/LMX1214=%04x/%04x LMK1D1208I_LCK/LRF=%02x/%02x\n", + v, r, s0, s1, s2, s3, r4, r5); // TODO: Initialize LMK05318B // XO: 25Mhz @@ -244,7 +282,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, 10000000, out_accuracy, out_accuracy, false, LVCMOS); res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, 1, out_accuracy, out_accuracy, false, LVCMOS); - res = res ? res : lmk05318_create_ex(dev, 0, I2C_ADDR_LMK05318B, &xo, false, lmk05318_outs_cfg, 8, &d->gen); + res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, false, lmk05318_outs_cfg, 8, &d->gen); return res; } diff --git a/src/lib/device/pe_sync/sync_const.h b/src/lib/device/pe_sync/sync_const.h index 6bdbe234..2d949dcd 100644 --- a/src/lib/device/pe_sync/sync_const.h +++ b/src/lib/device/pe_sync/sync_const.h @@ -38,8 +38,8 @@ enum sync_base_regs { enum sync_base_ints { INT_SPI_0 = 0, - INT_SPI_1 = 2, - INT_SPI_2 = 3, + INT_SPI_1 = 1, + INT_SPI_2 = 2, INT_SPI_3 = 3, INT_SPI_4 = 4, INT_SPI_5 = 5, From 156df08b96560e9c582be34c92b76709210ad36c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 1 Apr 2025 23:08:21 +0300 Subject: [PATCH 033/397] init() added - dump decomposed --- src/lib/hw/lmk05318/lmk05318.c | 224 ++++++++++++++++++++++++++++++ src/lib/hw/lmk05318/lmk05318.yaml | 59 +++++++- 2 files changed, 282 insertions(+), 1 deletion(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index bf5e8267..876775b3 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -102,6 +102,223 @@ static int lmk05318_softreset(lmk05318_state_t* out) return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; } +static int lmk05318_init(lmk05318_state_t* d) +{ + uint32_t regs[] = + { + MAKE_LMK05318_DEV_CTL(0,0,0,1,1), //R12 + + MAKE_LMK05318_INT_FLAG_POL0(1,1,1,1), //R17 + + MAKE_LMK05318_INT_FLAG_POL1(1,1,1,1,1,1,1,1), //R18 + + MAKE_LMK05318_INT_FLAG0(0,1,0,0), //R19 + MAKE_LMK05318_INT_FLAG1(0,0,1,0,0,0,0,0), //R20 + MAKE_LMK05318_MUTELVL1(1,1,1,1), //R23 + MAKE_LMK05318_MUTELVL2(1,1,1,1), //R24 + MAKE_LMK05318_OUT_MUTE(0,0,0,0,0,0,0,0), //R25 + + MAKE_LMK05318_GPIO_OUT(1,1), //R36 + + MAKE_LMK05318_SPARE_NVMBASE2_BY2(1,0), //R39 + + MAKE_LMK05318_SPARE_NVMBASE2_BY1(1,1,0), //R40 + + MAKE_LMK05318_REF_CLKCTL1(0,0,1,0), //R45 + + MAKE_LMK05318_REF_CLKCTL2(SECREF_TYPE_AC_DIFF_EXT, PRIREF_TYPE_AC_DIFF_EXT), //R46 + + MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 +++++++++++++ + MAKE_LMK05318_STAT0_SEL(0x50), //R48 + + MAKE_LMK05318_STAT1_SEL(0x4a), //R49 + + MAKE_LMK05318_PREDRIVER(0x08), //R68 + + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1,0), //R80 + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY0(0x0a), //R81 + 0x005200, //R82 BAW LOCKDET/UNLOCKDET begin + 0x005307, + 0x00549E, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D07, + 0x005E9E, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, //R99 BAW LOCKDET/UNLOCKDET end + MAKE_LMK05318_PLL2_CTRL1(0x01), //R101 + + MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 + + MAKE_LMK05318_PLL2_CALCTRL0(0x01), //R105 0x1 = 3ms + + MAKE_LMK05318_PLL1_MASHCTRL(0, 0x03), //R115 0x3 = APLL1 mash_order3 + + MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm + + MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm + + MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm + + MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 + + MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm + + MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm + + MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm + + MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF + + MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 3.3ms + + 0x00A0FC, //R160 MEMADR ? + +#ifdef LMK05380_DPLL_EN + 0x00B9F5, //R185 DPLL_REF settings ??? + 0x00BA01, //R186 DPLL REF Tuning history timer ??? +#endif + MAKE_LMK05318_REF01_DETAMP(1,1,0,0), //R192 + MAKE_LMK05318_REF0_DETEN(0,1,0,0,0,0), //R193 + MAKE_LMK05318_REF0_MISSCLK_DIV_BY0(0x00), //R195 + MAKE_LMK05318_REF0_MISSCLK_DIV_BY1(0x00), //R196 + MAKE_LMK05318_REF0_MISSCLK_DIV_BY2(0x1d), //R197 + MAKE_LMK05318_REF1_MISSCLK_DIV_BY0(0x00), //R198 + MAKE_LMK05318_REF1_MISSCLK_DIV_BY1(0x00), //R199 + MAKE_LMK05318_REF1_MISSCLK_DIV_BY2(0x1d), //R200 + MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(0x00), //R202 + MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(0x00), //R203 + MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(0x15), //R204 + MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(0x00), //R205 + MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(0x00), //R206 + MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(0x15), //R207 + 0x00D000, //R208 REF0/1 settings begin + 0x00D114, + 0x00D200, + 0x00D316, + 0x00D400, + 0x00D514, + 0x00D600, + 0x00D716, + 0x00D900, + 0x00DA00, + 0x00DB19, + 0x00DC6E, + 0x00DD00, + 0x00DE03, + 0x00DF0D, + 0x00E047, + 0x00E100, + 0x00E200, + 0x00E319, + 0x00E46E, + 0x00E500, + 0x00E603, + 0x00E70D, + 0x00E847, + 0x00E90A, + 0x00EA0A, //R234 REF0/1 settings end + MAKE_LMK05318_REF0_PH_VALID_CNT_BY0(0x01), //R235 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY1(0x8c), //R236 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY2(0xba), //R237 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY3(0x80), //R238 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(0x00), //R239 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY1(0xc3), //R240 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY2(0x50), //R241 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY3(0x00), //R242 + MAKE_LMK05318_REF0_PH_VALID_THR(0x3f), //R243 + MAKE_LMK05318_REF1_PH_VALID_THR(0x00), //R244 + +#ifdef LMK05380_DPLL_EN + MAKE_LMK05318_DPLL_REF01_PRTY(2,1), //R249 DPLL ref priority??? + MAKE_LMK05318_DPLL_REF_SWMODE(0,0,3), //R251 DPLL sw ctrls ??? + MAKE_LMK05318_DPLL_GEN_CTL(0,1,0,1,1), //R252 DPLL ctrls ??? + MAKE_LMK05318_DPLL_REF0_RDIV_BY0(0), //R256 DPLL RDIV ??? + MAKE_LMK05318_DPLL_REF0_RDIV_BY1(1), //R257 DPLL RDIV ??? + MAKE_LMK05318_DPLL_REF1_RDIV_BY0(0), //R258 ??? + MAKE_LMK05318_DPLL_REF1_RDIV_BY1(0), //R259 ??? + MAKE_LMK05318_DPLL_REF_TDC_CTL(1), //R260 DPLL cycle slip ??? + 0x010580, + 0x010601, + 0x01072A, + 0x010805, + 0x0109F2, + 0x010A00, + 0x010BA0, + 0x010C04, + 0x010D00, + 0x010E02, + 0x010F8C, + 0x011000, + 0x011100, + 0x011200, + 0x011316, + 0x011416, + 0x011516, + 0x011600, + 0x011700, + 0x011800, + 0x011900, + 0x011A00, + 0x011B00, + 0x011C1E, + 0x011D1E, + 0x011E00, + 0x011F00, + 0x012000, + 0x012100, + 0x012203, + 0x012322, + 0x012409, + 0x012501, + 0x012600, + 0x01272C, + 0x012809, + 0x012909, + 0x012A09, + 0x012B01, + 0x012C00, + 0x012D1B, + 0x012E1E, + 0x012F01, + 0x01300F, + 0x013104, + 0x013261, + 0x0133F8, + 0x013443, + 0x0135C3, + 0x0136C3, + 0x0137C3, + 0x0138C3, + 0x0139C3, + 0x013AFF, + 0x013BFF, + 0x013CFF, + 0x013DFF, + 0x013EFF, + 0x013F03, + 0x014000, + 0x01410A, + 0x014200, + 0x014300, + 0x014400, + 0x014501, + 0x014606, + 0x014735, + 0x014875, + 0x01490B, + 0x014A00, + 0x014B64, + 0x014C00, //R332 ^^DPLL ??? + 0x015000, + 0x015198, + 0x015296, //R338 DPLL ?? + 0x015400, + 0x015500, + 0x015600, + 0x015700, + 0x015800, + 0x015900, + 0x015A02, + 0x015B00, + 0x015C00, + 0x015D00, + 0x015E00, + 0x015F00, //R352 DPLL ??? +#endif + }; + + int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + if (res) + return res; + + return 0; +} + int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk05318_xo_settings_t* xo, bool dpll_mode, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, @@ -130,6 +347,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } + res = lmk05318_init(out); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d on init()", res); + return res; + } + res = lmk05318_set_xo_fref(out); if(res) { diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index 77f4aaec..8eaf71ad 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -407,6 +407,12 @@ pages: - bits: "2" name: PRIREF_CMOS_SLEW desc: PRIREF input buffer slew rate; 0x0 = Select Amplitude Detector Mode; 0x1 = Select CMOS Amplitude Detector Mode + - bits: "1" + name: SECREF_BUF_MODE + desc: SECREF buffer mode. 0x0 - Set AC buffer hysteresis to 50mV or enable DC buffer hysteresis; 0x1 = Set AC buffer hysteresis to 200mV or disable DC buffer hysteresis + - bits: "0" + name: PRIREF_BUF_MODE + desc: PRIREF buffer mode. 0x0 - Set AC buffer hysteresis to 50mV or enable DC buffer hysteresis; 0x1 = Set AC buffer hysteresis to 200mV or disable DC buffer hysteresis - addr: 0x2E name: REF_CLKCTL2 fields: @@ -423,7 +429,10 @@ pages: fields: - bits: "7" name: PLL2_RCLK_SEL - desc: PLL2 Reference clock selection; 0x0 = VCO1 - Cascaded Mode; 0x1 = XO + desc: PLL2 Reference clock selection; 0x0 = VCO1 - Cascaded Mode; 0x1 = XO + - bits: "2-0" + name: PLL1_VCO_TO_CNTRS_EN + desc: PLL1 VCO to counters enable. Enables VCO1 output drivers to PLL1 N counter, DPLL, digital top, PLL2 R divider. Bit 0 enables VCO1 output for DPLL TDC, reference window detect, DPLL loop filter high speed clock and ppm checker clock. Bit 1 enables VCO1 output to PLL1 N counter Bit 2 enables the PLL1_P1 output to PLL2 R divider for loop-back mode. - addr: 0x30 name: STAT0_SEL fields: @@ -648,6 +657,10 @@ pages: desc: BAW VCO Lock Detection - addr: 0x51 name: BAW_LOCKDET_PPM_MAX_BY0 + fields: + - bits: "7-0" + name: BAW_LOCK_DET_2 + desc: BAW VCO Lock Detection - addr: "0x52:0x55" name: BAW_LOCKDET_CNTSTRT @@ -693,6 +706,10 @@ pages: desc: PLL2 Post-Divider1 Note A RESET is required after changing Divider values; 0x0 = Invalid; 0x1 = 2; 0x2 = 3; 0x3 = 4; 0x4 = 5; 0x5 = 6; 0x6 = 7; 0x7 = Invalid - addr: 0x68 name: PLL2_CTRL4 + fields: + - bits: "5-0" + name: PLL2_RBLEED_CP + desc: PLL2 Bleed resistor selection - addr: 0x69 name: PLL2_CALCTRL0 @@ -726,12 +743,24 @@ pages: - addr: 0x81 name: PLL1_LF_R2 + fields: + - bits: "5-0" + name: PLL1_LF_R2 + desc: PLL1 Loop Filter R2, Ohm - addr: 0x83 name: PLL1_LF_R3 + fields: + - bits: "5-0" + name: PLL1_LF_R3 + desc: PLL1 Loop Filter R3, Ohm - addr: 0x84 name: PLL1_LF_R4 + fields: + - bits: "5-0" + name: PLL1_LF_R4 + desc: PLL1 Loop Filter R4, Ohm - addr: "0x86:0x87" name: PLL2_NDIV @@ -750,15 +779,34 @@ pages: desc: APLL2 SDM Order; 0x0 = Integer Mode; 0x1 = 1st; 0x2 = 2nd; 0x3 = 3rd; 0x4 = 4th - addr: 0x8C name: PLL2_LF_R2 + fields: + - bits: "5-0" + name: PLL2_LR_R2 + desc: PLL2 Loop Filter R2 (Ohm) - addr: 0x8E name: PLL2_LF_R3 + fields: + - bits: "5-0" + name: PLL2_LR_R3 + desc: PLL2 Loop Filter R3 (Ohm) - addr: 0x8F name: PLL2_LF_R4 + fields: + - bits: "5-0" + name: PLL2_LF_R4 + desc: PLL2 Loop Filter R4 (Ohm) - addr: 0x90 name: PLL2_LF_C3C4 + fields: + - bits: "6-4" + name: PLL2_LF_C4 + desc: PLL2 Loop Filter C4, pF + - bits: "2:0" + name: PLL2_LF_C3 + desc: PLL2 Loop Filter C3, pF - addr: 0x91 name: XO_OFFSET_SW_TIMER @@ -894,9 +942,18 @@ pages: - addr: 0xF3 name: REF0_PH_VALID_THR + fields: + - bits: "5-0" + name: REF0_PH_VALID_THR + desc: PRIREF Phase Valid Threshold - addr: 0xF4 name: REF1_PH_VALID_THR + fields: + - bits: "5-0" + name: REF1_PH_VALID_THR + desc: SECREF Phase Valid Threshold + - name: DPllControl regs: - addr: 0xF9 From 6e3c6f9d8fb4eb9b771ebaff82a1f8a766febc49 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 10:39:20 +0300 Subject: [PATCH 034/397] comment out init() --- src/lib/hw/lmk05318/lmk05318.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 876775b3..118951cd 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -102,6 +102,8 @@ static int lmk05318_softreset(lmk05318_state_t* out) return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; } +#undef LMK05380_DPLL_EN + static int lmk05318_init(lmk05318_state_t* d) { uint32_t regs[] = @@ -346,14 +348,14 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, if ( dummy[3] != 0x10 || dummy[2] != 0x0b || dummy[1] != 0x35 || dummy[0] != 0x42 ) { return -ENODEV; } - +#if 0 res = lmk05318_init(out); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d on init()", res); return res; } - +#endif res = lmk05318_set_xo_fref(out); if(res) { From 8216c3da254e38b3cadc68d3bd5fc9df5cc4d649 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 14:33:33 +0300 Subject: [PATCH 035/397] lmk05318 regs are written in asc order (as by doc) --- .../device/ext_simplesync/ext_simplesync.c | 2 +- src/lib/device/m2_dsdr/m2_dsdr.c | 4 +- src/lib/device/pe_sync/pe_sync.c | 46 ++++- src/lib/hw/lmk05318/lmk05318.c | 162 +++++++++++++----- src/lib/hw/lmk05318/lmk05318.h | 4 +- src/utests/lmk05318_solver_test.c | 45 ++++- src/utests/test_suite.c | 3 + 7 files changed, 217 insertions(+), 49 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 19c339cc..784c1fad 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -101,7 +101,7 @@ int board_ext_simplesync_init(lldev_t dev, lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); lmk05318_set_port_affinity(cfg, 7, AFF_APLL1); - res = lmk05318_create_ex(dev, subdev, i2ca, &xo, false, cfg, 4, &ob->lmk); + res = lmk05318_create_ex(dev, subdev, i2ca, &xo, false, cfg, 4, &ob->lmk, false /*dry_run*/); #endif if (res) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 54788414..241e5adb 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1425,7 +1425,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(1000); - res = res ? res : lmk05318_check_lock(&d->lmk, &los); + res = res ? res : lmk05318_check_lock(&d->lmk, &los, false /*silent*/); for (int i = 0; i < 5; i++) { uint32_t clk = 0; @@ -1435,7 +1435,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(0.5 * 1e6); } - res = res ? res : lmk05318_check_lock(&d->lmk, &los); + res = res ? res : lmk05318_check_lock(&d->lmk, &los, false /*silent*/); // res = res ? res : lmk05318_set_out_mux(&d->lmk, LMK_FPGA_SYSREF, false, LVDS); usleep(1000); diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index c53c6d8d..469db7b0 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -271,6 +271,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; + const bool use_dpll = false; + const int out_accuracy = 2; lmk05318_out_config_t lmk05318_outs_cfg[8]; res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 0, 125000000, out_accuracy, out_accuracy, false, LVDS); @@ -282,7 +284,49 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, 10000000, out_accuracy, out_accuracy, false, LVCMOS); res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, 1, out_accuracy, out_accuracy, false, LVCMOS); - res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, false, lmk05318_outs_cfg, 8, &d->gen); + res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, use_dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); + if(res) + return res; + + //wait for lock + unsigned lock_msk = 0; + unsigned cnt = 0; + bool locked = false; + + const unsigned lock_expected = LMK05318_LOS_XO | LMK05318_LOL_PLL1 | + (d->gen.vco2_freq ? LMK05318_LOL_PLL2 : 0) | + (xo.fdet_bypass ? 0 : LMK05318_LOS_FDET_XO) | + (use_dpll ? (LMK05318_LOPL_DPLL | LMK05318_LOFL_DPLL) : 0); + + //waiting 10ms (100*100 us) + while(cnt < 100) + { + res = lmk05318_check_lock(&d->gen, &lock_msk, true /*silent*/); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 lmk05318_check_lock() error:%d", res); + return res; + } + + locked = (lock_msk & lock_expected) == lock_expected; + if(locked) + break; + + usleep(100); + ++cnt; + } + + if(!locked) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 is not locked! expected:%u got:%u", lock_expected, lock_msk); + return -ETIMEDOUT; + } + else + USDR_LOG("SYNC", USDR_LOG_INFO, "LMK05318 locked OK"); + + lmk05318_check_lock(&d->gen, &lock_msk, false /*silent*/); //produce debug log + + return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 118951cd..da380f91 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -44,6 +44,7 @@ enum { }; + int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out) { uint8_t data[3] = { reg >> 8, reg, out }; @@ -84,6 +85,66 @@ int lmk05318_reg_wr_n(lmk05318_state_t* d, const uint32_t* regs, unsigned count) return 0; } + +enum +{ + LMK05318_REGADDR_MIN = 0x0000, + LMK05318_REGADDR_MAX = 0x019B, +}; + +static uint32_t registers_map[LMK05318_REGADDR_MAX - LMK05318_REGADDR_MIN + 1]; + +void lmk05318_registers_map_reset() +{ + memset(registers_map, 0xFF, sizeof(registers_map)); +} + +static int lmk05318_add_reg_to_map(lmk05318_state_t* d, const uint32_t* regs, unsigned count) +{ + for (unsigned j = 0; j < count; j++) + { + const uint16_t regaddr = (uint16_t)(regs[j] >> 8) & ~0x8000; + if(regaddr < LMK05318_REGADDR_MIN || regaddr > LMK05318_REGADDR_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 REGADDR 0x%04x out of range", regaddr); + return -EINVAL; + } + + const unsigned idx = regaddr - LMK05318_REGADDR_MIN; + uint32_t* ptr = registers_map + idx; + if(*ptr != (uint32_t)(-1) && (uint8_t)(*ptr) != (uint8_t)regs[j]) + { + USDR_LOG("5318", USDR_LOG_WARNING, "LMK05318 Rewriting REGADDR 0x%04x : 0x%02x -> 0x%02x", regaddr, (uint8_t)(*ptr), (uint8_t)regs[j]); + } + *ptr = regs[j]; + } + return 0; +} + +static int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run) +{ + for(unsigned j = 0; j < SIZEOF_ARRAY(registers_map); ++j) + { + if(registers_map[j] == (uint32_t)(-1)) + continue; + + uint16_t addr = registers_map[j] >> 8; + uint8_t data = registers_map[j]; + + USDR_LOG("5318", USDR_LOG_DEBUG, "LMK05318 Writing register R%03u: 0x%04x = 0x%02x [0x%06x]", j, addr, data, registers_map[j]); + + int res = dry_run ? 0 : lmk05318_reg_wr(d, addr, data); + if (res) + return res; + } + + lmk05318_registers_map_reset(); + return 0; +} + + + + static int lmk05318_softreset(lmk05318_state_t* out) { uint8_t reg_ctrl; @@ -102,6 +163,18 @@ static int lmk05318_softreset(lmk05318_state_t* out) return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; } +static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) +{ + uint32_t regs[] = + { + MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1), //R12 + }; + + return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); +} + +#if 0 + #undef LMK05380_DPLL_EN static int lmk05318_init(lmk05318_state_t* d) @@ -145,19 +218,19 @@ static int lmk05318_init(lmk05318_state_t* d) 0x00611E, 0x006284, 0x006380, //R99 BAW LOCKDET/UNLOCKDET end - MAKE_LMK05318_PLL2_CTRL1(0x01), //R101 + - MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 + - MAKE_LMK05318_PLL2_CALCTRL0(0x01), //R105 0x1 = 3ms + - MAKE_LMK05318_PLL1_MASHCTRL(0, 0x03), //R115 0x3 = APLL1 mash_order3 + - MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm + - MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm + - MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm + - MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 + - MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm + - MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm + - MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm + - MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF + - MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 3.3ms + + MAKE_LMK05318_PLL2_CTRL1(0x01), //R101 PLL2 charge pump drain 0x1=3.2mA [default 4.8mA] + + MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 PLL2 bleed resisror 0x1F=766.96 Ohm [default open]+ + MAKE_LMK05318_PLL2_CALCTRL0(0x01), //R105 0x1 = VCO calibration time per step (up to 7 steps) 0x1=3ms [default 0.3ms]+ + MAKE_LMK05318_PLL1_MASHCTRL(0, 0x03), //R115 0x3 = APLL1 mash_order3 [default 0 (int mode)]+ + MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm [default 9650]+ + MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm [default 2400] + + MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 [default 0 (int mode)]+ + MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm [default 1867]+ + MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF [defailt C3=0(open), C4=0(open)]+ + MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 XO input wait timer 3.3ms [default 52.4ms]+ 0x00A0FC, //R160 MEMADR ? #ifdef LMK05380_DPLL_EN @@ -320,14 +393,17 @@ static int lmk05318_init(lmk05318_state_t* d) return 0; } +#endif int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk05318_xo_settings_t* xo, bool dpll_mode, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, - lmk05318_state_t* out) + lmk05318_state_t* out, bool dry_run) { int res; - uint8_t dummy[4]; + uint8_t dummy[4] = {0,0,0,0}; + + lmk05318_registers_map_reset(); out->dev = dev; out->subdev = subdev; @@ -339,23 +415,23 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, out->fref_pll2_div_rs = (((VCO_APLL1 + APLL2_PD_MAX - 1) / APLL2_PD_MAX) + out->fref_pll2_div_rp - 1) / out->fref_pll2_div_rp; out->xo = *xo; - res = lmk05318_reg_get_u32(out, 0, &dummy[0]); + res = dry_run ? 0 : lmk05318_reg_get_u32(out, 0, &dummy[0]); if (res) return res; USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 DEVID[0/1/2/3] = %02x %02x %02x %02x\n", dummy[3], dummy[2], dummy[1], dummy[0]); - if ( dummy[3] != 0x10 || dummy[2] != 0x0b || dummy[1] != 0x35 || dummy[0] != 0x42 ) { + if (!dry_run && (dummy[3] != 0x10 || dummy[2] != 0x0b || dummy[1] != 0x35 || dummy[0] != 0x42)) { return -ENODEV; } -#if 0 - res = lmk05318_init(out); + + res = lmk05318_init(out, dpll_mode); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d on init()", res); return res; } -#endif + res = lmk05318_set_xo_fref(out); if(res) { @@ -377,14 +453,16 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } - res = lmk05318_softreset(out); + lmk05318_reg_wr_from_map(out, dry_run); + + res = dry_run ? 0 : lmk05318_softreset(out); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_softreset()", res); return res; } - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 initialized\n"); return 0; } @@ -512,7 +590,7 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned uint32_t regs[] = { MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), }; - return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs));; + return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } unsigned n = fvco2 / fref; @@ -532,7 +610,7 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned } uint32_t regs[] = { - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), //R100 + //MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), //R100 MAKE_LMK05318_PLL2_CTRL2(pd2 - 1, pd1 - 1), //R102 MAKE_LMK05318_PLL2_NDIV_BY0(n), //R135 MAKE_LMK05318_PLL2_NDIV_BY1(n), //R134 @@ -542,7 +620,7 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), //R100 }; - res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); if (res) return res; @@ -589,14 +667,13 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) MAKE_LMK05318_XO_CONFIG(d->xo.pll1_fref_rdiv - 1), //R44 }; - int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); if(res) return res; return 0; } -//R74, int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) { unsigned fref = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); @@ -604,10 +681,10 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) unsigned n = fvco / fref; uint64_t num = (fvco - n * (uint64_t)fref) * (1ull << 40) / fref; - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 "\n", fvco, n, num); + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 "\n", fvco, n, num); uint32_t regs[] = { - MAKE_LMK05318_PLL1_CTRL0(1), //R74 + //MAKE_LMK05318_PLL1_CTRL0(1), //R74 MAKE_LMK05318_PLL1_MODE(dpll_mode ? 1 : 0), //R116 MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 @@ -619,7 +696,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) MAKE_LMK05318_PLL1_CTRL0(0), //R74 }; - int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); if (res) return res; @@ -642,7 +719,7 @@ int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) (port == 4) ? MAKE_LMK05318_OUTDIV_4(div) : (port == 3 || port == 2) ? MAKE_LMK05318_OUTDIV_2_3(div) : MAKE_LMK05318_OUTDIV_0_1(div), }; - return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } static int lmk05318_set_out_mux_ex(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) @@ -668,7 +745,7 @@ static int lmk05318_set_out_mux_ex(lmk05318_state_t* d, unsigned port, unsigned (port == 5) ? MAKE_LMK05318_OUTCTL_5(mux, ot) : (port == 6) ? MAKE_LMK05318_OUTCTL_6(mux, ot) : MAKE_LMK05318_OUTCTL_7(mux, ot), }; - return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); + return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype) @@ -1514,7 +1591,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned return 0; } -int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk) +int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent) { uint8_t los[3]; int res = 0; @@ -1535,15 +1612,16 @@ int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk) ((los[1] & LOFL_DPLL_POL_MSK) ? LMK05318_LOFL_DPLL : 0); - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 LOS_MAK=[%s%s%s%s%s%s%s] %02x:%02x:%02x\n", - (los[0] & LOS_XO_POL_MSK) ? "XO" : "", - (los[0] & LOL_PLL1_POL_MSK) ? " PLL1" : "", - (los[0] & LOL_PLL2_POL_MSK) ? " PLL2" : "", - (los[0] & LOS_FDET_XO_POL_MSK) ? " XO_FDET" : "", - (los[1] & LOPL_DPLL_POL_MSK) ? " DPLL_P" : "", - (los[1] & LOFL_DPLL_POL_MSK) ? " DPLL_F" : "", - (los[2] & BAW_LOCK_MSK) ? "" : " BAW", - los[0], los[1], los[2]); + if(!silent) + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 LOS_MAK=[%s%s%s%s%s%s%s] %02x:%02x:%02x\n", + (los[0] & LOS_XO_POL_MSK) ? "XO" : "", + (los[0] & LOL_PLL1_POL_MSK) ? " PLL1" : "", + (los[0] & LOL_PLL2_POL_MSK) ? " PLL2" : "", + (los[0] & LOS_FDET_XO_POL_MSK) ? " XO_FDET" : "", + (los[1] & LOPL_DPLL_POL_MSK) ? " DPLL_P" : "", + (los[1] & LOFL_DPLL_POL_MSK) ? " DPLL_F" : "", + (los[2] & BAW_LOCK_MSK) ? "" : " BAW", + los[0], los[1], los[2]); *los_msk = losval; return 0; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 97b92a60..bb96e508 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -154,7 +154,7 @@ enum lock_msk { }; -int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk); +int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); @@ -167,6 +167,6 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk05318_xo_settings_t* xo, bool dpll_mode, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, - lmk05318_state_t* out); + lmk05318_state_t* out, bool dry_run); #endif diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index e82f3237..edf3c966 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -148,6 +148,48 @@ START_TEST(lmk05318_solver_test5) } +START_TEST(lmk05318_solver_test6) +{ + /* // TODO: Initialize LMK05318B + // XO: 25Mhz + // + // OUT0: LVDS 125.000 Mhz + // OUT1: LVDS 125.000 Mhz + // OUT2: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 + // OUT3: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 + // OUT4: LVDS OFF 156.250 Mhz | OFF by default + // OUT5: LVDS OFF 156.250 Mhz | OFF by default + // OUT6: Dual CMOS 10.000 Mhz + // OUT7: Dual CMOS 1 Hz + // res = res ? res : lmk05318_create() + */ + + int res = 0; + res = res ? res : lmk05318_port_request(cfg, 0, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 1, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 2, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 3, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 4, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 10000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); + ck_assert_int_eq( res, 0 ); + + lmk05318_xo_settings_t xo; + xo.fref = 25000000; + xo.doubler_enabled = true; + xo.fdet_bypass = false; + xo.pll1_fref_rdiv = 1; + xo.type = XO_CMOS; + + lmk05318_state_t st; + memset(&st, 0, sizeof(st)); + + res = lmk05318_create_ex(NULL, 0, 0, &xo, false, cfg, 8, &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); + +} + Suite * lmk05318_solver_suite(void) { Suite *s; @@ -162,7 +204,8 @@ Suite * lmk05318_solver_suite(void) //tcase_add_test(tc_core, lmk05318_solver_test2); //tcase_add_test(tc_core, lmk05318_solver_test3); //tcase_add_test(tc_core, lmk05318_solver_test4); - tcase_add_test(tc_core, lmk05318_solver_test5); + //tcase_add_test(tc_core, lmk05318_solver_test5); + tcase_add_test(tc_core, lmk05318_solver_test6); suite_add_tcase(s, tc_core); return s; diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index c1a7a027..80a7ff89 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -33,6 +33,9 @@ int main(int argc, char** argv) #else sr = srunner_create(lmk05318_solver_suite()); #endif + + srunner_set_fork_status (sr, CK_NOFORK); + srunner_run_all(sr, (argc > 1) ? CK_VERBOSE : CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); From 7a43507a816746de0347a81c50f9b54de6cc93b0 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 16:28:41 +0300 Subject: [PATCH 036/397] refactoring, minor changes, ++wait_lock --- src/lib/device/pe_sync/pe_sync.c | 36 ++------------ src/lib/hw/lmk05318/lmk05318.c | 83 +++++++++++++++++++++++++++----- src/lib/hw/lmk05318/lmk05318.h | 3 +- 3 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 469db7b0..a86160f2 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -288,43 +288,17 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; - //wait for lock - unsigned lock_msk = 0; - unsigned cnt = 0; - bool locked = false; + usleep(1000); //wait until lmk digests all this + //wait for lock const unsigned lock_expected = LMK05318_LOS_XO | LMK05318_LOL_PLL1 | (d->gen.vco2_freq ? LMK05318_LOL_PLL2 : 0) | (xo.fdet_bypass ? 0 : LMK05318_LOS_FDET_XO) | (use_dpll ? (LMK05318_LOPL_DPLL | LMK05318_LOFL_DPLL) : 0); - //waiting 10ms (100*100 us) - while(cnt < 100) - { - res = lmk05318_check_lock(&d->gen, &lock_msk, true /*silent*/); - if(res) - { - USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 lmk05318_check_lock() error:%d", res); - return res; - } - - locked = (lock_msk & lock_expected) == lock_expected; - if(locked) - break; - - usleep(100); - ++cnt; - } - - if(!locked) - { - USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 is not locked! expected:%u got:%u", lock_expected, lock_msk); - return -ETIMEDOUT; - } - else - USDR_LOG("SYNC", USDR_LOG_INFO, "LMK05318 locked OK"); - - lmk05318_check_lock(&d->gen, &lock_msk, false /*silent*/); //produce debug log + res = lmk05318_wait_lock(&d->gen, lock_expected, 10000); + if(res) + return res; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index da380f91..0e0120f2 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -167,7 +167,8 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) { uint32_t regs[] = { - MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1), //R12 + MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1), //R12 + MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, dpllmode ? 1 : 0), //R252 }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -1591,6 +1592,30 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned return 0; } +static void lmk05318_decode_lock_mask(unsigned m, char* s) +{ + if(!s) + return; + + unsigned len = 0; + *s = 0; + + if(m & LMK05318_LOS_XO) + len += sprintf(s + len, "%s ", "XO"); + if(m & LMK05318_LOL_PLL1) + len += sprintf(s + len, "%s ", "PLL1"); + if(m & LMK05318_LOL_PLL2) + len += sprintf(s + len, "%s ", "PLL2"); + if(m & LMK05318_LOS_FDET_XO) + len += sprintf(s + len, "%s ", "XO_FDET"); + if(m & LMK05318_LOPL_DPLL) + len += sprintf(s + len, "%s ", "DPLL_P"); + if(m & LMK05318_LOFL_DPLL) + len += sprintf(s + len, "%s ", "DPLL_F"); + if(m & LMK05318_BAW_LOCK) + len += sprintf(s + len, "%s ", "BAW"); +} + int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent) { uint8_t los[3]; @@ -1609,20 +1634,54 @@ int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent) ((los[0] & LOL_PLL2_POL_MSK) ? LMK05318_LOL_PLL2 : 0) | ((los[0] & LOS_FDET_XO_POL_MSK) ? LMK05318_LOS_FDET_XO : 0) | ((los[1] & LOPL_DPLL_POL_MSK) ? LMK05318_LOPL_DPLL : 0) | - ((los[1] & LOFL_DPLL_POL_MSK) ? LMK05318_LOFL_DPLL : 0); - + ((los[1] & LOFL_DPLL_POL_MSK) ? LMK05318_LOFL_DPLL : 0) | + ((los[2] & BAW_LOCK_MSK) ? LMK05318_BAW_LOCK : 0); if(!silent) - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 LOS_MAK=[%s%s%s%s%s%s%s] %02x:%02x:%02x\n", - (los[0] & LOS_XO_POL_MSK) ? "XO" : "", - (los[0] & LOL_PLL1_POL_MSK) ? " PLL1" : "", - (los[0] & LOL_PLL2_POL_MSK) ? " PLL2" : "", - (los[0] & LOS_FDET_XO_POL_MSK) ? " XO_FDET" : "", - (los[1] & LOPL_DPLL_POL_MSK) ? " DPLL_P" : "", - (los[1] & LOFL_DPLL_POL_MSK) ? " DPLL_F" : "", - (los[2] & BAW_LOCK_MSK) ? "" : " BAW", - los[0], los[1], los[2]); + { + char ss[255]; + lmk05318_decode_lock_mask(losval, ss); + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 LOS_MASK=[%s] %02x:%02x:%02x\n", ss, los[0], los[1], los[2]); + } *los_msk = losval; return 0; } + +int lmk05318_wait_lock(lmk05318_state_t* d, unsigned lock_expected, unsigned timeout) +{ + int res = 0; + unsigned lock_msk = 0; + unsigned elapsed = 0; + bool locked = false; + + while(timeout == 0 || elapsed < timeout) + { + res = lmk05318_check_lock(d, &lock_msk, true /*silent*/); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 lmk05318_check_lock() error:%d", res); + return res; + } + + locked = (lock_msk & lock_expected) == lock_expected; + if(locked) + break; + + usleep(100); + elapsed += 100; + } + + char sexp[255], sgot[255]; + lmk05318_decode_lock_mask(lock_expected, sexp); + lmk05318_decode_lock_mask(lock_msk, sgot); + + if(!locked) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 is not locked! expected:[%s] got:[%s]", sexp, sgot); + return -ETIMEDOUT; + } + + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 locked OK [%s]", sgot); + return 0; +} diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index bb96e508..6b4ad89e 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -151,10 +151,11 @@ enum lock_msk { LMK05318_LOPL_DPLL = 16, LMK05318_LOFL_DPLL = 32, - + LMK05318_BAW_LOCK = 64, }; int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); +int lmk05318_wait_lock(lmk05318_state_t* d, unsigned lock_expected, unsigned timeout); int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); From f239b36882c3f14bd0d929be24229ef055bbeba2 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 16:52:53 +0300 Subject: [PATCH 037/397] minor fix --- src/lib/hw/lmk05318/lmk05318.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 0e0120f2..e91d0870 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -454,7 +454,12 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } - lmk05318_reg_wr_from_map(out, dry_run); + res = lmk05318_reg_wr_from_map(out, dry_run); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d writing registers", res); + return res; + } res = dry_run ? 0 : lmk05318_softreset(out); if(res) From 9706742fec48282509a8b5954985bf51ded4fbe7 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 17:05:45 +0300 Subject: [PATCH 038/397] fixed in yaml - add bus info & some minors --- src/lib/hw/lmx2820/lmx2820.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/hw/lmx2820/lmx2820.yaml b/src/lib/hw/lmx2820/lmx2820.yaml index 7f123581..7b07fcf1 100644 --- a/src/lib/hw/lmx2820/lmx2820.yaml +++ b/src/lib/hw/lmx2820/lmx2820.yaml @@ -1,5 +1,13 @@ +# Copyright (c) 2025 Wavelet Lab +# SPDX-License-Identifier: MIT + name: LMX2820 revision: 0.0.1 +processors: [ c ] +bus: + type: SPI + wr_mask: 0x80000000 + usdr_path: /debug/hw/lmx2820/*/reg addr_width: 16 data_width: 16 From 71bbba5c037c27da9a68214d7a1ca1c035209287 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 17:54:46 +0300 Subject: [PATCH 039/397] validate&add yamls: ad5662, lmk1d1208i, lmx1204, lmx1205, lmx1214, lp87524j_q1 --- src/lib/hw/CMakeLists.txt | 4 +- src/lib/hw/ad5662/ad5662.c | 6 + src/lib/hw/ad5662/ad5662.h | 7 + src/lib/hw/ad5662/ad5662.yaml | 29 + src/lib/hw/lmk1d1208i/lmk1d1208i.c | 6 + src/lib/hw/lmk1d1208i/lmk1d1208i.h | 7 + src/lib/hw/lmk1d1208i/lmk1d1208i.yaml | 224 +++++ src/lib/hw/lmx1204/lmx1204.c | 6 + src/lib/hw/lmx1204/lmx1204.h | 7 + src/lib/hw/lmx1204/lmx1204.yaml | 974 +++++++++++++++++++ src/lib/hw/lmx1205/lmx1205.c | 6 + src/lib/hw/lmx1205/lmx1205.h | 7 + src/lib/hw/lmx1205/lmx1205.yaml | 1170 +++++++++++++++++++++++ src/lib/hw/lmx1214/lmx1214.c | 6 + src/lib/hw/lmx1214/lmx1214.h | 7 + src/lib/hw/lmx1214/lmx1214.yaml | 510 ++++++++++ src/lib/hw/lp87524j_q1/lp87524j_q1.c | 6 + src/lib/hw/lp87524j_q1/lp87524j_q1.h | 7 + src/lib/hw/lp87524j_q1/lp87524j_q1.yaml | 66 ++ 19 files changed, 3053 insertions(+), 2 deletions(-) create mode 100644 src/lib/hw/ad5662/ad5662.c create mode 100644 src/lib/hw/ad5662/ad5662.h create mode 100644 src/lib/hw/ad5662/ad5662.yaml create mode 100644 src/lib/hw/lmk1d1208i/lmk1d1208i.c create mode 100644 src/lib/hw/lmk1d1208i/lmk1d1208i.h create mode 100644 src/lib/hw/lmk1d1208i/lmk1d1208i.yaml create mode 100644 src/lib/hw/lmx1204/lmx1204.c create mode 100644 src/lib/hw/lmx1204/lmx1204.h create mode 100644 src/lib/hw/lmx1204/lmx1204.yaml create mode 100644 src/lib/hw/lmx1205/lmx1205.c create mode 100644 src/lib/hw/lmx1205/lmx1205.h create mode 100644 src/lib/hw/lmx1205/lmx1205.yaml create mode 100644 src/lib/hw/lmx1214/lmx1214.c create mode 100644 src/lib/hw/lmx1214/lmx1214.h create mode 100644 src/lib/hw/lmx1214/lmx1214.yaml create mode 100644 src/lib/hw/lp87524j_q1/lp87524j_q1.c create mode 100644 src/lib/hw/lp87524j_q1/lp87524j_q1.h create mode 100644 src/lib/hw/lp87524j_q1/lp87524j_q1.yaml diff --git a/src/lib/hw/CMakeLists.txt b/src/lib/hw/CMakeLists.txt index f8c7d417..400996ac 100644 --- a/src/lib/hw/CMakeLists.txt +++ b/src/lib/hw/CMakeLists.txt @@ -1,9 +1,9 @@ # Copyright (c) 2023-2024 Wavelet Lab # SPDX-License-Identifier: MIT -set(HW_FILES si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 lmk04832 tca6424a adf4002b lp875484 afe79xx) +set(HW_FILES si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j_q1) # YAML registers generators -set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 lmk04832 xra1405 tca6424a adf4002b lp875484) +set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 lmk04832 xra1405 tca6424a adf4002b lp875484 lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j_q1) foreach(I ${HW_FILES}) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/${I} HW_DIR_FILES) diff --git a/src/lib/hw/ad5662/ad5662.c b/src/lib/hw/ad5662/ad5662.c new file mode 100644 index 00000000..4d06260f --- /dev/null +++ b/src/lib/hw/ad5662/ad5662.c @@ -0,0 +1,6 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "def_ad5662.h" +#include "ad5662.h" +#include "usdr_logging.h" diff --git a/src/lib/hw/ad5662/ad5662.h b/src/lib/hw/ad5662/ad5662.h new file mode 100644 index 00000000..8b24bfe9 --- /dev/null +++ b/src/lib/hw/ad5662/ad5662.h @@ -0,0 +1,7 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef AD5662_H +#define AD5662_H + +#endif // AD5662_H diff --git a/src/lib/hw/ad5662/ad5662.yaml b/src/lib/hw/ad5662/ad5662.yaml new file mode 100644 index 00000000..18fc4fc6 --- /dev/null +++ b/src/lib/hw/ad5662/ad5662.yaml @@ -0,0 +1,29 @@ +name: AD5662 +revision: 0.0.1 +addr_width: 16 +data_width: 24 + +pages: +- name: Main + regs: + - addr: 0x0 + name: OUTPUT + fields: + - bits: '5:0' + name: NOT_USED + mode: W + desc: Not used bits + - bits: '7:6' + name: POWER_DOWN + mode: W + dflt: 0b00 + desc: Power down setting + opts: + 0b00: Normal operation + 0b01: 1kOmh to GND + 0b10: 100kOhm to GND + 0b11: Tree-state + - bits: '23:8' + name: OUTPUT + mode: W + desc: Output value diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.c b/src/lib/hw/lmk1d1208i/lmk1d1208i.c new file mode 100644 index 00000000..7a8e6ed9 --- /dev/null +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.c @@ -0,0 +1,6 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "def_lmk1d1208i.h" +#include "lmk1d1208i.h" +#include "usdr_logging.h" diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.h b/src/lib/hw/lmk1d1208i/lmk1d1208i.h new file mode 100644 index 00000000..af3c43a7 --- /dev/null +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.h @@ -0,0 +1,7 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef LMK1D1208I_H +#define LMK1D1208I_H + +#endif // LMK1D1208I_H diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml b/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml new file mode 100644 index 00000000..11a86215 --- /dev/null +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml @@ -0,0 +1,224 @@ +name: LMK1D1208I +revision: 0.0.1 +addr_width: 16 +data_width: 16 + +pages: +- name: Main + regs: + - addr: 0x0 + name: R0 + fields: + - bits: 0 + name: OUT0_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT0_P/OUT0_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - bits: 1 + name: OUT1_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT1_P/OUT1_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - bits: 2 + name: OUT2_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT2_P/OUT2_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - bits: 3 + name: OUT3_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT3_P/OUT3_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - bits: 4 + name: OUT4_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT4_P/OUT4_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - bits: 5 + name: OUT5_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT5_P/OUT5_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - bits: 6 + name: OUT6_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT6_P/OUT6_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - bits: 7 + name: OUT7_EN + mode: RW + dflt: 0x0 + desc: This bit controls the output enable signal for output channel OUT7_P/OUT7_N. + opts: + 0b0: Output Disabled (Hi-Z) + 0b1: Output Enabled + - addr: 0x1 + name: R1 + fields: + - bits: 0 + name: OUT0_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT0_P/ OUT0_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - bits: 1 + name: OUT1_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT1_P/ OUT1_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - bits: 2 + name: OUT2_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT2_P/ OUT2_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - bits: 3 + name: OUT3_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT3_P/ OUT3_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - bits: 4 + name: OUT4_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT4_P/ OUT4_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - bits: 5 + name: OUT5_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT5_P/ OUT5_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - bits: 6 + name: OUT6_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT6_P/ OUT6_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - bits: 7 + name: OUT7_AMP_SEL + mode: RW + dflt: 0x0 + desc: This bit sets the output amplitude for output channel OUT7_P/ OUT7_N. + opts: + 0b0: Standard LVDS Swing (350 mV) + 0b1: Boosted LVDS Swing (500 mV) + - addr: 0x2 + name: R2 + fields: + - bits: 0 + name: IN0_EN + mode: RW + dflt: 0x1 + desc: This bit controls the input enable signal for input channel IN0_P/ IN0_N. + opts: + 0b0: Input Disabled (reduces power consumption) + 0b1: Input Enabled + - bits: 1 + name: IN1_EN + mode: RW + dflt: 0x0 + desc: This bit controls the input enable signal for input channel IN1_P/ IN1_N. + opts: + 0b0: Input Disabled (reduces power consumption) + 0b1: Input Enabled + - bits: 2 + name: BANK0_MUTE + mode: RW + dflt: 0x0 + desc: This bit sets the outputs in Bank 0 to logic low level. + opts: + 0b0: INx_P/INx_N + 0b1: Logic low + - bits: 3 + name: BANK1_MUTE + mode: RW + dflt: 0x0 + desc: This bit sets the outputs in Bank 1 to logic low level. + opts: + 0b0: INx_P/INx_N + 0b1: Logic low + - bits: 4 + name: BANK0_IN_SEL + mode: RW + dflt: 0x1 + desc: This bit sets the input channel for Bank 0. + opts: + 0b0: IN1_P/IN1_N + 0b1: IN0_P/IN0_N + - bits: 5 + name: BANK1_IN_SEL + mode: RW + dflt: 0x1 + desc: This bit sets the input channel for Bank 1. + opts: + 0b0: IN1_P/IN1_N + 0b1: IN0_P/IN0_N + - bits: 6 + name: R2_RESERVED_1 + mode: RW + dflt: 0x1 + desc: Register bit can be written to 1. Writing a different value than 1 will affect device functionality. + - bits: 7 + name: R2_RESERVED_0 + mode: RW + dflt: 0x1 + desc: Register bit can be written to 1. Writing a different value than 1 will affect device functionality. + - addr: 0x5 + name: R5 + fields: + - bits: '3:0' + name: DEV_ID + mode: R + dflt: 0x0 + desc: These bits provide the device identification code. + - bits: '7:4' + name: REV_ID + mode: R + dflt: 0x2 + desc: These bits provide the silicon revision code. + - addr: 0xE + name: R14 + fields: + - bits: '7:0' + name: IDX_RB + mode: R + dflt: 0x0 + desc: These bits report the I2C address state. diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c new file mode 100644 index 00000000..2de3e7b5 --- /dev/null +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -0,0 +1,6 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "def_lmx1204.h" +#include "lmx1204.h" +#include "usdr_logging.h" diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h new file mode 100644 index 00000000..b807d50f --- /dev/null +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -0,0 +1,7 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef LMX1204_H +#define LMX1204_H + +#endif // LMX1204_H diff --git a/src/lib/hw/lmx1204/lmx1204.yaml b/src/lib/hw/lmx1204/lmx1204.yaml new file mode 100644 index 00000000..40a0e545 --- /dev/null +++ b/src/lib/hw/lmx1204/lmx1204.yaml @@ -0,0 +1,974 @@ +name: LMX1204 +revision: 0.0.1 +addr_width: 16 +data_width: 16 + +pages: +- name: Main + regs: + - addr: 0x0 + name: R0 + fields: + - bits: 0 + name: RESET + mode: RW + dflt: 0x0 + desc: Soft Reset. Resets the entire logic and registers (equivalent to power-on reset). Self-clearing on next register write. + - bits: 1 + name: R0_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Reserved. If this register is written, set this bit to 0x0. + - bits: 2 + name: POWERDOWN + mode: RW + dflt: 0x0 + desc: Sets the device in a low-power state. The states of other registers are maintained. + - bits: '15:3' + name: R0_RESERVED_0 + mode: R + dflt: 0x0000 + desc: Reserved (not used). + - addr: 0x2 + name: R2 + fields: + - bits: '4:0' + name: R2_RESERVED_2 + mode: RW + dflt: 0x03 + desc: Reserved. If this register is written, set these bits to 0x03. + - bits: 5 + name: SMCLK_EN + mode: RW + dflt: 0x1 + desc: Enables the state machine clock generator. Only required to calibrate the multiplier, and for multiplier lock detect (including on MUXOUT pin). If the multiplier is not used, or if the multiplier lock detect feature is not used, the state machine clock generator can be disabled to minimize crosstalk. + - bits: '9:6' + name: SMCLK_DIV_PRE + mode: RW + dflt: 0x8 + desc: "Sets pre-divider for state machine clock. The state machine clock is divided from CLKIN. The output of the pre-divider must be <= 1600 MHz. Values other than those listed below are reserved." + opts: + 0x2: "+2" + 0x4: "+4" + 0x8: "+8" + - bits: 10 + name: R2_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Reserved. If this register is written, set this bit to 0x0. + - bits: '15:11' + name: R2_RESERVED_0 + mode: R + dflt: 0x00 + desc: Reserved (not used). + - addr: 0x3 + name: R3 + fields: + - bits: '2:0' + name: SMCLK_DIV + mode: RW + dflt: 0x6 + desc: "Sets state machine clock divider. Further divides the output of the state machine clock pre-divider. Input frequency from SMCLK_DIV_PRE must be <= 1600 MHz. Output frequency must be <= 30 MHz. Divide value is 2SMCLK_DIV." + opts: + 0x0: "+1" + 0x1: "+2" + 0x2: "+4" + 0x3: "+8" + 0x4: "+16" + 0x5: "+32" + 0x6: "+64" + 0x7: "+128" + - bits: '6:3' + name: R3_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Reserved. If this register is written, set these bits to 0x0. + - bits: 7 + name: CH0_MUTE_CAL + mode: RW + dflt: 0x1 + desc: Mutes CH0 (CLKOUT0, SYSREFOUT0) during multiplier calibration. + - bits: 8 + name: CH1_MUTE_CAL + mode: RW + dflt: 0x1 + desc: Mutes CH1 (CLKOUT1, SYSREFOUT1) during multiplier calibration. + - bits: 9 + name: CH2_MUTE_CAL + mode: RW + dflt: 0x1 + desc: Mutes CH2 (CLKOUT2, SYSREFOUT2) during multiplier calibration. + - bits: 10 + name: CH3_MUTE_CAL + mode: RW + dflt: 0x1 + desc: Mutes CH3 (CLKOUT3, SYSREFOUT3) during multiplier calibration. + - bits: 11 + name: LOGIC_MUTE_CAL + mode: RW + dflt: 0x1 + desc: Mutes LOGIC outputs (LOGICLKOUT, LOGISYSREFOUT) during multiplier calibration. + - bits: 12 + name: CH0_EN + mode: RW + dflt: 0x1 + desc: Enables CH0 (CLKOUT0, SYSREFOUT0). Setting this bit to 0x0 completely disables all CH0 circuitry, overriding the state of other powerdown/enable bits. + - bits: 13 + name: CH1_EN + mode: RW + dflt: 0x1 + desc: Enables CH1 (CLKOUT1, SYSREFOUT1). Setting this bit to 0x0 completely disables all CH1 circuitry, overriding the state of other powerdown/enable bits. + - bits: 14 + name: CH2_EN + mode: RW + dflt: 0x1 + desc: Enables CH2 (CLKOUT2, SYSREFOUT2). Setting this bit to 0x0 completely disables all CH2 circuitry, overriding the state of other powerdown/enable bits. + - bits: 15 + name: CH3_EN + mode: RW + dflt: 0x1 + desc: Enables CH3 (CLKOUT3, SYSREFOUT3). Setting this bit to 0x0 completely disables all CH3 circuitry, overriding the state of other powerdown/enable bits. + - addr: 0x4 + name: R4 + fields: + - bits: 0 + name: CLKOUT0_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT0 output buffer. + - bits: 1 + name: CLKOUT1_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT1 output buffer. + - bits: 2 + name: CLKOUT2_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT2 output buffer. + - bits: 3 + name: CLKOUT3_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT3 output buffer. + - bits: 4 + name: SYSREFOUT0_EN + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT0 output buffer. + - bits: 5 + name: SYSREFOUT1_EN + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT1 output buffer. + - bits: 6 + name: SYSREFOUT2_EN + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT2 output buffer. + - bits: 7 + name: SYSREFOUT3_EN + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT3 output buffer. + - bits: '10:8' + name: CLKOUT0_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT0. Larger values correspond to higher output power. + - bits: '13:11' + name: CLKOUT1_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT1. Larger values correspond to higher output power. + - bits: '15:14' + name: R4_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x5 + name: R5 + fields: + - bits: '2:0' + name: CLKOUT2_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT2. Larger values correspond to higher output power. + - bits: '5:3' + name: CLKOUT3_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT3. Larger values correspond to higher output power. + - bits: '8:6' + name: SYSREFOUT0_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT0. Larger values correspond to higher output power. SYSREFOUT0_VCM must be set properly to bring the output common-mode voltage within permissible limits. See also R6 Register. + - bits: '11:9' + name: SYSREFOUT1_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT1. Larger values correspond to higher output power. SYSREFOUT1_VCM must be set properly to bring the output common-mode voltage within permissible limits. See also R6 Register. + - bits: '14:12' + name: SYSREFOUT2_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT2. Larger values correspond to higher output power. SYSREFOUT2_VCM must be set properly to bring the output common-mode voltage within permissible limits. See also R6 Register. + - bits: 15 + name: R5_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x6 + name: R6 + fields: + - bits: '2:0' + name: SYSREFOUT3_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT3. Larger values correspond to higher output power. SYSREFOUT3_VCM must be set properly bring the output common-mode voltage within permissible limits. + - bits: '5:3' + name: SYSREFOUT0_VCM + mode: RW + dflt: 0x3 + desc: Sets the output common mode of SYSREFOUT0. SYSREFOUT0_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. See also R5 Register. + - bits: '8:6' + name: SYSREFOUT1_VCM + mode: RW + dflt: 0x3 + desc: Sets the output common mode of SYSREFOUT1. SYSREFOUT1_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. See also R5 Register. + - bits: '11:9' + name: SYSREFOUT2_VCM + mode: RW + dflt: 0x3 + desc: Sets the output common mode of SYSREFOUT2. SYSREFOUT2_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. See also R5 Register. + - bits: '14:12' + name: SYSREFOUT3_VCM + mode: RW + dflt: 0x3 + desc: Sets the output common mode of SYSREFOUT3. SYSREFOUT3_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. + - bits: 15 + name: LOGICLKOUT_EN + mode: RW + dflt: 0x0 + desc: Enables the LOGICLKOUT output buffer. + - addr: 0x7 + name: R7 + fields: + - bits: 0 + name: LOGISYSREFOUT_EN + mode: RW + dflt: 0x0 + desc: Enables LOGISYSREFOUT output buffer. + - bits: '3:1' + name: LOGICLKOUT_PWR + mode: RW + dflt: 0x0 + desc: Sets the output power of LOGICLKOUT in CML format. Larger values correspond to higher output power. Other output formats (LVDS, LVPECL) ignore this field. Valid range is 0x0 to 0x3. + - bits: '6:4' + name: LOGISYSREFOUT_PWR + mode: RW + dflt: 0x0 + desc: Sets the output power of LOGISYSREFOUT in CML format. Larger values correspond to higher output power. Other output formats (LVDS, LVPECL) ignore this field. Valid range is 0x0 to 0x3. + - bits: '8:7' + name: LOGICLKOUT_PREDRV_PWR + mode: RW + dflt: 0x0 + desc: Sets the output power of the LOGICLKOUT pre-driver. Larger values correspond to higher output power. Default value is sufficient for typical use. + - bits: '10:9' + name: LOGISYSREFOUT_PREDRV_PWR + mode: RW + dflt: 0x0 + desc: Sets the output power of the LOGISYSREFOUT pre-driver. Larger values correspond to higher output power. Default value is sufficient for typical use. + - bits: '12:11' + name: LOGICLKOUT_VCM + mode: RW + dflt: 0x0 + desc: Sets the output common mode of LOGICLKOUT in LVDS format. Other output formats (CML, LVPECL) ignore this field. + opts: + 0x0: 0x0 = 1.2 V + 0x1: 0x1 = 1.1 V + 0x2: 0x2 = 1.0 V + 0x3: 0x3 = 0.9 V + - bits: '14:13' + name: LOGISYSREFOUT_VCM + mode: RW + dflt: 0x0 + desc: Sets the output common mode of LOGISYSREFOUT in LVDS format. Other output formats (CML, LVPECL) ignore this field. + opts: + 0x0: 0x0 = 1.2 V + 0x1: 0x1 = 1.1 V + 0x2: 0x2 = 1.0 V + 0x3: 0x3 = 0.9 V + - bits: 15 + name: R7_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x8 + name: R8 + fields: + - bits: '1:0' + name: LOGICLKOUT_FMT + mode: RW + dflt: 0x0 + desc: "Selects the output driver format of the LOGICLKOUT output. LVDS allows for common mode control with LOGICLKOUT_VCM field. CML allows for output power control with LOGICLKOUT_PWR field. CML format requires external 50-Ohm pull-up resistors. LVPECL requires external 220-Ohm emitter resistors to GND when AC-coupled, or 50-Ohm to VCC - 2 V (0.5 V) when DC-coupled. See also R7 Register." + opts: + 0x0: LVDS + 0x1: LVPECL + 0x2: CML + - bits: '3:2' + name: LOGISYSREFOUT_FMT + mode: RW + dflt: 0x0 + desc: "Selects the output driver format of the LOGISYSREFOUT output. LVDS allows for common mode control with LOGISYSREFOUT_VCM field. CML allows for output power control with LOGISYSREFOUT_PWR field. CML format requires external 50-Ohm pull-up resistors. LVPECL requires external 220-Ohm emitter resistors to GND when AC-coupled, or 50-Ohm to VCC - 2 V (0.5 V) when DC-coupled. See also R7 Register." + opts: + 0x0: LVDS + 0x1: LVPECL + 0x2: CML + - bits: 4 + name: LOGIC_EN + mode: RW + dflt: 0x0 + desc: Enables LOGICLK subsystem (LOGICLKOUT, LOGISYSREFOUT). Setting this bit to 0x0 completely disables all LOGICLKOUT and LOGISYSREFOUT circuitry, overriding the state of other powerdown/ enable bits. + - bits: 5 + name: R8_RESERVED_1 + mode: RW + dflt: 0x1 + desc: Reserved. If this register is written, set this bit to 0x1. + - bits: '8:6' + name: LOGICLK_DIV_PRE + mode: RW + dflt: 0x4 + desc: "Sets pre-divider value for logic clock divider. Output of the pre-divider must be <= 3.2 GHz. Values other than those listed below are reserved." + opts: + 0x1: "+1" + 0x2: "+2" + 0x4: "+4" + - bits: '15:9' + name: R8_RESERVED_0 + mode: R + dflt: 0x00 + desc: Reserved (not used). + - addr: 0x9 + name: R9 + fields: + - bits: '9:0' + name: LOGICLK_DIV + mode: RW + dflt: 0x1E + desc: "Sets LOGICLK divider value. Maximum input frequency from LOGICLK_DIV_PRE must be <= 3200 MHz. The maximum LOGICLKOUT frequency must be <= 800 MHz to avoid amplitude degradation. 0x0: Reserved 0x1: Reserved 0x2: +2 0x3: +3 ... 0x1FF: +1023" + - bits: 10 + name: R9_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Reserved. If this register is written, set this bit to 0x0. + - bits: 11 + name: LOGICLK_DIV_BYPASS + mode: RW + dflt: 0x0 + desc: "Bypasses the LOGICLK divider, deriving LOGICLK output directly from the pre-divider. Used to achieve divide-by-1 when LOGICLK_DIV_PRE = 0x1. When LOGICLK_DIV_PRE = 0x2 or 0x4, this bit must be set to 0x0. When LOGICLK_DIV_BYPASS = 0x1, set R90[6:5] = 0x3 and R79[9:8] = 0x0. When LOGICLK_DIV_BYPASS = 0x0, if R90[6:5] = 0x3 due to previous user setting, set R90[6:5] = 0x0. When LOGICLK_DIV_BYPASS = 0x1, the LOGICLKOUT frequency must be <= 800 MHz to avoid amplitude degradation. See also R79 Register and R90 Register." + - bits: 12 + name: LOGICLK_DIV_PD + mode: RW + dflt: 0x0 + desc: Disables the LOGICLK divider. LOGICLK pre-divider remains enabled. Used to reduce current consumption when bypassing the LOGICLK divider. When LOGICLK_DIV_PRE = 0x2 or 0x4, this bit must be set to 0x0. + - bits: 13 + name: SYNC_EN + mode: RW + dflt: 0x0 + desc: Enables synchronization path for the dividers and allows the clock position capture circuitry to be enabled. Used for multi-device synchronization. Redundant if SYSREF_EN = 0x1. + - bits: '15:14' + name: SYSREFREQ_VCM + mode: RW + dflt: 0x0 + desc: Sets the internal DC Bias for the SYSREFREQ pins. Bias must be enabled for AC-coupled inputs; but can be enabled and overdriven, or disabled, for DC-coupled inputs. SYSREFREQ DC pin voltage must be in the range of 0.7 V to VCC, including minimum and maximum signal swing. + opts: + 0x0: 1.3 V + 0x1: 1.1 V + 0x2: 1.5 V + 0x3: Disabled (DC-coupled only) + - addr: 0xB + name: R11 + fields: + - bits: '15:0' + name: RB_CLKPOS_L + mode: R + dflt: 0xFFFF + desc: Stores a snapshot of the CLKIN signal rising edge positions relative to a SYSREFREQ rising edge, with the snapshot starting from the LSB and ending at the MSB. Each bit represents a sample of the CLKIN signal, separated by a delay determined by the SYSREFREQ_DELAY_STEPSIZE field. The first and last bits of rb_CLKPOS are always set, indicating uncertainty at the capture window boundary conditions. CLKIN rising edges are represented by every sequence of two set bits from LSB to MSB, including bits at the boundary conditions. The position of the CLKIN rising edges in the snapshot, along with the CLKIN signal period and the delay step size, can be used to compute the value of SYSREFREQ_DELAY_STEP which maximizes setup and hold times for SYNC signals on the SYSREFREQ pins. See also R12 Register, R13 Register, R14 Register, and R15 Register. + - addr: 0xC + name: R12 + fields: + - bits: '15:0' + name: RB_CLKPOS_U + mode: R + dflt: 0xFFFF + desc: MSBs of rb_CLKPOS field. See also R11 Register, R13 Register, R14 Register, and R15 Register. + - addr: 0xD + name: R13 + fields: + - bits: '1:0' + name: SYSREFREQ_DELAY_STEPSIZE + mode: RW + dflt: 0x3 + desc: Sets the step size of the delay element used in the SYSREFREQ path, both for SYSREFREQ input delay and for clock position captures. The recommended frequency range for each step size creates the maximum number of usable steps for a given CLKIN frequency. The ranges include some overlap to account for process and temperature variations. If the CLKIN frequency is covered by an overlapping span, larger delay step sizes improve the likelihood of detecting a CLKIN rising edge during a clock position capture. However, since larger values include more delay steps, larger step sizes have greater total delay variation across PVT relative to smaller step sizes. See also R11 Register, R12 Register, R14 Register, and R15 Register. + opts: + 0x0: 28 ps (1.4 GHz to 2.7 GHz) + 0x1: 15 ps (2.4 GHz to 4.7 GHz) + 0x2: 11 ps (3.1 GHz to 5.7 GHz) + 0x3: 8 ps (4.5 GHz to 12.8 GHz) + - bits: '15:2' + name: R13_RESERVED_0 + mode: R + dflt: 0x0000 + desc: Reserved (not used). + - addr: 0xE + name: R14 + fields: + - bits: 0 + name: SYSREFREQ_LATCH + mode: RW + dflt: 0x0 + desc: Latches the internal SYSREFREQ state to logic high on the first rising edge of the SYSREFREQ pins. This latch can be cleared by setting SYSREFREQ_CLR to 0x1, or bypassed by setting SYSREFREQ_LATCH to 0x0. See also R15 Register. + - bits: 1 + name: SYSREFREQ_MODE + mode: RW + dflt: 0x1 + desc: Selects the function of the SYSREFREQ pins. + opts: + 0b0: SYNC Pin + 0b1: SYSREFREQ Pin + - bits: 2 + name: CLKPOS_CAPTURE_EN + mode: RW + dflt: 0x0 + desc: Enables the windowing circuit which captures the clock position in the rb_CLKPOS registers with respect to a SYSREF edge. The windowing circuit must be cleared by toggling SYSREFREQ_CLR high then low before a clock position capture. The first rising edge on the SYSREFREQ pins after clearing the windowing circuit triggers the capture. The capture circuitry greatly increases supply current, and does not need to be enabled to delay the SYSREFREQ signal in SYNC or SYSREF modes. Once the desired value of SYSREFREQ_DELAY_STEP is determined, set this bit to 0x0 to minimize current consumption. If SYNC_EN = 0x0 and SYSREF_EN = 0x0, the value of this bit is ignored, and the windowing circuit is disabled. See also R11 Register, R12 Register, R13 Register, and R15 Register. + - bits: '7:3' + name: R14_RESERVED_1 + mode: RW + dflt: 0x00 + desc: Reserved. If this register is written, set these bits to 0x00. + - bits: 8 + name: SYNC_MUTE_PD + mode: RW + dflt: 0x0 + desc: Removes the mute condition on the SYSREFOUT and LOGISYSREFOUT pins during SYNC mode (SYSREFREQ_MODE = 0x0). Since the SYNC operation also resets the SYSREF dividers, the mute condition is usually desirable, and this bit can be left at the default value. + - bits: '15:9' + name: R14_RESERVED_0 + mode: RW + dflt: 0x00 + desc: Reserved. If this register is written, set these bits to 0x00. + - addr: 0xF + name: R15 + fields: + - bits: 0 + name: SYSREFREQ_CLR + mode: RW + dflt: 0x1 + desc: Clears SYSREFREQ_LATCH, which resets the SYSREFREQ input latch, the internal divider synchronization retimers, and the clock position capture flip-flops comprising rb_CLKPOS. When set, holds the internal SYSREFREQ signal low in all modes except SYSREF repeater mode, overriding the state of SYSREFREQ_SPI. This bit must be set and cleared once before the SYNC or clock position capture operations are performed. See also R14 Register. + - bits: '6:1' + name: SYSREFREQ_DELAY_STEP + mode: RW + dflt: 0x0 + desc: Sets the delay line step for the external SYSREFREQ signal. Each delay line step delays the SYSREFREQ signal by an amount equal to SYSREFREQ_DELAY_STEP x SYSREFREQ_DELAY_STEPSIZE. In SYNC mode, the value for this field can be determined based on the rb_CLKPOS value to satisfy the internal setup and hold time of the SYNC signal with respect to the CLKIN signal. In SYSREF Repeater Mode, the value for this field can be used as a coarse global delay. Values greater than 0x3F are invalid. Since larger values include more delay steps, larger values have greater total step size variation across PVT relative to smaller values. Refer to the data sheet or the device TICS Pro profile for detailed description of the delay step computation procedure. See also R11 Register, R12 Register, R13 Register, and R14 Register. + - bits: 7 + name: SYSREF_EN + mode: RW + dflt: 0x0 + desc: Enables SYSREF subsystem (and SYNC subsystem when SYSREFREQ_MODE = 0x0). Setting this bit to 0x0 completely disables all SYNC, SYSREF, and clock position capture circuitry, overriding the state of other powerdown/enable bits except SYNC_EN. If SYNC_EN = 0x1, the SYNC path and clock position capture circuitry are still enabled, regardless of the state of SYSREF_EN. + - bits: '9:8' + name: R15_RESERVED_1 + mode: RW + dflt: 0x1 + desc: Reserved. If this register is written, set these bits to 0x1. + - bits: '11:10' + name: SYSREF_DIV_PRE + mode: RW + dflt: 0x2 + desc: "Sets the SYSREF pre-divider. Maximum output frequency must be <= 3.2 GHz." + opts: + 0x0: "+1" + 0x1: "+2" + 0x2: "+4" + - bits: '15:12' + name: R15_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x10 + name: R16 + fields: + - bits: '11:0' + name: SYSREF_DIV + mode: RW + dflt: 0x3 + desc: "Sets the SYSREF divider. Maximum input frequency from SYSREF_DIV_PRE must be <= 3200 MHz. Maximum output frequency must be <= 100 MHz. Odd divides (with duty cycle != 50%) are only allowed when the delay generators are bypassed. See also R72 Register. 0x0: Reserved 0x1: Reserved 0x2: +2 0x3: +3 ... 0xFFF: +4095" + - bits: '15:12' + name: SYSREF_PULSE_COUNT + mode: RW + dflt: 0x1 + desc: 'Programs the number of pulses generated in pulser mode. The pulser is a counter gating the SYSREF divider; consequently, the pulse duration and frequency are equal to the duty cycle and frequency of the SYSREF divider output, respectively. 0x0: Reserved 0x1: 1 pulse 0x2: 2 pulses ... 0xF: 15 pulses' + - addr: 0x11 + name: R17 + fields: + - bits: '1:0' + name: SYSREF_MODE + mode: RW + dflt: 0x0 + desc: Controls how the SYSREF signal is generated or repeated. See also SYSREF_DELAY_BYPASS in R79 Register for additional configuration options. + opts: + 0x0: Continuous (Generator Mode) + 0x1: Pulser (Generator Mode) + 0x2: Repeater (Repeater Mode) + - bits: '3:2' + name: SYSREFOUT0_DELAY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT0 delay generator retimer. Consult the data sheet for configuration instructions. See also R18 Register and R22 Register. + opts: + 0x0: ICLK0 + 0x1: QCLK0 + 0x2: QCLK1 + 0x3: ICLK1 + - bits: '10:4' + name: SYSREFOUT0_DELAY_I + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT0 delay generator. Must satisfy SYSREFOUT0_DELAY_I + SYSREFOUT0_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R18 Register and R22 Register. + - bits: '15:11' + name: R17_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x12 + name: R18 + fields: + - bits: '6:0' + name: SYSREFOUT0_DELAY_Q + mode: RW + dflt: 0x0 + desc: Sets the delay step for the SYSREFOUT0 delay generator. Must satisfy SYSREFOUT0_DELAY_I + SYSREFOUT0_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R17 Register and R22 Register. + - bits: '8:7' + name: SYSREFOUT1_DELAY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT1 delay generator retimer. Consult the data sheet for configuration instructions. See also R19 Register and R22 Register. 0x0 = ICLK 0x1 = QCLK 0x2 = QCLK 0x3 = ICLK + opts: + 0x0: ICLK0 + 0x1: QCLK0 + 0x2: QCLK1 + 0x3: ICLK1 + - bits: '15:9' + name: SYSREFOUT1_DELAY_I + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT1 delay generator. Must satisfy SYSREFOUT1_DELAY_I + SYSREFOUT1_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R19 Register and R22 Register. + - addr: 0x13 + name: R19 + fields: + - bits: '6:0' + name: SYSREFOUT1_DELAY_Q + mode: RW + dflt: 0x0 + desc: Sets the delay step for the SYSREFOUT1 delay generator. Must satisfy SYSREFOUT1_DELAY_I + SYSREFOUT1_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R18 Register and R22 Register. + - bits: '8:7' + name: SYSREFOUT2_DELAY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT2 delay generator retimer. Consult the data sheet for configuration instructions. See also R20 Register and R23 Register. + opts: + 0x0: ICLK0 + 0x1: QCLK0 + 0x2: QCLK1 + 0x3: ICLK1 + - bits: '15:9' + name: SYSREFOUT2_DELAY_I + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT2 delay generator. Must satisfy SYSREFOUT2_DELAY_I + SYSREFOUT2_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R20 Register and R23 Register. + - addr: 0x14 + name: R20 + fields: + - bits: '6:0' + name: SYSREFOUT2_DELAY_Q + mode: RW + dflt: 0x0 + desc: Sets the delay step for the SYSREFOUT2 delay generator. Must satisfy SYSREFOUT2_DELAY_I + SYSREFOUT2_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R19 Register and R23 Register. + - bits: '8:7' + name: SYSREFOUT3_DELAY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT3 delay generator retimer. Consult the data sheet for configuration instructions. See also R21 Register and R23 Register. + opts: + 0x0: ICLK0 + 0x1: QCLK0 + 0x2: QCLK1 + 0x3: ICLK1 + - bits: '15:9' + name: SYSREFOUT3_DELAY_I + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT3 delay generator. Must satisfy SYSREFOUT3_DELAY_I + SYSREFOUT3_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R21 Register and R23 Register. + - addr: 0x15 + name: R21 + fields: + - bits: '6:0' + name: SYSREFOUT3_DELAY_Q + mode: RW + dflt: 0x0 + desc: Sets the delay step for the SYSREFOUT3 delay generator. Must satisfy SYSREFOUT3_DELAY_I + SYSREFOUT3_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R20 Register and R23 Register. + - bits: '8:7' + name: LOGISYSREFOUT_DELAY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the LOGISYSREFOUT delay generator retimer. Consult the data sheet for configuration instructions. See also R22 Register and R23 Register. + opts: + 0x0: ICLK0 + 0x1: QCLK0 + 0x2: QCLK1 + 0x3: ICLK1 + - bits: '15:9' + name: LOGISYSREFOUT_DELAY_I + mode: RW + dflt: 0x7F + desc: Sets the delay step for the LOGISYSREFOUT delay generator. Must satisfy LOGISYSREFOUT_DELAY_I + LOGISYSREFOUT_DELAY_Q = 0x7F. Consult the data sheet for configuration instructions. See also R22 Register and R23 Register. + - addr: 0x16 + name: R22 + fields: + - bits: '6:0' + name: LOGISYSREFOUT_DELAY_Q + mode: RW + dflt: 0x0 + desc: Sets the delay step for the LOGISYSREFOUT delay generator. Must satisfy LOGISYSREFOUT_DELAY_I + LOGISYSREFOUT_DELAY_Q = 0x7F. See also R21 Register and R23 Register. + - bits: '8:7' + name: R22_RESERVED_0 + mode: RW + dflt: 0x0 + desc: Reserved. If this register is written, set these bits to 0x0. + - bits: '11:9' + name: SYSREF_DELAY_DIV + mode: RW + dflt: 0x4 + desc: "Sets the delay generator clock division, determining fINTERPOLATOR and the delay generator resolution. Values other than those listed below are reserved. See also R23 Register." + opts: + 0x0: "+2 (<= 1.6 GHz)" + 0x1: "+4 (1.6 GHz to 3.2 GHz)" + 0x2: "+8 (3.2 GHz to 6.4 GHz)" + 0x4: "+16 (6.4 GHz to 12.8 GHz)" + - bits: '13:12' + name: SYSREFOUT0_DELAY_SCALE + mode: RW + dflt: 0x0 + desc: Sets the frequency range of the SYSREFOUT0 delay generator. Set according to fINTERPOLATOR frequency. Consult the data sheet for configuration instructions. See also R17 Register and R18 Register. + opts: + 0x0: 400 MHz to 800 MHz + 0x1: 200 MHz to 400 MHz + 0x2: 150 MHz to 200 MHz + - bits: '15:14' + name: SYSREFOUT1_DELAY_SCALE + mode: RW + dflt: 0x0 + desc: Sets the frequency range of the SYSREFOUT1 delay generator. Set according to fINTERPOLATOR frequency. Consult the data sheet for configuration instructions. See also R18 Register and R19 Register. + opts: + 0x0: 400 MHz to 800 MHz + 0x1: 200 MHz to 400 MHz + 0x2: 150 MHz to 200 MHz + - addr: 0x17 + name: R23 + fields: + - bits: '1:0' + name: SYSREFOUT2_DELAY_SCALE + mode: RW + dflt: 0x0 + desc: Sets the frequency range of the SYSREFOUT2 delay generator. Set according to fINTERPOLATOR frequency. Consult the data sheet for configuration instructions. See also R19 Register, R20 Register, and R22 Register. + opts: + 0x0: 400 MHz to 800 MHz + 0x1: 200 MHz to 400 MHz + 0x2: 150 MHz to 200 MHz + - bits: '3:2' + name: SYSREFOUT3_DELAY_SCALE + mode: RW + dflt: 0x0 + desc: Sets the frequency range of the SYSREFOUT3 delay generator. Set according to fINTERPOLATOR frequency. Consult the data sheet for configuration instructions. See also R20 Register, R21 Register, and R22 Register. + opts: + 0x0: 400 MHz to 800 MHz + 0x1: 200 MHz to 400 MHz + 0x2: 150 MHz to 200 MHz + - bits: '5:4' + name: LOGISYSREFOUT_DELAY_SCALE + mode: RW + dflt: 0x0 + desc: Sets the frequency range of the LOGISYSREFOUT delay generator. Set according to fINTERPOLATOR frequency. Consult the data sheet for configuration instructions. See also R21 Register and R22 Register. + opts: + 0x0: 400 MHz to 800 MHz + 0x1: 200 MHz to 400 MHz + 0x2: 150 MHz to 200 MHz + - bits: 6 + name: MUXOUT_SEL + mode: RW + dflt: 0x0 + desc: Selects MUXOUT pin function. + opts: + 0b0: Lock Detect (Multiplier Only) + 0b1: SDO (SPI readback) + - bits: '12:7' + name: R23_RESERVED_1 + mode: RW + dflt: 0x00 + desc: Reserved. If this register is written, set these bits to 0x00. + - bits: 13 + name: MUXOUT_EN + mode: RW + dflt: 0x0 + desc: Enables or tri-states the MUXOUT pin driver. See also R86 Register. + opts: + 0b0: Tri-State + 0b1: Push-Pull + - bits: 14 + name: R23_RESERVED_0 + mode: RW + dflt: 0x1 + desc: Reserved. If this register is written, set this bit to 0x1. + - bits: 15 + name: EN_TEMPSENSE + mode: RW + dflt: 0x0 + desc: Enables the on-die temperature sensor. Temperature sensor counter (EN_TS_COUNT) must also be enabled for readback. See also R24 Register. + - addr: 0x18 + name: R24 + fields: + - bits: 0 + name: EN_TS_COUNT + mode: RW + dflt: 0x0 + desc: Enables temperature sensor counter. Temperature sensor (EN_TEMPSENSE) must be enabled for accurate data. See also R23 Register. + - bits: '11:1' + name: RB_TEMPSENSE + mode: R + dflt: 0x7FF + desc: "Output of on-die temperature sensor. Readback code can be converted to junction temperature (in \xB0C) according to the following equation: TJ = 0.65 * rb_TEMPSENSE - 351" + - bits: '13:12' + name: R24_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Reserved. If this register is written, set these bits to 0x0. + - bits: '15:14' + name: R24_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x19 + name: R25 + fields: + - bits: '2:0' + name: CLK_MUX + mode: RW + dflt: 0x1 + desc: Selects the function of the device. Multiplier Mode requires writing several other registers (R33, R34, and R67) to values differing from POR defaults, as well as configuring the state machine clock (R2 and R3), before multiplier calibration. Writing any value to R0 (as long as POWERDOWN = 0x0 and RESET = 0x0) triggers a multiplier calibration. Values other than those listed below are reserved. + opts: + 0x1: Buffer Mode + 0x2: Divider Mode + 0x3: Multiplier Mode + - bits: '5:3' + name: CLK_DIVCLK_MULT + mode: RW + dflt: 0x2 + desc: CLK_DIV and CLK_MULT are aliases for the same field. When CLK_MUX = 0x2 (Divider Mode), sets the clock divider equal to CLK_DIV + 1. Valid range is 0x1 to 0x7. Setting CLK_DIV = 0x0 disables the main clock divider and reverts to buffer mode. When CLK_MUX = 0x3 (Multiplier Mode), sets the multiplier equal to CLK_MULT. Valid range is 0x1 to 0x4. Setting CLK_MULT to an invalid value disables the multiplier and reverts to buffer mode. When CLK_MUX = 0x1 (buffer mode), this field is ignored. + - bits: 6 + name: CLK_DIV_RST + mode: RW + dflt: 0x0 + desc: Resets the main clock divider. If the clock divider value is changed during operation, set this bit high then low after setting the new divider value. Synchronizing the device with the SYSREFREQ pins in SYSREFREQ_MODE = 0x0 and SYNC_EN = 0x1 also resets the main clock divider. This bit has no effect when outside of Divider Mode. + - bits: '15:7' + name: R25_RESERVED_0 + mode: RW + dflt: 0x004 + desc: Reserved. If this register is written, set these bits to 0x004. + - addr: 0x1C + name: R28 + fields: + - bits: '8:0' + name: R28_RESERVED_1 + mode: RW + dflt: 0x008 + desc: Reserved. If this register is written, set these bits to 0x008. + - bits: '11:9' + name: VCO_SEL + mode: RW + dflt: 0x5 + desc: User specified start VCO for multiplier PLL. When FORCE_VCO = 0x0, multiplier calibration starts from the VCO set by this field. When FORCE_VCO = 0x1, this field sets the VCO core used by the multiplier. Not required for Multiplier Mode programming, but can optionally be used to reduce calibration time. + - bits: 12 + name: FORCE_VCO + mode: RW + dflt: 0x0 + desc: Forces the multiplier PLL's VCO to the value selected by VCO_SEL. Not required for Multiplier Mode programming, but can optionally be used to reduce calibration time. + - bits: '15:13' + name: R28_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x1D + name: R29 + fields: + - bits: '7:0' + name: CAPCTRL + mode: RW + dflt: 0xFF + desc: Sets the starting value for the VCO tuning capacitance during multiplier calibration. Not required for Multiplier Mode programming, but can optionally be used to reduce calibration time. + - bits: '12:8' + name: R29_RESERVED_1 + mode: RW + dflt: 0x5 + desc: Reserved. If this register is written, set these bits to 0x05. + - bits: '15:13' + name: R29_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x21 + name: R33 + fields: + - bits: '15:0' + name: R33_RESERVED_0 + mode: RW + dflt: 0x7777 + desc: Reserved. If the Multiplier Mode is used, set to 0x5666 before calibration. Otherwise, writing this register can be skipped. + - addr: 0x22 + name: R34 + fields: + - bits: '13:0' + name: R34_RESERVED_1 + mode: RW + dflt: 0x0000 + desc: Reserved. If the Multiplier Mode is used, set to 0x04C5 before calibration. Otherwise, writing this register can be skipped. + - bits: '15:14' + name: R34_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x41 + name: R65 + fields: + - bits: '3:0' + name: R65_RESERVED_1 + mode: RW + dflt: 0x0 + desc: Since this register is only used for readback, avoid writing these bits when possible. If this register must be written, set these bits to 0x0. + - bits: '8:4' + name: RB_VCO_SEL + mode: R + dflt: 0x1F + desc: Readback multiplier PLL's VCO core selection. Can be optionally used in conjunction with VCO_SEL and FORCE_VCO fields to improve calibration time. + opts: + 0xF: VCO5 + 0x17: VCO4 + 0x1B: VCO3 + 0x1D: VCO2 + 0x1E: VCO1 + - bits: '15:9' + name: R65_RESERVED_0 + mode: RW + dflt: 0x22 + desc: Since this register is only used for readback, avoid writing these bits when possible. If this register must be written, set these bits to 0x22. Readback can differ from default and written values. + - addr: 0x43 + name: R67 + fields: + - bits: '15:0' + name: R67_RESERVED_0 + mode: RW + dflt: 0x50C8 + desc: Reserved. If the Multiplier Mode is used, set to 0x51CB before calibration. Otherwise, writing this register can be skipped. + - addr: 0x48 + name: R72 + fields: + - bits: '1:0' + name: SYSREF_DELAY_BYPASS + mode: RW + dflt: 0x0 + desc: 'Option to bypass delay generator retiming. Under normal circumstances (SYSREF_DELAY_BYPASS = 0) the delay generator is engaged for continuous or pulser modes (Generator Modes), and bypassed in Repeater Mode. Generally this configuration is desirable: the delay generators rely on a signal generated by the SYSREF_DELAY_DIV from the CLKIN frequency, so the Generator Mode SYSREF signal is always well-aligned to the delay generator; in repeater mode, external signal sources can typically utilize a different delay mechanism. In certain cases, bypassing the delay generator retiming in Generator Mode by setting SYSREF_DELAY_BYPASS = 0x1 can substantially reduce the device current consumption if the SYSREF delay can be compensated at the JESD receiver. In other cases, retiming the SYSREFREQ signal to the delay generators by setting SYSREF_DELAY_BYPASS = 0x2 can improve the accuracy of the SYSREF output phase with respect to the CLKIN phase, or can vary the delay of individual outputs + independently, as long as coherent phase relationship exists between the interpolator divider phase and the SYSREFREQ phase.' + opts: + 0x0: Engage in Generator Mode, Bypass in Repeater Mode + 0x1: Bypass in All Modes + 0x2: Engage in All Modes + - bits: 2 + name: SYSREFREQ_SPI + mode: RW + dflt: 0x0 + desc: Trigger SYSREFREQ via SPI. Setting this bit emulates the behavior of a logic HIGH at SYSREFREQ pins. External signals on SYSREFREQ pins are ignored while this bit is set. + - bits: 3 + name: PULSER_LATCH + mode: RW + dflt: 0x0 + desc: Latches the pulser input when programmed to 0x1. When this bit is set, external signals on SYSREFREQ pins in pulser mode (SYSREF_MODE = 0x1) can not trigger the pulser more than once, until this bit is cleared. This bit is provided to enable changing SYSREF_MODE in repeater mode without risk of accidentally triggering the pulser. + - bits: '14:4' + name: R72_RESERVED_1 + mode: RW + dflt: 0x000 + desc: Reserved. Set to 0x000. + - bits: 15 + name: R72_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x4B + name: R75 + fields: + - bits: '3:0' + name: R75_RESERVED_2 + mode: RW + dflt: 0x6 + desc: Reserved. Since this register is only used for readback, avoid writing these bits when possible. If this register must be written, set to 0x6. + - bits: '7:4' + name: R75_RESERVED_1 + mode: R + dflt: 0x1 + desc: Read-only. Writes to these bits are ignored. Readback can differ from default values. + - bits: '9:8' + name: RB_LD + mode: R + dflt: 0x3 + desc: Multiplier PLL Lock Detect. Read-only. Field value has no meaning if device is not in Multiplier Mode. + opts: + 0x0: Unlocked (VTUNE low) + 0x2: Locked + 0x3: Unlocked (VTUNE high) + - bits: '15:10' + name: R75_RESERVED_0 + mode: R + dflt: 0x57 + desc: Read-only. Writes to these bits are ignored. Readback can differ from default values. + - addr: 0x4F + name: R79 + fields: + - bits: '14:0' + name: R79_RESERVED_1 + mode: RW + dflt: 0x0104 + desc: Reserved. Set to 0x0104 immediately after setting LOGICLK_DIV_BYPASS = 0x1; R90 must also be written immediately afterward. If LOGICLK_DIV_BYPASS is not used or set to 0x0, this register does not need to be written and can be skipped. See also R90 Register. + - bits: 15 + name: R79_RESERVED_0 + mode: R + dflt: 0x0 + desc: Reserved (not used). + - addr: 0x56 + name: R86 + fields: + - bits: '15:0' + name: R86_RESERVED_0 + mode: RW + dflt: 0x0000 + desc: Reserved. This register must be set to 0x0004 to allow MUXOUT_EN to tri-state the MUXOUT pin after SPI readback. If SPI readback is not required, or if tri-state is not required on the MUXOUT pin, writing this register can be skipped, forcing MUXOUT_EN to 0x1 (push-pull mode). + - addr: 0x5A + name: R90 + fields: + - bits: '15:0' + name: R90_RESERVED_1 + mode: RW + dflt: 0x00 + desc: Reserved. Set to 0x60 immediately after setting LOGICLK_DIV_BYPASS = 0x1 and setting R79 = 0x0104. If LOGICLK_DIV_BYPASS is not used or left at the default value, this register does not need to be written and can be skipped. However, if transitioning from LOGICLK_DIV_BYPASS = 0x1 to 0x0, this register must be re-written to 0x00. See also R79 Register. + - bits: '15:8' + name: R90_RESERVED_0 + mode: R + dflt: 0x00 + desc: Reserved (not used). diff --git a/src/lib/hw/lmx1205/lmx1205.c b/src/lib/hw/lmx1205/lmx1205.c new file mode 100644 index 00000000..0984c73a --- /dev/null +++ b/src/lib/hw/lmx1205/lmx1205.c @@ -0,0 +1,6 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "def_lmx1205.h" +#include "lmx1205.h" +#include "usdr_logging.h" diff --git a/src/lib/hw/lmx1205/lmx1205.h b/src/lib/hw/lmx1205/lmx1205.h new file mode 100644 index 00000000..bc15ceb9 --- /dev/null +++ b/src/lib/hw/lmx1205/lmx1205.h @@ -0,0 +1,7 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef LMX1205_H +#define LMX1205_H + +#endif // LMX1205_H diff --git a/src/lib/hw/lmx1205/lmx1205.yaml b/src/lib/hw/lmx1205/lmx1205.yaml new file mode 100644 index 00000000..88a4bfb4 --- /dev/null +++ b/src/lib/hw/lmx1205/lmx1205.yaml @@ -0,0 +1,1170 @@ +name: LMX1205 +revision: 0.0.1 +addr_width: 16 +data_width: 16 + +pages: +- name: Main + regs: + - addr: 0x0 + name: R0 + fields: + - bits: 0 + name: RESET + mode: RW + dflt: 0x0 + desc: Soft Reset. Resets the entirie logic and reigsters (equivalent to power-on reset). Self-clearing on next register write. + - bits: 1 + name: POWERDOWN + mode: RW + dflt: 0x0 + desc: Sets the device in a low-power state. The states of other registers are maintained. + - bits: '15:2' + name: UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x1 + name: R1 + fields: + - bits: '2:0' + name: R1_UNDISCLOSED_0 + mode: RW + dflt: 0x2 + desc: Program this field to 0x2. + - bits: 3 + name: READBACK_CTRL + mode: RW + dflt: 0x1 + desc: Set this field to 0x1 to readback the written register values. Set this field to 0x0 to readback the value set by device internal state machine. + - bits: 4 + name: LD_DIS + mode: RW + dflt: 0x0 + desc: If set to 0x1, disables the lock detect status coming out at MUXOUT pin in multiplier mode. This bit must be set to 1, when interfacing multiple devices and wants to perform a readback operation in multiplier mode. + opts: + 0b0: Lock Detect + 0b1: Readback + - bits: '15:5' + name: R1_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x2 + name: R2 + fields: + - bits: 0 + name: CH0_EN + mode: RW + dflt: 0x1 + desc: Enables CH0 (CLKOUT0, SYSREFOUT0). Setting this bit to 0 completely disables CH0, overriding the state of other powerdown/ enable bits. + - bits: 1 + name: CH1_EN + mode: RW + dflt: 0x1 + desc: Enables CH1 (CLKOUT1, SYSREFOUT1). Setting this bit to 0 completely disables CH1, overriding the state of other powerdown/ enable bits. + - bits: 2 + name: CH2_EN + mode: RW + dflt: 0x1 + desc: Enables CH2 (CLKOUT2, SYSREFOUT2). Setting this bit to 0 completely disables CH2, overriding the state of other powerdown/ enable bits. + - bits: 3 + name: CH3_EN + mode: RW + dflt: 0x1 + desc: Enables CH3 (CLKOUT3, SYSREFOUT3). Setting this bit to 0 completely disables CH3, overriding the state of other powerdown/ enable bits. + - bits: 4 + name: LOGIC_EN + mode: RW + dflt: 0x1 + desc: Enables LOGICLK subsystem (LOGICLKOUT, LOGISYSREFOUT). Setting this bit to 0x0 completely disables all LOGICLKOUT and LOGISYSREFOUT circuitry, overriding the state of other powerdown/ enable bits. + - bits: 5 + name: R2_UNDISCLOSED_1 + mode: RW + dflt: 0x1 + desc: Program this field to 0x1. + - bits: 6 + name: SYSREF_EN + mode: RW + dflt: 0x0 + desc: Enables SYSREF subsystem (and SYNC subsystem when SYSREFREQ_MODE = 0x0). Setting this bit to 0x0 completely disables all SYNC, SYSREF, and clock position capture circuitry, overriding the state of other powerdown/enable bits except SYNC_EN. If SYNC_EN = 0x1, the SYNC path and clock position capture circuitry are still enabled, regardless of the state of SYSREF_EN. + - bits: 7 + name: R2_UNDISCLOSED_0 + mode: RW + dflt: 0x1 + desc: Program this field to 0x1. + - bits: 8 + name: SYNC_EN + mode: RW + dflt: 0x0 + desc: Enables synchronization path for the dividers and allows the clock position capture circuitry to be enabled. Used for multi-device synchronization. Redundant if SYSREF_EN = 0x1. + - bits: 9 + name: TEMPSENSE_EN + mode: RW + dflt: 0x0 + desc: Temperature sensor enable override bit + - bits: '15:10' + name: R2_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x3 + name: R3 + fields: + - bits: '6:0' + name: CLKIN_DLY + mode: RW + dflt: 0x0 + desc: Sets the delay at input clock. Delay range - 60ps and step size - 1.1ps + - bits: '15:7' + name: R3_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x4 + name: R4 + fields: + - bits: 0 + name: CLK0_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT0 output buffer. + - bits: '3:1' + name: CLK0_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT0. Larger values correspond to higher output power. + - bits: '10:4' + name: CLK0_DLY + mode: RW + dflt: 0x0 + desc: Sets the delay at CLKOUT0 output clock. Delay range - 55ps and step size - 0.9ps + - bits: '15:11' + name: R4_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x5 + name: R5 + fields: + - bits: 0 + name: CLK1_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT1 output buffer. + - bits: '3:1' + name: CLK1_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT1. Larger values correspond to higher output power. + - bits: '10:4' + name: CLK1_DLY + mode: RW + dflt: 0x0 + desc: Sets the delay at CLKOUT1 output clock. Delay range - 55ps and step size - 0.9ps + - bits: '15:11' + name: R5_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x6 + name: R6 + fields: + - bits: 0 + name: CLK2_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT2 output buffer. + - bits: '3:1' + name: CLK2_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT2. Larger values correspond to higher output power. + - bits: '10:4' + name: CLK2_DLY + mode: RW + dflt: 0x0 + desc: Sets the delay at CLKOUT2 output clock. Delay range - 55ps and step size - 0.9ps + - bits: '15:11' + name: R6_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x7 + name: R7 + fields: + - bits: 0 + name: CLK3_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT3 output buffer. + - bits: '3:1' + name: CLK3_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT3. Larger values correspond to higher output power. + - bits: '10:4' + name: CLK3_DLY + mode: RW + dflt: 0x0 + desc: Sets the delay at CLKOUT3 output clock. Delay range - 55ps and step size - 0.9ps + - bits: '15:11' + name: R7_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x8 + name: R8 + fields: + - bits: 0 + name: SYSREF0_EN + mode: RW + dflt: 0x1 + desc: Enables SYSREFOUT0 output buffer. + - bits: '3:1' + name: SYSREF0_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT0. Larger values corespond to higher output power. SYSREFOUT0_VCM must be set properly bring the output common mode voltage within permissible limits. + - bits: '9:4' + name: SYSREF0_VCM + mode: RW + dflt: 0xA + desc: Sets the output common mode of SYSREFOUT0 with 25mV step size. SYSREF0_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. + - bits: '12:10' + name: R8_UNDISCLOSED_0 + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - bits: 13 + name: SYSREF0_AC + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT0 AC coupled mode. + - bits: 14 + name: SYSREF0_PWR_LOW + mode: RW + dflt: 0x1 + desc: Sets the SYSREFOUT0 output deriver at low power. Set to value 0 for single ended higher swing. + - bits: 15 + name: R8_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x9 + name: R9 + fields: + - bits: 0 + name: SYSREF1_EN + mode: RW + dflt: 0x1 + desc: Enables SYSREFOUT1 output buffer. + - bits: '3:1' + name: SYSREF1_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT1. Larger values corespond to higher output power. SYSREFOUT1_VCM must be set properly bring the output common mode voltage within permissible limits. + - bits: '9:4' + name: SYSREF1_VCM + mode: RW + dflt: 0xA + desc: Sets the output common mode of SYSREFOUT1 with 25mV step size. SYSREF1_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. + - bits: '12:10' + name: R9_UNDISCLOSED_0 + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - bits: 13 + name: SYSREF1_AC + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT1 AC coupled mode. + - bits: 14 + name: SYSREF1_PWR_LOW + mode: RW + dflt: 0x1 + desc: Sets the SYSREFOUT1 output deriver at low power. Set to value 0 for single ended higher swing. + - bits: 15 + name: R9_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0xA + name: R10 + fields: + - bits: 0 + name: SYSREF2_EN + mode: RW + dflt: 0x1 + desc: Enables SYSREFOUT2 output buffer. + - bits: '3:1' + name: SYSREF2_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT2. Larger values corespond to higher output power. SYSREFOUT2_VCM must be set properly to bring the output common mode voltage within permissible limits. + - bits: '9:4' + name: SYSREF2_VCM + mode: RW + dflt: 0xA + desc: Sets the output common mode of SYSREFOUT2 with 25mV step size. SYSREF2_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. + - bits: '12:10' + name: R10_UNDISCLOSED_0 + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - bits: 13 + name: SYSREF2_AC + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT2 AC coupled mode. + - bits: 14 + name: SYSREF2_PWR_LOW + mode: RW + dflt: 0x1 + desc: Sets the SYSREFOUT2 output deriver at low power. Set to value for single ended higher swing. + - bits: 15 + name: R10_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0xB + name: R11 + fields: + - bits: 0 + name: SYSREF3_EN + mode: RW + dflt: 0x1 + desc: Enables SYSREFOUT3 output buffer. + - bits: '3:1' + name: SYSREF3_PWR + mode: RW + dflt: 0x4 + desc: Sets the output power of SYSREFOUT3. Larger values corespond to higher output power. SYSREFOUT3_VCM must be set properly bring the output common mode voltage within permissible limits. + - bits: '9:4' + name: SYSREF3_VCM + mode: RW + dflt: 0xA + desc: Sets the output common mode of SYSREFOUT3 with 25mV step size. SYSREF3_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. + - bits: '12:10' + name: R11_UNDISCLOSED_0 + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - bits: 13 + name: SYSREF3_AC + mode: RW + dflt: 0x0 + desc: Enables SYSREFOUT3 AC coupled mode. + - bits: 14 + name: SYSREF3_PWR_LOW + mode: RW + dflt: 0x1 + desc: Sets the SYSREFOUT3 output deriver at low power. Set to value 0 for single ended higher swing. + - bits: 15 + name: R11_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0xC + name: R12 + fields: + - bits: 0 + name: LOGICLK_EN + mode: RW + dflt: 0x1 + desc: Enables the logic clock output buffer. + - bits: '3:1' + name: LOGICLK_PWR + mode: RW + dflt: 0x5 + desc: Sets the output power of LOGICLKOUT. Larger values correspond to higher output power. + - bits: '8:4' + name: LOGICLK_VCM + mode: RW + dflt: 0x2 + desc: Sets the output common mode voltage of LOGICLKOUT in LVDS output format. LOGICLK_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. + - bits: '10:9' + name: R12_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: '12:11' + name: LOGICLK_FMT + mode: RW + dflt: 0x0 + desc: Selects the output driver format of the LOGICLKOUT output. + opts: + 0x0: LVDS + 0x2: CML + - bits: '15:13' + name: R12_UNDISC + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0xD + name: R13 + fields: + - bits: 0 + name: LOGISYSREF_EN + mode: RW + dflt: 0x1 + desc: Enables the logic SYSREF output buffer. + - bits: '3:1' + name: LOGISYSREF_PWR + mode: RW + dflt: 0x5 + desc: Sets the output power of LOGISYSREFOUT. Larger values correspond to higher output power. + - bits: '8:4' + name: LOGISYSREF_VCM + mode: RW + dflt: 0x2 + desc: Sets the output common mode voltage of LOGISYSREFOUT in LVDS output format. LOGISYSREF_PWR must be set properly to bring the minimum and maximum output voltage within permissible limits. + - bits: '10:9' + name: R13_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: '12:11' + name: LOGISYSREF_FMT + mode: RW + dflt: 0x0 + desc: Selects the output driver format of the LOGISYSREFOUT output. + opts: + 0x0: LVDS + 0x2: CML + - bits: '15:13' + name: R13_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0xE + name: R14 + fields: + - bits: '2:0' + name: LOGICLK_DIV_PRE + mode: RW + dflt: 0x4 + desc: "Sets pre-divider value for logic clock divider. Output of the pre-divider must be <= 3.2GHz. Values other than those listed below are reserved." + opts: + 0x1: "/1" + 0x2: "/2" + 0x4: "/4" + - bits: '12:3' + name: LOGICLK_DIV + mode: RW + dflt: 0x10 + desc: "Sets LOGICLK divider value. Maximum input frequency from LOGICLK_DIV_PRE must be <= 3200MHz. The maximum LOGICLKOUT frequency must be <= 800MHz to avoid amplitude degradation." + opts: + 0x2: "/2" + 0x3: "/3" + 0x3ff: "/1023" + - bits: '14:13' + name: R14_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 15 + name: LOGICLK_DIV_RST + mode: RW + dflt: 0x0 + desc: Manual reset for logic clock divider. + - addr: 0xF + name: R15 + fields: + - bits: 0 + name: LOGICLK2_EN + mode: RW + dflt: 0x0 + desc: Enables the LOGICLKOUT1 + opts: + 0b0: LOGISYSREFOUT + 0b1: LOGICLKOUT1 + - bits: '2:1' + name: LOGICLK2_DIV + mode: RW + dflt: 0x1 + desc: Sets the divider value for LOGICLKOUT1 logic clock. + - bits: '15:3' + name: R15_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x10 + name: R16 + fields: + - bits: '1:0' + name: SYSREFREQ_VCM + mode: RW + dflt: 0x0 + desc: Sets the SYSREFREQ input pins common mode voltage + opts: + 0x0: Zero offset (AC coupled) + 0x1: Pin P biased higher than pin N (AC coupled) + 0x2: Pin N higher than pin P (AC coupled) + 0x3: No Bias (DC coupled) + - bits: '3:2' + name: SYSREFREQ_VCM_OFFSET + mode: RW + dflt: 0x0 + desc: Sets the voltage offset at SYSREFREQ P vs N + opts: + 0x0: 25mV + 0x1: 50mV + 0x2: 100mV + 0x3: 150mV + - bits: '5:4' + name: SYSREFREQ_DLY_STEP + mode: RW + dflt: 0x3 + desc: Sets the step size of the delay element used in the SYSREFREQ path, both for SYSREFREQ input delay and for clock position captures. The recommended frequency range for each step size creates the maximum number of usable steps for a given CLKIN frequency. The ranges include some overlap to account for process and temperature variations. If the CLKIN frequency is covered by an overlapping span, larger delay step sizes improve the likelihood of detecting a CLKIN rising edge during a clock position capture. However, since larger values include more delay steps, larger step sizes have greater total delay variation across PVT relative to smaller step sizes. + opts: + 0x0: 28ps (1.4GHz to 2.7GHz) + 0x1: 15ps ( 2.4GHz to 4.7GHz) + 0x2: 11ps (3.1GHz to 5.7GHz) + 0x3: 8ps (4.5GHz to 12.8GHz) + - bits: '7:6' + name: SYSREF_DLY_SCALE + mode: RW + dflt: 0x0 + desc: Sets the frequency range of the SYSREFOUT delay generator. Set according to phase interpolator frequency. + opts: + 0x0: 400MHz to 800MHz + 0x1: 200MHz to 400MHz + 0x2: 150MHz to 200MHz + - bits: '15:8' + name: R16_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x11 + name: R17 + fields: + - bits: '1:0' + name: SYSREFREQ_MODE + mode: RW + dflt: 0x1 + desc: Sets the SYSREFREQ input mode function + opts: + 0x0: SYNC + 0x1: SYSREFREQ + 0x2: SYSREF Windowing + - bits: 2 + name: SYSREFREQ_CLR + mode: RW + dflt: 0x1 + desc: Reset synchronization path timing for SYSREFREQ signal. Holding this bit high keeps internal SYSREFREQ signal low in all modes except SYSREF repeater mode, overriding the state of SYSREFREQ_INPUT[0]. This bit must be set and cleared once before the SYNC or clock position capture operations are performed. + - bits: 3 + name: SYSWND_LATCH + mode: RW + dflt: 0x0 + desc: Sets the SYSREF Windowing at first rising edge of the SYNC input + - bits: 4 + name: SYNC_STOP + mode: RW + dflt: 0x0 + desc: Stops the reset generation after setting bit to high. + - bits: 5 + name: SYSWND_UPDATE_STOP + mode: RW + dflt: 0x0 + desc: Stops the windowing after setting bit to high. + - bits: '7:6' + name: SYSREFREQ_INPUT + mode: RW + dflt: 0x0 + desc: Sets the functionality of the SYSREFREQ block + opts: + 0x0: SYSREFREQ Pin + 0x1: Force Low + 0x3: Force High + - bits: '11:8' + name: R17_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: '15:12' + name: R17_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x12 + name: R18 + fields: + - bits: '5:0' + name: SYSREFREQ_DLY + mode: RW + dflt: 0x0 + desc: Sets the delay line step for the external SYSREFREQ signal. Each delay line step delays the SYSREFREQ signal by an amount equal to SYSREFREQ_DLY x SYSREFREQ_DLY_STEP. In SYNC mode, the value for this field can be determined based on the rb_CLKPOS value to satisfy the internal setup and hold time of the SYNC signal with respect to the CLKIN signal. In SYSREF Repeater Mode, the value for this field can be used as a coarse global delay. Values greater than 0x3F are invalid. Since larger values include more delay steps, larger values have greater total step size variation across PVT relative to smaller values. Refer to the data sheet or the device TICS Pro profile for detailed description of the delay step computation procedure. + - bits: '15:6' + name: R18_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x13 + name: R19 + fields: + - bits: '1:0' + name: SYSREF_MODE + mode: RW + dflt: 0x0 + desc: Controls how the SYSREF signal is generated and is also impacted by the SYSREF_DLY_BYP field. Continuous mode generates a continuous SYSREF clock that is derived from the SYSREF divider and delay. In pulser mode, a pulse at the SYSREFREQ pin causes a specific number (determined by SYSREF_PULSE_CNT) of pulses to be generated for the SYSREF outputs. In Repeater mode, a pulse at the SYSREFREQ pins generates a single pulse at the SYSREF outputs and only the propagation delay through the device is added. + opts: + 0x0: Continuous + 0x1: Pulser + 0x2: Repeater + 0x3: Repeater Retime + - bits: '5:2' + name: SYSREF_PULSE_CNT + mode: RW + dflt: 0x1 + desc: Programs the number of pulses generated in pulser mode. The pulser is a counter gating the SYSREF divider; consequently, the pulse duration and frequency are equal to the duty cycle and frequency of the SYSREF divider output, respectively. + opts: + 0x1: 1 pulse + 0x2: 2 pulses + 0xF: 15 pulses + - bits: 6 + name: SYSREF_DLY_BYP + mode: RW + dflt: 0x0 + desc: Sets the SYSREF delay bypass + - bits: '15:7' + name: R19_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x14 + name: R20 + fields: + - bits: '1:0' + name: SYSREF_DIV_PRE + mode: RW + dflt: 0x2 + desc: "Sets the SYSREF pre-divider. Maximum output frequency must be <= 3.2GHz." + opts: + 0x0: "/1" + 0x1: "/2" + 0x2: "/4" + - bits: '13:2' + name: SYSREF_DIV + mode: RW + dflt: 0x20 + desc: "Sets the SYSREF divider. Maximum input frequency from SYSREF_DIV_PRE must be <= 3200MHz. Maximum output frequency must be <= 100MHz. Odd divides (with duty cycle < 50%) are only allowed when the delay generators are bypassed." + opts: + 0x2: /2 + 0x3: /3 + 0xFFF: /4095 + - bits: '15:14' + name: SYSREF_DLY_DIV + mode: RW + dflt: 0x2 + desc: "Sets the delay generator clock division, determining fINTERPOLATOR and the delay generator resolution." + opts: + 0x0: /2 (<= 1.6GHz) + 0x1: /4 (1.6GHz to 3.2GHz) + 0x2: /8 (3.2GHz to 6.4GHz) + 0x3: /16 (6.4GHz to 12.8GHz) + - addr: 0x15 + name: R21 + fields: + - bits: '1:0' + name: SYSREF0_DLY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT0 delay generator retimer. + opts: + 0x0: ICLK' + 0x1: QCLK' + 0x2: ICLK + 0x3: QCLK + - bits: '8:2' + name: SYSREF0_DLY + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT0 delay generator. In each quadrant, delay has 127 steps. + - bits: '15:9' + name: R21_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x16 + name: R22 + fields: + - bits: '1:0' + name: SYSREF1_DLY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT1 delay generator retimer. + opts: + 0x0: ICLK' + 0x1: QCLK' + 0x2: QCLK + 0x3: ICLK + - bits: '8:2' + name: SYSREF1_DLY + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT1 delay generator. In each quadrant, delay has 127 steps. + - bits: '15:9' + name: R22_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x17 + name: R23 + fields: + - bits: '1:0' + name: SYSREF2_DLY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT2 delay generator retimer. + opts: + 0x0: ICLK' + 0x1: QCLK' + 0x2: QCLK + 0x3: ICLK + - bits: '8:2' + name: SYSREF2_DLY + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT2 delay generator. In each quadrant, delay has 127 steps. + - bits: '15:9' + name: R23_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x18 + name: R24 + fields: + - bits: '1:0' + name: SYSREF3_DLY_PHASE + mode: RW + dflt: 0x0 + desc: Sets the quadrature phase of the interpolator clock used for the SYSREFOUT3 delay generator retimer. + opts: + 0x0: ICLK' + 0x1: QCLK' + 0x2: QCLK + 0x3: ICLK + - bits: '8:2' + name: SYSREF3_DLY + mode: RW + dflt: 0x7F + desc: Sets the delay step for the SYSREFOUT3 delay generator. In each quadrant, delay has 127 steps. + - bits: '15:9' + name: R24_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x19 + name: R25 + fields: + - bits: '8:2' + name: LOGISYSREF_DLY + mode: RW + dflt: 0x7F + desc: Sets the delay step for the LOGISYSREF delay generator. In each quadrant, delay has 127 steps. 1-0 LOGISYSREF_DLY_PHA SE R/W 0h Sets the quadrature phase of the interpolator clock used for the LOGISYSREFOUT delay generator retimer. + opts: + 0x0: ICLK' + 0x1: QCLK' + 0x2: QCLK + 0x3: ICLK + - bits: '15:9' + name: R25_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x1A + name: R26 + fields: + - bits: 0 + name: SMCLK_EN + mode: RW + dflt: 0x1 + desc: Enables the state machine clock generator. Only required to calibrate the multiplier, and for multiplier lock detect (including on MUXOUT pin). If the multiplier is not used, or if the multiplier lock detect feature is not used, the state machine clock generator can be disabled to minimize crosstalk. + - bits: '4:1' + name: SMCLK_DIV_PRE + mode: RW + dflt: 0x8 + desc: "Pre-divider for State Machine clock (one hot divider).The state machine clock is divided from the input clock. The output of the pre-divider must be <=1600MHz. Values other than those listed are reserved." + opts: + 0x2: /2 + 0x4: /4 + 0x8: /8 + - bits: '7:5' + name: SMCLK_DIV + mode: RW + dflt: 0x6 + desc: "Sets state machine clock divider. Further divides the output of the state machine clock pre-divider. Input frequency from SMCLK_DIV_PRE must be <= 1600MHz. Output frequency must be <= 30MHz. Divide value is 2SMCLK_DIV." + opts: + 0x0: "/1" + 0x1: "/2" + 0x2: "/4" + 0x3: "/8" + 0x4: "/16" + 0x5: "/32" + 0x6: "/64" + 0x7: "/128" + - bits: '15:8' + name: R26_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x1B + name: R27 + fields: + - bits: '2:0' + name: CLK_MUX + mode: RW + dflt: 0x1 + desc: Selects the function for the main clock outputs + opts: + 0x0: Reserved + 0x1: Buffer + 0x2: Dividers + 0x3: Multiplier + - bits: '5:3' + name: CLK_DIV + mode: RW + dflt: 0x1 + desc: CLK_DIV and CLK_MULT are aliases for the same field. When CLK_MUX=1 (Buffer Mode), this field is ignored. When CLK_MUX = 2 (Divider Mode), the clock divider is CLK_DIV + 1. Valid range for CLK_DIV is 1 to 7. Setting this to 0 disables the main clock divider and reverts to buffer mode. When CLK_MUX = 3 (Multiplier Mode), CLK_MULT the multiplier vaue is CLK_MULT. Valid range is 1 to 7. + - bits: 6 + name: CLK_DIV_RST + mode: RW + dflt: 0x0 + desc: Resets the main clock divider. If the clock divider value is changed during operation, set this bit high then low after setting the new divider value. Synchronizing the device with the SYSREFREQ pins in SYSREFREQ_MODE = 0x0 and SYNC_EN = 0x1 also resets the main clock divider. This bit has no effect when outside of Divider Mode. + - bits: '8:7' + name: R27_UNDISCLOSED_1 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 9 + name: FCAL_EN + mode: RW + dflt: 0x1 + desc: Enables Frequency calibration. Writing this register with this bit high triggers a multiplier frequency calibration. If the multiplier is unused, set to 0. + - bits: 10 + name: R27_UNDISCLOSED_0 + mode: RW + dflt: 0x1 + desc: Program this field to 0x1. + - bits: 11 + name: MULT_HIPFD_EN + mode: RW + dflt: 0x0 + desc: Above 4.2GHz frequency in multiplier mode, to optimized the current, toggle this bit low to high along with R0. To set the bit high without R0, increase a current with 20mA. + - bits: '15:12' + name: R27_UNDISCLOSED + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - addr: 0x1D + name: R29 + fields: + - bits: '15:0' + name: RB_CLKPOS_U + mode: R + dflt: 0x0 + desc: Stores a snapshot of the CLKIN signal rising edge positions relative to a SYSREFREQ rising edge, with the snapshot starting from the LSB and ending at the MSB. Each bit represents a sample of the CLKIN signal, separated by a delay determined by the SYSREFREQ_DLY_STEP field. The first and last bits of rb_CLKPOS are always set, indicating uncertainty at the capture window boundary conditions. CLKIN rising edges are represented by every sequence of two set bits from LSB to MSB, including bits at the boundary conditions. The position of the CLKIN rising edges in the snapshot, along with the CLKIN signal period and the delay step size, can be used to compute the value of SYSREFREQ_DLY_STEP which maximizes setup and hold times for SYNC signals on the SYSREFREQ pins. + - addr: 0x1E + name: R30 + fields: + - bits: '15:0' + name: RB_CLKPOS_L + mode: R + dflt: 0x0 + desc: LSBs of rb_CLKPOS field. + - addr: 0x1F + name: R31 + fields: + - bits: '10:0' + name: RB_TEMPSENSE + mode: R + dflt: 0x0 + desc: Readback value of on-die temperature sensor. + - bits: '13:11' + name: R31_UNDISCLOSED_0 + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - bits: '15:14' + name: R31_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x20 + name: R32 + fields: + - bits: '15:0' + name: RB_VER_ID + mode: R + dflt: 0x0 + desc: Version ID. + - addr: 0x24 + name: R36 + fields: + - bits: '5:0' + name: R36_UNDISCLOSED_2 + mode: RW + dflt: 0x23 + desc: Program this field to 0x16. + - bits: '7:6' + name: R36_UNDISCLOSED_1 + mode: RW + dflt: 0x2 + desc: Program this field to 0x0. + - bits: '9:8' + name: R36_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x3. + - bits: '15:10' + name: R36_UNDISCLOSED + mode: RW + dflt: 0x21 + desc: Program this field to 0x42. + - addr: 0x25 + name: R37 + fields: + - bits: 0 + name: RB_LOCK_DETECT + mode: R + dflt: 0x0 + desc: Reads back the lock detect status in multiplier mode + opts: + 0b0: Unlock + 0b1: Lock Detect + - bits: '14:1' + name: R37_UNDISCLOSED_0 + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 15 + name: R37_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x27 + name: R39 + fields: + - bits: '3:0' + name: R39_UNDISCLOSED_2 + mode: RW + dflt: 0x1 + desc: Program this field to 0x1. + - bits: '8:4' + name: R39_UNDISCLOSED_1 + mode: RW + dflt: 0xE + desc: Program this field to 0x16. + - bits: '11:9' + name: R39_UNDISCLOSED_0 + mode: RW + dflt: 0x4 + desc: Program this field to 0x4. + - bits: '15:12' + name: R39_UNDISCLOSED + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - addr: 0x28 + name: R40 + fields: + - bits: '3:0' + name: R40_UNDISCLOSED_2 + mode: RW + dflt: 0x1 + desc: Program this field to 0x3. + - bits: '8:4' + name: R40_UNDISCLOSED_1 + mode: RW + dflt: 0xE + desc: Program this field to 0x16. + - bits: '11:9' + name: R40_UNDISCLOSED_0 + mode: RW + dflt: 0x4 + desc: Program this field to 0x4. + - bits: '15:12' + name: R40_UNDISCLOSED + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - addr: 0x29 + name: R41 + fields: + - bits: '3:0' + name: R41_UNDISCLOSED_2 + mode: RW + dflt: 0x3 + desc: Program this field to 0x1. + - bits: '8:4' + name: R41_UNDISCLOSED_1 + mode: RW + dflt: 0xF + desc: Program this field to 0x14. + - bits: '11:9' + name: R41_UNDISCLOSED_0 + mode: RW + dflt: 0x4 + desc: Program this field to 0x2. + - bits: '15:12' + name: R41_UNDISCLOSED + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - addr: 0x2A + name: R42 + fields: + - bits: '3:0' + name: R42_UNDISCLOSED_2 + mode: RW + dflt: 0x3 + desc: Program this field to 0x1. + - bits: '8:4' + name: R42_UNDISCLOSED_1 + mode: RW + dflt: 0xF + desc: Program this field to 0x14. + - bits: '11:9' + name: R42_UNDISCLOSED_0 + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - bits: '15:12' + name: R42_UNDISCLOSED + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - addr: 0x2B + name: R43 + fields: + - bits: '3:0' + name: R43_UNDISCLOSED_2 + mode: RW + dflt: 0x7 + desc: Program this field to 0x1. + - bits: '8:4' + name: R43_UNDISCLOSED_1 + mode: RW + dflt: 0x10 + desc: Program this field to 0x14. + - bits: '11:9' + name: R43_UNDISCLOSED_0 + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - bits: '15:12' + name: R43_UNDISCLOSED + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - addr: 0x2C + name: R44 + fields: + - bits: '3:0' + name: R44_UNDISCLOSED_2 + mode: RW + dflt: 0x7 + desc: Program this field to 0x1. + - bits: '8:4' + name: R44_UNDISCLOSED_1 + mode: RW + dflt: 0x10 + desc: Program this field to 0x16. + - bits: '11:9' + name: R44_UNDISCLOSED_0 + mode: RW + dflt: 0x3 + desc: Program this field to 0x2. + - bits: '15:12' + name: R44_UNDISCLOSED + mode: RW + dflt: 0x7 + desc: Program this field to 0x7. + - addr: 0x2D + name: R45 + fields: + - bits: '1:0' + name: R45_UNDISCLOSED_5 + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - bits: '3:2' + name: R45_UNDISCLOSED_4 + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - bits: '5:4' + name: R45_UNDISCLOSED_3 + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - bits: '7:6' + name: R45_UNDISCLOSED_2 + mode: RW + dflt: 0x2 + desc: Program this field to 0x3. + - bits: '9:8' + name: R45_UNDISCLOSED_1 + mode: RW + dflt: 0x2 + desc: Program this field to 0x3. + - bits: '11:10' + name: R45_UNDISCLOSED_0 + mode: RW + dflt: 0x2 + desc: Program this field to 0x3. + - bits: '15:12' + name: R45_UNDISCLOSED + mode: RW + dflt: 0x2 + desc: Program this field to 0x2. + - addr: 0x36 + name: R54 + fields: + - bits: '1:0' + name: R54_UNDISCLOSED_2 + mode: RW + dflt: 0x0 + desc: Program this field to 0x2. + - bits: '3:2' + name: R54_UNDISCLOSED_1 + mode: RW + dflt: 0x0 + desc: Program this field to 0x3. + - bits: '13:4' + name: R54_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: '15:14' + name: R54_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x37 + name: R55 + fields: + - bits: '5:0' + name: DEV_IOPT_CTRL + mode: RW + dflt: 0x0 + desc: Set this field to 0x6 in all modes, also in powerdown. Set this field to 0x6 before calibration in multiplier mode and changed to 0x1 after calibration + - bits: '15:6' + name: R55_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x4D + name: R77 + fields: + - bits: '1:0' + name: R77_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x2. + - bits: '15:2' + name: R77_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c new file mode 100644 index 00000000..a6726a80 --- /dev/null +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -0,0 +1,6 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "def_lmx1214.h" +#include "lmx1214.h" +#include "usdr_logging.h" diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h new file mode 100644 index 00000000..6c03fb6a --- /dev/null +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -0,0 +1,7 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef LMX1214_H +#define LMX1214_H + +#endif // LMX1214_H diff --git a/src/lib/hw/lmx1214/lmx1214.yaml b/src/lib/hw/lmx1214/lmx1214.yaml new file mode 100644 index 00000000..76a28cd9 --- /dev/null +++ b/src/lib/hw/lmx1214/lmx1214.yaml @@ -0,0 +1,510 @@ +name: LMX1214 +revision: 0.0.1 +addr_width: 16 +data_width: 16 + +pages: +- name: Main + regs: + - addr: 0x0 + name: R0 + fields: + - bits: '1:0' + name: R0_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 2 + name: POWERDOWN + mode: RW + dflt: 0x0 + desc: Sets the device in a low-power state. The states of other registers are maintained. + - bits: '15:3' + name: UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x2 + name: R2 + fields: + - bits: '4:0' + name: R2_UNDISCLOSED_1 + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - bits: 5 + name: SMCLK_EN + mode: RW + dflt: 0x1 + desc: Enables the state machine clock generator. This is required for pin modes to function correctly and the part must be initialized with this bit enabled. However, this bit can later on be disabled to save current and prevent the state machine clock spur. + - bits: '10:6' + name: R2_UNDISCLOSED_0 + mode: RW + dflt: 0x8 + desc: Program this field to 0x8. + - bits: '15:11' + name: R2_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x3 + name: R3 + fields: + - bits: '11:0' + name: R3_UNDISCLOSED + mode: RW + dflt: 0xFE + desc: Program this field to 0xFE. + - bits: 12 + name: CLKOUT0_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT0 + - bits: 13 + name: CLKOUT1_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT1 + - bits: 14 + name: CLKOUT2_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT2 + - bits: 15 + name: CLKOUT3_EN + mode: RW + dflt: 0x1 + desc: Enables CLKOUT3 + - addr: 0x4 + name: R4 + fields: + - bits: '7:0' + name: R4_UNDISCLOSED_0 + mode: RW + dflt: 0xFF + desc: Program this field to 0xFF. + - bits: '10:8' + name: CLKOUT0_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT0. Larger values correspond to higher output power. + - bits: '13:11' + name: CLKOUT1_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT1. Larger values correspond to higher output power. + - bits: '15:14' + name: R4_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x5 + name: R5 + fields: + - bits: '2:0' + name: CLKOUT2_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT2. Larger values correspond to higher output power. + - bits: '5:3' + name: CLKOUT3_PWR + mode: RW + dflt: 0x6 + desc: Sets the output power of CLKOUT3. Larger values correspond to higher output power. + - bits: '14:6' + name: R5_UNDISCLOSED_0 + mode: RW + dflt: 0xDB + desc: Program this field to 0xDB. + - bits: 15 + name: R5_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x7 + name: R7 + fields: + - bits: 0 + name: R7_UNDISCLOSED_3 + mode: RW + dflt: 0x1 + desc: Program this field to 0x1. + - bits: '3:1' + name: AUXCLKOUT_PWR + mode: RW + dflt: 0x7 + desc: Sets the output power of AYXCLKOUT for CML format only (other output formats ignore this field). Larger values correspond to higher output power. + - bits: '6:4' + name: R7_UNDISCLOSED_2 + mode: RW + dflt: 0x3 + desc: Program this field to 0x3. + - bits: '8:7' + name: AUXCLK_DIV_PWR_PRE + mode: RW + dflt: 0x0 + desc: Sets the output power of the AUXCLK pre-driver. Larger values correspond to higher output power. + - bits: '10:9' + name: R7_UNDISCLOSED_1 + mode: RW + dflt: 0x2 + desc: Program this field to 0x2. + - bits: '12:11' + name: AUXCLKOUT_VCM + mode: RW + dflt: 0x2 + desc: In LVDS mode, sets the output common mode of the auxiliary clock output. Other output formats ignore this field. + opts: + 0x0: 1.2V + 0x1: 1.1V + 0x2: 1.0V + 0x3: 0.9V + - bits: '14:13' + name: R7_UNDISCLOSED_0 + mode: RW + dflt: 0x2 + desc: Program this field to 0x2. + - bits: 15 + name: R7_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x8 + name: R8 + fields: + - bits: '1:0' + name: AUXCLKOUT_FMT + mode: RW + dflt: 0x0 + desc: Selects the output driver format of the AUXCLKOUT output. + opts: + 0x0: LVDS + 0x2: CML + - bits: '4:2' + name: R8_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 5 + name: AUXCLKOUT_EN + mode: RW + dflt: 0x1 + desc: Enables AUXCLK subsystem. + - bits: '8:6' + name: AUXCLK_DIV_PRE + mode: RW + dflt: 0x4 + desc: Sets pre-divider value. Output of the pre-divider must be less than or equal to 3.2 GHz. When AUXCLK_DIV_PRE=1, register R79 is also required to be programmed to a value of 0x0005 and R90 to 0x0060 (AUXCLK_DIV_BYP2=1, AUXCLK_DIV_BYP3=1). Values for AUXCLK_DIV_PRE other than those listed below are reserved. + opts: + 0x1: "/1" + 0x2: "/2" + 0x4: "/4" + - bits: '15:9' + name: R8_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x9 + name: R9 + fields: + - bits: '9:0' + name: AUXCLK_DIV + mode: RW + dflt: 0x20 + desc: "Sets AUXCLK divider value. Maximum input frequency from AUXCLK_DIV_PRE must be <= 3200 MHz. The maximum AUXCLKOUT frequency must be <= 800 MHz to avoid amplitude degradation." + opts: + 0x2: "/2" + 0x3: "/3" + 0x3FF: "/1023" + - bits: 10 + name: R9_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 11 + name: AUXCLK_DIV_BYP + mode: RW + dflt: 0x0 + desc: Bypasses the AUXCLK_DIV divider to derive the AUXCLK output directly from the AUXCLK_DIV_PRE divider. Use only when AUXCLK_DIV_PRE=1 as one of the steps to achieve a total divide of 1 for the AUXCLK. To achieve a divide by 1, the following steps are required. 1. Set AUXCLK_DIV_PRE=1 2. Verify that register R79 is programmed to a value of 0x0005 3. Program R90 to 0x0060 (AUXCLK_DIV_BYP2=1, AUXCLK_DIV_BYP3=1) 4. Set AUXCLK_DIV_BYP=1 If a total divide of 1 for the AUXCLK is undesired, set this bit to 0. + - bits: 12 + name: R9_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 13 + name: SYNC_EN + mode: RW + dflt: 0x0 + desc: Enables synchronization path for the dividers and allows the clock position capture circuitry to be enabled. Used for multi-device synchronization. + - bits: '15:14' + name: SYNC_VCM + mode: RW + dflt: 0x0 + desc: Sets the internal DC Bias for the SYNC pins. Bias must be enabled for AC-coupled inputs; but can be enabled and overdriven, or disabled, for DC-coupled inputs. SYNC DC pin voltage must be in the range of 0.7 V to VCC, including minimum and maximum signal swing. + opts: + 0x0: "1.3V" + 0x1: "1.1V" + 0x2: "1.5V" + 0x3: "Disabled" + - addr: 0xB + name: R11 + fields: + - bits: '15:0' + name: RB_CLKPOS_L + mode: R + dflt: 0x0 + desc: Stores a snapshot of the CLKIN signal rising edge positions relative to a SYNC rising edge, with the snapshot starting from the LSB and ending at the MSB. Each bit represents a sample of the CLKIN signal, separated by a delay determined by the SYNC_DLY_STEP field. The first and last bits of rb_CLKPOS are always set, indicating uncertainty at the capture window boundary conditions. CLKIN rising edges are represented by every sequence of two set bits from LSB to MSB, including bits at the boundary conditions. The position of the CLKIN rising edges in the snapshot, along with the CLKIN signal period and the delay step size, can be used to compute the value of SYNC_DLY which maximizes setup and hold times for SYNC signals on the SYNC pins. + - addr: 0xC + name: R12 + fields: + - bits: '15:0' + name: RB_CLKPOS_U + mode: R + dflt: 0x0 + desc: MSB of rb_CLKPOS field. + - addr: 0xD + name: R13 + fields: + - bits: '1:0' + name: SYNC_DLY_STEP + mode: RW + dflt: 0x3 + desc: Sets the step size of the delay element used in the SYSNC path, both for SYNC input delay and for clock position captures. The recommended frequency range for each step size creates the maximum number of usable steps for a given CLKIN frequency. The ranges include some overlap to account for process and temperature variations. If the CLKIN frequency is covered by an overlapping span, larger delay step sizes improve the likelihood of detecting a CLKIN rising edge during a clock position capture. However, since larger values include more delay steps, larger step sizes have greater total delay variation across PVT relative to smaller step sizes. + opts: + 0x0: 28 ps (1.4GHz to 2.7GHz) + 0x1: 15 ps ( 2.4GHz to 4.7GHz) + 0x2: 11 ps (3.1GHz to 5.7GHz) + 0x3: 8 ps (4.5GHz to 12.8GHz) + - bits: '15:2' + name: R13_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0xE + name: R14 + fields: + - bits: 0 + name: SYNC_LATCH + mode: RW + dflt: 0x0 + desc: Latches the internal SYNC state to logic high on the first rising edge of the SYNC pins. This latch can be cleared by setting SYNC_CLR=1. + - bits: 1 + name: R14_UNDISCLOSED_0 + mode: RW + dflt: 0x1 + desc: Program this field to 0x1. + - bits: 2 + name: CLKPOS_CAPTURE_EN + mode: RW + dflt: 0x0 + desc: Enables the windowing circuit which captures the clock position in the rb_CLKPOS registers with respect to a SYNC edge. The windowing circuit must be cleared by toggling SYNC_CLR high then low before a clock position capture. The first rising edge on the SYNC pins after clearing the windowing circuit triggers the capture. The capture circuitry greatly increases supply current, and does not need to be enabled to delay the SYNC signal in SYNC mode. Once the desired value of SYNC_DLY is determined, set this bit to 0x0 to minimize current consumption. If SYNC_EN = 0, the value of this bit is ignored, and the windowing circuit is disabled. + - bits: '15:3' + name: R14_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0xF + name: R15 + fields: + - bits: 0 + name: SYNC_CLR + mode: RW + dflt: 0x1 + desc: Clears SYNC_LATCH and resets synchronization path timing for SYNC signal. Holding this bit high keeps internal SYNC signal low. This bit must be set and cleared once before the SYNC or clock position capture operations are performed. + - bits: '6:1' + name: SYNC_DLY + mode: RW + dflt: 0x0 + desc: Sets the delay line step for the external SYNC signal. Each delay line step delays the SYNC signal by an amount equal to SYNC_DLY_STEP x SYNC_DLY_STEP. In SYNC mode, the value for this field can be determined based on the rb_CLKPOS value to satisfy the internal setup and hold time of the SYNC signal with respect to the CLKIN signal. In SYSREF Repeater Mode, the value for this field can be used as a coarse global delay. Values greater than 0x3F are invalid. Since larger values include more delay steps, larger values have greater total step size variation across PVT relative to smaller values. Refer to the data sheet or the device TICS Pro profile for detailed description of the delay step computation procedure. + - bits: '11:7' + name: R15_UNDISCLOSED_0 + mode: RW + dflt: 0x16 + desc: Program this field to 0x16. + - bits: '15:12' + name: R15_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x17 + name: R23 + fields: + - bits: '12:0' + name: R23_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 13 + name: MUXOUT_EN + mode: RW + dflt: 0x0 + desc: Enables or tri-states the MUXOUT pin driver. + opts: + 0b0: Tri-States + 0b1: Push-Pull + - bits: 14 + name: R23_UNDISCLOSED + mode: RW + dflt: 0x1 + desc: Program this field to 0x1. + - bits: 15 + name: TS_EN + mode: RW + dflt: 0x0 + desc: Enables the on-die temperature sensor. Temperature sensor counter (TS_CNT_EN) must also be enabled for readback. + - addr: 0x18 + name: R24 + fields: + - bits: 0 + name: TS_CNT_EN + mode: RW + dflt: 0x0 + desc: Enables temperature sensor counter. Temperature sensor (TS_EN) must be enabled for accurate data. + - bits: '11:1' + name: RB_TS + mode: R + dflt: 0x0 + desc: Readback value of on-die temperature sensor. + - bits: '13:12' + name: R24_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: '15:14' + name: R24_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x19 + name: R25 + fields: + - bits: '2:0' + name: CLK_MUX + mode: RW + dflt: 0x1 + desc: Selects the function for the main clock outputs + opts: + 0x1: Buffer + 0x2: Divider + - bits: '5:3' + name: CLK_DIV + mode: RW + dflt: 0x2 + desc: Sets the clock divider value when CLK_MUX=2 (Divider Mode). The clock divider value is CLK_DIV+1. Valid value for CLK_DIV is 1 to 7. Setting this to 0 disables the main clock divider and reverts to buffer mode. + - bits: 6 + name: CLK_DIV_RST + mode: RW + dflt: 0x0 + desc: Resets the main clock divider. If the clock divider value is changed during operation, set this bit high then low after setting the new divider value. Synchronizing the device with the SYNC pins with SYNC_EN = 0x1 also resets the main clock divider. This bit has no effect when outside of Divider Mode. + - bits: '15:7' + name: R25_UNDISCLOSED + mode: RW + dflt: 0x4 + desc: Program this field to 0x4. + - addr: 0x4B + name: R75 + fields: + - bits: '3:0' + name: R75_UNDISCLOSED_0 + mode: RW + dflt: 0x6 + desc: Program this field to 0x6. + - bits: 4 + name: RB_CE + mode: R + dflt: 0x0 + desc: Readback Pin Status + - bits: 5 + name: RB_DIVSEL0 + mode: R + dflt: 0x0 + desc: Readback Pin Status + - bits: 6 + name: RB_DIVSEL1 + mode: R + dflt: 0x0 + desc: Readback Pin Status + - bits: '11:7' + name: R75_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 12 + name: RB_MUXSEL1 + mode: R + dflt: 0x0 + desc: Readback Pin Status + - bits: 13 + name: RB_CLKOUT0_EN + mode: R + dflt: 0x0 + desc: Readback Pin Status + - bits: 14 + name: RB_CLKOUT1_EN + mode: R + dflt: 0x0 + desc: Readback Pin Status + - bits: 15 + name: RB_CLKOUT2_EN + mode: R + dflt: 0x0 + desc: Readback Pin Status + - addr: 0x4F + name: R79 + fields: + - bits: '14:0' + name: R79_UNDISCLOSED_0 + mode: RW + dflt: 0x205 + desc: Program this field to 0x5. Note that this is different than the reset value. + - bits: 15 + name: R79_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x56 + name: R86 + fields: + - bits: '1:0' + name: R86_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 2 + name: MUXOUT_EN_OVRD + mode: RW + dflt: 0x0 + desc: This bit must be set to 1 to enable MUXOUT_EN to tri-state the MUXOUT pin. + - bits: '15:3' + name: R86_UNDISCLOSED + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - addr: 0x5A + name: R90 + fields: + - bits: '4:0' + name: R90_UNDISCLOSED_1 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: 5 + name: AUXCLK_DIV_BYP2 + mode: RW + dflt: 0x0 + desc: Set this bit to 1 if AUXCLK_BYP=1, set to 0 otherwise. + - bits: 6 + name: AUXCLK_DIV_BYP3 + mode: RW + dflt: 0x0 + desc: Set this bit to 1 if AUXCLK_BYP=1, set to 0 otherwise. + - bits: 7 + name: R90_UNDISCLOSED_0 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. + - bits: '15:8' + name: R90_UNDISCLOSED + mode: R + dflt: 0x0 + desc: Program this field to 0x0. diff --git a/src/lib/hw/lp87524j_q1/lp87524j_q1.c b/src/lib/hw/lp87524j_q1/lp87524j_q1.c new file mode 100644 index 00000000..3f53aa1f --- /dev/null +++ b/src/lib/hw/lp87524j_q1/lp87524j_q1.c @@ -0,0 +1,6 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "def_lp87524j_q1.h" +#include "lp87524j_q1.h" +#include "usdr_logging.h" diff --git a/src/lib/hw/lp87524j_q1/lp87524j_q1.h b/src/lib/hw/lp87524j_q1/lp87524j_q1.h new file mode 100644 index 00000000..20fc83f9 --- /dev/null +++ b/src/lib/hw/lp87524j_q1/lp87524j_q1.h @@ -0,0 +1,7 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef LP87524J_Q1_H +#define LP87524J_Q1_H + +#endif // LP87524J_Q1_H diff --git a/src/lib/hw/lp87524j_q1/lp87524j_q1.yaml b/src/lib/hw/lp87524j_q1/lp87524j_q1.yaml new file mode 100644 index 00000000..f8d5a0a3 --- /dev/null +++ b/src/lib/hw/lp87524j_q1/lp87524j_q1.yaml @@ -0,0 +1,66 @@ +name: LP87524J_Q1 +revision: 0.0.1 +addr_width: 16 +data_width: 16 + +pages: +- name: Main + regs: + - addr: 0x04 + name: BUCK1_CTRL1 + fields: + - bits: 7 + name: EN_BUCK1 + mode: RW + dflt: 1 + desc: Enable Buck1 regulator + opts: + 0: Buck1 regulator is disabled + 1: Buck1 regulator is enabled + - bits: 6 + name: EN_PIN_CTRL1 + mode: RW + dflt: 1 + desc: Enable EN1/2/3 pin control for Buck1 + opts: + 0: Only EN_BUCK1 bit controls Buck1 + 1: EN_BUCK1 bit AND ENx pin control Buck1 + - bits: '5:4' + name: BUCK1_EN_PIN_SELECT + mode: RW + dflt: 0x0 + desc: Enable EN1/2/3 pin control for Buck1 + opts: + 0x0: EN_BUCK1 bit AND EN1 pin control Buck1 + 0x1: EN_BUCK1 bit AND EN2 pin control Buck1 + 0x2: EN_BUCK1 bit AND EN3 pin control Buck1 + 0x3: Reserved + - bits: 3 + name: EN_ROOF_FLOOR1 + mode: RW + dflt: 0 + desc: Enable Roof/Floor control of EN1/2/3 pin if EN_PIN_CTRL1 = 1 + opts: + 0: Enable/Disable (1/0) control + 1: Roof/Floor (1/0) control + - bits: 2 + name: EN_RDIS1 + mode: RW + dflt: 1 + desc: Enable output discharge resistor when Buck1 is disabled + opts: + 0: Discharge resistor disabled + 1: Discharge resistor enabled + - bits: 1 + name: BUCK1_FPWM + mode: RW + dflt: 0 + desc: Forces the Buck1 regulator to operate in PWM mode + opts: + 0: Automatic transitions between PFM and PWM modes (AUTO mode). + 1: Forced to PWM operation + - bits: 0 + name: BUCK1_CTRL1_RESERVED_0 + mode: RW + dflt: 0 + desc: '' From cae8f914106770ad574eb1dcbd8b894dbcbd98ad Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 18:00:19 +0300 Subject: [PATCH 040/397] gen_h.py generator update --- src/hwparser/gen_h.py | 70 ++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/src/hwparser/gen_h.py b/src/hwparser/gen_h.py index 665caf09..b3f69e87 100755 --- a/src/hwparser/gen_h.py +++ b/src/hwparser/gen_h.py @@ -17,7 +17,7 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: self.o_name = str(os.path.splitext(os.path.basename(filename))[0]) self.l_name = self.o_name.lower() self.h_name = self.o_name.upper() - + self.parser = parser self.addr_width = parser.addr_width self.data_width = parser.data_width @@ -26,7 +26,7 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: self.page_prefix = parser.page_prefix self.reg_prefix = "%s_" % parser.reg_prefix.upper() if len(parser.reg_prefix) > 0 else '' - self.field_prefix_ar = [ a.lower() for a in parser.field_prefix_ar ] + self.field_prefix_ar = [a.lower() for a in parser.field_prefix_ar] # Flat all pages self.regs = {} @@ -36,8 +36,8 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: name = "%s_%s" % (pname, r.name) if self.page_prefix else r.name if name in self.regs.keys(): - raise(Exception("Rigester `%s` is already in flat map! Rename it" % name)) - + raise (Exception("Rigester `%s` is already in flat map! Rename it" % name)) + # TODO: parse ucnt if r.ucnt == 1: self.regs[name] = r.addr @@ -48,14 +48,12 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: for k in range(r.ucnt): self.regs[name + "_BY%d" % (r.ucnt - k - 1)] = r.addr_l + k - def regName(self, reg: reg_parser.ParserRegs) -> str: if self.page_prefix: return "%s_%s" % (reg.page.name.upper(), reg.name) return reg.name - def fieldName(self, field: reg_parser.ParserFields) -> str: pfx = [] for i in self.field_prefix_ar: @@ -66,7 +64,7 @@ def fieldName(self, field: reg_parser.ParserFields) -> str: elif i == "regaddr": pfx.append("%02x" % field.reg.addr_l) else: - raise(Exception("Unknown prefix type '%s'" % i)) + raise (Exception("Unknown prefix type '%s'" % i)) if len(pfx) > 0: pfx.append(field.name) @@ -74,16 +72,22 @@ def fieldName(self, field: reg_parser.ParserFields) -> str: return field.name - def normalize(self, name: str) -> str: return (name.replace('-', '_') - .replace('.', '_') - .replace(',', '_') - .replace(' ', '_') - .replace('(', '') - .replace('|', 'OR') - .replace(')', '') - .replace('/', 'DIV')) + .replace('<=', 'LE') + .replace('>=', 'GE') + .replace('>', 'GT') + .replace('<', 'LT') + .replace('=', 'EQ') + .replace('+', 'PL') + .replace("'", 'MARK') + .replace('.', '_') + .replace(',', '_') + .replace(' ', '_') + .replace('(', '') + .replace('|', 'OR') + .replace(')', '') + .replace('/', 'DIV')) def ser_ch_fenum(self, reg: reg_parser.ParserRegs, name: str) -> str: vt = False @@ -96,7 +100,7 @@ def ser_ch_fenum(self, reg: reg_parser.ParserRegs, name: str) -> str: str += "};" if vt and len(reg.fields) == 1: return "" - + return str def generate_setter_expression(self, f, custom_name) -> str: @@ -165,13 +169,13 @@ def ser_ch_enum(self, name: str, en_dict: dict, prefix: str = "") -> str: str = "enum %s_t {\n" % name for i, v in en_dict.items(): str += "%s%s%s = 0x%x,\n" % (GenH.TAB, prefix, i.replace('-', '_') - .replace('.', '_') - .replace(',', '_') - .replace(' ', '_') - .replace('(', '') - .replace('|', 'OR') - .replace(')', '') - .replace('/', 'DIV'), v) + .replace('.', '_') + .replace(',', '_') + .replace(' ', '_') + .replace('(', '') + .replace('|', 'OR') + .replace(')', '') + .replace('/', 'DIV'), v) str += "};" return str @@ -213,10 +217,12 @@ def write_ch(self, filename): print(self.ser_cf_fmacro(r)) if r.ucnt == 1: - defc = "#define MAKE_%s_%s(%s)" % (self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) - #defc += " ((%s << %d) |" % (name, self.data_width) + defc = "#define MAKE_%s_%s(%s)" % ( + self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) + # defc += " ((%s << %d) |" % (name, self.data_width) defc += " %s(%s," % (def_macro, name) - defc += reduce(lambda x, y: "%s | %s" % (x, y), [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields ]) + defc += reduce(lambda x, y: "%s | %s" % (x, y), + [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields]) defc += ")" print(defc) else: @@ -228,8 +234,10 @@ def write_ch(self, filename): value_msk = reduce(lambda x, y: x | y, [x.mask for x in r.fields]) value_off = reduce(lambda x, y: min(x, y), [x.bits_l for x in r.fields]) if len(r.fields) > 1: - defc = "#define MAKE_%s_%s_LONG(%s) (" % (self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) - defc += reduce(lambda x, y: "%s | %s" % (x, y), [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields ]) + defc = "#define MAKE_%s_%s_LONG(%s) (" % ( + self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) + defc += reduce(lambda x, y: "%s | %s" % (x, y), + [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields]) defc += ")" print(defc) @@ -247,9 +255,9 @@ def write_ch(self, filename): else: # defc += " ((%s_BY%d << %d) | (((value) << %d) & 0x%x))" % (name, u, self.data_width, -by_off, by_msk) defc += " (((value) << %d) & 0x%x))" % (-by_off, by_msk) - print(defc) + print(defc) - # if 'c-cache' in self.parser.raw_yaml: + # if 'c-cache' in self.parser.raw_yaml: # cc = self.parser.raw_yaml['c-cache'] # if 'regs' in cc: # print("\n\n/* Cached operations */") @@ -284,10 +292,10 @@ def parse_c_cache(self, cregs): fn += "p->%s = (p->%s & ~%s_MSK) | ((%s << %s_OFF) & %s_MSK); }" % (regn, regn, FLDN, fname, FLDN, FLDN) print(fn) - def write_vh(self, filename): pass + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Debug UI options') parser.add_argument('--yaml', dest='yaml', type=str, From bcf66b0c184ca2c49266633bdc902a8ad68f5397 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 19:27:00 +0300 Subject: [PATCH 041/397] update yamls, add bus info --- src/lib/hw/CMakeLists.txt | 4 ++-- src/lib/hw/ad5662/ad5662.yaml | 5 +++++ src/lib/hw/lmk1d1208i/lmk1d1208i.yaml | 5 +++++ src/lib/hw/lmx1204/lmx1204.yaml | 5 +++++ src/lib/hw/lmx1205/lmx1205.yaml | 5 +++++ src/lib/hw/lmx1214/lmx1214.yaml | 5 +++++ .../hw/{lp87524j_q1/lp87524j_q1.c => lp87524j/lp87524j.c} | 4 ++-- .../hw/{lp87524j_q1/lp87524j_q1.h => lp87524j/lp87524j.h} | 6 +++--- .../lp87524j_q1.yaml => lp87524j/lp87524j.yaml} | 7 ++++++- 9 files changed, 38 insertions(+), 8 deletions(-) rename src/lib/hw/{lp87524j_q1/lp87524j_q1.c => lp87524j/lp87524j.c} (63%) rename src/lib/hw/{lp87524j_q1/lp87524j_q1.h => lp87524j/lp87524j.h} (50%) rename src/lib/hw/{lp87524j_q1/lp87524j_q1.yaml => lp87524j/lp87524j.yaml} (93%) diff --git a/src/lib/hw/CMakeLists.txt b/src/lib/hw/CMakeLists.txt index 0cfac0d8..2282e881 100644 --- a/src/lib/hw/CMakeLists.txt +++ b/src/lib/hw/CMakeLists.txt @@ -2,10 +2,10 @@ # SPDX-License-Identifier: MIT set(HW_FILES si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 - lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j_q1 lmx2820) + lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820) # YAML registers generators set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 - lmk04832 xra1405 tca6424a adf4002b lp875484 lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j_q1 lmx2820) + lmk04832 xra1405 tca6424a adf4002b lp875484 lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820) foreach(I ${HW_FILES}) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/${I} HW_DIR_FILES) diff --git a/src/lib/hw/ad5662/ad5662.yaml b/src/lib/hw/ad5662/ad5662.yaml index 18fc4fc6..b48f5f8e 100644 --- a/src/lib/hw/ad5662/ad5662.yaml +++ b/src/lib/hw/ad5662/ad5662.yaml @@ -1,5 +1,10 @@ name: AD5662 revision: 0.0.1 +processors: [ c ] +bus: + type: SPI + wr_mask: 0x80000000 + usdr_path: /debug/hw/ad5662/*/reg addr_width: 16 data_width: 24 diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml b/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml index 11a86215..058eb990 100644 --- a/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml @@ -1,5 +1,10 @@ name: LMK1D1208I revision: 0.0.1 +processors: [ c ] +bus: + type: I2C + wr_mask: 0x80000000 + usdr_path: /debug/hw/lmk1d1208i/*/reg addr_width: 16 data_width: 16 diff --git a/src/lib/hw/lmx1204/lmx1204.yaml b/src/lib/hw/lmx1204/lmx1204.yaml index 40a0e545..5d5fda10 100644 --- a/src/lib/hw/lmx1204/lmx1204.yaml +++ b/src/lib/hw/lmx1204/lmx1204.yaml @@ -1,5 +1,10 @@ name: LMX1204 revision: 0.0.1 +processors: [ c ] +bus: + type: SPI + wr_mask: 0x80000000 + usdr_path: /debug/hw/lmx1204/*/reg addr_width: 16 data_width: 16 diff --git a/src/lib/hw/lmx1205/lmx1205.yaml b/src/lib/hw/lmx1205/lmx1205.yaml index 88a4bfb4..06ce0ad8 100644 --- a/src/lib/hw/lmx1205/lmx1205.yaml +++ b/src/lib/hw/lmx1205/lmx1205.yaml @@ -1,5 +1,10 @@ name: LMX1205 revision: 0.0.1 +processors: [ c ] +bus: + type: SPI + wr_mask: 0x80000000 + usdr_path: /debug/hw/lmx1205/*/reg addr_width: 16 data_width: 16 diff --git a/src/lib/hw/lmx1214/lmx1214.yaml b/src/lib/hw/lmx1214/lmx1214.yaml index 76a28cd9..f8726397 100644 --- a/src/lib/hw/lmx1214/lmx1214.yaml +++ b/src/lib/hw/lmx1214/lmx1214.yaml @@ -1,5 +1,10 @@ name: LMX1214 revision: 0.0.1 +processors: [ c ] +bus: + type: SPI + wr_mask: 0x80000000 + usdr_path: /debug/hw/lmx1214/*/reg addr_width: 16 data_width: 16 diff --git a/src/lib/hw/lp87524j_q1/lp87524j_q1.c b/src/lib/hw/lp87524j/lp87524j.c similarity index 63% rename from src/lib/hw/lp87524j_q1/lp87524j_q1.c rename to src/lib/hw/lp87524j/lp87524j.c index 3f53aa1f..986df9de 100644 --- a/src/lib/hw/lp87524j_q1/lp87524j_q1.c +++ b/src/lib/hw/lp87524j/lp87524j.c @@ -1,6 +1,6 @@ // Copyright (c) 2025 Wavelet Lab // SPDX-License-Identifier: MIT -#include "def_lp87524j_q1.h" -#include "lp87524j_q1.h" +#include "def_lp87524j.h" +#include "lp87524j.h" #include "usdr_logging.h" diff --git a/src/lib/hw/lp87524j_q1/lp87524j_q1.h b/src/lib/hw/lp87524j/lp87524j.h similarity index 50% rename from src/lib/hw/lp87524j_q1/lp87524j_q1.h rename to src/lib/hw/lp87524j/lp87524j.h index 20fc83f9..4ba9b4b6 100644 --- a/src/lib/hw/lp87524j_q1/lp87524j_q1.h +++ b/src/lib/hw/lp87524j/lp87524j.h @@ -1,7 +1,7 @@ // Copyright (c) 2025 Wavelet Lab // SPDX-License-Identifier: MIT -#ifndef LP87524J_Q1_H -#define LP87524J_Q1_H +#ifndef LP87524J +#define LP87524J -#endif // LP87524J_Q1_H +#endif // LP87524J diff --git a/src/lib/hw/lp87524j_q1/lp87524j_q1.yaml b/src/lib/hw/lp87524j/lp87524j.yaml similarity index 93% rename from src/lib/hw/lp87524j_q1/lp87524j_q1.yaml rename to src/lib/hw/lp87524j/lp87524j.yaml index f8d5a0a3..6f15c94e 100644 --- a/src/lib/hw/lp87524j_q1/lp87524j_q1.yaml +++ b/src/lib/hw/lp87524j/lp87524j.yaml @@ -1,5 +1,10 @@ -name: LP87524J_Q1 +name: LP87524J revision: 0.0.1 +processors: [ c ] +bus: + type: I2C + wr_mask: 0x80000000 + usdr_path: /debug/hw/lp87524j/*/reg addr_width: 16 data_width: 16 From 5f0a14d71ad712b95e1e4ab099af2c7d2fd0706f Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 2 Apr 2025 23:37:45 +0300 Subject: [PATCH 042/397] tmp version with TI dump --- src/lib/hw/lmk05318/lmk05318.c | 10 + src/lib/hw/lmk05318/lmk05318_rom.h | 339 +++++++++++++++++++++++++++++ 2 files changed, 349 insertions(+) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index e91d0870..da88d6f7 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -426,6 +426,15 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } +#if 1 + res = lmk05318_reg_wr_n(out, lmk05318_rom_test, SIZEOF_ARRAY(lmk05318_rom_test)); + if (res) + return res; + + return 0; +#endif + +#if 0 res = lmk05318_init(out, dpll_mode); if(res) { @@ -460,6 +469,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d writing registers", res); return res; } +#endif res = dry_run ? 0 : lmk05318_softreset(out); if(res) diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index e5cad551..caa88b73 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -1,6 +1,345 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +static const uint32_t lmk05318_rom_test[] = +{ + //0x000010, + //0x00010B, + //0x000235, + //0x000332, + //0x000404, + //0x00050E, + //0x000617, + //0x00078E, + //0x000802, + //0x000AC8, + //0x000B00, + 0x000C1B, + 0x000D08, + 0x000E00, + 0x000F00, + 0x001000, + 0x00111D, + 0x0012FF, + 0x001308, + 0x001420, + 0x001501, + 0x001600, + 0x001755, + 0x001855, + 0x001900, + 0x001A00, + 0x001B00, + 0x001C01, + 0x001D13, + 0x001E40, + 0x002044, + 0x002300, + 0x002403, + 0x002500, + 0x002600, + 0x002703, + 0x002803, + 0x002900, + 0x002A11, + 0x002BC2, + 0x002C00, + 0x002D03, + 0x002E11, + 0x002F07, + 0x003050, + 0x00314A, + 0x003200, + 0x003310, + 0x003410, + 0x003513, + 0x003610, + 0x003710, + 0x003809, + 0x003900, + 0x003A0F, + 0x003B00, + 0x003C0F, + 0x003D3E, + 0x003EF9, + 0x003F3E, + 0x004095, + 0x004102, + 0x0042F8, + 0x0043FF, + 0x004408, + 0x004500, + 0x004600, + 0x004700, + 0x004833, + 0x004900, + 0x004A00, + 0x004B00, + 0x004C00, + 0x004D0F, + 0x004E00, + 0x004F11, + 0x005080, + 0x00510A, + 0x005200, + 0x00530E, + 0x0054A6, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D0E, + 0x005EA6, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + 0x006429, + 0x006501, + 0x006622, + 0x00670F, + 0x00681F, + 0x006905, + 0x006A00, + 0x006B64, + 0x006C00, + 0x006D32, + 0x006E00, + 0x006F00, + 0x007000, + 0x007127, + 0x007210, + 0x007303, + 0x007400, + 0x007500, + 0x007600, + 0x007700, + 0x007800, + 0x007900, + 0x007A00, + 0x007B28, + 0x007C00, + 0x007D11, + 0x007E79, + 0x007F7A, + 0x008000, + 0x008101, + 0x008200, + 0x008301, + 0x008401, + 0x008577, + 0x008600, + 0x00872B, + 0x008800, + 0x008928, + 0x008AE5, + 0x008B03, + 0x008C02, + 0x008D00, + 0x008E01, + 0x008F01, + 0x009077, + 0x009101, + 0x009289, + 0x009320, + 0x00950D, + 0x009600, + 0x009701, + 0x00980D, + 0x009929, + 0x009A24, + 0x009B32, + 0x009C01, + //0x009D00, + 0x009E00, + 0x009F00, + 0x00A0FC, + 0x00A132, + 0x00A200, + //0x00A400, + 0x00A500, + 0x00A701, + 0x00B200, + 0x00B400, + 0x00B500, + 0x00B600, + 0x00B700, + 0x00B800, + 0x00B905, + 0x00BA08, + 0x00BB00, + 0x00BC00, + 0x00BD00, + 0x00BE2C, + 0x00BF00, + 0x00C050, + 0x00C100, + 0x00C200, + 0x00C300, + 0x00C400, + 0x00C51D, + 0x00C600, + 0x00C700, + 0x00C81D, + 0x00C900, + 0x00CA00, + 0x00CB00, + 0x00CC15, + 0x00CD00, + 0x00CE00, + 0x00CF15, + 0x00D000, + 0x00D114, + 0x00D200, + 0x00D316, + 0x00D400, + 0x00D514, + 0x00D600, + 0x00D716, + 0x00D80F, + 0x00D900, + 0x00DA00, + 0x00DB19, + 0x00DC6E, + 0x00DD00, + 0x00DE03, + 0x00DF0D, + 0x00E047, + 0x00E100, + 0x00E200, + 0x00E319, + 0x00E46E, + 0x00E500, + 0x00E603, + 0x00E70D, + 0x00E847, + 0x00E90A, + 0x00EA0A, + 0x00EB00, + 0x00ECC3, + 0x00ED50, + 0x00EE00, + 0x00EF00, + 0x00F0C3, + 0x00F150, + 0x00F200, + 0x00F300, + 0x00F400, + 0x00F912, + 0x00FA00, + 0x00FB13, + 0x00FC2C, + 0x00FD00, + 0x00FE00, + 0x00FF00, + 0x010000, + 0x010101, + 0x010200, + 0x010301, + 0x010402, + 0x010580, + 0x010600, + 0x010700, + 0x010800, + 0x010900, + 0x010AC8, + 0x010BA0, + 0x010C0C, + 0x010D0A, + 0x010E02, + 0x010F14, + 0x011000, + 0x011100, + 0x011200, + 0x01130E, + 0x01140C, + 0x01150E, + 0x011609, + 0x011708, + 0x011809, + 0x011907, + 0x011A0D, + 0x011B07, + 0x011C1E, + 0x011D1E, + 0x011E02, + 0x011F30, + 0x012000, + 0x0121EE, + 0x012202, + 0x0123CA, + 0x012409, + 0x012501, + 0x012600, + 0x01272C, + 0x012808, + 0x01290C, + 0x012A08, + 0x012B01, + 0x012C00, + 0x012D1C, + 0x012E20, + 0x012F01, + 0x013001, + 0x013100, + 0x013200, + 0x013300, + 0x013410, + 0x0135AA, + 0x0136AA, + 0x0137AA, + 0x0138AA, + 0x0139AA, + 0x013AFF, + 0x013BFF, + 0x013CFF, + 0x013DFF, + 0x013EFF, + 0x013F03, + 0x014000, + 0x01410A, + 0x014200, + 0x014324, + 0x01449F, + 0x014500, + 0x014600, + 0x014798, + 0x014896, + 0x014980, + 0x014A00, + 0x014B64, + 0x014C00, + 0x014D00, + 0x014E3D, + 0x014F09, + 0x015000, + 0x015100, + 0x015200, + 0x015300, + 0x015400, + 0x015500, + 0x015600, + 0x015700, + 0x015800, + 0x015900, + 0x015A02, + 0x015B00, + 0x015C00, + 0x015D00, + 0x015E00, + 0x015F00, + 0x016000, + 0x016528, + 0x016F00, + 0x019B0C, +}; + + static const uint32_t lmk05318_rom[] = { // 0x000010, // 0x00010B, From 8f94015031e1068ed5e179fead3164b15f99baf8 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 13:06:01 +0300 Subject: [PATCH 043/397] many fixes in yaml & logic --- src/lib/device/pe_sync/pe_sync.c | 22 ++- src/lib/hw/lmk05318/lmk05318.c | 294 +++++++++++++++++++++++------- src/lib/hw/lmk05318/lmk05318.h | 5 +- src/lib/hw/lmk05318/lmk05318.yaml | 71 +++++++- 4 files changed, 314 insertions(+), 78 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index a86160f2..de01fff5 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -288,19 +288,27 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; - usleep(1000); //wait until lmk digests all this + usleep(100); //wait until lmk digests all this //wait for lock - const unsigned lock_expected = LMK05318_LOS_XO | LMK05318_LOL_PLL1 | - (d->gen.vco2_freq ? LMK05318_LOL_PLL2 : 0) | - (xo.fdet_bypass ? 0 : LMK05318_LOS_FDET_XO) | - (use_dpll ? (LMK05318_LOPL_DPLL | LMK05318_LOFL_DPLL) : 0); + //APLL1/DPLL + res = lmk05318_wait_apll1_lock(&d->gen, use_dpll, 10000); + //APLL2 (if needed) + res = res ? res : (d->gen.vco2_freq ? lmk05318_wait_apll2_lock(&d->gen, 10000) : 0); + + unsigned los_msk; + lmk05318_check_lock(&d->gen, &los_msk, false /*silent*/); //just to log state - res = lmk05318_wait_lock(&d->gen, lock_expected, 10000); if(res) + { + USDR_LOG("SYNC", USDR_LOG_WARNING, "PLLs not locked during specified timeout"); return res; + } - + //sync + res = lmk05318_sync(&d->gen); + if(res) + return res; return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index da88d6f7..1c40abfc 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -163,12 +163,59 @@ static int lmk05318_softreset(lmk05318_state_t* out) return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; } +int lmk05318_sync(lmk05318_state_t* out) +{ + uint8_t reg_ctrl; + const uint8_t mask = ((uint8_t)1 << SYNC_SW_OFF); + + int res = lmk05318_reg_rd(out, DEV_CTL, ®_ctrl); + if(res) + return res; + + uint32_t regs[] = + { + MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl | mask), + MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl & ~mask), + }; + + return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; +} + +int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask) +{ + for(unsigned ch = 0; ch < 8; ++ch) + { + bool muted = ((chmask >> ch) & 0x1) == 0x1; + if(muted) + { + USDR_LOG("5318", USDR_LOG_WARNING, "LMK05318 OUT CH%u is MUTED", ch); + } + } + + uint32_t reg = MAKE_LMK05318_REG_WR(OUT_MUTE, chmask); + return lmk05318_reg_wr_n(out, ®, 1); +} + + static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) { uint32_t regs[] = { - MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1), //R12 - MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, dpllmode ? 1 : 0), //R252 + MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1, 1, 1), //R12 set APLL1 mode - DPLL | Free-run + MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, dpllmode ? 1 : 0), //R252 enable/disable DPLL + MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, dpllmode ? 0 : 1), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise + MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 0), //R40 set fixed APPL2 denumerator always + MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 set PLL clock cfg + MAKE_LMK05318_OUTSYNCCTL(1, 1, 1), //R70 enable APLL1/APLL2 channel sync + MAKE_LMK05318_OUTSYNCEN(1, 1, 1, 1, 1, 1), //R71 enable ch0..ch7 out sync + MAKE_LMK05318_MUTELVL1(CH3_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, + CH2_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, + CH1_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, + CH0_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R23 set ch0..3 mute levels + MAKE_LMK05318_MUTELVL2(CH7_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, + CH6_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, + CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, + CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -426,7 +473,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } -#if 1 +#if 0 res = lmk05318_reg_wr_n(out, lmk05318_rom_test, SIZEOF_ARRAY(lmk05318_rom_test)); if (res) return res; @@ -434,7 +481,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return 0; #endif -#if 0 +#if 1 res = lmk05318_init(out, dpll_mode); if(res) { @@ -604,13 +651,13 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned fvco2, pd1, pd2); // Disable uint32_t regs[] = { - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), //R100 Deactivate APLL2 }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } unsigned n = fvco2 / fref; - unsigned num = (fvco2 - n * (uint64_t)fref) * (1ull << 24) / fref; + unsigned num = (fvco2 - n * (uint64_t)fref) * ((1ull << 24) - 1) / fref; int res; USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 FVCO=%" PRIu64 " N=%d NUM=%d PD1=%d PD2=%d\n", fvco2, n, num, pd1, pd2); @@ -626,14 +673,13 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned } uint32_t regs[] = { - //MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), //R100 MAKE_LMK05318_PLL2_CTRL2(pd2 - 1, pd1 - 1), //R102 MAKE_LMK05318_PLL2_NDIV_BY0(n), //R135 MAKE_LMK05318_PLL2_NDIV_BY1(n), //R134 MAKE_LMK05318_PLL2_NUM_BY0(num), //R138 MAKE_LMK05318_PLL2_NUM_BY1(num), //R137 MAKE_LMK05318_PLL2_NUM_BY2(num), //R136 - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), //R100 + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), //R100 Activate APLL2 }; res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -678,9 +724,9 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) } uint32_t regs[] = { - MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0), //R42 - MAKE_LMK05318_XO_CLKCTL2(xo_type_raw), //R43 - MAKE_LMK05318_XO_CONFIG(d->xo.pll1_fref_rdiv - 1), //R44 + MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0, 0, 1), //R42 + MAKE_LMK05318_XO_CLKCTL2(1, xo_type_raw, 2), //R43 + MAKE_LMK05318_XO_CONFIG(d->xo.pll1_fref_rdiv - 1), //R44 }; int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -695,47 +741,120 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) unsigned fref = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); uint64_t fvco = VCO_APLL1; unsigned n = fvco / fref; - uint64_t num = (fvco - n * (uint64_t)fref) * (1ull << 40) / fref; - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 "\n", fvco, n, num); + //in DPLL mode we use FIXED 40-bit APLL1 denominator and programmed 40-bit numerator + if(dpll_mode) + { + uint64_t num = (fvco - n * (uint64_t)fref) * ((1ull << 40) - 1) / fref; - uint32_t regs[] = { - //MAKE_LMK05318_PLL1_CTRL0(1), //R74 - MAKE_LMK05318_PLL1_MODE(dpll_mode ? 1 : 0), //R116 - MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 - MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 - MAKE_LMK05318_PLL1_NUM_BY0(num), //R114 - MAKE_LMK05318_PLL1_NUM_BY1(num), //R113 - MAKE_LMK05318_PLL1_NUM_BY2(num), //R112 - MAKE_LMK05318_PLL1_NUM_BY3(num), //R111 - MAKE_LMK05318_PLL1_NUM_BY4(num), //R110 - MAKE_LMK05318_PLL1_CTRL0(0), //R74 - }; + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 " DEN=FIXED\n", fvco, n, num); - int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; + uint32_t regs[] = { + MAKE_LMK05318_PLL1_MODE(0, 0, 1), //R116 DPLL mode + MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 NDIV + MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 NDIV + MAKE_LMK05318_PLL1_NUM_BY0(num), //R110 | + MAKE_LMK05318_PLL1_NUM_BY1(num), //R111 | + MAKE_LMK05318_PLL1_NUM_BY2(num), //R112 | 40-bit NUM + MAKE_LMK05318_PLL1_NUM_BY3(num), //R113 | + MAKE_LMK05318_PLL1_NUM_BY4(num), //R114 | + MAKE_LMK05318_PLL1_CTRL0(0), //R74 Activate APLL1 + }; + + int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + if (res) + return res; + } + // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator + else + { + double frac = (double)fvco / fref - n; + const uint32_t den = ((uint32_t)1 << 24) - 1; //max 24-bit + const uint32_t num = (frac * den + 0.5); + + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu32 " DEN=%" PRIu32 "\n", fvco, n, num, den); + + uint32_t regs[] = { + MAKE_LMK05318_PLL1_MODE(0, 0, 0), //R116 free-run mode + MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 NDIV + MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 NDIV + + MAKE_LMK05318_REG_WR(PLL1_NUM_BY4, (uint8_t)den), //R114 + MAKE_LMK05318_REG_WR(PLL1_NUM_BY3, (uint8_t)(den >> 8)), //R113 | 24-bit DEN + MAKE_LMK05318_REG_WR(PLL1_NUM_BY2, (uint8_t)(den >> 16)), //R112 + + MAKE_LMK05318_REG_WR(PLL1_NUM_BY1, (uint8_t)num), //R111 + MAKE_LMK05318_REG_WR(PLL1_NUM_BY0, (uint8_t)(num >> 8)), //R110 | 24-bit NUM + MAKE_LMK05318_PLL1_24B_NUM_23_16((uint8_t)(num >> 16)), //R339 + + MAKE_LMK05318_PLL1_CTRL0(0), //R74 Activate APLL1 + }; + + int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + if (res) + return res; + } return 0; } +static inline uint64_t lmk05318_max_odiv(unsigned port) +{ + switch(port) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: return ((uint64_t)1 << 8); + case 7: return ((uint64_t)1 << 32); + } + return 1; +} int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) { - if (port > 7) + if (port > (LMK05318_MAX_OUT_PORTS - 1) || udiv < 1 || udiv > lmk05318_max_odiv(port)) return -EINVAL; - if (udiv == 0) + + //out7 is special + if(port == 7) + { + uint64_t div_stage2 = udiv >> 8; + div_stage2 = div_stage2 ? div_stage2 : 1; + uint8_t div_stage1 = udiv / div_stage2; + + --div_stage1; + --div_stage2; + + uint32_t regs[] = + { + MAKE_LMK05318_OUTDIV_7(div_stage1), + MAKE_LMK05318_OUTDIV_7_STG2_BY0(div_stage2), + MAKE_LMK05318_OUTDIV_7_STG2_BY1(div_stage2), + MAKE_LMK05318_OUTDIV_7_STG2_BY2(div_stage2), + }; + + return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + } + + uint32_t reg = 0; + switch(port) + { + case 6: reg = MAKE_LMK05318_OUTDIV_6(udiv - 1); break; + case 5: reg = MAKE_LMK05318_OUTDIV_5(udiv - 1); break; + case 4: reg = MAKE_LMK05318_OUTDIV_4(udiv - 1); break; + case 3: + case 2: reg = MAKE_LMK05318_OUTDIV_2_3(udiv - 1); break; + case 1: + case 0: reg = MAKE_LMK05318_OUTDIV_0_1(udiv-1); break; + default: return -EINVAL; + } - unsigned div = udiv - 1; - uint32_t regs[] = { - (port == 7) ? MAKE_LMK05318_OUTDIV_7(div) : - (port == 6) ? MAKE_LMK05318_OUTDIV_6(div) : - (port == 5) ? MAKE_LMK05318_OUTDIV_5(div) : - (port == 4) ? MAKE_LMK05318_OUTDIV_4(div) : - (port == 3 || port == 2) ? MAKE_LMK05318_OUTDIV_2_3(div) : MAKE_LMK05318_OUTDIV_0_1(div), - }; - return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + return lmk05318_add_reg_to_map(d, ®, 1); } static int lmk05318_set_out_mux_ex(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) @@ -769,24 +888,6 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned return lmk05318_set_out_mux_ex(d, port, (pll1 ? OUT_PLL_SEL_APLL1_P1 : OUT_PLL_SEL_APLL2_P1), otype); } -static uint64_t lmk05318_max_odiv(unsigned port) -{ - assert(port < LMK05318_MAX_OUT_PORTS); - - switch(port) - { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: return 256ull; - case 7: return 256ull * 256 * 256 * 256; - } - return 1; -} - static range_t lmk05318_get_freq_range(const lmk05318_out_config_t* cfg) { range_t r; @@ -1607,7 +1708,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned return 0; } -static void lmk05318_decode_lock_mask(unsigned m, char* s) +static inline void lmk05318_decode_los_mask(unsigned m, char* s) { if(!s) return; @@ -1655,7 +1756,7 @@ int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent) if(!silent) { char ss[255]; - lmk05318_decode_lock_mask(losval, ss); + lmk05318_decode_los_mask(losval, ss); USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 LOS_MASK=[%s] %02x:%02x:%02x\n", ss, los[0], los[1], los[2]); } @@ -1663,23 +1764,40 @@ int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent) return 0; } -int lmk05318_wait_lock(lmk05318_state_t* d, unsigned lock_expected, unsigned timeout) +int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeout) { int res = 0; - unsigned lock_msk = 0; unsigned elapsed = 0; bool locked = false; + uint8_t reg; + unsigned los_msk; while(timeout == 0 || elapsed < timeout) { - res = lmk05318_check_lock(d, &lock_msk, true /*silent*/); + res = lmk05318_reg_rd(d, PLL1_CALSTAT1, ®); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 read(PLL1_CALSTAT1) error:%d", res); + return res; + } + const bool pll1_vm_inside = reg & PLL1_VM_INSIDE_MSK; + + res = lmk05318_check_lock(d, &los_msk, true/*silent*/); if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 lmk05318_check_lock() error:%d", res); return res; } - locked = (lock_msk & lock_expected) == lock_expected; + if(dpll_mode) + { + locked = pll1_vm_inside && !(los_msk & LMK05318_LOPL_DPLL) && !(los_msk & LMK05318_LOFL_DPLL); + } + else + { + locked = pll1_vm_inside && (los_msk & LMK05318_BAW_LOCK); + } + if(locked) break; @@ -1687,16 +1805,56 @@ int lmk05318_wait_lock(lmk05318_state_t* d, unsigned lock_expected, unsigned tim elapsed += 100; } - char sexp[255], sgot[255]; - lmk05318_decode_lock_mask(lock_expected, sexp); - lmk05318_decode_lock_mask(lock_msk, sgot); + if(!locked) + { + USDR_LOG("5318", USDR_LOG_ERROR, "APLL1 is not locked!"); + return -ETIMEDOUT; + } + + USDR_LOG("5318", USDR_LOG_INFO, "APLL1 locked OK"); + return 0; +} + +int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) +{ + int res = 0; + unsigned elapsed = 0; + bool locked = false; + uint8_t reg; + unsigned los_msk; + + while(timeout == 0 || elapsed < timeout) + { + res = lmk05318_reg_rd(d, PLL2_CALSTAT1, ®); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 read(PLL2_CALSTAT1) error:%d", res); + return res; + } + const bool pll2_vm_inside = reg & PLL2_VM_INSIDE_MSK; + + res = lmk05318_check_lock(d, &los_msk, true/*silent*/); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 lmk05318_check_lock() error:%d", res); + return res; + } + + locked = pll2_vm_inside && !(los_msk & LMK05318_LOL_PLL2); + + if(locked) + break; + + usleep(100); + elapsed += 100; + } if(!locked) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 is not locked! expected:[%s] got:[%s]", sexp, sgot); + USDR_LOG("5318", USDR_LOG_ERROR, "APLL2 is not locked!"); return -ETIMEDOUT; } - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 locked OK [%s]", sgot); + USDR_LOG("5318", USDR_LOG_INFO, "APLL2 locked OK"); return 0; } diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 6b4ad89e..97ef8065 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -154,8 +154,11 @@ enum lock_msk { LMK05318_BAW_LOCK = 64, }; +int lmk05318_sync(lmk05318_state_t* out); +int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask); int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); -int lmk05318_wait_lock(lmk05318_state_t* d, unsigned lock_expected, unsigned timeout); +int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeout); +int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout); int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index 8eaf71ad..6cc96b24 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -78,6 +78,12 @@ pages: - bits: "3" name: SYNC_MUTE desc: Determines if the output drivers are muted during a SYNC event, 0x0 = Do not mute any outputs during SYNC, 0x1 = Mute all outputs during SYNC + - bits: "1" + name: PLLSTRTMODE + desc: PLL Startup Mode . When using cascade mode, PLL1 is fixed to a center value while PLL2 locks. Then PLL1 performs final lock. + - bits: "0" + name: AUTOSTRT + desc: Autostart. If AUTOSTRT is set to 1, the device will automatically initiate the PLL and output start-up sequence after a device reset. A device reset can be triggered by the power-on-reset, PDN pin, or by writing to the RESET_SW bit. If AUTOSTRT is 0, the device will halt after the configuration phase; a subsequent write to set the AUTOSTRT bit will initiate the start-up sequence. In Test mode, the AUTOSTRT bit is ignored after device reset, but start-up can be triggered by a subsequent write to set the AUTOSTART bit. - addr: 0xD name: INT_LIVE0 fields: @@ -385,13 +391,25 @@ pages: - bits: "3" name: XO_FDET_BYP desc: XO Frequency Detector Bypass If bypassed, the XO detector status is ignored and the XO input is considered valid by the PLL control state machines + - bits: "2" + name: XO_DETECT_BYP + desc: XO Amplitude Detector Bypass. If bypassed, the XO input is considered to be valid by the PLL control state machines. XO_DETECT_BYP bit has no effect on the Interrupt register or status outputs. + - bits: "0" + name: XO_BUFSEL + desc: XO Input Buffer Enable - addr: 0x2B name: XO_CLKCTL2 fields: + - bits: "7" + name: XO_CLKCTL2_RESERVED7 + desc: reset=1 - bits: "6-3" name: XO_TYPE desc: XO Input Type; 0x0 = DC-Differential (external termination); 0x1 = AC-Differential (external termination); 0x3 = AC-Differential (internal termination 100-Ω); 0x4 = HCSL (internal termination 50-Ω); 0x8 = CMOS; 0xC = Single-ended (internal termination 50-Ω) opts: *in-opts + - bits: "2-0" + name: XO_CLKCTL2_RESERVED0 + desc: reset=0x10 - addr: 0x2C name: XO_CONFIG fields: @@ -596,6 +614,8 @@ pages: - addr: 0x44 name: PREDRIVER fields: + - bits: "7-4" + name: PREDRIVER_RESERVED - bits: "3-0" name: PLL1_CP_BAW desc: APLL1 Charge Pump Current Gain PLL1_CP_BAW ranges from 0 to 15. Gain = PLL1_CP_BAW x 100 μA. @@ -646,6 +666,12 @@ pages: - bits: "4" name: BAW_LOCKDET_EN desc: BAW Lock Detect Enable + - bits: "3-2" + name: PLL1_CLSDWAIT + desc: Closed Loop Wait Period, VCO calibration time per step (up to 7 steps). + - bits: "1-0" + name: PLL1_VCOWAIT + desc: VCO Wait Period. Timeout counter before starting VCO calibration. - addr: 0x50 name: BAW_LOCKDET_PPM_MAX_BY1 fields: @@ -692,6 +718,9 @@ pages: - addr: 0x65 name: PLL2_CTRL1 fields: + - bits: "2" + name: PLL2_VM_BYP + desc: PLL2 Vtune Monitor Bypass - bits: "1-0" name: PLL2_CP desc: PLL2 Charge Pump Gain; 0x0 = 1.6 mA; 0x1 = 3.2 mA; 0x2 = 4.8 mA; 0x3 = 6.4 mA @@ -716,7 +745,10 @@ pages: fields: - bits: "3-2" name: PLL2_CLSDWAIT - desc: Closed Loop Wait Period VCO calibration time per step (up to 7 steps); 0x0 = 0.3 ms; 0x1 = 3 ms; 0x2 = 30 ms; 0x3 = 300 ms + desc: Closed Loop Wait Period VCO calibration time per step (up to 7 steps); 0x0 = 0.3 ms; 0x1 = 3 ms; 0x2 = 30 ms; 0x3 = 300 ms + - bits: "1-0" + name: PLL2_VCOWAIT + desc: VCO Wait Period. Timeout counter before starting VCO calibration. - addr: "0x6C:0x6D" name: PLL1_NDIV @@ -726,6 +758,15 @@ pages: - addr: 0x73 name: PLL1_MASHCTRL fields: + - bits: "7" + name: PLL1_DUAL_PH_EN + desc: PLL1 DUAL PHASE functionality on the feedback path enabled + - bits: "6" + name: PLL1_MASHSEED1 + desc: Mash Engine seed for second stage + - bits: "5" + name: PLL1_MASHSEED0 + desc: Mash Engine seed for first stage - bits: "4-3" name: PLL1_DTHRMODE desc: APLL1 SDM Dither Mode; 0x0 = Weak; 0x1 = Medium; 0x2 = Strong; 0x3 = Disabled @@ -735,6 +776,12 @@ pages: - addr: 0x74 name: PLL1_MODE fields: + - bits: "2" + name: PLL1_IGNORE_GPIO_PIN + desc: Ignore PLL1 frequency increment or decrement updates via pins + - bits: "1" + name: PLL1_FDEV_EN + desc: Enable PLL1 frequency increment or decrement via pins or registers - bits: "0" name: PLL1_MODE desc: PLL1 operational mode; 0x0 = Free-run mode (APLL only); 0x1 = DPLL mode @@ -748,6 +795,13 @@ pages: name: PLL1_LF_R2 desc: PLL1 Loop Filter R2, Ohm + - addr: 0x82 + name: PLL1_LF_C1 + fields: + - bits: "2-0" + name: PLL1_LF_C1 + desc: PLL1 Loop Filter C1. Not Used, fixed 100 pF + - addr: 0x83 name: PLL1_LF_R3 fields: @@ -983,6 +1037,9 @@ pages: - bits: "7" name: DPLL_ZDM_SYNC_EN desc: DPLL Zero Delay Synchronization enable + - bits: "6" + name: DPLL_ZDM_NDIV_RST_DIS + desc: DPLL NDIV reset disable when ZDM mode is enabled - bits: "5" name: DPLL_SWITCHOVER_1 desc: DPLL Switchover Timer @@ -1019,6 +1076,9 @@ pages: - addr: 0x104 name: DPLL_REF_TDC_CTL fields: + - bits: "4" + name: DPLL_TDC_SW_MODE + desc: DPLL TDC Software Control Enable. Value of TDC control word into the loop-filter is from register dpll_ref_frc_val[35:0]. - bits: "1" name: DPLL_REF_AVOID_SLIP desc: Disable Cycle Slip @@ -1166,9 +1226,16 @@ pages: - addr: "0x14C:0x14F" name: DPLL_REF_UNLOCKDET_CNTSTRT - - addr: "0x150:0x153" + - addr: "0x150:0x152" name: DPLL_REF_UNLOCKDET_VCO_CNTSTRT + - addr: 0x153 + name: PLL1_24B_NUM_23_16 + fields: + - bits: "7-0" + name: PLL1_24B_NUM_23_16 + desc: APPL1 24-bit numerator bits 23:16 + - addr: "0x154:0x159" name: DPLL_REF_SYNC_PH_OFFSET From b125191ffc0b3343be7df6ca2906a684b9650d0f Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 13:55:01 +0300 Subject: [PATCH 044/397] fix in pe_sync logging --- src/lib/device/pe_sync/pe_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index de01fff5..0ebe9f85 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -301,7 +301,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) { - USDR_LOG("SYNC", USDR_LOG_WARNING, "PLLs not locked during specified timeout"); + USDR_LOG("SYNC", USDR_LOG_WARNING, "LMK03518 PLLs not locked during specified timeout"); return res; } From f2bc4bfa4b7e73e2cb364e9db511c9d0f7dae683 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 15:37:17 +0300 Subject: [PATCH 045/397] add rd_mask(RD macro) to parser + fixes for LMX2820 --- src/hwparser/gen_h.py | 8 ++++++++ src/lib/hw/lmx2820/lmx2820.c | 2 +- src/lib/hw/lmx2820/lmx2820.yaml | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/hwparser/gen_h.py b/src/hwparser/gen_h.py index b3f69e87..b1b7a111 100755 --- a/src/hwparser/gen_h.py +++ b/src/hwparser/gen_h.py @@ -185,11 +185,19 @@ def write_ch(self, filename): print(all_regs) # Make register define + if (self.parser.wr_mask is not None) and (self.parser.rd_mask is not None): + raise (Exception("You should specify rd_mask OR wr_mask, but not both!")) + def_macro = "MAKE_%s_REG_WR" % self.h_name def_wr_msk = "0x%x | " % self.parser.wr_mask if self.parser.wr_mask is not None else "" def_wr = "#define %s(a, v) (%s((a) << %d) | ((v) & 0x%x))" % (def_macro, def_wr_msk, self.data_width, (1 << self.data_width) - 1) print(def_wr) + def_macro_rd = "MAKE_%s_REG_RD" % self.h_name + def_rd_msk = "0x%x | " % self.parser.rd_mask if self.parser.rd_mask is not None else "" + def_rd = "#define %s(a) (%s((a) << %d))" % (def_macro_rd, def_rd_msk, self.data_width) + print(def_rd) + # Predefined universal enums for e in self.enums: em = e.replace('-', '_') diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 6cb8876a..0d44940c 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -105,7 +105,7 @@ static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count static int lmx2820_spi_get(lmx2820_state_t* obj, uint16_t addr, uint16_t* out) { uint32_t v; - int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, addr << 16, &v); + int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, MAKE_LMX2820_REG_RD((uint32_t)addr), &v); if (res) return res; diff --git a/src/lib/hw/lmx2820/lmx2820.yaml b/src/lib/hw/lmx2820/lmx2820.yaml index 7b07fcf1..8e4934a6 100644 --- a/src/lib/hw/lmx2820/lmx2820.yaml +++ b/src/lib/hw/lmx2820/lmx2820.yaml @@ -6,9 +6,9 @@ revision: 0.0.1 processors: [ c ] bus: type: SPI - wr_mask: 0x80000000 + rd_mask: 0x800000 usdr_path: /debug/hw/lmx2820/*/reg -addr_width: 16 +addr_width: 8 data_width: 16 pages: From 238e7d3733ccb24780894cb45679fd9212e2b1cb Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 17:28:57 +0300 Subject: [PATCH 046/397] add init regs + fixes --- src/hwparser/gen_h.py | 78 +++++++++++++++++++------------ src/lib/device/pe_sync/pe_sync.c | 2 + src/lib/hw/lmk05318/lmk05318.c | 35 +++++++++++++- src/lib/hw/lmk05318/lmk05318.yaml | 2 +- 4 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/hwparser/gen_h.py b/src/hwparser/gen_h.py index 665caf09..b1b7a111 100755 --- a/src/hwparser/gen_h.py +++ b/src/hwparser/gen_h.py @@ -17,7 +17,7 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: self.o_name = str(os.path.splitext(os.path.basename(filename))[0]) self.l_name = self.o_name.lower() self.h_name = self.o_name.upper() - + self.parser = parser self.addr_width = parser.addr_width self.data_width = parser.data_width @@ -26,7 +26,7 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: self.page_prefix = parser.page_prefix self.reg_prefix = "%s_" % parser.reg_prefix.upper() if len(parser.reg_prefix) > 0 else '' - self.field_prefix_ar = [ a.lower() for a in parser.field_prefix_ar ] + self.field_prefix_ar = [a.lower() for a in parser.field_prefix_ar] # Flat all pages self.regs = {} @@ -36,8 +36,8 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: name = "%s_%s" % (pname, r.name) if self.page_prefix else r.name if name in self.regs.keys(): - raise(Exception("Rigester `%s` is already in flat map! Rename it" % name)) - + raise (Exception("Rigester `%s` is already in flat map! Rename it" % name)) + # TODO: parse ucnt if r.ucnt == 1: self.regs[name] = r.addr @@ -48,14 +48,12 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: for k in range(r.ucnt): self.regs[name + "_BY%d" % (r.ucnt - k - 1)] = r.addr_l + k - def regName(self, reg: reg_parser.ParserRegs) -> str: if self.page_prefix: return "%s_%s" % (reg.page.name.upper(), reg.name) return reg.name - def fieldName(self, field: reg_parser.ParserFields) -> str: pfx = [] for i in self.field_prefix_ar: @@ -66,7 +64,7 @@ def fieldName(self, field: reg_parser.ParserFields) -> str: elif i == "regaddr": pfx.append("%02x" % field.reg.addr_l) else: - raise(Exception("Unknown prefix type '%s'" % i)) + raise (Exception("Unknown prefix type '%s'" % i)) if len(pfx) > 0: pfx.append(field.name) @@ -74,16 +72,22 @@ def fieldName(self, field: reg_parser.ParserFields) -> str: return field.name - def normalize(self, name: str) -> str: return (name.replace('-', '_') - .replace('.', '_') - .replace(',', '_') - .replace(' ', '_') - .replace('(', '') - .replace('|', 'OR') - .replace(')', '') - .replace('/', 'DIV')) + .replace('<=', 'LE') + .replace('>=', 'GE') + .replace('>', 'GT') + .replace('<', 'LT') + .replace('=', 'EQ') + .replace('+', 'PL') + .replace("'", 'MARK') + .replace('.', '_') + .replace(',', '_') + .replace(' ', '_') + .replace('(', '') + .replace('|', 'OR') + .replace(')', '') + .replace('/', 'DIV')) def ser_ch_fenum(self, reg: reg_parser.ParserRegs, name: str) -> str: vt = False @@ -96,7 +100,7 @@ def ser_ch_fenum(self, reg: reg_parser.ParserRegs, name: str) -> str: str += "};" if vt and len(reg.fields) == 1: return "" - + return str def generate_setter_expression(self, f, custom_name) -> str: @@ -165,13 +169,13 @@ def ser_ch_enum(self, name: str, en_dict: dict, prefix: str = "") -> str: str = "enum %s_t {\n" % name for i, v in en_dict.items(): str += "%s%s%s = 0x%x,\n" % (GenH.TAB, prefix, i.replace('-', '_') - .replace('.', '_') - .replace(',', '_') - .replace(' ', '_') - .replace('(', '') - .replace('|', 'OR') - .replace(')', '') - .replace('/', 'DIV'), v) + .replace('.', '_') + .replace(',', '_') + .replace(' ', '_') + .replace('(', '') + .replace('|', 'OR') + .replace(')', '') + .replace('/', 'DIV'), v) str += "};" return str @@ -181,11 +185,19 @@ def write_ch(self, filename): print(all_regs) # Make register define + if (self.parser.wr_mask is not None) and (self.parser.rd_mask is not None): + raise (Exception("You should specify rd_mask OR wr_mask, but not both!")) + def_macro = "MAKE_%s_REG_WR" % self.h_name def_wr_msk = "0x%x | " % self.parser.wr_mask if self.parser.wr_mask is not None else "" def_wr = "#define %s(a, v) (%s((a) << %d) | ((v) & 0x%x))" % (def_macro, def_wr_msk, self.data_width, (1 << self.data_width) - 1) print(def_wr) + def_macro_rd = "MAKE_%s_REG_RD" % self.h_name + def_rd_msk = "0x%x | " % self.parser.rd_mask if self.parser.rd_mask is not None else "" + def_rd = "#define %s(a) (%s((a) << %d))" % (def_macro_rd, def_rd_msk, self.data_width) + print(def_rd) + # Predefined universal enums for e in self.enums: em = e.replace('-', '_') @@ -213,10 +225,12 @@ def write_ch(self, filename): print(self.ser_cf_fmacro(r)) if r.ucnt == 1: - defc = "#define MAKE_%s_%s(%s)" % (self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) - #defc += " ((%s << %d) |" % (name, self.data_width) + defc = "#define MAKE_%s_%s(%s)" % ( + self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) + # defc += " ((%s << %d) |" % (name, self.data_width) defc += " %s(%s," % (def_macro, name) - defc += reduce(lambda x, y: "%s | %s" % (x, y), [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields ]) + defc += reduce(lambda x, y: "%s | %s" % (x, y), + [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields]) defc += ")" print(defc) else: @@ -228,8 +242,10 @@ def write_ch(self, filename): value_msk = reduce(lambda x, y: x | y, [x.mask for x in r.fields]) value_off = reduce(lambda x, y: min(x, y), [x.bits_l for x in r.fields]) if len(r.fields) > 1: - defc = "#define MAKE_%s_%s_LONG(%s) (" % (self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) - defc += reduce(lambda x, y: "%s | %s" % (x, y), [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields ]) + defc = "#define MAKE_%s_%s_LONG(%s) (" % ( + self.h_name, name, reduce(lambda x, y: "%s, %s" % (x, y), [x.name.lower() for x in r.fields])) + defc += reduce(lambda x, y: "%s | %s" % (x, y), + [" \\\n%s%s" % (self.TAB, self.generate_setter_expression(x, x.name.lower())) for x in r.fields]) defc += ")" print(defc) @@ -247,9 +263,9 @@ def write_ch(self, filename): else: # defc += " ((%s_BY%d << %d) | (((value) << %d) & 0x%x))" % (name, u, self.data_width, -by_off, by_msk) defc += " (((value) << %d) & 0x%x))" % (-by_off, by_msk) - print(defc) + print(defc) - # if 'c-cache' in self.parser.raw_yaml: + # if 'c-cache' in self.parser.raw_yaml: # cc = self.parser.raw_yaml['c-cache'] # if 'regs' in cc: # print("\n\n/* Cached operations */") @@ -284,10 +300,10 @@ def parse_c_cache(self, cregs): fn += "p->%s = (p->%s & ~%s_MSK) | ((%s << %s_OFF) & %s_MSK); }" % (regn, regn, FLDN, fname, FLDN, FLDN) print(fn) - def write_vh(self, filename): pass + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Debug UI options') parser.add_argument('--yaml', dest='yaml', type=str, diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 0ebe9f85..3e10c055 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -310,6 +310,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; + USDR_LOG("SYNC", USDR_LOG_INFO, "LMK03518 outputs synced"); + return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 1c40abfc..28f905e0 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -203,8 +203,8 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) { MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1, 1, 1), //R12 set APLL1 mode - DPLL | Free-run MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, dpllmode ? 1 : 0), //R252 enable/disable DPLL - MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, dpllmode ? 0 : 1), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise - MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 0), //R40 set fixed APPL2 denumerator always + MAKE_LMK05318_SPARE_NVMBASE2_BY2(1, dpllmode ? 0 : 1), //R39 *** set fixed APLL1 denumerator for DPLL en, programmed den otherwise + MAKE_LMK05318_SPARE_NVMBASE2_BY1(1, 1, 0), //R40 *** set fixed APPL2 denumerator always MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 set PLL clock cfg MAKE_LMK05318_OUTSYNCCTL(1, 1, 1), //R70 enable APLL1/APLL2 channel sync MAKE_LMK05318_OUTSYNCEN(1, 1, 1, 1, 1, 1), //R71 enable ch0..ch7 out sync @@ -216,6 +216,37 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH6_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels + + + MAKE_LMK05318_INT_FLAG_POL0(1,1,1,1), //R17 + + MAKE_LMK05318_INT_FLAG_POL1(1,1,1,1,1,1,1,1), //R18 + + MAKE_LMK05318_GPIO_OUT(1,1), //R36 + + MAKE_LMK05318_REF_CLKCTL1(0,0,1,0), //R45 + + MAKE_LMK05318_REF_CLKCTL2(SECREF_TYPE_AC_DIFF_EXT, PRIREF_TYPE_AC_DIFF_EXT), //R46 + + MAKE_LMK05318_STAT0_SEL(0x50), //R48 + + MAKE_LMK05318_STAT1_SEL(0x4a), //R49 + + MAKE_LMK05318_PREDRIVER(0xF, 0x08), //R68 + + MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 XO input wait timer 3.3ms [default 52.4ms]+ + + + + MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0, 0x03), //R115 0x3 = APLL1 mash_order3 [default 0 (int mode)]+ + MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm [default 9650]+ + MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm [default 2400] + + MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm [default 2400]+ + + + + MAKE_LMK05318_PLL2_CTRL1(0,0x01), //R101 PLL2 charge pump drain 0x1=3.2mA [default 4.8mA] + + MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 PLL2 bleed resisror 0x1F=766.96 Ohm [default open]+ + MAKE_LMK05318_PLL2_CALCTRL0(0x01, 0x01), //R105 0x1 = VCO calibration time per step (up to 7 steps) 0x1=3ms [default 0.3ms]+ + MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 [default 0 (int mode)]+ + MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm [default 1867]+ + MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF [defailt C3=0(open), C4=0(open)]+ + + }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index 6cc96b24..8ac7152a 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -8,7 +8,7 @@ revision: "0.0.1" processors: [ c ] bus: type: I2C - wr_mask: 0x800000 + rd_mask: 0x800000 usdr_path: /debug/hw/lmk05318/0/reg addr_width: 16 data_width: 8 From 21b30990add22d131ffa000aeeeaa5098d305847 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 17:52:36 +0300 Subject: [PATCH 047/397] add all regs from dump --- src/lib/hw/lmk05318/lmk05318.c | 356 ++++++++++++++++++++++++++++++--- 1 file changed, 324 insertions(+), 32 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 28f905e0..5984023a 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -116,7 +116,7 @@ static int lmk05318_add_reg_to_map(lmk05318_state_t* d, const uint32_t* regs, un { USDR_LOG("5318", USDR_LOG_WARNING, "LMK05318 Rewriting REGADDR 0x%04x : 0x%02x -> 0x%02x", regaddr, (uint8_t)(*ptr), (uint8_t)regs[j]); } - *ptr = regs[j]; + else *ptr = regs[j]; } return 0; } @@ -203,8 +203,8 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) { MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1, 1, 1), //R12 set APLL1 mode - DPLL | Free-run MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, dpllmode ? 1 : 0), //R252 enable/disable DPLL - MAKE_LMK05318_SPARE_NVMBASE2_BY2(1, dpllmode ? 0 : 1), //R39 *** set fixed APLL1 denumerator for DPLL en, programmed den otherwise - MAKE_LMK05318_SPARE_NVMBASE2_BY1(1, 1, 0), //R40 *** set fixed APPL2 denumerator always + MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, dpllmode ? 0 : 1), //R39 *** set fixed APLL1 denumerator for DPLL en, programmed den otherwise + MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 0), //R40 *** set fixed APPL2 denumerator always MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 set PLL clock cfg MAKE_LMK05318_OUTSYNCCTL(1, 1, 1), //R70 enable APLL1/APLL2 channel sync MAKE_LMK05318_OUTSYNCEN(1, 1, 1, 1, 1, 1), //R71 enable ch0..ch7 out sync @@ -217,35 +217,327 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels - - MAKE_LMK05318_INT_FLAG_POL0(1,1,1,1), //R17 + - MAKE_LMK05318_INT_FLAG_POL1(1,1,1,1,1,1,1,1), //R18 + - MAKE_LMK05318_GPIO_OUT(1,1), //R36 + - MAKE_LMK05318_REF_CLKCTL1(0,0,1,0), //R45 + - MAKE_LMK05318_REF_CLKCTL2(SECREF_TYPE_AC_DIFF_EXT, PRIREF_TYPE_AC_DIFF_EXT), //R46 + - MAKE_LMK05318_STAT0_SEL(0x50), //R48 + - MAKE_LMK05318_STAT1_SEL(0x4a), //R49 + - MAKE_LMK05318_PREDRIVER(0xF, 0x08), //R68 + - MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 XO input wait timer 3.3ms [default 52.4ms]+ - - - - MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0, 0x03), //R115 0x3 = APLL1 mash_order3 [default 0 (int mode)]+ - MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm [default 9650]+ - MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm [default 2400] + - MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm [default 2400]+ - - - - MAKE_LMK05318_PLL2_CTRL1(0,0x01), //R101 PLL2 charge pump drain 0x1=3.2mA [default 4.8mA] + - MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 PLL2 bleed resisror 0x1F=766.96 Ohm [default open]+ - MAKE_LMK05318_PLL2_CALCTRL0(0x01, 0x01), //R105 0x1 = VCO calibration time per step (up to 7 steps) 0x1=3ms [default 0.3ms]+ - MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 [default 0 (int mode)]+ - MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm [default 1867]+ - MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF [defailt C3=0(open), C4=0(open)]+ - + 0x000C1B, + 0x000D08, + 0x000E00, + 0x000F00, + 0x001000, + 0x00111D, + 0x0012FF, + 0x001308, + 0x001420, + 0x001501, + 0x001600, + 0x001755, + 0x001855, + 0x001900, + 0x001A00, + 0x001B00, + 0x001C01, + 0x001D13, + 0x001E40, + 0x002044, + 0x002300, + 0x002403, + 0x002500, + 0x002600, + 0x002703, + 0x002803, + 0x002900, + 0x002A11, + 0x002BC2, + 0x002C00, + 0x002D03, + 0x002E11, + 0x002F07, + 0x003050, + 0x00314A, + 0x003200, + 0x003310, + 0x003410, + 0x003513, + 0x003610, + 0x003710, + 0x003809, + 0x003900, + 0x003A0F, + 0x003B00, + 0x003C0F, + 0x003D3E, + 0x003EF9, + 0x003F3E, + 0x004095, + 0x004102, + 0x0042F8, + 0x0043FF, + 0x004408, + 0x004500, + 0x004600, + 0x004700, + 0x004833, + 0x004900, + 0x004A00, + 0x004B00, + 0x004C00, + 0x004D0F, + 0x004E00, + 0x004F11, + 0x005080, + 0x00510A, + 0x005200, + 0x00530E, + 0x0054A6, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D0E, + 0x005EA6, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + 0x006429, + 0x006501, + 0x006622, + 0x00670F, + 0x00681F, + 0x006905, + 0x006A00, + 0x006B64, + 0x006C00, + 0x006D32, + 0x006E00, + 0x006F00, + 0x007000, + 0x007127, + 0x007210, + 0x007303, + 0x007400, + 0x007500, + 0x007600, + 0x007700, + 0x007800, + 0x007900, + 0x007A00, + 0x007B28, + 0x007C00, + 0x007D11, + 0x007E79, + 0x007F7A, + 0x008000, + 0x008101, + 0x008200, + 0x008301, + 0x008401, + 0x008577, + 0x008600, + 0x00872B, + 0x008800, + 0x008928, + 0x008AE5, + 0x008B03, + 0x008C02, + 0x008D00, + 0x008E01, + 0x008F01, + 0x009077, + 0x009101, + 0x009289, + 0x009320, + 0x00950D, + 0x009600, + 0x009701, + 0x00980D, + 0x009929, + 0x009A24, + 0x009B32, + 0x009C01, + 0x009E00, + 0x009F00, + 0x00A0FC, + 0x00A132, + 0x00A200, + 0x00A500, + 0x00A701, + 0x00B200, + 0x00B400, + 0x00B500, + 0x00B600, + 0x00B700, + 0x00B800, + 0x00B905, + 0x00BA08, + 0x00BB00, + 0x00BC00, + 0x00BD00, + 0x00BE2C, + 0x00BF00, + 0x00C050, + 0x00C100, + 0x00C200, + 0x00C300, + 0x00C400, + 0x00C51D, + 0x00C600, + 0x00C700, + 0x00C81D, + 0x00C900, + 0x00CA00, + 0x00CB00, + 0x00CC15, + 0x00CD00, + 0x00CE00, + 0x00CF15, + 0x00D000, + 0x00D114, + 0x00D200, + 0x00D316, + 0x00D400, + 0x00D514, + 0x00D600, + 0x00D716, + 0x00D80F, + 0x00D900, + 0x00DA00, + 0x00DB19, + 0x00DC6E, + 0x00DD00, + 0x00DE03, + 0x00DF0D, + 0x00E047, + 0x00E100, + 0x00E200, + 0x00E319, + 0x00E46E, + 0x00E500, + 0x00E603, + 0x00E70D, + 0x00E847, + 0x00E90A, + 0x00EA0A, + 0x00EB00, + 0x00ECC3, + 0x00ED50, + 0x00EE00, + 0x00EF00, + 0x00F0C3, + 0x00F150, + 0x00F200, + 0x00F300, + 0x00F400, + 0x00F912, + 0x00FA00, + 0x00FB13, + 0x00FC2C, + 0x00FD00, + 0x00FE00, + 0x00FF00, + 0x010000, + 0x010101, + 0x010200, + 0x010301, + 0x010402, + 0x010580, + 0x010600, + 0x010700, + 0x010800, + 0x010900, + 0x010AC8, + 0x010BA0, + 0x010C0C, + 0x010D0A, + 0x010E02, + 0x010F14, + 0x011000, + 0x011100, + 0x011200, + 0x01130E, + 0x01140C, + 0x01150E, + 0x011609, + 0x011708, + 0x011809, + 0x011907, + 0x011A0D, + 0x011B07, + 0x011C1E, + 0x011D1E, + 0x011E02, + 0x011F30, + 0x012000, + 0x0121EE, + 0x012202, + 0x0123CA, + 0x012409, + 0x012501, + 0x012600, + 0x01272C, + 0x012808, + 0x01290C, + 0x012A08, + 0x012B01, + 0x012C00, + 0x012D1C, + 0x012E20, + 0x012F01, + 0x013001, + 0x013100, + 0x013200, + 0x013300, + 0x013410, + 0x0135AA, + 0x0136AA, + 0x0137AA, + 0x0138AA, + 0x0139AA, + 0x013AFF, + 0x013BFF, + 0x013CFF, + 0x013DFF, + 0x013EFF, + 0x013F03, + 0x014000, + 0x01410A, + 0x014200, + 0x014324, + 0x01449F, + 0x014500, + 0x014600, + 0x014798, + 0x014896, + 0x014980, + 0x014A00, + 0x014B64, + 0x014C00, + 0x014D00, + 0x014E3D, + 0x014F09, + 0x015000, + 0x015100, + 0x015200, + 0x015300, + 0x015400, + 0x015500, + 0x015600, + 0x015700, + 0x015800, + 0x015900, + 0x015A02, + 0x015B00, + 0x015C00, + 0x015D00, + 0x015E00, + 0x015F00, + 0x016000, + 0x016528, + 0x016F00, + 0x019B0C, }; From f3d67748064239e0a8d1ba62352399df3f27157f Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 18:56:10 +0300 Subject: [PATCH 048/397] comment out soft-reset --- src/lib/hw/lmk05318/lmk05318.c | 327 +-------------------------------- 1 file changed, 2 insertions(+), 325 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 5984023a..4fa9b0f3 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -116,7 +116,7 @@ static int lmk05318_add_reg_to_map(lmk05318_state_t* d, const uint32_t* regs, un { USDR_LOG("5318", USDR_LOG_WARNING, "LMK05318 Rewriting REGADDR 0x%04x : 0x%02x -> 0x%02x", regaddr, (uint8_t)(*ptr), (uint8_t)regs[j]); } - else *ptr = regs[j]; + *ptr = regs[j]; } return 0; } @@ -216,329 +216,6 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH6_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels - - 0x000C1B, - 0x000D08, - 0x000E00, - 0x000F00, - 0x001000, - 0x00111D, - 0x0012FF, - 0x001308, - 0x001420, - 0x001501, - 0x001600, - 0x001755, - 0x001855, - 0x001900, - 0x001A00, - 0x001B00, - 0x001C01, - 0x001D13, - 0x001E40, - 0x002044, - 0x002300, - 0x002403, - 0x002500, - 0x002600, - 0x002703, - 0x002803, - 0x002900, - 0x002A11, - 0x002BC2, - 0x002C00, - 0x002D03, - 0x002E11, - 0x002F07, - 0x003050, - 0x00314A, - 0x003200, - 0x003310, - 0x003410, - 0x003513, - 0x003610, - 0x003710, - 0x003809, - 0x003900, - 0x003A0F, - 0x003B00, - 0x003C0F, - 0x003D3E, - 0x003EF9, - 0x003F3E, - 0x004095, - 0x004102, - 0x0042F8, - 0x0043FF, - 0x004408, - 0x004500, - 0x004600, - 0x004700, - 0x004833, - 0x004900, - 0x004A00, - 0x004B00, - 0x004C00, - 0x004D0F, - 0x004E00, - 0x004F11, - 0x005080, - 0x00510A, - 0x005200, - 0x00530E, - 0x0054A6, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D0E, - 0x005EA6, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - 0x006429, - 0x006501, - 0x006622, - 0x00670F, - 0x00681F, - 0x006905, - 0x006A00, - 0x006B64, - 0x006C00, - 0x006D32, - 0x006E00, - 0x006F00, - 0x007000, - 0x007127, - 0x007210, - 0x007303, - 0x007400, - 0x007500, - 0x007600, - 0x007700, - 0x007800, - 0x007900, - 0x007A00, - 0x007B28, - 0x007C00, - 0x007D11, - 0x007E79, - 0x007F7A, - 0x008000, - 0x008101, - 0x008200, - 0x008301, - 0x008401, - 0x008577, - 0x008600, - 0x00872B, - 0x008800, - 0x008928, - 0x008AE5, - 0x008B03, - 0x008C02, - 0x008D00, - 0x008E01, - 0x008F01, - 0x009077, - 0x009101, - 0x009289, - 0x009320, - 0x00950D, - 0x009600, - 0x009701, - 0x00980D, - 0x009929, - 0x009A24, - 0x009B32, - 0x009C01, - 0x009E00, - 0x009F00, - 0x00A0FC, - 0x00A132, - 0x00A200, - 0x00A500, - 0x00A701, - 0x00B200, - 0x00B400, - 0x00B500, - 0x00B600, - 0x00B700, - 0x00B800, - 0x00B905, - 0x00BA08, - 0x00BB00, - 0x00BC00, - 0x00BD00, - 0x00BE2C, - 0x00BF00, - 0x00C050, - 0x00C100, - 0x00C200, - 0x00C300, - 0x00C400, - 0x00C51D, - 0x00C600, - 0x00C700, - 0x00C81D, - 0x00C900, - 0x00CA00, - 0x00CB00, - 0x00CC15, - 0x00CD00, - 0x00CE00, - 0x00CF15, - 0x00D000, - 0x00D114, - 0x00D200, - 0x00D316, - 0x00D400, - 0x00D514, - 0x00D600, - 0x00D716, - 0x00D80F, - 0x00D900, - 0x00DA00, - 0x00DB19, - 0x00DC6E, - 0x00DD00, - 0x00DE03, - 0x00DF0D, - 0x00E047, - 0x00E100, - 0x00E200, - 0x00E319, - 0x00E46E, - 0x00E500, - 0x00E603, - 0x00E70D, - 0x00E847, - 0x00E90A, - 0x00EA0A, - 0x00EB00, - 0x00ECC3, - 0x00ED50, - 0x00EE00, - 0x00EF00, - 0x00F0C3, - 0x00F150, - 0x00F200, - 0x00F300, - 0x00F400, - 0x00F912, - 0x00FA00, - 0x00FB13, - 0x00FC2C, - 0x00FD00, - 0x00FE00, - 0x00FF00, - 0x010000, - 0x010101, - 0x010200, - 0x010301, - 0x010402, - 0x010580, - 0x010600, - 0x010700, - 0x010800, - 0x010900, - 0x010AC8, - 0x010BA0, - 0x010C0C, - 0x010D0A, - 0x010E02, - 0x010F14, - 0x011000, - 0x011100, - 0x011200, - 0x01130E, - 0x01140C, - 0x01150E, - 0x011609, - 0x011708, - 0x011809, - 0x011907, - 0x011A0D, - 0x011B07, - 0x011C1E, - 0x011D1E, - 0x011E02, - 0x011F30, - 0x012000, - 0x0121EE, - 0x012202, - 0x0123CA, - 0x012409, - 0x012501, - 0x012600, - 0x01272C, - 0x012808, - 0x01290C, - 0x012A08, - 0x012B01, - 0x012C00, - 0x012D1C, - 0x012E20, - 0x012F01, - 0x013001, - 0x013100, - 0x013200, - 0x013300, - 0x013410, - 0x0135AA, - 0x0136AA, - 0x0137AA, - 0x0138AA, - 0x0139AA, - 0x013AFF, - 0x013BFF, - 0x013CFF, - 0x013DFF, - 0x013EFF, - 0x013F03, - 0x014000, - 0x01410A, - 0x014200, - 0x014324, - 0x01449F, - 0x014500, - 0x014600, - 0x014798, - 0x014896, - 0x014980, - 0x014A00, - 0x014B64, - 0x014C00, - 0x014D00, - 0x014E3D, - 0x014F09, - 0x015000, - 0x015100, - 0x015200, - 0x015300, - 0x015400, - 0x015500, - 0x015600, - 0x015700, - 0x015800, - 0x015900, - 0x015A02, - 0x015B00, - 0x015C00, - 0x015D00, - 0x015E00, - 0x015F00, - 0x016000, - 0x016528, - 0x016F00, - 0x019B0C, - }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -841,7 +518,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, } #endif - res = dry_run ? 0 : lmk05318_softreset(out); + //res = dry_run ? 0 : lmk05318_softreset(out); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_softreset()", res); From 8624139ed64450d79fd7cd420c26e8d69cbf5827 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 19:03:12 +0300 Subject: [PATCH 049/397] add R19 R20 --- src/lib/hw/lmk05318/lmk05318.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 4fa9b0f3..649bfce2 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -216,6 +216,10 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH6_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels + + MAKE_LMK05318_INT_FLAG0(0,1,0,0), //R19 + MAKE_LMK05318_INT_FLAG1(0,0,1,0,0,0,0,0), //R20 + }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); From 3fa29fb5e4886429d4c8ee54dca1ecd242f1f3f1 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 23:04:04 +0300 Subject: [PATCH 050/397] APLL2 - fix try, rom again --- src/lib/hw/lmk05318/lmk05318.c | 21 +- src/lib/hw/lmk05318/lmk05318_rom.h | 337 +++++++++++++++++++++++++++++ src/utests/lmk05318_solver_test.c | 4 +- 3 files changed, 350 insertions(+), 12 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 649bfce2..2541a4f9 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -477,15 +477,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } -#if 0 +#if 1 res = lmk05318_reg_wr_n(out, lmk05318_rom_test, SIZEOF_ARRAY(lmk05318_rom_test)); if (res) return res; - - return 0; #endif -#if 1 +#if 0 res = lmk05318_init(out, dpll_mode); if(res) { @@ -661,10 +659,11 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned } unsigned n = fvco2 / fref; - unsigned num = (fvco2 - n * (uint64_t)fref) * ((1ull << 24) - 1) / fref; + unsigned num = (fvco2 - n * (uint64_t)fref) * (1ull << 24) / fref; int res; - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 FVCO=%" PRIu64 " N=%d NUM=%d PD1=%d PD2=%d\n", fvco2, n, num, pd1, pd2); + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 RS=%u RP=%u FPD2=%u FVCO2=%" PRIu64 " N=%d NUM=%d PD1=%d PD2=%d\n", + d->fref_pll2_div_rs, d->fref_pll2_div_rp, fref, fvco2, n, num, pd1, pd2); // one of PDs may be unused (==0) -> we should fix it before registers set if(pd1 < APLL2_PDIV_MIN || pd1 > APLL2_PDIV_MAX) @@ -749,7 +748,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) //in DPLL mode we use FIXED 40-bit APLL1 denominator and programmed 40-bit numerator if(dpll_mode) { - uint64_t num = (fvco - n * (uint64_t)fref) * ((1ull << 40) - 1) / fref; + uint64_t num = (fvco - n * (uint64_t)fref) * (1ull << 40) / fref; USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 " DEN=FIXED\n", fvco, n, num); @@ -939,7 +938,7 @@ static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, return freq_invalid; } -//#define LMK05318_SOLVER_DEBUG +#define LMK05318_SOLVER_DEBUG VWLT_ATTRIBUTE(optimize("-Ofast")) static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned cnt_to_solve, uint64_t f_in, @@ -1826,6 +1825,7 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) bool locked = false; uint8_t reg; unsigned los_msk; + bool pll2_vm_inside; while(timeout == 0 || elapsed < timeout) { @@ -1835,7 +1835,7 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 read(PLL2_CALSTAT1) error:%d", res); return res; } - const bool pll2_vm_inside = reg & PLL2_VM_INSIDE_MSK; + pll2_vm_inside = reg & PLL2_VM_INSIDE_MSK; res = lmk05318_check_lock(d, &los_msk, true/*silent*/); if(res) @@ -1855,7 +1855,8 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) if(!locked) { - USDR_LOG("5318", USDR_LOG_ERROR, "APLL2 is not locked!"); + USDR_LOG("5318", USDR_LOG_ERROR, "APLL2 is not locked! [PLL2_CALSTAT1:%u PLL2_VM_INSIDE:0x%02x LOS_MASK:0x%02x LMK05318_LOL_PLL2:%u]", + reg, pll2_vm_inside ? 1 : 0, los_msk,(los_msk & LMK05318_LOL_PLL2) ? 1 : 0); return -ETIMEDOUT; } diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index caa88b73..096c08e2 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -3,6 +3,342 @@ static const uint32_t lmk05318_rom_test[] = { + //0x000010, + //0x00010B, + //0x000235, + //0x000332, + //0x000404, + //0x00050E, + //0x000617, + //0x00078E, + //0x000802, + //0x000AC8, + //0x000B00, + 0x000C1B, + 0x000D08, + 0x000E00, + 0x000F00, + 0x001000, + 0x00111D, + 0x0012FF, + 0x001308, + 0x001420, + 0x001501, + 0x001600, + 0x001755, + 0x001855, + 0x001900, + 0x001A00, + 0x001B00, + 0x001C01, + 0x001D13, + 0x001E40, + 0x002044, + 0x002300, + 0x002403, + 0x002500, + 0x002600, + 0x002703, + 0x002802, + 0x002900, + 0x002A11, + 0x002BC2, + 0x002C00, + 0x002D03, + 0x002E11, + 0x002F07, + 0x003050, + 0x00314A, + 0x003280, + 0x003310, + 0x003410, + 0x003513, + 0x003610, + 0x003710, + 0x003809, + 0x003900, + 0x003A0F, + 0x003B80, + 0x003CE1, + 0x003DBE, + 0x003EE1, + 0x003F3E, + 0x004095, + 0x004102, + 0x0042F8, + 0x0043FF, + 0x004408, + 0x004500, + 0x004607, + 0x00473F, + 0x004833, + 0x004900, + 0x004A00, + 0x004B00, + 0x004C00, + 0x004D0F, + 0x004E00, + 0x004F11, + 0x005080, + 0x00510A, + 0x005200, + 0x00530E, + 0x0054A6, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D0E, + 0x005EA6, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + 0x006428, + 0x006501, + 0x006611, + 0x00670F, + 0x00681F, + 0x006905, + 0x006A00, + 0x006B64, + 0x006C00, + 0x006D32, + 0x006E00, + 0x006F00, + 0x007000, + 0x007127, + 0x007210, + 0x007303, + 0x007400, + 0x007500, + 0x007600, + 0x007700, + 0x007800, + 0x007900, + 0x007A00, + 0x007B28, + 0x007C00, + 0x007D11, + 0x007E79, + 0x007F7A, + 0x008000, + 0x008101, + 0x008200, + 0x008301, + 0x008401, + 0x008577, + 0x008600, + 0x00872A, + 0x00884E, + 0x0089A4, + 0x008AAC, + 0x008B03, + 0x008C02, + 0x008D00, + 0x008E01, + 0x008F01, + 0x009077, + 0x009101, + 0x009289, + 0x009320, + 0x00950D, + 0x009600, + 0x009701, + 0x00980D, + 0x009929, + 0x009A24, + 0x009B32, + 0x009C01, + //0x009D00, + 0x009E00, + 0x009F00, + 0x00A0FC, + 0x00A132, + 0x00A200, + //0x00A400, + 0x00A500, + 0x00A701, + 0x00B200, + 0x00B400, + 0x00B500, + 0x00B600, + 0x00B700, + 0x00B800, + 0x00B905, + 0x00BA08, + 0x00BB00, + 0x00BC00, + 0x00BD00, + 0x00BE2C, + 0x00BF00, + 0x00C050, + 0x00C100, + 0x00C200, + 0x00C300, + 0x00C400, + 0x00C51D, + 0x00C600, + 0x00C700, + 0x00C81D, + 0x00C900, + 0x00CA00, + 0x00CB00, + 0x00CC15, + 0x00CD00, + 0x00CE00, + 0x00CF15, + 0x00D000, + 0x00D114, + 0x00D200, + 0x00D316, + 0x00D400, + 0x00D514, + 0x00D600, + 0x00D716, + 0x00D80F, + 0x00D900, + 0x00DA00, + 0x00DB19, + 0x00DC6E, + 0x00DD00, + 0x00DE03, + 0x00DF0D, + 0x00E047, + 0x00E100, + 0x00E200, + 0x00E319, + 0x00E46E, + 0x00E500, + 0x00E603, + 0x00E70D, + 0x00E847, + 0x00E90A, + 0x00EA0A, + 0x00EB00, + 0x00ECC3, + 0x00ED50, + 0x00EE00, + 0x00EF00, + 0x00F0C3, + 0x00F150, + 0x00F200, + 0x00F300, + 0x00F400, + 0x00F912, + 0x00FA00, + 0x00FB13, + 0x00FC2C, + 0x00FD00, + 0x00FE00, + 0x00FF00, + 0x010000, + 0x010101, + 0x010200, + 0x010301, + 0x010402, + 0x010580, + 0x010600, + 0x010700, + 0x010800, + 0x010900, + 0x010AC8, + 0x010BA0, + 0x010C0C, + 0x010D0A, + 0x010E02, + 0x010F14, + 0x011000, + 0x011100, + 0x011200, + 0x01130E, + 0x01140C, + 0x01150E, + 0x011609, + 0x011708, + 0x011809, + 0x011907, + 0x011A0D, + 0x011B07, + 0x011C1E, + 0x011D1E, + 0x011E02, + 0x011F30, + 0x012000, + 0x0121EE, + 0x012202, + 0x0123CA, + 0x012409, + 0x012501, + 0x012600, + 0x01272C, + 0x012808, + 0x01290C, + 0x012A08, + 0x012B01, + 0x012C00, + 0x012D1C, + 0x012E20, + 0x012F01, + 0x013001, + 0x013100, + 0x013200, + 0x013300, + 0x013410, + 0x0135AA, + 0x0136AA, + 0x0137AA, + 0x0138AA, + 0x0139AA, + 0x013AFF, + 0x013BFF, + 0x013CFF, + 0x013DFF, + 0x013EFF, + 0x013F03, + 0x014000, + 0x01410A, + 0x014200, + 0x014324, + 0x01449F, + 0x014500, + 0x014600, + 0x014798, + 0x014896, + 0x014980, + 0x014A00, + 0x014B64, + 0x014C00, + 0x014D00, + 0x014E61, + 0x014FA8, + 0x015000, + 0x015100, + 0x015200, + 0x015300, + 0x015400, + 0x015500, + 0x015600, + 0x015700, + 0x015800, + 0x015900, + 0x015A01, + 0x015B00, + 0x015C00, + 0x015D00, + 0x015E00, + 0x015F00, + 0x016000, + 0x016528, + 0x016F00, + 0x019B0C, + +#if 0 //0x000010, //0x00010B, //0x000235, @@ -337,6 +673,7 @@ static const uint32_t lmk05318_rom_test[] = 0x016528, 0x016F00, 0x019B0C, +#endif }; diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index edf3c966..2eda16e5 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -170,8 +170,8 @@ START_TEST(lmk05318_solver_test6) res = res ? res : lmk05318_port_request(cfg, 2, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 3, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 4, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 10000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 5, 13000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 13000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); ck_assert_int_eq( res, 0 ); From 9ba4d330256142288a56e4e5374956abda0e7cd0 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 4 Apr 2025 23:58:23 +0300 Subject: [PATCH 051/397] APLL2 fixed --- src/lib/hw/lmk05318/lmk05318.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 2541a4f9..d537c9d0 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -217,8 +217,8 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels - MAKE_LMK05318_INT_FLAG0(0,1,0,0), //R19 - MAKE_LMK05318_INT_FLAG1(0,0,1,0,0,0,0,0), //R20 + MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 + MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 }; @@ -477,13 +477,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } -#if 1 +#if 0 res = lmk05318_reg_wr_n(out, lmk05318_rom_test, SIZEOF_ARRAY(lmk05318_rom_test)); if (res) return res; #endif -#if 0 +#if 1 res = lmk05318_init(out, dpll_mode); if(res) { @@ -938,7 +938,7 @@ static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, return freq_invalid; } -#define LMK05318_SOLVER_DEBUG +//#define LMK05318_SOLVER_DEBUG VWLT_ATTRIBUTE(optimize("-Ofast")) static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned cnt_to_solve, uint64_t f_in, From b4fbe67b95e1ae850ad0a84c6ef95bb70029a342 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 5 Apr 2025 00:09:59 +0300 Subject: [PATCH 052/397] fix 05318 solver for 1 APLL2 out --- src/lib/hw/lmk05318/lmk05318.c | 2 +- src/utests/lmk05318_solver_test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index d537c9d0..e6eef70a 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1044,7 +1044,7 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c fvco2_range_t* rr_sec = &fvco2_ranges[j]; //ignore equal port variants with different PDs - if(outs[rr_sec->port_idx].port == outs[rr_prim->port_idx].port) + if(outs[rr_sec->port_idx].port == outs[rr_prim->port_idx].port && cnt_to_solve != 1) continue; uint64_t nmin = MAX(intersection.min, rr_sec->fvco2.min); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 2eda16e5..27120d34 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -170,7 +170,7 @@ START_TEST(lmk05318_solver_test6) res = res ? res : lmk05318_port_request(cfg, 2, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 3, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 4, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 13000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 17000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 6, 13000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); ck_assert_int_eq( res, 0 ); From c24b1e66a9f57043927cf243199f0586e9709b10 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 5 Apr 2025 12:00:22 +0300 Subject: [PATCH 053/397] fix lock & LOS flags reset --- src/lib/device/pe_sync/pe_sync.c | 17 ++++++++++++++--- src/lib/hw/lmk05318/lmk05318.c | 16 +++++++++++----- src/lib/hw/lmk05318/lmk05318.h | 1 + 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 3e10c055..b7fbb8e3 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -288,13 +288,24 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; - usleep(100); //wait until lmk digests all this + usleep(10000); //wait until lmk digests all this + + //reset LOS flags after soft-reset (inside lmk05318_create_ex()) + res = lmk05318_reset_los_flags(&d->gen); + if(res) + return res; //wait for lock //APLL1/DPLL res = lmk05318_wait_apll1_lock(&d->gen, use_dpll, 10000); + //APLL2 (if needed) - res = res ? res : (d->gen.vco2_freq ? lmk05318_wait_apll2_lock(&d->gen, 10000) : 0); + if(res == 0 && d->gen.vco2_freq) + { + //reset LOS flags once again because APLL2 LOS is set after APLL1 tuning + res = lmk05318_reset_los_flags(&d->gen); + res = res ? res : lmk05318_wait_apll2_lock(&d->gen, 10000); + } unsigned los_msk; lmk05318_check_lock(&d->gen, &los_msk, false /*silent*/); //just to log state @@ -305,7 +316,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; } - //sync + //sync to make APLL1/APLL2 & out channels in-phase res = lmk05318_sync(&d->gen); if(res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index e6eef70a..ec7a23a7 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -196,6 +196,16 @@ int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask) return lmk05318_reg_wr_n(out, ®, 1); } +int lmk05318_reset_los_flags(lmk05318_state_t* d) +{ + uint32_t regs[] = + { + MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 + MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 + }; + + return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); +} static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) { @@ -216,10 +226,6 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH6_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels - - MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 - MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 - }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -520,7 +526,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, } #endif - //res = dry_run ? 0 : lmk05318_softreset(out); + res = dry_run ? 0 : lmk05318_softreset(out); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_softreset()", res); diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 97ef8065..1dadb325 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -156,6 +156,7 @@ enum lock_msk { int lmk05318_sync(lmk05318_state_t* out); int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask); +int lmk05318_reset_los_flags(lmk05318_state_t* d); int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeout); int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout); From 5f2dc33af4243e62d1c57d6a1bc5e6d68b885a74 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 5 Apr 2025 17:09:38 +0300 Subject: [PATCH 054/397] extra comments --- src/lib/hw/lmk05318/lmk05318.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index ec7a23a7..1b46dc6b 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -226,6 +226,8 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH6_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels + MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | + MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -526,7 +528,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, } #endif - res = dry_run ? 0 : lmk05318_softreset(out); + //res = dry_run ? 0 : lmk05318_softreset(out); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_softreset()", res); @@ -1780,6 +1782,7 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeo bool locked = false; uint8_t reg; unsigned los_msk; + bool pll1_vm_inside; while(timeout == 0 || elapsed < timeout) { @@ -1789,7 +1792,7 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeo USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 read(PLL1_CALSTAT1) error:%d", res); return res; } - const bool pll1_vm_inside = reg & PLL1_VM_INSIDE_MSK; + pll1_vm_inside = reg & PLL1_VM_INSIDE_MSK; res = lmk05318_check_lock(d, &los_msk, true/*silent*/); if(res) @@ -1816,7 +1819,9 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeo if(!locked) { - USDR_LOG("5318", USDR_LOG_ERROR, "APLL1 is not locked!"); + USDR_LOG("5318", USDR_LOG_ERROR, "APLL1 is not locked! [PLL1_CALSTAT1:%u PLL1_VM_INSIDE:0x%02x LOS_MASK:0x%02x LMK05318_BAW_LOCK:%u]", + reg, pll1_vm_inside ? 1 : 0, los_msk,(los_msk & LMK05318_BAW_LOCK) ? 1 : 0); + return -ETIMEDOUT; } From caaf9cef6d8e1f2d927d17f465e1dc0d6d64d6d9 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 5 Apr 2025 18:04:43 +0300 Subject: [PATCH 055/397] fix BAW lock --- src/lib/hw/lmk05318/lmk05318.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 1b46dc6b..6d12ca92 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -226,8 +226,30 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) CH6_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH5_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH4_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW), //R24 set ch4..7 mute levels + MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags + + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(0, 0), //R80 + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY0(0x0a), //R81 | BAW LOCKDET status + 0x005200, //R82 BAW LOCKDET/UNLOCKDET begin + 0x005307, + 0x00549E, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D07, + 0x005E9E, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, //R99 BAW LOCKDET/UNLOCKDET end }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -528,7 +550,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, } #endif - //res = dry_run ? 0 : lmk05318_softreset(out); + res = dry_run ? 0 : lmk05318_softreset(out); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d lmk05318_softreset()", res); From 28f7a6e591d7a792d128ae606f6bf869557abe87 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 5 Apr 2025 18:36:32 +0300 Subject: [PATCH 056/397] add all regs from dump to init() --- src/lib/hw/lmk05318/lmk05318.c | 84 ++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 6d12ca92..2680b887 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -230,6 +230,10 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags + + + + MAKE_LMK05318_PREDRIVER(0, 0x08), //R68 + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(0, 0), //R80 MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY0(0x0a), //R81 | BAW LOCKDET status 0x005200, //R82 BAW LOCKDET/UNLOCKDET begin @@ -250,6 +254,86 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) 0x00611E, 0x006284, 0x006380, //R99 BAW LOCKDET/UNLOCKDET end + + + MAKE_LMK05318_INT_FLAG_POL0(1,1,1,1), //R17 + + MAKE_LMK05318_INT_FLAG_POL1(1,1,1,1,1,1,1,1), //R18 + + MAKE_LMK05318_GPIO_OUT(1,1), //R36 + + MAKE_LMK05318_REF_CLKCTL1(0,0,1,0), //R45 + + MAKE_LMK05318_REF_CLKCTL2(SECREF_TYPE_AC_DIFF_EXT, PRIREF_TYPE_AC_DIFF_EXT), //R46 + + MAKE_LMK05318_STAT0_SEL(0x50), //R48 + + MAKE_LMK05318_STAT1_SEL(0x4a), //R49 + + MAKE_LMK05318_PLL2_CTRL1(0, 0x01), //R101 PLL2 charge pump drain 0x1=3.2mA [default 4.8mA] + + MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 PLL2 bleed resisror 0x1F=766.96 Ohm [default open]+ + MAKE_LMK05318_PLL2_CALCTRL0(0x02, 0x01), //R105 0x1 = VCO calibration time per step (up to 7 steps) 0x1=3ms [default 0.3ms]+ + MAKE_LMK05318_PLL1_MASHCTRL(0, 0, 0, 0, 0x03), //R115 0x3 = APLL1 mash_order3 [default 0 (int mode)]+ + MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm [default 9650]+ + MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm [default 2400] + + MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 [default 0 (int mode)]+ + MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm [default 1867]+ + MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm [default 2400]+ + MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF [defailt C3=0(open), C4=0(open)]+ + MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 XO input wait timer 3.3ms [default 52.4ms]+ + + 0x00A0FC, //R160 MEMADR ? + + 0x00C050, //R192 + 0x00C100, + 0x00C200, + 0x00C300, + 0x00C400, + 0x00C51D, + 0x00C600, + 0x00C700, + 0x00C81D, + 0x00C900, + 0x00CA00, + 0x00CB00, + 0x00CC15, + 0x00CD00, + 0x00CE00, + 0x00CF15, //R207 + + 0x00D000, //R208 REF0/1 settings begin + 0x00D114, + 0x00D200, + 0x00D316, + 0x00D400, + 0x00D514, + 0x00D600, + 0x00D716, + 0x00D900, + 0x00DA00, + 0x00DB19, + 0x00DC6E, + 0x00DD00, + 0x00DE03, + 0x00DF0D, + 0x00E047, + 0x00E100, + 0x00E200, + 0x00E319, + 0x00E46E, + 0x00E500, + 0x00E603, + 0x00E70D, + 0x00E847, + 0x00E90A, + 0x00EA0A, //R234 REF0/1 settings end + + MAKE_LMK05318_REF0_PH_VALID_CNT_BY0(0x01), //R235 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY1(0x8c), //R236 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY2(0xba), //R237 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY3(0x80), //R238 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(0x00), //R239 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY1(0xc3), //R240 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY2(0x50), //R241 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY3(0x00), //R242 + MAKE_LMK05318_REF0_PH_VALID_THR(0x3f), //R243 + MAKE_LMK05318_REF1_PH_VALID_THR(0x00), //R244 + }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); From f00062569fac64137f7e763cc85afdb7d3fd0fd9 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 5 Apr 2025 21:43:29 +0300 Subject: [PATCH 057/397] Final (I hope) BAW detect fix + rm redundant code --- src/lib/hw/lmk05318/lmk05318.c | 324 +-------------------------------- 1 file changed, 10 insertions(+), 314 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 2680b887..541d6d25 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -230,336 +230,32 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags - - - - MAKE_LMK05318_PREDRIVER(0, 0x08), //R68 + - MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(0, 0), //R80 - MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY0(0x0a), //R81 | BAW LOCKDET status - 0x005200, //R82 BAW LOCKDET/UNLOCKDET begin - 0x005307, - 0x00549E, + 0x004F11, //R79 + 0x005080, + 0x00510A, + 0x005200, + 0x00530E, + 0x0054A6, 0x005500, 0x005600, 0x00571E, 0x005884, - 0x005980, + 0x005980, // | BAW detect, lock&unlock settings 0x005A00, 0x005B14, 0x005C00, - 0x005D07, - 0x005E9E, + 0x005D0E, + 0x005EA6, 0x005F00, 0x006000, 0x00611E, 0x006284, - 0x006380, //R99 BAW LOCKDET/UNLOCKDET end - - - MAKE_LMK05318_INT_FLAG_POL0(1,1,1,1), //R17 + - MAKE_LMK05318_INT_FLAG_POL1(1,1,1,1,1,1,1,1), //R18 + - MAKE_LMK05318_GPIO_OUT(1,1), //R36 + - MAKE_LMK05318_REF_CLKCTL1(0,0,1,0), //R45 + - MAKE_LMK05318_REF_CLKCTL2(SECREF_TYPE_AC_DIFF_EXT, PRIREF_TYPE_AC_DIFF_EXT), //R46 + - MAKE_LMK05318_STAT0_SEL(0x50), //R48 + - MAKE_LMK05318_STAT1_SEL(0x4a), //R49 + - MAKE_LMK05318_PLL2_CTRL1(0, 0x01), //R101 PLL2 charge pump drain 0x1=3.2mA [default 4.8mA] + - MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 PLL2 bleed resisror 0x1F=766.96 Ohm [default open]+ - MAKE_LMK05318_PLL2_CALCTRL0(0x02, 0x01), //R105 0x1 = VCO calibration time per step (up to 7 steps) 0x1=3ms [default 0.3ms]+ - MAKE_LMK05318_PLL1_MASHCTRL(0, 0, 0, 0, 0x03), //R115 0x3 = APLL1 mash_order3 [default 0 (int mode)]+ - MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm [default 9650]+ - MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm [default 2400] + - MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 [default 0 (int mode)]+ - MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm [default 1867]+ - MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF [defailt C3=0(open), C4=0(open)]+ - MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 XO input wait timer 3.3ms [default 52.4ms]+ - - 0x00A0FC, //R160 MEMADR ? - - 0x00C050, //R192 - 0x00C100, - 0x00C200, - 0x00C300, - 0x00C400, - 0x00C51D, - 0x00C600, - 0x00C700, - 0x00C81D, - 0x00C900, - 0x00CA00, - 0x00CB00, - 0x00CC15, - 0x00CD00, - 0x00CE00, - 0x00CF15, //R207 - - 0x00D000, //R208 REF0/1 settings begin - 0x00D114, - 0x00D200, - 0x00D316, - 0x00D400, - 0x00D514, - 0x00D600, - 0x00D716, - 0x00D900, - 0x00DA00, - 0x00DB19, - 0x00DC6E, - 0x00DD00, - 0x00DE03, - 0x00DF0D, - 0x00E047, - 0x00E100, - 0x00E200, - 0x00E319, - 0x00E46E, - 0x00E500, - 0x00E603, - 0x00E70D, - 0x00E847, - 0x00E90A, - 0x00EA0A, //R234 REF0/1 settings end - - MAKE_LMK05318_REF0_PH_VALID_CNT_BY0(0x01), //R235 - MAKE_LMK05318_REF0_PH_VALID_CNT_BY1(0x8c), //R236 - MAKE_LMK05318_REF0_PH_VALID_CNT_BY2(0xba), //R237 - MAKE_LMK05318_REF0_PH_VALID_CNT_BY3(0x80), //R238 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(0x00), //R239 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY1(0xc3), //R240 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY2(0x50), //R241 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY3(0x00), //R242 - MAKE_LMK05318_REF0_PH_VALID_THR(0x3f), //R243 - MAKE_LMK05318_REF1_PH_VALID_THR(0x00), //R244 - + 0x006380, //R99 }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } -#if 0 - -#undef LMK05380_DPLL_EN - -static int lmk05318_init(lmk05318_state_t* d) -{ - uint32_t regs[] = - { - MAKE_LMK05318_DEV_CTL(0,0,0,1,1), //R12 + - MAKE_LMK05318_INT_FLAG_POL0(1,1,1,1), //R17 + - MAKE_LMK05318_INT_FLAG_POL1(1,1,1,1,1,1,1,1), //R18 + - MAKE_LMK05318_INT_FLAG0(0,1,0,0), //R19 - MAKE_LMK05318_INT_FLAG1(0,0,1,0,0,0,0,0), //R20 - MAKE_LMK05318_MUTELVL1(1,1,1,1), //R23 - MAKE_LMK05318_MUTELVL2(1,1,1,1), //R24 - MAKE_LMK05318_OUT_MUTE(0,0,0,0,0,0,0,0), //R25 + - MAKE_LMK05318_GPIO_OUT(1,1), //R36 + - MAKE_LMK05318_SPARE_NVMBASE2_BY2(1,0), //R39 + - MAKE_LMK05318_SPARE_NVMBASE2_BY1(1,1,0), //R40 + - MAKE_LMK05318_REF_CLKCTL1(0,0,1,0), //R45 + - MAKE_LMK05318_REF_CLKCTL2(SECREF_TYPE_AC_DIFF_EXT, PRIREF_TYPE_AC_DIFF_EXT), //R46 + - MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 +++++++++++++ - MAKE_LMK05318_STAT0_SEL(0x50), //R48 + - MAKE_LMK05318_STAT1_SEL(0x4a), //R49 + - MAKE_LMK05318_PREDRIVER(0x08), //R68 + - MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1,0), //R80 - MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY0(0x0a), //R81 - 0x005200, //R82 BAW LOCKDET/UNLOCKDET begin - 0x005307, - 0x00549E, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D07, - 0x005E9E, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, //R99 BAW LOCKDET/UNLOCKDET end - MAKE_LMK05318_PLL2_CTRL1(0x01), //R101 PLL2 charge pump drain 0x1=3.2mA [default 4.8mA] + - MAKE_LMK05318_PLL2_CTRL4(0x1F), //R104 PLL2 bleed resisror 0x1F=766.96 Ohm [default open]+ - MAKE_LMK05318_PLL2_CALCTRL0(0x01), //R105 0x1 = VCO calibration time per step (up to 7 steps) 0x1=3ms [default 0.3ms]+ - MAKE_LMK05318_PLL1_MASHCTRL(0, 0x03), //R115 0x3 = APLL1 mash_order3 [default 0 (int mode)]+ - MAKE_LMK05318_PLL1_LF_R2(0x01), //R129 0x1 = APLL1 Loop filter R2=414 Ohm [default 9650]+ - MAKE_LMK05318_PLL1_LF_R3(0x01), //R131 0x1 = APLL1 Loop filter R3=200 Ohm [default 2400] + - MAKE_LMK05318_PLL1_LF_R4(0x01), //R132 0x1 = APLL1 Loop filter R4=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_MASHCTRL(0, 0x03), //R139 0x3 = APLL2 mash_order3 [default 0 (int mode)]+ - MAKE_LMK05318_PLL2_LF_R2(0x02), //R140 APLL2 Loop Filter R2=300 Ohm [default 1867]+ - MAKE_LMK05318_PLL2_LF_R3(0x01), //R142 APLL2 Loop filter R3=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_LF_R4(0x01), //R143 APLL2 Loop filter R4=200 Ohm [default 2400]+ - MAKE_LMK05318_PLL2_LF_C3C4(0x7, 0x7), //R144 APLL2 Loop Filter C3 = 70pF, C4 = 70pF [defailt C3=0(open), C4=0(open)]+ - MAKE_LMK05318_XO_OFFSET_SW_TIMER(0x1), //R145 XO input wait timer 3.3ms [default 52.4ms]+ - 0x00A0FC, //R160 MEMADR ? - -#ifdef LMK05380_DPLL_EN - 0x00B9F5, //R185 DPLL_REF settings ??? - 0x00BA01, //R186 DPLL REF Tuning history timer ??? -#endif - MAKE_LMK05318_REF01_DETAMP(1,1,0,0), //R192 - MAKE_LMK05318_REF0_DETEN(0,1,0,0,0,0), //R193 - MAKE_LMK05318_REF0_MISSCLK_DIV_BY0(0x00), //R195 - MAKE_LMK05318_REF0_MISSCLK_DIV_BY1(0x00), //R196 - MAKE_LMK05318_REF0_MISSCLK_DIV_BY2(0x1d), //R197 - MAKE_LMK05318_REF1_MISSCLK_DIV_BY0(0x00), //R198 - MAKE_LMK05318_REF1_MISSCLK_DIV_BY1(0x00), //R199 - MAKE_LMK05318_REF1_MISSCLK_DIV_BY2(0x1d), //R200 - MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(0x00), //R202 - MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(0x00), //R203 - MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(0x15), //R204 - MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(0x00), //R205 - MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(0x00), //R206 - MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(0x15), //R207 - 0x00D000, //R208 REF0/1 settings begin - 0x00D114, - 0x00D200, - 0x00D316, - 0x00D400, - 0x00D514, - 0x00D600, - 0x00D716, - 0x00D900, - 0x00DA00, - 0x00DB19, - 0x00DC6E, - 0x00DD00, - 0x00DE03, - 0x00DF0D, - 0x00E047, - 0x00E100, - 0x00E200, - 0x00E319, - 0x00E46E, - 0x00E500, - 0x00E603, - 0x00E70D, - 0x00E847, - 0x00E90A, - 0x00EA0A, //R234 REF0/1 settings end - MAKE_LMK05318_REF0_PH_VALID_CNT_BY0(0x01), //R235 - MAKE_LMK05318_REF0_PH_VALID_CNT_BY1(0x8c), //R236 - MAKE_LMK05318_REF0_PH_VALID_CNT_BY2(0xba), //R237 - MAKE_LMK05318_REF0_PH_VALID_CNT_BY3(0x80), //R238 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(0x00), //R239 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY1(0xc3), //R240 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY2(0x50), //R241 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY3(0x00), //R242 - MAKE_LMK05318_REF0_PH_VALID_THR(0x3f), //R243 - MAKE_LMK05318_REF1_PH_VALID_THR(0x00), //R244 - -#ifdef LMK05380_DPLL_EN - MAKE_LMK05318_DPLL_REF01_PRTY(2,1), //R249 DPLL ref priority??? - MAKE_LMK05318_DPLL_REF_SWMODE(0,0,3), //R251 DPLL sw ctrls ??? - MAKE_LMK05318_DPLL_GEN_CTL(0,1,0,1,1), //R252 DPLL ctrls ??? - MAKE_LMK05318_DPLL_REF0_RDIV_BY0(0), //R256 DPLL RDIV ??? - MAKE_LMK05318_DPLL_REF0_RDIV_BY1(1), //R257 DPLL RDIV ??? - MAKE_LMK05318_DPLL_REF1_RDIV_BY0(0), //R258 ??? - MAKE_LMK05318_DPLL_REF1_RDIV_BY1(0), //R259 ??? - MAKE_LMK05318_DPLL_REF_TDC_CTL(1), //R260 DPLL cycle slip ??? - 0x010580, - 0x010601, - 0x01072A, - 0x010805, - 0x0109F2, - 0x010A00, - 0x010BA0, - 0x010C04, - 0x010D00, - 0x010E02, - 0x010F8C, - 0x011000, - 0x011100, - 0x011200, - 0x011316, - 0x011416, - 0x011516, - 0x011600, - 0x011700, - 0x011800, - 0x011900, - 0x011A00, - 0x011B00, - 0x011C1E, - 0x011D1E, - 0x011E00, - 0x011F00, - 0x012000, - 0x012100, - 0x012203, - 0x012322, - 0x012409, - 0x012501, - 0x012600, - 0x01272C, - 0x012809, - 0x012909, - 0x012A09, - 0x012B01, - 0x012C00, - 0x012D1B, - 0x012E1E, - 0x012F01, - 0x01300F, - 0x013104, - 0x013261, - 0x0133F8, - 0x013443, - 0x0135C3, - 0x0136C3, - 0x0137C3, - 0x0138C3, - 0x0139C3, - 0x013AFF, - 0x013BFF, - 0x013CFF, - 0x013DFF, - 0x013EFF, - 0x013F03, - 0x014000, - 0x01410A, - 0x014200, - 0x014300, - 0x014400, - 0x014501, - 0x014606, - 0x014735, - 0x014875, - 0x01490B, - 0x014A00, - 0x014B64, - 0x014C00, //R332 ^^DPLL ??? - 0x015000, - 0x015198, - 0x015296, //R338 DPLL ?? - 0x015400, - 0x015500, - 0x015600, - 0x015700, - 0x015800, - 0x015900, - 0x015A02, - 0x015B00, - 0x015C00, - 0x015D00, - 0x015E00, - 0x015F00, //R352 DPLL ??? -#endif - }; - - int res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; - - return 0; -} -#endif int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk05318_xo_settings_t* xo, bool dpll_mode, From 0b386dbae911b1bf9411eb765d7083351964f08d Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 5 Apr 2025 22:07:58 +0300 Subject: [PATCH 058/397] refactoring --- src/lib/hw/lmk05318/lmk05318.c | 41 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 541d6d25..19f03a47 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -230,26 +230,27 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags - 0x004F11, //R79 - 0x005080, - 0x00510A, - 0x005200, - 0x00530E, - 0x0054A6, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, // | BAW detect, lock&unlock settings - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D0E, - 0x005EA6, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, + MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 + + 0x00510A, //R81 + 0x005200, // | + 0x00530E, // | + 0x0054A6, // | + 0x005500, // | + 0x005600, // | + 0x00571E, // | + 0x005884, // | + 0x005980, // | BAW lock&unlock detection + 0x005A00, // | + 0x005B14, // | + 0x005C00, // | + 0x005D0E, // | + 0x005EA6, // | + 0x005F00, // | + 0x006000, // | + 0x00611E, // | + 0x006284, // | 0x006380, //R99 }; From a10bece92bffe5085456b3382415239ad0216771 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 6 Apr 2025 22:42:07 +0300 Subject: [PATCH 059/397] fix in solver + APLL2 programmed denum --- src/lib/hw/lmk05318/lmk05318.c | 187 +++++++++++++++++++++++------- src/lib/hw/lmk05318/lmk05318.h | 1 + src/lib/hw/lmk05318/lmk05318.yaml | 19 ++- src/utests/lmk05318_solver_test.c | 33 +++--- 4 files changed, 170 insertions(+), 70 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 19f03a47..922862fb 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -214,7 +214,7 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1, 1, 1), //R12 set APLL1 mode - DPLL | Free-run MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, dpllmode ? 1 : 0), //R252 enable/disable DPLL MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, dpllmode ? 0 : 1), //R39 *** set fixed APLL1 denumerator for DPLL en, programmed den otherwise - MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 0), //R40 *** set fixed APPL2 denumerator always + MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 1), //R40 *** set programmed APPL2 denumerator always MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 set PLL clock cfg MAKE_LMK05318_OUTSYNCCTL(1, 1, 1), //R70 enable APLL1/APLL2 channel sync MAKE_LMK05318_OUTSYNCEN(1, 1, 1, 1, 1, 1), //R71 enable ch0..ch7 out sync @@ -447,21 +447,45 @@ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) return 0; } -static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned pd1, unsigned pd2) +VWLT_ATTRIBUTE(optimize("-Ofast")) +static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, unsigned* pn, unsigned* pnum, unsigned* pden) { - unsigned fref = VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; + const unsigned den = VCO_APLL1 >> 8; //fit to 24 bit -> 9 765 625 (0x9502f9) + + double r = (double)(fvco2 * d->fref_pll2_div_rp * d->fref_pll2_div_rs) / VCO_APLL1; + unsigned n = (unsigned)r; + double n_frac = r - n; + unsigned num = (unsigned)(n_frac * den); + + const double fvco2_fact = (double)VCO_APLL1 * (n + (double)num / den) / d->fref_pll2_div_rp / d->fref_pll2_div_rs; + + //USDR_LOG("5318", USDR_LOG_ERROR, "WANTED_VCO2:%" PRIu64 " N:%u NUM:%u DEN:%u VCO2:%.8f", fvco2, n, num, den, fvco2_fact); + + if(pn) + *pn = n; + if(pnum) + *pnum = num; + if(pden) + *pden = den; + + return fvco2_fact; +} + +static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) +{ + double fref = (double)VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; if (fref < APLL2_PD_MIN || fref > APLL2_PD_MAX) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 PFD should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 PFD should be in range [%" PRIu64 ";%" PRIu64 "] but got %.8f!\n", (uint64_t)APLL2_PD_MIN, (uint64_t)APLL2_PD_MAX, fref); return -EINVAL; } - if(fvco2 < VCO_APLL2_MIN || fvco2 > VCO_APLL2_MAX || - ((pd1 < APLL2_PDIV_MIN || pd1 > APLL2_PDIV_MAX) && (pd2 < APLL2_PDIV_MIN || pd2 > APLL2_PDIV_MAX)) + if(d->vco2_freq < VCO_APLL2_MIN || d->vco2_freq > VCO_APLL2_MAX || + ((d->pd1 < APLL2_PDIV_MIN || d->pd1 > APLL2_PDIV_MAX) && (d->pd2 < APLL2_PDIV_MIN || d->pd2 > APLL2_PDIV_MAX)) ) { USDR_LOG("5318", USDR_LOG_WARNING, "LMK05318 APLL2: either FVCO2[%" PRIu64"] or (PD1[%d] && PD2[%d]) is out of range, APLL2 will be disabled", - fvco2, pd1, pd2); + d->vco2_freq, d->pd1, d->pd2); // Disable uint32_t regs[] = { MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), //R100 Deactivate APLL2 @@ -469,30 +493,34 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d, uint64_t fvco2, unsigned return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } - unsigned n = fvco2 / fref; - unsigned num = (fvco2 - n * (uint64_t)fref) * (1ull << 24) / fref; + const unsigned n = d->vco2_n; + const unsigned num = d->vco2_num; + const unsigned den = d->vco2_den; int res; - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 RS=%u RP=%u FPD2=%u FVCO2=%" PRIu64 " N=%d NUM=%d PD1=%d PD2=%d\n", - d->fref_pll2_div_rs, d->fref_pll2_div_rp, fref, fvco2, n, num, pd1, pd2); + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 RS=%u RP=%u FPD2=%.8f FVCO2=%" PRIu64 " N=%d NUM=%d DEN=%d PD1=%d PD2=%d\n", + d->fref_pll2_div_rs, d->fref_pll2_div_rp, fref, d->vco2_freq, n, num, den, d->pd1, d->pd2); // one of PDs may be unused (==0) -> we should fix it before registers set - if(pd1 < APLL2_PDIV_MIN || pd1 > APLL2_PDIV_MAX) + if(d->pd1 < APLL2_PDIV_MIN || d->pd1 > APLL2_PDIV_MAX) { - pd1 = pd2; + d->pd1 = d->pd2; } - else if(pd2 < APLL2_PDIV_MIN || pd2 > APLL2_PDIV_MAX) + else if(d->pd2 < APLL2_PDIV_MIN || d->pd2 > APLL2_PDIV_MAX) { - pd2 = pd1; + d->pd2 = d->pd1; } uint32_t regs[] = { - MAKE_LMK05318_PLL2_CTRL2(pd2 - 1, pd1 - 1), //R102 + MAKE_LMK05318_PLL2_CTRL2(d->pd2 - 1, d->pd1 - 1), //R102 MAKE_LMK05318_PLL2_NDIV_BY0(n), //R135 MAKE_LMK05318_PLL2_NDIV_BY1(n), //R134 MAKE_LMK05318_PLL2_NUM_BY0(num), //R138 MAKE_LMK05318_PLL2_NUM_BY1(num), //R137 MAKE_LMK05318_PLL2_NUM_BY2(num), //R136 + MAKE_LMK05318_PLL2_DEN_BY0(den), //R333 + MAKE_LMK05318_PLL2_DEN_BY1(den), //R334 + MAKE_LMK05318_PLL2_DEN_BY2(den), //R335 MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), //R100 Activate APLL2 }; @@ -716,18 +744,28 @@ static range_t lmk05318_get_freq_range(const lmk05318_out_config_t* cfg) return r; } +//#define LMK05318_SOLVER_DEBUG + +/* enum { freq_too_low = -1, freq_too_high = 1, freq_ok = 0, freq_invalid = 42, }; - +*/ VWLT_ATTRIBUTE(optimize("-Ofast")) -static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, uint64_t ifreq, uint64_t* div) +static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, double ifreq, uint64_t* div) { - *div = ifreq / cfg->wanted.freq; + *div = (uint64_t)((double)ifreq / cfg->wanted.freq + 0.5); + if(*div == 0 || *div > cfg->max_odiv) + return 1; + + double factf = ifreq / (*div); + + return (factf == cfg->wanted.freq) ? 0 : 1; +/* if(*div > cfg->max_odiv) return freq_too_high; @@ -747,13 +785,12 @@ static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, } return freq_invalid; +*/ } -//#define LMK05318_SOLVER_DEBUG - VWLT_ATTRIBUTE(optimize("-Ofast")) static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned cnt_to_solve, uint64_t f_in, - uint64_t* res_fvco2, int* res_pd1, int* res_pd2) + lmk05318_state_t* lmkst) { #ifdef LMK05318_SOLVER_DEBUG USDR_LOG("5318", USDR_LOG_DEBUG, "Solver iteration FVCO2:%" PRIu64 "", f_in); @@ -780,7 +817,7 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c for(int pd = out->pd_min; pd <= out->pd_max; ++pd) { - uint64_t f_pd = f_in / pd; + uint64_t f_pd = (uint64_t)((double)f_in / pd + 0.5); uint64_t divs[2]; lmk05318_get_output_divider(out, f_pd, &divs[0]); @@ -1157,14 +1194,67 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c if(!sol->is_valid) continue; - // use the first valid solution and return - USDR_LOG("5318", USDR_LOG_DEBUG, "SOLUTION#%d valid:%d FVCO2[%" PRIu64 "; %" PRIu64 "]->", i, sol->is_valid, sol->fvco2.min, sol->fvco2.max); + for(uint64_t f = sol->fvco2.min; f <= sol->fvco2.max; ++f) + { + unsigned n, num, den; + double fvco2 = lmk05318_calc_vco2_div(lmkst, f, &n, &num, &den); + + if(fvco2 < sol->fvco2.min || fvco2 > sol->fvco2.max) + continue; + + if(fvco2 != (uint64_t)fvco2) + continue; + + bool ok_flag = true; + + for(int ii = 0; ii < pd_binds_count; ++ii) + { + const pd_bind_t* b = &pd_binds[ii]; + + for(int j = 0; j < b->ports_count; ++j) + { + lmk05318_out_config_t* out = &outs[b->ports[j]]; + + uint64_t div; + const uint64_t fdiv_in = (uint64_t)(fvco2 / b->pd + 0.5); + int res = lmk05318_get_output_divider(out, fdiv_in, &div); + if(res) + { + ok_flag = false; + break; + } + + out->result.out_div = div; + out->result.freq = fvco2 / b->pd / div; + out->result.mux = (b->pd == pd1) ? OUT_PLL_SEL_APLL2_P1 : OUT_PLL_SEL_APLL2_P2; + out->solved = true; + } + + if(!ok_flag) + break; + } + + if(ok_flag) + { + lmkst->vco2_freq = fvco2; + lmkst->vco2_n = n; + lmkst->vco2_num = num; + lmkst->vco2_den = den; + lmkst->pd1 = pd1; + lmkst->pd2 = pd2; + return 0; + } + } + +#if 0 *res_fvco2 = (sol->fvco2.min + sol->fvco2.max) >> 1; *res_pd1 = pd1; *res_pd2 = pd2; + bool ok_flag = true; + for(int ii = 0; ii < pd_binds_count; ++ii) { const pd_bind_t* b = &pd_binds[ii]; @@ -1184,14 +1274,29 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c { lmk05318_out_config_t* out = &outs[b->ports[j]]; - out->result.out_div = b->odivs[j]; - out->result.freq = *res_fvco2 / b->pd / b->odivs[j]; + uint64_t div; + const uint64_t fdiv_in = (uint64_t)((double)(*res_fvco2) / b->pd + 0.5); + int res = lmk05318_get_output_divider(out, fdiv_in, &div); + if(res) + { + ok_flag = false; + break; + } + + out->result.out_div = div; //b->odivs[j]; + out->result.freq = (double)(*res_fvco2) / b->pd / div; //b->odivs[j]; out->result.mux = (b->pd == pd1) ? OUT_PLL_SEL_APLL2_P1 : OUT_PLL_SEL_APLL2_P2; out->solved = true; } + + if(!ok_flag) + break; } - return 0; + if(ok_flag) + return 0; +#endif + } #ifdef LMK05318_SOLVER_DEBUG @@ -1227,9 +1332,6 @@ static const char* lmk05318_decode_mux(enum lmk05318_out_pll_sel_t mux) VWLT_ATTRIBUTE(optimize("-Ofast")) int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run) { - int pd1 = 0, pd2 = 0; - uint64_t fvco2 = 0; - if(!_outs || !n_outs || n_outs > LMK05318_MAX_OUT_PORTS) { USDR_LOG("5318", USDR_LOG_ERROR, "input data is incorrect"); @@ -1392,11 +1494,11 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } const uint64_t f_mid = (VCO_APLL2_MAX + VCO_APLL2_MIN) / 2; - const uint64_t half_band = (VCO_APLL2_MAX - VCO_APLL2_MIN) / 2; + //const uint64_t half_band = (VCO_APLL2_MAX - VCO_APLL2_MIN) / 2; //first try the center - int res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, &fvco2, &pd1, &pd2); - + int res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, d); +/* //if not - do circular search if(res) { @@ -1409,14 +1511,14 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned for(uint64_t i = 1; i <= n; ++i) { - res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid + i * step, &fvco2, &pd1, &pd2); + res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid + i * step, &fvco2, &pd1, &pd2, d); if(!res) { step = 0; break; } - res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid - i * step, &fvco2, &pd1, &pd2); + res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid - i * step, &fvco2, &pd1, &pd2, d); if(!res) { step = 0; @@ -1427,7 +1529,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned step /= 2; } } - +*/ if(res) return res; @@ -1439,7 +1541,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned qsort(_outs, n_outs, sizeof(lmk05318_out_config_t), lmk05318_comp_port); bool complete_solution_check = true; - USDR_LOG("5318", USDR_LOG_DEBUG, "=== COMPLETE SOLUTION @ VCO1:%" PRIu64 " VCO2:%" PRIu64 " PD1:%d PD2:%d ===", VCO_APLL1, fvco2, pd1, pd2); + USDR_LOG("5318", USDR_LOG_DEBUG, "=== COMPLETE SOLUTION @ VCO1:%" PRIu64 " VCO2:%" PRIu64 " PD1:%d PD2:%d ===", VCO_APLL1, d->vco2_freq, d->pd1, d->pd2); for(unsigned i = 0; i < n_outs; ++i) { lmk05318_out_config_t* out_dst = _outs + i; @@ -1465,7 +1567,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(!is_freq_ok) complete_solution_check = false; - USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.2f mux:%d(%s)] %s", + USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.8f mux:%d(%s)] %s", out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux, lmk05318_decode_mux(out_dst->result.mux), is_freq_ok ? "**OK**" : "**BAD**"); @@ -1476,11 +1578,6 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(d) { - //update params in context - d->vco2_freq = fvco2; - d->pd1 = pd1; - d->pd2 = pd2; - for(unsigned i = 0; i < n_outs; ++i) { const lmk05318_out_config_t* out = _outs + i; @@ -1494,7 +1591,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(!dry_run) { //tune APLL2 - int res = lmk05318_tune_apll2_ex(d, fvco2, pd1, pd2); + int res = lmk05318_tune_apll2_ex(d); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "error %d tuning APLL2", res); diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 1dadb325..25a86d29 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -41,6 +41,7 @@ struct lmk05318_state { // VCO2 freq uint64_t vco2_freq; + unsigned vco2_n, vco2_num, vco2_den; unsigned pd1, pd2; struct { diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index 8ac7152a..da1f3eda 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -1211,20 +1211,17 @@ pages: - addr: 0x13F name: DPLL_REF_MASHCTL - - addr: "0x140:0x141" - name: DPLL_REF_LOCKDET_PPM_MAX + - addr: "0x140:0x144" + name: DPLL_REF_LOCKDET_1_5 - - addr: "0x142:0x145" - name: DPLL_REF_LOCKDET_CNTSTRT + - addr: "0x145:0x149" + name: DPLL_REF_LOCKDET_6_10 - - addr: "0x146:0x149" - name: DPLL_REF_LOCKDET_VCO_CNTSTRT + - addr: "0x14A:0x14C" + name: DPLL_REF_UNLOCKDET_1_3 - - addr: "0x14A:0x14B" - name: DPLL_REF_UNLOCKDET_PPM_MAX - - - addr: "0x14C:0x14F" - name: DPLL_REF_UNLOCKDET_CNTSTRT + - addr: "0x14D:0x14F" + name: PLL2_DEN - addr: "0x150:0x152" name: DPLL_REF_UNLOCKDET_VCO_CNTSTRT diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 27120d34..20ec5afc 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -6,10 +6,15 @@ #define DELTA_MINUS 2 static lmk05318_out_config_t cfg[OUTS_LEN]; +static lmk05318_state_t dev; static void setup() { memset(cfg, 0, sizeof(cfg)); + memset(&dev, 0, sizeof(dev)); + + dev.fref_pll2_div_rp = 3; + dev.fref_pll2_div_rs = 6; int res = 0; res = res ? res : lmk05318_port_request(cfg, 0, 100000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); @@ -29,14 +34,14 @@ static void teardown() START_TEST(lmk05318_solver_test1) { - int res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); + int res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); ck_assert_int_eq( res, 0 ); } START_TEST(lmk05318_solver_test2) { int res = 0; - const uint64_t f = 5659995555ull; + const uint64_t f = 5650000000ull; res = res ? res : lmk05318_port_request(cfg, 2, f/7/256, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 3, f/7/256, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); @@ -44,7 +49,7 @@ START_TEST(lmk05318_solver_test2) res = res ? res : lmk05318_port_request(cfg, 6, f/7/17, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); + res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); ck_assert_int_eq( res, 0 ); } @@ -52,7 +57,7 @@ START_TEST(lmk05318_solver_test2) START_TEST(lmk05318_solver_test3) { uint64_t fvco1 = 2500000000ull; - uint64_t f0_3 = fvco1 / 123; + uint64_t f0_3 = fvco1 / 16; uint64_t f4_7 = 12500000; //3840000; int res = 0; @@ -76,14 +81,14 @@ START_TEST(lmk05318_solver_test3) res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); + res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); ck_assert_int_eq( res, 0 ); } START_TEST(lmk05318_solver_test4) { uint64_t fvco1 = 2500000000ull; - uint64_t f0_3 = fvco1 / 123; + uint64_t f0_3 = fvco1 / 16; uint64_t f4_7 = 12500000; //3840000; memset(cfg, 0, sizeof(cfg)); @@ -109,10 +114,10 @@ START_TEST(lmk05318_solver_test4) res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(NULL, cfg, 4, true); + res = lmk05318_solver(&dev, cfg, 4, true); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(NULL, cfg + 4, 4, true); + res = lmk05318_solver(&dev, cfg + 4, 4, true); ck_assert_int_eq( res, 0 ); } @@ -143,7 +148,7 @@ START_TEST(lmk05318_solver_test5) res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(NULL, cfg, OUTS_LEN, true); + res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); ck_assert_int_eq( res, 0 ); } @@ -170,7 +175,7 @@ START_TEST(lmk05318_solver_test6) res = res ? res : lmk05318_port_request(cfg, 2, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 3, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 4, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 17000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 26000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 6, 13000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); ck_assert_int_eq( res, 0 ); @@ -200,11 +205,11 @@ Suite * lmk05318_solver_suite(void) tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - //tcase_add_test(tc_core, lmk05318_solver_test1); + tcase_add_test(tc_core, lmk05318_solver_test1); //tcase_add_test(tc_core, lmk05318_solver_test2); - //tcase_add_test(tc_core, lmk05318_solver_test3); - //tcase_add_test(tc_core, lmk05318_solver_test4); - //tcase_add_test(tc_core, lmk05318_solver_test5); + tcase_add_test(tc_core, lmk05318_solver_test3); + tcase_add_test(tc_core, lmk05318_solver_test4); + tcase_add_test(tc_core, lmk05318_solver_test5); tcase_add_test(tc_core, lmk05318_solver_test6); suite_add_tcase(s, tc_core); From a5fc2f969c87c493cbf4c4920b2c63cb8928af03 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 12:04:22 +0300 Subject: [PATCH 060/397] minor fixes & code cleaning --- .../device/ext_simplesync/ext_simplesync.c | 20 +-- src/lib/device/pe_sync/pe_sync.c | 17 +- src/lib/hw/lmk05318/lmk05318.c | 150 +++--------------- src/lib/hw/lmk05318/lmk05318.h | 13 +- src/utests/lmk05318_solver_test.c | 90 +++++------ 5 files changed, 90 insertions(+), 200 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 784c1fad..21cd3c4c 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -41,10 +41,6 @@ enum { I2C_ADDR_LMK = 0x65, }; -enum { - FREQ_DELTA_HZ = 2, -}; - int board_ext_simplesync_init(lldev_t dev, unsigned subdev, unsigned gpio_base, @@ -92,10 +88,10 @@ int board_ext_simplesync_init(lldev_t dev, xo.type = XO_CMOS; lmk05318_out_config_t cfg[4]; - lmk05318_port_request(cfg, 4, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); - lmk05318_port_request(cfg, 5, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); - lmk05318_port_request(cfg, 6, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); - lmk05318_port_request(cfg, 7, 25000000, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, LVCMOS); + lmk05318_port_request(cfg, 4, 25000000, false, LVCMOS); + lmk05318_port_request(cfg, 5, 25000000, false, LVCMOS); + lmk05318_port_request(cfg, 6, 25000000, false, LVCMOS); + lmk05318_port_request(cfg, 7, 25000000, false, LVCMOS); lmk05318_set_port_affinity(cfg, 4, AFF_APLL1); lmk05318_set_port_affinity(cfg, 5, AFF_APLL1); lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); @@ -126,10 +122,10 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) } #else lmk05318_out_config_t cfg[4]; - lmk05318_port_request(cfg, 0, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_port_request(cfg, 1, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_port_request(cfg, 2, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_port_request(cfg, 3, meas_lo, FREQ_DELTA_HZ, FREQ_DELTA_HZ, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_port_request(cfg, 0, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_port_request(cfg, 1, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_port_request(cfg, 2, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); + lmk05318_port_request(cfg, 3, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); lmk05318_set_port_affinity(cfg, 0, AFF_APLL2); lmk05318_set_port_affinity(cfg, 1, AFF_APLL2); lmk05318_set_port_affinity(cfg, 2, AFF_APLL2); diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index b7fbb8e3..8c0accf8 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -273,16 +273,15 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const bool use_dpll = false; - const int out_accuracy = 2; lmk05318_out_config_t lmk05318_outs_cfg[8]; - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 0, 125000000, out_accuracy, out_accuracy, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 1, 125000000, out_accuracy, out_accuracy, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 2, 250000000, out_accuracy, out_accuracy, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 3, 250000000, out_accuracy, out_accuracy, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 4, 156250000, out_accuracy, out_accuracy, false, OUT_OFF); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 5, 156250000, out_accuracy, out_accuracy, false, OUT_OFF); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, 10000000, out_accuracy, out_accuracy, false, LVCMOS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, 1, out_accuracy, out_accuracy, false, LVCMOS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 0, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 1, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 2, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 3, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 4, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 5, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, 10000000, false, LVCMOS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, 1, false, LVCMOS); res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, use_dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); if(res) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 922862fb..8f38aeeb 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -16,6 +16,8 @@ #include #include "../../xdsp/attribute_switch.h" +//#define LMK05318_SOLVER_DEBUG + enum { VCO_APLL1 = 2500000000ull, VCO_APLL1_MIN = 2499750000ull, @@ -342,7 +344,9 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return 0; } - +/* + * Legacy function, remove it later + */ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int flags, lmk05318_state_t* out) { int res; @@ -400,8 +404,11 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); return 0; } +/**/ - +/* + * Legacy function, remove it later + */ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) { const unsigned apll2_post_div = 2; @@ -446,6 +453,7 @@ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) *last_div = div; return 0; } +/**/ VWLT_ATTRIBUTE(optimize("-Ofast")) static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, unsigned* pn, unsigned* pnum, unsigned* pden) @@ -459,7 +467,9 @@ static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, const double fvco2_fact = (double)VCO_APLL1 * (n + (double)num / den) / d->fref_pll2_div_rp / d->fref_pll2_div_rs; - //USDR_LOG("5318", USDR_LOG_ERROR, "WANTED_VCO2:%" PRIu64 " N:%u NUM:%u DEN:%u VCO2:%.8f", fvco2, n, num, den, fvco2_fact); +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_ERROR, "WANTED_VCO2:%" PRIu64 " N:%u NUM:%u DEN:%u VCO2:%.8f", fvco2, n, num, den, fvco2_fact); +#endif if(pn) *pn = n; @@ -473,10 +483,10 @@ static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) { - double fref = (double)VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; - if (fref < APLL2_PD_MIN || fref > APLL2_PD_MAX) { + double fpd2 = (double)VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; + if (fpd2 < APLL2_PD_MIN || fpd2 > APLL2_PD_MAX) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 PFD should be in range [%" PRIu64 ";%" PRIu64 "] but got %.8f!\n", - (uint64_t)APLL2_PD_MIN, (uint64_t)APLL2_PD_MAX, fref); + (uint64_t)APLL2_PD_MIN, (uint64_t)APLL2_PD_MAX, fpd2); return -EINVAL; } @@ -499,7 +509,7 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) int res; USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 RS=%u RP=%u FPD2=%.8f FVCO2=%" PRIu64 " N=%d NUM=%d DEN=%d PD1=%d PD2=%d\n", - d->fref_pll2_div_rs, d->fref_pll2_div_rp, fref, d->vco2_freq, n, num, den, d->pd1, d->pd2); + d->fref_pll2_div_rs, d->fref_pll2_div_rp, fpd2, d->vco2_freq, n, num, den, d->pd1, d->pd2); // one of PDs may be unused (==0) -> we should fix it before registers set if(d->pd1 < APLL2_PDIV_MIN || d->pd1 > APLL2_PDIV_MAX) @@ -580,14 +590,14 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) { - unsigned fref = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); + unsigned fpd1 = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); uint64_t fvco = VCO_APLL1; - unsigned n = fvco / fref; + unsigned n = fvco / fpd1; //in DPLL mode we use FIXED 40-bit APLL1 denominator and programmed 40-bit numerator if(dpll_mode) { - uint64_t num = (fvco - n * (uint64_t)fref) * (1ull << 40) / fref; + uint64_t num = (fvco - n * (uint64_t)fpd1) * (1ull << 40) / fpd1; USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 " DEN=FIXED\n", fvco, n, num); @@ -610,7 +620,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator else { - double frac = (double)fvco / fref - n; + double frac = (double)fvco / fpd1 - n; const uint32_t den = ((uint32_t)1 << 24) - 1; //max 24-bit const uint32_t num = (frac * den + 0.5); @@ -744,16 +754,6 @@ static range_t lmk05318_get_freq_range(const lmk05318_out_config_t* cfg) return r; } -//#define LMK05318_SOLVER_DEBUG - -/* -enum { - freq_too_low = -1, - freq_too_high = 1, - freq_ok = 0, - freq_invalid = 42, -}; -*/ VWLT_ATTRIBUTE(optimize("-Ofast")) static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, double ifreq, uint64_t* div) { @@ -763,29 +763,7 @@ static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, return 1; double factf = ifreq / (*div); - return (factf == cfg->wanted.freq) ? 0 : 1; -/* - if(*div > cfg->max_odiv) - return freq_too_high; - - if(*div < 1) - return freq_too_low; - - double f = (double)ifreq / *div; - - if(f <= cfg->freq_max && f >= cfg->freq_min) - return freq_ok; - - if(*div <= cfg->max_odiv - 1) - { - f = (double)ifreq / ++(*div); - if(f <= cfg->freq_max && f >= cfg->freq_min) - return freq_ok; - } - - return freq_invalid; -*/ } VWLT_ATTRIBUTE(optimize("-Ofast")) @@ -1247,56 +1225,6 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c return 0; } } - -#if 0 - *res_fvco2 = (sol->fvco2.min + sol->fvco2.max) >> 1; - *res_pd1 = pd1; - *res_pd2 = pd2; - - bool ok_flag = true; - - for(int ii = 0; ii < pd_binds_count; ++ii) - { - const pd_bind_t* b = &pd_binds[ii]; - char tmp[1024]; - int tmp_len = sprintf(tmp, "\tPD%d=%d ports[", (ii+1), b->pd); - - for(int j = 0; j < b->ports_count; ++j) - { - tmp_len += sprintf(tmp + tmp_len, "%d(OD:%" PRIu64 ")),", outs[b->ports[j]].port, b->odivs[j]); - } - - tmp_len += sprintf(tmp + tmp_len, "]"); - USDR_LOG("5318", USDR_LOG_DEBUG, "%s", tmp); - - //set results - for(int j = 0; j < b->ports_count; ++j) - { - lmk05318_out_config_t* out = &outs[b->ports[j]]; - - uint64_t div; - const uint64_t fdiv_in = (uint64_t)((double)(*res_fvco2) / b->pd + 0.5); - int res = lmk05318_get_output_divider(out, fdiv_in, &div); - if(res) - { - ok_flag = false; - break; - } - - out->result.out_div = div; //b->odivs[j]; - out->result.freq = (double)(*res_fvco2) / b->pd / div; //b->odivs[j]; - out->result.mux = (b->pd == pd1) ? OUT_PLL_SEL_APLL2_P1 : OUT_PLL_SEL_APLL2_P2; - out->solved = true; - } - - if(!ok_flag) - break; - } - - if(ok_flag) - return 0; -#endif - } #ifdef LMK05318_SOLVER_DEBUG @@ -1494,46 +1422,10 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } const uint64_t f_mid = (VCO_APLL2_MAX + VCO_APLL2_MIN) / 2; - //const uint64_t half_band = (VCO_APLL2_MAX - VCO_APLL2_MIN) / 2; - - //first try the center int res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, d); -/* - //if not - do circular search - if(res) - { - uint64_t step = half_band; - - //max search granularity hardcoded here - while(step > 10000) - { - uint64_t n = half_band / step; - - for(uint64_t i = 1; i <= n; ++i) - { - res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid + i * step, &fvco2, &pd1, &pd2, d); - if(!res) - { - step = 0; - break; - } - - res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid - i * step, &fvco2, &pd1, &pd2, d); - if(!res) - { - step = 0; - break; - } - } - - step /= 2; - } - } -*/ if(res) return res; - have_complete_solution: //if ok - update the results diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 25a86d29..48612a29 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -104,10 +104,11 @@ struct lmk05318_out_config }; typedef struct lmk05318_out_config lmk05318_out_config_t; +#define LMK05318_FREQ_DELTA 2 + static inline int lmk05318_port_request(lmk05318_out_config_t* cfg, unsigned port, uint32_t freq, - unsigned freq_delta_plus, unsigned freq_delta_minus, bool revert_phase, lmk05318_type_t type) { @@ -118,8 +119,8 @@ static inline int lmk05318_port_request(lmk05318_out_config_t* cfg, memset(p, 0, sizeof(*p)); p->port = port; p->wanted.freq = freq; - p->wanted.freq_delta_plus = freq_delta_plus; - p->wanted.freq_delta_minus = freq_delta_minus; + p->wanted.freq_delta_plus = LMK05318_FREQ_DELTA; + p->wanted.freq_delta_minus = LMK05318_FREQ_DELTA; p->wanted.revert_phase = revert_phase; p->wanted.type = type; p->wanted.pll_affinity = AFF_ANY; @@ -138,9 +139,13 @@ static inline int lmk05318_set_port_affinity(lmk05318_out_config_t* cfg, unsigne return 0; } +/* + * Legacy functions, remove them later + */ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned flags, lmk05318_state_t* out); - int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div); +/**/ + int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t div); int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 20ec5afc..3dd1ed78 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -2,8 +2,6 @@ #include "lmk05318/lmk05318.h" #define OUTS_LEN LMK05318_MAX_OUT_PORTS -#define DELTA_PLUS 2 -#define DELTA_MINUS 2 static lmk05318_out_config_t cfg[OUTS_LEN]; static lmk05318_state_t dev; @@ -17,14 +15,14 @@ static void setup() dev.fref_pll2_div_rs = 6; int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, 100000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, 100000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 2, 122880000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, 122880000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, 31250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 3840000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 491520000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, true, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 0, 100000000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, 100000000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 2, 122880000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, 122880000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, 31250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 3840000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 491520000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 7, 1, true, OUT_OFF); ck_assert_int_eq( res, 0 ); } @@ -43,10 +41,10 @@ START_TEST(lmk05318_solver_test2) int res = 0; const uint64_t f = 5650000000ull; - res = res ? res : lmk05318_port_request(cfg, 2, f/7/256, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, f/7/256, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, f/2/4, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, f/7/17, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 2, f/7/256, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, f/7/256, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, f/2/4, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, f/7/17, false, OUT_OFF); ck_assert_int_eq( res, 0 ); res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); @@ -61,14 +59,14 @@ START_TEST(lmk05318_solver_test3) uint64_t f4_7 = 12500000; //3840000; int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 2, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 7, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 0, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 2, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 7, f4_7, false, OUT_OFF); ck_assert_int_eq( res, 0 ); res = res ? res : lmk05318_set_port_affinity(cfg, 0, AFF_APLL1); @@ -94,14 +92,14 @@ START_TEST(lmk05318_solver_test4) memset(cfg, 0, sizeof(cfg)); int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - //res = res ? res : lmk05318_port_request(cfg, 2, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, f0_3, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - //res = res ? res : lmk05318_port_request(cfg, 6, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 7, f4_7, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 0, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, f0_3, false, OUT_OFF); + //res = res ? res : lmk05318_port_request(cfg, 2, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 3, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, f4_7, false, OUT_OFF); + //res = res ? res : lmk05318_port_request(cfg, 6, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 7, f4_7, false, OUT_OFF); ck_assert_int_eq( res, 0 ); res = res ? res : lmk05318_set_port_affinity(cfg, 0, AFF_APLL1); @@ -138,14 +136,14 @@ START_TEST(lmk05318_solver_test5) */ int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 1, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 2, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 3, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 4, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 10000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); - res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 0, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 1, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 2, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 3, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 4, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 10000000, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 7, 1, false, LVCMOS); ck_assert_int_eq( res, 0 ); res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); @@ -170,14 +168,14 @@ START_TEST(lmk05318_solver_test6) */ int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 1, 125000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 2, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 3, 250000000, DELTA_PLUS, DELTA_MINUS, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 4, 156250000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 26000000, DELTA_PLUS, DELTA_MINUS, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 13000000, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); - res = res ? res : lmk05318_port_request(cfg, 7, 1, DELTA_PLUS, DELTA_MINUS, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 0, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 1, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 2, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 3, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 4, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 26000000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 13000000, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 7, 1, false, LVCMOS); ck_assert_int_eq( res, 0 ); lmk05318_xo_settings_t xo; From 22aaf5305f78ce3e798bc04afd9d16ddd0ab4a27 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 12:36:41 +0300 Subject: [PATCH 061/397] update ext_simplesync logic --- src/lib/device/ext_simplesync/ext_simplesync.c | 14 ++++++++++++-- src/lib/hw/lmk05318/lmk05318.c | 4 ++-- src/lib/hw/lmk05318/lmk05318.h | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 21cd3c4c..2fc233f8 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -97,7 +97,12 @@ int board_ext_simplesync_init(lldev_t dev, lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); lmk05318_set_port_affinity(cfg, 7, AFF_APLL1); - res = lmk05318_create_ex(dev, subdev, i2ca, &xo, false, cfg, 4, &ob->lmk, false /*dry_run*/); + const bool dpll_mode = false; + + res = lmk05318_create_ex(dev, subdev, i2ca, &xo, dpll_mode, cfg, 4, &ob->lmk, false /*dry_run*/); + res = res ? res : lmk05318_reset_los_flags(&ob->lmk); + res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, dpll_mode, 10000); + res = res ? res : lmk05318_sync(&ob->lmk); #endif if (res) @@ -131,7 +136,12 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) lmk05318_set_port_affinity(cfg, 2, AFF_APLL2); lmk05318_set_port_affinity(cfg, 3, AFF_APLL2); - int res = lmk05318_solver(&ob->lmk, cfg, 4, false); + int res = lmk05318_solver(&ob->lmk, cfg, 4, false /*dry_run*/); + res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); + res = res ? res : lmk05318_softreset(&ob->lmk); + res = res ? res : lmk05318_reset_los_flags(&ob->lmk); + res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); + res = res ? res : lmk05318_sync(&ob->lmk); #endif return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 8f38aeeb..01a6c724 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -123,7 +123,7 @@ static int lmk05318_add_reg_to_map(lmk05318_state_t* d, const uint32_t* regs, un return 0; } -static int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run) +int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run) { for(unsigned j = 0; j < SIZEOF_ARRAY(registers_map); ++j) { @@ -147,7 +147,7 @@ static int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run) -static int lmk05318_softreset(lmk05318_state_t* out) +int lmk05318_softreset(lmk05318_state_t* out) { uint8_t reg_ctrl; const uint8_t mask = ((uint8_t)1 << RESET_SW_OFF); diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 48612a29..f9d7f7c2 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -166,9 +166,11 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d); int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeout); int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout); +int lmk05318_softreset(lmk05318_state_t* out); int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); +int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run); int lmk05318_set_xo_fref(lmk05318_state_t* d); int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode); From c9d51c8df43e296d3b42ad4fcc400cc4f41f4627 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 15:20:21 +0300 Subject: [PATCH 062/397] fix accuracy for lmx2820 --- src/lib/hw/lmx2820/lmx2820.c | 50 +++++++++++++++++--------------- src/utests/lmx2820_solver_test.c | 5 ++-- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 0d44940c..0f41da2c 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -44,8 +44,7 @@ enum { OUT_DIV_LOG2_MAX = 7, }; -#define VCO_ACCURACY 0.1f -#define RF_ACCURACY 1.0f +#define RF_ACCURACY 0.0f #define OUT_DIV_DIAP_MAX (OUT_DIV_LOG2_MAX - OUT_DIV_LOG2_MIN + 1 + 1) //Pin3 bias capacitor, uF @@ -334,14 +333,21 @@ static int lmx2820_tune_vco(lmx2820_state_t* st, uint64_t vco) double pll_frac = n_total - pll_n; USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_FRAC:%.8f", pll_n, pll_frac); - uint32_t pll_den = UINT32_MAX; - uint32_t pll_num = pll_frac * pll_den; - double vco_fact = (double)settings->fpd * (pll_n + (double)pll_num / pll_den); + const unsigned pll_r_div = settings->pll_r * settings->pll_r_pre; + if(settings->fpd * pll_r_div > UINT32_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "PLL_DEN overflow, cannot solve in integer values. Try lower OSC_IN."); + return -EINVAL; + } + + uint32_t pll_den = settings->fpd * pll_r_div; + uint32_t pll_num = (uint32_t)(pll_frac * pll_den + 0.5); + const double ff = (double)settings->fosc_in * (settings->osc_2x ? 2 : 1) * settings->mult; + double vco_fact = ff * pll_n / pll_r_div + ff * pll_num / pll_r_div / pll_den; - double delta = fabs(vco_fact - vco); - USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f Deviation:%.8fHz", pll_n, pll_num, pll_den, vco_fact, delta); + USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.8f", pll_n, pll_num, pll_den, vco_fact); - if(delta > VCO_ACCURACY) + if(vco_fact != vco) { USDR_LOG("2820", USDR_LOG_ERROR, "VCO tuning too rough"); return -EINVAL; @@ -383,28 +389,26 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, if((osc_in < fpd_min) || force_mult) { + //need mult + if(force_mult) USDR_LOG("2820", USDR_LOG_DEBUG, "Mult:%d forced by user", force_mult); else USDR_LOG("2820", USDR_LOG_DEBUG, "Need mult"); - //need mult - mult = MAX(force_mult ? force_mult : (unsigned)ceil((double)fpd_min / osc_in), MULT_MIN); - if(mult > MULT_MAX) + if(osc_in < MULT_IN_FREQ_MIN) { - USDR_LOG("2820", USDR_LOG_ERROR, "Mult:%d out of range", mult); + USDR_LOG("2820", USDR_LOG_ERROR, "OSC_IN:%" PRIu64" too low for mult, set %" PRIu64 " at least", fosc_in, (uint64_t)MULT_IN_FREQ_MIN); return -EINVAL; } + mult = force_mult ? force_mult : (unsigned)floor((double)fpd_max / osc_in); + mult = MIN(MAX(mult, MULT_MIN), MULT_MAX); + USDR_LOG("2820", USDR_LOG_DEBUG, "Calculated mult:%u", mult); + pll_r_pre = 1; pll_r = 1; - if(osc_in < MULT_IN_FREQ_MIN) - { - USDR_LOG("2820", USDR_LOG_ERROR, "OSC_IN:%" PRIu64" too low for mult, set %" PRIu64 " at least", fosc_in, (uint64_t)MULT_IN_FREQ_MIN/2); - return -EINVAL; - } - if(osc_in > MULT_IN_FREQ_MAX) { pll_r_pre = (unsigned)ceil((double)osc_in / MULT_IN_FREQ_MAX); @@ -482,12 +486,12 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, return -EINVAL; } - uint64_t fpd = (uint64_t)((double)osc_in * mult / (pll_r_pre * pll_r) + 0.5); - USDR_LOG("2820", USDR_LOG_DEBUG, "For VCO:%" PRIu64 " -> FPD:%" PRIu64, vco, fpd); + double fpd = (double)osc_in * mult / (pll_r_pre * pll_r); + USDR_LOG("2820", USDR_LOG_DEBUG, "For VCO:%" PRIu64 " -> FPD:%.8f", vco, fpd); if(fpd < fpd_min || fpd > fpd_max) { - USDR_LOG("2820", USDR_LOG_ERROR, "FPD:%" PRIu64 " out of range: should never be happen!", fpd); + USDR_LOG("2820", USDR_LOG_ERROR, "FPD:%.8f out of range: should never be happen!", fpd); return -EINVAL; } @@ -680,8 +684,8 @@ static int lmx2820_solver_validate_and_save(lmx2820_state_t* st, uint64_t rfouta double rfa_delta = fabs(rfouta - rfa); double rfb_delta = fabs(rfoutb - rfb); - USDR_LOG("2820", USDR_LOG_DEBUG, "RF_A:%" PRIu64 "->%.6f Deviation:%.8fHz", rfouta, rfa, rfa_delta); - USDR_LOG("2820", USDR_LOG_DEBUG, "RF_B:%" PRIu64 "->%.6f Deviation:%.8fHz", rfoutb, rfb, rfb_delta); + USDR_LOG("2820", USDR_LOG_DEBUG, "RF_A:%" PRIu64 "->%.6f (DIV:%u) Deviation:%.8fHz", rfouta, rfa, ((unsigned)1 << diva), rfa_delta); + USDR_LOG("2820", USDR_LOG_DEBUG, "RF_B:%" PRIu64 "->%.6f (DIV:%u) Deviation:%.8fHz", rfoutb, rfb, ((unsigned)1 << divb), rfb_delta); if(rfa_delta > RF_ACCURACY || rfb_delta > RF_ACCURACY) { diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index 5eab6301..f1dd4b21 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -92,7 +92,7 @@ START_TEST(lmx2820_solver_test8) { const uint64_t osc_in = 250000000ull; const int mash_order = 0; - uint64_t out_freq1 = 20000987000ull; + uint64_t out_freq1 = 2000098000ull; uint64_t out_freq2 = out_freq1 >> 4; int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); @@ -103,7 +103,7 @@ START_TEST(lmx2820_solver_test9_force_mult) { const uint64_t osc_in = 250000000ull; const int mash_order = 0; - uint64_t out_freq1 = 20000987000ull; + uint64_t out_freq1 = 20000988000ull; uint64_t out_freq2 = out_freq1 >> 4; int res = lmx2820_solver(&st, osc_in, mash_order, _i, out_freq1, out_freq2); @@ -158,6 +158,7 @@ Suite * lmx2820_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); + tcase_add_test(tc_core, lmx2820_solver_test1); tcase_add_test(tc_core, lmx2820_solver_test2); tcase_add_test(tc_core, lmx2820_solver_test3); From 089bdb17ca086962700d05e468a51cb9cb185127 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 17:27:33 +0300 Subject: [PATCH 063/397] add CGD (common greatest divider) to VCOs num/den --- src/lib/cal/opt_func.c | 33 +++++++++++++++++++++++++++ src/lib/cal/opt_func.h | 2 ++ src/lib/hw/lmk05318/lmk05318.c | 32 ++++++++++++++++++++++---- src/lib/hw/lmk05318/lmk05318_solver.h | 5 ---- src/lib/hw/lmx2820/lmx2820.c | 24 +++++++++++++------ 5 files changed, 80 insertions(+), 16 deletions(-) diff --git a/src/lib/cal/opt_func.c b/src/lib/cal/opt_func.c index bdfeaf9b..56112122 100644 --- a/src/lib/cal/opt_func.c +++ b/src/lib/cal/opt_func.c @@ -170,3 +170,36 @@ int find_best_2d(struct opt_iteration2d *ops, unsigned max_count, void* param, i return 0; } +// Function to implement Stein's Algorithm +// Borrowed from: https://www.geeksforgeeks.org/steins-algorithm-for-finding-gcd/ (C) +// +uint64_t find_gcd(uint64_t a, uint64_t b) +{ + if (a == b) + return a; + + // GCD(0, b) == b; GCD(a, 0) == a, + // GCD(0, 0) == 0 + if (a == 0) + return b; + if (b == 0) + return a; + + // look for factors of 2 + if (~a & 1) // a is even + { + if (b & 1) // b is odd + return find_gcd(a >> 1, b); + else // both a and b are even + return find_gcd(a >> 1, b >> 1) << 1; + } + + if (~b & 1) // a is odd, b is even + return find_gcd(a, b >> 1); + + // reduce larger number + if (a > b) + return find_gcd((a - b) >> 1, b); + + return find_gcd((b - a) >> 1, a); +} diff --git a/src/lib/cal/opt_func.h b/src/lib/cal/opt_func.h index 7030271d..14a639dc 100644 --- a/src/lib/cal/opt_func.h +++ b/src/lib/cal/opt_func.h @@ -8,6 +8,7 @@ #ifndef OPT_FUNC_H #define OPT_FUNC_H +#include "stdint.h" #define MAX(a, b) \ ({ __typeof__ (a) _a = (a); \ @@ -55,5 +56,6 @@ struct opt_iteration2d int find_best_2d(struct opt_iteration2d *ops, unsigned max_count, void* param, int stop_when, int *px, int *py, int *pfxy); +uint64_t find_gcd(uint64_t a, uint64_t b); #endif diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 01a6c724..2763060a 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -15,6 +15,7 @@ #include #include "../../xdsp/attribute_switch.h" +#include "../cal/opt_func.h" //#define LMK05318_SOLVER_DEBUG @@ -458,14 +459,37 @@ int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) VWLT_ATTRIBUTE(optimize("-Ofast")) static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, unsigned* pn, unsigned* pnum, unsigned* pden) { - const unsigned den = VCO_APLL1 >> 8; //fit to 24 bit -> 9 765 625 (0x9502f9) + const uint64_t pll2_tot_prediv = d->fref_pll2_div_rp * d->fref_pll2_div_rs; - double r = (double)(fvco2 * d->fref_pll2_div_rp * d->fref_pll2_div_rs) / VCO_APLL1; + uint64_t den64 = VCO_APLL1 * pll2_tot_prediv; + double r = (double)(fvco2 * pll2_tot_prediv) / VCO_APLL1; unsigned n = (unsigned)r; double n_frac = r - n; - unsigned num = (unsigned)(n_frac * den); + uint64_t num64 = (uint64_t)(n_frac * den64 + 0.5); - const double fvco2_fact = (double)VCO_APLL1 * (n + (double)num / den) / d->fref_pll2_div_rp / d->fref_pll2_div_rs; + uint64_t nod = find_gcd(num64, den64); + if(nod > 1) + { +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_DEBUG, "PLL2 NUM/DEN reduced NOD:%" PRIu64 ": %" PRIu64 "/%" PRIu64" -> %" PRIu64 "/%" PRIu64, + nod, num64, den64, num64/nod, den64/nod); +#endif + num64 /= nod; + den64 /= nod; + } + + if(den64 > 0xFFFFFF) + { +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_ERROR, "PLL2_DEN overflow, cannot solve in integer values"); +#endif + return -EINVAL; + } + + uint32_t num = num64; + uint32_t den = den64; + + const double fvco2_fact = (double)VCO_APLL1 * (n + (double)num / den) / pll2_tot_prediv; #ifdef LMK05318_SOLVER_DEBUG USDR_LOG("5318", USDR_LOG_ERROR, "WANTED_VCO2:%" PRIu64 " N:%u NUM:%u DEN:%u VCO2:%.8f", fvco2, n, num, den, fvco2_fact); diff --git a/src/lib/hw/lmk05318/lmk05318_solver.h b/src/lib/hw/lmk05318/lmk05318_solver.h index 54862eb7..4a7436ff 100644 --- a/src/lib/hw/lmk05318/lmk05318_solver.h +++ b/src/lib/hw/lmk05318/lmk05318_solver.h @@ -3,11 +3,6 @@ #include -#define DIAP_MAX 6 - -#define MAX(a, b) (a) > (b) ? (a) : (b) -#define MIN(a, b) (a) < (b) ? (a) : (b) - struct range { uint64_t min, max; diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 0f41da2c..0f091a3d 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -9,6 +9,7 @@ #include "lmx2820.h" #include "def_lmx2820.h" #include +#include "../cal/opt_func.h" enum { @@ -82,9 +83,6 @@ static uint64_t FPD_MAX[MASH_ORDER_THIRD_ORDER + 1] = 400000000, 300000000, 300000000, 250000000 }; -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - #define INSTCAL_R0_MASK (((uint16_t)1 << FCAL_EN_OFF) | ((uint16_t)1 << DBLR_CAL_EN_OFF) | ((uint16_t)1 << INSTCAL_SKIP_ACAL_OFF)) static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count) @@ -306,7 +304,6 @@ int lmx2820_destroy(lmx2820_state_t* st) return 0; } - static int lmx2820_tune_vco(lmx2820_state_t* st, uint64_t vco) { int res = 0; @@ -334,14 +331,27 @@ static int lmx2820_tune_vco(lmx2820_state_t* st, uint64_t vco) USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_FRAC:%.8f", pll_n, pll_frac); const unsigned pll_r_div = settings->pll_r * settings->pll_r_pre; - if(settings->fpd * pll_r_div > UINT32_MAX) + uint64_t pll_den64 = settings->fpd * pll_r_div; + uint64_t pll_num64 = (uint64_t)(pll_frac * pll_den64 + 0.5); + uint64_t nod = find_gcd(pll_num64, pll_den64); + + if(nod > 1) + { + USDR_LOG("2820", USDR_LOG_DEBUG, "PLL NUM/DEN reduced NOD:%" PRIu64 ": %" PRIu64 "/%" PRIu64" -> %" PRIu64 "/%" PRIu64, + nod, pll_num64, pll_den64, pll_num64/nod, pll_den64/nod); + pll_num64 /= nod; + pll_den64 /= nod; + } + + if(pll_den64 > UINT32_MAX) { USDR_LOG("2820", USDR_LOG_ERROR, "PLL_DEN overflow, cannot solve in integer values. Try lower OSC_IN."); return -EINVAL; } - uint32_t pll_den = settings->fpd * pll_r_div; - uint32_t pll_num = (uint32_t)(pll_frac * pll_den + 0.5); + uint32_t pll_num = pll_num64; + uint32_t pll_den = pll_den64; + const double ff = (double)settings->fosc_in * (settings->osc_2x ? 2 : 1) * settings->mult; double vco_fact = ff * pll_n / pll_r_div + ff * pll_num / pll_r_div / pll_den; From b261a88a2d2b238bbacb8ab6dac92a2f74e1d58c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 18:47:12 +0300 Subject: [PATCH 064/397] lmx2820 lmx1 added to pe_sync --- src/lib/device/pe_sync/pe_sync.c | 46 ++++++++++++++++++++++++----- src/lib/hw/lmx2820/lmx2820.c | 50 +++++++++++++++++++++++--------- src/lib/hw/lmx2820/lmx2820.h | 4 +++ src/utests/lmx2820_solver_test.c | 14 ++++++++- 4 files changed, 92 insertions(+), 22 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 8c0accf8..e13d98e5 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -18,6 +18,8 @@ #include "sync_const.h" #include "../hw/lmk05318/lmk05318.h" +#include "../hw/lmx2820/lmx2820.h" +#include "../hw/def_lmx2820.h" // [0] 24bit 20Mhz AD5662 InRef::DAC_REF // [1] 24bit 20Mhz AD5662 ClockGen::GEN_DC @@ -122,6 +124,7 @@ struct dev_pe_sync { device_t base; lmk05318_state_t gen; + lmx2820_state_t lmx0, lmx1; }; enum dev_gpi { @@ -273,15 +276,27 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const bool use_dpll = false; + const uint64_t lmk_freq[8] = + { + 125000000, + 125000000, + 250000000, + 250000000, + 156250000, + 156250000, + 10000000, + 1 + }; + lmk05318_out_config_t lmk05318_outs_cfg[8]; - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 0, 125000000, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 1, 125000000, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 2, 250000000, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 3, 250000000, false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 4, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 5, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, 10000000, false, LVCMOS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, 1, false, LVCMOS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 0, lmk_freq[0], false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 1, lmk_freq[1], false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 2, lmk_freq[2], false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 3, lmk_freq[3], false, LVDS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 4, lmk_freq[4], false, OUT_OFF); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 5, lmk_freq[5], false, OUT_OFF); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, lmk_freq[6], false, LVCMOS); + res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, lmk_freq[7], false, LVCMOS); res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, use_dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); if(res) @@ -322,6 +337,21 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMK03518 outputs synced"); + // + //LMX2820 #1 setup + // + + const uint64_t lmx1_freq[] = + { + 580000000, + 145000000 + }; + + res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); + res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_INTEGER_MODE, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); + + return res; } diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 0f091a3d..a6612ff8 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -49,7 +49,7 @@ enum { #define OUT_DIV_DIAP_MAX (OUT_DIV_LOG2_MAX - OUT_DIV_LOG2_MIN + 1 + 1) //Pin3 bias capacitor, uF -#define C_BIAS 4.7f +#define C_BIAS 1.0f enum { PLL_N_MIN = 12, @@ -138,8 +138,25 @@ static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, un return -EINVAL; } +int lmx2820_sync(lmx2820_state_t* st) +{ + uint16_t r1; + + int res = lmx2820_spi_get(st, R1, &r1); + if(res) + return res; + + uint32_t regs[] = + { + MAKE_LMX2820_REG_WR(R1, (r1 & ~PHASE_SYNC_EN_MSK)), + MAKE_LMX2820_REG_WR(R1, (r1 | PHASE_SYNC_EN_MSK)), + MAKE_LMX2820_REG_WR(R1, (r1 & ~PHASE_SYNC_EN_MSK)), + }; -static int lmx2820_reset(lmx2820_state_t* st) + return lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); +} + +int lmx2820_reset(lmx2820_state_t* st) { memset(st, 0, sizeof(*st)); @@ -179,7 +196,7 @@ static int lmx2820_calibrate(lmx2820_state_t* st, bool set_flag) return lmx2820_spi_post(st, ®, 1); } -static int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) +int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) { int res = 0; unsigned elapsed = 0; @@ -277,7 +294,7 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ MAKE_LMX2820_R19(0x109, TEMPSENSE_EN_ENABLED, 0x0), //enable temperature sensor }; - res = lmx2820_spi_post(st, regs, sizeof(regs)); + res = lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); @@ -914,7 +931,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_DISABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) }; - res = lmx2820_spi_post(st, regs, sizeof(regs)); + res = lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); @@ -931,6 +948,20 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned return res; } + res = lmx2820_wait_pll_lock(st, 10000); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_wait_pll_lock() failed, err:%d", res); + return res; + } + + res = lmx2820_sync(st); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_sync() failed, err:%d", res); + return res; + } + if(use_instcal) { res = lmx2820_calibrate(st, false); @@ -941,13 +972,6 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned } } - res = lmx2820_wait_pll_lock(st, 10000); - if(res) - { - USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_wait_pll_lock() failed, err:%d", res); - return res; - } - return 0; } @@ -1008,7 +1032,7 @@ int lmx2820_tune_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb) MAKE_LMX2820_REG_WR(R0, r0) }; - res = lmx2820_spi_post(st, regs, sizeof(regs)); + res = lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index 2fd6f784..a50a6161 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -61,5 +61,9 @@ int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status); int lmx2820_tune(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb); int lmx2820_instant_calibration_init(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult); int lmx2820_tune_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb); +int lmx2820_sync(lmx2820_state_t* st); +int lmx2820_reset(lmx2820_state_t* st); +int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout); + #endif // LMX2820_H diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index f1dd4b21..708f2df6 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -148,6 +148,16 @@ START_TEST(lmx2820_solver_test12_instcal) ck_assert_int_eq( res, 0 ); } +START_TEST(lmx2820_solver_test13_pesync) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 0; + uint64_t out_freq1 = 580000000ull; + uint64_t out_freq2 = out_freq1 >> 2; + + int res = lmx2820_solver(&st, osc_in, 0, 0, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} Suite * lmx2820_solver_suite(void) { @@ -158,7 +168,7 @@ Suite * lmx2820_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - +/* tcase_add_test(tc_core, lmx2820_solver_test1); tcase_add_test(tc_core, lmx2820_solver_test2); tcase_add_test(tc_core, lmx2820_solver_test3); @@ -171,6 +181,8 @@ Suite * lmx2820_solver_suite(void) tcase_add_loop_test(tc_core, lmx2820_solver_test10_mash_order, 0, 4); tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 0, 4); tcase_add_test(tc_core, lmx2820_solver_test12_instcal); +*/ + tcase_add_test(tc_core, lmx2820_solver_test13_pesync); suite_add_tcase(s, tc_core); return s; From c070e7986898d1a14cc85af7327fc79ff5619726 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 18:51:34 +0300 Subject: [PATCH 065/397] add logging --- src/lib/device/pe_sync/pe_sync.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index e13d98e5..a2d6f778 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -349,8 +349,12 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_INTEGER_MODE, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); - USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); + if(!res) + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); + lmx2820_stats_t lmxstatus; + lmx2820_read_status(&d->lmx1, &lmxstatus); //just for logging + // return res; } From 9ad1e86db8b41f8f291c9c9d98df725aae9bd28d Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 18:58:34 +0300 Subject: [PATCH 066/397] fix memset --- src/lib/hw/lmx2820/lmx2820.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index a6612ff8..49443032 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -158,8 +158,6 @@ int lmx2820_sync(lmx2820_state_t* st) int lmx2820_reset(lmx2820_state_t* st) { - memset(st, 0, sizeof(*st)); - uint16_t r0; int res = lmx2820_spi_get(st, R0, &r0); @@ -280,6 +278,8 @@ int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status) int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st) { + memset(st, 0, sizeof(*st)); + st->dev = dev; st->subdev = subdev; st->lsaddr = lsaddr; From 43025c1121855c3164af637f0dc1853d2fa7e1b5 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 19:53:42 +0300 Subject: [PATCH 067/397] fix mash order --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmx2820/lmx2820.c | 6 ++++++ src/utests/lmx2820_solver_test.c | 29 +++++++++++++---------------- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index a2d6f778..54b7e601 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -348,7 +348,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); - res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_INTEGER_MODE, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); + res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_SECOND_ORDER, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); if(!res) USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 49443032..41324b01 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -347,6 +347,12 @@ static int lmx2820_tune_vco(lmx2820_state_t* st, uint64_t vco) double pll_frac = n_total - pll_n; USDR_LOG("2820", USDR_LOG_DEBUG, "PLL_N:%u PLL_FRAC:%.8f", pll_n, pll_frac); + if(pll_n != n_total && settings->mash_order == MASH_ORDER_INTEGER_MODE) + { + USDR_LOG("2820", USDR_LOG_ERROR, "PLL frac=%.8f, MASH_ORDER_INTEGER_MODE is inapplicable", pll_frac); + return -EINVAL; + } + const unsigned pll_r_div = settings->pll_r * settings->pll_r_pre; uint64_t pll_den64 = settings->fpd * pll_r_div; uint64_t pll_num64 = (uint64_t)(pll_frac * pll_den64 + 0.5); diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index 708f2df6..71bff0b4 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -25,7 +25,7 @@ START_TEST(lmx2820_solver_test1) START_TEST(lmx2820_solver_test2) { const uint64_t osc_in = 1400000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 45000000; uint64_t out_freq2 = out_freq1; @@ -47,7 +47,7 @@ START_TEST(lmx2820_solver_test3) START_TEST(lmx2820_solver_test4) { const uint64_t osc_in = 1400000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 22600000000ull; uint64_t out_freq2 = out_freq1; @@ -58,7 +58,7 @@ START_TEST(lmx2820_solver_test4) START_TEST(lmx2820_solver_test5) { const uint64_t osc_in = 250000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 5600000000ull; uint64_t out_freq2 = out_freq1 >> 3; @@ -69,7 +69,7 @@ START_TEST(lmx2820_solver_test5) START_TEST(lmx2820_solver_test6) { const uint64_t osc_in = 250000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 5600000000ull; uint64_t out_freq2 = out_freq1 << 1; @@ -80,7 +80,7 @@ START_TEST(lmx2820_solver_test6) START_TEST(lmx2820_solver_test7) { const uint64_t osc_in = 250000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 5800000000ull; uint64_t out_freq2 = out_freq1 << 1; @@ -91,7 +91,7 @@ START_TEST(lmx2820_solver_test7) START_TEST(lmx2820_solver_test8) { const uint64_t osc_in = 250000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 2000098000ull; uint64_t out_freq2 = out_freq1 >> 4; @@ -102,7 +102,7 @@ START_TEST(lmx2820_solver_test8) START_TEST(lmx2820_solver_test9_force_mult) { const uint64_t osc_in = 250000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 20000988000ull; uint64_t out_freq2 = out_freq1 >> 4; @@ -113,7 +113,6 @@ START_TEST(lmx2820_solver_test9_force_mult) START_TEST(lmx2820_solver_test10_mash_order) { const uint64_t osc_in = 250000000ull; - const int mash_order = 0; uint64_t out_freq1 = 5600000000ull; uint64_t out_freq2 = out_freq1 >> 3; @@ -124,7 +123,6 @@ START_TEST(lmx2820_solver_test10_mash_order) START_TEST(lmx2820_solver_test11_mash_order) { const uint64_t osc_in = 1400000000ull; - const int mash_order = 0; uint64_t out_freq1 = 45000000; uint64_t out_freq2 = out_freq1; @@ -139,7 +137,7 @@ START_TEST(lmx2820_solver_test12_instcal) uint64_t out_freq1 = 45000000ull << 8; uint64_t out_freq2 = out_freq1 >> 3; - int res = lmx2820_solver(&st, osc_in, 0, 0, 5650000000ull, 5650000000ull); + int res = lmx2820_solver(&st, osc_in, 2, 0, 5650000000ull, 5650000000ull); ck_assert_int_eq( res, 0 ); fprintf(stderr, "Calibrating for INSTCAL, fixing at FPD:%.2f\n", st.lmx2820_input_chain.fpd); @@ -151,11 +149,11 @@ START_TEST(lmx2820_solver_test12_instcal) START_TEST(lmx2820_solver_test13_pesync) { const uint64_t osc_in = 250000000ull; - const int mash_order = 0; + const int mash_order = 2; uint64_t out_freq1 = 580000000ull; uint64_t out_freq2 = out_freq1 >> 2; - int res = lmx2820_solver(&st, osc_in, 0, 0, out_freq1, out_freq2); + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } @@ -168,7 +166,7 @@ Suite * lmx2820_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); -/* + tcase_add_test(tc_core, lmx2820_solver_test1); tcase_add_test(tc_core, lmx2820_solver_test2); tcase_add_test(tc_core, lmx2820_solver_test3); @@ -178,10 +176,9 @@ Suite * lmx2820_solver_suite(void) tcase_add_test(tc_core, lmx2820_solver_test7); tcase_add_test(tc_core, lmx2820_solver_test8); tcase_add_loop_test(tc_core, lmx2820_solver_test9_force_mult, 3, 8); - tcase_add_loop_test(tc_core, lmx2820_solver_test10_mash_order, 0, 4); - tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 0, 4); + tcase_add_loop_test(tc_core, lmx2820_solver_test10_mash_order, 1, 4); + tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 1, 4); tcase_add_test(tc_core, lmx2820_solver_test12_instcal); -*/ tcase_add_test(tc_core, lmx2820_solver_test13_pesync); suite_add_tcase(s, tc_core); From 79599aa976f6825ba178bbebbff3f8e4bad520ff Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 20:46:06 +0300 Subject: [PATCH 068/397] add lmx2820 dump for testing --- src/lib/device/pe_sync/pe_sync.c | 17 ++++ src/lib/hw/lmx2820/lmx2820.c | 30 ++++++- src/lib/hw/lmx2820/lmx2820.h | 2 + src/lib/hw/lmx2820/lmx2820_dump.h | 133 ++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 src/lib/hw/lmx2820/lmx2820_dump.h diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 54b7e601..95b2ca4f 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -348,10 +348,27 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); +#if 0 res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_SECOND_ORDER, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); if(!res) USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); +#else + res = res ? res : lmx2820_loaddump(&d->lmx1); + usleep(1000); + res = res ? res : lmx2820_wait_pll_lock(&d->lmx1, 10000); + if(res) + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX2820 not locked!"); + else + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 locked OK"); + + res = res ? res : lmx2820_sync(&d->lmx1); + if(res) + USDR_LOG("SYNC", USDR_LOG_ERROR, "lmx2820_sync() failed, err:%d", res); + else + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 synced OK"); + +#endif lmx2820_stats_t lmxstatus; lmx2820_read_status(&d->lmx1, &lmxstatus); //just for logging // diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 41324b01..c1b73f8e 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -11,6 +11,8 @@ #include #include "../cal/opt_func.h" +#include "lmx2820_dump.h" + enum { OSC_IN_MIN = 5000000ull, @@ -88,6 +90,14 @@ static uint64_t FPD_MAX[MASH_ORDER_THIRD_ORDER + 1] = static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count) { int res; + + for (unsigned i = 0; i < count; i++) + { + uint8_t rn = regs[i] >> 16; + uint16_t rv = (uint16_t)regs[i]; + USDR_LOG("2820", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%x02) -> %0x04 [0x%x06]", i, rn, rn, rv, regs[i]); + } + for (unsigned i = 0; i < count; i++) { res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); if (res) @@ -276,6 +286,20 @@ int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status) return 0; } +int lmx2820_loaddump(lmx2820_state_t* st) +{ + int res = lmx2820_spi_post(st, lmx2820_rom_test, SIZEOF_ARRAY(lmx2820_rom_test)); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_loaddump() err:%d", res); + } + else + { + USDR_LOG("2820", USDR_LOG_DEBUG, "lmx2820_loaddump() OK"); + } + return res; +} + int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st) { memset(st, 0, sizeof(*st)); @@ -287,7 +311,7 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ int res = lmx2820_reset(st); if(res) return res; - +/* //this list is incompleted uint32_t regs[] = { @@ -300,8 +324,8 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); return res; } - - usleep(10); +*/ + usleep(1000); lmx2820_stats_t status; res = lmx2820_read_status(st, &status); diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index a50a6161..959d8e30 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -65,5 +65,7 @@ int lmx2820_sync(lmx2820_state_t* st); int lmx2820_reset(lmx2820_state_t* st); int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout); +int lmx2820_loaddump(lmx2820_state_t* st); + #endif // LMX2820_H diff --git a/src/lib/hw/lmx2820/lmx2820_dump.h b/src/lib/hw/lmx2820/lmx2820_dump.h new file mode 100644 index 00000000..793d7d1d --- /dev/null +++ b/src/lib/hw/lmx2820/lmx2820_dump.h @@ -0,0 +1,133 @@ +#ifndef LMX2820_DUMP_H +#define LMX2820_DUMP_H + +#include + +static uint32_t lmx2820_rom_test[] = +{ + /*R122*/ 0x7A0000, + /*R121*/ 0x790000, + /*R120*/ 0x780000, + /*R119*/ 0x770000, + /*R118*/ 0x760000, + /*R117*/ 0x750000, + /*R116*/ 0x740000, + /*R115*/ 0x730000, + /*R114*/ 0x720000, + /*R113*/ 0x710000, + /*R112*/ 0x70FFFF, + /*R111*/ 0x6F0000, + /*R110*/ 0x6E001F, + /*R109*/ 0x6D0000, + /*R108*/ 0x6C0000, + /*R107*/ 0x6B0000, + /*R106*/ 0x6A0000, + /*R105*/ 0x69000A, + /*R104*/ 0x680014, + /*R103*/ 0x670014, + /*R102*/ 0x660028, + /*R101*/ 0x6503E8, + /*R100*/ 0x640533, + /*R99*/ 0x6319B9, + /*R98*/ 0x621C80, + /*R97*/ 0x610000, + /*R96*/ 0x6017F8, + /*R95*/ 0x5F0000, + /*R94*/ 0x5E0000, + /*R93*/ 0x5D1000, + /*R92*/ 0x5C0000, + /*R91*/ 0x5B0000, + /*R90*/ 0x5A0000, + /*R89*/ 0x590000, + /*R88*/ 0x5803FF, + /*R87*/ 0x57FF00, + /*R86*/ 0x560040, + /*R85*/ 0x550000, + /*R84*/ 0x540040, + /*R83*/ 0x530F00, + /*R82*/ 0x520000, + /*R81*/ 0x510000, + /*R80*/ 0x5001C0, + /*R79*/ 0x4F000E, + /*R78*/ 0x4E0000, + /*R77*/ 0x4D0608, + /*R76*/ 0x4C0000, + /*R75*/ 0x4B0000, + /*R74*/ 0x4A0000, + /*R73*/ 0x490000, + /*R72*/ 0x480000, + /*R71*/ 0x470000, + /*R70*/ 0x46000E, + /*R69*/ 0x450011, + /*R68*/ 0x440020, + /*R67*/ 0x431000, + /*R66*/ 0x42003F, + /*R65*/ 0x410000, + /*R64*/ 0x400080, + /*R63*/ 0x3FC350, + /*R62*/ 0x3E0000, + /*R61*/ 0x3D03E8, + /*R60*/ 0x3C01F4, + /*R59*/ 0x3B1388, + /*R58*/ 0x3A0000, + /*R57*/ 0x390001, + /*R56*/ 0x380001, + /*R55*/ 0x370002, + /*R54*/ 0x360000, + /*R53*/ 0x350000, + /*R52*/ 0x340000, + /*R51*/ 0x33203F, + /*R50*/ 0x320080, + /*R49*/ 0x310000, + /*R48*/ 0x304180, + /*R47*/ 0x2F0300, + /*R46*/ 0x2E0300, + /*R45*/ 0x2D51EC, + /*R44*/ 0x2C1EB8, + /*R43*/ 0x2B0003, + /*R42*/ 0x2A0000, + /*R41*/ 0x290000, + /*R40*/ 0x280000, + /*R39*/ 0x270019, + /*R38*/ 0x260000, + /*R37*/ 0x250500, + /*R36*/ 0x240025, + /*R35*/ 0x233100, + /*R34*/ 0x220010, + /*R33*/ 0x210000, + /*R32*/ 0x201AC1, + /*R31*/ 0x1F0401, + /*R30*/ 0x1EB18C, + /*R29*/ 0x1D318C, + /*R28*/ 0x1C0639, + /*R27*/ 0x1B8001, + /*R26*/ 0x1A0DB0, + /*R25*/ 0x190624, + /*R24*/ 0x180E34, + /*R23*/ 0x171102, + /*R22*/ 0x16E2BF, + /*R21*/ 0x151C64, + /*R20*/ 0x14272C, + /*R19*/ 0x132120, + /*R18*/ 0x120000, + /*R17*/ 0x1115C0, + /*R16*/ 0x10171C, + /*R15*/ 0x0F2001, + /*R14*/ 0x0E3002, + /*R13*/ 0x0D0038, + /*R12*/ 0x0C0408, + /*R11*/ 0x0B0612, + /*R10*/ 0x0A0000, + /*R9*/ 0x090005, + /*R8*/ 0x08C802, + /*R7*/ 0x070000, + /*R6*/ 0x060A43, + /*R5*/ 0x050032, + /*R4*/ 0x044204, + /*R3*/ 0x030041, + /*R2*/ 0x0291F4, + /*R1*/ 0x0157A2, + /*R0*/ 0x006670, +}; + +#endif // LMX2820_DUMP_H From 9e942f5623276db06ebfc2f5daefaad2887dc478 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 20:49:48 +0300 Subject: [PATCH 069/397] llog fmt fix --- src/lib/hw/lmx2820/lmx2820.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index c1b73f8e..ae069754 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -95,7 +95,7 @@ static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count { uint8_t rn = regs[i] >> 16; uint16_t rv = (uint16_t)regs[i]; - USDR_LOG("2820", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%x02) -> %0x04 [0x%x06]", i, rn, rn, rv, regs[i]); + USDR_LOG("2820", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%02x) -> 0x%04x [0x%06x]", i, rn, rn, rv, regs[i]); } for (unsigned i = 0; i < count; i++) { From 0976ee7bce76560f71373f7431d90d7fa38e3025 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 22:21:21 +0300 Subject: [PATCH 070/397] comment out lmx2820 reset + fix for osc_2x detection --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmx2820/lmx2820.c | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 95b2ca4f..64ffe901 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -348,7 +348,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); -#if 0 +#if 1 res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_SECOND_ORDER, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); if(!res) USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index ae069754..60579c45 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -308,10 +308,14 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ st->subdev = subdev; st->lsaddr = lsaddr; - int res = lmx2820_reset(st); + int res; + +#if 0 + res = lmx2820_reset(st); if(res) return res; -/* +#endif + //this list is incompleted uint32_t regs[] = { @@ -324,8 +328,6 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); return res; } -*/ - usleep(1000); lmx2820_stats_t status; res = lmx2820_read_status(st, &status); @@ -440,7 +442,8 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, vco, min_n_total, max_n_total, fpd_min, fpd_max); bool need_mult = (fosc_in < fpd_min) || force_mult; - const bool osc_2x = (fosc_in <= OSC_IN_MAX_DBLR && !need_mult); + const bool osc_2x = (fosc_in <= OSC_IN_MAX_DBLR && (fosc_in << 1) <= fpd_max && !need_mult); + uint64_t osc_in = fosc_in * (osc_2x ? 2 : 1); USDR_LOG("2820", USDR_LOG_DEBUG, "OSC_2X:%d -> effective OSC_IN:%" PRIu64, osc_2x, osc_in); From 5811bcf1ba5f058eedb7b1ebc768a4b9ae2c39c4 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 7 Apr 2025 23:01:32 +0300 Subject: [PATCH 071/397] try to fix lmx2820 reset --- src/lib/device/pe_sync/pe_sync.c | 16 +++++++++++----- src/lib/hw/lmx2820/lmx2820.c | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 64ffe901..349dcdca 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -326,7 +326,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) { - USDR_LOG("SYNC", USDR_LOG_WARNING, "LMK03518 PLLs not locked during specified timeout"); + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 PLLs not locked during specified timeout"); return res; } @@ -343,15 +343,13 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const uint64_t lmx1_freq[] = { - 580000000, - 145000000 + 60000000, + 60000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); #if 1 res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_SECOND_ORDER, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); - if(!res) - USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); #else res = res ? res : lmx2820_loaddump(&d->lmx1); usleep(1000); @@ -371,6 +369,14 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const #endif lmx2820_stats_t lmxstatus; lmx2820_read_status(&d->lmx1, &lmxstatus); //just for logging + + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX2820 PLL not locked during specified timeout"); + return res; + } + + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); // return res; diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 60579c45..156629c6 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -174,11 +174,13 @@ int lmx2820_reset(lmx2820_state_t* st) if(res) return res; - r0 |= (uint16_t)1 << RESET_OFF; - - uint32_t reg = MAKE_LMX2820_REG_WR(R0, r0); + uint32_t regs[] = + { + MAKE_LMX2820_REG_WR(R0, r0 | RESET_MSK), + MAKE_LMX2820_REG_WR(R0, r0 & ~RESET_MSK) + }; - res = lmx2820_spi_post(st, ®, 1); + res = lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) return res; @@ -195,9 +197,9 @@ static int lmx2820_calibrate(lmx2820_state_t* st, bool set_flag) return res; if(set_flag) - r0 |= (uint16_t)1 << FCAL_EN_OFF; + r0 |= FCAL_EN_MSK; else - r0 &= ~((uint16_t)1 << FCAL_EN_OFF); + r0 &= ~FCAL_EN_MSK; uint32_t reg = MAKE_LMX2820_REG_WR(R0, r0); @@ -310,11 +312,11 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ int res; -#if 0 res = lmx2820_reset(st); if(res) return res; -#endif + + usleep(2); //reset takes less 1 us. //this list is incompleted uint32_t regs[] = From 33d6482e07e986718b0536750fff1b2115c6c3f7 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 8 Apr 2025 20:42:26 +0300 Subject: [PATCH 072/397] skip reset --- src/lib/hw/lmx2820/lmx2820.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 156629c6..60cb0a3a 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -166,7 +166,14 @@ int lmx2820_sync(lmx2820_state_t* st) return lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); } +#define LMX2820_RESET_SKIP + int lmx2820_reset(lmx2820_state_t* st) +#ifdef LMX2820_RESET_SKIP +{ + return 0; +} +#else { uint16_t r0; @@ -187,6 +194,7 @@ int lmx2820_reset(lmx2820_state_t* st) usleep(5); //reset takes <1us return 0; } +#endif static int lmx2820_calibrate(lmx2820_state_t* st, bool set_flag) { From abd325199ddf8d160bfd379e9107cdf9a0176950 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 9 Apr 2025 15:50:00 +0300 Subject: [PATCH 073/397] add LMX1214 support (need testing) --- src/lib/device/pe_sync/pe_sync.c | 36 ++- src/lib/hw/lmx1214/lmx1214.c | 366 +++++++++++++++++++++++++++++++ src/lib/hw/lmx1214/lmx1214.h | 45 ++++ src/lib/hw/lmx1214/lmx1214.yaml | 14 +- src/utests/CMakeLists.txt | 1 + src/utests/lmx1214_solver_test.c | 92 ++++++++ src/utests/lmx2820_solver_test.c | 4 +- src/utests/test_suite.c | 4 +- 8 files changed, 551 insertions(+), 11 deletions(-) create mode 100644 src/utests/lmx1214_solver_test.c diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 349dcdca..a8e3c01c 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -19,7 +19,7 @@ #include "sync_const.h" #include "../hw/lmk05318/lmk05318.h" #include "../hw/lmx2820/lmx2820.h" -#include "../hw/def_lmx2820.h" +#include "../hw/lmx1214/lmx1214.h" // [0] 24bit 20Mhz AD5662 InRef::DAC_REF // [1] 24bit 20Mhz AD5662 ClockGen::GEN_DC @@ -125,6 +125,8 @@ struct dev_pe_sync { lmk05318_state_t gen; lmx2820_state_t lmx0, lmx1; + lmx1214_state_t lodistr; + }; enum dev_gpi { @@ -343,13 +345,13 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const uint64_t lmx1_freq[] = { - 60000000, - 60000000 + 320000000, + 160000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); #if 1 - res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], MASH_ORDER_SECOND_ORDER, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); + res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], 2 /*mash order 2*/, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); #else res = res ? res : lmx2820_loaddump(&d->lmx1); usleep(1000); @@ -379,6 +381,32 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); // + // + //LMX1214 setup + // + + const uint64_t ld_clkout = 160000000; + bool ld_en[LMX1214_OUT_CNT] = {1,0,1,0}; + lmx1214_auxclkout_cfg_t ld_aux; + ld_aux.enable = 1; + ld_aux.fmt = LMX2124_FMT_LVDS; + ld_aux.freq = 8000000; + + res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); + res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*dry run*/); + + float lmx1214_tempval; + lmx1214_get_temperature(&d->lodistr, &lmx1214_tempval); //just for logging + + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX1214 failed to initialize, res:%d", res); + return res; + } + + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1214 initialized"); + // + return res; } diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index a6726a80..8f41e367 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -1,6 +1,372 @@ // Copyright (c) 2025 Wavelet Lab // SPDX-License-Identifier: MIT +#include +#include + #include "def_lmx1214.h" #include "lmx1214.h" #include "usdr_logging.h" + +enum +{ + CLKIN_MIN = 300000000ull, + CLKIN_MAX_DIV = 12800000000ull, + CLKIN_MAX_BUF = 18000000000ull, + + SYNC_IN_MIN = CLKIN_MIN, + SYNC_IN_MAX = CLKIN_MAX_DIV, + + CLKOUT_MIN_DIV = 150000000ull, + CLKOUT_MIN_BUF = CLKIN_MIN, + + CLKOUT_MAX_DIV_WO_SYNC = 8000000000ull, + CLKOUT_MAX_DIV_SYNC = 6400000000ull, + CLKOUT_MAX_BUF = CLKIN_MAX_BUF, + + AUXCLKOUT_MIN = 1000000ull, + AUXCLKOUT_MAX = 800000000ull, + AUXCLK_DIV_INP_MAX = 3200000000ull, + + CLK_DIV_MIN = 2, + CLK_DIV_MAX = 8, + + AUXCLK_DIV_MIN = 2, + AUXCLK_DIV_MAX = 1023, +}; + +static int lmx1214_print_registers(uint32_t* regs, unsigned count) +{ + for (unsigned i = 0; i < count; i++) + { + uint8_t rn = regs[i] >> 16; + uint16_t rv = (uint16_t)regs[i]; + USDR_LOG("1214", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%02x) -> 0x%04x [0x%06x]", i, rn, rn, rv, regs[i]); + } + + return 0; +} + +static int lmx1214_spi_post(lmx1214_state_t* obj, uint32_t* regs, unsigned count) +{ + int res; + lmx1214_print_registers(regs, count); + + for (unsigned i = 0; i < count; i++) { + res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); + if (res) + return res; + + USDR_LOG("1214", USDR_LOG_NOTE, "[%d/%d] reg wr %08x\n", i, count, regs[i]); + } + + return 0; +} + +static int lmx1214_spi_get(lmx1214_state_t* obj, uint16_t addr, uint16_t* out) +{ + uint32_t v; + int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, MAKE_LMX1214_REG_RD((uint32_t)addr), &v); + if (res) + return res; + + USDR_LOG("1214", USDR_LOG_NOTE, " reg rd %04x => %08x\n", addr, v); + *out = v; + return 0; +} + +int lmx1214_get_temperature(lmx1214_state_t* st, float* value) +{ + if(!value) + return -EINVAL; + + uint16_t r24; + + int res = lmx1214_spi_get(st, R24, &r24); + if(res) + return res; + + int16_t code = (r24 & RB_TS_MSK) >> RB_TS_OFF; + *value = 0.65f * code - 351.0f; + + return 0; +} + +static int lmx1214_reset_main_divider(lmx1214_state_t* st, bool set_flag) +{ + uint16_t r25; + + int res = lmx1214_spi_get(st, R25, &r25); + if(res) + return res; + + uint32_t reg = MAKE_LMX1214_REG_WR(R25, set_flag ? (r25 | CLK_DIV_RST_MSK) : (r25 & ~CLK_DIV_RST_MSK)); + return lmx1214_spi_post(st, ®, 1); +} + +int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_t* st) +{ + memset(st, 0, sizeof(*st)); + + st->dev = dev; + st->subdev = subdev; + st->lsaddr = lsaddr; + + int res; + uint32_t regs[] = + { + MAKE_LMX1214_R79(0, 0x5), //magic R79->0x5 (see manual) + MAKE_LMX1214_R24(0, 0, 0, 1), //temp sensor + MAKE_LMX1214_R23(1, 1, 0, 0), //temp sensor + }; + + res = lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + { + USDR_LOG("1214", USDR_LOG_ERROR, "Registers set lmx1214_spi_post() failed, err:%d", res); + return res; + } + + usleep(10); + + float tempval; + res = lmx1214_get_temperature(st, &tempval); + if(res) + { + USDR_LOG("1214", USDR_LOG_ERROR, "Registers set lmx1214_get_temperature() failed, err:%d", res); + return res; + } + + USDR_LOG("1214", USDR_LOG_DEBUG, "Create OK"); + return 0; +} + +int lmx1214_destroy(lmx1214_state_t* st) +{ + USDR_LOG("1214", USDR_LOG_DEBUG, "Destroy OK"); + return 0; +} + +static int lmx1214_solver_prevalidate(uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux) +{ + if(in < CLKIN_MIN || in > CLKIN_MAX_BUF) + { + USDR_LOG("1214", USDR_LOG_ERROR, "CLKIN:%" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", in, (uint64_t)CLKIN_MIN, (uint64_t)CLKIN_MAX_BUF); + return -EINVAL; + } + + const bool buffer_mode = (out == in); + if(!buffer_mode && in > CLKIN_MAX_DIV) + { + USDR_LOG("1214", USDR_LOG_ERROR, "CLKIN:%" PRIu64 " too high (>%" PRIu64 ") [BUFFERMODE:%u]", in, (uint64_t)CLKIN_MAX_DIV, buffer_mode); + return -EINVAL; + } + + const uint64_t out_min = (buffer_mode ? CLKOUT_MIN_BUF : CLKOUT_MIN_DIV); + const uint64_t out_max = (buffer_mode ? CLKOUT_MAX_BUF : CLKOUT_MAX_DIV_SYNC); + + if(out < out_min || out > out_max) + { + USDR_LOG("1214", USDR_LOG_ERROR, "CLKOUT:%" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "] [BUFFERMODE:%u]", out, out_min, out_max, buffer_mode); + return -EINVAL; + } + + if(aux->freq < AUXCLKOUT_MIN || aux->freq > AUXCLKOUT_MAX) + { + USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT:%" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", aux->freq, (uint64_t)AUXCLKOUT_MIN, (uint64_t)AUXCLKOUT_MAX); + return -EINVAL; + } + + switch(aux->fmt) + { + case LMX2124_FMT_LVDS: aux->fmt = AUXCLKOUT_FMT_LVDS; break; + case LMX2124_FMT_CML : aux->fmt = AUXCLKOUT_FMT_CML; break; + default: + { + USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT_FMT:%u is invalid", aux->fmt); + return -EINVAL; + } + } + + if(out_en[2] != out_en[3]) + { + USDR_LOG("1214", USDR_LOG_ERROR, "bad configuration, OUT_EN2 != OUT_EN3"); + return -EINVAL; + } + + return 0; +} + +static const char* lmx1214_decode_mux(uint8_t mux) +{ + switch(mux) + { + case CLK_MUX_BUFFER : return "CLK_MUX_BUFFER"; + case CLK_MUX_DIVIDER: return "CLK_MUX_DIVIDER"; + } + return "UNKNOWN"; +} + +static const char* lmx1214_decode_auxfmt(uint8_t fmt) +{ + switch(fmt) + { + case AUXCLKOUT_FMT_LVDS: return "LVDS"; + case AUXCLKOUT_FMT_CML : return "CML"; + } + return "UNKNOWN"; +} + +int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool dry_run) +{ + int res = lmx1214_solver_prevalidate(in, out, out_en, aux); + if(res) + return res; + + const bool buffer_mode = (out == in); + + unsigned clk_div; + uint8_t clk_mux; + + if(buffer_mode) + { + clk_mux = CLK_MUX_BUFFER; + clk_div = 1; //disabled + } + else + { + clk_mux = CLK_MUX_DIVIDER; + clk_div = in / out; + + if(clk_div < CLK_DIV_MIN || clk_div > CLK_DIV_MAX) + { + USDR_LOG("1214", USDR_LOG_ERROR, "CLK_DIV:%u out of range", clk_div); + return -EINVAL; + } + + if(in != out * clk_div) + { + USDR_LOG("1214", USDR_LOG_ERROR, "Cannot solve CLKOUT:%" PRIu64 " by int divider", out); + return -EINVAL; + } + } + + USDR_LOG("1214", USDR_LOG_DEBUG, "CLKIN:%" PRIu64 " CLKOUT:%" PRIu64 " CLK_DIV:%u MUX:%u [BUFFER_MODE:%u]", + in, out, clk_div, clk_mux, buffer_mode); + + + uint8_t auxclk_div_pre = AUXCLK_DIV_PRE_DIV4; + uint16_t auxclk_div = 0x20; + bool auxclk_div_byp = false; + + if(aux->enable) + { + uint8_t pre_div_min; + + if(in <= AUXCLK_DIV_INP_MAX) + pre_div_min = AUXCLK_DIV_PRE_DIV1; + else if(in <= ((uint64_t)AUXCLK_DIV_INP_MAX << 1)) + pre_div_min = AUXCLK_DIV_PRE_DIV2; + else + pre_div_min = AUXCLK_DIV_PRE_DIV4; + + bool found = false; + for(auxclk_div_pre = pre_div_min; auxclk_div_pre <= AUXCLK_DIV_PRE_DIV4; ++auxclk_div_pre) + { + if(auxclk_div_pre == AUXCLK_DIV_PRE_DIV4 - 1) + continue; + + uint64_t fmid = in / auxclk_div_pre; + if(in != fmid * auxclk_div_pre) + continue; + + if(fmid == aux->freq && auxclk_div_pre == AUXCLK_DIV_PRE_DIV1) + { + found = true; + auxclk_div_byp = true; + break; + } + + if(auxclk_div_pre == AUXCLK_DIV_PRE_DIV1) //cannot use pre_div==1 without bypassing div + continue; + + unsigned div = fmid / aux->freq; + if(fmid != aux->freq * div) + continue; + if(div < AUXCLK_DIV_MIN || div > AUXCLK_DIV_MAX) + continue; + + found = true; + auxclk_div = div; + break; + } + + if(!found) + { + USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT:%" PRIu64 " cannot be solved with LMX1214 divs", aux->freq); + return -EINVAL; + } + } + + //if we got here - the solution is found + st->clkin = in; + st->clk_mux = clk_mux; + st->clk_div = clk_div; + st->clkout = out; + for(unsigned i = 0; i < LMX1214_OUT_CNT; ++i) st->clkout_enabled[i] = out_en[i]; + st->auxclk_div_pre = auxclk_div_pre; + st->auxclk_div_byp = auxclk_div_byp; + st->auxclk_div = auxclk_div; + st->auxclkout = *aux; + + USDR_LOG("1214", USDR_LOG_INFO, "LMX1214 SOLUTION FOUND:"); + USDR_LOG("1214", USDR_LOG_INFO, "CLKIN:%" PRIu64 " CLK_DIV:%u CLKMUX:%s(%u) CLKOUT:%" PRIu64, + st->clkin, st->clk_div, lmx1214_decode_mux(st->clk_mux), st->clk_mux, st->clkout); + + if(st->auxclkout.enable) + USDR_LOG("1214", USDR_LOG_INFO, "AUXCLC_DIV_PRE:%u AUXCLK_DIV_BYP:%u AUXCLK_DIV:%u AUXCLKOUT:%" PRIu64 " AUXCLKOUT_FMT:%s(%u)", + st->auxclk_div_pre, st->auxclk_div_byp, st->auxclk_div, st->auxclkout.freq, + lmx1214_decode_auxfmt(st->auxclkout.fmt), st->auxclkout.fmt); + else + USDR_LOG("1214", USDR_LOG_INFO, "AUXCLKOUT:disabled"); + + //Setting registers + + res = dry_run ? 0 : lmx1214_reset_main_divider(st, true); + if(res) + { + USDR_LOG("1214", USDR_LOG_ERROR, "lmx1214_reset_main_divider(1) err:%d", res); + return res; + } + + uint32_t regs[] = + { + MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), + MAKE_LMX1214_R79(0, 0x5), + MAKE_LMX1214_R25(0x4, 0, st->clk_div - 1, st->clk_mux), + MAKE_LMX1214_R9 (0, 1, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), + MAKE_LMX1214_R8 (0, st->auxclk_div_pre, 0, (st->auxclkout.enable ? 1 : 0), 0, st->auxclkout.fmt), + MAKE_LMX1214_R3 (st->clkout_enabled[3] ? 1 : 0, + st->clkout_enabled[2] ? 1 : 0, + st->clkout_enabled[1] ? 1 : 0, + st->clkout_enabled[0] ? 1 : 0, + 0xF86//0xFE + ), + }; + + res = dry_run ? lmx1214_print_registers(regs, SIZEOF_ARRAY(regs)) : lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + { + USDR_LOG("1214", USDR_LOG_ERROR, "Registers set lmx1214_spi_post() failed, err:%d", res); + return res; + } + + res = dry_run ? 0 : lmx1214_reset_main_divider(st, false); + if(res) + { + USDR_LOG("1214", USDR_LOG_ERROR, "lmx1214_reset_main_divider(0) err:%d", res); + return res; + } + + return 0; +} diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index 6c03fb6a..8182b2bb 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -4,4 +4,49 @@ #ifndef LMX1214_H #define LMX1214_H +#include + +#define LMX1214_OUT_CNT 4 + +enum +{ + LMX2124_FMT_LVDS = 0, + LMX2124_FMT_CML = 2, +}; + +struct lmx1214_auxclkout_cfg +{ + uint64_t freq; + bool enable; + uint8_t fmt; +}; +typedef struct lmx1214_auxclkout_cfg lmx1214_auxclkout_cfg_t; + +struct lmx1214_state +{ + lldev_t dev; + unsigned subdev; + unsigned lsaddr; + + uint64_t clkin; + + uint8_t clk_mux; + uint8_t clk_div; + + uint8_t auxclk_div_pre; + uint16_t auxclk_div; + bool auxclk_div_byp; + + uint64_t clkout; + bool clkout_enabled[LMX1214_OUT_CNT]; + lmx1214_auxclkout_cfg_t auxclkout; +}; +typedef struct lmx1214_state lmx1214_state_t; + + +int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_t* st); +int lmx1214_destroy(lmx1214_state_t* st); +int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool dry_run); +int lmx1214_get_temperature(lmx1214_state_t* st, float* value); + #endif // LMX1214_H diff --git a/src/lib/hw/lmx1214/lmx1214.yaml b/src/lib/hw/lmx1214/lmx1214.yaml index f8726397..ad940865 100644 --- a/src/lib/hw/lmx1214/lmx1214.yaml +++ b/src/lib/hw/lmx1214/lmx1214.yaml @@ -3,11 +3,12 @@ revision: 0.0.1 processors: [ c ] bus: type: SPI - wr_mask: 0x80000000 + rd_mask: 0x800000 usdr_path: /debug/hw/lmx1214/*/reg -addr_width: 16 +addr_width: 8 data_width: 16 + pages: - name: Main regs: @@ -185,16 +186,21 @@ pages: opts: 0x0: LVDS 0x2: CML - - bits: '4:2' + - bits: '3:2' name: R8_UNDISCLOSED_0 mode: RW dflt: 0x0 desc: Program this field to 0x0. - - bits: 5 + - bits: 4 name: AUXCLKOUT_EN mode: RW dflt: 0x1 desc: Enables AUXCLK subsystem. + - bits: 5 + name: R8_UNDISCLOSED_5 + mode: RW + dflt: 0x0 + desc: Program this field to 0x0. - bits: '8:6' name: AUXCLK_DIV_PRE mode: RW diff --git a/src/utests/CMakeLists.txt b/src/utests/CMakeLists.txt index ad5c779b..fc21089a 100644 --- a/src/utests/CMakeLists.txt +++ b/src/utests/CMakeLists.txt @@ -14,6 +14,7 @@ set(TEST_SUIT_SRCS clockgen_test.c lmk05318_solver_test.c lmx2820_solver_test.c + lmx1214_solver_test.c ) include_directories(../lib/xdsp) diff --git a/src/utests/lmx1214_solver_test.c b/src/utests/lmx1214_solver_test.c new file mode 100644 index 00000000..c7d8a15a --- /dev/null +++ b/src/utests/lmx1214_solver_test.c @@ -0,0 +1,92 @@ +#include +#include +#include "lmx1214/lmx1214.h" + +static lmx1214_state_t st; + +static void setup() +{ + memset(&st, 0, sizeof(st)); +} + +static void teardown() {} + +START_TEST(lmx1214_solver_test1) +{ + const uint64_t osc_in = 600000000; + uint64_t out_freq = osc_in / 4; + bool en[4] = {1,1,1,1}; + + lmx1214_auxclkout_cfg_t aux; + aux.enable = 1; + aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.freq = osc_in / 16; + + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1214_solver_test2) +{ + const uint64_t osc_in = 640000000; + uint64_t out_freq = osc_in; + bool en[4] = {1,1,1,1}; + + lmx1214_auxclkout_cfg_t aux; + aux.enable = 1; + aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.freq = osc_in / 160; + + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1214_solver_test3) +{ + const uint64_t osc_in = 640000000; + uint64_t out_freq = osc_in; + bool en[4] = {1,1,1,1}; + + lmx1214_auxclkout_cfg_t aux; + aux.enable = 1; + aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.freq = osc_in; + + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1214_solver_test4_pesync) +{ + const uint64_t osc_in = 320000000; + uint64_t out_freq = osc_in / 2; + bool en[4] = {1,1,1,1}; + + lmx1214_auxclkout_cfg_t aux; + aux.enable = 1; + aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.freq = osc_in / 40; + + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + ck_assert_int_eq( res, 0 ); +} + +Suite * lmx1214_solver_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("lmx1214_solver"); + tc_core = tcase_create("HW"); + tcase_set_timeout(tc_core, 1); + tcase_add_checked_fixture(tc_core, setup, teardown); + + tcase_add_test(tc_core, lmx1214_solver_test1); + tcase_add_test(tc_core, lmx1214_solver_test2); + tcase_add_test(tc_core, lmx1214_solver_test3); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync); + + suite_add_tcase(s, tc_core); + return s; +} + diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index 71bff0b4..3e9bd7bd 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -150,8 +150,8 @@ START_TEST(lmx2820_solver_test13_pesync) { const uint64_t osc_in = 250000000ull; const int mash_order = 2; - uint64_t out_freq1 = 580000000ull; - uint64_t out_freq2 = out_freq1 >> 2; + uint64_t out_freq1 = 320000000ull; + uint64_t out_freq2 = 160000000ull; int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index 429190c1..1907bc42 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -13,6 +13,7 @@ Suite * trig_suite(void); Suite * clockgen_suite(void); Suite * lmk05318_solver_suite(void); Suite * lmx2820_solver_suite(void); +Suite * lmx1214_solver_suite(void); int main(int argc, char** argv) { @@ -33,8 +34,9 @@ int main(int argc, char** argv) srunner_add_suite(sr, clockgen_suite()); srunner_add_suite(sr, lmk05318_solver_suite()); srunner_add_suite(sr, lmx2820_solver_suite()); + srunner_add_suite(sr, lmx1214_solver_suite()); #else - sr = srunner_create(lmx2820_solver_suite()); + sr = srunner_create(lmx1214_solver_suite()); #endif srunner_set_fork_status (sr, CK_NOFORK); From 1c846f9d51dd5515c2f570b3f8bc86d66422567f Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 9 Apr 2025 16:25:16 +0300 Subject: [PATCH 074/397] extra logging --- src/lib/hw/lmx1214/lmx1214.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 8f41e367..52f4b7db 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -322,6 +322,8 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, USDR_LOG("1214", USDR_LOG_INFO, "LMX1214 SOLUTION FOUND:"); USDR_LOG("1214", USDR_LOG_INFO, "CLKIN:%" PRIu64 " CLK_DIV:%u CLKMUX:%s(%u) CLKOUT:%" PRIu64, st->clkin, st->clk_div, lmx1214_decode_mux(st->clk_mux), st->clk_mux, st->clkout); + USDR_LOG("1214", USDR_LOG_INFO, "CLKOUT enabled - OUT0:%u OUT1:%u OUT2:%u OUT3:%u", + st->clkout_enabled[0], st->clkout_enabled[1], st->clkout_enabled[2], st->clkout_enabled[3]); if(st->auxclkout.enable) USDR_LOG("1214", USDR_LOG_INFO, "AUXCLC_DIV_PRE:%u AUXCLK_DIV_BYP:%u AUXCLK_DIV:%u AUXCLKOUT:%" PRIu64 " AUXCLKOUT_FMT:%s(%u)", From 96900cecc2aa37dc118f2c29587a1062be1e5f47 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 9 Apr 2025 17:35:31 +0300 Subject: [PATCH 075/397] add lmx1214 test dump --- src/lib/device/pe_sync/pe_sync.c | 5 ++- src/lib/hw/lmx1214/lmx1214.c | 75 +++++++++++++++++++++++++++++-- src/lib/hw/lmx1214/lmx1214.h | 1 + src/lib/hw/lmx1214/lmx1214_dump.h | 30 +++++++++++++ 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 src/lib/hw/lmx1214/lmx1214_dump.h diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index a8e3c01c..34b6792f 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -386,15 +386,16 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // const uint64_t ld_clkout = 160000000; - bool ld_en[LMX1214_OUT_CNT] = {1,0,1,0}; + bool ld_en[LMX1214_OUT_CNT] = {1,0,1,1}; lmx1214_auxclkout_cfg_t ld_aux; ld_aux.enable = 1; ld_aux.fmt = LMX2124_FMT_LVDS; ld_aux.freq = 8000000; res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); +#if 0 res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*dry run*/); - +#endif float lmx1214_tempval; lmx1214_get_temperature(&d->lodistr, &lmx1214_tempval); //just for logging diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 52f4b7db..5d4abb36 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -8,6 +8,8 @@ #include "lmx1214.h" #include "usdr_logging.h" +#include "lmx1214_dump.h" + enum { CLKIN_MIN = 300000000ull, @@ -75,6 +77,38 @@ static int lmx1214_spi_get(lmx1214_state_t* obj, uint16_t addr, uint16_t* out) return 0; } +static int lmx1214_loaddump(lmx1214_state_t* st) +{ + int res = lmx1214_spi_post(st, lmx1214_rom_test, SIZEOF_ARRAY(lmx1214_rom_test)); + if(res) + { + USDR_LOG("2820", USDR_LOG_ERROR, "lmx1214_loaddump() err:%d", res); + } + else + { + USDR_LOG("2820", USDR_LOG_DEBUG, "lmx1214_loaddump() OK"); + } + return res; +} + +int lmx1214_sync_clr(lmx1214_state_t* st) +{ + uint16_t r15; + + int res = lmx1214_spi_get(st, R15, &r15); + if(res) + return res; + + uint32_t regs[] = + { + MAKE_LMX1214_REG_WR(R15, r15 & ~SYNC_CLR_MSK), + MAKE_LMX1214_REG_WR(R15, r15 | SYNC_CLR_MSK), + MAKE_LMX1214_REG_WR(R15, r15 & ~SYNC_CLR_MSK), + }; + + return lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs));; +} + int lmx1214_get_temperature(lmx1214_state_t* st, float* value) { if(!value) @@ -89,6 +123,7 @@ int lmx1214_get_temperature(lmx1214_state_t* st, float* value) int16_t code = (r24 & RB_TS_MSK) >> RB_TS_OFF; *value = 0.65f * code - 351.0f; + USDR_LOG("1214", USDR_LOG_DEBUG, "LMX1214 temperature sensor:%.2fC", *value); return 0; } @@ -107,12 +142,18 @@ static int lmx1214_reset_main_divider(lmx1214_state_t* st, bool set_flag) int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_t* st) { memset(st, 0, sizeof(*st)); + int res; st->dev = dev; st->subdev = subdev; st->lsaddr = lsaddr; - int res; +#if 1 + res = lmx1214_loaddump(st); + if(res) + return res; +#else + uint32_t regs[] = { MAKE_LMX1214_R79(0, 0x5), //magic R79->0x5 (see manual) @@ -126,8 +167,8 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ USDR_LOG("1214", USDR_LOG_ERROR, "Registers set lmx1214_spi_post() failed, err:%d", res); return res; } - - usleep(10); +#endif + usleep(100); float tempval; res = lmx1214_get_temperature(st, &tempval); @@ -341,11 +382,22 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, return res; } + uint8_t sync_dly_step = 0; + if(in >= 4500000000) + sync_dly_step = 3; + else if(in > 3100000000 && in <= 5700000000) + sync_dly_step = 2; + else if(in > 2400000000 && in <= 4700000000) + sync_dly_step = 1; + + USDR_LOG("1214", USDR_LOG_DEBUG, "CLKIN:%" PRIu64 " -> SYNC_DLY_STEP:%u", in, sync_dly_step); + uint32_t regs[] = { MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), MAKE_LMX1214_R79(0, 0x5), MAKE_LMX1214_R25(0x4, 0, st->clk_div - 1, st->clk_mux), + MAKE_LMX1214_R14(0, 1, 1, 0), //set CLKPOS_CAPTURE_EN MAKE_LMX1214_R9 (0, 1, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), MAKE_LMX1214_R8 (0, st->auxclk_div_pre, 0, (st->auxclkout.enable ? 1 : 0), 0, st->auxclkout.fmt), MAKE_LMX1214_R3 (st->clkout_enabled[3] ? 1 : 0, @@ -370,5 +422,22 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, return res; } + return 0; +} + +int lmx1214_windowing(lmx1214_state_t* st) +{ + int res; + uint16_t r11, r12; + + res = lmx1214_spi_get(st, R11, &r11); + res = res ? 0 : lmx1214_spi_get(st, R12, &r12); + if(res) + return res; + + uint32_t clkpos = ((uint32_t)r12 << 16) | r11; + //USDR_LOG(USDR_LOG_DEBUG, "CLKPOS:0b%b", clkpos); + + return 0; } diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index 8182b2bb..48f2b230 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -48,5 +48,6 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ int lmx1214_destroy(lmx1214_state_t* st); int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool dry_run); int lmx1214_get_temperature(lmx1214_state_t* st, float* value); +int lmx1214_sync_clr(lmx1214_state_t* st); #endif // LMX1214_H diff --git a/src/lib/hw/lmx1214/lmx1214_dump.h b/src/lib/hw/lmx1214/lmx1214_dump.h new file mode 100644 index 00000000..b54a345d --- /dev/null +++ b/src/lib/hw/lmx1214/lmx1214_dump.h @@ -0,0 +1,30 @@ +#ifndef LMX1214_DUMP_H +#define LMX1214_DUMP_H + +#include + +static uint32_t lmx1214_rom_test[] = +{ + /*R90*/ 0x5A0000, + /*R86*/ 0x560004, + /*R79*/ 0x4F0005, + /*R75*/ 0x4B0006, + /*R25*/ 0x19020A, + /*R24*/ 0x180001, + /*R23*/ 0x17E040, + /*R15*/ 0x0F0B01, + /*R14*/ 0x0E0002, + /*R13*/ 0x0D0003, + /*R12*/ 0x0C0000, + /*R11*/ 0x0B0000, + /*R9*/ 0x092014, + /*R8*/ 0x080090, + /*R7*/ 0x07543F, + /*R5*/ 0x0536F6, + /*R4*/ 0x0436FF, + /*R3*/ 0x03FF86, + /*R2*/ 0x020223, + /*R0*/ 0x000000, +}; + +#endif // LMX1214_DUMP_H From 119e04472d29dabbb2ef7f3bee1aa2d806f50667 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 10 Apr 2025 16:21:07 +0300 Subject: [PATCH 076/397] several minor changes + print all regs in create() --- src/lib/hw/lmx1214/lmx1214.c | 52 ++++++++++++++++++++++++++++++-- src/utests/lmx1214_solver_test.c | 6 ++-- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 5d4abb36..27de257a 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -77,6 +77,44 @@ static int lmx1214_spi_get(lmx1214_state_t* obj, uint16_t addr, uint16_t* out) return 0; } +static int lmx1214_read_all_regs(lmx1214_state_t* st) +{ + uint8_t regs[] = + { + R0, + R2, + R3, + R4, + R5, + R7, + R8, + R9, + R11, + R12, + R13, + R14, + R15, + R23, + R24, + R25, + R75, + R79, + R86, + R90, + }; + + for(unsigned i = 0; i < SIZEOF_ARRAY(regs); ++i) + { + uint16_t regval; + int res = lmx1214_spi_get(st, regs[i], ®val); + if(res) + return res; + USDR_LOG("2820", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", i, regval); + } + + return 0; +} + static int lmx1214_loaddump(lmx1214_state_t* st) { int res = lmx1214_spi_post(st, lmx1214_rom_test, SIZEOF_ARRAY(lmx1214_rom_test)); @@ -168,16 +206,26 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ return res; } #endif - usleep(100); + usleep(100000); float tempval; res = lmx1214_get_temperature(st, &tempval); if(res) { - USDR_LOG("1214", USDR_LOG_ERROR, "Registers set lmx1214_get_temperature() failed, err:%d", res); + USDR_LOG("1214", USDR_LOG_ERROR, "lmx1214_get_temperature() failed, err:%d", res); return res; } + uint16_t r75; + res = lmx1214_spi_get(st, R75, &r75); + if(res) + return res; + USDR_LOG("1214", USDR_LOG_DEBUG, "R75 status byte:0x%04x", r75); + + res = lmx1214_read_all_regs(st); + if(res) + return res; + USDR_LOG("1214", USDR_LOG_DEBUG, "Create OK"); return 0; } diff --git a/src/utests/lmx1214_solver_test.c b/src/utests/lmx1214_solver_test.c index c7d8a15a..5fe79e1b 100644 --- a/src/utests/lmx1214_solver_test.c +++ b/src/utests/lmx1214_solver_test.c @@ -58,14 +58,14 @@ START_TEST(lmx1214_solver_test3) START_TEST(lmx1214_solver_test4_pesync) { - const uint64_t osc_in = 320000000; - uint64_t out_freq = osc_in / 2; + const uint64_t osc_in = 640000000; + uint64_t out_freq = osc_in; bool en[4] = {1,1,1,1}; lmx1214_auxclkout_cfg_t aux; aux.enable = 1; aux.fmt = LMX2124_FMT_LVDS; //LVDS - aux.freq = osc_in / 40; + aux.freq = osc_in; int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); ck_assert_int_eq( res, 0 ); From 3fe421e16d25e33d4e06609a77ee0ed8199c426f Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 10 Apr 2025 18:01:15 +0300 Subject: [PATCH 077/397] lmx1204 first stub --- src/lib/device/pe_sync/pe_sync.c | 25 ++++- src/lib/hw/lmx1204/lmx1204.c | 152 +++++++++++++++++++++++++++++++ src/lib/hw/lmx1204/lmx1204.h | 16 ++++ src/lib/hw/lmx1204/lmx1204.yaml | 4 +- src/lib/hw/lmx1214/lmx1214.c | 2 +- 5 files changed, 191 insertions(+), 8 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 34b6792f..6d5a7cd6 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -20,6 +20,7 @@ #include "../hw/lmk05318/lmk05318.h" #include "../hw/lmx2820/lmx2820.h" #include "../hw/lmx1214/lmx1214.h" +#include "../hw/lmx1204/lmx1204.h" // [0] 24bit 20Mhz AD5662 InRef::DAC_REF // [1] 24bit 20Mhz AD5662 ClockGen::GEN_DC @@ -126,7 +127,7 @@ struct dev_pe_sync { lmk05318_state_t gen; lmx2820_state_t lmx0, lmx1; lmx1214_state_t lodistr; - + lmx1204_state_t cldistr; }; enum dev_gpi { @@ -345,8 +346,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const uint64_t lmx1_freq[] = { - 320000000, - 160000000 + 840000000, + 840000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); @@ -385,12 +386,12 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const //LMX1214 setup // - const uint64_t ld_clkout = 160000000; + const uint64_t ld_clkout = 840000000/3; bool ld_en[LMX1214_OUT_CNT] = {1,0,1,1}; lmx1214_auxclkout_cfg_t ld_aux; ld_aux.enable = 1; ld_aux.fmt = LMX2124_FMT_LVDS; - ld_aux.freq = 8000000; + ld_aux.freq = 840000000/4; res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); #if 0 @@ -408,6 +409,20 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1214 initialized"); // + // + //LMX1204 setup + // + + res = lmx1204_create(dev, 0, SPI_LMX1204, &d->cldistr); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX1204 failed to initialize, res:%d", res); + return res; + } + + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1204 initialized"); + // + return res; } diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 2de3e7b5..608a2608 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -4,3 +4,155 @@ #include "def_lmx1204.h" #include "lmx1204.h" #include "usdr_logging.h" + + +static int lmx1204_print_registers(uint32_t* regs, unsigned count) +{ + for (unsigned i = 0; i < count; i++) + { + uint8_t rn = regs[i] >> 16; + uint16_t rv = (uint16_t)regs[i]; + USDR_LOG("1204", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%02x) -> 0x%04x [0x%06x]", i, rn, rn, rv, regs[i]); + } + + return 0; +} + +static int lmx1204_spi_post(lmx1204_state_t* obj, uint32_t* regs, unsigned count) +{ + int res; + lmx1204_print_registers(regs, count); + + for (unsigned i = 0; i < count; i++) { + res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); + if (res) + return res; + + USDR_LOG("1204", USDR_LOG_NOTE, "[%d/%d] reg wr %08x\n", i, count, regs[i]); + } + + return 0; +} + +static int lmx1204_spi_get(lmx1204_state_t* obj, uint16_t addr, uint16_t* out) +{ + uint32_t v; + int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, MAKE_LMX1204_REG_RD((uint32_t)addr), &v); + if (res) + return res; + + USDR_LOG("1204", USDR_LOG_NOTE, " reg rd %04x => %08x\n", addr, v); + *out = v; + return 0; +} + +static int lmx1204_read_all_regs(lmx1204_state_t* st) +{ + uint8_t regs[] = + { + R0, + R2, + R3, + R4, + R5, + R6, + R7, + R8, + R9, + R11, + R12, + R13, + R14, + R15, + R16, + R17, + R18, + R19, + R20, + R21, + R22, + R23, + R24, + R25, + R28, + R29, + R33, + R34, + R65, + R67, + R72, + R75, + R79, + R86, + R90, + }; + + for(unsigned i = 0; i < SIZEOF_ARRAY(regs); ++i) + { + uint16_t regval; + int res = lmx1204_spi_get(st, regs[i], ®val); + if(res) + return res; + USDR_LOG("1204", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", i, regval); + } + + return 0; +} + +int lmx1204_get_temperature(lmx1204_state_t* st, float* value) +{ + if(!value) + return -EINVAL; + + uint16_t r24; + + int res = lmx1204_spi_get(st, R24, &r24); + if(res) + return res; + + int16_t code = (r24 & RB_TEMPSENSE_MSK) >> RB_TEMPSENSE_OFF; + *value = 0.65f * code - 351.0f; + + USDR_LOG("1214", USDR_LOG_DEBUG, "LMX1204 temperature sensor:%.2fC", *value); + return 0; +} + +int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st) +{ + memset(st, 0, sizeof(*st)); + int res; + + st->dev = dev; + st->subdev = subdev; + st->lsaddr = lsaddr; + + usleep(100000); + + uint32_t regs[] = + { + MAKE_LMX1204_R24(0,0,0,1), //enable temp sensor + MAKE_LMX1204_R23(1,1,0,0,0,0,0,0), //enable temp sensor + }; + res = lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + return res; + + usleep(100000); + + float tval; + res = lmx1204_get_temperature(st, &tval); + if(res) + return res; + + res = lmx1204_read_all_regs(st); + if(res) + return res; + + return 0; +} + +int lmx1204_destroy(lmx1204_state_t* st) +{ + USDR_LOG("1204", USDR_LOG_DEBUG, "Destroy OK"); + return 0; +} diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index b807d50f..497fe172 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -4,4 +4,20 @@ #ifndef LMX1204_H #define LMX1204_H +#include + +struct lmx1204_state +{ + lldev_t dev; + unsigned subdev; + unsigned lsaddr; + +}; +typedef struct lmx1204_state lmx1204_state_t; + +int lmx1204_get_temperature(lmx1204_state_t* st, float* value); +int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st); +int lmx1204_destroy(lmx1204_state_t* st); + + #endif // LMX1204_H diff --git a/src/lib/hw/lmx1204/lmx1204.yaml b/src/lib/hw/lmx1204/lmx1204.yaml index 5d5fda10..ca14a3f7 100644 --- a/src/lib/hw/lmx1204/lmx1204.yaml +++ b/src/lib/hw/lmx1204/lmx1204.yaml @@ -3,9 +3,9 @@ revision: 0.0.1 processors: [ c ] bus: type: SPI - wr_mask: 0x80000000 + rd_mask: 0x800000 usdr_path: /debug/hw/lmx1204/*/reg -addr_width: 16 +addr_width: 8 data_width: 16 pages: diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 27de257a..2fed6a7f 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -109,7 +109,7 @@ static int lmx1214_read_all_regs(lmx1214_state_t* st) int res = lmx1214_spi_get(st, regs[i], ®val); if(res) return res; - USDR_LOG("2820", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", i, regval); + USDR_LOG("1214", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", i, regval); } return 0; From 64b6c2ca8e096ade2acd0b8a63059d4a4bc6abaa Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 10 Apr 2025 21:01:47 +0300 Subject: [PATCH 078/397] lmx1204 works, 1214 fails --- src/lib/device/pe_sync/pe_sync.c | 18 +++++++++--------- src/lib/hw/lmx1204/lmx1204.c | 6 +++--- src/lib/hw/lmx1214/lmx1214.c | 15 ++++++++------- src/lib/hw/lmx1214/lmx1214.h | 4 ++-- src/lib/hw/lmx1214/lmx1214_dump.h | 2 +- src/utests/lmx1214_solver_test.c | 8 ++++---- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 6d5a7cd6..3ddbbe14 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -200,12 +200,12 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : dev_gpo_set(dev, IGPO_SY0_CTRL, 3); // Enable LMX2820 0 res = res ? res : dev_gpo_set(dev, IGPO_SY1_CTRL, 3); // Enable LMX2820 1 - // gpo_gen_ctrl[0] -- En LDO for LMK05318B - // gpo_gen_ctrl[1] -- PDN for LMK05318B - // gpo_gen_ctrl[2] -- En LDO for OCXO and OCXO DAC - // gpo_gen_ctrl[3] -- En distribution buffer REFCLK - // gpo_gen_ctrl[4] -- En distribution buffer 1PPS - // gpo_gen_ctrl[5] -- clk_gpio[0] + //* gpo_gen_ctrl[0] -- En LDO for LMK05318B + //* gpo_gen_ctrl[1] -- PDN for LMK05318B + //* gpo_gen_ctrl[2] -- En LDO for OCXO and OCXO DAC + //* gpo_gen_ctrl[3] -- En distribution buffer REFCLK + //* gpo_gen_ctrl[4] -- En distribution buffer 1PPS + //* gpo_gen_ctrl[5] -- clk_gpio[0] // gpo_gen_ctrl[6] -- clk_gpio[1] // gpo_gen_ctrl[7] -- clk_gpio[2] // res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (0 << 0) | (0 << 1) | (1 << 2) | (0 << 5)); @@ -219,7 +219,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // gpo_distrib_ctrl[3] -- 0 - buffers LMK1D1208I disable, 1 - en // gpo_distrib_ctrl[4] -- En LDO FCLK4..0 CMOS buffers // gpo_distrib_ctrl[5] -- 0 - internal path, 1 - external LO/REFCLK/SYSREF - res = res ? res : dev_gpo_set(dev, IGPO_DISTRIB_CTRL, (1 << 0) /* | (15 << 1) */ ); + res = res ? res : dev_gpo_set(dev, IGPO_DISTRIB_CTRL, (1 << 0) | (15 << 1)); // Wait for all LDOs to settle usleep(200000); @@ -390,11 +390,11 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const bool ld_en[LMX1214_OUT_CNT] = {1,0,1,1}; lmx1214_auxclkout_cfg_t ld_aux; ld_aux.enable = 1; - ld_aux.fmt = LMX2124_FMT_LVDS; + ld_aux.fmt = LMX1214_FMT_LVDS; ld_aux.freq = 840000000/4; res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); -#if 0 +#if 1 res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*dry run*/); #endif float lmx1214_tempval; diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 608a2608..bf979403 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -93,7 +93,7 @@ static int lmx1204_read_all_regs(lmx1204_state_t* st) int res = lmx1204_spi_get(st, regs[i], ®val); if(res) return res; - USDR_LOG("1204", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", i, regval); + USDR_LOG("1204", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", regs[i], regval); } return 0; @@ -113,7 +113,7 @@ int lmx1204_get_temperature(lmx1204_state_t* st, float* value) int16_t code = (r24 & RB_TEMPSENSE_MSK) >> RB_TEMPSENSE_OFF; *value = 0.65f * code - 351.0f; - USDR_LOG("1214", USDR_LOG_DEBUG, "LMX1204 temperature sensor:%.2fC", *value); + USDR_LOG("1204", USDR_LOG_DEBUG, "LMX1204 temperature sensor:%.2fC", *value); return 0; } @@ -131,7 +131,7 @@ int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_ uint32_t regs[] = { MAKE_LMX1204_R24(0,0,0,1), //enable temp sensor - MAKE_LMX1204_R23(1,1,0,0,0,0,0,0), //enable temp sensor + MAKE_LMX1204_R23(1,1,1,0,1,0,0,0), //enable temp sensor + MUXOUT_EN=1(push-pull) MUXOUT=1(SDO) }; res = lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 2fed6a7f..c5e2e58f 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -109,7 +109,7 @@ static int lmx1214_read_all_regs(lmx1214_state_t* st) int res = lmx1214_spi_get(st, regs[i], ®val); if(res) return res; - USDR_LOG("1214", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", i, regval); + USDR_LOG("1214", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", regs[i], regval); } return 0; @@ -186,7 +186,7 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ st->subdev = subdev; st->lsaddr = lsaddr; -#if 1 +#if 0 res = lmx1214_loaddump(st); if(res) return res; @@ -194,9 +194,10 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ uint32_t regs[] = { - MAKE_LMX1214_R79(0, 0x5), //magic R79->0x5 (see manual) - MAKE_LMX1214_R24(0, 0, 0, 1), //temp sensor - MAKE_LMX1214_R23(1, 1, 0, 0), //temp sensor + MAKE_LMX1214_R86(0, 0, 0), //MUXOUT_EN_OVRD=0 + MAKE_LMX1214_R79(0, 0x5), //magic R79->0x5 (see manual) + MAKE_LMX1214_R24(0, 0, 0, 1), //temp sensor + MAKE_LMX1214_R23(1, 1, 1, 1 << 6), //temp sensor + MUXOUT_EN=1(push-pull) MUXOUT=1(SDO) }; res = lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); @@ -268,8 +269,8 @@ static int lmx1214_solver_prevalidate(uint64_t in, uint64_t out, bool* out_en, l switch(aux->fmt) { - case LMX2124_FMT_LVDS: aux->fmt = AUXCLKOUT_FMT_LVDS; break; - case LMX2124_FMT_CML : aux->fmt = AUXCLKOUT_FMT_CML; break; + case LMX1214_FMT_LVDS: aux->fmt = AUXCLKOUT_FMT_LVDS; break; + case LMX1214_FMT_CML : aux->fmt = AUXCLKOUT_FMT_CML; break; default: { USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT_FMT:%u is invalid", aux->fmt); diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index 48f2b230..f4409ed7 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -10,8 +10,8 @@ enum { - LMX2124_FMT_LVDS = 0, - LMX2124_FMT_CML = 2, + LMX1214_FMT_LVDS = 0, + LMX1214_FMT_CML = 2, }; struct lmx1214_auxclkout_cfg diff --git a/src/lib/hw/lmx1214/lmx1214_dump.h b/src/lib/hw/lmx1214/lmx1214_dump.h index b54a345d..5c3daac0 100644 --- a/src/lib/hw/lmx1214/lmx1214_dump.h +++ b/src/lib/hw/lmx1214/lmx1214_dump.h @@ -6,7 +6,7 @@ static uint32_t lmx1214_rom_test[] = { /*R90*/ 0x5A0000, - /*R86*/ 0x560004, + /*R86*/ 0x560000, /*R79*/ 0x4F0005, /*R75*/ 0x4B0006, /*R25*/ 0x19020A, diff --git a/src/utests/lmx1214_solver_test.c b/src/utests/lmx1214_solver_test.c index 5fe79e1b..7bdabc15 100644 --- a/src/utests/lmx1214_solver_test.c +++ b/src/utests/lmx1214_solver_test.c @@ -19,7 +19,7 @@ START_TEST(lmx1214_solver_test1) lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.fmt = LMX1214_FMT_LVDS; //LVDS aux.freq = osc_in / 16; int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); @@ -34,7 +34,7 @@ START_TEST(lmx1214_solver_test2) lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.fmt = LMX1214_FMT_LVDS; //LVDS aux.freq = osc_in / 160; int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); @@ -49,7 +49,7 @@ START_TEST(lmx1214_solver_test3) lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.fmt = LMX1214_FMT_LVDS; //LVDS aux.freq = osc_in; int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); @@ -64,7 +64,7 @@ START_TEST(lmx1214_solver_test4_pesync) lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX2124_FMT_LVDS; //LVDS + aux.fmt = LMX1214_FMT_LVDS; //LVDS aux.freq = osc_in; int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); From e9fdaba5632b3f266efe7c61d54337653cbe384d Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 11 Apr 2025 11:24:33 +0300 Subject: [PATCH 079/397] code cleaning & fixes in regs. Stable --- src/lib/device/pe_sync/pe_sync.c | 53 ++++++++++---------------------- src/lib/hw/lmx1204/lmx1204.c | 11 ++----- src/lib/hw/lmx1214/lmx1214.c | 25 +++------------ src/lib/hw/lmx2820/lmx2820.c | 2 +- src/lib/hw/lmx2820/lmx2820.h | 3 -- 5 files changed, 26 insertions(+), 68 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 3ddbbe14..793307b2 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -200,12 +200,12 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : dev_gpo_set(dev, IGPO_SY0_CTRL, 3); // Enable LMX2820 0 res = res ? res : dev_gpo_set(dev, IGPO_SY1_CTRL, 3); // Enable LMX2820 1 - //* gpo_gen_ctrl[0] -- En LDO for LMK05318B - //* gpo_gen_ctrl[1] -- PDN for LMK05318B - //* gpo_gen_ctrl[2] -- En LDO for OCXO and OCXO DAC - //* gpo_gen_ctrl[3] -- En distribution buffer REFCLK - //* gpo_gen_ctrl[4] -- En distribution buffer 1PPS - //* gpo_gen_ctrl[5] -- clk_gpio[0] + // gpo_gen_ctrl[0] -- En LDO for LMK05318B + // gpo_gen_ctrl[1] -- PDN for LMK05318B + // gpo_gen_ctrl[2] -- En LDO for OCXO and OCXO DAC + // gpo_gen_ctrl[3] -- En distribution buffer REFCLK + // gpo_gen_ctrl[4] -- En distribution buffer 1PPS + // gpo_gen_ctrl[5] -- clk_gpio[0] // gpo_gen_ctrl[6] -- clk_gpio[1] // gpo_gen_ctrl[7] -- clk_gpio[2] // res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (0 << 0) | (0 << 1) | (1 << 2) | (0 << 5)); @@ -243,9 +243,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1204, 0x176040, NULL); //Enable MUXOUT as SPI readback res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1204, 0xA10000, &s2); - // TODO check LMX1214 readback settings - res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1214, 0x560004, NULL); //Enable MUXOUT_EN_OVRD - res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1214, 0x176000, NULL); //Enable MUXOUT + res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1214, 0x176040, NULL); //Enable MUXOUT res = res ? res : lowlevel_spi_tr32(dev, 0, SPI_LMX1214, 0xCF0000, &s3); res = res ? res : i2c_reg_rd8(dev, I2C_BUS_LMK1D1208I_LCK, 0x05, &r4); @@ -254,7 +252,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_WARNING, "STAT=%08x LP87524_OTP=%02x LMS2820[0/1]=%04x/%04x LMX1204/LMX1214=%04x/%04x LMK1D1208I_LCK/LRF=%02x/%02x\n", v, r, s0, s1, s2, s3, r4, r5); - // TODO: Initialize LMK05318B + // Initialize LMK05318B // XO: 25Mhz // // OUT0: LVDS 125.000 Mhz @@ -339,6 +337,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; USDR_LOG("SYNC", USDR_LOG_INFO, "LMK03518 outputs synced"); + // // //LMX2820 #1 setup @@ -346,57 +345,39 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const uint64_t lmx1_freq[] = { - 840000000, - 840000000 + 1600000000, + 1600000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); -#if 1 res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], 2 /*mash order 2*/, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); -#else - res = res ? res : lmx2820_loaddump(&d->lmx1); - usleep(1000); - - res = res ? res : lmx2820_wait_pll_lock(&d->lmx1, 10000); - if(res) - USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX2820 not locked!"); - else - USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 locked OK"); - res = res ? res : lmx2820_sync(&d->lmx1); - if(res) - USDR_LOG("SYNC", USDR_LOG_ERROR, "lmx2820_sync() failed, err:%d", res); - else - USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 synced OK"); - -#endif lmx2820_stats_t lmxstatus; lmx2820_read_status(&d->lmx1, &lmxstatus); //just for logging if(res) { - USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX2820 PLL not locked during specified timeout"); + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX2820[1] PLL not locked during specified timeout"); return res; } - USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820 outputs locked & synced"); + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820[1] outputs locked & synced"); // // //LMX1214 setup // - const uint64_t ld_clkout = 840000000/3; - bool ld_en[LMX1214_OUT_CNT] = {1,0,1,1}; + const uint64_t ld_clkout = 1600000000/2; + bool ld_en[LMX1214_OUT_CNT] = {1,1,1,1}; lmx1214_auxclkout_cfg_t ld_aux; ld_aux.enable = 1; ld_aux.fmt = LMX1214_FMT_LVDS; - ld_aux.freq = 840000000/4; + ld_aux.freq = 800000000/4; res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); -#if 1 res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*dry run*/); -#endif + float lmx1214_tempval; lmx1214_get_temperature(&d->lodistr, &lmx1214_tempval); //just for logging diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index bf979403..99614719 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -46,7 +46,7 @@ static int lmx1204_spi_get(lmx1204_state_t* obj, uint16_t addr, uint16_t* out) return 0; } -static int lmx1204_read_all_regs(lmx1204_state_t* st) +UNUSED static int lmx1204_read_all_regs(lmx1204_state_t* st) { uint8_t regs[] = { @@ -126,10 +126,9 @@ int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_ st->subdev = subdev; st->lsaddr = lsaddr; - usleep(100000); - uint32_t regs[] = { + MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 MAKE_LMX1204_R24(0,0,0,1), //enable temp sensor MAKE_LMX1204_R23(1,1,1,0,1,0,0,0), //enable temp sensor + MUXOUT_EN=1(push-pull) MUXOUT=1(SDO) }; @@ -137,17 +136,13 @@ int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_ if(res) return res; - usleep(100000); + usleep(10); float tval; res = lmx1204_get_temperature(st, &tval); if(res) return res; - res = lmx1204_read_all_regs(st); - if(res) - return res; - return 0; } diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index c5e2e58f..e0e84432 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -77,7 +77,7 @@ static int lmx1214_spi_get(lmx1214_state_t* obj, uint16_t addr, uint16_t* out) return 0; } -static int lmx1214_read_all_regs(lmx1214_state_t* st) +UNUSED static int lmx1214_read_all_regs(lmx1214_state_t* st) { uint8_t regs[] = { @@ -115,7 +115,7 @@ static int lmx1214_read_all_regs(lmx1214_state_t* st) return 0; } -static int lmx1214_loaddump(lmx1214_state_t* st) +UNUSED static int lmx1214_loaddump(lmx1214_state_t* st) { int res = lmx1214_spi_post(st, lmx1214_rom_test, SIZEOF_ARRAY(lmx1214_rom_test)); if(res) @@ -186,12 +186,6 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ st->subdev = subdev; st->lsaddr = lsaddr; -#if 0 - res = lmx1214_loaddump(st); - if(res) - return res; -#else - uint32_t regs[] = { MAKE_LMX1214_R86(0, 0, 0), //MUXOUT_EN_OVRD=0 @@ -206,8 +200,8 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ USDR_LOG("1214", USDR_LOG_ERROR, "Registers set lmx1214_spi_post() failed, err:%d", res); return res; } -#endif - usleep(100000); + + usleep(10); float tempval; res = lmx1214_get_temperature(st, &tempval); @@ -217,16 +211,6 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ return res; } - uint16_t r75; - res = lmx1214_spi_get(st, R75, &r75); - if(res) - return res; - USDR_LOG("1214", USDR_LOG_DEBUG, "R75 status byte:0x%04x", r75); - - res = lmx1214_read_all_regs(st); - if(res) - return res; - USDR_LOG("1214", USDR_LOG_DEBUG, "Create OK"); return 0; } @@ -486,6 +470,7 @@ int lmx1214_windowing(lmx1214_state_t* st) uint32_t clkpos = ((uint32_t)r12 << 16) | r11; //USDR_LOG(USDR_LOG_DEBUG, "CLKPOS:0b%b", clkpos); + //TODO return 0; diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 60cb0a3a..10c95ccc 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -296,7 +296,7 @@ int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status) return 0; } -int lmx2820_loaddump(lmx2820_state_t* st) +UNUSED static int lmx2820_loaddump(lmx2820_state_t* st) { int res = lmx2820_spi_post(st, lmx2820_rom_test, SIZEOF_ARRAY(lmx2820_rom_test)); if(res) diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index 959d8e30..419b78b0 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -65,7 +65,4 @@ int lmx2820_sync(lmx2820_state_t* st); int lmx2820_reset(lmx2820_state_t* st); int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout); -int lmx2820_loaddump(lmx2820_state_t* st); - - #endif // LMX2820_H From 5e66c9e7383142099c2a7a5af4e0a9153c37fe41 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 11 Apr 2025 12:51:00 +0300 Subject: [PATCH 080/397] LMX2124 1)fix for aux.disables 2)prec mode --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmx1204/lmx1204.c | 2 +- src/lib/hw/lmx1214/lmx1214.c | 45 +++++++++++++++---------- src/lib/hw/lmx1214/lmx1214.h | 6 ++-- src/utests/lmx1214_solver_test.c | 58 +++++++++++++++++++++++++------- 5 files changed, 77 insertions(+), 36 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 793307b2..c0fc3bdf 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -376,7 +376,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const ld_aux.freq = 800000000/4; res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); - res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*dry run*/); + res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*prec_mode*/, false /*dry run*/); float lmx1214_tempval; lmx1214_get_temperature(&d->lodistr, &lmx1214_tempval); //just for logging diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 99614719..2aee051b 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -136,7 +136,7 @@ int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_ if(res) return res; - usleep(10); + usleep(1000); float tval; res = lmx1204_get_temperature(st, &tval); diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index e0e84432..798ba604 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -201,7 +201,7 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ return res; } - usleep(10); + usleep(1000); float tempval; res = lmx1214_get_temperature(st, &tempval); @@ -245,9 +245,9 @@ static int lmx1214_solver_prevalidate(uint64_t in, uint64_t out, bool* out_en, l return -EINVAL; } - if(aux->freq < AUXCLKOUT_MIN || aux->freq > AUXCLKOUT_MAX) + if(aux->enable && (aux->freq < AUXCLKOUT_MIN || aux->freq > AUXCLKOUT_MAX)) { - USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT:%" PRIu64 " out of range [%" PRIu64 ";%" PRIu64 "]", aux->freq, (uint64_t)AUXCLKOUT_MIN, (uint64_t)AUXCLKOUT_MAX); + USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT:%.4f out of range [%" PRIu64 ";%" PRIu64 "]", aux->freq, (uint64_t)AUXCLKOUT_MIN, (uint64_t)AUXCLKOUT_MAX); return -EINVAL; } @@ -257,8 +257,15 @@ static int lmx1214_solver_prevalidate(uint64_t in, uint64_t out, bool* out_en, l case LMX1214_FMT_CML : aux->fmt = AUXCLKOUT_FMT_CML; break; default: { - USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT_FMT:%u is invalid", aux->fmt); - return -EINVAL; + if(!aux->enable) + { + aux->fmt = AUXCLKOUT_FMT_LVDS; + } + else + { + USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT_FMT:%u is invalid", aux->fmt); + return -EINVAL; + } } } @@ -291,7 +298,7 @@ static const char* lmx1214_decode_auxfmt(uint8_t fmt) return "UNKNOWN"; } -int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool dry_run) +int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool prec_mode, bool dry_run) { int res = lmx1214_solver_prevalidate(in, out, out_en, aux); if(res) @@ -310,7 +317,7 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, else { clk_mux = CLK_MUX_DIVIDER; - clk_div = in / out; + clk_div = (unsigned)((double)in / out + 0.5); if(clk_div < CLK_DIV_MIN || clk_div > CLK_DIV_MAX) { @@ -318,15 +325,15 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, return -EINVAL; } - if(in != out * clk_div) + if(prec_mode && in != out * clk_div) { USDR_LOG("1214", USDR_LOG_ERROR, "Cannot solve CLKOUT:%" PRIu64 " by int divider", out); return -EINVAL; } } - USDR_LOG("1214", USDR_LOG_DEBUG, "CLKIN:%" PRIu64 " CLKOUT:%" PRIu64 " CLK_DIV:%u MUX:%u [BUFFER_MODE:%u]", - in, out, clk_div, clk_mux, buffer_mode); + USDR_LOG("1214", USDR_LOG_DEBUG, "CLKIN:%" PRIu64 " CLKOUT:%.4f CLK_DIV:%u MUX:%u [BUFFER_MODE:%u] [PREC_MODE:%u]", + in, (double)in / clk_div, clk_div, clk_mux, buffer_mode, prec_mode); uint8_t auxclk_div_pre = AUXCLK_DIV_PRE_DIV4; @@ -350,8 +357,8 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, if(auxclk_div_pre == AUXCLK_DIV_PRE_DIV4 - 1) continue; - uint64_t fmid = in / auxclk_div_pre; - if(in != fmid * auxclk_div_pre) + double fmid = (double)in / auxclk_div_pre; + if(prec_mode && in != (uint64_t)(fmid + 0.5) * auxclk_div_pre) continue; if(fmid == aux->freq && auxclk_div_pre == AUXCLK_DIV_PRE_DIV1) @@ -364,8 +371,8 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, if(auxclk_div_pre == AUXCLK_DIV_PRE_DIV1) //cannot use pre_div==1 without bypassing div continue; - unsigned div = fmid / aux->freq; - if(fmid != aux->freq * div) + unsigned div = (unsigned)(fmid / aux->freq + 0.5); + if(prec_mode && fmid != aux->freq * div) continue; if(div < AUXCLK_DIV_MIN || div > AUXCLK_DIV_MAX) continue; @@ -377,7 +384,7 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, if(!found) { - USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT:%" PRIu64 " cannot be solved with LMX1214 divs", aux->freq); + USDR_LOG("1214", USDR_LOG_ERROR, "AUXCLKOUT:%.4f cannot be solved with LMX1214 divs", aux->freq); return -EINVAL; } } @@ -386,21 +393,23 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, st->clkin = in; st->clk_mux = clk_mux; st->clk_div = clk_div; - st->clkout = out; + st->clkout = (double)in / clk_div; for(unsigned i = 0; i < LMX1214_OUT_CNT; ++i) st->clkout_enabled[i] = out_en[i]; st->auxclk_div_pre = auxclk_div_pre; st->auxclk_div_byp = auxclk_div_byp; st->auxclk_div = auxclk_div; st->auxclkout = *aux; + if(st->auxclkout.enable) + st->auxclkout.freq = auxclk_div_byp ? (double)in / auxclk_div_pre : (double)in / auxclk_div_pre / auxclk_div; USDR_LOG("1214", USDR_LOG_INFO, "LMX1214 SOLUTION FOUND:"); - USDR_LOG("1214", USDR_LOG_INFO, "CLKIN:%" PRIu64 " CLK_DIV:%u CLKMUX:%s(%u) CLKOUT:%" PRIu64, + USDR_LOG("1214", USDR_LOG_INFO, "CLKIN:%" PRIu64 " CLK_DIV:%u CLKMUX:%s(%u) CLKOUT:%.4f", st->clkin, st->clk_div, lmx1214_decode_mux(st->clk_mux), st->clk_mux, st->clkout); USDR_LOG("1214", USDR_LOG_INFO, "CLKOUT enabled - OUT0:%u OUT1:%u OUT2:%u OUT3:%u", st->clkout_enabled[0], st->clkout_enabled[1], st->clkout_enabled[2], st->clkout_enabled[3]); if(st->auxclkout.enable) - USDR_LOG("1214", USDR_LOG_INFO, "AUXCLC_DIV_PRE:%u AUXCLK_DIV_BYP:%u AUXCLK_DIV:%u AUXCLKOUT:%" PRIu64 " AUXCLKOUT_FMT:%s(%u)", + USDR_LOG("1214", USDR_LOG_INFO, "AUXCLC_DIV_PRE:%u AUXCLK_DIV_BYP:%u AUXCLK_DIV:%u AUXCLKOUT:%.4f AUXCLKOUT_FMT:%s(%u)", st->auxclk_div_pre, st->auxclk_div_byp, st->auxclk_div, st->auxclkout.freq, lmx1214_decode_auxfmt(st->auxclkout.fmt), st->auxclkout.fmt); else diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index f4409ed7..d60713db 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -16,7 +16,7 @@ enum struct lmx1214_auxclkout_cfg { - uint64_t freq; + double freq; bool enable; uint8_t fmt; }; @@ -37,7 +37,7 @@ struct lmx1214_state uint16_t auxclk_div; bool auxclk_div_byp; - uint64_t clkout; + double clkout; bool clkout_enabled[LMX1214_OUT_CNT]; lmx1214_auxclkout_cfg_t auxclkout; }; @@ -46,7 +46,7 @@ typedef struct lmx1214_state lmx1214_state_t; int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_t* st); int lmx1214_destroy(lmx1214_state_t* st); -int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool dry_run); +int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool prec_mode, bool dry_run); int lmx1214_get_temperature(lmx1214_state_t* st, float* value); int lmx1214_sync_clr(lmx1214_state_t* st); diff --git a/src/utests/lmx1214_solver_test.c b/src/utests/lmx1214_solver_test.c index 7bdabc15..f7910a5b 100644 --- a/src/utests/lmx1214_solver_test.c +++ b/src/utests/lmx1214_solver_test.c @@ -19,10 +19,10 @@ START_TEST(lmx1214_solver_test1) lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX1214_FMT_LVDS; //LVDS + aux.fmt = LMX1214_FMT_LVDS; aux.freq = osc_in / 16; - int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); ck_assert_int_eq( res, 0 ); } @@ -34,10 +34,10 @@ START_TEST(lmx1214_solver_test2) lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX1214_FMT_LVDS; //LVDS + aux.fmt = LMX1214_FMT_LVDS; aux.freq = osc_in / 160; - int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); ck_assert_int_eq( res, 0 ); } @@ -49,25 +49,55 @@ START_TEST(lmx1214_solver_test3) lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX1214_FMT_LVDS; //LVDS + aux.fmt = LMX1214_FMT_LVDS; aux.freq = osc_in; - int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); ck_assert_int_eq( res, 0 ); } -START_TEST(lmx1214_solver_test4_pesync) +START_TEST(lmx1214_solver_test4_pesync0) { - const uint64_t osc_in = 640000000; - uint64_t out_freq = osc_in; + const uint64_t osc_in = 1600000000; + uint64_t out_freq = osc_in / 2; bool en[4] = {1,1,1,1}; lmx1214_auxclkout_cfg_t aux; aux.enable = 1; - aux.fmt = LMX1214_FMT_LVDS; //LVDS - aux.freq = osc_in; + aux.fmt = LMX1214_FMT_LVDS; + aux.freq = 800000000/4; + + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, false, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1214_solver_test4_pesync1) +{ + const uint64_t osc_in = 1600000000; + uint64_t out_freq = osc_in / 2; + bool en[4] = {1,1,1,1}; + + lmx1214_auxclkout_cfg_t aux; + aux.enable = 0; + aux.fmt = LMX1214_FMT_LVDS; + aux.freq = 0; + + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1214_solver_test4_pesync2) +{ + const uint64_t osc_in = 1600000000; + uint64_t out_freq = osc_in / 3; + bool en[4] = {1,1,1,1}; + + lmx1214_auxclkout_cfg_t aux; + aux.enable = 1; + aux.fmt = LMX1214_FMT_LVDS; + aux.freq = 1600000000 / 124; - int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true); + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, false, true); ck_assert_int_eq( res, 0 ); } @@ -84,7 +114,9 @@ Suite * lmx1214_solver_suite(void) tcase_add_test(tc_core, lmx1214_solver_test1); tcase_add_test(tc_core, lmx1214_solver_test2); tcase_add_test(tc_core, lmx1214_solver_test3); - tcase_add_test(tc_core, lmx1214_solver_test4_pesync); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync0); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync1); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync2); suite_add_tcase(s, tc_core); return s; From d97d76a03e71e24f94ebdfed70fc088c9ba166bb Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 11 Apr 2025 19:38:59 +0300 Subject: [PATCH 081/397] lmx1204 (not ready yet) --- src/lib/hw/lmx1204/lmx1204.c | 385 +++++++++++++++++++++++++++++++++++ src/lib/hw/lmx1204/lmx1204.h | 48 ++++- src/lib/hw/lmx1214/lmx1214.c | 20 +- 3 files changed, 449 insertions(+), 4 deletions(-) diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 2aee051b..51bf6902 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -1,10 +1,54 @@ // Copyright (c) 2025 Wavelet Lab // SPDX-License-Identifier: MIT +#include +#include +#include + #include "def_lmx1204.h" #include "lmx1204.h" #include "usdr_logging.h" +#include "../cal/opt_func.h" + +#define FREQ_EPS 1.0f + +enum +{ + SYSREFOUT_MIN = 0, + SYSREFOUT_MAX_GENMODE = 200000000ull, + SYSREFOUT_MAX_RPTMODE = 100000000ull, + + CLKIN_MIN = 300000000ull, + CLKIN_MAX = 12800000000ull, + + CLKOUT_MIN_DIV = 150000000ull, + CLKOUT_MAX_DIV = 6400000000ull, + + CLKOUT_MIN_BUF = CLKIN_MIN, + CLKOUT_MAX_BUF = CLKIN_MAX, + + CLKOUT_MIN_MUL = 3200000000ull, + CLKOUT_MAX_MUL = 6400000000ull, + LOGICLKOUT_MIN = 1000000ull, + LOGICLKOUT_MAX = 800000000ull, + + SMCLK_DIV_PRE_OUT_MAX = 1600000000ull, + SMCLK_DIV_OUT_MAX = 30000000ull, + + LOGICLK_DIV_PRE_OUT_MAX = 3200000000ull, + + SYSREF_DIV_PRE_OUT_MAX = 3200000000ull, + + CLK_DIV_MIN = 2, + CLK_DIV_MAX = 8, + CLK_MULT_MIN = 1, + CLK_MULT_MAX = 4, + LOGICLK_DIV_MIN = 2, + LOGICLK_DIV_MAX = 1023, + SYSREF_DIV_MIN = 2, + SYSREF_DIV_MAX = 4095, +}; static int lmx1204_print_registers(uint32_t* regs, unsigned count) { @@ -151,3 +195,344 @@ int lmx1204_destroy(lmx1204_state_t* st) USDR_LOG("1204", USDR_LOG_DEBUG, "Destroy OK"); return 0; } + +static int lmx1204_solver_prevalidate(lmx1204_state_t* st) +{ + if(st->clkin < CLKIN_MIN || st->clkin > CLKIN_MAX) + { + USDR_LOG("1204", USDR_LOG_ERROR, "CLKIN:%" PRIu64 " out of range [%" PRIu64 "; %" PRIu64 "]", + st->clkin, (uint64_t)CLKIN_MIN, (uint64_t)CLKIN_MAX); + return -EINVAL; + } + + if(st->logic_en && st->logiclkout_en && (st->logiclkout < LOGICLKOUT_MIN || st->logiclkout > LOGICLKOUT_MAX)) + { + USDR_LOG("1204", USDR_LOG_ERROR, "LOGICLKOUT:%.4f out of range [%" PRIu64 "; %" PRIu64 "]", + st->logiclkout, (uint64_t)LOGICLKOUT_MIN, (uint64_t)LOGICLKOUT_MAX); + return -EINVAL; + } + + double fmin, fmax; + + switch(st->clk_mux) + { + case CLK_MUX_DIVIDER_MODE: fmin = CLKOUT_MIN_DIV; fmax = CLKOUT_MAX_DIV; break; + case CLK_MUX_MULTIPLIER_MODE: fmin = CLKOUT_MIN_MUL; fmax = CLKOUT_MAX_MUL; break; + case CLK_MUX_BUFFER_MODE: fmin = CLKOUT_MIN_BUF; fmax = CLKOUT_MIN_BUF; break; + default: + USDR_LOG("1204", USDR_LOG_ERROR, "CLK_MUX:%u unknown", st->clk_mux); + return -EINVAL; + } + + if(st->clkout < fmin || st->clkout > fmax) + { + USDR_LOG("1204", USDR_LOG_ERROR, "CLKOUT:%.4f out of range [%.0f; %.0f]", st->clkout, fmin, fmax); + return -EINVAL; + } + + if(st->sysref_en) + { + fmin = SYSREFOUT_MIN; + switch(st->sysref_mode) + { + case SYSREF_MODE_CONTINUOUS_GENERATOR_MODE: fmax = SYSREFOUT_MAX_GENMODE; break; + case SYSREF_MODE_REPEATER_REPEATER_MODE: fmax = SYSREFOUT_MAX_RPTMODE; break; + case SYSREF_MODE_PULSER_GENERATOR_MODE: fmax = 0.0f; break; + default: + USDR_LOG("1204", USDR_LOG_ERROR, "SYSREF_MODE:%u unknown", st->sysref_mode); + return -EINVAL; + } + + if(fmax != 0.0f && (st->sysrefout < fmin || st->sysrefout > fmax)) + { + USDR_LOG("1204", USDR_LOG_ERROR, "SYSREFOUT:%.4f out of range [%.0f; %.0f]", st->sysrefout, fmin, fmax); + return -EINVAL; + } + } + + if(st->logic_en) + { + if(st->logiclkout_en) + { + switch(st->logiclkout_fmt) + { + case LMX1204_FMT_LVDS: st->logiclkout_fmt = LOGICLKOUT_FMT_LVDS; break; + case LMX1204_FMT_LVPECL: st->logiclkout_fmt = LOGICLKOUT_FMT_LVPECL; break; + case LMX1204_FMT_CML: st->logiclkout_fmt = LOGICLKOUT_FMT_CML; break; + default: + USDR_LOG("1204", USDR_LOG_ERROR, "LOGICLKOUT_FMT:%u unknown", st->logiclkout_fmt); + return -EINVAL; + } + } + + if(st->sysref_en && st->logisysrefout_en) + { + switch(st->logisysrefout_fmt) + { + case LMX1204_FMT_LVDS: st->logisysrefout_fmt = LOGISYSREFOUT_FMT_LVDS; break; + case LMX1204_FMT_LVPECL: st->logisysrefout_fmt = LOGISYSREFOUT_FMT_LVPECL; break; + case LMX1204_FMT_CML: st->logisysrefout_fmt = LOGISYSREFOUT_FMT_CML; break; + default: + USDR_LOG("1204", USDR_LOG_ERROR, "LOGISYSREFOUT_FMT:%u unknown", st->logisysrefout_fmt); + return -EINVAL; + } + } + } + + return 0; +} + +static const char* lmx1204_decode_clkmux(enum clk_mux_options mux) +{ + switch(mux) + { + case CLK_MUX_BUFFER_MODE: return "CLK_MUX_BUFFER_MODE"; + case CLK_MUX_MULTIPLIER_MODE: return "CLK_MUX_MULTIPLIER_MODE"; + case CLK_MUX_DIVIDER_MODE: return "CLK_MUX_DIVIDER_MODE"; + } + return "UNKNOWN"; +} + +// all params are in lmx1204_state_t struct +int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) +{ + int res; + enum clk_mux_options clk_mux; + unsigned mult_div; + + if(st->clkin > st->clkout) + clk_mux = CLK_MUX_DIVIDER_MODE; + else if(st->clkin < st->clkout) + clk_mux = CLK_MUX_MULTIPLIER_MODE; + else + clk_mux = st->filter_mode ? CLK_MUX_MULTIPLIER_MODE : CLK_MUX_BUFFER_MODE; + + st->clk_mux = clk_mux; + + res = lmx1204_solver_prevalidate(st); + if(res) + return res; + + double outclk_fact; + + switch(clk_mux) + { + case CLK_MUX_BUFFER_MODE: + { + mult_div = 1; + outclk_fact = st->clkin; + break; + } + case CLK_MUX_DIVIDER_MODE: + { + mult_div = (unsigned)((double)st->clkin / st->clkout + 0.5); + if(mult_div < CLK_DIV_MIN || mult_div > CLK_DIV_MAX) + { + USDR_LOG("1204", USDR_LOG_ERROR, "CLC_DIV:%u out of range", mult_div); + return -EINVAL; + } + + outclk_fact = (double)st->clkin / mult_div; + break; + } + case CLK_MUX_MULTIPLIER_MODE: + { + mult_div = (unsigned)(st->clkout / st->clkin + 0.5); + if(mult_div < CLK_MULT_MIN || mult_div > CLK_MULT_MAX) + { + USDR_LOG("1204", USDR_LOG_ERROR, "CLC_MULT:%u out of range", mult_div); + return -EINVAL; + } + + outclk_fact = (double)st->clkin * mult_div; + break; + } + } + + if(fabs(outclk_fact - st->clkout) > FREQ_EPS) + { + USDR_LOG("1204", USDR_LOG_ERROR, "Calculated CLKOUT:%.4f too rough", outclk_fact); + return -EINVAL; + } + + if(prec_mode && st->clkin != st->clkout * mult_div) + { + USDR_LOG("1204", USDR_LOG_ERROR, "Cannot solve CLKOUT:%.4f by int divider/multiplier", st->clkout); + return -EINVAL; + } + + st->clkout = outclk_fact; + st->clk_mult_div = mult_div; + + USDR_LOG("1204", USDR_LOG_DEBUG, "CLKIN:%" PRIu64 " CLK_MUX:%s CLK_MULT_DIV:%u CLKOUT:%.4f [FILTER_MODE:%u] [PREC_MODE:%u]", + st->clkin, lmx1204_decode_clkmux(clk_mux), mult_div, st->clkout, st->filter_mode, prec_mode); + + // need to setup VCO for mult + if(clk_mux == CLK_MUX_MULTIPLIER_MODE) + { + unsigned div_pre = MAX(ceil((double)st->clkin / SMCLK_DIV_PRE_OUT_MAX), SMCLK_DIV_PRE_PL2); + if(div_pre > SMCLK_DIV_PRE_PL2 && div_pre <= SMCLK_DIV_PRE_PL4) + div_pre = SMCLK_DIV_PRE_PL4; + else if(div_pre > SMCLK_DIV_PRE_PL4 && div_pre <= SMCLK_DIV_PRE_PL8) + div_pre = SMCLK_DIV_PRE_PL8; + else + return -EINVAL; //impossible + + double fdiv = (double)st->clkin / div_pre / SMCLK_DIV_OUT_MAX; + unsigned n = MAX(ceil(log2(fdiv)), SMCLK_DIV_PL1); + if(n > SMCLK_DIV_PL128) + { + return -EINVAL; //impossible + } + + const unsigned div = 1u << n; + + USDR_LOG("1204", USDR_LOG_DEBUG, "[MULT VCO SMCLK] SMCLK_DIV_PRE:%u SMCLK_DIV:%u(%u) F_SM_CLK:%.4f", + div_pre, n, div, (double)st->clkin / div_pre / div); + + st->smclk_div_pre = div_pre; + st->smclk_div = n; + } + + //need to setup LOGICLKOUT + if(st->logic_en && st->logiclkout_en) + { + unsigned div_pre, div; + double logiclkout_fact; + + if(st->logiclkout == st->clkin) + { + div_pre = LOGICLK_DIV_PRE_PL1; + div = 0; // bypassed + logiclkout_fact = st->clkin; + } + else + { + unsigned div_pre_min = MAX(ceil((double)st->clkin / LOGICLK_DIV_PRE_OUT_MAX), LOGICLK_DIV_PRE_PL2); + + bool found = false; + for(div_pre = div_pre_min; div_pre <= LOGICLK_DIV_PRE_PL4; ++div_pre) + { + if(div_pre == LOGICLK_DIV_PRE_PL4 - 1) + continue; + + div = (unsigned)((double)st->clkin / div_pre / st->logiclkout + 0.5); + if(div < LOGICLK_DIV_MIN) + { + USDR_LOG("1204", USDR_LOG_ERROR, "LOGICLKOUT:%.4f too high", st->logiclkout); + return -EINVAL; + } + if(div > LOGICLK_DIV_MAX) + continue; + + logiclkout_fact = (double)st->clkin / div_pre / div; + if(fabs(st->logiclkout - logiclkout_fact) > FREQ_EPS) + continue; + if(prec_mode && st->clkin != st->logiclkout * div_pre * div) + continue; + } + if(!found) + { + USDR_LOG("1204", USDR_LOG_ERROR, "Cannot solve LOGICLKOUT:%.4f", st->logiclkout); + return -EINVAL; + } + } + + st->logiclkout = logiclkout_fact; + st->logiclk_div_pre = div_pre; + st->logiclk_div = div; + + USDR_LOG("1204", USDR_LOG_DEBUG, "[LOGICLKOUT] LOGICLK_DIV_PRE:%u LOGICLK_DIV:%u%s LOGICLKOUT:%.4f", + div_pre, div, div ? "" : "(BYPASSED)", logiclkout_fact); + } + else + { + USDR_LOG("1204", USDR_LOG_DEBUG, "[LOGICLKOUT]:disabled"); + } + + //sysref + if(st->sysref_en) + { + uint64_t f_interpol; + + if(st->clkin <= 1600000000ull) + { + st->sysref_delay_div = SYSREF_DELAY_DIV_PL2_LE_1_6_GHZ; + f_interpol = st->clkin >> 1; + } + else if(st->clkin <= 3200000000ull) + { + st->sysref_delay_div = SYSREF_DELAY_DIV_PL4_1_6_GHZ_TO_3_2_GHZ; + f_interpol = st->clkin >> 2; + } + else if(st->clkin <= 6400000000ull) + { + st->sysref_delay_div = SYSREF_DELAY_DIV_PL8_3_2_GHZ_TO_6_4_GHZ; + f_interpol = st->clkin >> 3; + } + else + { + st->sysref_delay_div = SYSREF_DELAY_DIV_PL16_6_4_GHZ_TO_12_8_GHZ; + f_interpol = st->clkin >> 4; + } + + if(st->sysref_mode == SYSREF_MODE_REPEATER_REPEATER_MODE) + { + if(st->sysrefout != st->sysrefreq) + { + USDR_LOG("1204", USDR_LOG_ERROR, "[SYSREF] SYSREFREQ must be equal to SYSREFOUT for repeater mode"); + return -EINVAL; + } + } + else + { + if(f_interpol % (uint64_t)st->sysrefout) + { + USDR_LOG("1204", USDR_LOG_ERROR, "[SYSREF] F_INTERPOL:%" PRIu64 " %% SYSREFOUTCLK:%.0f != 0", f_interpol, st->sysrefout); + return -EINVAL; + } + + unsigned div_pre, div; + unsigned min_div_pre = MAX(log2f(ceil((double)st->clkin / SYSREF_DIV_PRE_OUT_MAX)), SYSREF_DIV_PRE_PL1); + + bool found = true; + + for(div_pre = min_div_pre; div_pre <= SYSREF_DIV_PRE_PL4; ++div_pre) + { + div = (unsigned)((st->clkin >> div_pre) / st->sysrefout + 0.5); + if(div < SYSREF_DIV_MIN) + { + USDR_LOG("1204", USDR_LOG_ERROR, "SYSREFOUT:%.4f too high", st->sysrefout); + return -EINVAL; + } + if(div > SYSREF_DIV_MAX) + continue; + + if(st->clkin != (((uint64_t)st->sysrefout * div) << div_pre)) + { + USDR_LOG("1204", USDR_LOG_ERROR, "SYSREFOUT:%.4f cannot be solved in integers", st->sysrefout); + return -EINVAL; + } + break; + } + + if(!found) + { + USDR_LOG("1204", USDR_LOG_ERROR, "Cannot solve SYSREFOUT:%.4f", st->sysrefout); + return -EINVAL; + } + } + + //SUCCESS LOG + } + else + { + USDR_LOG("1204", USDR_LOG_DEBUG, "[SYSREFCLK]:disabled"); + } + + + return 0; +} + + + diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index 497fe172..775ff276 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -6,15 +6,61 @@ #include +#define LMX1204_OUT_CNT 4 + struct lmx1204_state { - lldev_t dev; + lldev_t dev; unsigned subdev; unsigned lsaddr; + uint64_t clkin; + uint64_t sysrefreq; + bool filter_mode; //affects when clkin==clkout + uint8_t sysref_mode; //enum sysref_mode_options + + bool sysref_en; + + bool ch_en[LMX1204_OUT_CNT]; + bool clkout_en[LMX1204_OUT_CNT]; + bool sysrefout_en[LMX1204_OUT_CNT]; + + bool logic_en; + bool logiclkout_en; + bool logisysrefout_en; + + double clkout; + double sysrefout; + double logiclkout; + + uint8_t logiclkout_fmt; + uint8_t logisysrefout_fmt; + + // + + uint8_t clk_mux; //enum clk_mux_options + uint8_t clk_mult_div; + + uint8_t smclk_div_pre; + uint8_t smclk_div; + + uint8_t logiclk_div_pre; + uint16_t logiclk_div; + + uint8_t sysref_delay_div; + uint8_t sysref_div_pre; + uint16_t sysref_div; }; typedef struct lmx1204_state lmx1204_state_t; +enum +{ + LMX1204_FMT_LVDS = 0, + LMX1204_FMT_LVPECL = 1, + LMX1204_FMT_CML = 2, +}; + + int lmx1204_get_temperature(lmx1204_state_t* st, float* value); int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st); int lmx1204_destroy(lmx1204_state_t* st); diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 798ba604..79111d52 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -3,6 +3,7 @@ #include #include +#include #include "def_lmx1214.h" #include "lmx1214.h" @@ -10,6 +11,8 @@ #include "lmx1214_dump.h" +#define FREQ_EPS 1.0f + enum { CLKIN_MIN = 300000000ull, @@ -324,7 +327,12 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, USDR_LOG("1214", USDR_LOG_ERROR, "CLK_DIV:%u out of range", clk_div); return -EINVAL; } - + double f = (double)in / clk_div; + if(fabs(f - out) > FREQ_EPS) + { + USDR_LOG("1214", USDR_LOG_ERROR, "Calculated CLKOUT:%.4f too rough", f); + return -EINVAL; + } if(prec_mode && in != out * clk_div) { USDR_LOG("1214", USDR_LOG_ERROR, "Cannot solve CLKOUT:%" PRIu64 " by int divider", out); @@ -372,11 +380,17 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, continue; unsigned div = (unsigned)(fmid / aux->freq + 0.5); - if(prec_mode && fmid != aux->freq * div) - continue; + if(div < AUXCLK_DIV_MIN || div > AUXCLK_DIV_MAX) continue; + double f = fmid / div; + if(fabs(f - aux->freq) > FREQ_EPS) + continue; + + if(prec_mode && fmid != aux->freq * div) + continue; + found = true; auxclk_div = div; break; From 1625f787dbeeaf4bddf48d753899fc60f1cb5ca9 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 12 Apr 2025 00:02:10 +0300 Subject: [PATCH 082/397] lmx1204 - solver completed (except registers), unit-test added --- src/lib/hw/lmx1204/lmx1204.c | 74 ++++++++++++++++++++++++++++++++---- src/lib/hw/lmx1204/lmx1204.h | 8 ++++ src/utests/CMakeLists.txt | 1 + src/utests/test_suite.c | 3 +- 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 51bf6902..6ea89ce5 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -218,7 +218,7 @@ static int lmx1204_solver_prevalidate(lmx1204_state_t* st) { case CLK_MUX_DIVIDER_MODE: fmin = CLKOUT_MIN_DIV; fmax = CLKOUT_MAX_DIV; break; case CLK_MUX_MULTIPLIER_MODE: fmin = CLKOUT_MIN_MUL; fmax = CLKOUT_MAX_MUL; break; - case CLK_MUX_BUFFER_MODE: fmin = CLKOUT_MIN_BUF; fmax = CLKOUT_MIN_BUF; break; + case CLK_MUX_BUFFER_MODE: fmin = CLKOUT_MIN_BUF; fmax = CLKOUT_MAX_BUF; break; default: USDR_LOG("1204", USDR_LOG_ERROR, "CLK_MUX:%u unknown", st->clk_mux); return -EINVAL; @@ -235,9 +235,9 @@ static int lmx1204_solver_prevalidate(lmx1204_state_t* st) fmin = SYSREFOUT_MIN; switch(st->sysref_mode) { - case SYSREF_MODE_CONTINUOUS_GENERATOR_MODE: fmax = SYSREFOUT_MAX_GENMODE; break; - case SYSREF_MODE_REPEATER_REPEATER_MODE: fmax = SYSREFOUT_MAX_RPTMODE; break; - case SYSREF_MODE_PULSER_GENERATOR_MODE: fmax = 0.0f; break; + case LMX1204_CONTINUOUS: st->sysref_mode = SYSREF_MODE_CONTINUOUS_GENERATOR_MODE; fmax = SYSREFOUT_MAX_GENMODE; break; + case LMX1204_REPEATER: st->sysref_mode = SYSREF_MODE_REPEATER_REPEATER_MODE; fmax = SYSREFOUT_MAX_RPTMODE; break; + case LMX1204_PULSER: st->sysref_mode = SYSREF_MODE_PULSER_GENERATOR_MODE; fmax = 0.0f; break; default: USDR_LOG("1204", USDR_LOG_ERROR, "SYSREF_MODE:%u unknown", st->sysref_mode); return -EINVAL; @@ -293,8 +293,30 @@ static const char* lmx1204_decode_clkmux(enum clk_mux_options mux) return "UNKNOWN"; } +static const char* lmx1204_decode_sysref_mode(enum sysref_mode_options sm) +{ + switch(sm) + { + case SYSREF_MODE_CONTINUOUS_GENERATOR_MODE: return "CONTINUOUS_GENERATOR"; + case SYSREF_MODE_PULSER_GENERATOR_MODE: return "PULSER_GENERATOR"; + case SYSREF_MODE_REPEATER_REPEATER_MODE: return "REPEATER"; + } + return "UNKNOWN"; +} + +static const char* lmx1204_decode_fmt(enum logiclkout_fmt_options fmt) +{ + switch(fmt) + { + case LOGICLKOUT_FMT_LVDS : return "LVDS"; + case LOGICLKOUT_FMT_LVPECL: return "LVPECL"; + case LOGICLKOUT_FMT_CML: return "CML"; + } + return "UNKNOWN"; +} + // all params are in lmx1204_state_t struct -int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) +int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) { int res; enum clk_mux_options clk_mux; @@ -376,7 +398,7 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) else if(div_pre > SMCLK_DIV_PRE_PL4 && div_pre <= SMCLK_DIV_PRE_PL8) div_pre = SMCLK_DIV_PRE_PL8; else - return -EINVAL; //impossible + div_pre = SMCLK_DIV_PRE_PL2; double fdiv = (double)st->clkin / div_pre / SMCLK_DIV_OUT_MAX; unsigned n = MAX(ceil(log2(fdiv)), SMCLK_DIV_PL1); @@ -430,6 +452,9 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) continue; if(prec_mode && st->clkin != st->logiclkout * div_pre * div) continue; + + found = true; + break; } if(!found) { @@ -476,6 +501,15 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) f_interpol = st->clkin >> 4; } + if(f_interpol <= 200000000ull) + st->sysref_delay_scale = SYSREFOUT0_DELAY_SCALE_150_MHZ_TO_200_MHZ; + else if(f_interpol <= 400000000ull) + st->sysref_delay_scale = SYSREFOUT0_DELAY_SCALE_200_MHZ_TO_400_MHZ; + else + st->sysref_delay_scale = SYSREFOUT0_DELAY_SCALE_400_MHZ_TO_800_MHZ; + + unsigned div_pre = SYSREF_DIV_PRE_PL4, div = 0x3; //defaults + if(st->sysref_mode == SYSREF_MODE_REPEATER_REPEATER_MODE) { if(st->sysrefout != st->sysrefreq) @@ -492,7 +526,6 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) return -EINVAL; } - unsigned div_pre, div; unsigned min_div_pre = MAX(log2f(ceil((double)st->clkin / SYSREF_DIV_PRE_OUT_MAX)), SYSREF_DIV_PRE_PL1); bool found = true; @@ -513,6 +546,8 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) USDR_LOG("1204", USDR_LOG_ERROR, "SYSREFOUT:%.4f cannot be solved in integers", st->sysrefout); return -EINVAL; } + + found = true; break; } @@ -523,13 +558,36 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode) } } - //SUCCESS LOG + st->sysref_div_pre = div_pre; + st->sysref_div = div; + + USDR_LOG("1204", USDR_LOG_DEBUG, "[SYSREFCLK] SYSREFREQ:%" PRIu64 " SYSREF_MODE:%s(%u) SYSREFOUT:%.4f", + st->sysrefreq, lmx1204_decode_sysref_mode(st->sysref_mode), st->sysref_mode, st->sysrefout); + + if(st->sysref_mode != SYSREF_MODE_REPEATER_REPEATER_MODE) + { + USDR_LOG("1204", USDR_LOG_DEBUG, "[SYSREFCLK] SYSREF_DELAY_DIV:%u F_INTERPOL:%" PRIu64 " DELAY_SCALE:%u SYSREF_DIV_PRE:%u(%u) SYSREF_DIV:%u", + st->sysref_delay_div, f_interpol, st->sysref_delay_scale, (1 << st->sysref_div_pre), st->sysref_div_pre, st->sysref_div); + } } else { USDR_LOG("1204", USDR_LOG_DEBUG, "[SYSREFCLK]:disabled"); } + // succesfull solution + USDR_LOG("1204", USDR_LOG_INFO, "LMX1204 SOLUTION FOUND:"); + USDR_LOG("1204", USDR_LOG_INFO, "CLKIN:%" PRIu64 " SYSREFREQ:%" PRIu64, st->clkin, st->sysrefreq); + for(unsigned i = 0; i < LMX1204_OUT_CNT; ++i) + { + USDR_LOG("1204", USDR_LOG_INFO, "CLKOUT%u :%.4f EN:%u", i, st->clkout, st->ch_en[0] && st->clkout_en[0]); + USDR_LOG("1204", USDR_LOG_INFO, "SYSREFOUT%u:%.4f EN:%u", i, st->sysrefout, st->sysref_en && st->ch_en[0] && st->sysrefout_en[0]); + } + USDR_LOG("1204", USDR_LOG_INFO, "LOGICLKOUT :%.4f EN:%u FMT:%s", + st->logiclkout, st->logic_en && st->logiclkout_en, lmx1204_decode_fmt(st->logiclkout_fmt)); + USDR_LOG("1204", USDR_LOG_INFO, "LOGICSYSREFOUT:%.4f EN:%u FMT:%s", + st->sysrefout, st->sysref_en && st->logic_en && st->logisysrefout_en, lmx1204_decode_fmt(st->logisysrefout_fmt)); + USDR_LOG("1204", USDR_LOG_INFO, "--------------"); return 0; } diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index 775ff276..d82167aa 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -50,6 +50,7 @@ struct lmx1204_state uint8_t sysref_delay_div; uint8_t sysref_div_pre; uint16_t sysref_div; + uint8_t sysref_delay_scale; }; typedef struct lmx1204_state lmx1204_state_t; @@ -60,7 +61,14 @@ enum LMX1204_FMT_CML = 2, }; +enum +{ + LMX1204_CONTINUOUS = 0, + LMX1204_PULSER = 1, + LMX1204_REPEATER = 2, +}; +int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run); int lmx1204_get_temperature(lmx1204_state_t* st, float* value); int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st); int lmx1204_destroy(lmx1204_state_t* st); diff --git a/src/utests/CMakeLists.txt b/src/utests/CMakeLists.txt index fc21089a..bb2ddc3e 100644 --- a/src/utests/CMakeLists.txt +++ b/src/utests/CMakeLists.txt @@ -15,6 +15,7 @@ set(TEST_SUIT_SRCS lmk05318_solver_test.c lmx2820_solver_test.c lmx1214_solver_test.c + lmx1204_solver_test.c ) include_directories(../lib/xdsp) diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index 1907bc42..c599d74b 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -14,6 +14,7 @@ Suite * clockgen_suite(void); Suite * lmk05318_solver_suite(void); Suite * lmx2820_solver_suite(void); Suite * lmx1214_solver_suite(void); +Suite * lmx1204_solver_suite(void); int main(int argc, char** argv) { @@ -36,7 +37,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, lmx2820_solver_suite()); srunner_add_suite(sr, lmx1214_solver_suite()); #else - sr = srunner_create(lmx1214_solver_suite()); + sr = srunner_create(lmx1204_solver_suite()); #endif srunner_set_fork_status (sr, CK_NOFORK); From 2aa6dac4c195340b08a4c2460aa676a1f979102d Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 12 Apr 2025 15:09:59 +0300 Subject: [PATCH 083/397] lmx1204 add regs, lock etc --- src/lib/hw/lmx1204/lmx1204.c | 147 +++++++++++++++++++++++++++++++++++ src/lib/hw/lmx1204/lmx1204.h | 12 +++ 2 files changed, 159 insertions(+) diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 6ea89ce5..ae15eb2f 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -161,6 +161,54 @@ int lmx1204_get_temperature(lmx1204_state_t* st, float* value) return 0; } +static inline const char* lmx1204_decode_lock_status(enum rb_ld_options ld) +{ + switch(ld) + { + case RB_LD_UNLOCKED_VTUNE_LOW: return "UNLOCKED (VTUNE low)"; + case RB_LD_UNLOCKED_VTUNE_HIGH: return "UNLOCKED (VTUNE high)"; + case RB_LD_LOCKED: return "LOCKED"; + } + return "UNKNOWN"; +} + +static inline const char* lmx1204_decode_vco_core(enum rb_vco_sel_options c) +{ + switch(c) + { + case RB_VCO_SEL_VCO5: return "VCO5"; + case RB_VCO_SEL_VCO4: return "VCO4"; + case RB_VCO_SEL_VCO3: return "VCO3"; + case RB_VCO_SEL_VCO2: return "VCO2"; + case RB_VCO_SEL_VCO1: return "VCO1"; + } + return "UNKNOWN"; +} + +int lmx1204_read_status(lmx1204_state_t* st, lmx1204_stats_t* status) +{ + if(!status) + return -EINVAL; + + uint16_t r75, r65; + + int res = lmx1204_get_temperature(st, &status->temperature); + res = res ? res : lmx1204_spi_get(st, R75, &r75); + res = res ? res : lmx1204_spi_get(st, R65, &r65); + if(res) + return res; + + status->vco_sel = (r65 & RB_VCO_SEL_MSK) >> RB_VCO_SEL_OFF; + status->lock_detect_status = (r75 & RB_LD_MSK) >> RB_LD_OFF; + + USDR_LOG("1204", USDR_LOG_DEBUG, "STATUS> Temp:%.2fC LOCK:%u(%s) VCO_SEL:%u(%s)", + status->temperature, + status->lock_detect_status, lmx1204_decode_lock_status(status->lock_detect_status), + status->vco_sel, lmx1204_decode_vco_core(status->vco_sel)); + + return 0; +} + int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st) { memset(st, 0, sizeof(*st)); @@ -465,6 +513,7 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) st->logiclkout = logiclkout_fact; st->logiclk_div_pre = div_pre; + st->logiclk_div_bypass = (div == 0); st->logiclk_div = div; USDR_LOG("1204", USDR_LOG_DEBUG, "[LOGICLKOUT] LOGICLK_DIV_PRE:%u LOGICLK_DIV:%u%s LOGICLKOUT:%.4f", @@ -589,8 +638,106 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) st->sysrefout, st->sysref_en && st->logic_en && st->logisysrefout_en, lmx1204_decode_fmt(st->logisysrefout_fmt)); USDR_LOG("1204", USDR_LOG_INFO, "--------------"); + //registers + uint32_t regs[] = + { + MAKE_LMX1204_R0(0, 0, 0, 1), //set RESET bit first + // + MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 + MAKE_LMX1204_R72(0, 0, 0, 0, SYSREF_DELAY_BYPASS_ENGAGE_IN_GENERATOR_MODE__BYPASS_IN_REPEATER_MODE), + + // need for MULT VCO calibration + MAKE_LMX1204_R67(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x51cb : 0x50c8), + MAKE_LMX1204_R34(0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x04c5 : 0), + MAKE_LMX1204_R33(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x5666 : 0x7777), + // + + MAKE_LMX1204_R25(0x4, 0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? st->clk_mult_div : st->clk_mult_div - 1, st->clk_mux), + MAKE_LMX1204_R23(1, 1, 1, 0, 1, st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_scale), + MAKE_LMX1204_R22(st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_div, 0, 0), + + MAKE_LMX1204_R17(0, 0x7f, 0, st->sysref_mode), + MAKE_LMX1204_R16(0x1, st->sysref_div), + MAKE_LMX1204_R15(0, st->sysref_div_pre, 0x3, st->sysref_en ? 1 : 0, 0, 0), + + //according do doc: program R79 and R90 before setting logiclk_div_bypass + //desc order is broken here! + MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->logic_en ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), + MAKE_LMX1204_R79(0, st->logiclk_div_bypass ? 0x5 : 0x104), + MAKE_LMX1204_REG_WR(R90, st->logiclk_div_bypass ? 0x60 : 0x00), + MAKE_LMX1204_R9(0, 0, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), + // + + MAKE_LMX1204_R7(0, 0, 0, 0, 0, 0, 0, st->logisysrefout_en ? 1 : 0), + MAKE_LMX1204_R6(st->logiclkout_en, 0x3, 0x3, 0x3, 0x3, 0x4), + MAKE_LMX1204_R4(0, 0x6, 0x6, + st->sysrefout_en[3], st->sysrefout_en[2], st->sysrefout_en[1], st->sysrefout_en[0], + st->clkout_en[3], st->clkout_en[2], st->clkout_en[1], st->clkout_en[0]), + MAKE_LMX1204_R3(st->ch_en[3], st->ch_en[2], st->ch_en[1], st->ch_en[0], 1, 1, 1, 1, 1, 0, st->smclk_div), + MAKE_LMX1204_R2(0,0,st->smclk_div_pre, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 1 : 0, 0x3), + // + MAKE_LMX1204_R0(0, 0, 0, 0), + }; + + res = dry_run ? lmx1204_print_registers(regs, SIZEOF_ARRAY(regs)) : lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + return res; + + return 0; +} + +int lmx1204_calibrate(lmx1204_state_t* st) +{ + if(st->clk_mux != CLK_MUX_MULTIPLIER_MODE) + { + USDR_LOG("1204", USDR_LOG_DEBUG, "VCO calibration not needed for BUFFER & DIV modes"); + return 0; + } + + uint32_t regs[] = + { + MAKE_LMX1204_R67(0x51cb), + MAKE_LMX1204_R34(0, 0x04c5), + MAKE_LMX1204_R33(0x5666), + MAKE_LMX1204_R0(0, 0, 0, 0), + }; + + int res = lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + return res; + return 0; } +int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout) +{ + int res = 0; + unsigned elapsed = 0; + + if(st->clk_mux != CLK_MUX_MULTIPLIER_MODE) + { + USDR_LOG("1204", USDR_LOG_DEBUG, "VCO lock not needed for BUFFER & DIV modes"); + return 0; + } + + uint16_t r75; + while(timeout == 0 || elapsed < timeout) + { + res = lmx1204_spi_get(st, R75, &r75); + if(res) + return res; + + const uint16_t lock_detect_status = (r75 & RB_LD_MSK) >> RB_LD_OFF; + switch(lock_detect_status) + { + case RB_LD_LOCKED: return 0; + default: + usleep(100); + elapsed += 100; + } + } + + return -ETIMEDOUT; +} diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index d82167aa..4210d3ac 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -45,6 +45,7 @@ struct lmx1204_state uint8_t smclk_div; uint8_t logiclk_div_pre; + bool logiclk_div_bypass; uint16_t logiclk_div; uint8_t sysref_delay_div; @@ -54,6 +55,14 @@ struct lmx1204_state }; typedef struct lmx1204_state lmx1204_state_t; +struct lmx1204_stats +{ + float temperature; + uint8_t vco_sel; + uint8_t lock_detect_status; +}; +typedef struct lmx1204_stats lmx1204_stats_t; + enum { LMX1204_FMT_LVDS = 0, @@ -68,6 +77,9 @@ enum LMX1204_REPEATER = 2, }; +int lmx1204_read_status(lmx1204_state_t* st, lmx1204_stats_t* status); +int lmx1204_calibrate(lmx1204_state_t* st); +int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout); int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run); int lmx1204_get_temperature(lmx1204_state_t* st, float* value); int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st); From 5093b96416c7488d88012a6e04facfcbcd3b2747 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 12 Apr 2025 15:31:58 +0300 Subject: [PATCH 084/397] add LMX2820[0] & LMX1204 to pe_sync --- src/lib/device/pe_sync/pe_sync.c | 75 +++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index c0fc3bdf..65dd0278 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -339,6 +339,31 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMK03518 outputs synced"); // + // + //LMX2820 #0 setup + // + + const uint64_t lmx0_freq[] = + { + 1400000000, + 1400000000 + }; + + res = lmx2820_create(dev, 0, SPI_LMX2820_0, &d->lmx0); + res = res ? res : lmx2820_tune(&d->lmx0, lmk_freq[2], 2 /*mash order 2*/, 0 /*force_mult*/, lmx0_freq[0], lmx0_freq[1]); + + lmx2820_stats_t lmxstatus0; + lmx2820_read_status(&d->lmx0, &lmxstatus0); //just for logging + + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX2820[0] PLL not locked during specified timeout"); + return res; + } + + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820[0] outputs locked & synced"); + // + // //LMX2820 #1 setup // @@ -352,8 +377,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], 2 /*mash order 2*/, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); - lmx2820_stats_t lmxstatus; - lmx2820_read_status(&d->lmx1, &lmxstatus); //just for logging + lmx2820_stats_t lmxstatus1; + lmx2820_read_status(&d->lmx1, &lmxstatus1); //just for logging if(res) { @@ -401,6 +426,52 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; } + //set 1204 params + d->cldistr.clkin = lmx0_freq[0]; + d->cldistr.sysrefreq = lmx0_freq[1]; + d->cldistr.clkout = d->cldistr.clkin * 4; + d->cldistr.sysrefout = 4375000; + d->cldistr.sysref_mode = LMX1204_CONTINUOUS; + d->cldistr.logiclkout = 1400000; + + d->cldistr.ch_en[0] = 1; + d->cldistr.ch_en[1] = 1; + d->cldistr.ch_en[2] = 1; + d->cldistr.ch_en[3] = 1; + + d->cldistr.clkout_en[0] = 1; + d->cldistr.clkout_en[1] = 1; + d->cldistr.clkout_en[2] = 1; + d->cldistr.clkout_en[3] = 1; + + d->cldistr.sysref_en = 1; + d->cldistr.sysrefout_en[0] = 1; + d->cldistr.sysrefout_en[1] = 1; + d->cldistr.sysrefout_en[2] = 1; + d->cldistr.sysrefout_en[3] = 1; + + d->cldistr.logic_en = 1; + d->cldistr.logiclkout_en = 1; + d->cldistr.logisysrefout_en = 1; + d->cldistr.logiclkout_fmt = LMX1204_FMT_LVDS; + d->cldistr.logisysrefout_fmt = LMX1204_FMT_LVDS; + // + res = lmx1204_solver(&d->cldistr, false/*prec_mode*/, false/*dry_run*/); + if(res) + return res; + + res = lmx1204_wait_pll_lock(&d->cldistr, 10000); + + lmx1204_stats_t lmx1204status; + lmx1204_read_status(&d->cldistr, &lmx1204status); //just for log + + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX1204 not locked, err:%d", res); + return res; + } + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1204 locked"); + USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1204 initialized"); // From 50a6533b4686b76f43a4fb16ca7055547617f052 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 12 Apr 2025 15:43:30 +0300 Subject: [PATCH 085/397] minor changes --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/utests/lmx2820_solver_test.c | 13 +++++++++++++ src/utests/test_suite.c | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 65dd0278..deee08e1 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -346,7 +346,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const uint64_t lmx0_freq[] = { 1400000000, - 1400000000 + 175000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_0, &d->lmx0); diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index 3e9bd7bd..071319d6 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -157,6 +157,18 @@ START_TEST(lmx2820_solver_test13_pesync) ck_assert_int_eq( res, 0 ); } +START_TEST(lmx2820_solver_test14_pesync) +{ + const uint64_t osc_in = 250000000ull; + const int mash_order = 2; + uint64_t out_freq1 = 1400000000ull; + uint64_t out_freq2 = 175000000; //1400000000ull; + + int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); + ck_assert_int_eq( res, 0 ); +} + + Suite * lmx2820_solver_suite(void) { Suite *s; @@ -180,6 +192,7 @@ Suite * lmx2820_solver_suite(void) tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 1, 4); tcase_add_test(tc_core, lmx2820_solver_test12_instcal); tcase_add_test(tc_core, lmx2820_solver_test13_pesync); + tcase_add_test(tc_core, lmx2820_solver_test14_pesync); suite_add_tcase(s, tc_core); return s; diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index c599d74b..a189e1ab 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -36,6 +36,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, lmk05318_solver_suite()); srunner_add_suite(sr, lmx2820_solver_suite()); srunner_add_suite(sr, lmx1214_solver_suite()); + srunner_add_suite(sr, lmx1204_solver_suite()); #else sr = srunner_create(lmx1204_solver_suite()); #endif From cfd14890899352d5dbd287bf4efb678d650d825d Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 12 Apr 2025 18:42:25 +0300 Subject: [PATCH 086/397] add forgotten test --- src/utests/lmx1204_solver_test.c | 116 +++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/utests/lmx1204_solver_test.c diff --git a/src/utests/lmx1204_solver_test.c b/src/utests/lmx1204_solver_test.c new file mode 100644 index 00000000..66f0b0d7 --- /dev/null +++ b/src/utests/lmx1204_solver_test.c @@ -0,0 +1,116 @@ +#include +#include +#include "lmx1204/lmx1204.h" + +static lmx1204_state_t st; + +static void setup() +{ + memset(&st, 0, sizeof(st)); + + st.ch_en[0] = 1; + st.ch_en[1] = 1; + st.ch_en[2] = 1; + st.ch_en[3] = 1; + + st.clkout_en[0] = 1; + st.clkout_en[1] = 1; + st.clkout_en[2] = 1; + st.clkout_en[3] = 1; + + st.sysref_en = 1; + st.sysrefout_en[0] = 1; + st.sysrefout_en[1] = 1; + st.sysrefout_en[2] = 1; + st.sysrefout_en[3] = 1; + + st.logic_en = 1; + st.logiclkout_en = 1; + st.logisysrefout_en = 1; + + st.logiclkout_fmt = LMX1204_FMT_LVDS; + st.logisysrefout_fmt = LMX1204_FMT_LVDS; +} + +static void teardown() {} + +START_TEST(lmx1204_solver_test1) +{ + st.clkin = 12800000000; + st.clkout = st.clkin; + + st.sysrefreq = 1000000; + st.sysrefout = st.sysrefreq; + st.sysref_mode = LMX1204_REPEATER; + + st.logiclkout = 400000000; + + int res = lmx1204_solver(&st, false, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1204_solver_test2) +{ + st.clkin = 12800000000; + st.clkout = st.clkin; + + st.sysrefreq = 0; + st.sysrefout = 40000000; + st.sysref_mode = LMX1204_CONTINUOUS; + + st.logiclkout = 8000000; + + int res = lmx1204_solver(&st, false, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1204_solver_test3) +{ + st.clkin = 6400000000; + st.clkout = st.clkin; + st.filter_mode = 1; + + st.sysrefreq = 0; + st.sysrefout = 20000000; + st.sysref_mode = LMX1204_CONTINUOUS; + + st.logiclkout = 4000000; + + int res = lmx1204_solver(&st, false, true); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmx1204_solver_test4) +{ + st.clkin = 1400000000; + st.clkout = st.clkin * 4; + + st.sysrefreq = 0; + st.sysrefout = 4375000; + st.sysref_mode = LMX1204_CONTINUOUS; + + st.logiclkout = 1400000; + + int res = lmx1204_solver(&st, false, true); + ck_assert_int_eq( res, 0 ); +} + +Suite * lmx1204_solver_suite(void) +{ + Suite *s; + TCase *tc_core; + + s = suite_create("lmx1204_solver"); + tc_core = tcase_create("HW"); + tcase_set_timeout(tc_core, 1); + tcase_add_checked_fixture(tc_core, setup, teardown); + + tcase_add_test(tc_core, lmx1204_solver_test1); + tcase_add_test(tc_core, lmx1204_solver_test2); + tcase_add_test(tc_core, lmx1204_solver_test3); + tcase_add_test(tc_core, lmx1204_solver_test4); + + suite_add_tcase(s, tc_core); + return s; +} + From e1f2c63a3f5397a522704cc966cb0f379976a743 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 12 Apr 2025 19:50:28 +0300 Subject: [PATCH 087/397] LMK05380 add log --- src/lib/hw/lmk05318/lmk05318.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 2763060a..95f38a44 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -733,6 +733,18 @@ int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) return lmk05318_add_reg_to_map(d, ®, 1); } +static inline const char* lmk05318_decode_fmt(unsigned f) +{ + switch (f) { + case LVDS: return "OUT_OPTS_AC_LVDS"; + case CML: return "OUT_OPTS_AC_CML"; + case LVPECL: return "OUT_OPTS_AC_LVPECL"; + case LVCMOS: return "OUT_OPTS_LVCMOS_P_N"; + default: return "OUT_OPTS_Disabled"; + } + return "UNKNOWN"; +} + static int lmk05318_set_out_mux_ex(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) { unsigned ot; @@ -1483,9 +1495,9 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(!is_freq_ok) complete_solution_check = false; - USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.8f mux:%d(%s)] %s", + USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.8f mux:%d(%s) fmt:%u(%s)] %s", out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux, - lmk05318_decode_mux(out_dst->result.mux), + lmk05318_decode_mux(out_dst->result.mux), out_dst->wanted.type, lmk05318_decode_fmt(out_dst->wanted.type), is_freq_ok ? "**OK**" : "**BAD**"); } @@ -1522,6 +1534,9 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned if(out->wanted.freq == 0) continue; + USDR_LOG("5318", USDR_LOG_DEBUG, "OUT%u port:%u div:%" PRIu64 " fmt:%u(%s)", + i, out->port, out->result.out_div, out->wanted.type, lmk05318_decode_fmt(out->wanted.type)); + res = lmk05318_set_out_mux_ex(d, out->port, out->result.mux, out->wanted.type); res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); if(res) From 724b3a9cecb3deb62772a2c9376fe69bda62cf33 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 12 Apr 2025 21:48:42 +0300 Subject: [PATCH 088/397] sporadic fixes to make lmx2820 work --- src/lib/device/pe_sync/pe_sync.c | 16 ++++++++++++---- src/lib/hw/lmx1204/lmx1204.c | 2 ++ src/lib/hw/lmx2820/lmx2820.c | 10 +++++----- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index deee08e1..a79e6a01 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -166,6 +166,14 @@ static void usdr_device_pe_sync_destroy(pdevice_t udev) // struct dev_pe_sync *d = (struct dev_pe_sync *)udev; // lldev_t dev = d->base.dev; // TODO: power off + + struct dev_pe_sync *d = (struct dev_pe_sync *)udev; + lldev_t dev = d->base.dev; + + dev_gpo_set(dev, IGPO_DISTRIB_CTRL, 0); + dev_gpo_set(dev, IGPO_SY0_CTRL, 0); + dev_gpo_set(dev, IGPO_SY1_CTRL, 0); + usdr_device_base_destroy(udev); } @@ -344,10 +352,10 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // const uint64_t lmx0_freq[] = - { - 1400000000, - 175000000 - }; + { + 1400000000, + 1400000000 + }; res = lmx2820_create(dev, 0, SPI_LMX2820_0, &d->lmx0); res = res ? res : lmx2820_tune(&d->lmx0, lmk_freq[2], 2 /*mash order 2*/, 0 /*force_mult*/, lmx0_freq[0], lmx0_freq[1]); diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index ae15eb2f..b1e21c1b 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -683,6 +683,8 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) if(res) return res; + usleep(10000); + return 0; } diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 10c95ccc..294af17a 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -166,7 +166,7 @@ int lmx2820_sync(lmx2820_state_t* st) return lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); } -#define LMX2820_RESET_SKIP +//#define LMX2820_RESET_SKIP int lmx2820_reset(lmx2820_state_t* st) #ifdef LMX2820_RESET_SKIP @@ -191,7 +191,7 @@ int lmx2820_reset(lmx2820_state_t* st) if(res) return res; - usleep(5); //reset takes <1us + usleep(10000); //reset takes <1us return 0; } #endif @@ -229,7 +229,7 @@ int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) const uint16_t lock_detect_status = (r74 & RB_LD_MSK) >> RB_LD_OFF; switch(lock_detect_status) { - case RB_LD_INVALID: return -EINVAL; + //case RB_LD_INVALID: return -EINVAL; case RB_LD_LOCKED: return 0; default: usleep(100); @@ -324,8 +324,6 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ if(res) return res; - usleep(2); //reset takes less 1 us. - //this list is incompleted uint32_t regs[] = { @@ -339,6 +337,8 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ return res; } + usleep(10000); + lmx2820_stats_t status; res = lmx2820_read_status(st, &status); if(res) From fcdf1c27cb8168881cbb876bcf9cccbe683f479c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 13 Apr 2025 14:30:48 +0300 Subject: [PATCH 089/397] LMX1204 individual sysref delays settings --- src/lib/device/pe_sync/pe_sync.c | 57 +++++++++++---------- src/lib/hw/lmx1204/lmx1204.c | 87 +++++++++++++++++++++++++------- src/lib/hw/lmx1204/lmx1204.h | 39 +++++++++++--- src/utests/lmx1204_solver_test.c | 39 +++++++------- 4 files changed, 152 insertions(+), 70 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index a79e6a01..ef685f93 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -435,34 +435,35 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const } //set 1204 params - d->cldistr.clkin = lmx0_freq[0]; - d->cldistr.sysrefreq = lmx0_freq[1]; - d->cldistr.clkout = d->cldistr.clkin * 4; - d->cldistr.sysrefout = 4375000; - d->cldistr.sysref_mode = LMX1204_CONTINUOUS; - d->cldistr.logiclkout = 1400000; - - d->cldistr.ch_en[0] = 1; - d->cldistr.ch_en[1] = 1; - d->cldistr.ch_en[2] = 1; - d->cldistr.ch_en[3] = 1; - - d->cldistr.clkout_en[0] = 1; - d->cldistr.clkout_en[1] = 1; - d->cldistr.clkout_en[2] = 1; - d->cldistr.clkout_en[3] = 1; - - d->cldistr.sysref_en = 1; - d->cldistr.sysrefout_en[0] = 1; - d->cldistr.sysrefout_en[1] = 1; - d->cldistr.sysrefout_en[2] = 1; - d->cldistr.sysrefout_en[3] = 1; - - d->cldistr.logic_en = 1; - d->cldistr.logiclkout_en = 1; - d->cldistr.logisysrefout_en = 1; - d->cldistr.logiclkout_fmt = LMX1204_FMT_LVDS; - d->cldistr.logisysrefout_fmt = LMX1204_FMT_LVDS; + lmx1204_state_t* lmx1204 = &d->cldistr; + lmx1204->clkin = lmx0_freq[0]; + lmx1204->sysrefreq = lmx0_freq[1]; + lmx1204->clkout = d->cldistr.clkin * 4; + lmx1204->sysrefout = 4375000; + lmx1204->sysref_mode = LMX1204_CONTINUOUS; + lmx1204->logiclkout = 1400000; + + lmx1204->ch_en[LMX1204_CH0] = 1; + lmx1204->ch_en[LMX1204_CH1] = 1; + lmx1204->ch_en[LMX1204_CH2] = 1; + lmx1204->ch_en[LMX1204_CH3] = 1; + lmx1204->ch_en[LMX1204_CH_LOGIC] = 1; + + lmx1204->clkout_en[LMX1204_CH0] = 1; + lmx1204->clkout_en[LMX1204_CH1] = 1; + lmx1204->clkout_en[LMX1204_CH2] = 1; + lmx1204->clkout_en[LMX1204_CH3] = 1; + lmx1204->clkout_en[LMX1204_CH_LOGIC] = 1; + + lmx1204->sysref_en = 1; + lmx1204->sysrefout_en[LMX1204_CH0] = 1; + lmx1204->sysrefout_en[LMX1204_CH1] = 1; + lmx1204->sysrefout_en[LMX1204_CH2] = 1; + lmx1204->sysrefout_en[LMX1204_CH3] = 1; + lmx1204->sysrefout_en[LMX1204_CH_LOGIC] = 1; + + lmx1204->logiclkout_fmt = LMX1204_FMT_LVDS; + lmx1204->logisysrefout_fmt = LMX1204_FMT_LVDS; // res = lmx1204_solver(&d->cldistr, false/*prec_mode*/, false/*dry_run*/); if(res) diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index b1e21c1b..d818ac41 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -218,6 +218,16 @@ int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_ st->subdev = subdev; st->lsaddr = lsaddr; + //SYSREF individual channel delays defaults (according to TICS Pro) + //Could be overriden before solver call (lmx1204_set_sysrefout_ch_delay()) + for(unsigned i = 0; i < SIZEOF_ARRAY(st->sysref_indiv_ch_delay); ++i) + { + lmx1204_sysrefout_channel_delay_t* d = &st->sysref_indiv_ch_delay[i]; + d->phase = SYSREFOUT0_DELAY_PHASE_QCLK0; + d->i = 7; + d->q = 0x7f - d->i; + } + uint32_t regs[] = { MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 @@ -253,7 +263,7 @@ static int lmx1204_solver_prevalidate(lmx1204_state_t* st) return -EINVAL; } - if(st->logic_en && st->logiclkout_en && (st->logiclkout < LOGICLKOUT_MIN || st->logiclkout > LOGICLKOUT_MAX)) + if(st->ch_en[LMX1204_CH_LOGIC] && st->clkout_en[LMX1204_CH_LOGIC] && (st->logiclkout < LOGICLKOUT_MIN || st->logiclkout > LOGICLKOUT_MAX)) { USDR_LOG("1204", USDR_LOG_ERROR, "LOGICLKOUT:%.4f out of range [%" PRIu64 "; %" PRIu64 "]", st->logiclkout, (uint64_t)LOGICLKOUT_MIN, (uint64_t)LOGICLKOUT_MAX); @@ -296,11 +306,36 @@ static int lmx1204_solver_prevalidate(lmx1204_state_t* st) USDR_LOG("1204", USDR_LOG_ERROR, "SYSREFOUT:%.4f out of range [%.0f; %.0f]", st->sysrefout, fmin, fmax); return -EINVAL; } + + for(unsigned i = 0; i < SIZEOF_ARRAY(st->sysref_indiv_ch_delay); ++i) + { + if(!st->ch_en[i]) + continue; //do not check if channel is disabled + + lmx1204_sysrefout_channel_delay_t* d = &st->sysref_indiv_ch_delay[i]; + + switch(d->phase) + { + case SYSREFOUT0_DELAY_PHASE_ICLK0: + case SYSREFOUT0_DELAY_PHASE_QCLK0: + case SYSREFOUT0_DELAY_PHASE_QCLK1: + case SYSREFOUT0_DELAY_PHASE_ICLK1: break; + default: + USDR_LOG("1204", USDR_LOG_ERROR, "SYSREFOUT[%u] delay phase:%u is invalid", i, d->phase); + return -EINVAL; + } + + if(d->i + d->q != 0x7f) + { + USDR_LOG("1204", USDR_LOG_ERROR, "SYSREFOUT[%u] delay I:%u + Q:%u != 127", i, d->i, d->q); + return -EINVAL; + } + } } - if(st->logic_en) + if(st->ch_en[LMX1204_CH_LOGIC]) { - if(st->logiclkout_en) + if(st->clkout_en[LMX1204_CH_LOGIC]) { switch(st->logiclkout_fmt) { @@ -313,7 +348,7 @@ static int lmx1204_solver_prevalidate(lmx1204_state_t* st) } } - if(st->sysref_en && st->logisysrefout_en) + if(st->sysref_en && st->sysrefout_en[LMX1204_CH_LOGIC]) { switch(st->logisysrefout_fmt) { @@ -465,7 +500,7 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) } //need to setup LOGICLKOUT - if(st->logic_en && st->logiclkout_en) + if(st->ch_en[LMX1204_CH_LOGIC] && st->clkout_en[LMX1204_CH_LOGIC]) { unsigned div_pre, div; double logiclkout_fact; @@ -633,9 +668,9 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) USDR_LOG("1204", USDR_LOG_INFO, "SYSREFOUT%u:%.4f EN:%u", i, st->sysrefout, st->sysref_en && st->ch_en[0] && st->sysrefout_en[0]); } USDR_LOG("1204", USDR_LOG_INFO, "LOGICLKOUT :%.4f EN:%u FMT:%s", - st->logiclkout, st->logic_en && st->logiclkout_en, lmx1204_decode_fmt(st->logiclkout_fmt)); + st->logiclkout, st->ch_en[LMX1204_CH_LOGIC] && st->clkout_en[LMX1204_CH_LOGIC], lmx1204_decode_fmt(st->logiclkout_fmt)); USDR_LOG("1204", USDR_LOG_INFO, "LOGICSYSREFOUT:%.4f EN:%u FMT:%s", - st->sysrefout, st->sysref_en && st->logic_en && st->logisysrefout_en, lmx1204_decode_fmt(st->logisysrefout_fmt)); + st->sysrefout, st->sysref_en && st->ch_en[LMX1204_CH_LOGIC] && st->sysrefout_en[LMX1204_CH_LOGIC], lmx1204_decode_fmt(st->logisysrefout_fmt)); USDR_LOG("1204", USDR_LOG_INFO, "--------------"); //registers @@ -654,29 +689,32 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) MAKE_LMX1204_R25(0x4, 0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? st->clk_mult_div : st->clk_mult_div - 1, st->clk_mux), MAKE_LMX1204_R23(1, 1, 1, 0, 1, st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_scale), - MAKE_LMX1204_R22(st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_div, 0, 0), - - MAKE_LMX1204_R17(0, 0x7f, 0, st->sysref_mode), - MAKE_LMX1204_R16(0x1, st->sysref_div), + MAKE_LMX1204_R22(st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_div, 0, st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].q), + MAKE_LMX1204_R21(st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].i, st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].phase, st->sysref_indiv_ch_delay[LMX1204_CH3].q), + MAKE_LMX1204_R20(st->sysref_indiv_ch_delay[LMX1204_CH3].i, st->sysref_indiv_ch_delay[LMX1204_CH3].phase, st->sysref_indiv_ch_delay[LMX1204_CH2].q), + MAKE_LMX1204_R19(st->sysref_indiv_ch_delay[LMX1204_CH2].i, st->sysref_indiv_ch_delay[LMX1204_CH2].phase, st->sysref_indiv_ch_delay[LMX1204_CH1].q), + MAKE_LMX1204_R18(st->sysref_indiv_ch_delay[LMX1204_CH1].i, st->sysref_indiv_ch_delay[LMX1204_CH1].phase, st->sysref_indiv_ch_delay[LMX1204_CH0].q), + MAKE_LMX1204_R17(0, st->sysref_indiv_ch_delay[LMX1204_CH0].i, st->sysref_indiv_ch_delay[LMX1204_CH0].phase, st->sysref_mode), + MAKE_LMX1204_R16(0x1, st->sysref_div), //0x1 == sysref pulse count MAKE_LMX1204_R15(0, st->sysref_div_pre, 0x3, st->sysref_en ? 1 : 0, 0, 0), //according do doc: program R79 and R90 before setting logiclk_div_bypass //desc order is broken here! - MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->logic_en ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), + MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->ch_en[LMX1204_CH_LOGIC] ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), MAKE_LMX1204_R79(0, st->logiclk_div_bypass ? 0x5 : 0x104), MAKE_LMX1204_REG_WR(R90, st->logiclk_div_bypass ? 0x60 : 0x00), MAKE_LMX1204_R9(0, 0, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), // - MAKE_LMX1204_R7(0, 0, 0, 0, 0, 0, 0, st->logisysrefout_en ? 1 : 0), - MAKE_LMX1204_R6(st->logiclkout_en, 0x3, 0x3, 0x3, 0x3, 0x4), + MAKE_LMX1204_R7(0, 0, 0, 0, 0, 0, 0, st->sysrefout_en[LMX1204_CH_LOGIC] ? 1 : 0), + MAKE_LMX1204_R6(st->clkout_en[LMX1204_CH_LOGIC], 0x3, 0x3, 0x3, 0x3, 0x4), MAKE_LMX1204_R4(0, 0x6, 0x6, - st->sysrefout_en[3], st->sysrefout_en[2], st->sysrefout_en[1], st->sysrefout_en[0], - st->clkout_en[3], st->clkout_en[2], st->clkout_en[1], st->clkout_en[0]), - MAKE_LMX1204_R3(st->ch_en[3], st->ch_en[2], st->ch_en[1], st->ch_en[0], 1, 1, 1, 1, 1, 0, st->smclk_div), + st->sysrefout_en[LMX1204_CH3], st->sysrefout_en[LMX1204_CH2], st->sysrefout_en[LMX1204_CH1], st->sysrefout_en[LMX1204_CH0], + st->clkout_en[LMX1204_CH3], st->clkout_en[LMX1204_CH2], st->clkout_en[LMX1204_CH1], st->clkout_en[LMX1204_CH0]), + MAKE_LMX1204_R3(st->ch_en[LMX1204_CH3], st->ch_en[LMX1204_CH2], st->ch_en[LMX1204_CH1], st->ch_en[LMX1204_CH0], 1, 1, 1, 1, 1, 0, st->smclk_div), MAKE_LMX1204_R2(0,0,st->smclk_div_pre, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 1 : 0, 0x3), // - MAKE_LMX1204_R0(0, 0, 0, 0), + MAKE_LMX1204_R0(0, 0, 0, 0), //reset RESET bit last }; res = dry_run ? lmx1204_print_registers(regs, SIZEOF_ARRAY(regs)) : lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); @@ -742,4 +780,17 @@ int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout) return -ETIMEDOUT; } +int lmx1204_reload_sysrefout_ch_delay(lmx1204_state_t* st) +{ + uint32_t regs[] = + { + MAKE_LMX1204_R22(st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_div, 0, st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].q), + MAKE_LMX1204_R21(st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].i, st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].phase, st->sysref_indiv_ch_delay[LMX1204_CH3].q), + MAKE_LMX1204_R20(st->sysref_indiv_ch_delay[LMX1204_CH3].i, st->sysref_indiv_ch_delay[LMX1204_CH3].phase, st->sysref_indiv_ch_delay[LMX1204_CH2].q), + MAKE_LMX1204_R19(st->sysref_indiv_ch_delay[LMX1204_CH2].i, st->sysref_indiv_ch_delay[LMX1204_CH2].phase, st->sysref_indiv_ch_delay[LMX1204_CH1].q), + MAKE_LMX1204_R18(st->sysref_indiv_ch_delay[LMX1204_CH1].i, st->sysref_indiv_ch_delay[LMX1204_CH1].phase, st->sysref_indiv_ch_delay[LMX1204_CH0].q), + MAKE_LMX1204_R17(0, st->sysref_indiv_ch_delay[LMX1204_CH0].i, st->sysref_indiv_ch_delay[LMX1204_CH0].phase, st->sysref_mode), + }; + return lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); +} diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index 4210d3ac..2d631ce8 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -8,6 +8,23 @@ #define LMX1204_OUT_CNT 4 +enum +{ + LMX1204_CH0 = 0, + LMX1204_CH1 = 1, + LMX1204_CH2 = 2, + LMX1204_CH3 = 3, + LMX1204_CH_LOGIC = 4, +}; + +struct lmx1204_sysrefout_channel_delay +{ + uint8_t phase; + uint8_t q; + uint8_t i; +}; +typedef struct lmx1204_sysrefout_channel_delay lmx1204_sysrefout_channel_delay_t; + struct lmx1204_state { lldev_t dev; @@ -21,13 +38,9 @@ struct lmx1204_state bool sysref_en; - bool ch_en[LMX1204_OUT_CNT]; - bool clkout_en[LMX1204_OUT_CNT]; - bool sysrefout_en[LMX1204_OUT_CNT]; - - bool logic_en; - bool logiclkout_en; - bool logisysrefout_en; + bool ch_en[LMX1204_OUT_CNT + 1]; // 4 + logic ch + bool clkout_en[LMX1204_OUT_CNT + 1]; + bool sysrefout_en[LMX1204_OUT_CNT + 1]; double clkout; double sysrefout; @@ -52,9 +65,20 @@ struct lmx1204_state uint8_t sysref_div_pre; uint16_t sysref_div; uint8_t sysref_delay_scale; + lmx1204_sysrefout_channel_delay_t sysref_indiv_ch_delay[LMX1204_OUT_CNT + 1]; // 4 + logic ch }; typedef struct lmx1204_state lmx1204_state_t; +static inline void lmx1204_init_sysrefout_ch_delay(lmx1204_state_t* st, unsigned ch, uint8_t phase, uint8_t i, uint8_t q) +{ + if(ch > LMX1204_CH_LOGIC) + return; + + st->sysref_indiv_ch_delay[ch].phase = phase; + st->sysref_indiv_ch_delay[ch].i = i; + st->sysref_indiv_ch_delay[ch].q = q; +} + struct lmx1204_stats { float temperature; @@ -82,6 +106,7 @@ int lmx1204_calibrate(lmx1204_state_t* st); int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout); int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run); int lmx1204_get_temperature(lmx1204_state_t* st, float* value); +int lmx1204_reload_sysrefout_ch_delay(lmx1204_state_t* st); int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st); int lmx1204_destroy(lmx1204_state_t* st); diff --git a/src/utests/lmx1204_solver_test.c b/src/utests/lmx1204_solver_test.c index 66f0b0d7..5098a2b2 100644 --- a/src/utests/lmx1204_solver_test.c +++ b/src/utests/lmx1204_solver_test.c @@ -8,28 +8,33 @@ static void setup() { memset(&st, 0, sizeof(st)); - st.ch_en[0] = 1; - st.ch_en[1] = 1; - st.ch_en[2] = 1; - st.ch_en[3] = 1; - - st.clkout_en[0] = 1; - st.clkout_en[1] = 1; - st.clkout_en[2] = 1; - st.clkout_en[3] = 1; + st.ch_en[LMX1204_CH0] = 1; + st.ch_en[LMX1204_CH1] = 1; + st.ch_en[LMX1204_CH2] = 1; + st.ch_en[LMX1204_CH3] = 1; + st.ch_en[LMX1204_CH_LOGIC] = 1; + + st.clkout_en[LMX1204_CH0] = 1; + st.clkout_en[LMX1204_CH1] = 1; + st.clkout_en[LMX1204_CH2] = 1; + st.clkout_en[LMX1204_CH3] = 1; + st.clkout_en[LMX1204_CH_LOGIC] = 1; st.sysref_en = 1; - st.sysrefout_en[0] = 1; - st.sysrefout_en[1] = 1; - st.sysrefout_en[2] = 1; - st.sysrefout_en[3] = 1; - - st.logic_en = 1; - st.logiclkout_en = 1; - st.logisysrefout_en = 1; + st.sysrefout_en[LMX1204_CH0] = 1; + st.sysrefout_en[LMX1204_CH1] = 1; + st.sysrefout_en[LMX1204_CH2] = 1; + st.sysrefout_en[LMX1204_CH3] = 1; + st.sysrefout_en[LMX1204_CH_LOGIC] = 1; st.logiclkout_fmt = LMX1204_FMT_LVDS; st.logisysrefout_fmt = LMX1204_FMT_LVDS; + + lmx1204_init_sysrefout_ch_delay(&st, LMX1204_CH0, 1/*SYSREFOUT0_DELAY_PHASE_QCLK0*/, 7, 120); + lmx1204_init_sysrefout_ch_delay(&st, LMX1204_CH1, 1/*SYSREFOUT0_DELAY_PHASE_QCLK0*/, 7, 120); + lmx1204_init_sysrefout_ch_delay(&st, LMX1204_CH2, 1/*SYSREFOUT0_DELAY_PHASE_QCLK0*/, 7, 120); + lmx1204_init_sysrefout_ch_delay(&st, LMX1204_CH3, 1/*SYSREFOUT0_DELAY_PHASE_QCLK0*/, 7, 120); + lmx1204_init_sysrefout_ch_delay(&st, LMX1204_CH_LOGIC, 1/*SYSREFOUT0_DELAY_PHASE_QCLK0*/, 7, 120); } static void teardown() {} From 260757d54cfd7d965c43af9d0a7bfe85f0882cb8 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 13 Apr 2025 22:42:39 +0300 Subject: [PATCH 090/397] LMX1204/1214 sync wnd capture + refactoring --- src/lib/cal/opt_func.c | 39 ++++++++++++ src/lib/cal/opt_func.h | 1 + src/lib/hw/CMakeLists.txt | 2 +- src/lib/hw/common/common.c | 81 +++++++++++++++++++++++++ src/lib/hw/common/common.h | 10 ++++ src/lib/hw/lmx1204/lmx1204.c | 109 +++++++++++++++++++++++++++++++++ src/lib/hw/lmx1204/lmx1204.h | 3 + src/lib/hw/lmx1214/lmx1214.c | 113 ++++++++++++++++++++++++----------- src/lib/hw/lmx1214/lmx1214.h | 5 +- 9 files changed, 325 insertions(+), 38 deletions(-) create mode 100644 src/lib/hw/common/common.c create mode 100644 src/lib/hw/common/common.h diff --git a/src/lib/cal/opt_func.c b/src/lib/cal/opt_func.c index 56112122..2dd923e4 100644 --- a/src/lib/cal/opt_func.c +++ b/src/lib/cal/opt_func.c @@ -4,6 +4,7 @@ #include "opt_func.h" #include #include +#include int find_golden_min(int start, int stop, void* param, evaluate_fn_t fn, int* px, int* pv, int exparam) { @@ -203,3 +204,41 @@ uint64_t find_gcd(uint64_t a, uint64_t b) return find_gcd((b - a) >> 1, a); } + +void binary_print_u32_reverse(uint32_t x, char* s) +{ + sprintf(s, "%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u", + (x >> 0) & 0x1, + (x >> 1) & 0x1, + (x >> 2) & 0x1, + (x >> 3) & 0x1, + (x >> 4) & 0x1, + (x >> 5) & 0x1, + (x >> 6) & 0x1, + (x >> 7) & 0x1, + (x >> 8) & 0x1, + (x >> 9) & 0x1, + (x >> 10) & 0x1, + (x >> 11) & 0x1, + (x >> 12) & 0x1, + (x >> 13) & 0x1, + (x >> 14) & 0x1, + (x >> 15) & 0x1, + (x >> 16) & 0x1, + (x >> 17) & 0x1, + (x >> 18) & 0x1, + (x >> 19) & 0x1, + (x >> 20) & 0x1, + (x >> 21) & 0x1, + (x >> 22) & 0x1, + (x >> 23) & 0x1, + (x >> 24) & 0x1, + (x >> 25) & 0x1, + (x >> 26) & 0x1, + (x >> 27) & 0x1, + (x >> 28) & 0x1, + (x >> 29) & 0x1, + (x >> 30) & 0x1, + (x >> 31) & 0x1 + ); +} diff --git a/src/lib/cal/opt_func.h b/src/lib/cal/opt_func.h index 14a639dc..a9a71331 100644 --- a/src/lib/cal/opt_func.h +++ b/src/lib/cal/opt_func.h @@ -57,5 +57,6 @@ int find_best_2d(struct opt_iteration2d *ops, unsigned max_count, void* param, i int *px, int *py, int *pfxy); uint64_t find_gcd(uint64_t a, uint64_t b); +void binary_print_u32_reverse(uint32_t x, char* s); #endif diff --git a/src/lib/hw/CMakeLists.txt b/src/lib/hw/CMakeLists.txt index 2282e881..cbe453b1 100644 --- a/src/lib/hw/CMakeLists.txt +++ b/src/lib/hw/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) 2023-2024 Wavelet Lab # SPDX-License-Identifier: MIT -set(HW_FILES si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 +set(HW_FILES common si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820) # YAML registers generators set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 diff --git a/src/lib/hw/common/common.c b/src/lib/hw/common/common.c new file mode 100644 index 00000000..fa7b9429 --- /dev/null +++ b/src/lib/hw/common/common.c @@ -0,0 +1,81 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "usdr_logging.h" +#include "../cal/opt_func.h" + +int common_ti_calc_sync_delay(uint32_t clkpos, unsigned* calced_delay) +{ + const unsigned WBSIZE = sizeof(uint32_t) * 8; + + char tmps[WBSIZE + 1]; + + binary_print_u32_reverse(clkpos, tmps); + USDR_LOG("COMN", USDR_LOG_DEBUG, "WINDOW DATA:0b%s", tmps); + + //MSB & LSB should be 1 + if((clkpos & 0x80000001) != 0x80000001) + { + USDR_LOG("COMN", USDR_LOG_ERROR, "Window data is inconstent, check capture conditions"); + return -EINVAL; + } + + unsigned i = 0; + uint8_t idx_found[WBSIZE]; + + while(i < WBSIZE) + { + uint32_t v = clkpos >> i; + + if((v & 0b1111) == 0b1101 || (v & 0b1111) == 0b1011) + { + idx_found[i] = 1; + i += 4; + } + else if((v & 0b111) == 0b111) + { + idx_found[i] = 1; + i += 3; + } + else if((v & 0b11) == 0b11) + { + idx_found[i] = 1; + i += 2; + } + + idx_found[i++] = 0; + } + + uint8_t first_raise = 0xff, second_raise = 0xff; + for(unsigned i = 0; i < WBSIZE; ++i) + { + if(idx_found[i]) + { + if(first_raise == 0xff) + first_raise = i; + else + { + second_raise = i; + break; + } + } + } + + if(first_raise == 0xff || second_raise == 0xff) + { + USDR_LOG("COMN", USDR_LOG_ERROR, "Clock raise patterns not found, cannot determine delay"); + return -EINVAL; + } + + unsigned delay = (second_raise + first_raise) >> 1; + if(!delay || delay > 0x3f) + { + USDR_LOG("COMN", USDR_LOG_ERROR, "Invalid calculated delay:%u, out of range (0; 0x3f)", delay); + return -EINVAL; + } + USDR_LOG("COMN", USDR_LOG_DEBUG, "SYSREF vs CLOCK delay:%u", delay); + + *calced_delay = delay; + return 0; +} diff --git a/src/lib/hw/common/common.h b/src/lib/hw/common/common.h new file mode 100644 index 00000000..449be522 --- /dev/null +++ b/src/lib/hw/common/common.h @@ -0,0 +1,10 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT +#ifndef HW_COMMON_H +#define HW_COMMON_H + +#include "stdint.h" + +int common_ti_calc_sync_delay(uint32_t clkpos, unsigned* calced_delay); + +#endif // HW_COMMON_H diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index d818ac41..e03b0d1d 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -10,6 +10,8 @@ #include "usdr_logging.h" #include "../cal/opt_func.h" +#include "../common/common.h" + #define FREQ_EPS 1.0f enum @@ -143,6 +145,18 @@ UNUSED static int lmx1204_read_all_regs(lmx1204_state_t* st) return 0; } +static int lmx1204_reset_main_divider(lmx1204_state_t* st, bool set_flag) +{ + uint16_t r25; + + int res = lmx1204_spi_get(st, R25, &r25); + if(res) + return res; + + uint32_t reg = MAKE_LMX1204_REG_WR(R25, set_flag ? (r25 | CLK_DIV_RST_MSK) : (r25 & ~CLK_DIV_RST_MSK)); + return lmx1204_spi_post(st, ®, 1); +} + int lmx1204_get_temperature(lmx1204_state_t* st, float* value) { if(!value) @@ -674,6 +688,14 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) USDR_LOG("1204", USDR_LOG_INFO, "--------------"); //registers + + res = dry_run ? 0 : lmx1204_reset_main_divider(st, true); + if(res) + { + USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_reset_main_divider(1) err:%d", res); + return res; + } + uint32_t regs[] = { MAKE_LMX1204_R0(0, 0, 0, 1), //set RESET bit first @@ -723,6 +745,13 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) usleep(10000); + res = dry_run ? 0 : lmx1204_reset_main_divider(st, false); + if(res) + { + USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_reset_main_divider(0) err:%d", res); + return res; + } + return 0; } @@ -794,3 +823,83 @@ int lmx1204_reload_sysrefout_ch_delay(lmx1204_state_t* st) return lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); } + +int lmx1204_sysref_windowing_beforesync(lmx1204_state_t* st) +{ + int res; + + uint8_t delay_step_size = SYSREFREQ_DELAY_STEPSIZE_28_PS_1_4_GHZ_TO_2_7_GHZ; + if(st->clkin > 2400000000 && st->clkin <= 4700000000) + delay_step_size = SYSREFREQ_DELAY_STEPSIZE_15_PS_2_4_GHZ_TO_4_7_GHZ; + if(st->clkin > 3100000000 && st->clkin <= 5700000000) + delay_step_size = SYSREFREQ_DELAY_STEPSIZE_11_PS_3_1_GHZ_TO_5_7_GHZ; + if(st->clkin > 4500000000 && st->clkin <= 12800000000) + delay_step_size = SYSREFREQ_DELAY_STEPSIZE_8_PS_4_5_GHZ_TO_12_8_GHZ; + + USDR_LOG("1204", USDR_LOG_DEBUG, "DELAY_STEPSIZE:%u", delay_step_size); + + { + uint32_t regs[] = + { + MAKE_LMX1204_R9(0, 1/*SYNC_EN*/, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), + MAKE_LMX1204_R14(0, 0, 0, 1/*CLKPOS_CAPTURE_EN*/, 1, 0), + MAKE_LMX1204_R13(0, delay_step_size), + }; + + res = lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + return res; + } + + { + uint16_t r15; + res = lmx1204_spi_get(st, R15, &r15); + if(res) + return res; + + uint32_t regval_set = MAKE_LMX1204_REG_WR(R15, r15 | SYSREFREQ_CLR_MSK); + uint32_t regval_rst = MAKE_LMX1204_REG_WR(R15, r15 & ~SYSREFREQ_CLR_MSK); + + res = lmx1204_spi_post(st, ®val_set, 1); + res = res ? res : lmx1204_spi_post(st, ®val_rst, 1); + } + + return res; +} + +int lmx1204_sysref_windowing_aftersync(lmx1204_state_t* st) +{ + uint32_t regs[] = + { + MAKE_LMX1204_R9(0, 0/*SYNC_EN*/, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), + MAKE_LMX1204_R14(0, 0, 0, 0/*CLKPOS_CAPTURE_EN*/, 1, 0), + }; + return lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); +} + +int lmx1204_sysref_windowing_capture(lmx1204_state_t* st) +{ + int res; + uint16_t r11, r12; + + res = lmx1204_spi_get(st, R11, &r11); + res = res ? res : lmx1204_spi_get(st, R12, &r12); + if(res) + return res; + + uint32_t clkpos = ((uint32_t)r12 << 16) | r11; + + unsigned delay; + res = common_ti_calc_sync_delay(clkpos, &delay); + if(res) + return res; + + { + uint32_t reg = MAKE_LMX1204_R15(0, st->sysref_div_pre, 0x3, st->sysref_en ? 1 : 0, delay, 0); + res = lmx1204_spi_post(st, ®, 1); + if(res) + return res; + } + + return 0; +} diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index 2d631ce8..2115831c 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -110,5 +110,8 @@ int lmx1204_reload_sysrefout_ch_delay(lmx1204_state_t* st); int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_t* st); int lmx1204_destroy(lmx1204_state_t* st); +int lmx1204_sysref_windowing_beforesync(lmx1204_state_t* st); +int lmx1204_sysref_windowing_capture(lmx1204_state_t* st); +int lmx1204_sysref_windowing_aftersync(lmx1204_state_t* st); #endif // LMX1204_H diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 79111d52..41dbfb11 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -8,6 +8,7 @@ #include "def_lmx1214.h" #include "lmx1214.h" #include "usdr_logging.h" +#include "../common/common.h" #include "lmx1214_dump.h" @@ -132,24 +133,6 @@ UNUSED static int lmx1214_loaddump(lmx1214_state_t* st) return res; } -int lmx1214_sync_clr(lmx1214_state_t* st) -{ - uint16_t r15; - - int res = lmx1214_spi_get(st, R15, &r15); - if(res) - return res; - - uint32_t regs[] = - { - MAKE_LMX1214_REG_WR(R15, r15 & ~SYNC_CLR_MSK), - MAKE_LMX1214_REG_WR(R15, r15 | SYNC_CLR_MSK), - MAKE_LMX1214_REG_WR(R15, r15 & ~SYNC_CLR_MSK), - }; - - return lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs));; -} - int lmx1214_get_temperature(lmx1214_state_t* st, float* value) { if(!value) @@ -438,24 +421,18 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, return res; } - uint8_t sync_dly_step = 0; - if(in >= 4500000000) - sync_dly_step = 3; - else if(in > 3100000000 && in <= 5700000000) - sync_dly_step = 2; - else if(in > 2400000000 && in <= 4700000000) - sync_dly_step = 1; - - USDR_LOG("1214", USDR_LOG_DEBUG, "CLKIN:%" PRIu64 " -> SYNC_DLY_STEP:%u", in, sync_dly_step); - uint32_t regs[] = { - MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), - MAKE_LMX1214_R79(0, 0x5), MAKE_LMX1214_R25(0x4, 0, st->clk_div - 1, st->clk_mux), - MAKE_LMX1214_R14(0, 1, 1, 0), //set CLKPOS_CAPTURE_EN - MAKE_LMX1214_R9 (0, 1, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), + MAKE_LMX1214_R14(0, 0, 1, 0), + + //according do doc: program R79 and R90 before setting logiclk_div_bypass + //desc order is broken here! MAKE_LMX1214_R8 (0, st->auxclk_div_pre, 0, (st->auxclkout.enable ? 1 : 0), 0, st->auxclkout.fmt), + MAKE_LMX1214_R79(0, st->auxclk_div_byp ? 0x5 : 0x104 /*0x205*/), + MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), + + MAKE_LMX1214_R9 (0, 0, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), MAKE_LMX1214_R3 (st->clkout_enabled[3] ? 1 : 0, st->clkout_enabled[2] ? 1 : 0, st->clkout_enabled[1] ? 1 : 0, @@ -471,6 +448,8 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, return res; } + usleep(10000); + res = dry_run ? 0 : lmx1214_reset_main_divider(st, false); if(res) { @@ -481,20 +460,82 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, return 0; } -int lmx1214_windowing(lmx1214_state_t* st) +int lmx1214_sysref_windowing_beforesync(lmx1214_state_t* st) +{ + int res; + + uint8_t delay_step_size = SYNC_DLY_STEP_28_PS_1_4GHZ_TO_2_7GHZ; + if(st->clkin > 2400000000 && st->clkin <= 4700000000) + delay_step_size = SYNC_DLY_STEP_15_PS__2_4GHZ_TO_4_7GHZ; + if(st->clkin > 3100000000 && st->clkin <= 5700000000) + delay_step_size = SYNC_DLY_STEP_11_PS_3_1GHZ_TO_5_7GHZ; + if(st->clkin > 4500000000 && st->clkin <= 12800000000) + delay_step_size = SYNC_DLY_STEP_8_PS_4_5GHZ_TO_12_8GHZ; + + USDR_LOG("1214", USDR_LOG_DEBUG, "DELAY_STEPSIZE:%u", delay_step_size); + + { + uint32_t regs[] = + { + MAKE_LMX1214_R9 (0, 1/*SYNC_EN*/, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), + MAKE_LMX1214_R14(0, 1/*CLKPOS_CAPTURE_EN*/, 1, 0), + MAKE_LMX1214_R13(0, delay_step_size), + }; + + res = lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + return res; + } + + { + uint16_t r15; + res = lmx1214_spi_get(st, R15, &r15); + if(res) + return res; + + uint32_t regval_set = MAKE_LMX1214_REG_WR(R15, r15 | SYNC_CLR_MSK); + uint32_t regval_rst = MAKE_LMX1214_REG_WR(R15, r15 & ~SYNC_CLR_MSK); + + res = lmx1214_spi_post(st, ®val_set, 1); + res = res ? res : lmx1214_spi_post(st, ®val_rst, 1); + } + + return res; +} + +int lmx1214_sysref_windowing_aftersync(lmx1214_state_t* st) +{ + uint32_t regs[] = + { + MAKE_LMX1214_R9 (0, 0/*SYNC_EN*/, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), + MAKE_LMX1214_R14(0, 0/*CLKPOS_CAPTURE_EN*/, 1, 0), + }; + return lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); +} + +int lmx1214_sysref_windowing_capture(lmx1214_state_t* st) { int res; uint16_t r11, r12; res = lmx1214_spi_get(st, R11, &r11); - res = res ? 0 : lmx1214_spi_get(st, R12, &r12); + res = res ? res : lmx1214_spi_get(st, R12, &r12); if(res) return res; uint32_t clkpos = ((uint32_t)r12 << 16) | r11; - //USDR_LOG(USDR_LOG_DEBUG, "CLKPOS:0b%b", clkpos); - //TODO + unsigned delay; + res = common_ti_calc_sync_delay(clkpos, &delay); + if(res) + return res; + + { + uint32_t reg = MAKE_LMX1214_R15(0, 0x16, delay, 0); + res = lmx1214_spi_post(st, ®, 1); + if(res) + return res; + } return 0; } diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index d60713db..3147e8e3 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -48,6 +48,9 @@ int lmx1214_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1214_state_ int lmx1214_destroy(lmx1214_state_t* st); int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, lmx1214_auxclkout_cfg_t* aux, bool prec_mode, bool dry_run); int lmx1214_get_temperature(lmx1214_state_t* st, float* value); -int lmx1214_sync_clr(lmx1214_state_t* st); + +int lmx1214_sysref_windowing_beforesync(lmx1214_state_t* st); +int lmx1214_sysref_windowing_capture(lmx1214_state_t* st); +int lmx1214_sysref_windowing_aftersync(lmx1214_state_t* st); #endif // LMX1214_H From 0cef8ab4c7229f9787ff2675553138c68162b257 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 15 Apr 2025 12:37:06 +0300 Subject: [PATCH 091/397] move spi common funcs to common.c --- src/lib/hw/common/common.c | 42 ++++++++++++++++++++++++++++++++++++ src/lib/hw/common/common.h | 14 +++++++++++- src/lib/hw/lmx1204/lmx1204.c | 39 ++++++--------------------------- src/lib/hw/lmx1214/lmx1214.c | 41 ++++++----------------------------- src/lib/hw/lmx2820/lmx2820.c | 33 ++++++---------------------- 5 files changed, 74 insertions(+), 95 deletions(-) diff --git a/src/lib/hw/common/common.c b/src/lib/hw/common/common.c index fa7b9429..946c3637 100644 --- a/src/lib/hw/common/common.c +++ b/src/lib/hw/common/common.c @@ -79,3 +79,45 @@ int common_ti_calc_sync_delay(uint32_t clkpos, unsigned* calced_delay) *calced_delay = delay; return 0; } + +int common_print_registers_a8d16(uint32_t* regs, unsigned count, int loglevel) +{ + for (unsigned i = 0; i < count; i++) + { + uint8_t ra = regs[i] >> 16; + uint16_t rv = (uint16_t)regs[i]; + USDR_LOG("COMN", loglevel, "WRITE#%u: R%03u (0x%02x) -> 0x%04x [0x%06x]", i, ra, ra, rv, regs[i]); + } + + return 0; +} + +int common_spi_post(void* o, uint32_t* regs, unsigned count) +{ + int res; + const common_hw_state_struct_t* obj = (common_hw_state_struct_t*)o; + + for (unsigned i = 0; i < count; i++) { + res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); + if (res) + return res; + + USDR_LOG("COMN", USDR_LOG_NOTE, "[%d/%d] reg wr %08x\n", i, count, regs[i]); + } + + return 0; +} + +int common_spi_get(void* o, uint16_t addr, uint16_t* out) +{ + uint32_t v; + const common_hw_state_struct_t* obj = (common_hw_state_struct_t*)o; + + int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, addr, &v); + if (res) + return res; + + USDR_LOG("COMN", USDR_LOG_NOTE, " reg rd %04x => %08x\n", addr, v); + *out = v; + return 0; +} diff --git a/src/lib/hw/common/common.h b/src/lib/hw/common/common.h index 449be522..6dd5f1cd 100644 --- a/src/lib/hw/common/common.h +++ b/src/lib/hw/common/common.h @@ -3,8 +3,20 @@ #ifndef HW_COMMON_H #define HW_COMMON_H -#include "stdint.h" +#include "usdr_lowlevel.h" + +struct common_hw_state_struct +{ + lldev_t dev; + unsigned subdev; + unsigned lsaddr; +}; +typedef struct common_hw_state_struct common_hw_state_struct_t; + int common_ti_calc_sync_delay(uint32_t clkpos, unsigned* calced_delay); +int common_print_registers_a8d16(uint32_t* regs, unsigned count, int loglevel); +int common_spi_post(void* o, uint32_t* regs, unsigned count); +int common_spi_get(void* o, uint16_t addr, uint16_t* out); #endif // HW_COMMON_H diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index e03b0d1d..12e9333f 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -52,44 +52,17 @@ enum SYSREF_DIV_MAX = 4095, }; -static int lmx1204_print_registers(uint32_t* regs, unsigned count) -{ - for (unsigned i = 0; i < count; i++) - { - uint8_t rn = regs[i] >> 16; - uint16_t rv = (uint16_t)regs[i]; - USDR_LOG("1204", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%02x) -> 0x%04x [0x%06x]", i, rn, rn, rv, regs[i]); - } - - return 0; -} - static int lmx1204_spi_post(lmx1204_state_t* obj, uint32_t* regs, unsigned count) { - int res; - lmx1204_print_registers(regs, count); - - for (unsigned i = 0; i < count; i++) { - res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); - if (res) - return res; - - USDR_LOG("1204", USDR_LOG_NOTE, "[%d/%d] reg wr %08x\n", i, count, regs[i]); - } - - return 0; + return + common_print_registers_a8d16(regs, count, USDR_LOG_DEBUG) + || + common_spi_post(obj, regs, count); } static int lmx1204_spi_get(lmx1204_state_t* obj, uint16_t addr, uint16_t* out) { - uint32_t v; - int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, MAKE_LMX1204_REG_RD((uint32_t)addr), &v); - if (res) - return res; - - USDR_LOG("1204", USDR_LOG_NOTE, " reg rd %04x => %08x\n", addr, v); - *out = v; - return 0; + return common_spi_get(obj, MAKE_LMX1204_REG_RD((uint32_t)addr), out); } UNUSED static int lmx1204_read_all_regs(lmx1204_state_t* st) @@ -739,7 +712,7 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) MAKE_LMX1204_R0(0, 0, 0, 0), //reset RESET bit last }; - res = dry_run ? lmx1204_print_registers(regs, SIZEOF_ARRAY(regs)) : lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); + res = dry_run ? common_print_registers_a8d16(regs, SIZEOF_ARRAY(regs), USDR_LOG_DEBUG) : lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) return res; diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 41dbfb11..1fc129bf 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -41,44 +41,17 @@ enum AUXCLK_DIV_MAX = 1023, }; -static int lmx1214_print_registers(uint32_t* regs, unsigned count) -{ - for (unsigned i = 0; i < count; i++) - { - uint8_t rn = regs[i] >> 16; - uint16_t rv = (uint16_t)regs[i]; - USDR_LOG("1214", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%02x) -> 0x%04x [0x%06x]", i, rn, rn, rv, regs[i]); - } - - return 0; -} - static int lmx1214_spi_post(lmx1214_state_t* obj, uint32_t* regs, unsigned count) { - int res; - lmx1214_print_registers(regs, count); - - for (unsigned i = 0; i < count; i++) { - res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); - if (res) - return res; - - USDR_LOG("1214", USDR_LOG_NOTE, "[%d/%d] reg wr %08x\n", i, count, regs[i]); - } - - return 0; + return + common_print_registers_a8d16(regs, count, USDR_LOG_DEBUG) + || + common_spi_post(obj, regs, count); } static int lmx1214_spi_get(lmx1214_state_t* obj, uint16_t addr, uint16_t* out) { - uint32_t v; - int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, MAKE_LMX1214_REG_RD((uint32_t)addr), &v); - if (res) - return res; - - USDR_LOG("1214", USDR_LOG_NOTE, " reg rd %04x => %08x\n", addr, v); - *out = v; - return 0; + return common_spi_get(obj, MAKE_LMX1214_REG_RD((uint32_t)addr), out); } UNUSED static int lmx1214_read_all_regs(lmx1214_state_t* st) @@ -431,8 +404,8 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, MAKE_LMX1214_R8 (0, st->auxclk_div_pre, 0, (st->auxclkout.enable ? 1 : 0), 0, st->auxclkout.fmt), MAKE_LMX1214_R79(0, st->auxclk_div_byp ? 0x5 : 0x104 /*0x205*/), MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), - MAKE_LMX1214_R9 (0, 0, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), + MAKE_LMX1214_R3 (st->clkout_enabled[3] ? 1 : 0, st->clkout_enabled[2] ? 1 : 0, st->clkout_enabled[1] ? 1 : 0, @@ -441,7 +414,7 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, ), }; - res = dry_run ? lmx1214_print_registers(regs, SIZEOF_ARRAY(regs)) : lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); + res = dry_run ? common_print_registers_a8d16(regs, SIZEOF_ARRAY(regs), USDR_LOG_DEBUG) : lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) { USDR_LOG("1214", USDR_LOG_ERROR, "Registers set lmx1214_spi_post() failed, err:%d", res); diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 294af17a..0b7fa855 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -12,6 +12,7 @@ #include "../cal/opt_func.h" #include "lmx2820_dump.h" +#include "../common/common.h" enum { @@ -89,39 +90,17 @@ static uint64_t FPD_MAX[MASH_ORDER_THIRD_ORDER + 1] = static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count) { - int res; - - for (unsigned i = 0; i < count; i++) - { - uint8_t rn = regs[i] >> 16; - uint16_t rv = (uint16_t)regs[i]; - USDR_LOG("2820", USDR_LOG_DEBUG, "WRITE#%u: R%03u (0x%02x) -> 0x%04x [0x%06x]", i, rn, rn, rv, regs[i]); - } - - for (unsigned i = 0; i < count; i++) { - res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, regs[i], NULL); - if (res) - return res; - - USDR_LOG("2820", USDR_LOG_NOTE, "[%d/%d] reg wr %08x\n", i, count, regs[i]); - } - - return 0; + return + common_print_registers_a8d16(regs, count, USDR_LOG_DEBUG) + || + common_spi_post(obj, regs, count); } static int lmx2820_spi_get(lmx2820_state_t* obj, uint16_t addr, uint16_t* out) { - uint32_t v; - int res = lowlevel_spi_tr32(obj->dev, obj->subdev, obj->lsaddr, MAKE_LMX2820_REG_RD((uint32_t)addr), &v); - if (res) - return res; - - USDR_LOG("2820", USDR_LOG_NOTE, " reg rd %04x => %08x\n", addr, v); - *out = v; - return 0; + return common_spi_get(obj, MAKE_LMX2820_REG_RD((uint32_t)addr), out); } - static int lmx2820_get_worst_vco_core(uint64_t vco_freq, unsigned mash_order, unsigned* vco_core, uint16_t* min_pll_n) { if( vco_freq < VCO_MIN || vco_freq > VCO_MAX || From fc07372aff961ce0e64ecc3f34242733c890b12c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 15 Apr 2025 13:17:49 +0300 Subject: [PATCH 092/397] lite refactoring --- src/lib/cal/opt_func.c | 41 ++++++-------------------------------- src/lib/cal/opt_func.h | 3 ++- src/lib/hw/common/common.c | 2 +- 3 files changed, 9 insertions(+), 37 deletions(-) diff --git a/src/lib/cal/opt_func.c b/src/lib/cal/opt_func.c index 2dd923e4..dddddbce 100644 --- a/src/lib/cal/opt_func.c +++ b/src/lib/cal/opt_func.c @@ -205,40 +205,11 @@ uint64_t find_gcd(uint64_t a, uint64_t b) return find_gcd((b - a) >> 1, a); } -void binary_print_u32_reverse(uint32_t x, char* s) +void binary_print_u32(uint32_t x, char* s, bool reverse) { - sprintf(s, "%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u%1u", - (x >> 0) & 0x1, - (x >> 1) & 0x1, - (x >> 2) & 0x1, - (x >> 3) & 0x1, - (x >> 4) & 0x1, - (x >> 5) & 0x1, - (x >> 6) & 0x1, - (x >> 7) & 0x1, - (x >> 8) & 0x1, - (x >> 9) & 0x1, - (x >> 10) & 0x1, - (x >> 11) & 0x1, - (x >> 12) & 0x1, - (x >> 13) & 0x1, - (x >> 14) & 0x1, - (x >> 15) & 0x1, - (x >> 16) & 0x1, - (x >> 17) & 0x1, - (x >> 18) & 0x1, - (x >> 19) & 0x1, - (x >> 20) & 0x1, - (x >> 21) & 0x1, - (x >> 22) & 0x1, - (x >> 23) & 0x1, - (x >> 24) & 0x1, - (x >> 25) & 0x1, - (x >> 26) & 0x1, - (x >> 27) & 0x1, - (x >> 28) & 0x1, - (x >> 29) & 0x1, - (x >> 30) & 0x1, - (x >> 31) & 0x1 - ); + unsigned len = 0; + for(unsigned i = 0; i < sizeof(x) * 8; ++i) + { + len += sprintf(s + len, "%1u", reverse ? (x >> i) & 0x1 : (int32_t)(x << i) < 0); + } } diff --git a/src/lib/cal/opt_func.h b/src/lib/cal/opt_func.h index a9a71331..b71f94e6 100644 --- a/src/lib/cal/opt_func.h +++ b/src/lib/cal/opt_func.h @@ -9,6 +9,7 @@ #define OPT_FUNC_H #include "stdint.h" +#include "stdbool.h" #define MAX(a, b) \ ({ __typeof__ (a) _a = (a); \ @@ -57,6 +58,6 @@ int find_best_2d(struct opt_iteration2d *ops, unsigned max_count, void* param, i int *px, int *py, int *pfxy); uint64_t find_gcd(uint64_t a, uint64_t b); -void binary_print_u32_reverse(uint32_t x, char* s); +void binary_print_u32(uint32_t x, char* s, bool reverse); #endif diff --git a/src/lib/hw/common/common.c b/src/lib/hw/common/common.c index 946c3637..db58f843 100644 --- a/src/lib/hw/common/common.c +++ b/src/lib/hw/common/common.c @@ -11,7 +11,7 @@ int common_ti_calc_sync_delay(uint32_t clkpos, unsigned* calced_delay) char tmps[WBSIZE + 1]; - binary_print_u32_reverse(clkpos, tmps); + binary_print_u32(clkpos, tmps, true /*reverse*/); USDR_LOG("COMN", USDR_LOG_DEBUG, "WINDOW DATA:0b%s", tmps); //MSB & LSB should be 1 From d755b8a9d2d1c48c05b4f1a619658eda0a2f2eec Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 15 Apr 2025 20:21:54 +0300 Subject: [PATCH 093/397] refactoring + fix + skip 2820 reset --- src/lib/hw/common/common.c | 2 +- src/lib/hw/common/common.h | 2 +- src/lib/hw/lmx1214/lmx1214.c | 8 ++++---- src/lib/hw/lmx1214/lmx1214.h | 8 ++++++++ src/lib/hw/lmx2820/lmx2820.c | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/lib/hw/common/common.c b/src/lib/hw/common/common.c index db58f843..d506274d 100644 --- a/src/lib/hw/common/common.c +++ b/src/lib/hw/common/common.c @@ -108,7 +108,7 @@ int common_spi_post(void* o, uint32_t* regs, unsigned count) return 0; } -int common_spi_get(void* o, uint16_t addr, uint16_t* out) +int common_spi_get(void* o, uint32_t addr, uint16_t* out) { uint32_t v; const common_hw_state_struct_t* obj = (common_hw_state_struct_t*)o; diff --git a/src/lib/hw/common/common.h b/src/lib/hw/common/common.h index 6dd5f1cd..dcdc80d6 100644 --- a/src/lib/hw/common/common.h +++ b/src/lib/hw/common/common.h @@ -17,6 +17,6 @@ typedef struct common_hw_state_struct common_hw_state_struct_t; int common_ti_calc_sync_delay(uint32_t clkpos, unsigned* calced_delay); int common_print_registers_a8d16(uint32_t* regs, unsigned count, int loglevel); int common_spi_post(void* o, uint32_t* regs, unsigned count); -int common_spi_get(void* o, uint16_t addr, uint16_t* out); +int common_spi_get(void* o, uint32_t addr, uint16_t* out); #endif // HW_COMMON_H diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 1fc129bf..e7083469 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -406,10 +406,10 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), MAKE_LMX1214_R9 (0, 0, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), - MAKE_LMX1214_R3 (st->clkout_enabled[3] ? 1 : 0, - st->clkout_enabled[2] ? 1 : 0, - st->clkout_enabled[1] ? 1 : 0, - st->clkout_enabled[0] ? 1 : 0, + MAKE_LMX1214_R3 (st->clkout_enabled[LMX1214_CH3] ? 1 : 0, + st->clkout_enabled[LMX1214_CH2] ? 1 : 0, + st->clkout_enabled[LMX1214_CH1] ? 1 : 0, + st->clkout_enabled[LMX1214_CH0] ? 1 : 0, 0xF86//0xFE ), }; diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index 3147e8e3..b4aeba6a 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -8,6 +8,14 @@ #define LMX1214_OUT_CNT 4 +enum +{ + LMX1214_CH0 = 0, + LMX1214_CH1 = 1, + LMX1214_CH2 = 2, + LMX1214_CH3 = 3, +}; + enum { LMX1214_FMT_LVDS = 0, diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 0b7fa855..d8cd65ed 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -145,7 +145,7 @@ int lmx2820_sync(lmx2820_state_t* st) return lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); } -//#define LMX2820_RESET_SKIP +#define LMX2820_RESET_SKIP int lmx2820_reset(lmx2820_state_t* st) #ifdef LMX2820_RESET_SKIP From 1b9f62eb3189330aa4e6d1f6a5f9988c0e492db1 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 16 Apr 2025 20:17:24 +0300 Subject: [PATCH 094/397] DPLL added - testing needed --- .../device/ext_simplesync/ext_simplesync.c | 7 +- src/lib/device/pe_sync/pe_sync.c | 29 +- src/lib/hw/lmk05318/lmk05318.c | 378 +++++++++++++++++- src/lib/hw/lmk05318/lmk05318.h | 48 ++- src/lib/hw/lmk05318/lmk05318.yaml | 15 + src/utests/test_suite.c | 2 +- 6 files changed, 451 insertions(+), 28 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 2fc233f8..0ebe81d7 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -97,11 +97,12 @@ int board_ext_simplesync_init(lldev_t dev, lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); lmk05318_set_port_affinity(cfg, 7, AFF_APLL1); - const bool dpll_mode = false; + lmk05318_dpll_settings_t dpll; + dpll.enabled = false; - res = lmk05318_create_ex(dev, subdev, i2ca, &xo, dpll_mode, cfg, 4, &ob->lmk, false /*dry_run*/); + res = lmk05318_create_ex(dev, subdev, i2ca, &xo, &dpll, cfg, 4, &ob->lmk, false /*dry_run*/); res = res ? res : lmk05318_reset_los_flags(&ob->lmk); - res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, dpll_mode, 10000); + res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); #endif diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index ef685f93..b9db7ac1 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -283,7 +283,14 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; - const bool use_dpll = false; + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + dpll.enabled = true; + dpll.en[LMK05318_PRIREF] = true; + dpll.fref[LMK05318_PRIREF] = 1; + dpll.type[LMK05318_PRIREF] = XO_DC_DIFF_EXT; + dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; + dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; const uint64_t lmk_freq[8] = { @@ -307,7 +314,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, lmk_freq[6], false, LVCMOS); res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, lmk_freq[7], false, LVCMOS); - res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, use_dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); + res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); if(res) return res; @@ -318,9 +325,17 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; + //wait for PRIREF/SECREF validation + res = lmk05318_wait_dpll_ref_stat(&d->gen, 5000000); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); + return res; + } + //wait for lock //APLL1/DPLL - res = lmk05318_wait_apll1_lock(&d->gen, use_dpll, 10000); + res = lmk05318_wait_apll1_lock(&d->gen, 10000); //APLL2 (if needed) if(res == 0 && d->gen.vco2_freq) @@ -350,7 +365,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // //LMX2820 #0 setup // - +#if 0 const uint64_t lmx0_freq[] = { 1400000000, @@ -371,7 +386,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820[0] outputs locked & synced"); // - +#endif // //LMX2820 #1 setup // @@ -426,7 +441,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // //LMX1204 setup // - +#if 0 res = lmx1204_create(dev, 0, SPI_LMX1204, &d->cldistr); if(res) { @@ -483,7 +498,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1204 initialized"); // - +#endif return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 95f38a44..8a49cdc1 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "def_lmk05318.h" #include "lmk05318.h" @@ -44,8 +45,193 @@ enum { APLL2_PDIV_MIN = 2, APLL2_PDIV_MAX = 7, APLL2_PDIV_COUNT = 2, //PD1 & PD2 + + F_TDC_MIN = 1, + F_TDC_MAX = 26000000, + + DPLL_REF_R_DIV_MIN = 1, + DPLL_REF_R_DIV_MAX = UINT16_MAX - 1, + + DPLL_PRE_DIV_MIN = 2, + DPLL_PRE_DIV_MAX = 17, }; +int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) +{ + if(!dpll->enabled) + { + d->dpll.enabled = false; + USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] DPLL disabled"); + return 0; + } + + //Validate REF inputs + for(unsigned i = LMK05318_PRIREF; i <= LMK05318_SECREF; ++i) + { + if(!dpll->en[i]) + continue; + + switch(dpll->dc_mode[i]) + { + case DPLL_REF_AC_COUPLED_INT: dpll->dc_mode[i] = REF_DC_MODE_AC_COUPLED_INT; break; + case DPLL_REF_DC_COUPLED_INT: dpll->dc_mode[i] = REF_DC_MODE_DC_COUPLED_INT; break; + default: + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] %sREF DC_MODE:%u unsupported", + (i == LMK05318_PRIREF) ? "PRI" : "SEC", dpll->dc_mode[i]); + return -EINVAL; + } + + switch(dpll->buf_mode[i]) + { + case DPLL_REF_AC_BUF_HYST50_DC_EN: dpll->buf_mode[i] = REF_BUF_MODE_AC_HYST50_DC_EN; break; + case DPLL_REF_AC_BUF_HYST200_DC_DIS: dpll->buf_mode[i] = REF_BUF_MODE_AC_HYST200_DC_DIS; break; + default: + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] %sREF BUF_MODE:%u unsupported", + (i == LMK05318_PRIREF) ? "PRI" : "SEC", dpll->buf_mode[i]); + return -EINVAL; + } + + switch(dpll->type[i]) + { + case XO_DC_DIFF_EXT: dpll->type[i] = IN_OPTS_DC_DIFF_EXT; break; + case XO_AC_DIFF_EXT: dpll->type[i] = IN_OPTS_AC_DIFF_EXT; break; + case XO_AC_DIFF_INT_100: dpll->type[i] = IN_OPTS_AC_DIFF_INT_100; break; + case XO_HCSL_INT_50: dpll->type[i] = IN_OPTS_HCSL_INT_50; break; + case XO_CMOS: dpll->type[i] = IN_OPTS_CMOS; break; + case XO_SE_INT_50: dpll->type[i] = IN_OPTS_SE_INT_50; break; + default: + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] %sREF TYPE:%u unsupported", + (i == LMK05318_PRIREF) ? "PRI" : "SEC", dpll->type[i]); + return -EINVAL; + } + } + + d->dpll.enabled = true; + + if(dpll->en[LMK05318_PRIREF] && dpll->en[LMK05318_SECREF]) + { + unsigned max_ref_id, min_ref_id; + if(dpll->fref[LMK05318_PRIREF] > dpll->fref[LMK05318_SECREF]) + { + max_ref_id = LMK05318_PRIREF; min_ref_id = LMK05318_SECREF; + } else + { + max_ref_id = LMK05318_SECREF; min_ref_id = LMK05318_PRIREF; + } + + uint64_t max_div = dpll->fref[max_ref_id]; + uint64_t min_div = dpll->fref[min_ref_id]; + uint64_t gcd = find_gcd(min_div, max_div); + if(gcd > 1) + { + min_div /= gcd; + max_div /= gcd; + } + + const unsigned min_div_required = ceil((double)dpll->fref[max_ref_id] / F_TDC_MAX); + + if(max_div > DPLL_REF_R_DIV_MAX || min_div < min_div_required) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] incorrect PRIREF/SECREF ratio (%.2f)", (double)min_div / max_div); + return -EINVAL; + } + + d->dpll.ref_en[LMK05318_PRIREF] = d->dpll.ref_en[LMK05318_SECREF] = true; + d->dpll.rdiv[min_ref_id] = min_div; + d->dpll.rdiv[max_ref_id] = max_div; + d->dpll.ftdc = (double)dpll->fref[min_ref_id] / d->dpll.rdiv[min_ref_id]; + + const double ftdc2 = (double)dpll->fref[max_ref_id] / d->dpll.rdiv[max_ref_id]; + if(fabs(ftdc2 - d->dpll.ftdc) > 1E-6) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] PRIREF/SECREF cannot be resolved to one TDC (%.6f != %.6f)", d->dpll.ftdc, ftdc2); + } + } + else if(dpll->en[LMK05318_PRIREF] || dpll->en[LMK05318_SECREF]) + { + uint8_t id = dpll->en[LMK05318_PRIREF] ? LMK05318_PRIREF : LMK05318_SECREF; + uint64_t div = ceil((double)dpll->fref[id] / F_TDC_MAX); + if(div > DPLL_REF_R_DIV_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] PRIREF or SECREF value too high"); + return -EINVAL; + } + + d->dpll.ref_en[id] = true; + d->dpll.rdiv[id] = div; + d->dpll.ftdc = (double)dpll->fref[id] / div; + } + else + { + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] PRIREF and SECREF are disabled, cannot configure DPLL"); + return -EINVAL; + } + + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] PRIREF:%" PRIu64 " EN:%u RDIV:%u", + dpll->fref[LMK05318_PRIREF], d->dpll.ref_en[LMK05318_PRIREF], d->dpll.rdiv[LMK05318_PRIREF]); + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] SECREF:%" PRIu64 " EN:%u RDIV:%u", + dpll->fref[LMK05318_SECREF], d->dpll.ref_en[LMK05318_SECREF], d->dpll.rdiv[LMK05318_SECREF]); + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] FTDC:%.8f", d->dpll.ftdc); + + + const uint64_t max_fbdiv = ((uint64_t)1 << 30) - 1; + const uint64_t min_fbdiv = 1; + + unsigned max_pre_div = MIN(VCO_APLL1 / d->dpll.ftdc / 2 / min_fbdiv, DPLL_PRE_DIV_MAX); + unsigned min_pre_div = MAX(VCO_APLL1 / d->dpll.ftdc / 2 / max_fbdiv, DPLL_PRE_DIV_MIN); + if(max_pre_div < min_pre_div) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] cannot calculate PRE_DIV"); + return -EINVAL; + } + + const unsigned pre_div = min_pre_div; + double fbdiv = (double)VCO_APLL1 / d->dpll.ftdc / 2.0 / pre_div; + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] PRE_DIV:%u FB_DIV:%.8f", pre_div, fbdiv); + if(fbdiv < min_fbdiv || fbdiv > max_fbdiv) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] FB_DIV:%.8f out of range", fbdiv); + return -EINVAL; + } + + uint32_t fb_int = (uint32_t)fbdiv; + double fb_frac = fbdiv - fb_int; + uint64_t fb_den = VCO_APLL1 * 2 * pre_div; //(uint64_t)1 << 40; + uint64_t fb_num = (uint64_t)(fb_frac * fb_den + 0.5); + uint64_t gcd = find_gcd(fb_num, fb_den); + if(gcd > 1) + { + fb_num /= gcd; + fb_den /= gcd; + } + + //check + const double vco1_fact = d->dpll.ftdc * 2.0 * pre_div * (fb_int + (double)fb_num / fb_den); + const double delta = fabs((double)VCO_APLL1 - vco1_fact); + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] N:%u NUM:%" PRIu64 " DEN:%" PRIu64 " VCO1_FACT:%.8f DELTA:%.8fHz", + fb_int, fb_num, fb_den, vco1_fact, delta); + if(delta > 1E-6) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] VCO1_FACT too rough"); + return -EINVAL; + } + + d->dpll.n = fb_int; + d->dpll.num = fb_num; + d->dpll.den = fb_den; + + //DPLL BW + if((dpll->en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1) || (dpll->en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] == 1)) + { + d->dpll.lbw = 0.01; + } + else + d->dpll.lbw = 100; + + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] LBW:%.2fHz", d->dpll.lbw); + + return 0; +} int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out) @@ -210,17 +396,120 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) +static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bool zdm) { + int res = lmk05318_dpll_config(d, dpll); + if(res) + return res; + + if(d->dpll.enabled == false) + { + uint32_t dpll_regs[] = + { + MAKE_LMK05318_DEV_CTL(0, 0, 1, 1, 1, 1, 1), //R12 set APLL1 mode - DPLL + MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, 1), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise + MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 1), //R40 set programmed APPL2 denumerator always + MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, 0, 0), //R252 disable DPLL + MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 + }; + res = lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); + } + else + { + const bool one_pps[] = + { + (dpll->en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1), + (dpll->en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] == 1), + }; + + const bool lt2k[] = + { + !one_pps[LMK05318_PRIREF] && (dpll->en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] < 2000), + !one_pps[LMK05318_SECREF] && (dpll->en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] < 2000), + }; + + const bool ge2k[] = + { + !one_pps[LMK05318_PRIREF] && !lt2k[LMK05318_PRIREF], + !one_pps[LMK05318_SECREF] && !lt2k[LMK05318_SECREF], + }; + + unsigned meas_time[] = + { + (unsigned)(log2f(10000.f / dpll->fref[LMK05318_PRIREF]) + 2.5), + (unsigned)(log2f(10000.f / dpll->fref[LMK05318_SECREF]) + 2.5), + }; + + uint32_t dpll_regs[] = + { + MAKE_LMK05318_DEV_CTL(0, 0, 0, 1, 1, 1, 1), //R12 set APLL1 mode - Free-run + MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, 0), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise + MAKE_LMK05318_SPARE_NVMBASE2_BY1(dpll->dc_mode[LMK05318_SECREF], dpll->dc_mode[LMK05318_PRIREF], 1), //R40 set programmed APPL2 denumerator always + MAKE_LMK05318_REF_CLKCTL1(dpll->fref[LMK05318_SECREF] >= 5000000 && dpll->type[LMK05318_SECREF] != IN_OPTS_CMOS && dpll->type[LMK05318_SECREF] != IN_OPTS_SE_INT_50, + dpll->fref[LMK05318_PRIREF] >= 5000000 && dpll->type[LMK05318_PRIREF] != IN_OPTS_CMOS && dpll->type[LMK05318_PRIREF] != IN_OPTS_SE_INT_50, + dpll->buf_mode[LMK05318_SECREF], + dpll->buf_mode[LMK05318_PRIREF]), //R45 + MAKE_LMK05318_REF_CLKCTL2(dpll->type[LMK05318_SECREF], dpll->type[LMK05318_PRIREF]), //R46 + + MAKE_LMK05318_PLL1_CALCTRL0(0, 0, 1), //R79 BAW_LOCKDET_EN=0 PLL1_VCOWAIT=1 + + MAKE_LMK05318_REF0_DETEN(ge2k[LMK05318_PRIREF], + lt2k[LMK05318_PRIREF] || one_pps[LMK05318_PRIREF], + dpll->en[LMK05318_PRIREF], + ge2k[LMK05318_PRIREF], + ge2k[LMK05318_PRIREF], + ge2k[LMK05318_PRIREF]), //R193 + + MAKE_LMK05318_REF0_DETEN(ge2k[LMK05318_SECREF], + lt2k[LMK05318_SECREF] || one_pps[LMK05318_SECREF], + dpll->en[LMK05318_SECREF], + ge2k[LMK05318_SECREF], + ge2k[LMK05318_SECREF], + ge2k[LMK05318_SECREF]), //R194 + + MAKE_LMK05318_REG_WR(REF0_VLDTMR, meas_time[LMK05318_PRIREF] & 0b00011111), //R233 + MAKE_LMK05318_REG_WR(REF1_VLDTMR, meas_time[LMK05318_SECREF] & 0b00011111), //R234 + + MAKE_LMK05318_REF0_PH_VALID_THR(lt2k[LMK05318_PRIREF] || one_pps[LMK05318_PRIREF] ? 63 : 0), //R243 *********TODO + MAKE_LMK05318_REF1_PH_VALID_THR(lt2k[LMK05318_SECREF] || one_pps[LMK05318_SECREF] ? 63 : 0), //R244 *********TODO + + MAKE_LMK05318_DPLL_REF01_PRTY(2, 1), //R249 set PRIREF 1st, SECREF 2nd priority + MAKE_LMK05318_DPLL_REF_SWMODE(0, + (d->dpll.ref_en[LMK05318_PRIREF] ? LMK05318_PRIREF : LMK05318_SECREF), + (d->dpll.ref_en[LMK05318_PRIREF] && d->dpll.ref_en[LMK05318_SECREF]) ? 0x0 : 0x3), //R251 + MAKE_LMK05318_DPLL_GEN_CTL(zdm ? 1 : 0, 0, 0, !one_pps[LMK05318_PRIREF] && !one_pps[LMK05318_SECREF], 1, 0, 1), //R252 enable ZDM & enable DPLL + MAKE_LMK05318_DPLL_REF0_RDIV_BY0(d->dpll.rdiv[LMK05318_PRIREF]), //R256 + MAKE_LMK05318_DPLL_REF0_RDIV_BY1(d->dpll.rdiv[LMK05318_PRIREF]), + MAKE_LMK05318_DPLL_REF1_RDIV_BY0(d->dpll.rdiv[LMK05318_SECREF]), + MAKE_LMK05318_DPLL_REF1_RDIV_BY1(d->dpll.rdiv[LMK05318_SECREF]), //R259 + MAKE_LMK05318_DPLL_REF_FB_PREDIV(d->dpll.pre_div - 2), //R304 + MAKE_LMK05318_DPLL_REF_FB_DIV_BY0(d->dpll.n), //R305 + MAKE_LMK05318_DPLL_REF_FB_DIV_BY1(d->dpll.n), + MAKE_LMK05318_DPLL_REF_FB_DIV_BY2(d->dpll.n), + MAKE_LMK05318_DPLL_REF_FB_DIV_BY3(d->dpll.n), //R308 + MAKE_LMK05318_DPLL_REF_NUM_BY0(d->dpll.num), //R309 + MAKE_LMK05318_DPLL_REF_NUM_BY1(d->dpll.num), + MAKE_LMK05318_DPLL_REF_NUM_BY2(d->dpll.num), + MAKE_LMK05318_DPLL_REF_NUM_BY3(d->dpll.num), + MAKE_LMK05318_DPLL_REF_NUM_BY4(d->dpll.num), //R313 + MAKE_LMK05318_DPLL_REF_DEN_BY0(d->dpll.den), //R314 + MAKE_LMK05318_DPLL_REF_DEN_BY1(d->dpll.den), + MAKE_LMK05318_DPLL_REF_DEN_BY2(d->dpll.den), + MAKE_LMK05318_DPLL_REF_DEN_BY3(d->dpll.den), + MAKE_LMK05318_DPLL_REF_DEN_BY4(d->dpll.den), //R318 + }; + res = lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); + } + + if(res) + return res; + uint32_t regs[] = { - MAKE_LMK05318_DEV_CTL(0, 0, dpllmode ? 1 : 0, 1, 1, 1, 1), //R12 set APLL1 mode - DPLL | Free-run - MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, dpllmode ? 1 : 0), //R252 enable/disable DPLL - MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, dpllmode ? 0 : 1), //R39 *** set fixed APLL1 denumerator for DPLL en, programmed den otherwise - MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 1), //R40 *** set programmed APPL2 denumerator always - MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 set PLL clock cfg + MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 APLL cascade mode + set PLL clock cfg MAKE_LMK05318_OUTSYNCCTL(1, 1, 1), //R70 enable APLL1/APLL2 channel sync MAKE_LMK05318_OUTSYNCEN(1, 1, 1, 1, 1, 1), //R71 enable ch0..ch7 out sync + MAKE_LMK05318_MUTELVL1(CH3_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH2_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH1_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, @@ -233,7 +522,6 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags - MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 0x00510A, //R81 @@ -262,7 +550,7 @@ static int lmk05318_init(lmk05318_state_t* d, bool dpllmode) int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, - const lmk05318_xo_settings_t* xo, bool dpll_mode, + const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, lmk05318_state_t* out, bool dry_run) { @@ -298,7 +586,25 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, #endif #if 1 - res = lmk05318_init(out, dpll_mode); + + //detect ZDM mode -> if 1)OUT7 = 1Hz 2) DPLL input ref = 1Hz + bool zdm = false; + for(unsigned i = 0; i < out_ports_len; ++i) + { + lmk05318_out_config_t* p = out_ports_cfg + i; + if(p->port == 7 && p->wanted.freq == 1) + { + zdm = true; + break; + } + } + zdm &= (dpll->enabled && ((dpll->en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1) + || (dpll->en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] == 1))); + if(zdm) + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] ZDM enabled"); + // + + res = lmk05318_init(out, dpll, zdm); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d on init()", res); @@ -312,7 +618,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } - res = lmk05318_tune_apll1(out, dpll_mode); + res = lmk05318_tune_apll1(out); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d tuning APLL1", res); @@ -612,14 +918,14 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) return 0; } -int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode) +int lmk05318_tune_apll1(lmk05318_state_t* d) { unsigned fpd1 = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); uint64_t fvco = VCO_APLL1; unsigned n = fvco / fpd1; //in DPLL mode we use FIXED 40-bit APLL1 denominator and programmed 40-bit numerator - if(dpll_mode) + if(d->dpll.enabled) { uint64_t num = (fvco - n * (uint64_t)fpd1) * (1ull << 40) / fpd1; @@ -1606,7 +1912,7 @@ int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent) return 0; } -int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeout) +int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout) { int res = 0; unsigned elapsed = 0; @@ -1632,7 +1938,7 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeo return res; } - if(dpll_mode) + if(d->dpll.enabled) { locked = pll1_vm_inside && !(los_msk & LMK05318_LOPL_DPLL) && !(los_msk & LMK05318_LOFL_DPLL); } @@ -1705,3 +2011,47 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) USDR_LOG("5318", USDR_LOG_INFO, "APLL2 locked OK"); return 0; } + +int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) +{ + if(!d->dpll.enabled) + { + USDR_LOG("5318", USDR_LOG_DEBUG, "DPLL disabled, validating ref ignored"); + return 0; + } + + int res = 0; + unsigned elapsed = 0; + bool valid = false; + uint8_t reg; + + while(timeout == 0 || elapsed < timeout) + { + res = lmk05318_reg_rd(d, REFVALSTAT, ®); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 read(REFVALSTAT) error:%d", res); + return res; + } + + bool pri_valid = d->dpll.ref_en[LMK05318_PRIREF] ? (reg & PRIREF_VALSTAT_MSK) : true; + bool sec_valid = d->dpll.ref_en[LMK05318_SECREF] ? (reg & SECREF_VALSTAT_MSK) : true; + valid = pri_valid && sec_valid; + + if(valid) + break; + + usleep(100); + elapsed += 100; + } + + if(!valid) + { + USDR_LOG("5318", USDR_LOG_ERROR, "DPLL input reference NOT VALID! PRIREF_VALSTAT:%u SECREF_VALSTAT:%u", + reg & PRIREF_VALSTAT_MSK, reg & SECREF_VALSTAT_MSK); + return -ETIMEDOUT; + } + + USDR_LOG("5318", USDR_LOG_INFO, "DPLL input reference is valid"); + return 0; +} diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index f9d7f7c2..2a206e87 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -20,6 +20,18 @@ enum xo_input_type }; typedef enum xo_input_type xo_input_type_t; +enum +{ + DPLL_REF_AC_COUPLED_INT = 0, + DPLL_REF_DC_COUPLED_INT = 1, +}; + +enum +{ + DPLL_REF_AC_BUF_HYST50_DC_EN = 0, + DPLL_REF_AC_BUF_HYST200_DC_DIS = 1, +}; + struct lmk05318_xo_settings { unsigned pll1_fref_rdiv; @@ -30,6 +42,23 @@ struct lmk05318_xo_settings }; typedef struct lmk05318_xo_settings lmk05318_xo_settings_t; +enum +{ + LMK05318_PRIREF = 0, + LMK05318_SECREF = 1, +}; + +struct lmk05318_dpll_settings +{ + bool enabled; + bool en[2]; + uint64_t fref[2]; + uint8_t dc_mode[2]; + uint8_t buf_mode[2]; + uint8_t type[2]; +}; +typedef struct lmk05318_dpll_settings lmk05318_dpll_settings_t; + struct lmk05318_state { lldev_t dev; unsigned subdev; @@ -50,6 +79,16 @@ struct lmk05318_state { int mux; } outputs[LMK05318_MAX_OUT_PORTS]; + struct { + bool enabled; + bool ref_en[2]; + uint16_t rdiv[2]; + double ftdc; + double lbw; + uint8_t pre_div; + uint64_t n, num, den; + } dpll; + lmk05318_xo_settings_t xo; }; @@ -164,7 +203,7 @@ int lmk05318_sync(lmk05318_state_t* out); int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask); int lmk05318_reset_los_flags(lmk05318_state_t* d); int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); -int lmk05318_wait_apll1_lock(lmk05318_state_t* d, bool dpll_mode, unsigned timeout); +int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout); int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout); int lmk05318_softreset(lmk05318_state_t* out); @@ -173,13 +212,16 @@ int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run); int lmk05318_set_xo_fref(lmk05318_state_t* d); -int lmk05318_tune_apll1(lmk05318_state_t* d, bool dpll_mode); +int lmk05318_tune_apll1(lmk05318_state_t* d); int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run); int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, - const lmk05318_xo_settings_t* xo, bool dpll_mode, + const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, lmk05318_state_t* out, bool dry_run); +int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll); +int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout); + #endif diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index da1f3eda..adc3ca87 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -57,6 +57,14 @@ x-mute-lvl: &mute-lvl 0x2: DIFF_HIGH_P_LOW_N_BY 0x3: DIFF_LOW_P_LOW_N_LOW +x-ref-dc-mode: &ref-dc-mode + 0x0: AC_COUPLED_INT + 0x1: DC_COUPLED_INT + +x-ref-buf-mode: &ref-buf-mode + 0x0: AC_HYST50_DC_EN + 0x1: AC_HYST200_DC_DIS + pages: - name: Top regs: @@ -376,9 +384,11 @@ pages: - bits: "3" name: SECREF_DC_MODE desc: SECREF DC buffer mode; 0x0 = SECREF is AC coupled internally; 0x1 = SECREF is DC coupled internally + opts: *ref-dc-mode - bits: "2" name: PRIREF_DC_MODE desc: PRIREF DC buffer mode; 0x0 = PRIREF is AC coupled internally; 0x1 = PRIREF is DC coupled internally + opts: *ref-dc-mode - bits: "0" name: APLL2_DEN_MODE desc: Programmable APLL2 denominator mode; 0x0 = APLL2 uses fixed 24-bit denominator; 0x1 = APLL2 uses programmable 24-bit denominator (R333, R334, R335) @@ -428,9 +438,11 @@ pages: - bits: "1" name: SECREF_BUF_MODE desc: SECREF buffer mode. 0x0 - Set AC buffer hysteresis to 50mV or enable DC buffer hysteresis; 0x1 = Set AC buffer hysteresis to 200mV or disable DC buffer hysteresis + opts: *ref-buf-mode - bits: "0" name: PRIREF_BUF_MODE desc: PRIREF buffer mode. 0x0 - Set AC buffer hysteresis to 50mV or enable DC buffer hysteresis; 0x1 = Set AC buffer hysteresis to 200mV or disable DC buffer hysteresis + opts: *ref-buf-mode - addr: 0x2E name: REF_CLKCTL2 fields: @@ -1046,6 +1058,9 @@ pages: - bits: "4" name: DPLL_FASTLOCK_ALWAYS desc: Enable DPLL fast lock + - bits: "3" + name: DPLL_LOCKDET_PPM_EN + desc: Enable DPLL Frequency Lock Detect - bits: "2" name: DPLL_HLDOVR_MODE desc: DPLL Holdover mode when tuning word history unavailable; 0x0 = Enter free-run mode; 0x1 = Hold last control value prior to holdover diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index a189e1ab..505c80df 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -38,7 +38,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, lmx1214_solver_suite()); srunner_add_suite(sr, lmx1204_solver_suite()); #else - sr = srunner_create(lmx1204_solver_suite()); + sr = srunner_create(lmk05318_solver_suite()); #endif srunner_set_fork_status (sr, CK_NOFORK); From 435a65e9ecab2c4e01f89d679024ee49ee452e53 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 16 Apr 2025 21:33:41 +0300 Subject: [PATCH 095/397] minors --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index b9db7ac1..da7b20ea 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -326,7 +326,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; //wait for PRIREF/SECREF validation - res = lmk05318_wait_dpll_ref_stat(&d->gen, 5000000); + res = lmk05318_wait_dpll_ref_stat(&d->gen, 100000); if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 8a49cdc1..506202ec 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -556,6 +556,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, { int res; uint8_t dummy[4] = {0,0,0,0}; + memset(out, 0, sizeof(lmk05318_state_t)); lmk05318_registers_map_reset(); @@ -2023,11 +2024,12 @@ int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) int res = 0; unsigned elapsed = 0; bool valid = false; - uint8_t reg; + uint8_t reg, reg2; while(timeout == 0 || elapsed < timeout) { res = lmk05318_reg_rd(d, REFVALSTAT, ®); + res = res ? res : lmk05318_reg_rd(d, 0xa7, ®2); if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK05318 read(REFVALSTAT) error:%d", res); @@ -2047,8 +2049,8 @@ int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) if(!valid) { - USDR_LOG("5318", USDR_LOG_ERROR, "DPLL input reference NOT VALID! PRIREF_VALSTAT:%u SECREF_VALSTAT:%u", - reg & PRIREF_VALSTAT_MSK, reg & SECREF_VALSTAT_MSK); + USDR_LOG("5318", USDR_LOG_ERROR, "DPLL input reference NOT VALID! PRIREF_VALSTAT:%u SECREF_VALSTAT:%u R167:0x%02x", + reg & PRIREF_VALSTAT_MSK, reg & SECREF_VALSTAT_MSK, reg2); return -ETIMEDOUT; } From 589eda9c2ff2e10beb0a7188c2b414b4b5c650e2 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 16 Apr 2025 22:33:54 +0300 Subject: [PATCH 096/397] LMK - add load DPLL from dump --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 6 +- src/lib/hw/lmk05318/lmk05318_rom.h | 342 +++++++++++++++++++++++++++++ 3 files changed, 346 insertions(+), 4 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index da7b20ea..b4677fb5 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -326,7 +326,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; //wait for PRIREF/SECREF validation - res = lmk05318_wait_dpll_ref_stat(&d->gen, 100000); + res = lmk05318_wait_dpll_ref_stat(&d->gen, 200000); if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 506202ec..e05c0a84 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -580,13 +580,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } -#if 0 - res = lmk05318_reg_wr_n(out, lmk05318_rom_test, SIZEOF_ARRAY(lmk05318_rom_test)); +#if 1 + res = lmk05318_reg_wr_n(out, lmk05318_rom_dpll, SIZEOF_ARRAY(lmk05318_rom_dpll)); if (res) return res; #endif -#if 1 +#if 0 //detect ZDM mode -> if 1)OUT7 = 1Hz 2) DPLL input ref = 1Hz bool zdm = false; diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index 096c08e2..cda0b85c 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -1,6 +1,348 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +static const uint32_t lmk05318_rom_dpll[] = +{ + /* + 0x000000, + 0x000100, + 0x000200, + 0x000300, + 0x000400, + 0x000500, + 0x000600, + 0x000700, + 0x000800, + 0x000A00, + 0x000B00, +*/ + 0x000C1B, + 0x000D00, + 0x000E00, + 0x000F00, + 0x001000, + 0x001100, + 0x001200, + 0x001300, + 0x001400, + 0x001500, + 0x001600, + 0x001700, + 0x001800, + 0x001900, + 0x001A00, + 0x001B00, + 0x001C00, + 0x001D00, + 0x001E00, + 0x002000, + 0x002300, + 0x002400, + 0x002500, + 0x002600, + 0x002700, + 0x002806, + 0x002900, + 0x002A10, + 0x002B40, + 0x002C00, + 0x002D06, + 0x002E01, + 0x002F00, + 0x003000, + 0x003100, + 0x003200, + 0x003310, + 0x003410, + 0x003513, + 0x003610, + 0x003710, + 0x003809, + 0x003900, + 0x003A0F, + 0x003B00, + 0x003C0F, + 0x003D3E, + 0x003EF9, + 0x003F3E, + 0x004095, + 0x004102, + 0x0042F8, + 0x0043FF, + 0x004400, + 0x004500, + 0x004600, + 0x004700, + 0x004800, + 0x004900, + 0x004A00, + 0x004B00, + 0x004C00, + 0x004D00, + 0x004E00, + 0x004F00, + 0x005000, + 0x00510A, + 0x005200, + 0x00530E, + 0x0054A6, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D0E, + 0x005EA6, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + 0x006429, + 0x006500, + 0x006633, + 0x006700, + 0x006800, + 0x006900, + 0x006A00, + 0x006B00, + 0x006C00, + 0x006D32, + 0x006E00, + 0x006F00, + 0x007000, + 0x007100, + 0x007200, + 0x007303, + 0x007401, + 0x007500, + 0x007600, + 0x007700, + 0x007800, + 0x007900, + 0x007A00, + 0x007B00, + 0x007C00, + 0x007D00, + 0x007E00, + 0x007F00, + 0x008000, + 0x008100, + 0x008200, + 0x008300, + 0x008400, + 0x008500, + 0x008600, + 0x00872C, + 0x00887C, + 0x0089E0, + 0x008ABF, + 0x008B00, + 0x008C00, + 0x008D00, + 0x008E00, + 0x008F00, + 0x009000, + 0x009100, + 0x009200, + 0x009300, + 0x009500, + 0x009600, + 0x009700, + 0x009800, + 0x009900, + 0x009A00, + 0x009B00, + 0x009C00, + // 0x009D00, + 0x009E00, + 0x009F00, + 0x00A000, + 0x00A100, + 0x00A200, + // 0x00A400, + 0x00A500, + 0x00A700, + 0x00B200, + 0x00B400, + 0x00B500, + 0x00B600, + 0x00B700, + 0x00B800, + 0x00B9F1, + 0x00BA01, + 0x00BB00, + 0x00BC00, + 0x00BD00, + 0x00BE00, + 0x00BF00, + 0x00C000, + 0x00C119, + 0x00C200, + 0x00C300, + 0x00C400, + 0x00C51D, + 0x00C600, + 0x00C700, + 0x00C800, + 0x00C900, + 0x00CA00, + 0x00CB00, + 0x00CC15, + 0x00CD00, + 0x00CE00, + 0x00CF00, + 0x00D000, + 0x00D100, + 0x00D200, + 0x00D300, + 0x00D400, + 0x00D500, + 0x00D600, + 0x00D700, + 0x00D800, + 0x00D900, + 0x00DA00, + 0x00DB00, + 0x00DC00, + 0x00DD00, + 0x00DE00, + 0x00DF00, + 0x00E000, + 0x00E100, + 0x00E200, + 0x00E300, + 0x00E400, + 0x00E500, + 0x00E600, + 0x00E700, + 0x00E800, + 0x00E919, + 0x00EA00, + 0x00EB02, + 0x00ECFA, + 0x00EDF0, + 0x00EE80, + 0x00EF00, + 0x00F000, + 0x00F100, + 0x00F200, + 0x00F33F, + 0x00F400, + 0x00F921, + 0x00FA00, + 0x00FB03, + 0x00FC29, + 0x00FD00, + 0x00FE00, + 0x00FF00, + 0x010000, + 0x010101, + 0x010200, + 0x010300, + 0x010402, + 0x010580, + 0x010601, + 0x01072A, + 0x010805, + 0x0109F2, + 0x010A00, + 0x010BA0, + 0x010C00, + 0x010D00, + 0x010E02, + 0x010FA6, + 0x011000, + 0x011100, + 0x011200, + 0x011316, + 0x011416, + 0x011516, + 0x011600, + 0x011700, + 0x011800, + 0x011900, + 0x011A00, + 0x011B00, + 0x011C1E, + 0x011D1E, + 0x011E00, + 0x011F00, + 0x012000, + 0x012100, + 0x012203, + 0x012322, + 0x012400, + 0x012500, + 0x012600, + 0x012700, + 0x01280A, + 0x01290A, + 0x012A0A, + 0x012B00, + 0x012C00, + 0x012D1C, + 0x012E1E, + 0x012F01, + 0x01300F, + 0x013104, + 0x013261, + 0x0133F8, + 0x013443, + 0x0135C3, + 0x0136C3, + 0x0137C3, + 0x0138C3, + 0x0139C3, + 0x013AFF, + 0x013BFF, + 0x013CFF, + 0x013DFF, + 0x013EFF, + 0x013F03, + 0x014000, + 0x01410A, + 0x014200, + 0x014300, + 0x014400, + 0x014501, + 0x014606, + 0x014735, + 0x014875, + 0x01490B, + 0x014A00, + 0x014B64, + 0x014C00, + 0x014D00, + 0x014E61, + 0x014FA8, + 0x015006, + 0x015135, + 0x015275, + 0x01530B, + 0x015400, + 0x015500, + 0x015600, + 0x015700, + 0x015800, + 0x015900, + 0x015A00, + 0x015B00, + 0x015C00, + 0x015D00, + 0x015E00, + 0x015F00, + 0x016000, + 0x016500, + 0x016F00, + 0x019B00, +}; + + + static const uint32_t lmk05318_rom_test[] = { //0x000010, From dadd63046fe1a98370d3f153c1b2b29fa6aff967 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 18 Apr 2025 00:59:36 +0300 Subject: [PATCH 097/397] multiple LMK DPLL regs fixes --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 50 ++-- src/lib/hw/lmk05318/lmk05318.h | 9 + src/lib/hw/lmk05318/lmk05318.yaml | 13 +- src/lib/hw/lmk05318/lmk05318_rom.h | 442 +++++++++++++++-------------- src/utests/lmk05318_solver_test.c | 36 ++- 6 files changed, 313 insertions(+), 239 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index b4677fb5..8d19aa95 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -288,7 +288,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const dpll.enabled = true; dpll.en[LMK05318_PRIREF] = true; dpll.fref[LMK05318_PRIREF] = 1; - dpll.type[LMK05318_PRIREF] = XO_DC_DIFF_EXT; + dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index e05c0a84..6b17c0a7 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -93,12 +93,11 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) switch(dpll->type[i]) { - case XO_DC_DIFF_EXT: dpll->type[i] = IN_OPTS_DC_DIFF_EXT; break; - case XO_AC_DIFF_EXT: dpll->type[i] = IN_OPTS_AC_DIFF_EXT; break; - case XO_AC_DIFF_INT_100: dpll->type[i] = IN_OPTS_AC_DIFF_INT_100; break; - case XO_HCSL_INT_50: dpll->type[i] = IN_OPTS_HCSL_INT_50; break; - case XO_CMOS: dpll->type[i] = IN_OPTS_CMOS; break; - case XO_SE_INT_50: dpll->type[i] = IN_OPTS_SE_INT_50; break; + case DPLL_REF_TYPE_DIFF_NOTERM: dpll->type[i] = REF_INPUT_TYPE_DIFF_NOTERM; break; + case DPLL_REF_TYPE_DIFF_100: dpll->type[i] = REF_INPUT_TYPE_DIFF_100; break; + case DPLL_REF_TYPE_DIFF_50: dpll->type[i] = REF_INPUT_TYPE_DIFF_50; break; + case DPLL_REF_TYPE_SE_NOTERM: dpll->type[i] = REF_INPUT_TYPE_SE_NOTERM; break; + case DPLL_REF_TYPE_SE_50: dpll->type[i] = REF_INPUT_TYPE_SE_50; break; default: USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] %sREF TYPE:%u unsupported", (i == LMK05318_PRIREF) ? "PRI" : "SEC", dpll->type[i]); @@ -185,7 +184,7 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) return -EINVAL; } - const unsigned pre_div = min_pre_div; + const unsigned pre_div = max_pre_div; double fbdiv = (double)VCO_APLL1 / d->dpll.ftdc / 2.0 / pre_div; USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] PRE_DIV:%u FB_DIV:%.8f", pre_div, fbdiv); if(fbdiv < min_fbdiv || fbdiv > max_fbdiv) @@ -216,6 +215,7 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) return -EINVAL; } + d->dpll.pre_div = pre_div; d->dpll.n = fb_int; d->dpll.num = fb_num; d->dpll.den = fb_den; @@ -411,6 +411,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 1), //R40 set programmed APPL2 denumerator always MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, 0, 0), //R252 disable DPLL MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 }; res = lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); } @@ -445,27 +446,34 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DEV_CTL(0, 0, 0, 1, 1, 1, 1), //R12 set APLL1 mode - Free-run MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, 0), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise MAKE_LMK05318_SPARE_NVMBASE2_BY1(dpll->dc_mode[LMK05318_SECREF], dpll->dc_mode[LMK05318_PRIREF], 1), //R40 set programmed APPL2 denumerator always - MAKE_LMK05318_REF_CLKCTL1(dpll->fref[LMK05318_SECREF] >= 5000000 && dpll->type[LMK05318_SECREF] != IN_OPTS_CMOS && dpll->type[LMK05318_SECREF] != IN_OPTS_SE_INT_50, - dpll->fref[LMK05318_PRIREF] >= 5000000 && dpll->type[LMK05318_PRIREF] != IN_OPTS_CMOS && dpll->type[LMK05318_PRIREF] != IN_OPTS_SE_INT_50, - dpll->buf_mode[LMK05318_SECREF], - dpll->buf_mode[LMK05318_PRIREF]), //R45 + MAKE_LMK05318_REF_CLKCTL1(!dpll->en[LMK05318_SECREF] || (dpll->fref[LMK05318_SECREF] >= 5000000 && dpll->type[LMK05318_SECREF] != IN_OPTS_CMOS && dpll->type[LMK05318_SECREF] != IN_OPTS_SE_INT_50) ? 0 : 1, + !dpll->en[LMK05318_PRIREF] || (dpll->fref[LMK05318_PRIREF] >= 5000000 && dpll->type[LMK05318_PRIREF] != IN_OPTS_CMOS && dpll->type[LMK05318_PRIREF] != IN_OPTS_SE_INT_50) ? 0 : 1, + dpll->en[LMK05318_SECREF] ? dpll->buf_mode[LMK05318_SECREF] : DPLL_REF_AC_BUF_HYST200_DC_DIS, + dpll->en[LMK05318_PRIREF] ? dpll->buf_mode[LMK05318_PRIREF] : DPLL_REF_AC_BUF_HYST200_DC_DIS), //R45 MAKE_LMK05318_REF_CLKCTL2(dpll->type[LMK05318_SECREF], dpll->type[LMK05318_PRIREF]), //R46 MAKE_LMK05318_PLL1_CALCTRL0(0, 0, 1), //R79 BAW_LOCKDET_EN=0 PLL1_VCOWAIT=1 + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(0, 0), //R80 BAW_LOCK=0 + dpll->en[LMK05318_PRIREF] ? MAKE_LMK05318_REF0_DETEN(ge2k[LMK05318_PRIREF], lt2k[LMK05318_PRIREF] || one_pps[LMK05318_PRIREF], - dpll->en[LMK05318_PRIREF], + 1, //validation timer en ge2k[LMK05318_PRIREF], ge2k[LMK05318_PRIREF], - ge2k[LMK05318_PRIREF]), //R193 + 1 /* amp_det_en ge2k[LMK05318_PRIREF]*/) : + MAKE_LMK05318_REF0_DETEN(0,0,0,0,0,0) + , //R193 - MAKE_LMK05318_REF0_DETEN(ge2k[LMK05318_SECREF], + dpll->en[LMK05318_SECREF] ? + MAKE_LMK05318_REF1_DETEN(ge2k[LMK05318_SECREF], lt2k[LMK05318_SECREF] || one_pps[LMK05318_SECREF], - dpll->en[LMK05318_SECREF], + 1, //validation timer en, ge2k[LMK05318_SECREF], ge2k[LMK05318_SECREF], - ge2k[LMK05318_SECREF]), //R194 + 1 /* amp_det_en ge2k[LMK05318_SECREF]*/) : + MAKE_LMK05318_REF1_DETEN(0,0,0,0,0,0) + , //R194 MAKE_LMK05318_REG_WR(REF0_VLDTMR, meas_time[LMK05318_PRIREF] & 0b00011111), //R233 MAKE_LMK05318_REG_WR(REF1_VLDTMR, meas_time[LMK05318_SECREF] & 0b00011111), //R234 @@ -477,7 +485,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_SWMODE(0, (d->dpll.ref_en[LMK05318_PRIREF] ? LMK05318_PRIREF : LMK05318_SECREF), (d->dpll.ref_en[LMK05318_PRIREF] && d->dpll.ref_en[LMK05318_SECREF]) ? 0x0 : 0x3), //R251 - MAKE_LMK05318_DPLL_GEN_CTL(zdm ? 1 : 0, 0, 0, !one_pps[LMK05318_PRIREF] && !one_pps[LMK05318_SECREF], 1, 0, 1), //R252 enable ZDM & enable DPLL + MAKE_LMK05318_DPLL_GEN_CTL(zdm ? 1 : 0, 0, 1/*DPLL_SWITCHOVER_ALWAYS*/, !one_pps[LMK05318_PRIREF] && !one_pps[LMK05318_SECREF], 1, 0, 1), //R252 enable ZDM & enable DPLL MAKE_LMK05318_DPLL_REF0_RDIV_BY0(d->dpll.rdiv[LMK05318_PRIREF]), //R256 MAKE_LMK05318_DPLL_REF0_RDIV_BY1(d->dpll.rdiv[LMK05318_PRIREF]), MAKE_LMK05318_DPLL_REF1_RDIV_BY0(d->dpll.rdiv[LMK05318_SECREF]), @@ -522,8 +530,6 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags - MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 - 0x00510A, //R81 0x005200, // | 0x00530E, // | @@ -543,6 +549,8 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo 0x00611E, // | 0x006284, // | 0x006380, //R99 + + MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,3), //R115 PLL1 MASHORD=3 }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -580,13 +588,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } -#if 1 +#if 0 res = lmk05318_reg_wr_n(out, lmk05318_rom_dpll, SIZEOF_ARRAY(lmk05318_rom_dpll)); if (res) return res; #endif -#if 0 +#if 1 //detect ZDM mode -> if 1)OUT7 = 1Hz 2) DPLL input ref = 1Hz bool zdm = false; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 2a206e87..ae16030e 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -20,6 +20,15 @@ enum xo_input_type }; typedef enum xo_input_type xo_input_type_t; +enum +{ + DPLL_REF_TYPE_DIFF_NOTERM = 1, + DPLL_REF_TYPE_DIFF_100 = 3, + DPLL_REF_TYPE_DIFF_50 = 5, + DPLL_REF_TYPE_SE_NOTERM = 8, + DPLL_REF_TYPE_SE_50 = 0xC, +}; + enum { DPLL_REF_AC_COUPLED_INT = 0, diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index adc3ca87..63f63365 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -65,6 +65,13 @@ x-ref-buf-mode: &ref-buf-mode 0x0: AC_HYST50_DC_EN 0x1: AC_HYST200_DC_DIS +x-ref-input-type: &ref-input-type + 0x1: DIFF_NOTERM + 0x3: DIFF_100 + 0x5: DIFF_50 + 0x8: SE_NOTERM + 0xC: SE_50 + pages: - name: Top regs: @@ -449,11 +456,11 @@ pages: - bits: "7-4" name: SECREF_TYPE desc: SECREF Input Type See PRIREF_TYPE for input type bit settings. - opts: *in-opts + opts: *ref-input-type - bits: "3-0" name: PRIREF_TYPE - desc: PRIREF Input Type; 0x0 = DC-Differential (external termination); 0x1 = AC-Differential (external termination); 0x3 = AC-Differential (internal termination 100-Ω); 0x4 = HCSL (internal termination 50-Ω); 0x8 = CMOS; 0xC = Single-ended (internal termination 50-Ω) - opts: *in-opts + desc: PRIREF Input Type + opts: *ref-input-type - addr: 0x2F name: PLL_CLK_CFG fields: diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index cda0b85c..8d963a0a 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -3,13 +3,13 @@ static const uint32_t lmk05318_rom_dpll[] = { - /* +/* 0x000000, 0x000100, 0x000200, 0x000300, 0x000400, - 0x000500, + 0x000500, // R 0x000600, 0x000700, 0x000800, @@ -69,17 +69,23 @@ static const uint32_t lmk05318_rom_dpll[] = 0x004102, 0x0042F8, 0x0043FF, - 0x004400, - 0x004500, + + 0x004400, // APLL1 Charge Pump Current Gain + 0x004500, // ? + 0x004600, 0x004700, - 0x004800, - 0x004900, + + 0x004800, // ? + 0x004900, // ? + 0x004A00, - 0x004B00, - 0x004C00, - 0x004D00, - 0x004E00, + + 0x004B00, // ? + 0x004C00, // ? + 0x004D00, // ? + 0x004E00, // ? + 0x004F00, 0x005000, 0x00510A, @@ -102,13 +108,15 @@ static const uint32_t lmk05318_rom_dpll[] = 0x006284, 0x006380, 0x006429, - 0x006500, - 0x006633, - 0x006700, - 0x006800, - 0x006900, - 0x006A00, - 0x006B00, + + 0x006500, // PLL2 Charge Pump Gain + 0x006633, // PLL2 Post-Divider 1/2 + 0x006700, // ? + 0x006800, // PLL2 Bleed resistor selection + 0x006900, // Closed Loop Wait Period + 0x006A00, // ? + 0x006B00, // ? + 0x006C00, 0x006D32, 0x006E00, @@ -118,175 +126,188 @@ static const uint32_t lmk05318_rom_dpll[] = 0x007200, 0x007303, 0x007401, - 0x007500, - 0x007600, - 0x007700, - 0x007800, - 0x007900, - 0x007A00, - 0x007B00, - 0x007C00, - 0x007D00, - 0x007E00, - 0x007F00, - 0x008000, - 0x008100, - 0x008200, - 0x008300, - 0x008400, - 0x008500, - 0x008600, - 0x00872C, - 0x00887C, - 0x0089E0, - 0x008ABF, - 0x008B00, - 0x008C00, - 0x008D00, - 0x008E00, - 0x008F00, - 0x009000, - 0x009100, - 0x009200, - 0x009300, - 0x009500, - 0x009600, - 0x009700, - 0x009800, - 0x009900, - 0x009A00, - 0x009B00, - 0x009C00, - // 0x009D00, - 0x009E00, - 0x009F00, - 0x00A000, - 0x00A100, - 0x00A200, - // 0x00A400, - 0x00A500, - 0x00A700, - 0x00B200, - 0x00B400, - 0x00B500, - 0x00B600, - 0x00B700, - 0x00B800, - 0x00B9F1, - 0x00BA01, - 0x00BB00, - 0x00BC00, - 0x00BD00, - 0x00BE00, - 0x00BF00, - 0x00C000, + + 0x007500, // ? + 0x007600, // ? + 0x007700, // ? + 0x007800, // ? + 0x007900, // ? + 0x007A00, // ? + 0x007B00, // PLL1_NUM_STAT_39:32 + 0x007C00, // PLL1_NUM_STAT_31:24 + 0x007D00, // PLL1_NUM_STAT_23:16 + 0x007E00, // PLL1_NUM_STAT_15:8 + 0x007F00, // PLL1_NUM_STAT + 0x008000, // ? + 0x008100, // PLL1 Loop Filter R2 + 0x008200, // ? + 0x008300, // PLL1 Loop Filter R3 + 0x008400, // PLL1 Loop Filter R4 + 0x008500, // ? + 0x008600, // Bit 8 of PLL2_NDIV + 0x00872C, // Bits 7:0 of PLL2 N Divider + 0x00887C, // Bits 23:16 of PLL2_NUM + 0x0089E0, // Bits 15:8 of PLL2_NUM + 0x008ABF, // PLL2 Fractional Divider Numerator + 0x008B00, // SDM Dither Mode + APLL2 SDM Order + 0x008C00, // PLL2 Loop Filter R2 + 0x008D00, // ? + 0x008E00, // PLL2 Loop Filter R3 + 0x008F00, // PLL2 Loop Filter R4 + 0x009000, // PLL2 Loop Filter C4/C3 + 0x009100, // XO Input Wait Timer + 0x009200, // ? + 0x009300, // ? + 0x009500, // ? + 0x009600, // ? + 0x009700, // ? + 0x009800, // ? + 0x009900, // ? + 0x009A00, // ? + 0x009B00, // ? + 0x009C00, // NVM Program Count + // 0x009D00, // NVM misc + 0x009E00, // ? + 0x009F00, // Bits 12:8 of MEMADR + 0x00A000, // Memory Address + 0x00A100, // EEPROM Read Data + 0x00A200, // RAM Read/Write Data + // 0x00A400, // NVM Program Unlock + 0x00A500, // ? + 0x00A700, // ? + 0x00B200, // ? + 0x00B400, // Bits 37:32 of DPLL_TUNING_FREE_RUN + 0x00B500, // Bits 31:24 of DPLL_TUNING_FREE_RUN + 0x00B600, // Bits 23:16 of DPLL_TUNING_FREE_RUN + 0x00B700, // Bits 15:8 of DPLL_TUNING_FREE_RUN + 0x00B800, // DPLL Free-run tuning word + 0x00B9F1, // DPLL_REF_HIST_EN++ + 0x00BA01, // DPLL REF Tuning History Timer + 0x00BB00, // Bits 30:24 of DPLL_REF_HISTDLY + 0x00BC00, // Bits 23:16 of DPLL_REF_HISTDLY + 0x00BD00, // Bits 15:8 of DPLL_REF_HISTDLY + 0x00BE00, // DPLL REF Tuning History delay + 0x00BF00, // ? + 0x00C000, // PRI/SECREF detectors settings + + 0x00C119, 0x00C200, - 0x00C300, - 0x00C400, - 0x00C51D, - 0x00C600, - 0x00C700, - 0x00C800, - 0x00C900, - 0x00CA00, - 0x00CB00, - 0x00CC15, - 0x00CD00, - 0x00CE00, - 0x00CF00, - 0x00D000, - 0x00D100, - 0x00D200, - 0x00D300, - 0x00D400, - 0x00D500, - 0x00D600, - 0x00D700, - 0x00D800, - 0x00D900, - 0x00DA00, - 0x00DB00, - 0x00DC00, - 0x00DD00, - 0x00DE00, - 0x00DF00, - 0x00E000, - 0x00E100, - 0x00E200, - 0x00E300, - 0x00E400, - 0x00E500, - 0x00E600, - 0x00E700, - 0x00E800, + + 0x00C300, // PRIREF Missing Clock Detection + 0x00C400, // PRIREF Missing Clock Detection + 0x00C51D, // PRIREF Missing Clock Detection + 0x00C600, // SECREF Missing Clock Detection + 0x00C700, // SECREF Missing Clock Detection + 0x00C800, // SECREF Missing Clock Detection + 0x00C900, // PRI/SECREF Window Detection + 0x00CA00, // PRIREF Early Clock Detection + 0x00CB00, // PRIREF Early Clock Detection + 0x00CC15, // PRIREF Early Clock Detection + 0x00CD00, // SECREF Early Clock Detection + 0x00CE00, // SECREF Early Clock Detection + 0x00CF00, // SECREF Early Clock Detection + 0x00D000, // PRIREF Frequency Detection + 0x00D100, // PRIREF Frequency Detection + 0x00D200, // PRIREF Frequency Detection + 0x00D300, // PRIREF Frequency Detection + 0x00D400, // SECREF Frequency Detection + 0x00D500, // SECREF Frequency Detection + 0x00D600, // SECREF Frequency Detection + 0x00D700, // SECREF Frequency Detection + 0x00D800, // PRIREF Frequency Detection + 0x00D900, // PRIREF Frequency Detection + 0x00DA00, // PRIREF Frequency Detection + 0x00DB00, // PRIREF Frequency Detection + 0x00DC00, // PRIREF Frequency Detection + 0x00DD00, // PRIREF Frequency Detection + 0x00DE00, // PRIREF Frequency Detection + 0x00DF00, // PRIREF Frequency Detection + 0x00E000, // PRIREF Frequency Detection + 0x00E100, // SECREF Frequency Detection + 0x00E200, // SECREF Frequency Detection + 0x00E300, // SECREF Frequency Detection + 0x00E400, // SECREF Frequency Detection + 0x00E500, // SECREF Frequency Detection + 0x00E600, // SECREF Frequency Detection + 0x00E700, // SECREF Frequency Detection + 0x00E800, // SECREF Frequency Detection + 0x00E919, 0x00EA00, - 0x00EB02, - 0x00ECFA, - 0x00EDF0, - 0x00EE80, - 0x00EF00, - 0x00F000, - 0x00F100, - 0x00F200, + + 0x00EB02, // PRIREF_PH_VALID_DET1 + 0x00ECFA, // PRIREF_PH_VALID_DET2 + 0x00EDF0, // PRIREF_PH_VALID_DET3 + 0x00EE80, // PRIREF_PH_VALID_DET4 + 0x00EF00, // SECREF_PH_VALID_DET1 + 0x00F000, // SECREF_PH_VALID_DET2 + 0x00F100, // SECREF_PH_VALID_DET3 + 0x00F200, // SECREF_PH_VALID_DET4 + 0x00F33F, 0x00F400, 0x00F921, - 0x00FA00, + + 0x00FA00, // ? + 0x00FB03, 0x00FC29, - 0x00FD00, - 0x00FE00, - 0x00FF00, + + 0x00FD00, // DPLL Switchover Timer + 0x00FE00, // DPLL Switchover Timer + 0x00FF00, // DPLL Switchover Timer + 0x010000, 0x010101, 0x010200, 0x010300, - 0x010402, - 0x010580, - 0x010601, - 0x01072A, - 0x010805, - 0x0109F2, - 0x010A00, - 0x010BA0, - 0x010C00, - 0x010D00, - 0x010E02, - 0x010FA6, - 0x011000, - 0x011100, - 0x011200, - 0x011316, - 0x011416, - 0x011516, - 0x011600, - 0x011700, - 0x011800, - 0x011900, - 0x011A00, - 0x011B00, - 0x011C1E, - 0x011D1E, - 0x011E00, - 0x011F00, - 0x012000, - 0x012100, - 0x012203, - 0x012322, - 0x012400, - 0x012500, - 0x012600, - 0x012700, - 0x01280A, - 0x01290A, - 0x012A0A, - 0x012B00, - 0x012C00, - 0x012D1C, - 0x012E1E, - 0x012F01, + + 0x010402, // DPLL_REF_AVOID_SLIP + 0x010580, // DPLL Reference Control + 0x010601, // DPLL Reference Control + 0x01072A, // DPLL Reference Control + 0x010805, // DPLL Reference Control + 0x0109F2, // DPLL Reference Control + 0x010A00, // DPLL Reference Control + 0x010BA0, // DPLL Reference Control + DPLL Loop Filter + 0x010C00, // DPLL Reference Control + 0x010D00, // DPLL Reference Control + 0x010E02, // DPLL Loop Filter + 0x010FA6, // DPLL Loop Filter + 0x011000, // DPLL Loop Filter + 0x011100, // DPLL Loop Filter + 0x011200, // DPLL Loop Filter + 0x011316, // DPLL Loop Filter + 0x011416, // DPLL Loop Filter + 0x011516, // DPLL Loop Filter + 0x011600, // DPLL Loop Filter + 0x011700, // DPLL Loop Filter + 0x011800, // DPLL Loop Filter + 0x011900, // DPLL Loop Filter + 0x011A00, // DPLL Loop Filter + 0x011B00, // DPLL Loop Filter + 0x011C1E, // DPLL Loop Filter + 0x011D1E, // DPLL Loop Filter + 0x011E00, // DPLL Loop Filter + 0x011F00, // DPLL Loop Filter + 0x012000, // DPLL Loop Filter + 0x012100, // DPLL Loop Filter + 0x012203, // DPLL Phase Lock Detection + 0x012322, // DPLL Phase Lock Detection + 0x012400, // Phase Cancellation for Hitless Switching + 0x012500, // Phase Cancellation for Hitless Switching + 0x012600, // Phase Cancellation for Hitless Switching + 0x012700, // Phase Cancellation for Hitless Switching + 0x01280A, // DPLL Loop Filter + 0x01290A, // DPLL Loop Filter + 0x012A0A, // DPLL Loop Filter + 0x012B00, // ? + 0x012C00, // DPLL Phase Lock Detection + 0x012D1C, // Phase lock declaration threshold + 0x012E1E, // Phase un-lock declaration threshold + 0x012F01, // ? + 0x01300F, 0x013104, 0x013261, @@ -302,43 +323,48 @@ static const uint32_t lmk05318_rom_dpll[] = 0x013CFF, 0x013DFF, 0x013EFF, - 0x013F03, - 0x014000, - 0x01410A, - 0x014200, - 0x014300, - 0x014400, - 0x014501, - 0x014606, - 0x014735, - 0x014875, - 0x01490B, - 0x014A00, - 0x014B64, - 0x014C00, + + 0x013F03, // DPLL Reference Control + 0x014000, // DPLL DCO Lock Detection + 0x01410A, // DPLL DCO Lock Detection + 0x014200, // DPLL DCO Lock Detection + 0x014300, // DPLL DCO Lock Detection + 0x014400, // DPLL DCO Lock Detection + 0x014501, // DPLL DCO Lock Detection + 0x014606, // DPLL DCO Lock Detection + 0x014735, // DPLL DCO Lock Detection + 0x014875, // DPLL DCO Lock Detection + 0x01490B, // DPLL DCO Lock Detection + 0x014A00, // DPLL DCO Unlock Detection + 0x014B64, // DPLL DCO Unlock Detection + 0x014C00, // DPLL DCO Unlock Detection + 0x014D00, - 0x014E61, + 0x014E61, /* PLL2 den */ 0x014FA8, - 0x015006, - 0x015135, - 0x015275, - 0x01530B, - 0x015400, - 0x015500, - 0x015600, - 0x015700, - 0x015800, - 0x015900, - 0x015A00, - 0x015B00, - 0x015C00, - 0x015D00, - 0x015E00, - 0x015F00, - 0x016000, - 0x016500, - 0x016F00, - 0x019B00, + + 0x015006, // DPLL DCO Unlock Detection + 0x015135, // DPLL DCO Unlock Detection + 0x015275, // DPLL DCO Unlock Detection + + 0x01530B, /* PLL1 num*/ + + 0x015400, // DPLL_REF_SYNC_PH_OFFSET + 0x015500, // DPLL_REF_SYNC_PH_OFFSET + 0x015600, // DPLL_REF_SYNC_PH_OFFSET + 0x015700, // DPLL_REF_SYNC_PH_OFFSET + 0x015800, // DPLL_REF_SYNC_PH_OFFSET + 0x015900, // DPLL REF Zero Delay Mode Phase Offset + 0x015A00, // DPLL Freq Incr/Decr enable via pin or reg control + 0x015B00, // DPLL_FDEV + 0x015C00, // DPLL_FDEV + 0x015D00, // DPLL_FDEV + 0x015E00, // DPLL_FDEV + 0x015F00, // DPLL Freq Incr/Decr Numerator Step Word + 0x016000, // DPLL Freq Incr/Decr register control + //0x016500, R + //0x016F00, R + //0x019B00, R }; diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 3dd1ed78..044a26ae 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -173,8 +173,8 @@ START_TEST(lmk05318_solver_test6) res = res ? res : lmk05318_port_request(cfg, 2, 250000000, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 3, 250000000, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 4, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 26000000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 13000000, false, LVCMOS); + res = res ? res : lmk05318_port_request(cfg, 5, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 6, 10000000, false, LVCMOS); res = res ? res : lmk05318_port_request(cfg, 7, 1, false, LVCMOS); ck_assert_int_eq( res, 0 ); @@ -185,14 +185,36 @@ START_TEST(lmk05318_solver_test6) xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + dpll.enabled = true; + dpll.en[LMK05318_PRIREF] = true; + dpll.fref[LMK05318_PRIREF] = 1; + dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; + dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; + dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; + lmk05318_state_t st; memset(&st, 0, sizeof(st)); - res = lmk05318_create_ex(NULL, 0, 0, &xo, false, cfg, 8, &st, true /*dry_run*/); + res = lmk05318_create_ex(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } +START_TEST(lmk05318_dpll_test1) +{ + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + + dpll.enabled = true; + dpll.en[LMK05318_PRIREF] = true; + dpll.fref[LMK05318_PRIREF] = 1; + + int res = lmk05318_dpll_config(&dev, &dpll); + ck_assert_int_eq( res, 0 ); +} + Suite * lmk05318_solver_suite(void) { Suite *s; @@ -202,13 +224,15 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - +/* tcase_add_test(tc_core, lmk05318_solver_test1); - //tcase_add_test(tc_core, lmk05318_solver_test2); + ////////tcase_add_test(tc_core, lmk05318_solver_test2); tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); tcase_add_test(tc_core, lmk05318_solver_test5); - tcase_add_test(tc_core, lmk05318_solver_test6); +*/ tcase_add_test(tc_core, lmk05318_solver_test6); + + //tcase_add_test(tc_core, lmk05318_dpll_test1); suite_add_tcase(s, tc_core); return s; From 980a93d93820d247800dab4b37ac85374d02d629 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 18 Apr 2025 11:50:10 +0300 Subject: [PATCH 098/397] enable GPS & minor fix --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 8d19aa95..eb3ee09d 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -200,7 +200,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // gpo_in_ctrl[1] -- 0 - external SMA, 1 - feedback from LCK_FB // gpo_in_ctrl[2] -- 0 - external SMA, 1 - 1PPS from GPS // gpo_in_ctrl[3] -- En GPS LDO - res = res ? res : dev_gpo_set(dev, IGPO_IN_CTRL, 0); // Disable GPS + res = res ? res : dev_gpo_set(dev, IGPO_IN_CTRL, 0b1101); // Enable GPS // gpo_sy_ctrl*[0] -- LMX2820 LDO Pwr EN // gpo_sy_ctrl*[1] -- LMX2820 CE pin diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 6b17c0a7..0fcf5c43 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -589,6 +589,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, } #if 0 + out->dpll.enabled = true; res = lmk05318_reg_wr_n(out, lmk05318_rom_dpll, SIZEOF_ARRAY(lmk05318_rom_dpll)); if (res) return res; From 06870a6322d2443d839bbc155ca8c6e5dd06a9f7 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 18 Apr 2025 12:48:06 +0300 Subject: [PATCH 099/397] add terra-incognita LMK DPLL registers, it works sometimes --- src/lib/hw/lmk05318/lmk05318.c | 38 ++++++++++++++++++++++++++++++ src/lib/hw/lmk05318/lmk05318_rom.h | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 0fcf5c43..7165fcbb 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -505,6 +505,44 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_DEN_BY2(d->dpll.den), MAKE_LMK05318_DPLL_REF_DEN_BY3(d->dpll.den), MAKE_LMK05318_DPLL_REF_DEN_BY4(d->dpll.den), //R318 + + 0x00C300, // PRIREF Missing Clock Detection + 0x00C400, // PRIREF Missing Clock Detection + 0x00C51D, // PRIREF Missing Clock Detection + // 0x00C600, // SECREF Missing Clock Detection + // 0x00C700, // SECREF Missing Clock Detection + // 0x00C800, // SECREF Missing Clock Detection + 0x00C900, // PRI/SECREF Window Detection + 0x00CA00, // PRIREF Early Clock Detection + 0x00CB00, // PRIREF Early Clock Detection + 0x00CC15, // PRIREF Early Clock Detection + // 0x00CD00, // SECREF Early Clock Detection + // 0x00CE00, // SECREF Early Clock Detection + // 0x00CF00, // SECREF Early Clock Detection + 0x00D000, // PRIREF Frequency Detection + 0x00D100, // PRIREF Frequency Detection + 0x00D200, // PRIREF Frequency Detection + 0x00D300, // PRIREF Frequency Detection + // 0x00D400, // SECREF Frequency Detection + // 0x00D500, // SECREF Frequency Detection + // 0x00D600, // SECREF Frequency Detection + // 0x00D700, // SECREF Frequency Detection + 0x00D900, // PRIREF Frequency Detection + 0x00DA00, // PRIREF Frequency Detection + 0x00DB00, // PRIREF Frequency Detection + 0x00DC00, // PRIREF Frequency Detection + 0x00DD00, // PRIREF Frequency Detection + 0x00DE00, // PRIREF Frequency Detection + 0x00DF00, // PRIREF Frequency Detection + 0x00E000, // PRIREF Frequency Detection + // 0x00E100, // SECREF Frequency Detection + // 0x00E200, // SECREF Frequency Detection + // 0x00E300, // SECREF Frequency Detection + // 0x00E400, // SECREF Frequency Detection + // 0x00E500, // SECREF Frequency Detection + // 0x00E600, // SECREF Frequency Detection + // 0x00E700, // SECREF Frequency Detection + // 0x00E800, // SECREF Frequency Detection }; res = lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); } diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index 8d963a0a..3db49857 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -215,7 +215,7 @@ static const uint32_t lmk05318_rom_dpll[] = 0x00D500, // SECREF Frequency Detection 0x00D600, // SECREF Frequency Detection 0x00D700, // SECREF Frequency Detection - 0x00D800, // PRIREF Frequency Detection + 0x00D800, // ? 0x00D900, // PRIREF Frequency Detection 0x00DA00, // PRIREF Frequency Detection 0x00DB00, // PRIREF Frequency Detection From e30bad9f7bc618167fef93a258b4b6e4e9355be3 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 18 Apr 2025 16:01:58 +0300 Subject: [PATCH 100/397] LMK DPLL fixes --- src/lib/cal/opt_func.h | 8 ++ src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 118 ++++++++++++++++-------- src/lib/xdsp/utests/xdsp_utest_common.h | 9 +- 4 files changed, 87 insertions(+), 50 deletions(-) diff --git a/src/lib/cal/opt_func.h b/src/lib/cal/opt_func.h index b71f94e6..5c37a9ab 100644 --- a/src/lib/cal/opt_func.h +++ b/src/lib/cal/opt_func.h @@ -10,6 +10,7 @@ #include "stdint.h" #include "stdbool.h" +#include "time.h" #define MAX(a, b) \ ({ __typeof__ (a) _a = (a); \ @@ -60,4 +61,11 @@ int find_best_2d(struct opt_iteration2d *ops, unsigned max_count, void* param, i uint64_t find_gcd(uint64_t a, uint64_t b); void binary_print_u32(uint32_t x, char* s, bool reverse); +static inline uint64_t clock_get_time() +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (uint64_t)ts.tv_sec * 1000000LL + (uint64_t)ts.tv_nsec/1000LL; +} + #endif diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index eb3ee09d..50f5efd5 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -326,7 +326,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; //wait for PRIREF/SECREF validation - res = lmk05318_wait_dpll_ref_stat(&d->gen, 200000); + res = lmk05318_wait_dpll_ref_stat(&d->gen, 10000000); //10s if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 7165fcbb..06113bb4 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -505,46 +505,65 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_DEN_BY2(d->dpll.den), MAKE_LMK05318_DPLL_REF_DEN_BY3(d->dpll.den), MAKE_LMK05318_DPLL_REF_DEN_BY4(d->dpll.den), //R318 + }; + + uint32_t pri_miss_clock_det = d->dpll.ref_en[LMK05318_PRIREF] ? 0x1D : 0x0; + uint32_t sec_miss_clock_det = d->dpll.ref_en[LMK05318_SECREF] ? 0x1D : 0x0; - 0x00C300, // PRIREF Missing Clock Detection - 0x00C400, // PRIREF Missing Clock Detection - 0x00C51D, // PRIREF Missing Clock Detection - // 0x00C600, // SECREF Missing Clock Detection - // 0x00C700, // SECREF Missing Clock Detection - // 0x00C800, // SECREF Missing Clock Detection - 0x00C900, // PRI/SECREF Window Detection - 0x00CA00, // PRIREF Early Clock Detection - 0x00CB00, // PRIREF Early Clock Detection - 0x00CC15, // PRIREF Early Clock Detection - // 0x00CD00, // SECREF Early Clock Detection - // 0x00CE00, // SECREF Early Clock Detection - // 0x00CF00, // SECREF Early Clock Detection - 0x00D000, // PRIREF Frequency Detection - 0x00D100, // PRIREF Frequency Detection - 0x00D200, // PRIREF Frequency Detection - 0x00D300, // PRIREF Frequency Detection - // 0x00D400, // SECREF Frequency Detection - // 0x00D500, // SECREF Frequency Detection - // 0x00D600, // SECREF Frequency Detection - // 0x00D700, // SECREF Frequency Detection - 0x00D900, // PRIREF Frequency Detection - 0x00DA00, // PRIREF Frequency Detection - 0x00DB00, // PRIREF Frequency Detection - 0x00DC00, // PRIREF Frequency Detection - 0x00DD00, // PRIREF Frequency Detection - 0x00DE00, // PRIREF Frequency Detection - 0x00DF00, // PRIREF Frequency Detection - 0x00E000, // PRIREF Frequency Detection - // 0x00E100, // SECREF Frequency Detection - // 0x00E200, // SECREF Frequency Detection - // 0x00E300, // SECREF Frequency Detection - // 0x00E400, // SECREF Frequency Detection - // 0x00E500, // SECREF Frequency Detection - // 0x00E600, // SECREF Frequency Detection - // 0x00E700, // SECREF Frequency Detection - // 0x00E800, // SECREF Frequency Detection + uint32_t pri_early_clk_det = d->dpll.ref_en[LMK05318_PRIREF] ? 0x15 : 0x0; + uint32_t sec_early_clk_det = d->dpll.ref_en[LMK05318_SECREF] ? 0x15 : 0x0; + + uint32_t dpll_regs_clk_detections[] = + { + MAKE_LMK05318_REF0_MISSCLK_DIV_BY0(pri_miss_clock_det), + MAKE_LMK05318_REF0_MISSCLK_DIV_BY1(pri_miss_clock_det), + MAKE_LMK05318_REF0_MISSCLK_DIV_BY2(pri_miss_clock_det), // R195:197 PRIREF Missing Clock Detection + // + MAKE_LMK05318_REF1_MISSCLK_DIV_BY0(sec_miss_clock_det), + MAKE_LMK05318_REF1_MISSCLK_DIV_BY1(sec_miss_clock_det), + MAKE_LMK05318_REF1_MISSCLK_DIV_BY2(sec_miss_clock_det), // R198:200 SECREF Missing Clock Detection + + MAKE_LMK05318_REF_MISSCLK_CTL(d->dpll.ref_en[LMK05318_SECREF] ? 0 : 0, d->dpll.ref_en[LMK05318_PRIREF] ? 0 : 0), // R201 PRI/SECREF Window Detection + + MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY0(pri_early_clk_det), + MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY1(pri_early_clk_det), + MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(pri_early_clk_det), // R202:204 PRIREF Early Clock Detection + // + MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY0(sec_early_clk_det), + MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY1(sec_early_clk_det), + MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(sec_early_clk_det), // R205:207 SECREF Early Clock Detection + + MAKE_LMK05318_REF0_PPM_MIN_BY0(0), + MAKE_LMK05318_REF0_PPM_MIN_BY1(0), + MAKE_LMK05318_REF0_PPM_MAX_BY0(0), + MAKE_LMK05318_REF0_PPM_MAX_BY1(0), // R208:211 PRIREF Frequency Detection + // + MAKE_LMK05318_REF1_PPM_MIN_BY0(0), + MAKE_LMK05318_REF1_PPM_MIN_BY1(0), + MAKE_LMK05318_REF1_PPM_MAX_BY0(0), + MAKE_LMK05318_REF1_PPM_MAX_BY1(0), // R212:215 SECREF Frequency Detection + + MAKE_LMK05318_REF0_CNTSTRT_BY0(0), + MAKE_LMK05318_REF0_CNTSTRT_BY1(0), + MAKE_LMK05318_REF0_CNTSTRT_BY2(0), + MAKE_LMK05318_REF0_CNTSTRT_BY3(0), + MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY0(0), + MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY1(0), + MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY2(0), + MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY3(0), // R217:224 PRIREF Frequency Detection + // + MAKE_LMK05318_REF1_CNTSTRT_BY0(0), + MAKE_LMK05318_REF1_CNTSTRT_BY1(0), + MAKE_LMK05318_REF1_CNTSTRT_BY2(0), + MAKE_LMK05318_REF1_CNTSTRT_BY3(0), + MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY0(0), + MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY1(0), + MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY2(0), + MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY3(0), // R225:232 SECREF Frequency Detection }; + res = lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); + res = res ? res : lmk05318_add_reg_to_map(d, dpll_regs_clk_detections, SIZEOF_ARRAY(dpll_regs_clk_detections)); } if(res) @@ -2060,6 +2079,19 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) return 0; } +static const char* lmk05318_decode_dpll_refsel_stat(uint8_t stat) +{ + switch(stat) + { + case 0: return "HOLDOVER"; + case 1: return "PRIREF"; + case 2: return "SECREF"; + case 3: return "RESERVED"; + } + + return "UNKNOWN"; +} + int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) { if(!d->dpll.enabled) @@ -2075,6 +2107,8 @@ int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) while(timeout == 0 || elapsed < timeout) { + uint64_t tk = clock_get_time(); + res = lmk05318_reg_rd(d, REFVALSTAT, ®); res = res ? res : lmk05318_reg_rd(d, 0xa7, ®2); if(res) @@ -2090,14 +2124,16 @@ int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) if(valid) break; - usleep(100); - elapsed += 100; + usleep(100000); + elapsed += (clock_get_time() - tk); } + USDR_LOG("5318", USDR_LOG_INFO, "PRIREF_VALSTAT:%u SECREF_VALSTAT:%u DPLL_REFSEL_STAT:0x%02x(%s)", + reg & PRIREF_VALSTAT_MSK, reg & SECREF_VALSTAT_MSK, reg2, lmk05318_decode_dpll_refsel_stat(reg2 & 0b11)); + if(!valid) { - USDR_LOG("5318", USDR_LOG_ERROR, "DPLL input reference NOT VALID! PRIREF_VALSTAT:%u SECREF_VALSTAT:%u R167:0x%02x", - reg & PRIREF_VALSTAT_MSK, reg & SECREF_VALSTAT_MSK, reg2); + USDR_LOG("5318", USDR_LOG_ERROR, "DPLL input reference NOT VALID!"); return -ETIMEDOUT; } diff --git a/src/lib/xdsp/utests/xdsp_utest_common.h b/src/lib/xdsp/utests/xdsp_utest_common.h index 09cb0de5..cad9e06e 100644 --- a/src/lib/xdsp/utests/xdsp_utest_common.h +++ b/src/lib/xdsp/utests/xdsp_utest_common.h @@ -4,17 +4,10 @@ #ifndef XDSP_UTEST_COMMON_H #define XDSP_UTEST_COMMON_H -#include #include #include +#include "../../cal/opt_func.h" #define ALIGN_BYTES (size_t)64 -static inline uint64_t clock_get_time() -{ - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - return (uint64_t)ts.tv_sec * 1000000LL + (uint64_t)ts.tv_nsec/1000LL; -} - #endif // XDSP_UTEST_COMMON_H From 027eebe0c3bb37da6079bae043618612995073a0 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 18 Apr 2025 16:09:55 +0300 Subject: [PATCH 101/397] minor LMK fix --- src/lib/hw/lmk05318/lmk05318.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 06113bb4..03daf166 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -2128,8 +2128,11 @@ int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) elapsed += (clock_get_time() - tk); } - USDR_LOG("5318", USDR_LOG_INFO, "PRIREF_VALSTAT:%u SECREF_VALSTAT:%u DPLL_REFSEL_STAT:0x%02x(%s)", - reg & PRIREF_VALSTAT_MSK, reg & SECREF_VALSTAT_MSK, reg2, lmk05318_decode_dpll_refsel_stat(reg2 & 0b11)); + USDR_LOG("5318", USDR_LOG_INFO, "ELAPSED:%.4f PRIREF_VALSTAT:%u SECREF_VALSTAT:%u DPLL_REFSEL_STAT:0x%02x(%s)", + (double)elapsed / 1000000.f, + (reg & PRIREF_VALSTAT_MSK) >> PRIREF_VALSTAT_OFF, + (reg & SECREF_VALSTAT_MSK) >> SECREF_VALSTAT_OFF, + reg2, lmk05318_decode_dpll_refsel_stat(reg2 & 0b11)); if(!valid) { From 0eb44137c5dc5da3691826fa828a6874babfc274 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 18 Apr 2025 17:49:18 +0300 Subject: [PATCH 102/397] minor fixes --- src/lib/device/pe_sync/pe_sync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 50f5efd5..5f14027d 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -326,7 +326,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; //wait for PRIREF/SECREF validation - res = lmk05318_wait_dpll_ref_stat(&d->gen, 10000000); //10s + res = lmk05318_wait_dpll_ref_stat(&d->gen, 60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 03daf166..65a79d83 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -2128,7 +2128,7 @@ int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) elapsed += (clock_get_time() - tk); } - USDR_LOG("5318", USDR_LOG_INFO, "ELAPSED:%.4f PRIREF_VALSTAT:%u SECREF_VALSTAT:%u DPLL_REFSEL_STAT:0x%02x(%s)", + USDR_LOG("5318", USDR_LOG_INFO, "ELAPSED:%.4fs PRIREF_VALSTAT:%u SECREF_VALSTAT:%u DPLL_REFSEL_STAT:0x%02x(%s)", (double)elapsed / 1000000.f, (reg & PRIREF_VALSTAT_MSK) >> PRIREF_VALSTAT_OFF, (reg & SECREF_VALSTAT_MSK) >> SECREF_VALSTAT_OFF, From 85103f40d0bf6c0284c718503fc457e87e1c44d3 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 18 Apr 2025 20:36:16 +0300 Subject: [PATCH 103/397] LMK DPLL another dump --- src/lib/hw/lmk05318/lmk05318.c | 1 + src/lib/hw/lmk05318/lmk05318_rom.h | 353 +++++++++++++++++++++++++++++ 2 files changed, 354 insertions(+) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 65a79d83..d0a4906b 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -647,6 +647,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, #if 0 out->dpll.enabled = true; + out->dpll.ref_en[LMK05318_PRIREF] = true; res = lmk05318_reg_wr_n(out, lmk05318_rom_dpll, SIZEOF_ARRAY(lmk05318_rom_dpll)); if (res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index 3db49857..ff6b8ac4 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -2,6 +2,359 @@ // SPDX-License-Identifier: MIT static const uint32_t lmk05318_rom_dpll[] = +{ + //0x000000, + //0x000100, + //0x000200, + //0x000300, + //0x000400, + //0x000500, R + //0x000600, + //0x000700, + //0x000800, + //0x000A00, + //0x000B00, + + 0x000C1B, //ok + //0x000D00, R + //0x000E00, R + //0x000F00, // ok default + //0x001000, // ok default + //0x001100, // ok default + //0x001200, // ok default + 0x001300, // ok + 0x001400, // ok + //0x001500, // ok default + //0x001600, // ok default + 0x001700, // ok, 0xff - mute specifics + 0x001800, // ok, 0xff - mute specifics + 0x001900, // ok + 0x001A00, // XO hyst timer + 0x001B00, // XO SE energy det mode + 0x001C00, // XO DIFF energy det mode + 0x001D17, // ************************? DPLL mute on ph lock + 0x001E00, // *********? LDO timer scale + 0x002000, // *********? PLL1/2 MASH LDO trim + //0x002300, // ok default + //0x002400, // ok default + //0x002500, //default STATUS0 open Drain mode + //0x002600,//default + 0x002700, // ok + 0x002806, // ok (?) + //0x002900, // default SPARE_NVMBASE2 + 0x002A10, // ok (? XO inp buffer=0) + 0x002B40, // ok (default bits?) + 0x002C00, //ok + 0x002D07, //ok (default bits) + 0x002E01, //ok + 0x002F00, //ok (counters differ) + //0x003000, // ok stats + //0x003100, // ok stats + //0x003200, //default + 0x003310, //ok + 0x003410, //ok + 0x003513, //ok + 0x003610, //ok + 0x003710, //ok + 0x003809, //ok + 0x003900, //ok + 0x003A0F, //ok + 0x003B00, //ok + 0x003C0F, //ok + 0x003D3E, //ok + 0x003EF9, //ok + 0x003F3E, //ok + 0x004095, //ok + 0x004102, //ok + 0x0042F8, //ok + 0x0043FF, //ok + 0x004400, // ????? APLL1 BAW drain != default TODO + //0x004500, //default + 0x004607, //ok + 0x00473F, //ok + //0x004800, R + //0x004900, //default + 0x004A00, //ok + 0x004B00, //???? !=default + 0x004C00, //APLL1 Post div1???? todo + 0x004D00, //PLL1 loop filter?.. todo + //0x004E00, ??? unknown + 0x004F00, //ok (default bit) + 0x005000, //ok + 0x00510A, //ok + 0x005200, //ok + 0x00530E, //ok + 0x0054A6, //ok + 0x005500, //ok + 0x005600, //ok + 0x00571E, //ok + 0x005884, //ok + 0x005980, //ok + 0x005A00, //ok + 0x005B14, //ok + 0x005C00, //ok + 0x005D0E, //ok + 0x005EA6, //ok + 0x005F00, //ok + 0x006000, //ok + 0x00611E, //ok + 0x006284, //ok + 0x006380, //ok + 0x006429, //ok + //0x006500, // != default, PLL2 charge pump + //0x006633, //PLL2 (off) + //0x006700, //PLL2 Loop filter sett + //0x006800, //PLL2 (off) default + //0x006900, //PLL2 + 0x006A00, // PLL1 N Delay div (!=default) + 0x006B00, // PLL1 N Delay div (!=default) + 0x006C00, //ok + 0x006D32, //ok + 0x006E00, //ok + 0x006F00, //ok + 0x007000, //ok + 0x007100, //ok + 0x007200, //ok + 0x007303, //ok + 0x007401, //ok + + //0x007500, //PLL1_FDEV ==default + //0x007600, //PLL1_FDEV ==default + //0x007700, //PLL1_FDEV ==default + //0x007800, //PLL1_FDEV ==default + //0x007900, //PLL1_FDEV ==default + //0x007A00, //PLL1_FDEV ==default + //0x007B00, // PLL1_NUM_STAT_39:32 + //0x007C00, // PLL1_NUM_STAT_31:24 + //0x007D00, // PLL1_NUM_STAT_23:16 + //0x007E00, // PLL1_NUM_STAT_15:8 + //0x007F00, // PLL1_NUM_STAT + //0x008000, //PLL1 NUM saturation(default) + 0x008100, // PLL1 Loop Filter R2 ??? !=default + //0x008200, // PLL1 loop filter C1 ==default + 0x008300, // PLL1 Loop Filter R3 ??? != default + 0x008400, // PLL1 Loop Filter R4 ??? != default + //0x008500, // PLL1 Loop Filter C4 ==default + //0x008600, // Bit 8 of PLL2_NDIV + //0x00872C, // Bits 7:0 of PLL2 N Divider + //0x00887C, // Bits 23:16 of PLL2_NUM + //0x0089E0, // Bits 15:8 of PLL2_NUM + //0x008ABF, // PLL2 Fractional Divider Numerator + //0x008B00, // SDM Dither Mode + APLL2 SDM Order + //0x008C00, // PLL2 Loop Filter R2 + //0x008D00, // PLL2 Loop Filter C1 == default + //0x008E00, // PLL2 Loop Filter R3 + //0x008F00, // PLL2 Loop Filter R4 + //0x009000, // PLL2 Loop Filter C4/C3 + 0x009100, // XO Input Wait Timer ??? != default + 0x009200, // ??? unknown !=default 0x84 + //0x009300, // ??? unknown ==default + //0x009500, // ??? unknown ==default + //0x009600, //APPL1 Amp Cal up/low threhold ==default + //0x009700, // ??? unknown ==default + //0x009800, // ??? unknown ==default + //0x009900, //APPL2 Amp Cal up/low threhold ==default + 0x009A00, // LDO trim bits ??? != default + //0x009B00, // NVM Stored CRC RO + //0x009C00, // NVM Program Count RO + //0x009D00, // NVM misc + //0x009E00, //MUMLCRC RO + //0x009F00, // Bits 12:8 of MEMADR ==default + //0x00A000, // Memory Address ==default + //0x00A100, // EEPROM Read Data RO + //0x00A200, // RAM Read/Write Data ==default + //0x00A400, // NVM Program Unlock + //0x00A500, // NVM BASE unlock ==default + //0x00A700, // unknown ==default + //0x00B200, // unknown ==default + //0x00B400, // Bits 37:32 of DPLL_TUNING_FREE_RUN ==default + //0x00B500, // Bits 31:24 of DPLL_TUNING_FREE_RUN ==default + //0x00B600, // Bits 23:16 of DPLL_TUNING_FREE_RUN ==default + //0x00B700, // Bits 15:8 of DPLL_TUNING_FREE_RUN ==default + //0x00B800, // DPLL Free-run tuning word ==default + 0x00B9F1, // DPLL_REF_HIST_EN=enabled !=default ????? + 0x00BA01, // DPLL REF Tuning History Timer !=default ??? + //0x00BB00, //DPLL_REF_HISTDLY ==default + //0x00BC00, //DPLL_REF_HISTDLY ==default + //0x00BD00, //DPLL_REF_HISTDLY ==default + //0x00BE00, //DPLL_REF_HISTDLY ==default + //0x00BF00, //unknown ==default + 0x00C000, // PRI/SECREF detectors settings !=default ??? + + 0x00C119, //ok + 0x00C200, //ok + 0x00C300, //ok + 0x00C400, //ok + 0x00C51D, //ok + 0x00C600, //ok + 0x00C700, //ok + 0x00C800, //ok + 0x00C900, //ok + 0x00CA00, //ok + 0x00CB00, //ok + 0x00CC15, //ok + 0x00CD00, //ok + 0x00CE00, //ok + 0x00CF00, //ok + 0x00D000, //ok + 0x00D100, //ok + 0x00D200, //ok + 0x00D300, //ok + 0x00D400, //ok + 0x00D500, //ok + 0x00D600, //ok + 0x00D700, //ok + //0x00D800, //unknown + 0x00D900, //ok + 0x00DA00, //ok + 0x00DB00, //ok + 0x00DC00, //ok + 0x00DD00, //ok + 0x00DE00, //ok + 0x00DF00, //ok + 0x00E000, //ok + 0x00E100, //ok + 0x00E200, //ok + 0x00E300, //ok + 0x00E400, //ok + 0x00E500, //ok + 0x00E600, //ok + 0x00E700, //ok + 0x00E800, //ok + 0x00E90F, //ok + 0x00EA00, //ok + + 0x00EB02, //PRIREF_PH_VALID_DET1 !=default + 0x00ECFA, + 0x00EDF0, + 0x00EE80, // + 0x00EF00, + 0x00F000, + 0x00F100, + 0x00F200, //SECREF_PH_VALID_DET4 !=default + + 0x00F33F, //ok + 0x00F400, //ok + 0x00F921, //ok + //0x00FA00, //default + 0x00FB03, //ok + 0x00FC29, //ok +++ZDM + //0x00FD00, default + //0x00FE00, default + //0x00FF00, default + + 0x010000, //ok + 0x010101, //ok + 0x010200, //ok + 0x010300, //ok + + 0x010402, // DPLL_REF_AVOID_SLIP !=default + 0x010580, // DPLL Reference Control + 0x010601, // DPLL Reference Control + 0x01072A, // DPLL Reference Control + 0x010805, // DPLL Reference Control + 0x0109F2, // DPLL Reference Control + 0x010A00, // DPLL Reference Control + 0x010BA0, // DPLL Reference Control + DPLL Loop Filter + 0x010C00, // DPLL Reference Control + 0x010D00, // DPLL Reference Control + 0x010E02, // DPLL Loop Filter + 0x010FA6, // DPLL Loop Filter + 0x011000, // DPLL Loop Filter + 0x011100, // DPLL Loop Filter + 0x011200, // DPLL Loop Filter + 0x011316, // DPLL Loop Filter + 0x011416, // DPLL Loop Filter + 0x011516, // DPLL Loop Filter + 0x011600, // DPLL Loop Filter + 0x011700, // DPLL Loop Filter + 0x011800, // DPLL Loop Filter + 0x011900, // DPLL Loop Filter + 0x011A00, // DPLL Loop Filter + 0x011B00, // DPLL Loop Filter + 0x011C1E, // DPLL Loop Filter + 0x011D1E, // DPLL Loop Filter + 0x011E00, // DPLL Loop Filter + 0x011F00, // DPLL Loop Filter + 0x012000, // DPLL Loop Filter + 0x012100, // DPLL Loop Filter + 0x012203, // DPLL Phase Lock Detection + 0x012322, // DPLL Phase Lock Detection + 0x012400, // Phase Cancellation for Hitless Switching + 0x012500, // Phase Cancellation for Hitless Switching + 0x012600, // Phase Cancellation for Hitless Switching + 0x012700, // Phase Cancellation for Hitless Switching + 0x01280A, // DPLL Loop Filter + 0x01290A, // DPLL Loop Filter + 0x012A0A, // DPLL Loop Filter + //0x012B00, // unknown + 0x012C00, // DPLL Phase Lock Detection + 0x012D1C, // Phase lock declaration threshold + 0x012E1E, // Phase un-lock declaration threshold + //0x012F01, // unknown????????????? + + 0x01300F, //ok + 0x013104, //ok + 0x013261, //ok + 0x0133F8, //ok + 0x013443, //ok + 0x0135C3, /////// + 0x0136C3, /////// + 0x0137C3, /////// + 0x0138C3, /////// + 0x0139C3, /////// + 0x013AFF, /////// DPLL NUM/DEN (may differ) + 0x013BFF, /////// + 0x013CFF, /////// + 0x013DFF, /////// + 0x013EFF, /////// + + 0x013F03, // DPLL Reference Control != default + 0x014000, // DPLL DCO Lock Detection + 0x01410A, // DPLL DCO Lock Detection + 0x014200, // DPLL DCO Lock Detection + 0x014300, // DPLL DCO Lock Detection + 0x014400, // DPLL DCO Lock Detection + 0x014501, // DPLL DCO Lock Detection + 0x014606, // DPLL DCO Lock Detection + 0x014735, // DPLL DCO Lock Detection + 0x014875, // DPLL DCO Lock Detection + 0x01490B, // DPLL DCO Lock Detection + 0x014A00, // DPLL DCO Unlock Detection + 0x014B64, // DPLL DCO Unlock Detection + 0x014C00, // DPLL DCO Unlock Detection + + //0x014D00, + //0x014E61, /* PLL2 den */ + //0x014FA8, + + 0x015006, // DPLL DCO Unlock Detection != default + 0x015135, // DPLL DCO Unlock Detection + 0x015275, // DPLL DCO Unlock Detection + + 0x01530B, /* Ok PLL1 num*/ + + //0x015400, // DPLL_REF_SYNC_PH_OFFSET ==default + //0x015500, // DPLL_REF_SYNC_PH_OFFSET ==default + //0x015600, // DPLL_REF_SYNC_PH_OFFSET ==default + //0x015700, // DPLL_REF_SYNC_PH_OFFSET ==default + //0x015800, // DPLL_REF_SYNC_PH_OFFSET ==default + //0x015900, // DPLL REF Zero Delay Mode Phase Offset ==default + //0x015A00, // DPLL Freq Incr/Decr enable via pin or reg control ==default + //0x015B00, // DPLL_FDEV ==default + //0x015C00, // DPLL_FDEV ==default + //0x015D00, // DPLL_FDEV ==default + //0x015E00, // DPLL_FDEV ==default + //0x015F00, // DPLL Freq Incr/Decr Numerator Step Word ==default + //0x016000, // DPLL Freq Incr/Decr register control ==default + + //0x016500, + //0x016F00, R + //0x019B00, +}; + + +static const uint32_t lmk05318_rom_dpll____[] = { /* 0x000000, From 1067f226560402de5460d3e69c347aa79f10dd45 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 19 Apr 2025 14:16:02 +0300 Subject: [PATCH 104/397] another DPLL patch bundle --- src/lib/hw/lmk05318/lmk05318.c | 85 +++---------- src/lib/hw/lmk05318/lmk05318_rom.h | 193 +++++++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 68 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index d0a4906b..36846e11 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -404,19 +404,21 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo if(d->dpll.enabled == false) { - uint32_t dpll_regs[] = + // WITHOUT DPLL + uint32_t no_dpll_regs[] = { - MAKE_LMK05318_DEV_CTL(0, 0, 1, 1, 1, 1, 1), //R12 set APLL1 mode - DPLL - MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, 1), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise - MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 1), //R40 set programmed APPL2 denumerator always - MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, 0, 0), //R252 disable DPLL - MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 - MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 + MAKE_LMK05318_DEV_CTL(0, 0, 0/*SYNC_AUTO_DPLL*/, 1, 1, 1, 1), //R12 set APLL1 mode - NO DPLL + MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, 1/*Programmed 24-bit DEN*/), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise + MAKE_LMK05318_SPARE_NVMBASE2_BY1(0, 0, 1), //R40 set programmed APPL2 denumerator always + MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, 0, 0), //R252 disable DPLL + MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 + MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 }; - res = lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); + res = lmk05318_add_reg_to_map(d, no_dpll_regs, SIZEOF_ARRAY(no_dpll_regs)); } else { + //WITH DPLL const bool one_pps[] = { (dpll->en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1), @@ -443,8 +445,8 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo uint32_t dpll_regs[] = { - MAKE_LMK05318_DEV_CTL(0, 0, 0, 1, 1, 1, 1), //R12 set APLL1 mode - Free-run - MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, 0), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise + MAKE_LMK05318_DEV_CTL(0, 0, 1/*SYNC_AUTO_DPLL*/, 1, 1, 1, 1), //R12 set APLL1 mode - Free-run + MAKE_LMK05318_SPARE_NVMBASE2_BY2(0, 0/*Fixed 40-bit DEN*/), //R39 set fixed APLL1 denumerator for DPLL en, programmed den otherwise MAKE_LMK05318_SPARE_NVMBASE2_BY1(dpll->dc_mode[LMK05318_SECREF], dpll->dc_mode[LMK05318_PRIREF], 1), //R40 set programmed APPL2 denumerator always MAKE_LMK05318_REF_CLKCTL1(!dpll->en[LMK05318_SECREF] || (dpll->fref[LMK05318_SECREF] >= 5000000 && dpll->type[LMK05318_SECREF] != IN_OPTS_CMOS && dpll->type[LMK05318_SECREF] != IN_OPTS_SE_INT_50) ? 0 : 1, !dpll->en[LMK05318_PRIREF] || (dpll->fref[LMK05318_PRIREF] >= 5000000 && dpll->type[LMK05318_PRIREF] != IN_OPTS_CMOS && dpll->type[LMK05318_PRIREF] != IN_OPTS_SE_INT_50) ? 0 : 1, @@ -507,63 +509,8 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_DEN_BY4(d->dpll.den), //R318 }; - uint32_t pri_miss_clock_det = d->dpll.ref_en[LMK05318_PRIREF] ? 0x1D : 0x0; - uint32_t sec_miss_clock_det = d->dpll.ref_en[LMK05318_SECREF] ? 0x1D : 0x0; - - uint32_t pri_early_clk_det = d->dpll.ref_en[LMK05318_PRIREF] ? 0x15 : 0x0; - uint32_t sec_early_clk_det = d->dpll.ref_en[LMK05318_SECREF] ? 0x15 : 0x0; - - uint32_t dpll_regs_clk_detections[] = - { - MAKE_LMK05318_REF0_MISSCLK_DIV_BY0(pri_miss_clock_det), - MAKE_LMK05318_REF0_MISSCLK_DIV_BY1(pri_miss_clock_det), - MAKE_LMK05318_REF0_MISSCLK_DIV_BY2(pri_miss_clock_det), // R195:197 PRIREF Missing Clock Detection - // - MAKE_LMK05318_REF1_MISSCLK_DIV_BY0(sec_miss_clock_det), - MAKE_LMK05318_REF1_MISSCLK_DIV_BY1(sec_miss_clock_det), - MAKE_LMK05318_REF1_MISSCLK_DIV_BY2(sec_miss_clock_det), // R198:200 SECREF Missing Clock Detection - - MAKE_LMK05318_REF_MISSCLK_CTL(d->dpll.ref_en[LMK05318_SECREF] ? 0 : 0, d->dpll.ref_en[LMK05318_PRIREF] ? 0 : 0), // R201 PRI/SECREF Window Detection - - MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY0(pri_early_clk_det), - MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY1(pri_early_clk_det), - MAKE_LMK05318_REF0_EARLY_CLK_DIV_BY2(pri_early_clk_det), // R202:204 PRIREF Early Clock Detection - // - MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY0(sec_early_clk_det), - MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY1(sec_early_clk_det), - MAKE_LMK05318_REF1_EARLY_CLK_DIV_BY2(sec_early_clk_det), // R205:207 SECREF Early Clock Detection - - MAKE_LMK05318_REF0_PPM_MIN_BY0(0), - MAKE_LMK05318_REF0_PPM_MIN_BY1(0), - MAKE_LMK05318_REF0_PPM_MAX_BY0(0), - MAKE_LMK05318_REF0_PPM_MAX_BY1(0), // R208:211 PRIREF Frequency Detection - // - MAKE_LMK05318_REF1_PPM_MIN_BY0(0), - MAKE_LMK05318_REF1_PPM_MIN_BY1(0), - MAKE_LMK05318_REF1_PPM_MAX_BY0(0), - MAKE_LMK05318_REF1_PPM_MAX_BY1(0), // R212:215 SECREF Frequency Detection - - MAKE_LMK05318_REF0_CNTSTRT_BY0(0), - MAKE_LMK05318_REF0_CNTSTRT_BY1(0), - MAKE_LMK05318_REF0_CNTSTRT_BY2(0), - MAKE_LMK05318_REF0_CNTSTRT_BY3(0), - MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY0(0), - MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY1(0), - MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY2(0), - MAKE_LMK05318_REF0_HOLD_CNTSTRT_BY3(0), // R217:224 PRIREF Frequency Detection - // - MAKE_LMK05318_REF1_CNTSTRT_BY0(0), - MAKE_LMK05318_REF1_CNTSTRT_BY1(0), - MAKE_LMK05318_REF1_CNTSTRT_BY2(0), - MAKE_LMK05318_REF1_CNTSTRT_BY3(0), - MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY0(0), - MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY1(0), - MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY2(0), - MAKE_LMK05318_REF1_HOLD_CNTSTRT_BY3(0), // R225:232 SECREF Frequency Detection - }; - - res = lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); - res = res ? res : lmk05318_add_reg_to_map(d, dpll_regs_clk_detections, SIZEOF_ARRAY(dpll_regs_clk_detections)); + res = lmk05318_add_reg_to_map(d, lmk05318_rom_dpll_empiric, SIZEOF_ARRAY(lmk05318_rom_dpll_empiric)); + res = res ? res : lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); } if(res) @@ -607,7 +554,9 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo 0x006284, // | 0x006380, //R99 - MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,3), //R115 PLL1 MASHORD=3 + MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,3), //R115 PLL1 MASHORD=3 + MAKE_LMK05318_OUT_MUTE(0,0,0,0,0,0,0,0), //R25 unmute all chans + }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index ff6b8ac4..d38e2f99 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -1,6 +1,199 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +static const uint32_t lmk05318_rom_dpll_empiric[] = +{ + 0x000d00, // [RO] + 0x000e00, // [RO] + 0x000f00, // [DEF] INT_MASK + 0x001000, // [DEF] INT_MASK + 0x001100, // [DEF] XO/APLL LOL Polarity + 0x001200, // [DEF] DPLL LOL Polarity + 0x001500, // [DEF] INT_AND_OR + 0x001600, // [DEF] STATUS0/1 Polarity + 0x001900, // OUT MUTE ctrls + 0x001a00, // [DEF] XO hyst timer + 0x001b00, // XO SE energy det mode + 0x001c00, // XO DIFF energy det mode + 0x001d00, // mute during LOCK ?? 0x17 + 0x001e00, // LDO timer scale + 0x002000, // APLL MASD + LDO trim + 0x002300, // [DEF] VCO1/2 LSO settings + 0x002400, // [DEF] STAT0/1 Driver Type Output + 0x002500, // STATUS0 open Drain mode + 0x002600, // STATUS1 open Drain mode + 0x002900, // [DEF] SPARE_NVMBASE2 + 0x003000, // STAT0_SEL + 0x003100, // STAT1_SEL + 0x003200, // [DEF] DCO freq + CH6/7 PD + 0x004400, // APLL1 BAW drain + 0x004500, // unknown + 0x004800, // [RO] RO OUTCH active flags + 0x004900, // [DEF] REF_BYPASS (route REF to OUTs instead of VCO1) + 0x004b00, // PLL1 Vtune Monitor bypass + charge pump gain + 0x004c00, // PLL1 post-div 1 + 0x004d00, // PLL1 loop filter + 0x004e00, // [DEF] PLL1 bleed resistor + 0x006500, // PLL2 charge pump + 0x006633, // PLL2 post-div2 post-div1 + 0x006700, // PLL2 Loop filter + 0x006800, // [DEF] PLL2 bleed resistor + 0x006900, // [DEF] PLL2 closed loop wait + VCO wait + 0x006a00, // PLL1 N Delay div (MSB) + 0x006b00, // PLL1 N Delay div + 0x007500, // [DEF] PLL1_FDEV (MSB) + 0x007600, // [DEF] PLL1_FDEV def + 0x007700, // [DEF] PLL1_FDEV def + 0x007800, // [DEF] PLL1_FDEV def + 0x007900, // [DEF] PLL1_FDEV def + 0x007a00, // [DEF] PLL1 inc/dec ctrl + 0x007b00, // [DEF] PLL1_NUM_STAT (MSB) + 0x007c00, // [DEF] PLL1_NUM_STAT + 0x007d00, // [DEF] PLL1_NUM_STAT + 0x007e00, // [DEF] PLL1_NUM_STAT + 0x007f00, // [DEF] PLL1_NUM_STAT + 0x008000, // [DEF] PLL1 NUM saturation + 0x008100, // PLL1 Loop Filter R2 + 0x008200, // [DEF] PLL1 loop filter C1 + 0x008300, // PLL1 Loop Filter R3 + 0x008400, // PLL1 Loop Filter R4 + 0x008500, // [DEF] PLL1 Loop Filter C4 + 0x008600, // Bit 8 of PLL2_NDIV + 0x00872c, // Bits 7:0 of PLL2 NDIV + 0x00887c, // PLL2_NUM (MSB) + 0x0089e0, // PLL2_NUM + 0x008abf, // PLL2_NUM + 0x008b00, // [DEF] SDM Dither Mode + APLL2 SDM Order + 0x008c00, // PLL2 Loop Filter R2 + 0x008d00, // [DEF] PLL2 Loop Filter C1 + 0x008e00, // PLL2 Loop Filter R3 + 0x008f00, // PLL2 Loop Filter R4 + 0x009000, // [DEF] PLL2 Loop Filter C4/C3 + 0x009100, // XO Input Wait Timer + 0x009200, // unknown + 0x009300, // unknown + 0x009500, // unknown + 0x009600, // [DEF] PLL1 Amp Cal up/low threhold def + 0x009700, // unknown + 0x009800, // unknown + 0x009900, // PLL1 Amp Cal up/low threhold + 0x009a00, // LDO trim bits + 0x009b00, // [RO] NVM Stored CRC + 0x009c00, // [RO] NVM Program Count + 0x009e00, // [RO] MUMLCRC + 0x009f00, // [DEF] Bits 12:8 of MEMADR + 0x00a000, // [DEF] Memory Address + 0x00a100, // [RO]EEPROM Read Data + 0x00a200, // [DEF] RAM Read/Write Data + 0x00a500, // [DEF] NVM BASE unlock + 0x00a700, // unknown + 0x00b200, // unknown + 0x00b400, // [DEF] DPLL_TUNING_FREE_RUN (MSB) + 0x00b500, // [DEF] DPLL_TUNING_FREE_RUN + 0x00b600, // [DEF] DPLL_TUNING_FREE_RUN + 0x00b700, // [DEF] DPLL_TUNING_FREE_RUN + 0x00b800, // [DEF] DPLL_TUNING_FREE_RUN + 0x00b9f1, // DPLL_REF_HIST_EN=enabled + 0x00ba01, // DPLL REF Tuning History Timer + 0x00bb00, // [DEF] DPLL_REF_HISTDLY (MSB) + 0x00bc00, // [DEF] DPLL_REF_HISTDLY + 0x00bd00, // [DEF] DPLL_REF_HISTDLY + 0x00be00, // [DEF] DPLL_REF_HISTDLY + 0x00bf00, // unknown + 0x00c000, // PRI/SECREF detectors settings + 0x00d800, // unknown + 0x00eb02, // PRIREF_PH_VALID_DET (MSB) + 0x00ecfa, // PRIREF_PH_VALID_DET + 0x00edf0, // PRIREF_PH_VALID_DET + 0x00ee80, // PRIREF_PH_VALID_DET + 0x00ef00, // SECREF_PH_VALID_DET (MSB) + 0x00f000, // SECREF_PH_VALID_DET + 0x00f100, // SECREF_PH_VALID_DET + 0x00f200, // SECREF_PH_VALID_DET + 0x00fa00, // [DEF] DPLL_VAL_FL(PL)_EN + 0x00fd00, // [DEF] DPLL switchover timer + 0x00fe00, // [DEF] DPLL switchover timer + 0x00ff00, // [DEF] DPLL switchover timer + 0x010402, // DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) + 0x010580, // DPLL Reference Control + 0x010601, // DPLL Reference Control + 0x01072a, // DPLL Reference Control + 0x010805, // DPLL Reference Control + 0x0109f2, // DPLL Reference Control + 0x010a00, // DPLL Reference Control + 0x010ba0, // DPLL Reference Control + DPLL loop filter + 0x010c00, // DPLL Loop Filter + 0x010d00, // DPLL Loop Filter + 0x010e02, // DPLL Loop Filter + 0x010fa6, // DPLL Loop Filter + 0x011000, // DPLL Loop Filter + 0x011100, // DPLL Loop Filter + 0x011200, // DPLL Loop Filter + 0x011316, // DPLL Loop Filter + 0x011416, // DPLL Loop Filter + 0x011516, // DPLL Loop Filter + 0x011600, // DPLL Loop Filter + 0x011700, // DPLL Loop Filter + 0x011800, // DPLL Loop Filter + 0x011900, // DPLL Loop Filter + 0x011a00, // DPLL Loop Filter + 0x011b00, // DPLL Loop Filter + 0x011c1e, // DPLL Loop Filter + 0x011d1e, // DPLL Loop Filter + 0x011e00, // DPLL Loop Filter + 0x011f00, // DPLL Loop Filter + 0x012000, // DPLL Loop Filter + 0x012100, // DPLL Loop Filter + 0x012203, // DPLL Phase Lock Detection + 0x012322, // DPLL Phase Lock Detection + 0x012400, // Phase Cancellation for Hitless Switching + 0x012500, // Phase Cancellation for Hitless Switching + 0x012600, // Phase Cancellation for Hitless Switching + 0x012700, // Phase Cancellation for Hitless Switching + 0x01280a, // DPLL Loop Filter + 0x01290a, // DPLL Loop Filter + 0x012a0a, // DPLL Loop Filter + 0x012b00, // unknown + 0x012c00, // [DEF] DPLL Phase Lock Detection + 0x012d1c, // Phase lock declaration threshold + 0x012e1e, // Phase un-lock declaration threshold + 0x012f01, // unknown + 0x013f03, // DPLL Reference Control + 0x014000, // DPLL DCO Lock Detection + 0x01410a, // DPLL DCO Lock Detection + 0x014200, // DPLL DCO Lock Detection + 0x014300, // DPLL DCO Lock Detection + 0x014400, // DPLL DCO Lock Detection + 0x014501, // DPLL DCO Lock Detection + 0x014606, // DPLL DCO Lock Detection + 0x014735, // DPLL DCO Lock Detection + 0x014875, // DPLL DCO Lock Detection + 0x01490b, // DPLL DCO Lock Detection + 0x014a00, // DPLL DCO Unlock Detection + 0x014b64, // DPLL DCO Unlock Detection + 0x014c00, // DPLL DCO Unlock Detection + 0x014d00, // PLL2 DEN (MSB) + 0x014e61, // PLL2 DEN + 0x014fa8, // PLL2 DEN + 0x015006, // DPLL DCO Unlock Detection + 0x015135, // DPLL DCO Unlock Detection + 0x015275, // DPLL DCO Unlock Detection + 0x01530b, // PLL1 24-b NUM MSB (not used in DPLL mode) + 0x015400, // [DEF] DPLL_REF_SYNC_PH_OFFSET + 0x015500, // [DEF] DPLL_REF_SYNC_PH_OFFSET + 0x015600, // [DEF] DPLL_REF_SYNC_PH_OFFSET + 0x015700, // [DEF] DPLL_REF_SYNC_PH_OFFSET + 0x015800, // [DEF] DPLL_REF_SYNC_PH_OFFSET + 0x015900, // [DEF] DPLL REF Zero Delay Mode Phase Offset + 0x015a00, // [DEF] DPLL Freq Incr/Decr enable via pin/reg + 0x015b00, // [DEF] DPLL_FDEV + 0x015c00, // [DEF] DPLL_FDEV + 0x015d00, // [DEF] DPLL_FDEV + 0x015e00, // [DEF] DPLL_FDEV + 0x015f00, // [DEF] DPLL Freq Incr/Decr Numerator Step Word (MSB) + 0x016000, // [DEF] DPLL Freq Incr/Decr Numerator Step Word +}; + static const uint32_t lmk05318_rom_dpll[] = { //0x000000, From e927276635518db4796c21d4e1e8cec67b4f54cc Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 19 Apr 2025 17:34:25 +0300 Subject: [PATCH 105/397] LMK add empirical regs set (for debug) --- src/lib/hw/lmk05318/lmk05318.c | 80 ++++-- src/lib/hw/lmk05318/lmk05318_rom.h | 405 +++++++++++++++-------------- 2 files changed, 268 insertions(+), 217 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 36846e11..3261d69f 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -396,6 +396,29 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } +static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* regs, unsigned count, unsigned mask) +{ + unsigned n = 0; + + for(unsigned i = 0; i < count; ++i) + { + const empiric_t v = regs[i]; + if(v.type & mask) + { + USDR_LOG("5318", USDR_LOG_DEBUG, "ADD REGISTER from empirical set [0x%06x]", v.reg); + ++n; + + int res = lmk05318_add_reg_to_map(d, &v.reg, 1); + if(res) + return res; + } + } + + USDR_LOG("5318", USDR_LOG_DEBUG, "%u REGISTERS added from empirical set", n); + + return 0; +} + static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bool zdm) { int res = lmk05318_dpll_config(d, dpll); @@ -413,6 +436,27 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, 0, 0), //R252 disable DPLL MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 + + 0x00510A, //R81 + 0x005200, // | + 0x00530E, // | + 0x0054A6, // | + 0x005500, // | + 0x005600, // | + 0x00571E, // | + 0x005884, // | + 0x005980, // | BAW lock&unlock detection + 0x005A00, // | + 0x005B14, // | + 0x005C00, // | + 0x005D0E, // | + 0x005EA6, // | + 0x005F00, // | + 0x006000, // | + 0x00611E, // | + 0x006284, // | + 0x006380, //R99 + }; res = lmk05318_add_reg_to_map(d, no_dpll_regs, SIZEOF_ARRAY(no_dpll_regs)); } @@ -464,8 +508,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo ge2k[LMK05318_PRIREF], ge2k[LMK05318_PRIREF], 1 /* amp_det_en ge2k[LMK05318_PRIREF]*/) : - MAKE_LMK05318_REF0_DETEN(0,0,0,0,0,0) - , //R193 + MAKE_LMK05318_REF0_DETEN(0,0,0,0,0,0), //R193 dpll->en[LMK05318_SECREF] ? MAKE_LMK05318_REF1_DETEN(ge2k[LMK05318_SECREF], @@ -474,8 +517,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo ge2k[LMK05318_SECREF], ge2k[LMK05318_SECREF], 1 /* amp_det_en ge2k[LMK05318_SECREF]*/) : - MAKE_LMK05318_REF1_DETEN(0,0,0,0,0,0) - , //R194 + MAKE_LMK05318_REF1_DETEN(0,0,0,0,0,0), //R194 MAKE_LMK05318_REG_WR(REF0_VLDTMR, meas_time[LMK05318_PRIREF] & 0b00011111), //R233 MAKE_LMK05318_REG_WR(REF1_VLDTMR, meas_time[LMK05318_SECREF] & 0b00011111), //R234 @@ -509,18 +551,23 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_DEN_BY4(d->dpll.den), //R318 }; - res = lmk05318_add_reg_to_map(d, lmk05318_rom_dpll_empiric, SIZEOF_ARRAY(lmk05318_rom_dpll_empiric)); + const unsigned mask = (unsigned)-1; //all + res = lmk05318_empirics_smartload(d, lmk05318_rom_dpll_empiric, SIZEOF_ARRAY(lmk05318_rom_dpll_empiric), mask); res = res ? res : lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); } if(res) return res; + //common registers uint32_t regs[] = { MAKE_LMK05318_PLL_CLK_CFG(0, 0b111), //R47 APLL cascade mode + set PLL clock cfg MAKE_LMK05318_OUTSYNCCTL(1, 1, 1), //R70 enable APLL1/APLL2 channel sync MAKE_LMK05318_OUTSYNCEN(1, 1, 1, 1, 1, 1), //R71 enable ch0..ch7 out sync + MAKE_LMK05318_DPLL_MUTE(1,1,1,1), //R29 mute during lock + + MAKE_LMK05318_OUT_MUTE(0,0,0,0,0,0,0,0), //R25 unmute all chans MAKE_LMK05318_MUTELVL1(CH3_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, CH2_MUTE_LVL_DIFF_LOW_P_LOW_N_LOW, @@ -534,29 +581,8 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags - 0x00510A, //R81 - 0x005200, // | - 0x00530E, // | - 0x0054A6, // | - 0x005500, // | - 0x005600, // | - 0x00571E, // | - 0x005884, // | - 0x005980, // | BAW lock&unlock detection - 0x005A00, // | - 0x005B14, // | - 0x005C00, // | - 0x005D0E, // | - 0x005EA6, // | - 0x005F00, // | - 0x006000, // | - 0x00611E, // | - 0x006284, // | - 0x006380, //R99 - MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,3), //R115 PLL1 MASHORD=3 - MAKE_LMK05318_OUT_MUTE(0,0,0,0,0,0,0,0), //R25 unmute all chans - + MAKE_LMK05318_PLL2_MASHCTRL(0,3), //R139 PLL2 MASHORD=3 }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index d38e2f99..f9100bc1 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -1,197 +1,222 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT -static const uint32_t lmk05318_rom_dpll_empiric[] = +#include +#include + +enum empiric_type { - 0x000d00, // [RO] - 0x000e00, // [RO] - 0x000f00, // [DEF] INT_MASK - 0x001000, // [DEF] INT_MASK - 0x001100, // [DEF] XO/APLL LOL Polarity - 0x001200, // [DEF] DPLL LOL Polarity - 0x001500, // [DEF] INT_AND_OR - 0x001600, // [DEF] STATUS0/1 Polarity - 0x001900, // OUT MUTE ctrls - 0x001a00, // [DEF] XO hyst timer - 0x001b00, // XO SE energy det mode - 0x001c00, // XO DIFF energy det mode - 0x001d00, // mute during LOCK ?? 0x17 - 0x001e00, // LDO timer scale - 0x002000, // APLL MASD + LDO trim - 0x002300, // [DEF] VCO1/2 LSO settings - 0x002400, // [DEF] STAT0/1 Driver Type Output - 0x002500, // STATUS0 open Drain mode - 0x002600, // STATUS1 open Drain mode - 0x002900, // [DEF] SPARE_NVMBASE2 - 0x003000, // STAT0_SEL - 0x003100, // STAT1_SEL - 0x003200, // [DEF] DCO freq + CH6/7 PD - 0x004400, // APLL1 BAW drain - 0x004500, // unknown - 0x004800, // [RO] RO OUTCH active flags - 0x004900, // [DEF] REF_BYPASS (route REF to OUTs instead of VCO1) - 0x004b00, // PLL1 Vtune Monitor bypass + charge pump gain - 0x004c00, // PLL1 post-div 1 - 0x004d00, // PLL1 loop filter - 0x004e00, // [DEF] PLL1 bleed resistor - 0x006500, // PLL2 charge pump - 0x006633, // PLL2 post-div2 post-div1 - 0x006700, // PLL2 Loop filter - 0x006800, // [DEF] PLL2 bleed resistor - 0x006900, // [DEF] PLL2 closed loop wait + VCO wait - 0x006a00, // PLL1 N Delay div (MSB) - 0x006b00, // PLL1 N Delay div - 0x007500, // [DEF] PLL1_FDEV (MSB) - 0x007600, // [DEF] PLL1_FDEV def - 0x007700, // [DEF] PLL1_FDEV def - 0x007800, // [DEF] PLL1_FDEV def - 0x007900, // [DEF] PLL1_FDEV def - 0x007a00, // [DEF] PLL1 inc/dec ctrl - 0x007b00, // [DEF] PLL1_NUM_STAT (MSB) - 0x007c00, // [DEF] PLL1_NUM_STAT - 0x007d00, // [DEF] PLL1_NUM_STAT - 0x007e00, // [DEF] PLL1_NUM_STAT - 0x007f00, // [DEF] PLL1_NUM_STAT - 0x008000, // [DEF] PLL1 NUM saturation - 0x008100, // PLL1 Loop Filter R2 - 0x008200, // [DEF] PLL1 loop filter C1 - 0x008300, // PLL1 Loop Filter R3 - 0x008400, // PLL1 Loop Filter R4 - 0x008500, // [DEF] PLL1 Loop Filter C4 - 0x008600, // Bit 8 of PLL2_NDIV - 0x00872c, // Bits 7:0 of PLL2 NDIV - 0x00887c, // PLL2_NUM (MSB) - 0x0089e0, // PLL2_NUM - 0x008abf, // PLL2_NUM - 0x008b00, // [DEF] SDM Dither Mode + APLL2 SDM Order - 0x008c00, // PLL2 Loop Filter R2 - 0x008d00, // [DEF] PLL2 Loop Filter C1 - 0x008e00, // PLL2 Loop Filter R3 - 0x008f00, // PLL2 Loop Filter R4 - 0x009000, // [DEF] PLL2 Loop Filter C4/C3 - 0x009100, // XO Input Wait Timer - 0x009200, // unknown - 0x009300, // unknown - 0x009500, // unknown - 0x009600, // [DEF] PLL1 Amp Cal up/low threhold def - 0x009700, // unknown - 0x009800, // unknown - 0x009900, // PLL1 Amp Cal up/low threhold - 0x009a00, // LDO trim bits - 0x009b00, // [RO] NVM Stored CRC - 0x009c00, // [RO] NVM Program Count - 0x009e00, // [RO] MUMLCRC - 0x009f00, // [DEF] Bits 12:8 of MEMADR - 0x00a000, // [DEF] Memory Address - 0x00a100, // [RO]EEPROM Read Data - 0x00a200, // [DEF] RAM Read/Write Data - 0x00a500, // [DEF] NVM BASE unlock - 0x00a700, // unknown - 0x00b200, // unknown - 0x00b400, // [DEF] DPLL_TUNING_FREE_RUN (MSB) - 0x00b500, // [DEF] DPLL_TUNING_FREE_RUN - 0x00b600, // [DEF] DPLL_TUNING_FREE_RUN - 0x00b700, // [DEF] DPLL_TUNING_FREE_RUN - 0x00b800, // [DEF] DPLL_TUNING_FREE_RUN - 0x00b9f1, // DPLL_REF_HIST_EN=enabled - 0x00ba01, // DPLL REF Tuning History Timer - 0x00bb00, // [DEF] DPLL_REF_HISTDLY (MSB) - 0x00bc00, // [DEF] DPLL_REF_HISTDLY - 0x00bd00, // [DEF] DPLL_REF_HISTDLY - 0x00be00, // [DEF] DPLL_REF_HISTDLY - 0x00bf00, // unknown - 0x00c000, // PRI/SECREF detectors settings - 0x00d800, // unknown - 0x00eb02, // PRIREF_PH_VALID_DET (MSB) - 0x00ecfa, // PRIREF_PH_VALID_DET - 0x00edf0, // PRIREF_PH_VALID_DET - 0x00ee80, // PRIREF_PH_VALID_DET - 0x00ef00, // SECREF_PH_VALID_DET (MSB) - 0x00f000, // SECREF_PH_VALID_DET - 0x00f100, // SECREF_PH_VALID_DET - 0x00f200, // SECREF_PH_VALID_DET - 0x00fa00, // [DEF] DPLL_VAL_FL(PL)_EN - 0x00fd00, // [DEF] DPLL switchover timer - 0x00fe00, // [DEF] DPLL switchover timer - 0x00ff00, // [DEF] DPLL switchover timer - 0x010402, // DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) - 0x010580, // DPLL Reference Control - 0x010601, // DPLL Reference Control - 0x01072a, // DPLL Reference Control - 0x010805, // DPLL Reference Control - 0x0109f2, // DPLL Reference Control - 0x010a00, // DPLL Reference Control - 0x010ba0, // DPLL Reference Control + DPLL loop filter - 0x010c00, // DPLL Loop Filter - 0x010d00, // DPLL Loop Filter - 0x010e02, // DPLL Loop Filter - 0x010fa6, // DPLL Loop Filter - 0x011000, // DPLL Loop Filter - 0x011100, // DPLL Loop Filter - 0x011200, // DPLL Loop Filter - 0x011316, // DPLL Loop Filter - 0x011416, // DPLL Loop Filter - 0x011516, // DPLL Loop Filter - 0x011600, // DPLL Loop Filter - 0x011700, // DPLL Loop Filter - 0x011800, // DPLL Loop Filter - 0x011900, // DPLL Loop Filter - 0x011a00, // DPLL Loop Filter - 0x011b00, // DPLL Loop Filter - 0x011c1e, // DPLL Loop Filter - 0x011d1e, // DPLL Loop Filter - 0x011e00, // DPLL Loop Filter - 0x011f00, // DPLL Loop Filter - 0x012000, // DPLL Loop Filter - 0x012100, // DPLL Loop Filter - 0x012203, // DPLL Phase Lock Detection - 0x012322, // DPLL Phase Lock Detection - 0x012400, // Phase Cancellation for Hitless Switching - 0x012500, // Phase Cancellation for Hitless Switching - 0x012600, // Phase Cancellation for Hitless Switching - 0x012700, // Phase Cancellation for Hitless Switching - 0x01280a, // DPLL Loop Filter - 0x01290a, // DPLL Loop Filter - 0x012a0a, // DPLL Loop Filter - 0x012b00, // unknown - 0x012c00, // [DEF] DPLL Phase Lock Detection - 0x012d1c, // Phase lock declaration threshold - 0x012e1e, // Phase un-lock declaration threshold - 0x012f01, // unknown - 0x013f03, // DPLL Reference Control - 0x014000, // DPLL DCO Lock Detection - 0x01410a, // DPLL DCO Lock Detection - 0x014200, // DPLL DCO Lock Detection - 0x014300, // DPLL DCO Lock Detection - 0x014400, // DPLL DCO Lock Detection - 0x014501, // DPLL DCO Lock Detection - 0x014606, // DPLL DCO Lock Detection - 0x014735, // DPLL DCO Lock Detection - 0x014875, // DPLL DCO Lock Detection - 0x01490b, // DPLL DCO Lock Detection - 0x014a00, // DPLL DCO Unlock Detection - 0x014b64, // DPLL DCO Unlock Detection - 0x014c00, // DPLL DCO Unlock Detection - 0x014d00, // PLL2 DEN (MSB) - 0x014e61, // PLL2 DEN - 0x014fa8, // PLL2 DEN - 0x015006, // DPLL DCO Unlock Detection - 0x015135, // DPLL DCO Unlock Detection - 0x015275, // DPLL DCO Unlock Detection - 0x01530b, // PLL1 24-b NUM MSB (not used in DPLL mode) - 0x015400, // [DEF] DPLL_REF_SYNC_PH_OFFSET - 0x015500, // [DEF] DPLL_REF_SYNC_PH_OFFSET - 0x015600, // [DEF] DPLL_REF_SYNC_PH_OFFSET - 0x015700, // [DEF] DPLL_REF_SYNC_PH_OFFSET - 0x015800, // [DEF] DPLL_REF_SYNC_PH_OFFSET - 0x015900, // [DEF] DPLL REF Zero Delay Mode Phase Offset - 0x015a00, // [DEF] DPLL Freq Incr/Decr enable via pin/reg - 0x015b00, // [DEF] DPLL_FDEV - 0x015c00, // [DEF] DPLL_FDEV - 0x015d00, // [DEF] DPLL_FDEV - 0x015e00, // [DEF] DPLL_FDEV - 0x015f00, // [DEF] DPLL Freq Incr/Decr Numerator Step Word (MSB) - 0x016000, // [DEF] DPLL Freq Incr/Decr Numerator Step Word + REG_READONLY = 1, + REG_DEFAULTS = 2, + REG_OVERRIDE = 4, + REG_PLL1 = 8, + REG_PLL2 = 16, + REG_DPLL = 32, + REG_XO = 64, + REG_LDO = 128, + REG_NVM = 256, + REG_UNKNOWN = 512, +}; +typedef enum empiric_type empiric_type_t; + +struct empiric +{ + uint32_t reg; + empiric_type_t type; +}; +typedef struct empiric empiric_t; + +static const empiric_t lmk05318_rom_dpll_empiric[] = +{ + {0x000d00, REG_READONLY | REG_XO | REG_PLL1 | REG_PLL2}, // [RO] APLL&XO LOSSes + {0x000e00, REG_READONLY | REG_DPLL}, // [RO] DPLL LOSSes + {0x000f00, REG_DEFAULTS}, // [DEF] INT_MASK + {0x001000, REG_DEFAULTS}, // [DEF] INT_MASK + {0x001100, REG_DEFAULTS | REG_XO | REG_PLL1 | REG_PLL2}, // [DEF] XO/APLL LOL Polarity + {0x001200, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL LOL Polarity + {0x001500, REG_DEFAULTS}, // [DEF] INT_AND_OR + {0x001600, REG_DEFAULTS}, // [DEF] STATUS0/1 Polarity + //{0x001900, REG_OVERRIDE}, // OUT MUTE ctrls (unmute) + {0x001a00, REG_DEFAULTS | REG_XO}, // [DEF] XO hyst timer + {0x001b00, REG_OVERRIDE | REG_XO}, // XO SE energy det mode + {0x001c00, REG_OVERRIDE | REG_XO}, // XO DIFF energy det mode + //{0x001d00, REG_OVERRIDE}, // mute during LOCK ?? 0x17 + {0x001e00, REG_OVERRIDE | REG_LDO}, // LDO timer scale + {0x002000, REG_OVERRIDE | REG_LDO | REG_PLL1 | REG_PLL2},// APLL MASH LDO trim + {0x002300, REG_DEFAULTS | REG_LDO | REG_PLL1 | REG_PLL2},// [DEF] VCO1/2 LDO settings + {0x002400, REG_DEFAULTS}, // [DEF] STAT0/1 Driver Type Output + {0x002500, REG_OVERRIDE}, // STATUS0 open Drain mode + {0x002600, REG_OVERRIDE}, // STATUS1 open Drain mode + {0x002900, REG_DEFAULTS | REG_NVM}, // [DEF] SPARE_NVMBASE2 + {0x003000, REG_OVERRIDE}, // STAT0_SEL + {0x003100, REG_OVERRIDE}, // STAT1_SEL + {0x003200, REG_DEFAULTS}, // [DEF] DCO freq + CH6/7 PD + {0x004400, REG_OVERRIDE | REG_PLL1}, // APLL1 BAW drain + {0x004500, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x004800, REG_READONLY}, // [RO] RO OUTCH active flags + {0x004900, REG_DEFAULTS}, // [DEF] REF_BYPASS (route REF to OUTs instead of VCO1) + {0x004b00, REG_OVERRIDE | REG_PLL1}, // PLL1 Vtune Monitor bypass + charge pump gain + {0x004c00, REG_OVERRIDE | REG_PLL1}, // PLL1 post-div 1 + {0x004d00, REG_OVERRIDE | REG_PLL1}, // PLL1 loop filter + {0x004e00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 bleed resistor + {0x006500, REG_OVERRIDE | REG_PLL2}, // PLL2 charge pump + {0x006633, REG_OVERRIDE | REG_PLL2}, // PLL2 post-div2 post-div1 + {0x006700, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop filter + {0x006800, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 bleed resistor + {0x006900, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 closed loop wait + VCO wait + {0x006a00, REG_OVERRIDE | REG_PLL1}, // PLL1 N Delay div (MSB) + {0x006b00, REG_OVERRIDE | REG_PLL1}, // PLL1 N Delay div + {0x007500, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV (MSB) + {0x007600, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def + {0x007700, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def + {0x007800, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def + {0x007900, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def + {0x007a00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 inc/dec ctrl + {0x007b00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT (MSB) + {0x007c00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT + {0x007d00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT + {0x007e00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT + {0x007f00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT + {0x008000, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 NUM saturation + {0x008100, REG_OVERRIDE | REG_PLL1}, // PLL1 Loop Filter R2 + {0x008200, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 loop filter C1 + {0x008300, REG_OVERRIDE | REG_PLL1}, // PLL1 Loop Filter R3 + {0x008400, REG_OVERRIDE | REG_PLL1}, // PLL1 Loop Filter R4 + {0x008500, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 Loop Filter C4 + {0x008600, REG_OVERRIDE | REG_PLL2}, // Bit 8 of PLL2_NDIV + {0x00872c, REG_OVERRIDE | REG_PLL2}, // Bits 7:0 of PLL2 NDIV + {0x00887c, REG_OVERRIDE | REG_PLL2}, // PLL2_NUM (MSB) + {0x0089e0, REG_OVERRIDE | REG_PLL2}, // PLL2_NUM + {0x008abf, REG_OVERRIDE | REG_PLL2}, // PLL2_NUM + //{0x008b00, REG_DEFAULTS | REG_PLL2}, // [DEF] SDM Dither Mode + APLL2 SDM Order + {0x008c00, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop Filter R2 + {0x008d00, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 Loop Filter C1 + {0x008e00, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop Filter R3 + {0x008f00, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop Filter R4 + {0x009000, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 Loop Filter C4/C3 + {0x009100, REG_OVERRIDE | REG_XO}, // XO Input Wait Timer + {0x009200, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x009300, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x009500, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x009600, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 Amp Cal up/low threhold def + {0x009700, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x009800, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x009900, REG_OVERRIDE | REG_PLL1}, // PLL1 Amp Cal up/low threhold + {0x009a00, REG_OVERRIDE | REG_LDO}, // LDO trim bits + {0x009b00, REG_READONLY | REG_NVM}, // [RO] NVM Stored CRC + {0x009c00, REG_READONLY | REG_NVM}, // [RO] NVM Program Count + {0x009e00, REG_READONLY | REG_NVM}, // [RO] MUMLCRC + {0x009f00, REG_DEFAULTS | REG_NVM}, // [DEF] Bits 12:8 of MEMADR + {0x00a000, REG_DEFAULTS | REG_NVM}, // [DEF] Memory Address + {0x00a100, REG_READONLY | REG_NVM}, // [RO]EEPROM Read Data + {0x00a200, REG_DEFAULTS | REG_NVM}, // [DEF] RAM Read/Write Data + {0x00a500, REG_DEFAULTS | REG_NVM}, // [DEF] NVM BASE unlock + {0x00a700, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x00b200, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x00b400, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN (MSB) + {0x00b500, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN + {0x00b600, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN + {0x00b700, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN + {0x00b800, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN + {0x00b9f1, REG_OVERRIDE | REG_DPLL}, // DPLL_REF_HIST_EN=enabled + {0x00ba01, REG_OVERRIDE | REG_DPLL}, // DPLL REF Tuning History Timer + {0x00bb00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY (MSB) + {0x00bc00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY + {0x00bd00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY + {0x00be00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY + {0x00bf00, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x00c000, REG_OVERRIDE | REG_DPLL}, // PRI/SECREF detectors settings + {0x00d800, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x00eb02, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET (MSB) + {0x00ecfa, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET + {0x00edf0, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET + {0x00ee80, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET + {0x00ef00, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET (MSB) + {0x00f000, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET + {0x00f100, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET + {0x00f200, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET + {0x00fa00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_VAL_FL(PL)_EN + {0x00fd00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer + {0x00fe00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer + {0x00ff00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer + {0x010402, REG_OVERRIDE | REG_DPLL}, // DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) + {0x010580, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x010601, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x01072a, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x010805, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x0109f2, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x010a00, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x010ba0, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + DPLL loop filter + {0x010c00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x010d00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x010e02, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x010fa6, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011000, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011100, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011200, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011316, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011416, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011516, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011600, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011700, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011800, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011900, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011a00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011b00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011c1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011d1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011e00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011f00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x012000, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x012100, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x012203, REG_OVERRIDE | REG_DPLL}, // DPLL Phase Lock Detection + {0x012322, REG_OVERRIDE | REG_DPLL}, // DPLL Phase Lock Detection + {0x012400, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching + {0x012500, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching + {0x012600, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching + {0x012700, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching + {0x01280a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x01290a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x012a0a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x012b00, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x012c00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Phase Lock Detection + {0x012d1c, REG_OVERRIDE | REG_DPLL}, // Phase lock declaration threshold + {0x012e1e, REG_OVERRIDE | REG_DPLL}, // Phase un-lock declaration threshold + {0x012f01, REG_OVERRIDE | REG_UNKNOWN}, // unknown + {0x013f03, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x014000, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x01410a, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014200, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014300, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014400, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014501, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014606, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014735, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014875, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x01490b, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x014a00, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection + {0x014b64, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection + {0x014c00, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection + {0x014d00, REG_OVERRIDE | REG_PLL2}, // PLL2 DEN (MSB) + {0x014e61, REG_OVERRIDE | REG_PLL2}, // PLL2 DEN + {0x014fa8, REG_OVERRIDE | REG_PLL2}, // PLL2 DEN + {0x015006, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection + {0x015135, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection + {0x015275, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection + {0x01530b, REG_OVERRIDE | REG_PLL1}, // PLL1 24-b NUM MSB (not used in DPLL mode) + {0x015400, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET + {0x015500, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET + {0x015600, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET + {0x015700, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET + {0x015800, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET + {0x015900, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL REF Zero Delay Mode Phase Offset + {0x015a00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Freq Incr/Decr enable via pin/reg + {0x015b00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV + {0x015c00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV + {0x015d00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV + {0x015e00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV + {0x015f00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Freq Incr/Decr Numerator Step Word (MSB) + {0x016000, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Freq Incr/Decr Numerator Step Word }; static const uint32_t lmk05318_rom_dpll[] = From a0cd2bf3e4b6db8bf36c8f2f90c8b4e8728069b8 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 19 Apr 2025 20:51:38 +0300 Subject: [PATCH 106/397] minor fixes & comments --- src/lib/hw/lmk05318/lmk05318.c | 27 +- src/lib/hw/lmk05318/lmk05318_rom.h | 390 ++--------------------------- 2 files changed, 34 insertions(+), 383 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 3261d69f..92e40b61 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -580,9 +580,6 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags - - MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,3), //R115 PLL1 MASHORD=3 - MAKE_LMK05318_PLL2_MASHCTRL(0,3), //R139 PLL2 MASHORD=3 }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -894,7 +891,10 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) d->pd2 = d->pd1; } + const uint8_t apll2_sdm_order = num ? 3 : 0; //override if needed + uint32_t regs[] = { + MAKE_LMK05318_PLL2_MASHCTRL(0,apll2_sdm_order), //R139 PLL2 MASHORD=3 MAKE_LMK05318_PLL2_CTRL2(d->pd2 - 1, d->pd1 - 1), //R102 MAKE_LMK05318_PLL2_NDIV_BY0(n), //R135 MAKE_LMK05318_PLL2_NDIV_BY1(n), //R134 @@ -966,6 +966,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) unsigned fpd1 = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); uint64_t fvco = VCO_APLL1; unsigned n = fvco / fpd1; + const uint8_t apll1_sdm_order = 3; //override if needed //in DPLL mode we use FIXED 40-bit APLL1 denominator and programmed 40-bit numerator if(d->dpll.enabled) @@ -975,15 +976,16 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 " DEN=FIXED\n", fvco, n, num); uint32_t regs[] = { - MAKE_LMK05318_PLL1_MODE(0, 0, 1), //R116 DPLL mode - MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 NDIV - MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 NDIV - MAKE_LMK05318_PLL1_NUM_BY0(num), //R110 | - MAKE_LMK05318_PLL1_NUM_BY1(num), //R111 | - MAKE_LMK05318_PLL1_NUM_BY2(num), //R112 | 40-bit NUM - MAKE_LMK05318_PLL1_NUM_BY3(num), //R113 | - MAKE_LMK05318_PLL1_NUM_BY4(num), //R114 | - MAKE_LMK05318_PLL1_CTRL0(0), //R74 Activate APLL1 + MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,apll1_sdm_order), //R115 PLL1 MASHORD=3 WeakDither + MAKE_LMK05318_PLL1_MODE(0, 0, 1), //R116 DPLL mode + MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 NDIV + MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 NDIV + MAKE_LMK05318_PLL1_NUM_BY0(num), //R110 | + MAKE_LMK05318_PLL1_NUM_BY1(num), //R111 | + MAKE_LMK05318_PLL1_NUM_BY2(num), //R112 | 40-bit NUM + MAKE_LMK05318_PLL1_NUM_BY3(num), //R113 | + MAKE_LMK05318_PLL1_NUM_BY4(num), //R114 | + MAKE_LMK05318_PLL1_CTRL0(0), //R74 Activate APLL1 }; int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); @@ -1000,6 +1002,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu32 " DEN=%" PRIu32 "\n", fvco, n, num, den); uint32_t regs[] = { + MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,apll1_sdm_order), //R115 PLL1 MASHORD=3 WeakDither MAKE_LMK05318_PLL1_MODE(0, 0, 0), //R116 free-run mode MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 NDIV MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 NDIV diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h index f9100bc1..c93ed848 100644 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ b/src/lib/hw/lmk05318/lmk05318_rom.h @@ -16,6 +16,7 @@ enum empiric_type REG_LDO = 128, REG_NVM = 256, REG_UNKNOWN = 512, + REF_FORCE = 1024, }; typedef enum empiric_type empiric_type_t; @@ -140,31 +141,31 @@ static const empiric_t lmk05318_rom_dpll_empiric[] = {0x00fe00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer {0x00ff00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer {0x010402, REG_OVERRIDE | REG_DPLL}, // DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) - {0x010580, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control - {0x010601, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control - {0x01072a, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control - {0x010805, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control - {0x0109f2, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control - {0x010a00, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x010580, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET (MSB) + {0x010601, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET + {0x01072a, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET + {0x010805, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET + {0x0109f2, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET + {0x010a00, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET (LSB) = 5000000000 {0x010ba0, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + DPLL loop filter {0x010c00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x010d00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x010e02, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x010fa6, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x010e02, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_FILTER_SCALAR (MSB) + {0x010fa6, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_FILTER_SCALAR (LSB) = 678 {0x011000, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011100, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011200, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011316, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011416, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011516, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011316, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LOOP_GAIN=22 + {0x011416, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LOOP_GAIN_FL1=22 + {0x011516, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LOOP_GAIN_FL2=22 {0x011600, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011700, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011800, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011900, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011a00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011b00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011c1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011d1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x011c1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LPF0_GAIN2_FL=20 + {0x011d1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LPF1_GAIN2_FL=20 {0x011e00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x011f00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter {0x012000, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter @@ -175,17 +176,17 @@ static const empiric_t lmk05318_rom_dpll_empiric[] = {0x012500, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching {0x012600, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching {0x012700, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching - {0x01280a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x01290a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x012a0a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter + {0x01280a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_QUANT=10 + {0x01290a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_QUANT_FL1=10 + {0x012a0a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_QUANT_FL2=10 {0x012b00, REG_OVERRIDE | REG_UNKNOWN}, // unknown {0x012c00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Phase Lock Detection {0x012d1c, REG_OVERRIDE | REG_DPLL}, // Phase lock declaration threshold {0x012e1e, REG_OVERRIDE | REG_DPLL}, // Phase un-lock declaration threshold {0x012f01, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x013f03, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + {0x013f03, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_ORDER=3 {0x014000, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x01410a, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection + {0x01410a, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection ?DPLL_REF_LOOPFILT_CLK_DIV=10 {0x014200, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection {0x014300, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection {0x014400, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection @@ -220,359 +221,6 @@ static const empiric_t lmk05318_rom_dpll_empiric[] = }; static const uint32_t lmk05318_rom_dpll[] = -{ - //0x000000, - //0x000100, - //0x000200, - //0x000300, - //0x000400, - //0x000500, R - //0x000600, - //0x000700, - //0x000800, - //0x000A00, - //0x000B00, - - 0x000C1B, //ok - //0x000D00, R - //0x000E00, R - //0x000F00, // ok default - //0x001000, // ok default - //0x001100, // ok default - //0x001200, // ok default - 0x001300, // ok - 0x001400, // ok - //0x001500, // ok default - //0x001600, // ok default - 0x001700, // ok, 0xff - mute specifics - 0x001800, // ok, 0xff - mute specifics - 0x001900, // ok - 0x001A00, // XO hyst timer - 0x001B00, // XO SE energy det mode - 0x001C00, // XO DIFF energy det mode - 0x001D17, // ************************? DPLL mute on ph lock - 0x001E00, // *********? LDO timer scale - 0x002000, // *********? PLL1/2 MASH LDO trim - //0x002300, // ok default - //0x002400, // ok default - //0x002500, //default STATUS0 open Drain mode - //0x002600,//default - 0x002700, // ok - 0x002806, // ok (?) - //0x002900, // default SPARE_NVMBASE2 - 0x002A10, // ok (? XO inp buffer=0) - 0x002B40, // ok (default bits?) - 0x002C00, //ok - 0x002D07, //ok (default bits) - 0x002E01, //ok - 0x002F00, //ok (counters differ) - //0x003000, // ok stats - //0x003100, // ok stats - //0x003200, //default - 0x003310, //ok - 0x003410, //ok - 0x003513, //ok - 0x003610, //ok - 0x003710, //ok - 0x003809, //ok - 0x003900, //ok - 0x003A0F, //ok - 0x003B00, //ok - 0x003C0F, //ok - 0x003D3E, //ok - 0x003EF9, //ok - 0x003F3E, //ok - 0x004095, //ok - 0x004102, //ok - 0x0042F8, //ok - 0x0043FF, //ok - 0x004400, // ????? APLL1 BAW drain != default TODO - //0x004500, //default - 0x004607, //ok - 0x00473F, //ok - //0x004800, R - //0x004900, //default - 0x004A00, //ok - 0x004B00, //???? !=default - 0x004C00, //APLL1 Post div1???? todo - 0x004D00, //PLL1 loop filter?.. todo - //0x004E00, ??? unknown - 0x004F00, //ok (default bit) - 0x005000, //ok - 0x00510A, //ok - 0x005200, //ok - 0x00530E, //ok - 0x0054A6, //ok - 0x005500, //ok - 0x005600, //ok - 0x00571E, //ok - 0x005884, //ok - 0x005980, //ok - 0x005A00, //ok - 0x005B14, //ok - 0x005C00, //ok - 0x005D0E, //ok - 0x005EA6, //ok - 0x005F00, //ok - 0x006000, //ok - 0x00611E, //ok - 0x006284, //ok - 0x006380, //ok - 0x006429, //ok - //0x006500, // != default, PLL2 charge pump - //0x006633, //PLL2 (off) - //0x006700, //PLL2 Loop filter sett - //0x006800, //PLL2 (off) default - //0x006900, //PLL2 - 0x006A00, // PLL1 N Delay div (!=default) - 0x006B00, // PLL1 N Delay div (!=default) - 0x006C00, //ok - 0x006D32, //ok - 0x006E00, //ok - 0x006F00, //ok - 0x007000, //ok - 0x007100, //ok - 0x007200, //ok - 0x007303, //ok - 0x007401, //ok - - //0x007500, //PLL1_FDEV ==default - //0x007600, //PLL1_FDEV ==default - //0x007700, //PLL1_FDEV ==default - //0x007800, //PLL1_FDEV ==default - //0x007900, //PLL1_FDEV ==default - //0x007A00, //PLL1_FDEV ==default - //0x007B00, // PLL1_NUM_STAT_39:32 - //0x007C00, // PLL1_NUM_STAT_31:24 - //0x007D00, // PLL1_NUM_STAT_23:16 - //0x007E00, // PLL1_NUM_STAT_15:8 - //0x007F00, // PLL1_NUM_STAT - //0x008000, //PLL1 NUM saturation(default) - 0x008100, // PLL1 Loop Filter R2 ??? !=default - //0x008200, // PLL1 loop filter C1 ==default - 0x008300, // PLL1 Loop Filter R3 ??? != default - 0x008400, // PLL1 Loop Filter R4 ??? != default - //0x008500, // PLL1 Loop Filter C4 ==default - //0x008600, // Bit 8 of PLL2_NDIV - //0x00872C, // Bits 7:0 of PLL2 N Divider - //0x00887C, // Bits 23:16 of PLL2_NUM - //0x0089E0, // Bits 15:8 of PLL2_NUM - //0x008ABF, // PLL2 Fractional Divider Numerator - //0x008B00, // SDM Dither Mode + APLL2 SDM Order - //0x008C00, // PLL2 Loop Filter R2 - //0x008D00, // PLL2 Loop Filter C1 == default - //0x008E00, // PLL2 Loop Filter R3 - //0x008F00, // PLL2 Loop Filter R4 - //0x009000, // PLL2 Loop Filter C4/C3 - 0x009100, // XO Input Wait Timer ??? != default - 0x009200, // ??? unknown !=default 0x84 - //0x009300, // ??? unknown ==default - //0x009500, // ??? unknown ==default - //0x009600, //APPL1 Amp Cal up/low threhold ==default - //0x009700, // ??? unknown ==default - //0x009800, // ??? unknown ==default - //0x009900, //APPL2 Amp Cal up/low threhold ==default - 0x009A00, // LDO trim bits ??? != default - //0x009B00, // NVM Stored CRC RO - //0x009C00, // NVM Program Count RO - //0x009D00, // NVM misc - //0x009E00, //MUMLCRC RO - //0x009F00, // Bits 12:8 of MEMADR ==default - //0x00A000, // Memory Address ==default - //0x00A100, // EEPROM Read Data RO - //0x00A200, // RAM Read/Write Data ==default - //0x00A400, // NVM Program Unlock - //0x00A500, // NVM BASE unlock ==default - //0x00A700, // unknown ==default - //0x00B200, // unknown ==default - //0x00B400, // Bits 37:32 of DPLL_TUNING_FREE_RUN ==default - //0x00B500, // Bits 31:24 of DPLL_TUNING_FREE_RUN ==default - //0x00B600, // Bits 23:16 of DPLL_TUNING_FREE_RUN ==default - //0x00B700, // Bits 15:8 of DPLL_TUNING_FREE_RUN ==default - //0x00B800, // DPLL Free-run tuning word ==default - 0x00B9F1, // DPLL_REF_HIST_EN=enabled !=default ????? - 0x00BA01, // DPLL REF Tuning History Timer !=default ??? - //0x00BB00, //DPLL_REF_HISTDLY ==default - //0x00BC00, //DPLL_REF_HISTDLY ==default - //0x00BD00, //DPLL_REF_HISTDLY ==default - //0x00BE00, //DPLL_REF_HISTDLY ==default - //0x00BF00, //unknown ==default - 0x00C000, // PRI/SECREF detectors settings !=default ??? - - 0x00C119, //ok - 0x00C200, //ok - 0x00C300, //ok - 0x00C400, //ok - 0x00C51D, //ok - 0x00C600, //ok - 0x00C700, //ok - 0x00C800, //ok - 0x00C900, //ok - 0x00CA00, //ok - 0x00CB00, //ok - 0x00CC15, //ok - 0x00CD00, //ok - 0x00CE00, //ok - 0x00CF00, //ok - 0x00D000, //ok - 0x00D100, //ok - 0x00D200, //ok - 0x00D300, //ok - 0x00D400, //ok - 0x00D500, //ok - 0x00D600, //ok - 0x00D700, //ok - //0x00D800, //unknown - 0x00D900, //ok - 0x00DA00, //ok - 0x00DB00, //ok - 0x00DC00, //ok - 0x00DD00, //ok - 0x00DE00, //ok - 0x00DF00, //ok - 0x00E000, //ok - 0x00E100, //ok - 0x00E200, //ok - 0x00E300, //ok - 0x00E400, //ok - 0x00E500, //ok - 0x00E600, //ok - 0x00E700, //ok - 0x00E800, //ok - 0x00E90F, //ok - 0x00EA00, //ok - - 0x00EB02, //PRIREF_PH_VALID_DET1 !=default - 0x00ECFA, - 0x00EDF0, - 0x00EE80, // - 0x00EF00, - 0x00F000, - 0x00F100, - 0x00F200, //SECREF_PH_VALID_DET4 !=default - - 0x00F33F, //ok - 0x00F400, //ok - 0x00F921, //ok - //0x00FA00, //default - 0x00FB03, //ok - 0x00FC29, //ok +++ZDM - //0x00FD00, default - //0x00FE00, default - //0x00FF00, default - - 0x010000, //ok - 0x010101, //ok - 0x010200, //ok - 0x010300, //ok - - 0x010402, // DPLL_REF_AVOID_SLIP !=default - 0x010580, // DPLL Reference Control - 0x010601, // DPLL Reference Control - 0x01072A, // DPLL Reference Control - 0x010805, // DPLL Reference Control - 0x0109F2, // DPLL Reference Control - 0x010A00, // DPLL Reference Control - 0x010BA0, // DPLL Reference Control + DPLL Loop Filter - 0x010C00, // DPLL Reference Control - 0x010D00, // DPLL Reference Control - 0x010E02, // DPLL Loop Filter - 0x010FA6, // DPLL Loop Filter - 0x011000, // DPLL Loop Filter - 0x011100, // DPLL Loop Filter - 0x011200, // DPLL Loop Filter - 0x011316, // DPLL Loop Filter - 0x011416, // DPLL Loop Filter - 0x011516, // DPLL Loop Filter - 0x011600, // DPLL Loop Filter - 0x011700, // DPLL Loop Filter - 0x011800, // DPLL Loop Filter - 0x011900, // DPLL Loop Filter - 0x011A00, // DPLL Loop Filter - 0x011B00, // DPLL Loop Filter - 0x011C1E, // DPLL Loop Filter - 0x011D1E, // DPLL Loop Filter - 0x011E00, // DPLL Loop Filter - 0x011F00, // DPLL Loop Filter - 0x012000, // DPLL Loop Filter - 0x012100, // DPLL Loop Filter - 0x012203, // DPLL Phase Lock Detection - 0x012322, // DPLL Phase Lock Detection - 0x012400, // Phase Cancellation for Hitless Switching - 0x012500, // Phase Cancellation for Hitless Switching - 0x012600, // Phase Cancellation for Hitless Switching - 0x012700, // Phase Cancellation for Hitless Switching - 0x01280A, // DPLL Loop Filter - 0x01290A, // DPLL Loop Filter - 0x012A0A, // DPLL Loop Filter - //0x012B00, // unknown - 0x012C00, // DPLL Phase Lock Detection - 0x012D1C, // Phase lock declaration threshold - 0x012E1E, // Phase un-lock declaration threshold - //0x012F01, // unknown????????????? - - 0x01300F, //ok - 0x013104, //ok - 0x013261, //ok - 0x0133F8, //ok - 0x013443, //ok - 0x0135C3, /////// - 0x0136C3, /////// - 0x0137C3, /////// - 0x0138C3, /////// - 0x0139C3, /////// - 0x013AFF, /////// DPLL NUM/DEN (may differ) - 0x013BFF, /////// - 0x013CFF, /////// - 0x013DFF, /////// - 0x013EFF, /////// - - 0x013F03, // DPLL Reference Control != default - 0x014000, // DPLL DCO Lock Detection - 0x01410A, // DPLL DCO Lock Detection - 0x014200, // DPLL DCO Lock Detection - 0x014300, // DPLL DCO Lock Detection - 0x014400, // DPLL DCO Lock Detection - 0x014501, // DPLL DCO Lock Detection - 0x014606, // DPLL DCO Lock Detection - 0x014735, // DPLL DCO Lock Detection - 0x014875, // DPLL DCO Lock Detection - 0x01490B, // DPLL DCO Lock Detection - 0x014A00, // DPLL DCO Unlock Detection - 0x014B64, // DPLL DCO Unlock Detection - 0x014C00, // DPLL DCO Unlock Detection - - //0x014D00, - //0x014E61, /* PLL2 den */ - //0x014FA8, - - 0x015006, // DPLL DCO Unlock Detection != default - 0x015135, // DPLL DCO Unlock Detection - 0x015275, // DPLL DCO Unlock Detection - - 0x01530B, /* Ok PLL1 num*/ - - //0x015400, // DPLL_REF_SYNC_PH_OFFSET ==default - //0x015500, // DPLL_REF_SYNC_PH_OFFSET ==default - //0x015600, // DPLL_REF_SYNC_PH_OFFSET ==default - //0x015700, // DPLL_REF_SYNC_PH_OFFSET ==default - //0x015800, // DPLL_REF_SYNC_PH_OFFSET ==default - //0x015900, // DPLL REF Zero Delay Mode Phase Offset ==default - //0x015A00, // DPLL Freq Incr/Decr enable via pin or reg control ==default - //0x015B00, // DPLL_FDEV ==default - //0x015C00, // DPLL_FDEV ==default - //0x015D00, // DPLL_FDEV ==default - //0x015E00, // DPLL_FDEV ==default - //0x015F00, // DPLL Freq Incr/Decr Numerator Step Word ==default - //0x016000, // DPLL Freq Incr/Decr register control ==default - - //0x016500, - //0x016F00, R - //0x019B00, -}; - - -static const uint32_t lmk05318_rom_dpll____[] = { /* 0x000000, From 8246166addc6216b1e3fdc4f9bbdfdd5db0b830a Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 19 Apr 2025 21:25:01 +0300 Subject: [PATCH 107/397] wait functions refactoring, timeout more accurate --- src/lib/device/pe_sync/pe_sync.c | 3 ++- src/lib/hw/lmk05318/lmk05318.c | 24 ++++++++++++++++-------- src/lib/hw/lmx1204/lmx1204.c | 4 +++- src/lib/hw/lmx2820/lmx2820.c | 9 ++++++--- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 5f14027d..b2fe4171 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -491,7 +491,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) { - USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX1204 not locked, err:%d", res); + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMX1204 not locked, err:%d [%s]", + res, (res == -ETIMEDOUT ? "TIMEOUT" : "ERROR")); return res; } USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1204 locked"); diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 92e40b61..ea3f92bc 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1969,6 +1969,8 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout) while(timeout == 0 || elapsed < timeout) { + uint64_t tk = clock_get_time(); + res = lmk05318_reg_rd(d, PLL1_CALSTAT1, ®); if(res) { @@ -1997,14 +1999,15 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout) break; usleep(100); - elapsed += 100; + elapsed += (clock_get_time() - tk); } + USDR_LOG("5318", USDR_LOG_INFO, "ELAPSED:%.4fs PLL1_CALSTAT1:%u PLL1_VM_INSIDE:0x%02x LOS_MASK:0x%02x LMK05318_BAW_LOCK:%u", + (double)elapsed / 1000000.f, reg, pll1_vm_inside ? 1 : 0, los_msk,(los_msk & LMK05318_BAW_LOCK) ? 1 : 0); + if(!locked) { - USDR_LOG("5318", USDR_LOG_ERROR, "APLL1 is not locked! [PLL1_CALSTAT1:%u PLL1_VM_INSIDE:0x%02x LOS_MASK:0x%02x LMK05318_BAW_LOCK:%u]", - reg, pll1_vm_inside ? 1 : 0, los_msk,(los_msk & LMK05318_BAW_LOCK) ? 1 : 0); - + USDR_LOG("5318", USDR_LOG_ERROR, "APLL1 is not locked!"); return -ETIMEDOUT; } @@ -2023,6 +2026,8 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) while(timeout == 0 || elapsed < timeout) { + uint64_t tk = clock_get_time(); + res = lmk05318_reg_rd(d, PLL2_CALSTAT1, ®); if(res) { @@ -2044,13 +2049,16 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) break; usleep(100); - elapsed += 100; + elapsed += (clock_get_time() - tk); } + USDR_LOG("5318", USDR_LOG_INFO, "ELAPSED:%.4fs PLL2_CALSTAT1:%u PLL2_VM_INSIDE:0x%02x LOS_MASK:0x%02x LMK05318_LOL_PLL2:%u", + (double)elapsed / 1000000.f, reg, pll2_vm_inside ? 1 : 0, los_msk,(los_msk & LMK05318_LOL_PLL2) ? 1 : 0); + + if(!locked) { - USDR_LOG("5318", USDR_LOG_ERROR, "APLL2 is not locked! [PLL2_CALSTAT1:%u PLL2_VM_INSIDE:0x%02x LOS_MASK:0x%02x LMK05318_LOL_PLL2:%u]", - reg, pll2_vm_inside ? 1 : 0, los_msk,(los_msk & LMK05318_LOL_PLL2) ? 1 : 0); + USDR_LOG("5318", USDR_LOG_ERROR, "APLL2 is not locked!"); return -ETIMEDOUT; } @@ -2103,7 +2111,7 @@ int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout) if(valid) break; - usleep(100000); + usleep(1000000); elapsed += (clock_get_time() - tk); } diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 12e9333f..cb9ee86d 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -765,6 +765,8 @@ int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout) uint16_t r75; while(timeout == 0 || elapsed < timeout) { + uint64_t tk = clock_get_time(); + res = lmx1204_spi_get(st, R75, &r75); if(res) return res; @@ -775,7 +777,7 @@ int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout) case RB_LD_LOCKED: return 0; default: usleep(100); - elapsed += 100; + elapsed += (clock_get_time() - tk); } } diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index d8cd65ed..e8e95daa 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -201,6 +201,8 @@ int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) uint16_t r74; while(timeout == 0 || elapsed < timeout) { + uint64_t tk = clock_get_time(); + res = lmx2820_spi_get(st, R74, &r74); if(res) return res; @@ -208,11 +210,11 @@ int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) const uint16_t lock_detect_status = (r74 & RB_LD_MSK) >> RB_LD_OFF; switch(lock_detect_status) { - //case RB_LD_INVALID: return -EINVAL; + case RB_LD_INVALID: return -EINVAL; case RB_LD_LOCKED: return 0; default: usleep(100); - elapsed += 100; + elapsed += (clock_get_time() - tk); } } @@ -973,7 +975,8 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned res = lmx2820_wait_pll_lock(st, 10000); if(res) { - USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_wait_pll_lock() failed, err:%d", res); + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_wait_pll_lock() failed, err:%d [%s]", + res, (res == -ETIMEDOUT ? "TIMEOUT" : "ERROR")); return res; } From 90c0995273e1bc89f835f3162e34e889f4f8715a Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 20 Apr 2025 21:19:17 +0300 Subject: [PATCH 108/397] minor change for debug --- src/lib/hw/lmk05318/lmk05318.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index ea3f92bc..e50de084 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -396,14 +396,14 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* regs, unsigned count, unsigned mask) +static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* regs, unsigned count, unsigned mask_allow, unsigned mask_deny) { unsigned n = 0; for(unsigned i = 0; i < count; ++i) { const empiric_t v = regs[i]; - if(v.type & mask) + if((v.type & mask_allow) && !(v.type & mask_deny)) { USDR_LOG("5318", USDR_LOG_DEBUG, "ADD REGISTER from empirical set [0x%06x]", v.reg); ++n; @@ -551,8 +551,9 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_DEN_BY4(d->dpll.den), //R318 }; - const unsigned mask = (unsigned)-1; //all - res = lmk05318_empirics_smartload(d, lmk05318_rom_dpll_empiric, SIZEOF_ARRAY(lmk05318_rom_dpll_empiric), mask); + const unsigned mask_allow = (unsigned)-1; //all + const unsigned mask_deny = 0; //none + res = lmk05318_empirics_smartload(d, lmk05318_rom_dpll_empiric, SIZEOF_ARRAY(lmk05318_rom_dpll_empiric), mask_allow, mask_deny); res = res ? res : lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); } From 4e41e36d925277856a24de55410fdbfeea340dee Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 21 Apr 2025 01:06:44 +0300 Subject: [PATCH 109/397] LMK DPLL registers cleared: --- src/lib/hw/lmk05318/lmk05318.c | 126 +++++++++++++++++++++++++++++- src/lib/hw/lmk05318/lmk05318.yaml | 35 +++------ 2 files changed, 133 insertions(+), 28 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index e50de084..b7f116d8 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -396,6 +396,7 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } +#if 0 static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* regs, unsigned count, unsigned mask_allow, unsigned mask_deny) { unsigned n = 0; @@ -418,6 +419,7 @@ static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* reg return 0; } +#endif static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bool zdm) { @@ -487,6 +489,30 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo (unsigned)(log2f(10000.f / dpll->fref[LMK05318_SECREF]) + 2.5), }; + //this value is empirical and should be clarified + uint32_t phase_valid_detection[] = + { + dpll->en[LMK05318_PRIREF] ? 50000000 : 0, + dpll->en[LMK05318_SECREF] ? 50000000 : 0, + }; + + //this value is empirical and should be clarified + uint64_t ref_cycslip_offset = 5000000000; + + //this value is empirical and should be clarified + uint16_t ref_filter_scalar = 678; + + //this value is empirical and should be clarified + uint8_t ref_quant = 10; + + uint8_t dpll_sdm_order = 3; + + //this value is empirical and should be clarified + uint64_t dco_lock_det0 = 0x000a000000; + uint64_t dco_lock_det1 = 0x010635750b; + uint32_t dco_unlock_det0 = 0x006400; + uint32_t dco_unlock_det1 = 0x063575; + uint32_t dpll_regs[] = { MAKE_LMK05318_DEV_CTL(0, 0, 1/*SYNC_AUTO_DPLL*/, 1, 1, 1, 1), //R12 set APLL1 mode - Free-run @@ -549,11 +575,104 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_DEN_BY2(d->dpll.den), MAKE_LMK05318_DPLL_REF_DEN_BY3(d->dpll.den), MAKE_LMK05318_DPLL_REF_DEN_BY4(d->dpll.den), //R318 - }; - const unsigned mask_allow = (unsigned)-1; //all - const unsigned mask_deny = 0; //none + MAKE_LMK05318_REG_WR(0x00d8, 0x00), //R216 unknown, undocumented, but critical to start DPLL + + MAKE_LMK05318_REF0_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_PRIREF]), //R235 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY1(phase_valid_detection[LMK05318_PRIREF]), //R236 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY2(phase_valid_detection[LMK05318_PRIREF]), //R237 + MAKE_LMK05318_REF0_PH_VALID_CNT_BY3(phase_valid_detection[LMK05318_PRIREF]), //R238 + + MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R239 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R240 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R241 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R242 + + MAKE_LMK05318_DPLL_REF_TDC_CTL(0, 1), //R260 DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) + + MAKE_LMK05318_REG_WR(DPLL_REF_DLY_GEN, 0x80), //R261 empirical! clarify! + + MAKE_LMK05318_DPLL_REF_CYCSLIP_OFFSET_BY0(ref_cycslip_offset), //R262 + MAKE_LMK05318_DPLL_REF_CYCSLIP_OFFSET_BY1(ref_cycslip_offset), //R263 + MAKE_LMK05318_DPLL_REF_CYCSLIP_OFFSET_BY2(ref_cycslip_offset), //R264 + MAKE_LMK05318_DPLL_REF_CYCSLIP_OFFSET_BY3(ref_cycslip_offset), //R265 + MAKE_LMK05318_DPLL_REF_CYCSLIP_OFFSET_BY4(ref_cycslip_offset), //R266 + + MAKE_LMK05318_REG_WR(DPLL_REF_LOOPCTL, 0xa0), //R267 empirical! clarify! + + MAKE_LMK05318_REG_WR(DPLL_REF_LOOPCTL_CHG, 0), //R268 + MAKE_LMK05318_REG_WR(DPLL_REF_DECIMATION, 0), //R269 + + MAKE_LMK05318_DPLL_REF_FILTSCALAR_BY0(ref_filter_scalar), //R270 + MAKE_LMK05318_DPLL_REF_FILTSCALAR_BY1(ref_filter_scalar), //R271 + + MAKE_LMK05318_REG_WR(DPLL_REF_FILTGAIN, 0), //R272 + MAKE_LMK05318_REG_WR(DPLL_REF_FILTGAIN_FL1, 0), //R273 + MAKE_LMK05318_REG_WR(DPLL_REF_FILTGAIN_FL2, 0), //R274 + + MAKE_LMK05318_REG_WR(DPLL_REF_LOOPGAIN, 22), //R275 empirical! clarify! + MAKE_LMK05318_REG_WR(DPLL_REF_LOOPGAIN_FL1, 22), //R276 empirical! clarify! + MAKE_LMK05318_REG_WR(DPLL_REF_LOOPGAIN_FL2, 22), //R277 empirical! clarify! + + MAKE_LMK05318_REG_WR(DPLL_REF_LPF0GAIN, 0), //R278 + MAKE_LMK05318_REG_WR(DPLL_REF_LPF0GAIN_FL1, 0), //R279 + MAKE_LMK05318_REG_WR(DPLL_REF_LPF0GAIN_FL2, 0), //R280 + + MAKE_LMK05318_REG_WR(DPLL_REF_LPF1GAIN, 0), //R281 + MAKE_LMK05318_REG_WR(DPLL_REF_LPF1GAIN_FL1, 0), //R282 + MAKE_LMK05318_REG_WR(DPLL_REF_LPF1GAIN_FL2, 0), //R283 + + MAKE_LMK05318_REG_WR(DPLL_REF_LPF0GAIN2_FL, 30), //R284 empirical! clarify! + MAKE_LMK05318_REG_WR(DPLL_REF_LPF1GAIN2_FL, 30), //R285 empirical! clarify! + + MAKE_LMK05318_DPLL_REF_TMR_FL1_BY0(0), //R286 + MAKE_LMK05318_DPLL_REF_TMR_FL1_BY1(0), //R287 + MAKE_LMK05318_DPLL_REF_TMR_FL2_BY0(0), //R288 + MAKE_LMK05318_DPLL_REF_TMR_FL2_BY1(0), //R289 + + MAKE_LMK05318_DPLL_REF_TMR_LCK_BY0(0x0322), //R290 empirical! clarify! + MAKE_LMK05318_DPLL_REF_TMR_LCK_BY0(0x0322), //R291 empirical! clarify! + + MAKE_LMK05318_REG_WR(DPLL_REF_PHC_LPF, 0), //R292 + MAKE_LMK05318_REG_WR(DPLL_REF_PHC_CTRL, 0), //R293 + MAKE_LMK05318_DPLL_REF_PHC_TIMER_BY0(0), //R294 + MAKE_LMK05318_DPLL_REF_PHC_TIMER_BY1(0), //R295 + + MAKE_LMK05318_REG_WR(DPLL_REF_QUANT, ref_quant), //R296 + MAKE_LMK05318_REG_WR(DPLL_REF_QUANT_FL1, ref_quant), //R297 + MAKE_LMK05318_REG_WR(DPLL_REF_QUANT_FL2, ref_quant), //R298 + + MAKE_LMK05318_REG_WR(DPLL_PL_LPF_GAIN, 0), //R300 empirical! clarify! + MAKE_LMK05318_REG_WR(DPLL_PL_THRESH, 0x1c), //R301 empirical! clarify! + MAKE_LMK05318_REG_WR(DPLL_PL_UNLK_THRESH, 0x1e), //R302 empirical! clarify! + + MAKE_LMK05318_REG_WR(DPLL_REF_MASHCTL, dpll_sdm_order), //R319 + + MAKE_LMK05318_DPLL_REF_LOCKDET_1_5_BY0(dco_lock_det0), //R320 + MAKE_LMK05318_DPLL_REF_LOCKDET_1_5_BY1(dco_lock_det0), + MAKE_LMK05318_DPLL_REF_LOCKDET_1_5_BY2(dco_lock_det0), + MAKE_LMK05318_DPLL_REF_LOCKDET_1_5_BY3(dco_lock_det0), + MAKE_LMK05318_DPLL_REF_LOCKDET_1_5_BY4(dco_lock_det0), + + MAKE_LMK05318_DPLL_REF_LOCKDET_6_10_BY0(dco_lock_det1), //R325 + MAKE_LMK05318_DPLL_REF_LOCKDET_6_10_BY1(dco_lock_det1), + MAKE_LMK05318_DPLL_REF_LOCKDET_6_10_BY2(dco_lock_det1), + MAKE_LMK05318_DPLL_REF_LOCKDET_6_10_BY3(dco_lock_det1), + MAKE_LMK05318_DPLL_REF_LOCKDET_6_10_BY4(dco_lock_det1), + + MAKE_LMK05318_DPLL_REF_UNLOCKDET_1_3_BY0(dco_unlock_det0), //R330 + MAKE_LMK05318_DPLL_REF_UNLOCKDET_1_3_BY1(dco_unlock_det0), + MAKE_LMK05318_DPLL_REF_UNLOCKDET_1_3_BY2(dco_unlock_det0), + + MAKE_LMK05318_DPLL_REF_UNLOCKDET_VCO_CNTSTRT_BY0(dco_unlock_det1),//R336 + MAKE_LMK05318_DPLL_REF_UNLOCKDET_VCO_CNTSTRT_BY1(dco_unlock_det1),//R337 + MAKE_LMK05318_DPLL_REF_UNLOCKDET_VCO_CNTSTRT_BY2(dco_unlock_det1),//R338 + }; +#if 0 + const unsigned mask_allow = REG_OVERRIDE; + const unsigned mask_deny = REG_PLL1 | REG_PLL2 | REG_XO | REG_LDO | REG_NVM | REG_UNKNOWN; res = lmk05318_empirics_smartload(d, lmk05318_rom_dpll_empiric, SIZEOF_ARRAY(lmk05318_rom_dpll_empiric), mask_allow, mask_deny); +#endif res = res ? res : lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); } @@ -581,6 +700,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_INT_FLAG0(0,0,0,0), //R19 | MAKE_LMK05318_INT_FLAG1(0,0,0,0,0,0,0,0), //R20 | reset interrupt LOS flags + MAKE_LMK05318_INTCTL(0,0), //R21 }; return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index 63f63365..5a9a9389 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -1119,11 +1119,8 @@ pages: - addr: 0x10D name: DPLL_REF_DECIMATION - - addr: 0x10E - name: DPLL_REF_FILTSCALAR_BY1 - - - addr: 0x10F - name: DPLL_REF_FILTSCALAR_BY0 + - addr: "0x10E:0x10F" + name: DPLL_REF_FILTSCALAR - addr: 0x110 name: DPLL_REF_FILTGAIN @@ -1167,23 +1164,14 @@ pages: - addr: 0x11D name: DPLL_REF_LPF1GAIN2_FL - - addr: 0x11E - name: DPLL_REF_TMR_FL1_BY1 - - - addr: 0x11F - name: DPLL_REF_TMR_FL1_BY0 - - - addr: 0x120 - name: DPLL_REF_TMR_FL2_BY1 + - addr: "0x11E:0x11F" + name: DPLL_REF_TMR_FL1 - - addr: 0x121 - name: DPLL_REF_TMR_FL2_BY0 + - addr: "0x120:0x121" + name: DPLL_REF_TMR_FL2 - - addr: 0x122 - name: DPLL_REF_TMR_LCK_BY1 - - - addr: 0x123 - name: DPLL_REF_TMR_LCK_BY0 + - addr: "0x122:0x123" + name: DPLL_REF_TMR_LCK - addr: 0x124 name: DPLL_REF_PHC_LPF @@ -1191,11 +1179,8 @@ pages: - addr: 0x125 name: DPLL_REF_PHC_CTRL - - addr: 0x126 - name: DPLL_REF_PHC_TIMER_BY1 - - - addr: 0x127 - name: DPLL_REF_PHC_TIMER_BY0 + - addr: "0x126:0x127" + name: DPLL_REF_PHC_TIMER - addr: 0x128 name: DPLL_REF_QUANT From 962fb484634a7e6d30af08308ddd4e487534da86 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 21 Apr 2025 01:20:25 +0300 Subject: [PATCH 110/397] minor change --- src/lib/hw/lmk05318/lmk05318.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index b7f116d8..bcce694a 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -396,7 +396,7 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -#if 0 +UNUSED static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* regs, unsigned count, unsigned mask_allow, unsigned mask_deny) { unsigned n = 0; @@ -419,7 +419,6 @@ static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* reg return 0; } -#endif static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bool zdm) { From fdd62a11f807418777491016c76787c97f7e4381 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 21 Apr 2025 16:25:11 +0300 Subject: [PATCH 111/397] several fixes in LMK DPLL regs --- src/lib/hw/lmk05318/lmk05318.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index bcce694a..cdb57cbf 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -583,9 +583,9 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_REF0_PH_VALID_CNT_BY3(phase_valid_detection[LMK05318_PRIREF]), //R238 MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R239 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R240 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R241 - MAKE_LMK05318_REF1_PH_VALID_CNT_BY0(phase_valid_detection[LMK05318_SECREF]), //R242 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY1(phase_valid_detection[LMK05318_SECREF]), //R240 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY2(phase_valid_detection[LMK05318_SECREF]), //R241 + MAKE_LMK05318_REF1_PH_VALID_CNT_BY3(phase_valid_detection[LMK05318_SECREF]), //R242 MAKE_LMK05318_DPLL_REF_TDC_CTL(0, 1), //R260 DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) @@ -630,12 +630,12 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_TMR_FL2_BY1(0), //R289 MAKE_LMK05318_DPLL_REF_TMR_LCK_BY0(0x0322), //R290 empirical! clarify! - MAKE_LMK05318_DPLL_REF_TMR_LCK_BY0(0x0322), //R291 empirical! clarify! + MAKE_LMK05318_DPLL_REF_TMR_LCK_BY1(0x0322), //R291 empirical! clarify! - MAKE_LMK05318_REG_WR(DPLL_REF_PHC_LPF, 0), //R292 - MAKE_LMK05318_REG_WR(DPLL_REF_PHC_CTRL, 0), //R293 - MAKE_LMK05318_DPLL_REF_PHC_TIMER_BY0(0), //R294 - MAKE_LMK05318_DPLL_REF_PHC_TIMER_BY1(0), //R295 + MAKE_LMK05318_REG_WR(DPLL_REF_PHC_LPF, 0), //R292 | + MAKE_LMK05318_REG_WR(DPLL_REF_PHC_CTRL, 0), //R293 | + MAKE_LMK05318_DPLL_REF_PHC_TIMER_BY0(0), //R294 | Phase Cancellation for Hitless Switching + MAKE_LMK05318_DPLL_REF_PHC_TIMER_BY1(0), //R295 | MAKE_LMK05318_REG_WR(DPLL_REF_QUANT, ref_quant), //R296 MAKE_LMK05318_REG_WR(DPLL_REF_QUANT_FL1, ref_quant), //R297 From c916e99a25decb5fe55853a9e62c3256756ff3b4 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 21 Apr 2025 19:02:56 +0300 Subject: [PATCH 112/397] LMK yaml upd + minor changes --- src/lib/hw/lmk05318/lmk05318.c | 5 +++-- src/lib/hw/lmk05318/lmk05318.yaml | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index cdb57cbf..4a07af07 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -505,6 +505,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo uint8_t ref_quant = 10; uint8_t dpll_sdm_order = 3; + uint8_t dpll_sdm_dither = 0; //this value is empirical and should be clarified uint64_t dco_lock_det0 = 0x000a000000; @@ -587,7 +588,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_REF1_PH_VALID_CNT_BY2(phase_valid_detection[LMK05318_SECREF]), //R241 MAKE_LMK05318_REF1_PH_VALID_CNT_BY3(phase_valid_detection[LMK05318_SECREF]), //R242 - MAKE_LMK05318_DPLL_REF_TDC_CTL(0, 1), //R260 DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) + MAKE_LMK05318_DPLL_REF_TDC_CTL(0, 1), //R260 TDC software ctrl(dis) + DPLL_REF_AVOID_SLIP(en) MAKE_LMK05318_REG_WR(DPLL_REF_DLY_GEN, 0x80), //R261 empirical! clarify! @@ -645,7 +646,7 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_REG_WR(DPLL_PL_THRESH, 0x1c), //R301 empirical! clarify! MAKE_LMK05318_REG_WR(DPLL_PL_UNLK_THRESH, 0x1e), //R302 empirical! clarify! - MAKE_LMK05318_REG_WR(DPLL_REF_MASHCTL, dpll_sdm_order), //R319 + MAKE_LMK05318_DPLL_REF_MASHCTL(dpll_sdm_dither, dpll_sdm_order), //R319 MAKE_LMK05318_DPLL_REF_LOCKDET_1_5_BY0(dco_lock_det0), //R320 MAKE_LMK05318_DPLL_REF_LOCKDET_1_5_BY1(dco_lock_det0), diff --git a/src/lib/hw/lmk05318/lmk05318.yaml b/src/lib/hw/lmk05318/lmk05318.yaml index 5a9a9389..94f3ad65 100644 --- a/src/lib/hw/lmk05318/lmk05318.yaml +++ b/src/lib/hw/lmk05318/lmk05318.yaml @@ -1217,6 +1217,11 @@ pages: - addr: 0x13F name: DPLL_REF_MASHCTL + fields: + - bits: "4-3" + name: DPLL_REF_DTHRMODE + - bits: "2-0" + name: DPLL_REF_ORDER - addr: "0x140:0x144" name: DPLL_REF_LOCKDET_1_5 From 9e44ce223e2293edb7f80c9a1e93652941b38b25 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 21 Apr 2025 21:02:18 +0300 Subject: [PATCH 113/397] inscrease lock timeouts - due to timeout functions change several commits above --- src/lib/device/pe_sync/pe_sync.c | 6 +++--- src/lib/hw/lmx2820/lmx2820.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index b2fe4171..17a7c7af 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -335,14 +335,14 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const //wait for lock //APLL1/DPLL - res = lmk05318_wait_apll1_lock(&d->gen, 10000); + res = lmk05318_wait_apll1_lock(&d->gen, 100000); //APLL2 (if needed) if(res == 0 && d->gen.vco2_freq) { //reset LOS flags once again because APLL2 LOS is set after APLL1 tuning res = lmk05318_reset_los_flags(&d->gen); - res = res ? res : lmk05318_wait_apll2_lock(&d->gen, 10000); + res = res ? res : lmk05318_wait_apll2_lock(&d->gen, 100000); } unsigned los_msk; @@ -484,7 +484,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; - res = lmx1204_wait_pll_lock(&d->cldistr, 10000); + res = lmx1204_wait_pll_lock(&d->cldistr, 100000); lmx1204_stats_t lmx1204status; lmx1204_read_status(&d->cldistr, &lmx1204status); //just for log diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index e8e95daa..4bc9fdc6 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -972,7 +972,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned return res; } - res = lmx2820_wait_pll_lock(st, 10000); + res = lmx2820_wait_pll_lock(st, 100000); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_wait_pll_lock() failed, err:%d [%s]", From 36d6daf2778cfbafaf4d5d2302ec2ec18cdcd0bf Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 22 Apr 2025 17:07:14 +0300 Subject: [PATCH 114/397] LMK APLL1 tune refactoring --- src/lib/hw/lmk05318/lmk05318.c | 121 ++++++++++++++++++++++++--------- 1 file changed, 87 insertions(+), 34 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 4a07af07..5905b24a 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -22,8 +22,9 @@ enum { VCO_APLL1 = 2500000000ull, - VCO_APLL1_MIN = 2499750000ull, - VCO_APLL1_MAX = 2500250000ull, + VCO_APLL1_DELTA_MAX = 250000, + VCO_APLL1_MIN = VCO_APLL1 - VCO_APLL1_DELTA_MAX, + VCO_APLL1_MAX = VCO_APLL1 + VCO_APLL1_DELTA_MAX, VCO_APLL2_MIN = 5500000000ull, VCO_APLL2_MAX = 6250000000ull, @@ -56,6 +57,23 @@ enum { DPLL_PRE_DIV_MAX = 17, }; +enum +{ + SDM_DITHER_MODE_WEAK = 0x0, + SDM_DITHER_MODE_MEDIUM = 0x1, + SDM_DITHER_MODE_STRONG = 0x2, + SDM_DITHER_MODE_DISABLED = 0x3, +}; + +enum +{ + SDM_ORDER_INT = 0x0, + SDM_ORDER_FIRST = 0x1, + SDM_ORDER_SECOND = 0x2, + SDM_ORDER_THIRD = 0x3, + SDM_ORDER_FORTH = 0x4, +}; + int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) { if(!dpll->enabled) @@ -209,7 +227,7 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) const double delta = fabs((double)VCO_APLL1 - vco1_fact); USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] N:%u NUM:%" PRIu64 " DEN:%" PRIu64 " VCO1_FACT:%.8f DELTA:%.8fHz", fb_int, fb_num, fb_den, vco1_fact, delta); - if(delta > 1E-6) + if(delta > 1E-4) { USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] VCO1_FACT too rough"); return -EINVAL; @@ -504,8 +522,8 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo //this value is empirical and should be clarified uint8_t ref_quant = 10; - uint8_t dpll_sdm_order = 3; - uint8_t dpll_sdm_dither = 0; + uint8_t dpll_sdm_order = d->dpll.num ? SDM_ORDER_THIRD : SDM_ORDER_INT; + uint8_t dpll_sdm_dither = SDM_DITHER_MODE_WEAK; //this value is empirical and should be clarified uint64_t dco_lock_det0 = 0x000a000000; @@ -974,9 +992,11 @@ static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) { + int res; + double fpd2 = (double)VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; if (fpd2 < APLL2_PD_MIN || fpd2 > APLL2_PD_MAX) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 PFD should be in range [%" PRIu64 ";%" PRIu64 "] but got %.8f!\n", + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 FPD should be in range [%" PRIu64 ";%" PRIu64 "] but got %.8f!\n", (uint64_t)APLL2_PD_MIN, (uint64_t)APLL2_PD_MAX, fpd2); return -EINVAL; } @@ -997,10 +1017,12 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) const unsigned n = d->vco2_n; const unsigned num = d->vco2_num; const unsigned den = d->vco2_den; - int res; - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 RS=%u RP=%u FPD2=%.8f FVCO2=%" PRIu64 " N=%d NUM=%d DEN=%d PD1=%d PD2=%d\n", - d->fref_pll2_div_rs, d->fref_pll2_div_rp, fpd2, d->vco2_freq, n, num, den, d->pd1, d->pd2); + const uint8_t apll2_sdm_order = num ? SDM_ORDER_THIRD : SDM_ORDER_INT; //override if needed + const uint8_t apll2_sdm_dither = SDM_DITHER_MODE_WEAK; + + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 RS=%u RP=%u FPD2=%.8f FVCO2=%" PRIu64 " N=%d NUM=%d DEN=%d PD1=%d PD2=%d MASH_ORD:%u", + d->fref_pll2_div_rs, d->fref_pll2_div_rp, fpd2, d->vco2_freq, n, num, den, d->pd1, d->pd2, apll2_sdm_order); // one of PDs may be unused (==0) -> we should fix it before registers set if(d->pd1 < APLL2_PDIV_MIN || d->pd1 > APLL2_PDIV_MAX) @@ -1012,10 +1034,8 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) d->pd2 = d->pd1; } - const uint8_t apll2_sdm_order = num ? 3 : 0; //override if needed - uint32_t regs[] = { - MAKE_LMK05318_PLL2_MASHCTRL(0,apll2_sdm_order), //R139 PLL2 MASHORD=3 + MAKE_LMK05318_PLL2_MASHCTRL(apll2_sdm_dither, apll2_sdm_order), //R139 PLL2 MASHORD=3 MAKE_LMK05318_PLL2_CTRL2(d->pd2 - 1, d->pd1 - 1), //R102 MAKE_LMK05318_PLL2_NDIV_BY0(n), //R135 MAKE_LMK05318_PLL2_NDIV_BY1(n), //R134 @@ -1084,20 +1104,63 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) int lmk05318_tune_apll1(lmk05318_state_t* d) { - unsigned fpd1 = (d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2 : 1); - uint64_t fvco = VCO_APLL1; - unsigned n = fvco / fpd1; - const uint8_t apll1_sdm_order = 3; //override if needed + int res; + + uint8_t apll1_sdm_order; + const uint8_t apll1_sdm_dither = SDM_DITHER_MODE_WEAK; + + uint64_t num, den; + + const double fpd1 = ((double)d->xo.fref / d->xo.pll1_fref_rdiv) * (d->xo.doubler_enabled ? 2.0f : 1.0f); + if(fpd1 < APLL1_PD_MIN || fpd1 > APLL1_PD_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FPD should be in range [%" PRIu64 ";%" PRIu64 "] but got %.8f!\n", + (uint64_t)APLL1_PD_MIN, (uint64_t)APLL1_PD_MAX, fpd1); + return -EINVAL; + } + + const uint64_t fvco = VCO_APLL1; + const double r = (double)fvco / fpd1; + const unsigned n = (unsigned)r; + const double n_frac = r - n; + + if(n > UINT16_MAX) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FDIV.N=%u out of range [1;65535]", n); + return -EINVAL; + } //in DPLL mode we use FIXED 40-bit APLL1 denominator and programmed 40-bit numerator if(d->dpll.enabled) { - uint64_t num = (fvco - n * (uint64_t)fpd1) * (1ull << 40) / fpd1; + den = (uint64_t)1 << 40; //fixed + num = (uint64_t)(n_frac * den + 0.5); + apll1_sdm_order = SDM_ORDER_THIRD; //for DPLL correction + } + // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator + else + { + den = ((uint64_t)1 << 24) - 1; //max 24-bit + num = (uint64_t)(n_frac * den + 0.5); + apll1_sdm_order = num ? SDM_ORDER_THIRD : SDM_ORDER_INT; + } + + const double vco1_fact = fpd1 * (n + (double)num / den); + + USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FPD=%.8f VCO_FACT=%.8f N=%d NUM=%" PRIu64 " DEN=%" PRIu64 "[%s] MASH_ORD:%u", + fpd1, vco1_fact, n, num, den, (d->dpll.enabled ? "FIXED" : "PROGRAMMED"), apll1_sdm_order); - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu64 " DEN=FIXED\n", fvco, n, num); + if(fabs(vco1_fact - fvco) > 1E-4) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 VCO too rough"); + return -EINVAL; + } + if(d->dpll.enabled) + { uint32_t regs[] = { - MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,apll1_sdm_order), //R115 PLL1 MASHORD=3 WeakDither + MAKE_LMK05318_PLL1_MASHCTRL(0, 0, 0, + apll1_sdm_dither, apll1_sdm_order), //R115 PLL1 MASHORD=3 WeakDither MAKE_LMK05318_PLL1_MODE(0, 0, 1), //R116 DPLL mode MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 NDIV MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 NDIV @@ -1109,21 +1172,13 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) MAKE_LMK05318_PLL1_CTRL0(0), //R74 Activate APLL1 }; - int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; + res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } - // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator else { - double frac = (double)fvco / fpd1 - n; - const uint32_t den = ((uint32_t)1 << 24) - 1; //max 24-bit - const uint32_t num = (frac * den + 0.5); - - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FVCO=%" PRIu64 " N=%d NUM=%" PRIu32 " DEN=%" PRIu32 "\n", fvco, n, num, den); - uint32_t regs[] = { - MAKE_LMK05318_PLL1_MASHCTRL(0,0,0,0,apll1_sdm_order), //R115 PLL1 MASHORD=3 WeakDither + MAKE_LMK05318_PLL1_MASHCTRL(0, 0, 0, + apll1_sdm_dither, apll1_sdm_order), //R115 PLL1 MASHORD=3 WeakDither MAKE_LMK05318_PLL1_MODE(0, 0, 0), //R116 free-run mode MAKE_LMK05318_PLL1_NDIV_BY0(n), //R109 NDIV MAKE_LMK05318_PLL1_NDIV_BY1(n), //R108 NDIV @@ -1139,12 +1194,10 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) MAKE_LMK05318_PLL1_CTRL0(0), //R74 Activate APLL1 }; - int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; + res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } - return 0; + return res; } static inline uint64_t lmk05318_max_odiv(unsigned port) From 3a4c890e7e3e17996849dbc376f364ff0187aecb Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 23 Apr 2025 13:52:17 +0300 Subject: [PATCH 115/397] DPLL ZDM refactored & several minor refact --- .../device/ext_simplesync/ext_simplesync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 109 ++++++++---------- src/lib/hw/lmk05318/lmk05318.h | 17 ++- src/utests/lmk05318_solver_test.c | 12 +- 4 files changed, 67 insertions(+), 73 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 0ebe81d7..e4e60821 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -137,7 +137,7 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) lmk05318_set_port_affinity(cfg, 2, AFF_APLL2); lmk05318_set_port_affinity(cfg, 3, AFF_APLL2); - int res = lmk05318_solver(&ob->lmk, cfg, 4, false /*dry_run*/); + int res = lmk05318_solver(&ob->lmk, cfg, 4); res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); res = res ? res : lmk05318_softreset(&ob->lmk); res = res ? res : lmk05318_reset_los_flags(&ob->lmk); diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 5905b24a..4e27536c 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -76,7 +76,7 @@ enum int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) { - if(!dpll->enabled) + if(!dpll || !dpll->enabled) { d->dpll.enabled = false; USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] DPLL disabled"); @@ -248,10 +248,21 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] LBW:%.2fHz", d->dpll.lbw); + //detect ZDM mode -> + // if 1) OUT7 = 1Hz + // 2) DPLL input ref = 1Hz + // 3) OUT2 routed via APLL1 + const lmk05318_output_t* p7 = &d->outputs[LMK05318_MAX_OUT_PORTS - 1]; + d->dpll.zdm = p7->freq == 1.0 && (p7->mux == OUT_PLL_SEL_APLL1_P1_INV || p7->mux == OUT_PLL_SEL_APLL1_P1); + d->dpll.zdm &= (d->dpll.ref_en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1) + || + (d->dpll.ref_en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] == 1); + + USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] ZDM %s", d->dpll.zdm ? "enabled" : "disabled"); + return 0; } - int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out) { uint8_t data[3] = { reg >> 8, reg, out }; @@ -438,7 +449,7 @@ static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* reg return 0; } -static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bool zdm) +static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) { int res = lmk05318_dpll_config(d, dpll); if(res) @@ -573,7 +584,8 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo MAKE_LMK05318_DPLL_REF_SWMODE(0, (d->dpll.ref_en[LMK05318_PRIREF] ? LMK05318_PRIREF : LMK05318_SECREF), (d->dpll.ref_en[LMK05318_PRIREF] && d->dpll.ref_en[LMK05318_SECREF]) ? 0x0 : 0x3), //R251 - MAKE_LMK05318_DPLL_GEN_CTL(zdm ? 1 : 0, 0, 1/*DPLL_SWITCHOVER_ALWAYS*/, !one_pps[LMK05318_PRIREF] && !one_pps[LMK05318_SECREF], 1, 0, 1), //R252 enable ZDM & enable DPLL + MAKE_LMK05318_DPLL_GEN_CTL(d->dpll.zdm ? 1 : 0, 0, 1/*DPLL_SWITCHOVER_ALWAYS*/, + !one_pps[LMK05318_PRIREF] && !one_pps[LMK05318_SECREF], 1, 0, 1), //R252 enable ZDM & enable DPLL MAKE_LMK05318_DPLL_REF0_RDIV_BY0(d->dpll.rdiv[LMK05318_PRIREF]), //R256 MAKE_LMK05318_DPLL_REF0_RDIV_BY1(d->dpll.rdiv[LMK05318_PRIREF]), MAKE_LMK05318_DPLL_REF1_RDIV_BY0(d->dpll.rdiv[LMK05318_SECREF]), @@ -724,7 +736,6 @@ static int lmk05318_init(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll, bo return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } - int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, @@ -762,34 +773,7 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, res = lmk05318_reg_wr_n(out, lmk05318_rom_dpll, SIZEOF_ARRAY(lmk05318_rom_dpll)); if (res) return res; -#endif - -#if 1 - - //detect ZDM mode -> if 1)OUT7 = 1Hz 2) DPLL input ref = 1Hz - bool zdm = false; - for(unsigned i = 0; i < out_ports_len; ++i) - { - lmk05318_out_config_t* p = out_ports_cfg + i; - if(p->port == 7 && p->wanted.freq == 1) - { - zdm = true; - break; - } - } - zdm &= (dpll->enabled && ((dpll->en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1) - || (dpll->en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] == 1))); - if(zdm) - USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] ZDM enabled"); - // - - res = lmk05318_init(out, dpll, zdm); - if(res) - { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d on init()", res); - return res; - } - +#else res = lmk05318_set_xo_fref(out); if(res) { @@ -804,13 +788,20 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } - res = lmk05318_solver(out, out_ports_cfg, out_ports_len, false /*dry_run*/); + res = lmk05318_solver(out, out_ports_cfg, out_ports_len); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d solving output frequencies", res); return res; } + res = lmk05318_set_common_registers(out, dpll); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d on init()", res); + return res; + } + res = lmk05318_reg_wr_from_map(out, dry_run); if(res) { @@ -1820,8 +1811,10 @@ static const char* lmk05318_decode_mux(enum lmk05318_out_pll_sel_t mux) } VWLT_ATTRIBUTE(optimize("-Ofast")) -int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run) +int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs) { + int res; + if(!_outs || !n_outs || n_outs > LMK05318_MAX_OUT_PORTS) { USDR_LOG("5318", USDR_LOG_ERROR, "input data is incorrect"); @@ -1984,7 +1977,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } const uint64_t f_mid = (VCO_APLL2_MAX + VCO_APLL2_MIN) / 2; - int res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, d); + res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, d); if(res) return res; @@ -2041,35 +2034,31 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } } - //update hw registers - if(!dry_run) + //tune APLL2 + res = lmk05318_tune_apll2_ex(d); + if(res) { - //tune APLL2 - int res = lmk05318_tune_apll2_ex(d); - if(res) - { - USDR_LOG("5318", USDR_LOG_ERROR, "error %d tuning APLL2", res); - return res; - } + USDR_LOG("5318", USDR_LOG_ERROR, "error %d tuning APLL2", res); + return res; + } - //set output ports - for(unsigned i = 0; i < n_outs; ++i) - { - const lmk05318_out_config_t* out = _outs + i; + //set output ports + for(unsigned i = 0; i < n_outs; ++i) + { + const lmk05318_out_config_t* out = _outs + i; - if(out->wanted.freq == 0) - continue; + if(out->wanted.freq == 0) + continue; - USDR_LOG("5318", USDR_LOG_DEBUG, "OUT%u port:%u div:%" PRIu64 " fmt:%u(%s)", - i, out->port, out->result.out_div, out->wanted.type, lmk05318_decode_fmt(out->wanted.type)); + USDR_LOG("5318", USDR_LOG_DEBUG, "OUT%u port:%u div:%" PRIu64 " fmt:%u(%s)", + i, out->port, out->result.out_div, out->wanted.type, lmk05318_decode_fmt(out->wanted.type)); - res = lmk05318_set_out_mux_ex(d, out->port, out->result.mux, out->wanted.type); - res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); - if(res) - { - USDR_LOG("5318", USDR_LOG_ERROR, "error %d setting hw parameters for port#%d", res, out->port); - return res; - } + res = lmk05318_set_out_mux_ex(d, out->port, out->result.mux, out->wanted.type); + res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "error %d setting mux/div for port#%d", res, out->port); + return res; } } diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index ae16030e..6cef6a98 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -68,6 +68,14 @@ struct lmk05318_dpll_settings }; typedef struct lmk05318_dpll_settings lmk05318_dpll_settings_t; +struct lmk05318_output +{ + double freq; + uint64_t odiv; + int mux; +}; +typedef struct lmk05318_output lmk05318_output_t; + struct lmk05318_state { lldev_t dev; unsigned subdev; @@ -82,11 +90,7 @@ struct lmk05318_state { unsigned vco2_n, vco2_num, vco2_den; unsigned pd1, pd2; - struct { - double freq; - uint64_t odiv; - int mux; - } outputs[LMK05318_MAX_OUT_PORTS]; + lmk05318_output_t outputs[LMK05318_MAX_OUT_PORTS]; struct { bool enabled; @@ -96,6 +100,7 @@ struct lmk05318_state { double lbw; uint8_t pre_div; uint64_t n, num, den; + bool zdm; } dpll; lmk05318_xo_settings_t xo; @@ -223,7 +228,7 @@ int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run); int lmk05318_set_xo_fref(lmk05318_state_t* d); int lmk05318_tune_apll1(lmk05318_state_t* d); -int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs, bool dry_run); +int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs); int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 044a26ae..d1079c97 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -32,7 +32,7 @@ static void teardown() START_TEST(lmk05318_solver_test1) { - int res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); + int res = lmk05318_solver(&dev, cfg, OUTS_LEN); ck_assert_int_eq( res, 0 ); } @@ -47,7 +47,7 @@ START_TEST(lmk05318_solver_test2) res = res ? res : lmk05318_port_request(cfg, 6, f/7/17, false, OUT_OFF); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); + res = lmk05318_solver(&dev, cfg, OUTS_LEN); ck_assert_int_eq( res, 0 ); } @@ -79,7 +79,7 @@ START_TEST(lmk05318_solver_test3) res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); + res = lmk05318_solver(&dev, cfg, OUTS_LEN); ck_assert_int_eq( res, 0 ); } @@ -112,10 +112,10 @@ START_TEST(lmk05318_solver_test4) res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(&dev, cfg, 4, true); + res = lmk05318_solver(&dev, cfg, 4); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(&dev, cfg + 4, 4, true); + res = lmk05318_solver(&dev, cfg + 4, 4); ck_assert_int_eq( res, 0 ); } @@ -146,7 +146,7 @@ START_TEST(lmk05318_solver_test5) res = res ? res : lmk05318_port_request(cfg, 7, 1, false, LVCMOS); ck_assert_int_eq( res, 0 ); - res = lmk05318_solver(&dev, cfg, OUTS_LEN, true); + res = lmk05318_solver(&dev, cfg, OUTS_LEN); ck_assert_int_eq( res, 0 ); } From c244c101a91b89973503c8bf6dba3411d3687b53 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 23 Apr 2025 15:36:15 +0300 Subject: [PATCH 116/397] fix err in prev commit + refact + additional log --- src/lib/hw/lmk05318/lmk05318.c | 127 +++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 23 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 4e27536c..333844b6 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -74,6 +74,42 @@ enum SDM_ORDER_FORTH = 0x4, }; +static const char* lmk05318_dpll_decode_ref_dc_mode(enum lmk05318_ref_dc_mode_t m) +{ + switch(m) + { + case REF_DC_MODE_AC_COUPLED_INT: return "AC_COUPLED_INT"; + case REF_DC_MODE_DC_COUPLED_INT: return "DC_COUPLED_INT"; + } + + return "UNKNOWN"; +} + +static const char* lmk05318_dpll_decode_ref_buf_mode(enum lmk05318_ref_buf_mode_t b) +{ + switch(b) + { + case REF_BUF_MODE_AC_HYST50_DC_EN: return "AC_HYST50_DC_EN"; + case REF_BUF_MODE_AC_HYST200_DC_DIS: return "AC_HYST200_DC_DIS"; + } + + return "UNKNOWN"; +} + +static const char* lmk05318_dpll_decode_ref_type(enum lmk05318_ref_input_type_t t) +{ + switch(t) + { + case REF_INPUT_TYPE_DIFF_NOTERM: return "DIFF_NOTERM"; + case REF_INPUT_TYPE_DIFF_100: return "DIFF_100"; + case REF_INPUT_TYPE_DIFF_50: return "DIFF_50"; + case REF_INPUT_TYPE_SE_NOTERM: return "SE_NOTERM"; + case REF_INPUT_TYPE_SE_50: return "SE_50"; + } + + return "UNKNOWN"; +} + int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) { if(!dpll || !dpll->enabled) @@ -229,7 +265,7 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) fb_int, fb_num, fb_den, vco1_fact, delta); if(delta > 1E-4) { - USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] VCO1_FACT too rough"); + USDR_LOG("5318", USDR_LOG_ERROR, "[DPLL] VCO1_FACT:%.8f too rough", vco1_fact); return -EINVAL; } @@ -248,17 +284,24 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] LBW:%.2fHz", d->dpll.lbw); - //detect ZDM mode -> - // if 1) OUT7 = 1Hz - // 2) DPLL input ref = 1Hz - // 3) OUT2 routed via APLL1 - const lmk05318_output_t* p7 = &d->outputs[LMK05318_MAX_OUT_PORTS - 1]; - d->dpll.zdm = p7->freq == 1.0 && (p7->mux == OUT_PLL_SEL_APLL1_P1_INV || p7->mux == OUT_PLL_SEL_APLL1_P1); - d->dpll.zdm &= (d->dpll.ref_en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1) - || - (d->dpll.ref_en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] == 1); + //log + for(unsigned i = LMK05318_PRIREF; i <= LMK05318_SECREF; ++i) + { + const char* nm = i == LMK05318_PRIREF ? "PRIREF" : "SECREF"; + if(d->dpll.ref_en[i]) + USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] %s:enabled FREF:%" PRIu64 " DC_MODE:%u(%s) BUF_MODE:%u(%s) TYPE:%u(%s) RDIV:%u", + nm, + dpll->fref[i], + dpll->dc_mode[i], lmk05318_dpll_decode_ref_dc_mode(dpll->dc_mode[i]), + dpll->buf_mode[i], lmk05318_dpll_decode_ref_buf_mode(dpll->buf_mode[i]), + dpll->type[i], lmk05318_dpll_decode_ref_type(dpll->type[i]), + d->dpll.rdiv[i]); + else + USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] %s:disabled", nm); + } - USDR_LOG("5318", USDR_LOG_DEBUG, "[DPLL] ZDM %s", d->dpll.zdm ? "enabled" : "disabled"); + USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] FTDC:%.4f N:%" PRIu64" NUM:%" PRIu64" DEN:%" PRIu64 " PRE_DIV:%u LBW:%.2fHz VCO1:%.8f", + d->dpll.ftdc, d->dpll.n, d->dpll.num, d->dpll.den, d->dpll.pre_div, d->dpll.lbw, vco1_fact); return 0; } @@ -451,9 +494,7 @@ static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* reg static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) { - int res = lmk05318_dpll_config(d, dpll); - if(res) - return res; + int res = 0; if(d->dpll.enabled == false) { @@ -535,6 +576,7 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett uint8_t dpll_sdm_order = d->dpll.num ? SDM_ORDER_THIRD : SDM_ORDER_INT; uint8_t dpll_sdm_dither = SDM_DITHER_MODE_WEAK; + USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] MASH_ORD:%u", dpll_sdm_order); //this value is empirical and should be clarified uint64_t dco_lock_det0 = 0x000a000000; @@ -542,6 +584,18 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett uint32_t dco_unlock_det0 = 0x006400; uint32_t dco_unlock_det1 = 0x063575; + //detect ZDM mode -> + // if 1) OUT7 = 1Hz + // 2) DPLL input ref = 1Hz + // 3) OUT2 routed via APLL1 + const lmk05318_output_t* p7 = &d->outputs[LMK05318_MAX_OUT_PORTS - 1]; + d->dpll.zdm = p7->freq == 1.0 && (p7->mux == OUT_PLL_SEL_APLL1_P1_INV || p7->mux == OUT_PLL_SEL_APLL1_P1); + d->dpll.zdm &= (d->dpll.ref_en[LMK05318_PRIREF] && dpll->fref[LMK05318_PRIREF] == 1) + || + (d->dpll.ref_en[LMK05318_SECREF] && dpll->fref[LMK05318_SECREF] == 1); + + USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] ZDM %s", d->dpll.zdm ? "enabled" : "disabled"); + uint32_t dpll_regs[] = { MAKE_LMK05318_DEV_CTL(0, 0, 1/*SYNC_AUTO_DPLL*/, 1, 1, 1, 1), //R12 set APLL1 mode - Free-run @@ -781,6 +835,13 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } + res = lmk05318_dpll_config(out, dpll); + if(res) + { + USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d configuring DPLL", res); + return res; + } + res = lmk05318_tune_apll1(out); if(res) { @@ -987,7 +1048,7 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) double fpd2 = (double)VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; if (fpd2 < APLL2_PD_MIN || fpd2 > APLL2_PD_MAX) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 FPD should be in range [%" PRIu64 ";%" PRIu64 "] but got %.8f!\n", + USDR_LOG("5318", USDR_LOG_ERROR, "[APLL2] FPD should be in range [%" PRIu64 ";%" PRIu64 "] but got %.8f!\n", (uint64_t)APLL2_PD_MIN, (uint64_t)APLL2_PD_MAX, fpd2); return -EINVAL; } @@ -996,7 +1057,7 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) ((d->pd1 < APLL2_PDIV_MIN || d->pd1 > APLL2_PDIV_MAX) && (d->pd2 < APLL2_PDIV_MIN || d->pd2 > APLL2_PDIV_MAX)) ) { - USDR_LOG("5318", USDR_LOG_WARNING, "LMK05318 APLL2: either FVCO2[%" PRIu64"] or (PD1[%d] && PD2[%d]) is out of range, APLL2 will be disabled", + USDR_LOG("5318", USDR_LOG_WARNING, "[APLL2] either FVCO2[%" PRIu64"] nor (PD1[%d] && PD2[%d]) is out of range, APLL2 will be disabled", d->vco2_freq, d->pd1, d->pd2); // Disable uint32_t regs[] = { @@ -1012,7 +1073,7 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) const uint8_t apll2_sdm_order = num ? SDM_ORDER_THIRD : SDM_ORDER_INT; //override if needed const uint8_t apll2_sdm_dither = SDM_DITHER_MODE_WEAK; - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL2 RS=%u RP=%u FPD2=%.8f FVCO2=%" PRIu64 " N=%d NUM=%d DEN=%d PD1=%d PD2=%d MASH_ORD:%u", + USDR_LOG("5318", USDR_LOG_INFO, "[APLL2] RS=%u RP=%u FPD2=%.8f FVCO2=%" PRIu64 " N=%d NUM=%d DEN=%d PD1=%d PD2=%d MASH_ORD:%u", d->fref_pll2_div_rs, d->fref_pll2_div_rp, fpd2, d->vco2_freq, n, num, den, d->pd1, d->pd2, apll2_sdm_order); // one of PDs may be unused (==0) -> we should fix it before registers set @@ -1046,6 +1107,21 @@ static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) return 0; } +static const char* lmk05318_decode_xo_type(enum xo_type_options t) +{ + switch(t) + { + case XO_TYPE_DC_DIFF_EXT: return "DC_DIFF_EXT"; + case XO_TYPE_AC_DIFF_EXT: return "AC_DIFF_EXT"; + case XO_TYPE_AC_DIFF_INT_100: return "AC_DIFF_INT_100"; + case XO_TYPE_HCSL_INT_50: return "HCSL_INT_50"; + case XO_TYPE_CMOS: return "CMOS"; + case XO_TYPE_SE_INT_50: return "SE_INT_50"; + } + + return "UNKNOWN"; +} + int lmk05318_set_xo_fref(lmk05318_state_t* d) { const uint32_t xo_fref = d->xo.fref; @@ -1055,14 +1131,14 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) if(xo_fref < XO_FREF_MIN || xo_fref > XO_FREF_MAX) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 XO input fref should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", + USDR_LOG("5318", USDR_LOG_ERROR, "[XO] input fref should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", (uint64_t)XO_FREF_MIN, (uint64_t)XO_FREF_MAX, xo_fref); return -EINVAL; } if(d->xo.pll1_fref_rdiv < APLL1_DIVIDER_MIN || d->xo.pll1_fref_rdiv > APLL1_DIVIDER_MAX) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APPL1_RDIV:%d out of range [%d;%d]", d->xo.pll1_fref_rdiv, (int)APLL1_DIVIDER_MIN, (int)APLL1_DIVIDER_MAX); + USDR_LOG("5318", USDR_LOG_ERROR, "[XO] APPL1_RDIV:%d out of range [%d;%d]", d->xo.pll1_fref_rdiv, (int)APLL1_DIVIDER_MIN, (int)APLL1_DIVIDER_MAX); return -EINVAL; } @@ -1076,10 +1152,15 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) case XO_CMOS: xo_type_raw = XO_TYPE_CMOS; break; case XO_SE_INT_50: xo_type_raw = XO_TYPE_SE_INT_50; break; default: - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 XO input type %d is not supported!\n", (int)xo_type); + USDR_LOG("5318", USDR_LOG_ERROR, "[XO] input type %d is not supported!\n", (int)xo_type); return -EINVAL; } + USDR_LOG("5318", USDR_LOG_INFO, "[XO] FREF:%u TYPE:%u(%s) DOUBLER:%u RDIV:%u FDET_BYPASS:%u", + xo_fref, + xo_type_raw, lmk05318_decode_xo_type(xo_type_raw), + xo_doubler_enabled, d->xo.pll1_fref_rdiv, xo_fdet_bypass); + uint32_t regs[] = { MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0, 0, 1), //R42 MAKE_LMK05318_XO_CLKCTL2(1, xo_type_raw, 2), //R43 @@ -1117,7 +1198,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) if(n > UINT16_MAX) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 FDIV.N=%u out of range [1;65535]", n); + USDR_LOG("5318", USDR_LOG_ERROR, "[APLL1] FDIV.N=%u out of range [1;65535]", n); return -EINVAL; } @@ -1138,12 +1219,12 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) const double vco1_fact = fpd1 * (n + (double)num / den); - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 APLL1 FPD=%.8f VCO_FACT=%.8f N=%d NUM=%" PRIu64 " DEN=%" PRIu64 "[%s] MASH_ORD:%u", + USDR_LOG("5318", USDR_LOG_INFO, "[APLL1] FPD=%.8f VCO_FACT=%.8f N=%d NUM=%" PRIu64 " DEN=%" PRIu64 "[%s] MASH_ORD:%u", fpd1, vco1_fact, n, num, den, (d->dpll.enabled ? "FIXED" : "PROGRAMMED"), apll1_sdm_order); if(fabs(vco1_fact - fvco) > 1E-4) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL1 VCO too rough"); + USDR_LOG("5318", USDR_LOG_ERROR, "[APLL1] VCO too rough"); return -EINVAL; } From 580b98c82efba2c59a0516ffbb54b8de8b288abd Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 23 Apr 2025 15:54:47 +0300 Subject: [PATCH 117/397] APLL1 additional check --- src/lib/hw/lmk05318/lmk05318.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 333844b6..ab0c3e8f 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -74,6 +74,10 @@ enum SDM_ORDER_FORTH = 0x4, }; +#define DPLL_FDIV_FRAC_MAX 0.9375f +#define DPLL_FDIV_FRAC_MIN 0.0625f + + static const char* lmk05318_dpll_decode_ref_dc_mode(enum lmk05318_ref_dc_mode_t m) { switch(m) @@ -1208,6 +1212,14 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) den = (uint64_t)1 << 40; //fixed num = (uint64_t)(n_frac * den + 0.5); apll1_sdm_order = SDM_ORDER_THIRD; //for DPLL correction + + //additional check for DPLL mode + if(num && ((double)num / den <= DPLL_FDIV_FRAC_MIN || (double)num / den >= DPLL_FDIV_FRAC_MAX)) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[APLL1] NUM/DEN ratio:%.8f out of range (%.4f;%.4f)", + (double)num / den, DPLL_FDIV_FRAC_MIN, DPLL_FDIV_FRAC_MAX); + return -EINVAL; + } } // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator else From 44cea4b642cb70aaf6ae41805eeee420cfc3ccb8 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 25 Apr 2025 18:28:10 +0300 Subject: [PATCH 118/397] fix inaccuracy in OUT7 div calculation --- src/lib/hw/lmk05318/lmk05318.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index ab0c3e8f..0c60f971 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -47,6 +47,10 @@ enum { APLL2_PDIV_MAX = 7, APLL2_PDIV_COUNT = 2, //PD1 & PD2 + OUTDIV7_STAGE2_MAX = (uint64_t)1 << 24, + OUTDIV7_STAGE1_MAX = (uint64_t)1 << 8, + OUTDIV7_STAGE1_WITH_ST2_MIN = 6, + F_TDC_MIN = 1, F_TDC_MAX = 26000000, @@ -1300,6 +1304,27 @@ static inline uint64_t lmk05318_max_odiv(unsigned port) return 1; } +VWLT_ATTRIBUTE(optimize("-Ofast")) +static inline uint16_t lmk05318_factorize_out7div(uint64_t total_div) +{ + if(total_div <= OUTDIV7_STAGE1_MAX) + return total_div; + + uint16_t div = OUTDIV7_STAGE1_MAX; + + while(div >= OUTDIV7_STAGE1_WITH_ST2_MIN) + { + if(total_div % div == 0 && total_div / div <= OUTDIV7_STAGE2_MAX) + { + return div; + } + --div; + } + + return OUTDIV7_STAGE1_MAX; //if total div is not divisible by any of [256..6], let it be 256 +} + + int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) { if (port > (LMK05318_MAX_OUT_PORTS - 1) || udiv < 1 || udiv > lmk05318_max_odiv(port)) @@ -1308,9 +1333,11 @@ int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) //out7 is special if(port == 7) { - uint64_t div_stage2 = udiv >> 8; - div_stage2 = div_stage2 ? div_stage2 : 1; - uint8_t div_stage1 = udiv / div_stage2; + uint16_t div_stage1 = lmk05318_factorize_out7div(udiv); + uint64_t div_stage2 = (uint64_t)((double)udiv / div_stage1 + 0.5); + + USDR_LOG("5318", USDR_LOG_DEBUG, "[OUT7] TOTAL_DIV:%" PRIu64 " DIV_STAGE1:%u DIV_STAGE2:%" PRIu64 " FACT:%" PRIu64 "", + udiv, div_stage1, div_stage2, div_stage2 * div_stage1); --div_stage1; --div_stage2; From 96f487463b5c77cdfaaa137c87bf08c0ade88628 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 1 May 2025 20:23:08 +0300 Subject: [PATCH 119/397] lmx1204 does not lock --- src/lib/device/pe_sync/pe_sync.c | 25 ++++++++++++++++++++----- src/lib/hw/lmx1204/lmx1204.c | 30 ++++++++++++++++++++++++++++-- src/lib/hw/lmx2820/lmx2820.c | 2 +- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 17a7c7af..48f42a53 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -196,6 +196,16 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return 0; } +#if 0 + { + USDR_LOG("SYNC", USDR_LOG_WARNING, "PESync shutdown..."); + usdr_device_pe_sync_destroy(udev); + usleep(30000000); + USDR_LOG("SYNC", USDR_LOG_WARNING, "PESync OFF"); + return 0; + } +#endif + // gpo_in_ctrl[0] -- 0 - Disable input 1PPS / 10Mhz buffer and REF ADC for 1PPS // gpo_in_ctrl[1] -- 0 - external SMA, 1 - feedback from LCK_FB // gpo_in_ctrl[2] -- 0 - external SMA, 1 - 1PPS from GPS @@ -326,7 +336,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; //wait for PRIREF/SECREF validation - res = lmk05318_wait_dpll_ref_stat(&d->gen, 60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on + res = lmk05318_wait_dpll_ref_stat(&d->gen, 2*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); @@ -362,10 +372,12 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMK03518 outputs synced"); // + //return 0; + // //LMX2820 #0 setup // -#if 0 +#if 1 const uint64_t lmx0_freq[] = { 1400000000, @@ -387,6 +399,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820[0] outputs locked & synced"); // #endif +#if 1 // //LMX2820 #1 setup // @@ -437,11 +450,11 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1214 initialized"); // - +#endif // //LMX1204 setup // -#if 0 +#if 1 res = lmx1204_create(dev, 0, SPI_LMX1204, &d->cldistr); if(res) { @@ -484,9 +497,11 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; + lmx1204_stats_t lmx1204status; + lmx1204_read_status(&d->cldistr, &lmx1204status); //just for log + res = lmx1204_wait_pll_lock(&d->cldistr, 100000); - lmx1204_stats_t lmx1204status; lmx1204_read_status(&d->cldistr, &lmx1204status); //just for log if(res) diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index cb9ee86d..6739d57a 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -232,6 +232,9 @@ int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_ if(res) return res; + lmx1204_stats_t lmx1204status; + lmx1204_read_status(st, &lmx1204status); //just for log + return 0; } @@ -385,6 +388,23 @@ static const char* lmx1204_decode_fmt(enum logiclkout_fmt_options fmt) return "UNKNOWN"; } +static int lmx1204_reset(lmx1204_state_t* st) +{ + uint32_t regs[] = + { + MAKE_LMX1204_R0(0, 0, 0, 1), //set RESET bit + MAKE_LMX1204_R0(0, 0, 0, 0), //reset RESET bit + }; + + int res = lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); + if(res) + return res; + + usleep(10000); + + return 0; +} + // all params are in lmx1204_state_t struct int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) { @@ -662,6 +682,13 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) //registers + res = dry_run ? 0 : lmx1204_reset(st); + if(res) + { + USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_reset() err:%d", res); + return res; + } + res = dry_run ? 0 : lmx1204_reset_main_divider(st, true); if(res) { @@ -671,8 +698,6 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) uint32_t regs[] = { - MAKE_LMX1204_R0(0, 0, 0, 1), //set RESET bit first - // MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 MAKE_LMX1204_R72(0, 0, 0, 0, SYSREF_DELAY_BYPASS_ENGAGE_IN_GENERATOR_MODE__BYPASS_IN_REPEATER_MODE), @@ -683,6 +708,7 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) // MAKE_LMX1204_R25(0x4, 0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? st->clk_mult_div : st->clk_mult_div - 1, st->clk_mux), + MAKE_LMX1204_R24(0,0,0,1), //enable temp sensor MAKE_LMX1204_R23(1, 1, 1, 0, 1, st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_scale), MAKE_LMX1204_R22(st->sysref_delay_scale, st->sysref_delay_scale, st->sysref_delay_div, 0, st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].q), MAKE_LMX1204_R21(st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].i, st->sysref_indiv_ch_delay[LMX1204_CH_LOGIC].phase, st->sysref_indiv_ch_delay[LMX1204_CH3].q), diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 4bc9fdc6..25a4cf0a 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -210,7 +210,7 @@ int lmx2820_wait_pll_lock(lmx2820_state_t* st, unsigned timeout) const uint16_t lock_detect_status = (r74 & RB_LD_MSK) >> RB_LD_OFF; switch(lock_detect_status) { - case RB_LD_INVALID: return -EINVAL; + //case RB_LD_INVALID: return -EINVAL; case RB_LD_LOCKED: return 0; default: usleep(100); From 6454c6c30357cf43b2aee2848bbafc9e439aa21c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 2 May 2025 20:00:19 +0300 Subject: [PATCH 120/397] LMX1204 works (except multiplier mode), LMX1214 - AUXCLK doesn't work. New freqs settings for PESync --- src/lib/device/pe_sync/pe_sync.c | 27 ++++++++++------ src/lib/hw/lmx1204/lmx1204.c | 51 +++++++++++++++++++++++-------- src/lib/hw/lmx1204/lmx1204.h | 2 ++ src/lib/hw/lmx1204/lmx1204_dump.h | 48 +++++++++++++++++++++++++++++ src/lib/hw/lmx1214/lmx1214.c | 24 ++++++++++----- src/lib/hw/lmx1214/lmx1214.h | 2 ++ src/lib/hw/lmx1214/lmx1214_dump.h | 40 ++++++++++++------------ src/lib/hw/lmx2820/lmx2820.c | 2 +- src/utests/lmx1204_solver_test.c | 25 ++++++++++++--- src/utests/lmx1214_solver_test.c | 28 +++++++++++++---- src/utests/test_suite.c | 2 +- 11 files changed, 189 insertions(+), 62 deletions(-) create mode 100644 src/lib/hw/lmx1204/lmx1204_dump.h diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 48f42a53..425d93c7 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -166,7 +166,7 @@ static void usdr_device_pe_sync_destroy(pdevice_t udev) // struct dev_pe_sync *d = (struct dev_pe_sync *)udev; // lldev_t dev = d->base.dev; // TODO: power off - +#if 0 struct dev_pe_sync *d = (struct dev_pe_sync *)udev; lldev_t dev = d->base.dev; @@ -175,6 +175,8 @@ static void usdr_device_pe_sync_destroy(pdevice_t udev) dev_gpo_set(dev, IGPO_SY1_CTRL, 0); usdr_device_base_destroy(udev); + USDR_LOG("SYNC", USDR_LOG_WARNING, "PESync destroyed"); +#endif } static int i2c_reg_rd8(lldev_t dev, unsigned lsaddr, uint8_t reg, uint8_t* val) @@ -374,14 +376,16 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const //return 0; + usleep(2000000); + // //LMX2820 #0 setup // #if 1 const uint64_t lmx0_freq[] = { - 1400000000, - 1400000000 + 500000000, //1400000000, + 500000000, //1400000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_0, &d->lmx0); @@ -406,8 +410,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const uint64_t lmx1_freq[] = { - 1600000000, - 1600000000 + 550000000, //1600000000, + 550000000, //1600000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); @@ -429,15 +433,16 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const //LMX1214 setup // - const uint64_t ld_clkout = 1600000000/2; + const uint64_t ld_clkout = lmx1_freq[0]; bool ld_en[LMX1214_OUT_CNT] = {1,1,1,1}; lmx1214_auxclkout_cfg_t ld_aux; ld_aux.enable = 1; ld_aux.fmt = LMX1214_FMT_LVDS; - ld_aux.freq = 800000000/4; + ld_aux.freq = ld_clkout; res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*prec_mode*/, false /*dry run*/); + //res = res ? res : lmx1214_loaddump(&d->lodistr); float lmx1214_tempval; lmx1214_get_temperature(&d->lodistr, &lmx1214_tempval); //just for logging @@ -455,6 +460,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const //LMX1204 setup // #if 1 + res = lmx1204_create(dev, 0, SPI_LMX1204, &d->cldistr); if(res) { @@ -466,10 +472,10 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmx1204_state_t* lmx1204 = &d->cldistr; lmx1204->clkin = lmx0_freq[0]; lmx1204->sysrefreq = lmx0_freq[1]; - lmx1204->clkout = d->cldistr.clkin * 4; - lmx1204->sysrefout = 4375000; + lmx1204->clkout = d->cldistr.clkin; + lmx1204->sysrefout = 3125000; lmx1204->sysref_mode = LMX1204_CONTINUOUS; - lmx1204->logiclkout = 1400000; + lmx1204->logiclkout = 125000000; lmx1204->ch_en[LMX1204_CH0] = 1; lmx1204->ch_en[LMX1204_CH1] = 1; @@ -494,6 +500,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmx1204->logisysrefout_fmt = LMX1204_FMT_LVDS; // res = lmx1204_solver(&d->cldistr, false/*prec_mode*/, false/*dry_run*/); + //res = lmx1204_loaddump(&d->cldistr); if(res) return res; diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 6739d57a..bc503807 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -11,6 +11,7 @@ #include "../cal/opt_func.h" #include "../common/common.h" +#include "lmx1204_dump.h" #define FREQ_EPS 1.0f @@ -65,6 +66,20 @@ static int lmx1204_spi_get(lmx1204_state_t* obj, uint16_t addr, uint16_t* out) return common_spi_get(obj, MAKE_LMX1204_REG_RD((uint32_t)addr), out); } +int lmx1204_loaddump(lmx1204_state_t* st) +{ + int res = lmx1204_spi_post(st, lmx1204_rom_test, SIZEOF_ARRAY(lmx1204_rom_test)); + if(res) + { + USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_loaddump() err:%d", res); + } + else + { + USDR_LOG("1204", USDR_LOG_DEBUG, "lmx1204_loaddump() OK"); + } + return res; +} + UNUSED static int lmx1204_read_all_regs(lmx1204_state_t* st) { uint8_t regs[] = @@ -405,6 +420,19 @@ static int lmx1204_reset(lmx1204_state_t* st) return 0; } +static inline uint8_t lmx1204_get_delay_step_size(lmx1204_state_t* st) +{ + uint8_t delay_step_size = SYSREFREQ_DELAY_STEPSIZE_28_PS_1_4_GHZ_TO_2_7_GHZ; + if(st->clkin > 2400000000 && st->clkin <= 4700000000) + delay_step_size = SYSREFREQ_DELAY_STEPSIZE_15_PS_2_4_GHZ_TO_4_7_GHZ; + if(st->clkin > 3100000000 && st->clkin <= 5700000000) + delay_step_size = SYSREFREQ_DELAY_STEPSIZE_11_PS_3_1_GHZ_TO_5_7_GHZ; + if(st->clkin > 4500000000 && st->clkin <= 12800000000) + delay_step_size = SYSREFREQ_DELAY_STEPSIZE_8_PS_4_5_GHZ_TO_12_8_GHZ; + + return delay_step_size; +} + // all params are in lmx1204_state_t struct int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) { @@ -698,13 +726,16 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) uint32_t regs[] = { - MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 + MAKE_LMX1204_REG_WR(R90, st->logiclk_div_bypass ? 0x60 : 0x00), + //MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 + MAKE_LMX1204_R79(0, st->logiclk_div_bypass ? 0x104 : 0x5), + MAKE_LMX1204_REG_WR(0x4c, 0), MAKE_LMX1204_R72(0, 0, 0, 0, SYSREF_DELAY_BYPASS_ENGAGE_IN_GENERATOR_MODE__BYPASS_IN_REPEATER_MODE), // need for MULT VCO calibration MAKE_LMX1204_R67(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x51cb : 0x50c8), MAKE_LMX1204_R34(0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x04c5 : 0), - MAKE_LMX1204_R33(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x5666 : 0x7777), + MAKE_LMX1204_R33(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? /*0x5666*/0x6666 : 0x7777), // MAKE_LMX1204_R25(0x4, 0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? st->clk_mult_div : st->clk_mult_div - 1, st->clk_mux), @@ -718,7 +749,8 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) MAKE_LMX1204_R17(0, st->sysref_indiv_ch_delay[LMX1204_CH0].i, st->sysref_indiv_ch_delay[LMX1204_CH0].phase, st->sysref_mode), MAKE_LMX1204_R16(0x1, st->sysref_div), //0x1 == sysref pulse count MAKE_LMX1204_R15(0, st->sysref_div_pre, 0x3, st->sysref_en ? 1 : 0, 0, 0), - + MAKE_LMX1204_R13(0, lmx1204_get_delay_step_size(st)), +/* //according do doc: program R79 and R90 before setting logiclk_div_bypass //desc order is broken here! MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->ch_en[LMX1204_CH_LOGIC] ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), @@ -726,7 +758,9 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) MAKE_LMX1204_REG_WR(R90, st->logiclk_div_bypass ? 0x60 : 0x00), MAKE_LMX1204_R9(0, 0, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), // - +*/ + MAKE_LMX1204_R9(0, 0, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), + MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->ch_en[LMX1204_CH_LOGIC] ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), MAKE_LMX1204_R7(0, 0, 0, 0, 0, 0, 0, st->sysrefout_en[LMX1204_CH_LOGIC] ? 1 : 0), MAKE_LMX1204_R6(st->clkout_en[LMX1204_CH_LOGIC], 0x3, 0x3, 0x3, 0x3, 0x4), MAKE_LMX1204_R4(0, 0x6, 0x6, @@ -829,14 +863,7 @@ int lmx1204_sysref_windowing_beforesync(lmx1204_state_t* st) { int res; - uint8_t delay_step_size = SYSREFREQ_DELAY_STEPSIZE_28_PS_1_4_GHZ_TO_2_7_GHZ; - if(st->clkin > 2400000000 && st->clkin <= 4700000000) - delay_step_size = SYSREFREQ_DELAY_STEPSIZE_15_PS_2_4_GHZ_TO_4_7_GHZ; - if(st->clkin > 3100000000 && st->clkin <= 5700000000) - delay_step_size = SYSREFREQ_DELAY_STEPSIZE_11_PS_3_1_GHZ_TO_5_7_GHZ; - if(st->clkin > 4500000000 && st->clkin <= 12800000000) - delay_step_size = SYSREFREQ_DELAY_STEPSIZE_8_PS_4_5_GHZ_TO_12_8_GHZ; - + uint8_t delay_step_size = lmx1204_get_delay_step_size(st); USDR_LOG("1204", USDR_LOG_DEBUG, "DELAY_STEPSIZE:%u", delay_step_size); { diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index 2115831c..05cd2af5 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -114,4 +114,6 @@ int lmx1204_sysref_windowing_beforesync(lmx1204_state_t* st); int lmx1204_sysref_windowing_capture(lmx1204_state_t* st); int lmx1204_sysref_windowing_aftersync(lmx1204_state_t* st); +int lmx1204_loaddump(lmx1204_state_t* st); + #endif // LMX1204_H diff --git a/src/lib/hw/lmx1204/lmx1204_dump.h b/src/lib/hw/lmx1204/lmx1204_dump.h new file mode 100644 index 00000000..b97330b5 --- /dev/null +++ b/src/lib/hw/lmx1204/lmx1204_dump.h @@ -0,0 +1,48 @@ +#ifndef LMX1204_DUMP_H +#define LMX1204_DUMP_H + +#include + +static uint32_t lmx1204_rom_test[] = +{ + //500M inputs, 500M outclk, 3.125M refclk, 125M logiclk + + /*R90*/ 0x5A0000, + /*R86*/ 0x560004, + /*R79*/ 0x4F0005, + /*R76*/ 0x4C0000, + /*R75*/ 0x4B0003, + /*R72*/ 0x480000, + /*R67*/ 0x4351CB, + /*R65*/ 0x416410, + /*R34*/ 0x220005, + /*R33*/ 0x216666, + /*R29*/ 0x1D05FF, + /*R28*/ 0x1C0A08, + /*R25*/ 0x190221, + /*R24*/ 0x180001, + /*R23*/ 0x17E055, + /*R22*/ 0x165078, + /*R21*/ 0x150EF8, + /*R20*/ 0x140EF8, + /*R19*/ 0x130EF8, + /*R18*/ 0x120EF8, + /*R17*/ 0x110074, + /*R16*/ 0x1010A0, + /*R15*/ 0x0F0380, + /*R14*/ 0x0E0002, + /*R13*/ 0x0D0000, + /*R12*/ 0x0C0000, + /*R11*/ 0x0B0000, + /*R9 */ 0x090002, + /*R8 */ 0x0800B0, + /*R7 */ 0x070001, + /*R6 */ 0x06C924, + /*R5 */ 0x054936, + /*R4 */ 0x0436FF, + /*R3 */ 0x03FF85, + /*R2 */ 0x020083, + /*R0 */ 0x000000, +}; + +#endif // LMX1204_DUMP_H diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index e7083469..3dff6480 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -92,16 +92,16 @@ UNUSED static int lmx1214_read_all_regs(lmx1214_state_t* st) return 0; } -UNUSED static int lmx1214_loaddump(lmx1214_state_t* st) +int lmx1214_loaddump(lmx1214_state_t* st) { int res = lmx1214_spi_post(st, lmx1214_rom_test, SIZEOF_ARRAY(lmx1214_rom_test)); if(res) { - USDR_LOG("2820", USDR_LOG_ERROR, "lmx1214_loaddump() err:%d", res); + USDR_LOG("1214", USDR_LOG_ERROR, "lmx1214_loaddump() err:%d", res); } else { - USDR_LOG("2820", USDR_LOG_DEBUG, "lmx1214_loaddump() OK"); + USDR_LOG("1214", USDR_LOG_DEBUG, "lmx1214_loaddump() OK"); } return res; } @@ -396,22 +396,30 @@ int lmx1214_solver(lmx1214_state_t* st, uint64_t in, uint64_t out, bool* out_en, uint32_t regs[] = { - MAKE_LMX1214_R25(0x4, 0, st->clk_div - 1, st->clk_mux), + MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), + MAKE_LMX1214_R79(0, 0x5), + MAKE_LMX1214_REG_WR(R75, 0x6), + MAKE_LMX1214_R25(0x4, 0/*clk div reset*/, st->clk_div - 1, st->clk_mux), MAKE_LMX1214_R14(0, 0, 1, 0), - + MAKE_LMX1214_R9 (0, 0, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), + MAKE_LMX1214_R8 (0, st->auxclk_div_pre, 0, (st->auxclkout.enable ? 1 : 0), 0, st->auxclkout.fmt), + MAKE_LMX1214_R7 (0, 0x2, 0x2, 0x2, 0x0/*prediv-pwr 2 bits*/, 0x3, 0x7/*aux pwr*/, 0x1), +#if 0 //according do doc: program R79 and R90 before setting logiclk_div_bypass //desc order is broken here! - MAKE_LMX1214_R8 (0, st->auxclk_div_pre, 0, (st->auxclkout.enable ? 1 : 0), 0, st->auxclkout.fmt), - MAKE_LMX1214_R79(0, st->auxclk_div_byp ? 0x5 : 0x104 /*0x205*/), + MAKE_LMX1214_R8 (0, st->auxclk_div_pre, (st->auxclkout.enable ? 1 : 0), 0, st->auxclkout.fmt), + //MAKE_LMX1214_R79(0, st->auxclk_div_byp ? 0x5 : 0x104 /*0x205*/), MAKE_LMX1214_R90(0, 0, (st->auxclk_div_byp ? 1 : 0), (st->auxclk_div_byp ? 1 : 0), 0), MAKE_LMX1214_R9 (0, 0, 0, (st->auxclk_div_byp ? 1 : 0), 0, st->auxclk_div), - +#endif MAKE_LMX1214_R3 (st->clkout_enabled[LMX1214_CH3] ? 1 : 0, st->clkout_enabled[LMX1214_CH2] ? 1 : 0, st->clkout_enabled[LMX1214_CH1] ? 1 : 0, st->clkout_enabled[LMX1214_CH0] ? 1 : 0, 0xF86//0xFE ), + MAKE_LMX1214_R2 (0, 0x8, 1/*en state machine*/, 0x3), + MAKE_LMX1214_R0 (0, 0/*pwr down*/, 0), }; res = dry_run ? common_print_registers_a8d16(regs, SIZEOF_ARRAY(regs), USDR_LOG_DEBUG) : lmx1214_spi_post(st, regs, SIZEOF_ARRAY(regs)); diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index b4aeba6a..a02d0001 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -61,4 +61,6 @@ int lmx1214_sysref_windowing_beforesync(lmx1214_state_t* st); int lmx1214_sysref_windowing_capture(lmx1214_state_t* st); int lmx1214_sysref_windowing_aftersync(lmx1214_state_t* st); +int lmx1214_loaddump(lmx1214_state_t* st); + #endif // LMX1214_H diff --git a/src/lib/hw/lmx1214/lmx1214_dump.h b/src/lib/hw/lmx1214/lmx1214_dump.h index 5c3daac0..5ef3e05c 100644 --- a/src/lib/hw/lmx1214/lmx1214_dump.h +++ b/src/lib/hw/lmx1214/lmx1214_dump.h @@ -5,26 +5,26 @@ static uint32_t lmx1214_rom_test[] = { - /*R90*/ 0x5A0000, - /*R86*/ 0x560000, - /*R79*/ 0x4F0005, - /*R75*/ 0x4B0006, - /*R25*/ 0x19020A, - /*R24*/ 0x180001, - /*R23*/ 0x17E040, - /*R15*/ 0x0F0B01, - /*R14*/ 0x0E0002, - /*R13*/ 0x0D0003, - /*R12*/ 0x0C0000, - /*R11*/ 0x0B0000, - /*R9*/ 0x092014, - /*R8*/ 0x080090, - /*R7*/ 0x07543F, - /*R5*/ 0x0536F6, - /*R4*/ 0x0436FF, - /*R3*/ 0x03FF86, - /*R2*/ 0x020223, - /*R0*/ 0x000000, + /*R90*/ 0x5A0060, + /*R86*/ 0x560000, + /*R79*/ 0x4F0005, + /*R75*/ 0x4B0006, + /*R25*/ 0x190209, + /*R24*/ 0x180001, + /*R23*/ 0x17E040, + /*R15*/ 0x0F0B00, + /*R14*/ 0x0E0002, + /*R13*/ 0x0D0003, + /*R12*/ 0x0C0000, + /*R11*/ 0x0B0000, + /*R9 */ 0x092802, + /*R8 */ 0x080050, + /*R7 */ 0x07543F, + /*R5 */ 0x0536F6, + /*R4 */ 0x0436FF, + /*R3 */ 0x03FF86, + /*R2 */ 0x020223, + /*R0 */ 0x000000, }; #endif // LMX1214_DUMP_H diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 25a4cf0a..e6e1c735 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -145,7 +145,7 @@ int lmx2820_sync(lmx2820_state_t* st) return lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); } -#define LMX2820_RESET_SKIP +//#define LMX2820_RESET_SKIP int lmx2820_reset(lmx2820_state_t* st) #ifdef LMX2820_RESET_SKIP diff --git a/src/utests/lmx1204_solver_test.c b/src/utests/lmx1204_solver_test.c index 5098a2b2..b86ecf0c 100644 --- a/src/utests/lmx1204_solver_test.c +++ b/src/utests/lmx1204_solver_test.c @@ -100,6 +100,22 @@ START_TEST(lmx1204_solver_test4) ck_assert_int_eq( res, 0 ); } +START_TEST(lmx1204_solver_test5) +{ + st.clkin = 500000000; + st.clkout = st.clkin; + + st.sysrefreq = 0; + st.sysrefout = 3125000; + st.sysref_mode = LMX1204_CONTINUOUS; + + //st.ch_en[LMX1204_CH_LOGIC] = false; + st.logiclkout = 125000000; + + int res = lmx1204_solver(&st, false, true); + ck_assert_int_eq( res, 0 ); +} + Suite * lmx1204_solver_suite(void) { Suite *s; @@ -110,10 +126,11 @@ Suite * lmx1204_solver_suite(void) tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, lmx1204_solver_test1); - tcase_add_test(tc_core, lmx1204_solver_test2); - tcase_add_test(tc_core, lmx1204_solver_test3); - tcase_add_test(tc_core, lmx1204_solver_test4); + //tcase_add_test(tc_core, lmx1204_solver_test1); + //tcase_add_test(tc_core, lmx1204_solver_test2); + //tcase_add_test(tc_core, lmx1204_solver_test3); + //tcase_add_test(tc_core, lmx1204_solver_test4); + tcase_add_test(tc_core, lmx1204_solver_test5); suite_add_tcase(s, tc_core); return s; diff --git a/src/utests/lmx1214_solver_test.c b/src/utests/lmx1214_solver_test.c index f7910a5b..deff490d 100644 --- a/src/utests/lmx1214_solver_test.c +++ b/src/utests/lmx1214_solver_test.c @@ -101,6 +101,21 @@ START_TEST(lmx1214_solver_test4_pesync2) ck_assert_int_eq( res, 0 ); } +START_TEST(lmx1214_solver_test4_pesync3) +{ + const uint64_t osc_in = 550000000; + uint64_t out_freq = osc_in; + bool en[4] = {1,1,1,1}; + + lmx1214_auxclkout_cfg_t aux; + aux.enable = 1; + aux.fmt = LMX1214_FMT_LVDS; + aux.freq = osc_in; + + int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, false, true); + ck_assert_int_eq( res, 0 ); +} + Suite * lmx1214_solver_suite(void) { Suite *s; @@ -111,12 +126,13 @@ Suite * lmx1214_solver_suite(void) tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, lmx1214_solver_test1); - tcase_add_test(tc_core, lmx1214_solver_test2); - tcase_add_test(tc_core, lmx1214_solver_test3); - tcase_add_test(tc_core, lmx1214_solver_test4_pesync0); - tcase_add_test(tc_core, lmx1214_solver_test4_pesync1); - tcase_add_test(tc_core, lmx1214_solver_test4_pesync2); +// tcase_add_test(tc_core, lmx1214_solver_test1); +// tcase_add_test(tc_core, lmx1214_solver_test2); +// tcase_add_test(tc_core, lmx1214_solver_test3); +// tcase_add_test(tc_core, lmx1214_solver_test4_pesync0); +// tcase_add_test(tc_core, lmx1214_solver_test4_pesync1); +// tcase_add_test(tc_core, lmx1214_solver_test4_pesync2); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync3); suite_add_tcase(s, tc_core); return s; diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index 505c80df..a189e1ab 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -38,7 +38,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, lmx1214_solver_suite()); srunner_add_suite(sr, lmx1204_solver_suite()); #else - sr = srunner_create(lmk05318_solver_suite()); + sr = srunner_create(lmx1204_solver_suite()); #endif srunner_set_fork_status (sr, CK_NOFORK); From 8ecca2ade70a65341559f7c1ffb36ed5378427bc Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 3 May 2025 12:57:20 +0300 Subject: [PATCH 121/397] Add distributers LMK1D1208i for LMX1204 LOGICLK/LOGICREF --- src/lib/device/pe_sync/pe_sync.c | 81 +++++++++++++++- src/lib/hw/lmk1d1208i/lmk1d1208i.c | 128 ++++++++++++++++++++++++++ src/lib/hw/lmk1d1208i/lmk1d1208i.h | 55 +++++++++++ src/lib/hw/lmk1d1208i/lmk1d1208i.yaml | 5 +- 4 files changed, 265 insertions(+), 4 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 425d93c7..b95c0fa9 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -21,6 +21,7 @@ #include "../hw/lmx2820/lmx2820.h" #include "../hw/lmx1214/lmx1214.h" #include "../hw/lmx1204/lmx1204.h" +#include "../hw/lmk1d1208i/lmk1d1208i.h" // [0] 24bit 20Mhz AD5662 InRef::DAC_REF // [1] 24bit 20Mhz AD5662 ClockGen::GEN_DC @@ -128,6 +129,7 @@ struct dev_pe_sync { lmx2820_state_t lmx0, lmx1; lmx1214_state_t lodistr; lmx1204_state_t cldistr; + lmk1d1208i_state_t lmk1d0, lmk1d1; }; enum dev_gpi { @@ -432,7 +434,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // //LMX1214 setup // - +#if 1 const uint64_t ld_clkout = lmx1_freq[0]; bool ld_en[LMX1214_OUT_CNT] = {1,1,1,1}; lmx1214_auxclkout_cfg_t ld_aux; @@ -454,6 +456,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const } USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1214 initialized"); +#endif // #endif // @@ -522,6 +525,82 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1204 initialized"); // #endif + + // + // LMK1D1208I[0] setup + // + + lmk1d1208i_config_t lmk1d_cfg; + lmk1d_cfg.in[0].enabled = true; + lmk1d_cfg.in[1].enabled = false; + lmk1d_cfg.bank[0].mute = false; + lmk1d_cfg.bank[1].mute = false; + lmk1d_cfg.bank[0].sel = LMK1D1208I_IN0; + lmk1d_cfg.bank[1].sel = LMK1D1208I_IN0; + lmk1d_cfg.out[0].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[1].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[2].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[3].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[4].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[5].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[6].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[7].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[0].enabled = true; + lmk1d_cfg.out[1].enabled = true; + lmk1d_cfg.out[2].enabled = true; + lmk1d_cfg.out[3].enabled = true; + lmk1d_cfg.out[4].enabled = true; + lmk1d_cfg.out[5].enabled = true; + lmk1d_cfg.out[6].enabled = true; + lmk1d_cfg.out[7].enabled = true; + + res = lmk1d1208i_create(dev, 0, I2C_BUS_LMK1D1208I_LCK, &lmk1d_cfg, &d->lmk1d0); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK1D1208I[0] failed to initialize, res:%d", res); + return res; + } + + USDR_LOG("SYNC", USDR_LOG_INFO, "LMK1D1208I[0] initialized"); + // + + // + // LMK1D1208I[1] setup + // + + lmk1d_cfg.in[0].enabled = true; + lmk1d_cfg.in[1].enabled = false; + lmk1d_cfg.bank[0].mute = false; + lmk1d_cfg.bank[1].mute = false; + lmk1d_cfg.bank[0].sel = LMK1D1208I_IN0; + lmk1d_cfg.bank[1].sel = LMK1D1208I_IN0; + lmk1d_cfg.out[0].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[1].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[2].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[3].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[4].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[5].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[6].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[7].amp = LMK1D1208I_STANDARD_LVDS; + lmk1d_cfg.out[0].enabled = true; + lmk1d_cfg.out[1].enabled = true; + lmk1d_cfg.out[2].enabled = true; + lmk1d_cfg.out[3].enabled = true; + lmk1d_cfg.out[4].enabled = true; + lmk1d_cfg.out[5].enabled = true; + lmk1d_cfg.out[6].enabled = true; + lmk1d_cfg.out[7].enabled = true; + + res = lmk1d1208i_create(dev, 0, I2C_BUS_LMK1D1208I_LRF, &lmk1d_cfg, &d->lmk1d1); + if(res) + { + USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK1D1208I[1] failed to initialize, res:%d", res); + return res; + } + + USDR_LOG("SYNC", USDR_LOG_INFO, "LMK1D1208I[1] initialized"); + // + return res; } diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.c b/src/lib/hw/lmk1d1208i/lmk1d1208i.c index 7a8e6ed9..870d9e7b 100644 --- a/src/lib/hw/lmk1d1208i/lmk1d1208i.c +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.c @@ -1,6 +1,134 @@ // Copyright (c) 2025 Wavelet Lab // SPDX-License-Identifier: MIT +#include +#include +#include + #include "def_lmk1d1208i.h" #include "lmk1d1208i.h" #include "usdr_logging.h" + + +static int lmk1d1208i_reg_wr(lmk1d1208i_state_t* d, uint8_t reg, uint8_t out) +{ + uint8_t data[2] = { reg, out }; + return lowlevel_ls_op(d->dev, d->subdev, + USDR_LSOP_I2C_DEV, d->lsaddr, + 0, NULL, 2, data); +} + +static int lmk1d1208i_reg_rd(lmk1d1208i_state_t* d, uint8_t reg, uint8_t* val) +{ + uint8_t addr[1] = { reg }; + return lowlevel_ls_op(d->dev, d->subdev, + USDR_LSOP_I2C_DEV, d->lsaddr, + 1, val, 1, addr); +} + +static int lmk1d1208i_reg_print(const uint16_t* regs, unsigned count) +{ + for (unsigned j = 0; j < count; j++) + { + uint8_t addr = regs[j] >> 8; + uint8_t data = regs[j]; + USDR_LOG("1D1208I", USDR_LOG_DEBUG, "WRITING REG R%02u -> 0x%02x [0x%04x]", addr, data, regs[j]); + } + return 0; +} + +static int lmk1d1208i_reg_wr_n(lmk1d1208i_state_t* d, const uint16_t* regs, unsigned count) +{ + int res; + // + lmk1d1208i_reg_print(regs, count); + // + for (unsigned j = 0; j < count; j++) + { + uint8_t addr = regs[j] >> 8; + uint8_t data = regs[j]; + + res = lmk1d1208i_reg_wr(d, addr, data); + if (res) + return res; + } + + return 0; +} + +int lmk1d1208i_create(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk1d1208i_config_t* cfg, + lmk1d1208i_state_t* st) +{ + int res; + memset(st, 0, sizeof(lmk1d1208i_state_t)); + + st->dev = dev; + st->subdev = subdev; + st->lsaddr = lsaddr; + + uint8_t r5; + res = lmk1d1208i_reg_rd(st, R5, &r5); + if(res) + { + USDR_LOG("1D1208I", USDR_LOG_ERROR, "lmk1d1208i_reg_rd() error:%d", res); + return res; + } + + const uint8_t rev_id = (r5 & REV_ID_MSK) >> REV_ID_OFF; + const uint8_t dev_id = (r5 & DEV_ID_MSK) >> DEV_ID_OFF; + USDR_LOG("1D1208I", USDR_LOG_DEBUG, "REV_ID:0x%01x DEV_ID:0x%01x", rev_id, dev_id); + + if(rev_id != 0x2 && dev_id != 0x0) + { + USDR_LOG("1D1208I", USDR_LOG_ERROR, "1D1208I chip/bus not found"); + return -EINVAL; + } + + uint16_t regs[] = + { + MAKE_LMK1D1208I_R0(cfg->out[7].enabled ? OUT7_EN_OUTPUT_ENABLED : OUT7_EN_OUTPUT_DISABLED_HI_Z, + cfg->out[6].enabled ? OUT6_EN_OUTPUT_ENABLED : OUT6_EN_OUTPUT_DISABLED_HI_Z, + cfg->out[5].enabled ? OUT5_EN_OUTPUT_ENABLED : OUT5_EN_OUTPUT_DISABLED_HI_Z, + cfg->out[4].enabled ? OUT4_EN_OUTPUT_ENABLED : OUT4_EN_OUTPUT_DISABLED_HI_Z, + cfg->out[3].enabled ? OUT3_EN_OUTPUT_ENABLED : OUT3_EN_OUTPUT_DISABLED_HI_Z, + cfg->out[2].enabled ? OUT2_EN_OUTPUT_ENABLED : OUT2_EN_OUTPUT_DISABLED_HI_Z, + cfg->out[1].enabled ? OUT1_EN_OUTPUT_ENABLED : OUT1_EN_OUTPUT_DISABLED_HI_Z, + cfg->out[0].enabled ? OUT0_EN_OUTPUT_ENABLED : OUT0_EN_OUTPUT_DISABLED_HI_Z + ), + MAKE_LMK1D1208I_R1(cfg->out[7].amp == LMK1D1208I_BOOSTED_LVDS ? OUT7_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT7_AMP_SEL_STANDARD_LVDS_SWING_350_MV, + cfg->out[6].amp == LMK1D1208I_BOOSTED_LVDS ? OUT6_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT6_AMP_SEL_STANDARD_LVDS_SWING_350_MV, + cfg->out[5].amp == LMK1D1208I_BOOSTED_LVDS ? OUT5_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT5_AMP_SEL_STANDARD_LVDS_SWING_350_MV, + cfg->out[4].amp == LMK1D1208I_BOOSTED_LVDS ? OUT4_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT4_AMP_SEL_STANDARD_LVDS_SWING_350_MV, + cfg->out[3].amp == LMK1D1208I_BOOSTED_LVDS ? OUT3_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT3_AMP_SEL_STANDARD_LVDS_SWING_350_MV, + cfg->out[2].amp == LMK1D1208I_BOOSTED_LVDS ? OUT2_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT2_AMP_SEL_STANDARD_LVDS_SWING_350_MV, + cfg->out[1].amp == LMK1D1208I_BOOSTED_LVDS ? OUT1_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT1_AMP_SEL_STANDARD_LVDS_SWING_350_MV, + cfg->out[0].amp == LMK1D1208I_BOOSTED_LVDS ? OUT0_AMP_SEL_BOOSTED_LVDS_SWING_500_MV : OUT0_AMP_SEL_STANDARD_LVDS_SWING_350_MV + ), + MAKE_LMK1D1208I_R2(1, 1, /*reserved*/ + cfg->bank[1].sel == LMK1D1208I_IN0 ? BANK1_IN_SEL_IN0_PDIVIN0_N : BANK1_IN_SEL_IN1_PDIVIN1_N, + cfg->bank[0].sel == LMK1D1208I_IN0 ? BANK0_IN_SEL_IN0_PDIVIN0_N : BANK0_IN_SEL_IN1_PDIVIN1_N, + cfg->bank[1].mute ? BANK1_MUTE_LOGIC_LOW : BANK1_MUTE_INX_PDIVINX_N, + cfg->bank[0].mute ? BANK0_MUTE_LOGIC_LOW : BANK0_MUTE_INX_PDIVINX_N, + cfg->in[1].enabled ? IN1_EN_INPUT_ENABLED : IN1_EN_INPUT_DISABLED_REDUCES_POWER_CONSUMPTION, + cfg->in[0].enabled ? IN0_EN_INPUT_ENABLED : IN0_EN_INPUT_DISABLED_REDUCES_POWER_CONSUMPTION + ), + }; + + res = lmk1d1208i_reg_wr_n(st, regs, SIZEOF_ARRAY(regs)); + if(res) + { + USDR_LOG("1D1208I", USDR_LOG_ERROR, "lmk1d1208i_reg_wr_n() error:%d", res); + return res; + } + + USDR_LOG("1D1208I", USDR_LOG_DEBUG, "Create OK"); + return 0; +} + +int lmk1d1208i_destroy(lmk1d1208i_state_t* st) +{ + USDR_LOG("1D1208I", USDR_LOG_DEBUG, "Destroy OK"); + return 0; +} + + diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.h b/src/lib/hw/lmk1d1208i/lmk1d1208i.h index af3c43a7..de4e3a45 100644 --- a/src/lib/hw/lmk1d1208i/lmk1d1208i.h +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.h @@ -4,4 +4,59 @@ #ifndef LMK1D1208I_H #define LMK1D1208I_H +#include + +#define LMK1D1208I_IN_CNT 2 +#define LMK1D1208I_BANK_CNT 2 +#define LMK1D1208I_OUT_CNT 8 + +struct lmk1d1208i_state { + lldev_t dev; + unsigned subdev; + unsigned lsaddr; +}; +typedef struct lmk1d1208i_state lmk1d1208i_state_t; + +enum lmk1d1208i_bank_sel +{ + LMK1D1208I_IN0 = 1, + LMK1D1208I_IN1 = 0, +}; +typedef enum lmk1d1208i_bank_sel lmk1d1208i_bank_sel_t; + +enum lmk1d1208i_amp_sel +{ + LMK1D1208I_STANDARD_LVDS = 0, + LMK1D1208I_BOOSTED_LVDS = 1, +}; +typedef enum lmk1d1208i_amp_sel lmk1d1208i_amp_sel_t; + +struct lmk1d1208i_config +{ + struct + { + bool enabled; + } + in[LMK1D1208I_IN_CNT]; + + struct + { + lmk1d1208i_bank_sel_t sel; + bool mute; + } + bank[LMK1D1208I_BANK_CNT]; + + struct + { + bool enabled; + lmk1d1208i_amp_sel_t amp; + } + out[LMK1D1208I_OUT_CNT]; +}; +typedef struct lmk1d1208i_config lmk1d1208i_config_t; + + +int lmk1d1208i_create(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk1d1208i_config_t* cfg, lmk1d1208i_state_t* st); +int lmk1d1208i_destroy(lmk1d1208i_state_t* st); + #endif // LMK1D1208I_H diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml b/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml index 058eb990..fc654f4e 100644 --- a/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.yaml @@ -3,10 +3,9 @@ revision: 0.0.1 processors: [ c ] bus: type: I2C - wr_mask: 0x80000000 usdr_path: /debug/hw/lmk1d1208i/*/reg -addr_width: 16 -data_width: 16 +addr_width: 8 +data_width: 8 pages: - name: Main From a743ca8c53bd1453d01810338486c47588204c64 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 3 May 2025 19:44:12 +0300 Subject: [PATCH 122/397] LMX1204 MULT mode lock fixed --- src/lib/device/pe_sync/pe_sync.c | 26 +++++++---------- src/lib/hw/lmk1d1208i/lmk1d1208i.c | 14 +++++----- src/lib/hw/lmx1204/lmx1204.c | 45 +++++++++++++----------------- src/lib/hw/lmx1204/lmx1204.h | 1 + src/lib/hw/lmx1204/lmx1204_dump.h | 43 ++++++++++++++++++++++++++++ src/lib/hw/lmx2820/lmx2820.c | 20 ++++++------- 6 files changed, 90 insertions(+), 59 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index b95c0fa9..20d9af34 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -299,7 +299,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmk05318_dpll_settings_t dpll; memset(&dpll, 0, sizeof(dpll)); - dpll.enabled = true; + dpll.enabled = false; dpll.en[LMK05318_PRIREF] = true; dpll.fref[LMK05318_PRIREF] = 1; dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; @@ -376,18 +376,16 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMK03518 outputs synced"); // - //return 0; - - usleep(2000000); + usleep(2000000); //LMX2820[0] will not start without it // //LMX2820 #0 setup // -#if 1 + const uint64_t lmx0_freq[] = { - 500000000, //1400000000, - 500000000, //1400000000 + 500000000*2, //1400000000, + 500000000*2, //1400000000 }; res = lmx2820_create(dev, 0, SPI_LMX2820_0, &d->lmx0); @@ -404,8 +402,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX2820[0] outputs locked & synced"); // -#endif -#if 1 + // //LMX2820 #1 setup // @@ -434,7 +431,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // //LMX1214 setup // -#if 1 + const uint64_t ld_clkout = lmx1_freq[0]; bool ld_en[LMX1214_OUT_CNT] = {1,1,1,1}; lmx1214_auxclkout_cfg_t ld_aux; @@ -456,13 +453,11 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const } USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1214 initialized"); -#endif // -#endif + // //LMX1204 setup // -#if 1 res = lmx1204_create(dev, 0, SPI_LMX1204, &d->cldistr); if(res) @@ -475,7 +470,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmx1204_state_t* lmx1204 = &d->cldistr; lmx1204->clkin = lmx0_freq[0]; lmx1204->sysrefreq = lmx0_freq[1]; - lmx1204->clkout = d->cldistr.clkin; + lmx1204->clkout = d->cldistr.clkin * 4; lmx1204->sysrefout = 3125000; lmx1204->sysref_mode = LMX1204_CONTINUOUS; lmx1204->logiclkout = 125000000; @@ -510,7 +505,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmx1204_stats_t lmx1204status; lmx1204_read_status(&d->cldistr, &lmx1204status); //just for log - res = lmx1204_wait_pll_lock(&d->cldistr, 100000); + res = lmx1204_wait_pll_lock(&d->cldistr, 1000000); lmx1204_read_status(&d->cldistr, &lmx1204status); //just for log @@ -524,7 +519,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const USDR_LOG("SYNC", USDR_LOG_INFO, "LMX1204 initialized"); // -#endif // // LMK1D1208I[0] setup diff --git a/src/lib/hw/lmk1d1208i/lmk1d1208i.c b/src/lib/hw/lmk1d1208i/lmk1d1208i.c index 870d9e7b..bcf6c348 100644 --- a/src/lib/hw/lmk1d1208i/lmk1d1208i.c +++ b/src/lib/hw/lmk1d1208i/lmk1d1208i.c @@ -32,7 +32,7 @@ static int lmk1d1208i_reg_print(const uint16_t* regs, unsigned count) { uint8_t addr = regs[j] >> 8; uint8_t data = regs[j]; - USDR_LOG("1D1208I", USDR_LOG_DEBUG, "WRITING REG R%02u -> 0x%02x [0x%04x]", addr, data, regs[j]); + USDR_LOG("1208", USDR_LOG_DEBUG, "WRITING REG R%02u -> 0x%02x [0x%04x]", addr, data, regs[j]); } return 0; } @@ -70,17 +70,17 @@ int lmk1d1208i_create(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk1d res = lmk1d1208i_reg_rd(st, R5, &r5); if(res) { - USDR_LOG("1D1208I", USDR_LOG_ERROR, "lmk1d1208i_reg_rd() error:%d", res); + USDR_LOG("1208", USDR_LOG_ERROR, "lmk1d1208i_reg_rd() error:%d", res); return res; } const uint8_t rev_id = (r5 & REV_ID_MSK) >> REV_ID_OFF; const uint8_t dev_id = (r5 & DEV_ID_MSK) >> DEV_ID_OFF; - USDR_LOG("1D1208I", USDR_LOG_DEBUG, "REV_ID:0x%01x DEV_ID:0x%01x", rev_id, dev_id); + USDR_LOG("1208", USDR_LOG_DEBUG, "REV_ID:0x%01x DEV_ID:0x%01x", rev_id, dev_id); if(rev_id != 0x2 && dev_id != 0x0) { - USDR_LOG("1D1208I", USDR_LOG_ERROR, "1D1208I chip/bus not found"); + USDR_LOG("1208", USDR_LOG_ERROR, "1D1208I chip/bus not found"); return -EINVAL; } @@ -117,17 +117,17 @@ int lmk1d1208i_create(lldev_t dev, unsigned subdev, unsigned lsaddr, const lmk1d res = lmk1d1208i_reg_wr_n(st, regs, SIZEOF_ARRAY(regs)); if(res) { - USDR_LOG("1D1208I", USDR_LOG_ERROR, "lmk1d1208i_reg_wr_n() error:%d", res); + USDR_LOG("1208", USDR_LOG_ERROR, "lmk1d1208i_reg_wr_n() error:%d", res); return res; } - USDR_LOG("1D1208I", USDR_LOG_DEBUG, "Create OK"); + USDR_LOG("1208", USDR_LOG_DEBUG, "Create OK"); return 0; } int lmk1d1208i_destroy(lmk1d1208i_state_t* st) { - USDR_LOG("1D1208I", USDR_LOG_DEBUG, "Destroy OK"); + USDR_LOG("1208", USDR_LOG_DEBUG, "Destroy OK"); return 0; } diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index bc503807..a60cc1a5 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -68,7 +68,7 @@ static int lmx1204_spi_get(lmx1204_state_t* obj, uint16_t addr, uint16_t* out) int lmx1204_loaddump(lmx1204_state_t* st) { - int res = lmx1204_spi_post(st, lmx1204_rom_test, SIZEOF_ARRAY(lmx1204_rom_test)); + int res = lmx1204_spi_post(st, lmx1204_rom_with_mult, SIZEOF_ARRAY(lmx1204_rom_with_mult)); if(res) { USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_loaddump() err:%d", res); @@ -77,6 +77,9 @@ int lmx1204_loaddump(lmx1204_state_t* st) { USDR_LOG("1204", USDR_LOG_DEBUG, "lmx1204_loaddump() OK"); } + + st->clk_mux = CLK_MUX_MULTIPLIER_MODE; + return res; } @@ -133,7 +136,7 @@ UNUSED static int lmx1204_read_all_regs(lmx1204_state_t* st) return 0; } -static int lmx1204_reset_main_divider(lmx1204_state_t* st, bool set_flag) +int lmx1204_reset_main_divider(lmx1204_state_t* st, bool set_flag) { uint16_t r25; @@ -717,25 +720,18 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) return res; } - res = dry_run ? 0 : lmx1204_reset_main_divider(st, true); - if(res) - { - USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_reset_main_divider(1) err:%d", res); - return res; - } - uint32_t regs[] = { MAKE_LMX1204_REG_WR(R90, st->logiclk_div_bypass ? 0x60 : 0x00), - //MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 + MAKE_LMX1204_R86(0), //MUXOUT_EN_OVRD=0 MAKE_LMX1204_R79(0, st->logiclk_div_bypass ? 0x104 : 0x5), - MAKE_LMX1204_REG_WR(0x4c, 0), + MAKE_LMX1204_REG_WR(0x4c, 0), //R76==0 MAKE_LMX1204_R72(0, 0, 0, 0, SYSREF_DELAY_BYPASS_ENGAGE_IN_GENERATOR_MODE__BYPASS_IN_REPEATER_MODE), // need for MULT VCO calibration MAKE_LMX1204_R67(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x51cb : 0x50c8), MAKE_LMX1204_R34(0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x04c5 : 0), - MAKE_LMX1204_R33(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? /*0x5666*/0x6666 : 0x7777), + MAKE_LMX1204_R33(st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 0x6666 : 0x7777), // MAKE_LMX1204_R25(0x4, 0, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? st->clk_mult_div : st->clk_mult_div - 1, st->clk_mux), @@ -762,29 +758,20 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) MAKE_LMX1204_R9(0, 0, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->ch_en[LMX1204_CH_LOGIC] ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), MAKE_LMX1204_R7(0, 0, 0, 0, 0, 0, 0, st->sysrefout_en[LMX1204_CH_LOGIC] ? 1 : 0), - MAKE_LMX1204_R6(st->clkout_en[LMX1204_CH_LOGIC], 0x3, 0x3, 0x3, 0x3, 0x4), + MAKE_LMX1204_R6(st->clkout_en[LMX1204_CH_LOGIC], 0x4, 0x4, 0x4, 0x4, 0x4), MAKE_LMX1204_R4(0, 0x6, 0x6, st->sysrefout_en[LMX1204_CH3], st->sysrefout_en[LMX1204_CH2], st->sysrefout_en[LMX1204_CH1], st->sysrefout_en[LMX1204_CH0], st->clkout_en[LMX1204_CH3], st->clkout_en[LMX1204_CH2], st->clkout_en[LMX1204_CH1], st->clkout_en[LMX1204_CH0]), MAKE_LMX1204_R3(st->ch_en[LMX1204_CH3], st->ch_en[LMX1204_CH2], st->ch_en[LMX1204_CH1], st->ch_en[LMX1204_CH0], 1, 1, 1, 1, 1, 0, st->smclk_div), MAKE_LMX1204_R2(0,0,st->smclk_div_pre, st->clk_mux == CLK_MUX_MULTIPLIER_MODE ? 1 : 0, 0x3), // - MAKE_LMX1204_R0(0, 0, 0, 0), //reset RESET bit last + MAKE_LMX1204_R0(0, 0, 0, 0), //reset RESET bit last -> calibration started }; res = dry_run ? common_print_registers_a8d16(regs, SIZEOF_ARRAY(regs), USDR_LOG_DEBUG) : lmx1204_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) return res; - usleep(10000); - - res = dry_run ? 0 : lmx1204_reset_main_divider(st, false); - if(res) - { - USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_reset_main_divider(0) err:%d", res); - return res; - } - return 0; } @@ -800,7 +787,7 @@ int lmx1204_calibrate(lmx1204_state_t* st) { MAKE_LMX1204_R67(0x51cb), MAKE_LMX1204_R34(0, 0x04c5), - MAKE_LMX1204_R33(0x5666), + MAKE_LMX1204_R33(0x6666), MAKE_LMX1204_R0(0, 0, 0, 0), }; @@ -834,9 +821,15 @@ int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout) const uint16_t lock_detect_status = (r75 & RB_LD_MSK) >> RB_LD_OFF; switch(lock_detect_status) { - case RB_LD_LOCKED: return 0; + case RB_LD_LOCKED: + { + uint32_t reg = MAKE_LMX1204_R2(0,0,st->smclk_div_pre, 0, 0x3); //switch off state machine to reduce spurs + lmx1204_spi_post(st, ®, 1); + USDR_LOG("1204", USDR_LOG_DEBUG, "VCO locked in %.2f msecs. State machine disabled.", (double)elapsed / 1000); + return 0; + } default: - usleep(100); + usleep(1000); elapsed += (clock_get_time() - tk); } } diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index 05cd2af5..a9e3d908 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -104,6 +104,7 @@ enum int lmx1204_read_status(lmx1204_state_t* st, lmx1204_stats_t* status); int lmx1204_calibrate(lmx1204_state_t* st); int lmx1204_wait_pll_lock(lmx1204_state_t* st, unsigned timeout); +int lmx1204_reset_main_divider(lmx1204_state_t* st, bool set_flag); int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run); int lmx1204_get_temperature(lmx1204_state_t* st, float* value); int lmx1204_reload_sysrefout_ch_delay(lmx1204_state_t* st); diff --git a/src/lib/hw/lmx1204/lmx1204_dump.h b/src/lib/hw/lmx1204/lmx1204_dump.h index b97330b5..b9300bbd 100644 --- a/src/lib/hw/lmx1204/lmx1204_dump.h +++ b/src/lib/hw/lmx1204/lmx1204_dump.h @@ -3,6 +3,49 @@ #include +static uint32_t lmx1204_rom_with_mult[] = +{ + //1GHz input, 4GHz outclk, 3.125M refclk, 125M logiclk + + /*R90*/ 0x5A0000, + /*R86*/ 0x560004, + /*R79*/ 0x4F0005, + /*R76*/ 0x4C0000, + /*R75*/ 0x4B0003, + /*R72*/ 0x480000, + /*R67*/ 0x4351CB, + /*R65*/ 0x416410, + /*R34*/ 0x220005, + /*R33*/ 0x216666, + /*R29*/ 0x1D05FF, + ///*R28*/ 0x1C0A08, + /*R25*/ 0x190223, + /*R24*/ 0x180001, + /*R23*/ 0x17E040, + /*R22*/ 0x160078, + /*R21*/ 0x150EF8, + /*R20*/ 0x140EF8, + /*R19*/ 0x130EF8, + /*R18*/ 0x120EF8, + /*R17*/ 0x110074, + /*R16*/ 0x101140, + /*R15*/ 0x0F0380, + /*R14*/ 0x0E0002, + /*R13*/ 0x0D0000, + /*R12*/ 0x0C0000, + /*R11*/ 0x0B0000, + /*R9 */ 0x090004, + /*R8 */ 0x0800B0, + /*R7 */ 0x070001, + /*R6 */ 0x06C924, + /*R5 */ 0x054936, + /*R4 */ 0x0436FF, + /*R3 */ 0x03FF85, + /*R2 */ 0x0200A3, + /*R0 */ 0x000000, +}; + + static uint32_t lmx1204_rom_test[] = { //500M inputs, 500M outclk, 3.125M refclk, 125M logiclk diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index e6e1c735..193a67fa 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -560,7 +560,7 @@ static int lmx2820_calculate_input_chain(lmx2820_state_t* st, uint64_t fosc_in, if(res) return res; - USDR_LOG("2820", USDR_LOG_WARNING, "Input circuit res: OSC_IN:%" PRIu64 " OSC_2X:%d PLL_R_PRE:%d MULT:%d PLL_R:%d FPD:%.0f PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f", + USDR_LOG("2820", USDR_LOG_INFO, "Input circuit res: OSC_IN:%" PRIu64 " OSC_2X:%d PLL_R_PRE:%d MULT:%d PLL_R:%d FPD:%.0f PLL_N:%u PLL_NUM:%u PLL_DEN:%u VCO:%.2f", settings->fosc_in, settings->osc_2x, settings->pll_r_pre, @@ -805,11 +805,11 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un lmx2820_output_chain_t * outs = &st->lmx2820_output_chain; - USDR_LOG("2820", USDR_LOG_WARNING, "***** SOLUTION *****"); - USDR_LOG("2820", USDR_LOG_WARNING, "VCO:%.2f OSC_IN:%" PRIu64 " MASH_ORDER:%u VCO_CORE%u", st->lmx2820_input_chain.fvco, osc_in, mash_order, st->lmx2820_input_chain.vco_core); - USDR_LOG("2820", USDR_LOG_WARNING, "CH_A - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfouta, outs->chdiva - 1, (1 << outs->chdiva), + USDR_LOG("2820", USDR_LOG_INFO, "***** SOLUTION *****"); + USDR_LOG("2820", USDR_LOG_INFO, "VCO:%.2f OSC_IN:%" PRIu64 " MASH_ORDER:%u VCO_CORE%u", st->lmx2820_input_chain.fvco, osc_in, mash_order, st->lmx2820_input_chain.vco_core); + USDR_LOG("2820", USDR_LOG_INFO, "CH_A - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfouta, outs->chdiva - 1, (1 << outs->chdiva), outs->outa_mux == OUTA_MUX_VCO_DOUBLER ? "OUTA_MUX_VCO_DOUBLER" : (outs->outa_mux == OUTA_MUX_VCO ? "OUTA_MUX_VCO": "OUTA_MUX_CHANNEL_DIVIDER")); - USDR_LOG("2820", USDR_LOG_WARNING, "CH_B - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfoutb, outs->chdivb - 1, (1 << outs->chdivb), + USDR_LOG("2820", USDR_LOG_INFO, "CH_B - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfoutb, outs->chdivb - 1, (1 << outs->chdivb), outs->outb_mux == OUTB_MUX_VCO_DOUBLER ? "OUTB_MUX_VCO_DOUBLER" : (outs->outb_mux == OUTB_MUX_VCO ? "OUTB_MUX_VCO": "OUTB_MUX_CHANNEL_DIVIDER")); return 0; @@ -864,11 +864,11 @@ int lmx2820_solver_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb lmx2820_output_chain_t * outs = &st->lmx2820_output_chain; - USDR_LOG("2820", USDR_LOG_WARNING, "***** INSTCAL SOLUTION *****"); - USDR_LOG("2820", USDR_LOG_WARNING, "VCO:%.2f", st->lmx2820_input_chain.fvco); - USDR_LOG("2820", USDR_LOG_WARNING, "CH_A - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfouta, outs->chdiva - 1, (1 << outs->chdiva), + USDR_LOG("2820", USDR_LOG_INFO, "***** INSTCAL SOLUTION *****"); + USDR_LOG("2820", USDR_LOG_INFO, "VCO:%.2f", st->lmx2820_input_chain.fvco); + USDR_LOG("2820", USDR_LOG_INFO, "CH_A - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfouta, outs->chdiva - 1, (1 << outs->chdiva), outs->outa_mux == OUTA_MUX_VCO_DOUBLER ? "OUTA_MUX_VCO_DOUBLER" : (outs->outa_mux == OUTA_MUX_VCO ? "OUTA_MUX_VCO": "OUTA_MUX_CHANNEL_DIVIDER")); - USDR_LOG("2820", USDR_LOG_WARNING, "CH_B - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfoutb, outs->chdivb - 1, (1 << outs->chdivb), + USDR_LOG("2820", USDR_LOG_INFO, "CH_B - RF:%.2f DIV:%u(%u) MUX:%s", outs->rfoutb, outs->chdivb - 1, (1 << outs->chdivb), outs->outb_mux == OUTB_MUX_VCO_DOUBLER ? "OUTB_MUX_VCO_DOUBLER" : (outs->outb_mux == OUTB_MUX_VCO ? "OUTB_MUX_VCO": "OUTB_MUX_CHANNEL_DIVIDER")); return 0; @@ -972,7 +972,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned return res; } - res = lmx2820_wait_pll_lock(st, 100000); + res = lmx2820_wait_pll_lock(st, 1000000); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_wait_pll_lock() failed, err:%d [%s]", From db69a4c5cb602ccb1dadcb83fd52f978fcc6b3b3 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 4 May 2025 14:11:56 +0300 Subject: [PATCH 123/397] LMX2820 SYSREF added (not tested) --- src/lib/hw/lmx2820/lmx2820.c | 220 ++++++++++++++++++++++++++++++- src/lib/hw/lmx2820/lmx2820.h | 27 ++++ src/utests/lmx2820_solver_test.c | 12 +- src/utests/test_suite.c | 2 +- 4 files changed, 254 insertions(+), 7 deletions(-) diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 193a67fa..08558513 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -46,6 +46,18 @@ enum { OUT_DIV_LOG2_MIN = 1, OUT_DIV_LOG2_MAX = 7, + + SYSREF_DIV_PRE_MIN = 2, + SYSREF_DIV_PRE_MID = 4, + SYSREF_DIV_PRE_MAX = 8, + SYSREF_DIV_MIN = 2, + SYSREF_DIV_MAX = 2049, + SYSREF_FINTERPOLATOR_MIN = 600000000ull, + SYSREF_FINTERPOLATOR_MAX = 1500000000ull, + SYSREF_PULSE_CNT_MIN = 1, + SYSREF_PULSE_CNT_MAX = 15, + SYSREF_DELAY_CTRL_MIN = 0, + SYSREF_DELAY_CTRL_MAX = 251, }; #define RF_ACCURACY 0.0f @@ -88,6 +100,57 @@ static uint64_t FPD_MAX[MASH_ORDER_THIRD_ORDER + 1] = #define INSTCAL_R0_MASK (((uint16_t)1 << FCAL_EN_OFF) | ((uint16_t)1 << DBLR_CAL_EN_OFF) | ((uint16_t)1 << INSTCAL_SKIP_ACAL_OFF)) +struct jesd_flds +{ + uint8_t DAC1_CTRL; + uint8_t DAC2_CTRL; + uint8_t DAC3_CTRL; + uint8_t DAC4_CTRL; +}; + +#define JESD_SIZE 252 +static struct jesd_flds JESD[JESD_SIZE]; + +static void lmx2820_fill_jesd() +{ + JESD[0].DAC1_CTRL = 63; + JESD[0].DAC2_CTRL = 0; + JESD[0].DAC3_CTRL = 0; + JESD[0].DAC4_CTRL = 0; + + for(uint8_t i = 1; i < JESD_SIZE; ++i) + { + if(i < 64) + { + JESD[i].DAC1_CTRL = JESD[i - 1].DAC1_CTRL - 1; + JESD[i].DAC2_CTRL = JESD[i - 1].DAC2_CTRL + 1; + JESD[i].DAC3_CTRL = 0; + JESD[i].DAC4_CTRL = 0; + } + else if(i < 127) + { + JESD[i].DAC1_CTRL = 0; + JESD[i].DAC2_CTRL = JESD[i - 1].DAC2_CTRL - 1; + JESD[i].DAC3_CTRL = JESD[i - 1].DAC3_CTRL + 1; + JESD[i].DAC4_CTRL = 0; + } + else if(i < 190) + { + JESD[i].DAC1_CTRL = 0; + JESD[i].DAC2_CTRL = 0; + JESD[i].DAC3_CTRL = JESD[i - 1].DAC3_CTRL - 1; + JESD[i].DAC4_CTRL = JESD[i - 1].DAC4_CTRL + 1; + } + else + { + JESD[i].DAC1_CTRL = JESD[i - 1].DAC1_CTRL + 1; + JESD[i].DAC2_CTRL = 0; + JESD[i].DAC3_CTRL = 0; + JESD[i].DAC4_CTRL = JESD[i - 1].DAC4_CTRL - 1; + } + } +} + static int lmx2820_spi_post(lmx2820_state_t* obj, uint32_t* regs, unsigned count) { return @@ -755,6 +818,103 @@ static int lmx2820_solver_validate_and_save(lmx2820_state_t* st, uint64_t rfouta return 0; } +static int lmx2820_calculate_systef_chain(lmx2820_state_t* st) +{ + if(!st->lmx2820_sysref_chain.enabled) + { + USDR_LOG("2820", USDR_LOG_INFO, "SYSREF disabled, skipping setup"); + return 0; + } + + lmx2820_sysref_chain_t* sr = &st->lmx2820_sysref_chain; + + if(sr->master_mode == false) + { + switch(sr->srreq_fmt) + { + case SRREQ_CMOS: sr->srreq_fmt = SYSREF_INP_FMT_CMOS_INPUT_AT_SRREQ_P_PIN__1_8_V_TO_3_3_V_LOGIC; break; + case SRREQ_CMOS_AC: sr->srreq_fmt = SYSREF_INP_FMT_AC_COUPLE_CMOS_INPUT_AT_SRREQ_P_PIN; break; + case SRREQ_LVDS_AC: sr->srreq_fmt = SYSREF_INP_FMT_AC_COUPLED_DIFFERENTIAL_LVDS_INPUT__REQUIRES_EXTERNAL_100_OHM_DIFFERENTIAL_TERMINATION; break; + case SRREQ_LVDS_DC: sr->srreq_fmt = SYSREF_INP_FMT_DC_COUPLED_DIFFERENTIAL_LVDS_INPUT__REQUIRES_EXTERNAL_100_OHM_DIFFERENTIAL_TERMINATION; break; + default: + { + USDR_LOG("2820", USDR_LOG_ERROR, "[SYSREF] Invalid SRREG_FMT:%u", sr->srreq_fmt); + return -EINVAL; + } + } + } + + if(sr->cont_pulse == false && (sr->pulse_cnt < SYSREF_PULSE_CNT_MIN || sr->pulse_cnt > SYSREF_PULSE_CNT_MAX)) + { + USDR_LOG("2820", USDR_LOG_ERROR, "[SYSREF] PULSE_CNT:%u out of range [%u;%u]", + sr->pulse_cnt, (int)SYSREF_PULSE_CNT_MIN, (int)SYSREF_PULSE_CNT_MAX); + return -EINVAL; + } + + if(sr->delay_ctrl < SYSREF_DELAY_CTRL_MIN || sr->delay_ctrl > SYSREF_DELAY_CTRL_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "[SYSREF] DELAY_CTRL:%u out of range [%u;%u]", + sr->delay_ctrl, (int)SYSREF_DELAY_CTRL_MIN, (int)SYSREF_DELAY_CTRL_MAX); + return -EINVAL; + } + + const double fvco = st->lmx2820_input_chain.fvco; + + bool found = false; + double finterpolator; + for(uint8_t i = 3; i > 0; --i) + { + finterpolator = fvco / (1 << i); + if(finterpolator >= SYSREF_FINTERPOLATOR_MIN && finterpolator <= SYSREF_FINTERPOLATOR_MAX) + { + sr->div_pre = 1 << i; + found = true; + break; + } + } + + if(!found) + { + USDR_LOG("2820", USDR_LOG_ERROR, "[SYSREF] Cannot obtain Finterpolator:[%u;%u] having VCO:%.2f", + (unsigned)SYSREF_FINTERPOLATOR_MIN, (unsigned)SYSREF_FINTERPOLATOR_MAX, fvco); + return -EINVAL; + } + + double fdiv = finterpolator / 4; + unsigned div = (unsigned)(fdiv / sr->srout + 0.5f); + if(div < SYSREF_DIV_MIN || div > SYSREF_DIV_MAX) + { + USDR_LOG("2820", USDR_LOG_ERROR, "[SYSREF] Cannot obtain SROUT:%" PRIu64 " using SYSREF_DIV:[%u;%u]", + sr->srout, (int)SYSREF_DIV_MIN, (int)SYSREF_DIV_MAX); + return -EINVAL; + } + sr->div = div; + sr->srout_fact = fvco / sr->div_pre / sr->div / 4; + + lmx2820_fill_jesd(); + /* + for(unsigned i = 0; i < JESD_SIZE; ++i) + { + USDR_LOG("2820", USDR_LOG_DEBUG, "PHASE_SHIFT:%03u -> DAC1_CTRL:%02u DAC2_CTRL:%02u DAC3_CTRL:%02u DAC4_CTRL:%02u", + i, JESD[i].DAC1_CTRL, JESD[i].DAC2_CTRL, JESD[i].DAC3_CTRL, JESD[i].DAC4_CTRL); + } + */ + double delay_per_inc = (double)sr->div_pre / 126.0 / fvco; + sr->delay = delay_per_inc * (sr->delay_ctrl + 1); + + USDR_LOG("2820", USDR_LOG_INFO, "[SYSREF] SROUT:%" PRIu64 " VCO:%.4f DIV_PRE:%u DIV:%u SROUT_FACT:%.4f DELAY_PER_INC:%.2fps DELAY:%.2fps", + sr->srout, fvco, sr->div_pre, sr->div, sr->srout_fact, + delay_per_inc * 1E12, sr->delay * 1E12); + + if((double)sr->srout != sr->srout_fact) + { + USDR_LOG("2820", USDR_LOG_WARNING, "[SYSREF] SROUT_FACT=%.4f differs from required SROUT, delta:%.4f", + sr->srout_fact, fabs((double)sr->srout - sr->srout_fact)); + } + + return 0; +} + int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb) { int res = 0; @@ -799,6 +959,10 @@ int lmx2820_solver(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, un if(res) return res; + res = lmx2820_calculate_systef_chain(st); + if(res) + return res; + res = lmx2820_solver_validate_and_save(st, rfouta, rfoutb, diva, divb, muxa, muxb); if(res) return res; @@ -874,6 +1038,18 @@ int lmx2820_solver_instcal(lmx2820_state_t* st, uint64_t rfouta, uint64_t rfoutb return 0; } +static uint8_t lmx2820_encode_sysref_prediv(lmx2820_state_t* st) +{ + switch(st->lmx2820_sysref_chain.div_pre) + { + case SYSREF_DIV_PRE_MAX: return 4; + case SYSREF_DIV_PRE_MID: return 2; + case SYSREF_DIV_PRE_MIN: return 1; + } + USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_encode_sysref_prediv() unsupported value!"); + return 0; +} + static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned mash_order, unsigned force_mult, uint64_t rfouta, uint64_t rfoutb, bool use_instcal) { int res = lmx2820_solver(st, osc_in, mash_order, force_mult, rfouta, rfoutb); @@ -930,10 +1106,45 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned USDR_LOG("2820", USDR_LOG_DEBUG, "REGS> LP_FD_ADJ:%d HP_FD_ADJ:%d CAL_CLK_DIV:%d INSTCAL_DLY:%d INSTCAL_PLL_NUM:%u INSTCAL_DBLR_EN:%d", LP_fd_adj, HP_fd_adj, cal_clk_div, instcal_dly, instcal_pll_num, instcal_dblr_en); + const lmx2820_sysref_chain_t* sr = &st->lmx2820_sysref_chain; + uint32_t regs[] = { MAKE_LMX2820_R79(0, OUTB_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outb_mux, 0x7, 0), MAKE_LMX2820_R78(0, OUTA_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outa_mux), + MAKE_LMX2820_R69(0, sr->enabled ? SROUT_PD_NORMAL_OPERATION : SROUT_PD_POWER_DOWN, 1), + + sr->enabled ? + MAKE_LMX2820_R67(sr->cont_pulse ? 0 : sr->pulse_cnt, + JESD[sr->delay_ctrl].DAC4_CTRL, + JESD[sr->delay_ctrl].DAC3_CTRL) + : + MAKE_LMX2820_R67(0,0,0), //default + + sr->enabled ? + MAKE_LMX2820_R66(0x0, + JESD[sr->delay_ctrl].DAC2_CTRL, + JESD[sr->delay_ctrl].DAC1_CTRL) + : + MAKE_LMX2820_R66(0,0,0x3F), //default + + sr->enabled ? + MAKE_LMX2820_R65(0x0, sr->div - 2) + : + MAKE_LMX2820_R65(0,1), //default + + sr->enabled ? + MAKE_LMX2820_R64(0x10, + sr->master_mode ? 0 : sr->srreq_fmt, + lmx2820_encode_sysref_prediv(st), + 0, /*sysref_repeat_ns*/ + sr->cont_pulse ? 0 : 1, + 1, /*sysref enabled*/ + sr->master_mode ? 0 : 1, + 0x0) + : + MAKE_LMX2820_R64(0x10, 0, 0x4, 0, 0, 0/*sysref disabled*/, 0, 0x0), //default + MAKE_LMX2820_R45((uint16_t)instcal_pll_num), MAKE_LMX2820_R44((uint16_t)(instcal_pll_num >> 16)), MAKE_LMX2820_R43((uint16_t)st->lmx2820_input_chain.pll_num), @@ -949,9 +1160,12 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R12(0, st->lmx2820_input_chain.mult, 0x8), MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x3), MAKE_LMX2820_R2 (1, cal_clk_div, instcal_dly, QUICK_RECAL_EN_DISABLED), - MAKE_LMX2820_R1 (PHASE_SYNC_EN_NORMAL_OPERATION, 0x15E, LD_VTUNE_EN_VCOCAL_AND_VTUNE_LOCK_DETECT, 0, - instcal_dblr_en, - use_instcal ? INSTCAL_EN_ENABLED : INSTCAL_EN_DISABLED), + MAKE_LMX2820_R1 (sr->enabled ? PHASE_SYNC_EN_PHASE_SYNCHRONIZATION_ENABLED : PHASE_SYNC_EN_NORMAL_OPERATION, + 0x15E, + LD_VTUNE_EN_VCOCAL_AND_VTUNE_LOCK_DETECT, + 0, + instcal_dblr_en, + use_instcal ? INSTCAL_EN_ENABLED : INSTCAL_EN_DISABLED), MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_DISABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) }; diff --git a/src/lib/hw/lmx2820/lmx2820.h b/src/lib/hw/lmx2820/lmx2820.h index 419b78b0..aa1345ac 100644 --- a/src/lib/hw/lmx2820/lmx2820.h +++ b/src/lib/hw/lmx2820/lmx2820.h @@ -31,6 +31,32 @@ struct lmx2820_output_chain_st }; typedef struct lmx2820_output_chain_st lmx2820_output_chain_t; +enum lmx2820_sysref_in_fmt +{ + SRREQ_CMOS = 0, + SRREQ_CMOS_AC = 1, + SRREQ_LVDS_AC = 2, + SRREQ_LVDS_DC = 3, +}; +typedef enum lmx2820_sysref_in_fmt lmx2820_sysref_in_fmt_t; + +struct lmx2820_sysref_chain_st +{ + uint64_t srout; + bool enabled; + bool master_mode; //true:master mode, false:repeater mode + bool cont_pulse; //true:continious, false:pulsed + uint8_t pulse_cnt; + uint8_t delay_ctrl; + double delay; + uint8_t div_pre; + uint16_t div; + double srout_fact; + // + uint8_t srreq_fmt; +}; +typedef struct lmx2820_sysref_chain_st lmx2820_sysref_chain_t; + struct lmx2820_stats { float temperature; uint16_t vco_sel; @@ -48,6 +74,7 @@ struct lmx2820_state { uint16_t instcal_dly; lmx2820_input_chain_t lmx2820_input_chain; lmx2820_output_chain_t lmx2820_output_chain; + lmx2820_sysref_chain_t lmx2820_sysref_chain; }; typedef struct lmx2820_state lmx2820_state_t; diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index 071319d6..e636c599 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -161,8 +161,13 @@ START_TEST(lmx2820_solver_test14_pesync) { const uint64_t osc_in = 250000000ull; const int mash_order = 2; - uint64_t out_freq1 = 1400000000ull; - uint64_t out_freq2 = 175000000; //1400000000ull; + uint64_t out_freq1 = 4000000000ull; + uint64_t out_freq2 = 4000000000ull; + + st.lmx2820_sysref_chain.enabled = true; + st.lmx2820_sysref_chain.srout = 25000000; + st.lmx2820_sysref_chain.master_mode = true; + st.lmx2820_sysref_chain.cont_pulse = true; int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); @@ -178,7 +183,7 @@ Suite * lmx2820_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - +/* tcase_add_test(tc_core, lmx2820_solver_test1); tcase_add_test(tc_core, lmx2820_solver_test2); tcase_add_test(tc_core, lmx2820_solver_test3); @@ -192,6 +197,7 @@ Suite * lmx2820_solver_suite(void) tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 1, 4); tcase_add_test(tc_core, lmx2820_solver_test12_instcal); tcase_add_test(tc_core, lmx2820_solver_test13_pesync); +*/ tcase_add_test(tc_core, lmx2820_solver_test14_pesync); suite_add_tcase(s, tc_core); diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index a189e1ab..b5239091 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -38,7 +38,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, lmx1214_solver_suite()); srunner_add_suite(sr, lmx1204_solver_suite()); #else - sr = srunner_create(lmx1204_solver_suite()); + sr = srunner_create(lmx2820_solver_suite()); #endif srunner_set_fork_status (sr, CK_NOFORK); From 56ebff43b3fc62c9e1e0a71bef2045be745db85a Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 5 May 2025 20:43:00 +0300 Subject: [PATCH 124/397] LMX2820@PESync SYSREF implementation --- src/lib/device/pe_sync/pe_sync.c | 25 +++++++++++--- src/lib/hw/lmx2820/lmx2820.c | 16 +++++---- src/lib/hw/lmx2820/lmx2820_dump.h | 56 +++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 20d9af34..57c2dd7d 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -384,11 +384,20 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const const uint64_t lmx0_freq[] = { - 500000000*2, //1400000000, - 500000000*2, //1400000000 + 500000000*2, //1400000000, //OUT_A + 500000000*2, //1400000000 //OUT_B + 25000000, //SR_OUT }; res = lmx2820_create(dev, 0, SPI_LMX2820_0, &d->lmx0); + + lmx2820_sysref_chain_t* lmx0_sr = &d->lmx0.lmx2820_sysref_chain; + lmx0_sr->enabled = false; + lmx0_sr->master_mode = true; + lmx0_sr->cont_pulse = true; + lmx0_sr->srout = lmx0_freq[2]; + lmx0_sr->delay_ctrl = 0;//60; + res = res ? res : lmx2820_tune(&d->lmx0, lmk_freq[2], 2 /*mash order 2*/, 0 /*force_mult*/, lmx0_freq[0], lmx0_freq[1]); lmx2820_stats_t lmxstatus0; @@ -414,6 +423,14 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const }; res = lmx2820_create(dev, 0, SPI_LMX2820_1, &d->lmx1); + + lmx2820_sysref_chain_t* lmx1_sr = &d->lmx1.lmx2820_sysref_chain; + lmx1_sr->enabled = false; + lmx1_sr->master_mode = true; + lmx1_sr->cont_pulse = true; + lmx1_sr->srout = 25000000; + lmx1_sr->delay_ctrl = 0;//60; + res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], 2 /*mash order 2*/, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); lmx2820_stats_t lmxstatus1; @@ -468,8 +485,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const //set 1204 params lmx1204_state_t* lmx1204 = &d->cldistr; - lmx1204->clkin = lmx0_freq[0]; - lmx1204->sysrefreq = lmx0_freq[1]; + lmx1204->clkin = lmx0_freq[1]; //LMX0 OUT_B + lmx1204->sysrefreq = lmx0_freq[2]; //LMX0 SR_OUT lmx1204->clkout = d->cldistr.clkin * 4; lmx1204->sysrefout = 3125000; lmx1204->sysref_mode = LMX1204_CONTINUOUS; diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 08558513..703577e5 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -342,7 +342,7 @@ int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status) UNUSED static int lmx2820_loaddump(lmx2820_state_t* st) { - int res = lmx2820_spi_post(st, lmx2820_rom_test, SIZEOF_ARRAY(lmx2820_rom_test)); + int res = lmx2820_spi_post(st, lmx2820_rom_sysref, SIZEOF_ARRAY(lmx2820_rom_sysref)); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_loaddump() err:%d", res); @@ -900,7 +900,7 @@ static int lmx2820_calculate_systef_chain(lmx2820_state_t* st) } */ double delay_per_inc = (double)sr->div_pre / 126.0 / fvco; - sr->delay = delay_per_inc * (sr->delay_ctrl + 1); + sr->delay = delay_per_inc * sr->delay_ctrl; USDR_LOG("2820", USDR_LOG_INFO, "[SYSREF] SROUT:%" PRIu64 " VCO:%.4f DIV_PRE:%u DIV:%u SROUT_FACT:%.4f DELAY_PER_INC:%.2fps DELAY:%.2fps", sr->srout, fvco, sr->div_pre, sr->div, sr->srout_fact, @@ -1115,7 +1115,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R69(0, sr->enabled ? SROUT_PD_NORMAL_OPERATION : SROUT_PD_POWER_DOWN, 1), sr->enabled ? - MAKE_LMX2820_R67(sr->cont_pulse ? 0 : sr->pulse_cnt, + MAKE_LMX2820_R67(sr->cont_pulse ? 1 : sr->pulse_cnt, JESD[sr->delay_ctrl].DAC4_CTRL, JESD[sr->delay_ctrl].DAC3_CTRL) : @@ -1134,8 +1134,8 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R65(0,1), //default sr->enabled ? - MAKE_LMX2820_R64(0x10, - sr->master_mode ? 0 : sr->srreq_fmt, + MAKE_LMX2820_R64(0x00, //0x10 by doc + sr->master_mode ? 0x2 : sr->srreq_fmt, lmx2820_encode_sysref_prediv(st), 0, /*sysref_repeat_ns*/ sr->cont_pulse ? 0 : 1, @@ -1158,7 +1158,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R14(0x3, st->lmx2820_input_chain.pll_r_pre), MAKE_LMX2820_R13(0, st->lmx2820_input_chain.pll_r, 0x18), MAKE_LMX2820_R12(0, st->lmx2820_input_chain.mult, 0x8), - MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x3), + MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x2), //0x3 by doc MAKE_LMX2820_R2 (1, cal_clk_div, instcal_dly, QUICK_RECAL_EN_DISABLED), MAKE_LMX2820_R1 (sr->enabled ? PHASE_SYNC_EN_PHASE_SYNCHRONIZATION_ENABLED : PHASE_SYNC_EN_NORMAL_OPERATION, 0x15E, @@ -1169,12 +1169,16 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_DISABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) }; +#if 1 res = lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); return res; } +#else + lmx2820_loaddump(st); +#endif //Wait 10 ms to allow the internal LDOs to power up. usleep(10000); diff --git a/src/lib/hw/lmx2820/lmx2820_dump.h b/src/lib/hw/lmx2820/lmx2820_dump.h index 793d7d1d..4e00faa4 100644 --- a/src/lib/hw/lmx2820/lmx2820_dump.h +++ b/src/lib/hw/lmx2820/lmx2820_dump.h @@ -3,6 +3,62 @@ #include +static uint32_t lmx2820_rom_sysref[] = +{ + /*R79 */ 0x4F000E, + /*R78 */ 0x4E0000, + /*R69 */ 0x450001, + /*R67 */ 0x431000, + /*R66 */ 0x42003F, + /*R65 */ 0x410008, + /*R64 */ 0x400284, + /*R45 */ 0x2D0000, + /*R44 */ 0x2C0000, + /*R43 */ 0x2B0000, + /*R42 */ 0x2A0000, + /*R39 */ 0x270002, /*****/ + /*R38 */ 0x260000, + /*R36 */ 0x240020, + /*R35 */ 0x233100, + /*R32 */ 0x2016C1, + /*R22 */ 0x16E2BF, /*****/ + /*R14 */ 0x0E3001, + /*R13 */ 0x0D0038, + /*R12 */ 0x0C0408, + /*R11 */ 0x0B0602, + /*R2 */ 0x0293E8, + /*R1 */ 0x01D7A0, + /*R0 */ 0x006630, /****/ +}; + +/* +21:21:14.518863 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#0: R079 (0x4f) -> 0x000e [0x4f000e] +21:21:14.518874 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#1: R078 (0x4e) -> 0x0000 [0x4e0000] +21:21:14.518881 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#2: R069 (0x45) -> 0x0001 [0x450001] +21:21:14.518888 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#3: R067 (0x43) -> 0x1000 [0x431000] +21:21:14.518897 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#4: R066 (0x42) -> 0x003f [0x42003f] +21:21:14.518904 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#5: R065 (0x41) -> 0x0008 [0x410008] +21:21:14.518914 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#6: R064 (0x40) -> 0x0284 [0x400284] +21:21:14.518923 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#7: R045 (0x2d) -> 0x0000 [0x2d0000] +21:21:14.518928 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#8: R044 (0x2c) -> 0x0000 [0x2c0000] +21:21:14.518935 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#9: R043 (0x2b) -> 0x0000 [0x2b0000] +21:21:14.518941 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#10: R042 (0x2a) -> 0x0000 [0x2a0000] +21:21:14.518948 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#11: R039 (0x27) -> 0x0001 [0x270001] +21:21:14.518955 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#12: R038 (0x26) -> 0x0000 [0x260000] +21:21:14.518962 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#13: R036 (0x24) -> 0x0020 [0x240020] +21:21:14.518969 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#14: R035 (0x23) -> 0x3100 [0x233100] +21:21:14.518978 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#15: R032 (0x20) -> 0x16c1 [0x2016c1] +21:21:14.518983 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#16: R022 (0x16) -> 0x62bf [0x1662bf] +21:21:14.519004 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#17: R014 (0x0e) -> 0x3001 [0x0e3001] +21:21:14.519020 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#18: R013 (0x0d) -> 0x0038 [0x0d0038] +21:21:14.519031 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#19: R012 (0x0c) -> 0x0408 [0x0c0408] +21:21:14.519040 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#20: R011 (0x0b) -> 0x0602 [0x0b0602] +21:21:14.519052 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#21: R002 (0x02) -> 0x93e8 [0x0293e8] +21:21:14.519062 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#22: R001 (0x01) -> 0xd7a0 [0x01d7a0] +21:21:14.519072 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#23: R000 (0x00) -> 0x6660 [0x006660] +*/ + + static uint32_t lmx2820_rom_test[] = { /*R122*/ 0x7A0000, From 60b22bd936c0d7eccda6f84fc9586b10c10a2e3b Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 6 May 2025 14:30:40 +0300 Subject: [PATCH 125/397] fix in LMX2820 solver for SROUT. SROUT still not working --- src/lib/device/pe_sync/pe_sync.c | 4 +- src/lib/hw/lmx2820/lmx2820.c | 21 +++-- src/lib/hw/lmx2820/lmx2820_dump.h | 148 ++++++++++++++++++++++-------- 3 files changed, 128 insertions(+), 45 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 57c2dd7d..7e7e596e 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -310,8 +310,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const { 125000000, 125000000, - 250000000, - 250000000, + 150000000, + 150000000, 156250000, 156250000, 10000000, diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 703577e5..69756e4d 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -19,6 +19,7 @@ enum { OSC_IN_MIN = 5000000ull, OSC_IN_MAX = 1400000000ull, OSC_IN_MAX_DBLR = 250000000ull, + OSC_IN_MAX_SYNC = 200000000ull, OUT_FREQ_MIN = 45000000ull, OUT_FREQ_MAX = 22600000000ull, @@ -828,6 +829,13 @@ static int lmx2820_calculate_systef_chain(lmx2820_state_t* st) lmx2820_sysref_chain_t* sr = &st->lmx2820_sysref_chain; + if(st->lmx2820_input_chain.fosc_in > OSC_IN_MAX_SYNC) + { + USDR_LOG("2820", USDR_LOG_ERROR, "[SYSREF] OSC_IN:%" PRIu64" is too high (>%" PRIu64 ")", + st->lmx2820_input_chain.fosc_in, (uint64_t)OSC_IN_MAX_SYNC); + return -EINVAL; + } + if(sr->master_mode == false) { switch(sr->srreq_fmt) @@ -1113,6 +1121,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R79(0, OUTB_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outb_mux, 0x7, 0), MAKE_LMX2820_R78(0, OUTA_PD_NORMAL_OPERATION, 0, st->lmx2820_output_chain.outa_mux), MAKE_LMX2820_R69(0, sr->enabled ? SROUT_PD_NORMAL_OPERATION : SROUT_PD_POWER_DOWN, 1), + MAKE_LMX2820_R68(0, 0/*psync pin ignore*/, 0, 0), sr->enabled ? MAKE_LMX2820_R67(sr->cont_pulse ? 1 : sr->pulse_cnt, @@ -1158,7 +1167,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R14(0x3, st->lmx2820_input_chain.pll_r_pre), MAKE_LMX2820_R13(0, st->lmx2820_input_chain.pll_r, 0x18), MAKE_LMX2820_R12(0, st->lmx2820_input_chain.mult, 0x8), - MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x2), //0x3 by doc + MAKE_LMX2820_R11(0x30, st->lmx2820_input_chain.osc_2x ? 1 : 0, 0x3), //0x3 by doc MAKE_LMX2820_R2 (1, cal_clk_div, instcal_dly, QUICK_RECAL_EN_DISABLED), MAKE_LMX2820_R1 (sr->enabled ? PHASE_SYNC_EN_PHASE_SYNCHRONIZATION_ENABLED : PHASE_SYNC_EN_NORMAL_OPERATION, 0x15E, @@ -1166,7 +1175,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned 0, instcal_dblr_en, use_instcal ? INSTCAL_EN_ENABLED : INSTCAL_EN_DISABLED), - MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_DISABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) + MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_ENABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) }; #if 1 @@ -1182,14 +1191,14 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned //Wait 10 ms to allow the internal LDOs to power up. usleep(10000); - +/* res = lmx2820_calibrate(st, true); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_calibrate(1) failed, err:%d", res); return res; } - +*/ res = lmx2820_wait_pll_lock(st, 1000000); if(res) { @@ -1197,14 +1206,14 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned res, (res == -ETIMEDOUT ? "TIMEOUT" : "ERROR")); return res; } - +/* res = lmx2820_sync(st); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_sync() failed, err:%d", res); return res; } - +*/ if(use_instcal) { res = lmx2820_calibrate(st, false); diff --git a/src/lib/hw/lmx2820/lmx2820_dump.h b/src/lib/hw/lmx2820/lmx2820_dump.h index 4e00faa4..1054a771 100644 --- a/src/lib/hw/lmx2820/lmx2820_dump.h +++ b/src/lib/hw/lmx2820/lmx2820_dump.h @@ -5,59 +5,133 @@ static uint32_t lmx2820_rom_sysref[] = { + // osc_in = 150M out_a = out_b = 1G sr_out = 25M + // + /*R122*/ 0x7A0000, + /*R121*/ 0x790000, + /*R120*/ 0x780000, + /*R119*/ 0x770000, + /*R118*/ 0x760000, + /*R117*/ 0x750000, + /*R116*/ 0x740000, + /*R115*/ 0x730000, + /*R114*/ 0x720000, + /*R113*/ 0x710000, + /*R112*/ 0x70FFFF, + /*R111*/ 0x6F0000, + /*R110*/ 0x6E001F, + /*R109*/ 0x6D0000, + /*R108*/ 0x6C0000, + /*R107*/ 0x6B0000, + /*R106*/ 0x6A0000, + /*R105*/ 0x69000A, + /*R104*/ 0x680014, + /*R103*/ 0x670014, + /*R102*/ 0x660028, + /*R101*/ 0x6503E8, + /*R100*/ 0x640533, + /*R99 */ 0x6319B9, + /*R98 */ 0x621C80, + /*R97 */ 0x610000, + /*R96 */ 0x6017F8, + /*R95 */ 0x5F0000, + /*R94 */ 0x5E0000, + /*R93 */ 0x5D1000, + /*R92 */ 0x5C0000, + /*R91 */ 0x5B0000, + /*R90 */ 0x5A0000, + /*R89 */ 0x590000, + /*R88 */ 0x5803FF, + /*R87 */ 0x57FF00, + /*R86 */ 0x560040, + /*R85 */ 0x550000, + /*R84 */ 0x540040, + /*R83 */ 0x530F00, + /*R82 */ 0x520000, + /*R81 */ 0x510000, + /*R80 */ 0x5001C0, /*R79 */ 0x4F000E, /*R78 */ 0x4E0000, + /*R77 */ 0x4D0608, + /*R76 */ 0x4C0000, + /*R75 */ 0x4B0000, + /*R74 */ 0x4A0000, + /*R73 */ 0x490000, + /*R72 */ 0x480000, + /*R71 */ 0x470000, + /*R70 */ 0x46000E, /*R69 */ 0x450001, + /*R68 */ 0x440000, /*R67 */ 0x431000, /*R66 */ 0x42003F, /*R65 */ 0x410008, /*R64 */ 0x400284, + /*R63 */ 0x3FC350, + /*R62 */ 0x3E0000, + /*R61 */ 0x3D03E8, + /*R60 */ 0x3C01F4, + /*R59 */ 0x3B1388, + /*R58 */ 0x3A0000, + /*R57 */ 0x390001, + /*R56 */ 0x380001, + /*R55 */ 0x370002, + /*R54 */ 0x360000, + /*R53 */ 0x350000, + /*R52 */ 0x340000, + /*R51 */ 0x33203F, + /*R50 */ 0x320080, + /*R49 */ 0x310000, + /*R48 */ 0x304180, + /*R47 */ 0x2F0300, + /*R46 */ 0x2E0300, /*R45 */ 0x2D0000, - /*R44 */ 0x2C0000, - /*R43 */ 0x2B0000, + /*R44 */ 0x2C8000, + /*R43 */ 0x2B0002, /*R42 */ 0x2A0000, - /*R39 */ 0x270002, /*****/ + /*R41 */ 0x290000, + /*R40 */ 0x280000, + /*R39 */ 0x270003, /*R38 */ 0x260000, - /*R36 */ 0x240020, + /*R37 */ 0x250500, + /*R36 */ 0x24001A, /*R35 */ 0x233100, - /*R32 */ 0x2016C1, - /*R22 */ 0x16E2BF, /*****/ + /*R34 */ 0x220010, + /*R33 */ 0x210000, + /*R32 */ 0x201481, + /*R31 */ 0x1F0401, + /*R30 */ 0x1EB18C, + /*R29 */ 0x1D318C, + /*R28 */ 0x1C0639, + /*R27 */ 0x1B8001, + /*R26 */ 0x1A0DB0, + /*R25 */ 0x190624, + /*R24 */ 0x180E34, + /*R23 */ 0x171102, + /*R22 */ 0x16E2BF, + /*R21 */ 0x151C64, + /*R20 */ 0x14272C, + /*R19 */ 0x132120, + /*R18 */ 0x120000, + /*R17 */ 0x1115C0, + /*R16 */ 0x10171C, + /*R15 */ 0x0F2001, /*R14 */ 0x0E3001, /*R13 */ 0x0D0038, /*R12 */ 0x0C0408, - /*R11 */ 0x0B0602, - /*R2 */ 0x0293E8, - /*R1 */ 0x01D7A0, - /*R0 */ 0x006630, /****/ + /*R11 */ 0x0B0612, + /*R10 */ 0x0A0000, + /*R9 */0x090005, + /*R8 */0x08C802, + /*R7 */0x070000, + /*R6 */0x060A43, + /*R5 */0x050032, + /*R4 */0x044204, + /*R3 */0x030041, + /*R2 */0x0283E8, + /*R1 */0x01D7A0, + /*R0 */0x006630, }; -/* -21:21:14.518863 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#0: R079 (0x4f) -> 0x000e [0x4f000e] -21:21:14.518874 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#1: R078 (0x4e) -> 0x0000 [0x4e0000] -21:21:14.518881 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#2: R069 (0x45) -> 0x0001 [0x450001] -21:21:14.518888 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#3: R067 (0x43) -> 0x1000 [0x431000] -21:21:14.518897 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#4: R066 (0x42) -> 0x003f [0x42003f] -21:21:14.518904 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#5: R065 (0x41) -> 0x0008 [0x410008] -21:21:14.518914 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#6: R064 (0x40) -> 0x0284 [0x400284] -21:21:14.518923 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#7: R045 (0x2d) -> 0x0000 [0x2d0000] -21:21:14.518928 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#8: R044 (0x2c) -> 0x0000 [0x2c0000] -21:21:14.518935 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#9: R043 (0x2b) -> 0x0000 [0x2b0000] -21:21:14.518941 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#10: R042 (0x2a) -> 0x0000 [0x2a0000] -21:21:14.518948 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#11: R039 (0x27) -> 0x0001 [0x270001] -21:21:14.518955 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#12: R038 (0x26) -> 0x0000 [0x260000] -21:21:14.518962 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#13: R036 (0x24) -> 0x0020 [0x240020] -21:21:14.518969 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#14: R035 (0x23) -> 0x3100 [0x233100] -21:21:14.518978 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#15: R032 (0x20) -> 0x16c1 [0x2016c1] -21:21:14.518983 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#16: R022 (0x16) -> 0x62bf [0x1662bf] -21:21:14.519004 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#17: R014 (0x0e) -> 0x3001 [0x0e3001] -21:21:14.519020 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#18: R013 (0x0d) -> 0x0038 [0x0d0038] -21:21:14.519031 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#19: R012 (0x0c) -> 0x0408 [0x0c0408] -21:21:14.519040 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#20: R011 (0x0b) -> 0x0602 [0x0b0602] -21:21:14.519052 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#21: R002 (0x02) -> 0x93e8 [0x0293e8] -21:21:14.519062 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#22: R001 (0x01) -> 0xd7a0 [0x01d7a0] -21:21:14.519072 DEBUG: common_print_registers_a8d16:89 [COMN] WRITE#23: R000 (0x00) -> 0x6660 [0x006660] -*/ - static uint32_t lmx2820_rom_test[] = { From a7e94ce7c5df5c587a0c4efcd6c9e9c3002e27c8 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 6 May 2025 16:55:54 +0300 Subject: [PATCH 126/397] enable DPLL + timeout 4min --- src/lib/device/pe_sync/pe_sync.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 7e7e596e..9668527d 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -299,7 +299,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmk05318_dpll_settings_t dpll; memset(&dpll, 0, sizeof(dpll)); - dpll.enabled = false; + dpll.enabled = true; dpll.en[LMK05318_PRIREF] = true; dpll.fref[LMK05318_PRIREF] = 1; dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; @@ -340,7 +340,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; //wait for PRIREF/SECREF validation - res = lmk05318_wait_dpll_ref_stat(&d->gen, 2*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on + res = lmk05318_wait_dpll_ref_stat(&d->gen, 4*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on if(res) { USDR_LOG("SYNC", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); From 27c95d67475b607791952b285380fbcc5c6e939c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 19 May 2025 20:09:53 +0300 Subject: [PATCH 127/397] minor cleaning --- src/lib/device/ext_simplesync/ext_simplesync.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 8 ++++++-- src/lib/hw/lmk05318/lmk05318_solver.h | 12 ------------ 3 files changed, 7 insertions(+), 15 deletions(-) delete mode 100644 src/lib/hw/lmk05318/lmk05318_solver.h diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index e4e60821..5a7ff702 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -82,7 +82,7 @@ int board_ext_simplesync_init(lldev_t dev, #else lmk05318_xo_settings_t xo; xo.doubler_enabled = true; - xo.fdet_bypass = true; + xo.fdet_bypass = false; xo.fref = 26000000; xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 0c60f971..4d439dc3 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -12,13 +12,12 @@ #include "def_lmk05318.h" #include "lmk05318.h" #include "lmk05318_rom.h" -#include "lmk05318_solver.h" #include #include "../../xdsp/attribute_switch.h" #include "../cal/opt_func.h" -//#define LMK05318_SOLVER_DEBUG +#undef LMK05318_SOLVER_DEBUG enum { VCO_APLL1 = 2500000000ull, @@ -81,6 +80,11 @@ enum #define DPLL_FDIV_FRAC_MAX 0.9375f #define DPLL_FDIV_FRAC_MIN 0.0625f +struct range +{ + uint64_t min, max; +}; +typedef struct range range_t; static const char* lmk05318_dpll_decode_ref_dc_mode(enum lmk05318_ref_dc_mode_t m) { diff --git a/src/lib/hw/lmk05318/lmk05318_solver.h b/src/lib/hw/lmk05318/lmk05318_solver.h deleted file mode 100644 index 4a7436ff..00000000 --- a/src/lib/hw/lmk05318/lmk05318_solver.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef LMK05318_SOLVER_H -#define LMK05318_SOLVER_H - -#include - -struct range -{ - uint64_t min, max; -}; -typedef struct range range_t; - -#endif // LMK05318_SOLVER_H From 44e639d402634608d4105d4ab9a33dde924a9100 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 19 May 2025 20:42:14 +0300 Subject: [PATCH 128/397] cleaning before merge [1] --- .../device/ext_simplesync/ext_simplesync.c | 15 +- src/lib/device/pe_sync/pe_sync.c | 27 +- src/lib/hw/lmk05318/lmk05318.c | 158 +- src/lib/hw/lmk05318/lmk05318.h | 7 - src/lib/hw/lmk05318/lmk05318_rom.h | 1939 ----------------- src/lib/hw/lmx1204/lmx1204.c | 82 +- src/lib/hw/lmx1204/lmx1204.h | 2 - src/lib/hw/lmx1204/lmx1204_dump.h | 91 - src/lib/hw/lmx1214/lmx1214.c | 16 - src/lib/hw/lmx1214/lmx1214.h | 2 - src/lib/hw/lmx1214/lmx1214_dump.h | 30 - src/lib/hw/lmx2820/lmx2820.c | 55 +- src/lib/hw/lmx2820/lmx2820_dump.h | 263 --- 13 files changed, 11 insertions(+), 2676 deletions(-) delete mode 100644 src/lib/hw/lmk05318/lmk05318_rom.h delete mode 100644 src/lib/hw/lmx1204/lmx1204_dump.h delete mode 100644 src/lib/hw/lmx1214/lmx1214_dump.h delete mode 100644 src/lib/hw/lmx2820/lmx2820_dump.h diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 5a7ff702..4f4b3ff7 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -77,9 +77,6 @@ int board_ext_simplesync_init(lldev_t dev, // Wait for power up usleep(50000); -#if 0 - res = lmk05318_create(dev, subdev, i2ca, 0, &ob->lmk); -#else lmk05318_xo_settings_t xo; xo.doubler_enabled = true; xo.fdet_bypass = false; @@ -104,7 +101,6 @@ int board_ext_simplesync_init(lldev_t dev, res = res ? res : lmk05318_reset_los_flags(&ob->lmk); res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); -#endif if (res) return res; @@ -118,15 +114,6 @@ int board_ext_simplesync_init(lldev_t dev, int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) { -#if 0 - unsigned div = 255; - int res = lmk05318_tune_apll2(&ob->lmk, meas_lo, &div); - - for (unsigned p = 0; p < 4; p++) { - res = (res) ? res : lmk05318_set_out_div(&ob->lmk, p, div); - res = (res) ? res : lmk05318_set_out_mux(&ob->lmk, p, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - } -#else lmk05318_out_config_t cfg[4]; lmk05318_port_request(cfg, 0, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); lmk05318_port_request(cfg, 1, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); @@ -143,6 +130,6 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) res = res ? res : lmk05318_reset_los_flags(&ob->lmk); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); -#endif + return res; } diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 9668527d..a8dcaafe 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -165,10 +165,6 @@ int dev_pe_sync_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) static void usdr_device_pe_sync_destroy(pdevice_t udev) { - // struct dev_pe_sync *d = (struct dev_pe_sync *)udev; - // lldev_t dev = d->base.dev; - // TODO: power off -#if 0 struct dev_pe_sync *d = (struct dev_pe_sync *)udev; lldev_t dev = d->base.dev; @@ -178,7 +174,6 @@ static void usdr_device_pe_sync_destroy(pdevice_t udev) usdr_device_base_destroy(udev); USDR_LOG("SYNC", USDR_LOG_WARNING, "PESync destroyed"); -#endif } static int i2c_reg_rd8(lldev_t dev, unsigned lsaddr, uint8_t reg, uint8_t* val) @@ -200,16 +195,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return 0; } -#if 0 - { - USDR_LOG("SYNC", USDR_LOG_WARNING, "PESync shutdown..."); - usdr_device_pe_sync_destroy(udev); - usleep(30000000); - USDR_LOG("SYNC", USDR_LOG_WARNING, "PESync OFF"); - return 0; - } -#endif - // gpo_in_ctrl[0] -- 0 - Disable input 1PPS / 10Mhz buffer and REF ADC for 1PPS // gpo_in_ctrl[1] -- 0 - external SMA, 1 - feedback from LCK_FB // gpo_in_ctrl[2] -- 0 - external SMA, 1 - 1PPS from GPS @@ -230,10 +215,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // gpo_gen_ctrl[5] -- clk_gpio[0] // gpo_gen_ctrl[6] -- clk_gpio[1] // gpo_gen_ctrl[7] -- clk_gpio[2] - // res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (0 << 0) | (0 << 1) | (1 << 2) | (0 << 5)); - // usleep(1000); - // res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (1 << 0) | (0 << 1) | (1 << 2) | (1 << 5)); - // usleep(25000); res = res ? res : dev_gpo_set(dev, IGPO_GEN_CTRL, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 5) | (1 << 3) | (1 << 4)); // gpo_distrib_ctrl[0] -- En global LDO for all distribution logic @@ -396,7 +377,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmx0_sr->master_mode = true; lmx0_sr->cont_pulse = true; lmx0_sr->srout = lmx0_freq[2]; - lmx0_sr->delay_ctrl = 0;//60; + lmx0_sr->delay_ctrl = 0; res = res ? res : lmx2820_tune(&d->lmx0, lmk_freq[2], 2 /*mash order 2*/, 0 /*force_mult*/, lmx0_freq[0], lmx0_freq[1]); @@ -429,7 +410,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmx1_sr->master_mode = true; lmx1_sr->cont_pulse = true; lmx1_sr->srout = 25000000; - lmx1_sr->delay_ctrl = 0;//60; + lmx1_sr->delay_ctrl = 0; res = res ? res : lmx2820_tune(&d->lmx1, lmk_freq[3], 2 /*mash order 2*/, 0 /*force_mult*/, lmx1_freq[0], lmx1_freq[1]); @@ -458,7 +439,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = lmx1214_create(dev, 0, SPI_LMX1214, &d->lodistr); res = res ? res : lmx1214_solver(&d->lodistr, lmx1_freq[0], ld_clkout, ld_en, &ld_aux, false /*prec_mode*/, false /*dry run*/); - //res = res ? res : lmx1214_loaddump(&d->lodistr); float lmx1214_tempval; lmx1214_get_temperature(&d->lodistr, &lmx1214_tempval); //just for logging @@ -513,9 +493,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const lmx1204->logiclkout_fmt = LMX1204_FMT_LVDS; lmx1204->logisysrefout_fmt = LMX1204_FMT_LVDS; - // + res = lmx1204_solver(&d->cldistr, false/*prec_mode*/, false/*dry_run*/); - //res = lmx1204_loaddump(&d->cldistr); if(res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 4d439dc3..cb5df253 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -11,12 +11,12 @@ #include "def_lmk05318.h" #include "lmk05318.h" -#include "lmk05318_rom.h" #include #include "../../xdsp/attribute_switch.h" #include "../cal/opt_func.h" +//define this for solver extra logging #undef LMK05318_SOLVER_DEBUG enum { @@ -480,30 +480,6 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -UNUSED -static int lmk05318_empirics_smartload(lmk05318_state_t* d, const empiric_t* regs, unsigned count, unsigned mask_allow, unsigned mask_deny) -{ - unsigned n = 0; - - for(unsigned i = 0; i < count; ++i) - { - const empiric_t v = regs[i]; - if((v.type & mask_allow) && !(v.type & mask_deny)) - { - USDR_LOG("5318", USDR_LOG_DEBUG, "ADD REGISTER from empirical set [0x%06x]", v.reg); - ++n; - - int res = lmk05318_add_reg_to_map(d, &v.reg, 1); - if(res) - return res; - } - } - - USDR_LOG("5318", USDR_LOG_DEBUG, "%u REGISTERS added from empirical set", n); - - return 0; -} - static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) { int res = 0; @@ -528,7 +504,7 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett 0x005600, // | 0x00571E, // | 0x005884, // | - 0x005980, // | BAW lock&unlock detection + 0x005980, // | BAW lock&unlock detection, may depend on XO params 0x005A00, // | 0x005B14, // | 0x005C00, // | @@ -764,11 +740,7 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett MAKE_LMK05318_DPLL_REF_UNLOCKDET_VCO_CNTSTRT_BY1(dco_unlock_det1),//R337 MAKE_LMK05318_DPLL_REF_UNLOCKDET_VCO_CNTSTRT_BY2(dco_unlock_det1),//R338 }; -#if 0 - const unsigned mask_allow = REG_OVERRIDE; - const unsigned mask_deny = REG_PLL1 | REG_PLL2 | REG_XO | REG_LDO | REG_NVM | REG_UNKNOWN; - res = lmk05318_empirics_smartload(d, lmk05318_rom_dpll_empiric, SIZEOF_ARRAY(lmk05318_rom_dpll_empiric), mask_allow, mask_deny); -#endif + res = res ? res : lmk05318_add_reg_to_map(d, dpll_regs, SIZEOF_ARRAY(dpll_regs)); } @@ -833,13 +805,6 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return -ENODEV; } -#if 0 - out->dpll.enabled = true; - out->dpll.ref_en[LMK05318_PRIREF] = true; - res = lmk05318_reg_wr_n(out, lmk05318_rom_dpll, SIZEOF_ARRAY(lmk05318_rom_dpll)); - if (res) - return res; -#else res = lmk05318_set_xo_fref(out); if(res) { @@ -881,7 +846,6 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 error %d writing registers", res); return res; } -#endif res = dry_run ? 0 : lmk05318_softreset(out); if(res) @@ -894,117 +858,6 @@ int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, return 0; } -/* - * Legacy function, remove it later - */ -int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int flags, lmk05318_state_t* out) -{ - int res; - uint8_t dummy[4]; - - const uint32_t* lmk_init = flags ? lmk05318_rom_49152_12288_384 : lmk05318_rom; - unsigned lmk_init_sz = flags ? SIZEOF_ARRAY(lmk05318_rom_49152_12288_384) : SIZEOF_ARRAY(lmk05318_rom); - - out->dev = dev; - out->subdev = subdev; - out->lsaddr = lsaddr; - out->vco2_freq = 0; - out->pd1 = 0; - out->pd2 = 0; - - res = lmk05318_reg_get_u32(out, 0, &dummy[0]); - if (res) - return res; - - USDR_LOG("5318", USDR_LOG_INFO, "LMK05318 DEVID[0/1/2/3] = %02x %02x %02x %02x\n", dummy[3], dummy[2], dummy[1], dummy[0]); - - if ( dummy[3] != 0x10 || dummy[2] != 0x0b || dummy[1] != 0x35 || dummy[0] != 0x42 ) { - return -ENODEV; - } - - // Do the initialization - res = lmk05318_reg_wr_n(out, lmk_init, lmk_init_sz); - if (res) - return res; - - // Reset - uint32_t regs[] = { - lmk05318_rom[0] | (1 << RESET_SW_OFF), - lmk05318_rom[0] | (0 << RESET_SW_OFF), - - MAKE_LMK05318_XO_CONFIG(flags > 1 ? 1 : 0), - - MAKE_LMK05318_PLL1_CTRL0(0), - MAKE_LMK05318_PLL1_CTRL0(1), - MAKE_LMK05318_PLL1_CTRL0(0), - - }; - res = lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; - - out->fref_pll2_div_rp = 3; - out->fref_pll2_div_rs = (((VCO_APLL1 + APLL2_PD_MAX - 1) / APLL2_PD_MAX) + out->fref_pll2_div_rp - 1) / out->fref_pll2_div_rp; - - out->xo.fref = 0; - out->xo.doubler_enabled = false; - out->xo.fdet_bypass = false; - out->xo.type = XO_CMOS; - - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 initialized\n"); - return 0; -} -/**/ - -/* - * Legacy function, remove it later - */ -int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div) -{ - const unsigned apll2_post_div = 2; - - unsigned fref = VCO_APLL1 / d->fref_pll2_div_rp / d->fref_pll2_div_rs; - if (fref < APLL2_PD_MIN || fref > APLL2_PD_MAX) { - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 PFD should be in range [%" PRIu64 ";%" PRIu64 "] but got %d!\n", - (uint64_t)APLL2_PD_MIN, (uint64_t)APLL2_PD_MAX, fref); - return -EINVAL; - } - if (freq < 1e6) { - // Disable - uint32_t regs[] = { - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), - }; - return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs));; - } - - unsigned div = ((VCO_APLL2_MAX / apll2_post_div)) / freq; - uint64_t fvco = (uint64_t)freq * div * apll2_post_div; - unsigned n = fvco / fref; - unsigned num = (fvco - n * (uint64_t)fref) * (1ull << 24) / fref; - int res; - - USDR_LOG("5318", USDR_LOG_ERROR, "LMK05318 APLL2 FREQ=%u FVCO=%" PRIu64 " N=%d NUM=%d DIV=%d\n", freq, fvco, n, num, div); - - uint32_t regs[] = { - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), - MAKE_LMK05318_PLL2_CTRL2(apll2_post_div - 1, apll2_post_div - 1), - MAKE_LMK05318_PLL2_NDIV_BY0(n), - MAKE_LMK05318_PLL2_NDIV_BY1(n), - MAKE_LMK05318_PLL2_NUM_BY0(num), - MAKE_LMK05318_PLL2_NUM_BY1(num), - MAKE_LMK05318_PLL2_NUM_BY2(num), - MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), - }; - - res = lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); - if (res) - return res; - - *last_div = div; - return 0; -} -/**/ - VWLT_ATTRIBUTE(optimize("-Ofast")) static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, unsigned* pn, unsigned* pnum, unsigned* pden) { @@ -1412,11 +1265,6 @@ static int lmk05318_set_out_mux_ex(lmk05318_state_t* d, unsigned port, unsigned return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } -int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype) -{ - return lmk05318_set_out_mux_ex(d, port, (pll1 ? OUT_PLL_SEL_APLL1_P1 : OUT_PLL_SEL_APLL2_P1), otype); -} - static range_t lmk05318_get_freq_range(const lmk05318_out_config_t* cfg) { range_t r; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 6cef6a98..b1c59d2f 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -192,13 +192,6 @@ static inline int lmk05318_set_port_affinity(lmk05318_out_config_t* cfg, unsigne return 0; } -/* - * Legacy functions, remove them later - */ -int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned flags, lmk05318_state_t* out); -int lmk05318_tune_apll2(lmk05318_state_t* d, uint32_t freq, unsigned *last_div); -/**/ - int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t div); int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype); diff --git a/src/lib/hw/lmk05318/lmk05318_rom.h b/src/lib/hw/lmk05318/lmk05318_rom.h deleted file mode 100644 index c93ed848..00000000 --- a/src/lib/hw/lmk05318/lmk05318_rom.h +++ /dev/null @@ -1,1939 +0,0 @@ -// Copyright (c) 2023-2024 Wavelet Lab -// SPDX-License-Identifier: MIT - -#include -#include - -enum empiric_type -{ - REG_READONLY = 1, - REG_DEFAULTS = 2, - REG_OVERRIDE = 4, - REG_PLL1 = 8, - REG_PLL2 = 16, - REG_DPLL = 32, - REG_XO = 64, - REG_LDO = 128, - REG_NVM = 256, - REG_UNKNOWN = 512, - REF_FORCE = 1024, -}; -typedef enum empiric_type empiric_type_t; - -struct empiric -{ - uint32_t reg; - empiric_type_t type; -}; -typedef struct empiric empiric_t; - -static const empiric_t lmk05318_rom_dpll_empiric[] = -{ - {0x000d00, REG_READONLY | REG_XO | REG_PLL1 | REG_PLL2}, // [RO] APLL&XO LOSSes - {0x000e00, REG_READONLY | REG_DPLL}, // [RO] DPLL LOSSes - {0x000f00, REG_DEFAULTS}, // [DEF] INT_MASK - {0x001000, REG_DEFAULTS}, // [DEF] INT_MASK - {0x001100, REG_DEFAULTS | REG_XO | REG_PLL1 | REG_PLL2}, // [DEF] XO/APLL LOL Polarity - {0x001200, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL LOL Polarity - {0x001500, REG_DEFAULTS}, // [DEF] INT_AND_OR - {0x001600, REG_DEFAULTS}, // [DEF] STATUS0/1 Polarity - //{0x001900, REG_OVERRIDE}, // OUT MUTE ctrls (unmute) - {0x001a00, REG_DEFAULTS | REG_XO}, // [DEF] XO hyst timer - {0x001b00, REG_OVERRIDE | REG_XO}, // XO SE energy det mode - {0x001c00, REG_OVERRIDE | REG_XO}, // XO DIFF energy det mode - //{0x001d00, REG_OVERRIDE}, // mute during LOCK ?? 0x17 - {0x001e00, REG_OVERRIDE | REG_LDO}, // LDO timer scale - {0x002000, REG_OVERRIDE | REG_LDO | REG_PLL1 | REG_PLL2},// APLL MASH LDO trim - {0x002300, REG_DEFAULTS | REG_LDO | REG_PLL1 | REG_PLL2},// [DEF] VCO1/2 LDO settings - {0x002400, REG_DEFAULTS}, // [DEF] STAT0/1 Driver Type Output - {0x002500, REG_OVERRIDE}, // STATUS0 open Drain mode - {0x002600, REG_OVERRIDE}, // STATUS1 open Drain mode - {0x002900, REG_DEFAULTS | REG_NVM}, // [DEF] SPARE_NVMBASE2 - {0x003000, REG_OVERRIDE}, // STAT0_SEL - {0x003100, REG_OVERRIDE}, // STAT1_SEL - {0x003200, REG_DEFAULTS}, // [DEF] DCO freq + CH6/7 PD - {0x004400, REG_OVERRIDE | REG_PLL1}, // APLL1 BAW drain - {0x004500, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x004800, REG_READONLY}, // [RO] RO OUTCH active flags - {0x004900, REG_DEFAULTS}, // [DEF] REF_BYPASS (route REF to OUTs instead of VCO1) - {0x004b00, REG_OVERRIDE | REG_PLL1}, // PLL1 Vtune Monitor bypass + charge pump gain - {0x004c00, REG_OVERRIDE | REG_PLL1}, // PLL1 post-div 1 - {0x004d00, REG_OVERRIDE | REG_PLL1}, // PLL1 loop filter - {0x004e00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 bleed resistor - {0x006500, REG_OVERRIDE | REG_PLL2}, // PLL2 charge pump - {0x006633, REG_OVERRIDE | REG_PLL2}, // PLL2 post-div2 post-div1 - {0x006700, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop filter - {0x006800, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 bleed resistor - {0x006900, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 closed loop wait + VCO wait - {0x006a00, REG_OVERRIDE | REG_PLL1}, // PLL1 N Delay div (MSB) - {0x006b00, REG_OVERRIDE | REG_PLL1}, // PLL1 N Delay div - {0x007500, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV (MSB) - {0x007600, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def - {0x007700, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def - {0x007800, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def - {0x007900, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_FDEV def - {0x007a00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 inc/dec ctrl - {0x007b00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT (MSB) - {0x007c00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT - {0x007d00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT - {0x007e00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT - {0x007f00, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1_NUM_STAT - {0x008000, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 NUM saturation - {0x008100, REG_OVERRIDE | REG_PLL1}, // PLL1 Loop Filter R2 - {0x008200, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 loop filter C1 - {0x008300, REG_OVERRIDE | REG_PLL1}, // PLL1 Loop Filter R3 - {0x008400, REG_OVERRIDE | REG_PLL1}, // PLL1 Loop Filter R4 - {0x008500, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 Loop Filter C4 - {0x008600, REG_OVERRIDE | REG_PLL2}, // Bit 8 of PLL2_NDIV - {0x00872c, REG_OVERRIDE | REG_PLL2}, // Bits 7:0 of PLL2 NDIV - {0x00887c, REG_OVERRIDE | REG_PLL2}, // PLL2_NUM (MSB) - {0x0089e0, REG_OVERRIDE | REG_PLL2}, // PLL2_NUM - {0x008abf, REG_OVERRIDE | REG_PLL2}, // PLL2_NUM - //{0x008b00, REG_DEFAULTS | REG_PLL2}, // [DEF] SDM Dither Mode + APLL2 SDM Order - {0x008c00, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop Filter R2 - {0x008d00, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 Loop Filter C1 - {0x008e00, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop Filter R3 - {0x008f00, REG_OVERRIDE | REG_PLL2}, // PLL2 Loop Filter R4 - {0x009000, REG_DEFAULTS | REG_PLL2}, // [DEF] PLL2 Loop Filter C4/C3 - {0x009100, REG_OVERRIDE | REG_XO}, // XO Input Wait Timer - {0x009200, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x009300, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x009500, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x009600, REG_DEFAULTS | REG_PLL1}, // [DEF] PLL1 Amp Cal up/low threhold def - {0x009700, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x009800, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x009900, REG_OVERRIDE | REG_PLL1}, // PLL1 Amp Cal up/low threhold - {0x009a00, REG_OVERRIDE | REG_LDO}, // LDO trim bits - {0x009b00, REG_READONLY | REG_NVM}, // [RO] NVM Stored CRC - {0x009c00, REG_READONLY | REG_NVM}, // [RO] NVM Program Count - {0x009e00, REG_READONLY | REG_NVM}, // [RO] MUMLCRC - {0x009f00, REG_DEFAULTS | REG_NVM}, // [DEF] Bits 12:8 of MEMADR - {0x00a000, REG_DEFAULTS | REG_NVM}, // [DEF] Memory Address - {0x00a100, REG_READONLY | REG_NVM}, // [RO]EEPROM Read Data - {0x00a200, REG_DEFAULTS | REG_NVM}, // [DEF] RAM Read/Write Data - {0x00a500, REG_DEFAULTS | REG_NVM}, // [DEF] NVM BASE unlock - {0x00a700, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x00b200, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x00b400, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN (MSB) - {0x00b500, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN - {0x00b600, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN - {0x00b700, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN - {0x00b800, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_TUNING_FREE_RUN - {0x00b9f1, REG_OVERRIDE | REG_DPLL}, // DPLL_REF_HIST_EN=enabled - {0x00ba01, REG_OVERRIDE | REG_DPLL}, // DPLL REF Tuning History Timer - {0x00bb00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY (MSB) - {0x00bc00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY - {0x00bd00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY - {0x00be00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_HISTDLY - {0x00bf00, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x00c000, REG_OVERRIDE | REG_DPLL}, // PRI/SECREF detectors settings - {0x00d800, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x00eb02, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET (MSB) - {0x00ecfa, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET - {0x00edf0, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET - {0x00ee80, REG_OVERRIDE | REG_DPLL}, // PRIREF_PH_VALID_DET - {0x00ef00, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET (MSB) - {0x00f000, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET - {0x00f100, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET - {0x00f200, REG_OVERRIDE | REG_DPLL}, // SECREF_PH_VALID_DET - {0x00fa00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_VAL_FL(PL)_EN - {0x00fd00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer - {0x00fe00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer - {0x00ff00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL switchover timer - {0x010402, REG_OVERRIDE | REG_DPLL}, // DPLL_REF_AVOID_SLIP(en) + TDC software ctrl(dis) - {0x010580, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET (MSB) - {0x010601, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET - {0x01072a, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET - {0x010805, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET - {0x0109f2, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET - {0x010a00, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_CYCSLIP_OFFSET (LSB) = 5000000000 - {0x010ba0, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control + DPLL loop filter - {0x010c00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x010d00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x010e02, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_FILTER_SCALAR (MSB) - {0x010fa6, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_FILTER_SCALAR (LSB) = 678 - {0x011000, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011100, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011200, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011316, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LOOP_GAIN=22 - {0x011416, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LOOP_GAIN_FL1=22 - {0x011516, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LOOP_GAIN_FL2=22 - {0x011600, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011700, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011800, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011900, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011a00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011b00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011c1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LPF0_GAIN2_FL=20 - {0x011d1e, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_LPF1_GAIN2_FL=20 - {0x011e00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x011f00, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x012000, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x012100, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter - {0x012203, REG_OVERRIDE | REG_DPLL}, // DPLL Phase Lock Detection - {0x012322, REG_OVERRIDE | REG_DPLL}, // DPLL Phase Lock Detection - {0x012400, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching - {0x012500, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching - {0x012600, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching - {0x012700, REG_OVERRIDE | REG_DPLL}, // Phase Cancellation for Hitless Switching - {0x01280a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_QUANT=10 - {0x01290a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_QUANT_FL1=10 - {0x012a0a, REG_OVERRIDE | REG_DPLL}, // DPLL Loop Filter ?DPLL_REF_QUANT_FL2=10 - {0x012b00, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x012c00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Phase Lock Detection - {0x012d1c, REG_OVERRIDE | REG_DPLL}, // Phase lock declaration threshold - {0x012e1e, REG_OVERRIDE | REG_DPLL}, // Phase un-lock declaration threshold - {0x012f01, REG_OVERRIDE | REG_UNKNOWN}, // unknown - {0x013f03, REG_OVERRIDE | REG_DPLL}, // DPLL Reference Control ?DPLL_REF_ORDER=3 - {0x014000, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x01410a, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection ?DPLL_REF_LOOPFILT_CLK_DIV=10 - {0x014200, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x014300, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x014400, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x014501, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x014606, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x014735, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x014875, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x01490b, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Lock Detection - {0x014a00, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection - {0x014b64, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection - {0x014c00, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection - {0x014d00, REG_OVERRIDE | REG_PLL2}, // PLL2 DEN (MSB) - {0x014e61, REG_OVERRIDE | REG_PLL2}, // PLL2 DEN - {0x014fa8, REG_OVERRIDE | REG_PLL2}, // PLL2 DEN - {0x015006, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection - {0x015135, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection - {0x015275, REG_OVERRIDE | REG_DPLL}, // DPLL DCO Unlock Detection - {0x01530b, REG_OVERRIDE | REG_PLL1}, // PLL1 24-b NUM MSB (not used in DPLL mode) - {0x015400, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET - {0x015500, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET - {0x015600, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET - {0x015700, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET - {0x015800, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_REF_SYNC_PH_OFFSET - {0x015900, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL REF Zero Delay Mode Phase Offset - {0x015a00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Freq Incr/Decr enable via pin/reg - {0x015b00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV - {0x015c00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV - {0x015d00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV - {0x015e00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL_FDEV - {0x015f00, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Freq Incr/Decr Numerator Step Word (MSB) - {0x016000, REG_DEFAULTS | REG_DPLL}, // [DEF] DPLL Freq Incr/Decr Numerator Step Word -}; - -static const uint32_t lmk05318_rom_dpll[] = -{ -/* - 0x000000, - 0x000100, - 0x000200, - 0x000300, - 0x000400, - 0x000500, // R - 0x000600, - 0x000700, - 0x000800, - 0x000A00, - 0x000B00, -*/ - 0x000C1B, - 0x000D00, - 0x000E00, - 0x000F00, - 0x001000, - 0x001100, - 0x001200, - 0x001300, - 0x001400, - 0x001500, - 0x001600, - 0x001700, - 0x001800, - 0x001900, - 0x001A00, - 0x001B00, - 0x001C00, - 0x001D00, - 0x001E00, - 0x002000, - 0x002300, - 0x002400, - 0x002500, - 0x002600, - 0x002700, - 0x002806, - 0x002900, - 0x002A10, - 0x002B40, - 0x002C00, - 0x002D06, - 0x002E01, - 0x002F00, - 0x003000, - 0x003100, - 0x003200, - 0x003310, - 0x003410, - 0x003513, - 0x003610, - 0x003710, - 0x003809, - 0x003900, - 0x003A0F, - 0x003B00, - 0x003C0F, - 0x003D3E, - 0x003EF9, - 0x003F3E, - 0x004095, - 0x004102, - 0x0042F8, - 0x0043FF, - - 0x004400, // APLL1 Charge Pump Current Gain - 0x004500, // ? - - 0x004600, - 0x004700, - - 0x004800, // ? - 0x004900, // ? - - 0x004A00, - - 0x004B00, // ? - 0x004C00, // ? - 0x004D00, // ? - 0x004E00, // ? - - 0x004F00, - 0x005000, - 0x00510A, - 0x005200, - 0x00530E, - 0x0054A6, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D0E, - 0x005EA6, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - 0x006429, - - 0x006500, // PLL2 Charge Pump Gain - 0x006633, // PLL2 Post-Divider 1/2 - 0x006700, // ? - 0x006800, // PLL2 Bleed resistor selection - 0x006900, // Closed Loop Wait Period - 0x006A00, // ? - 0x006B00, // ? - - 0x006C00, - 0x006D32, - 0x006E00, - 0x006F00, - 0x007000, - 0x007100, - 0x007200, - 0x007303, - 0x007401, - - 0x007500, // ? - 0x007600, // ? - 0x007700, // ? - 0x007800, // ? - 0x007900, // ? - 0x007A00, // ? - 0x007B00, // PLL1_NUM_STAT_39:32 - 0x007C00, // PLL1_NUM_STAT_31:24 - 0x007D00, // PLL1_NUM_STAT_23:16 - 0x007E00, // PLL1_NUM_STAT_15:8 - 0x007F00, // PLL1_NUM_STAT - 0x008000, // ? - 0x008100, // PLL1 Loop Filter R2 - 0x008200, // ? - 0x008300, // PLL1 Loop Filter R3 - 0x008400, // PLL1 Loop Filter R4 - 0x008500, // ? - 0x008600, // Bit 8 of PLL2_NDIV - 0x00872C, // Bits 7:0 of PLL2 N Divider - 0x00887C, // Bits 23:16 of PLL2_NUM - 0x0089E0, // Bits 15:8 of PLL2_NUM - 0x008ABF, // PLL2 Fractional Divider Numerator - 0x008B00, // SDM Dither Mode + APLL2 SDM Order - 0x008C00, // PLL2 Loop Filter R2 - 0x008D00, // ? - 0x008E00, // PLL2 Loop Filter R3 - 0x008F00, // PLL2 Loop Filter R4 - 0x009000, // PLL2 Loop Filter C4/C3 - 0x009100, // XO Input Wait Timer - 0x009200, // ? - 0x009300, // ? - 0x009500, // ? - 0x009600, // ? - 0x009700, // ? - 0x009800, // ? - 0x009900, // ? - 0x009A00, // ? - 0x009B00, // ? - 0x009C00, // NVM Program Count - // 0x009D00, // NVM misc - 0x009E00, // ? - 0x009F00, // Bits 12:8 of MEMADR - 0x00A000, // Memory Address - 0x00A100, // EEPROM Read Data - 0x00A200, // RAM Read/Write Data - // 0x00A400, // NVM Program Unlock - 0x00A500, // ? - 0x00A700, // ? - 0x00B200, // ? - 0x00B400, // Bits 37:32 of DPLL_TUNING_FREE_RUN - 0x00B500, // Bits 31:24 of DPLL_TUNING_FREE_RUN - 0x00B600, // Bits 23:16 of DPLL_TUNING_FREE_RUN - 0x00B700, // Bits 15:8 of DPLL_TUNING_FREE_RUN - 0x00B800, // DPLL Free-run tuning word - 0x00B9F1, // DPLL_REF_HIST_EN++ - 0x00BA01, // DPLL REF Tuning History Timer - 0x00BB00, // Bits 30:24 of DPLL_REF_HISTDLY - 0x00BC00, // Bits 23:16 of DPLL_REF_HISTDLY - 0x00BD00, // Bits 15:8 of DPLL_REF_HISTDLY - 0x00BE00, // DPLL REF Tuning History delay - 0x00BF00, // ? - 0x00C000, // PRI/SECREF detectors settings - - - 0x00C119, - 0x00C200, - - 0x00C300, // PRIREF Missing Clock Detection - 0x00C400, // PRIREF Missing Clock Detection - 0x00C51D, // PRIREF Missing Clock Detection - 0x00C600, // SECREF Missing Clock Detection - 0x00C700, // SECREF Missing Clock Detection - 0x00C800, // SECREF Missing Clock Detection - 0x00C900, // PRI/SECREF Window Detection - 0x00CA00, // PRIREF Early Clock Detection - 0x00CB00, // PRIREF Early Clock Detection - 0x00CC15, // PRIREF Early Clock Detection - 0x00CD00, // SECREF Early Clock Detection - 0x00CE00, // SECREF Early Clock Detection - 0x00CF00, // SECREF Early Clock Detection - 0x00D000, // PRIREF Frequency Detection - 0x00D100, // PRIREF Frequency Detection - 0x00D200, // PRIREF Frequency Detection - 0x00D300, // PRIREF Frequency Detection - 0x00D400, // SECREF Frequency Detection - 0x00D500, // SECREF Frequency Detection - 0x00D600, // SECREF Frequency Detection - 0x00D700, // SECREF Frequency Detection - 0x00D800, // ? - 0x00D900, // PRIREF Frequency Detection - 0x00DA00, // PRIREF Frequency Detection - 0x00DB00, // PRIREF Frequency Detection - 0x00DC00, // PRIREF Frequency Detection - 0x00DD00, // PRIREF Frequency Detection - 0x00DE00, // PRIREF Frequency Detection - 0x00DF00, // PRIREF Frequency Detection - 0x00E000, // PRIREF Frequency Detection - 0x00E100, // SECREF Frequency Detection - 0x00E200, // SECREF Frequency Detection - 0x00E300, // SECREF Frequency Detection - 0x00E400, // SECREF Frequency Detection - 0x00E500, // SECREF Frequency Detection - 0x00E600, // SECREF Frequency Detection - 0x00E700, // SECREF Frequency Detection - 0x00E800, // SECREF Frequency Detection - - 0x00E919, - 0x00EA00, - - 0x00EB02, // PRIREF_PH_VALID_DET1 - 0x00ECFA, // PRIREF_PH_VALID_DET2 - 0x00EDF0, // PRIREF_PH_VALID_DET3 - 0x00EE80, // PRIREF_PH_VALID_DET4 - 0x00EF00, // SECREF_PH_VALID_DET1 - 0x00F000, // SECREF_PH_VALID_DET2 - 0x00F100, // SECREF_PH_VALID_DET3 - 0x00F200, // SECREF_PH_VALID_DET4 - - 0x00F33F, - 0x00F400, - 0x00F921, - - 0x00FA00, // ? - - 0x00FB03, - 0x00FC29, - - 0x00FD00, // DPLL Switchover Timer - 0x00FE00, // DPLL Switchover Timer - 0x00FF00, // DPLL Switchover Timer - - 0x010000, - 0x010101, - 0x010200, - 0x010300, - - 0x010402, // DPLL_REF_AVOID_SLIP - 0x010580, // DPLL Reference Control - 0x010601, // DPLL Reference Control - 0x01072A, // DPLL Reference Control - 0x010805, // DPLL Reference Control - 0x0109F2, // DPLL Reference Control - 0x010A00, // DPLL Reference Control - 0x010BA0, // DPLL Reference Control + DPLL Loop Filter - 0x010C00, // DPLL Reference Control - 0x010D00, // DPLL Reference Control - 0x010E02, // DPLL Loop Filter - 0x010FA6, // DPLL Loop Filter - 0x011000, // DPLL Loop Filter - 0x011100, // DPLL Loop Filter - 0x011200, // DPLL Loop Filter - 0x011316, // DPLL Loop Filter - 0x011416, // DPLL Loop Filter - 0x011516, // DPLL Loop Filter - 0x011600, // DPLL Loop Filter - 0x011700, // DPLL Loop Filter - 0x011800, // DPLL Loop Filter - 0x011900, // DPLL Loop Filter - 0x011A00, // DPLL Loop Filter - 0x011B00, // DPLL Loop Filter - 0x011C1E, // DPLL Loop Filter - 0x011D1E, // DPLL Loop Filter - 0x011E00, // DPLL Loop Filter - 0x011F00, // DPLL Loop Filter - 0x012000, // DPLL Loop Filter - 0x012100, // DPLL Loop Filter - 0x012203, // DPLL Phase Lock Detection - 0x012322, // DPLL Phase Lock Detection - 0x012400, // Phase Cancellation for Hitless Switching - 0x012500, // Phase Cancellation for Hitless Switching - 0x012600, // Phase Cancellation for Hitless Switching - 0x012700, // Phase Cancellation for Hitless Switching - 0x01280A, // DPLL Loop Filter - 0x01290A, // DPLL Loop Filter - 0x012A0A, // DPLL Loop Filter - 0x012B00, // ? - 0x012C00, // DPLL Phase Lock Detection - 0x012D1C, // Phase lock declaration threshold - 0x012E1E, // Phase un-lock declaration threshold - 0x012F01, // ? - - 0x01300F, - 0x013104, - 0x013261, - 0x0133F8, - 0x013443, - 0x0135C3, - 0x0136C3, - 0x0137C3, - 0x0138C3, - 0x0139C3, - 0x013AFF, - 0x013BFF, - 0x013CFF, - 0x013DFF, - 0x013EFF, - - 0x013F03, // DPLL Reference Control - 0x014000, // DPLL DCO Lock Detection - 0x01410A, // DPLL DCO Lock Detection - 0x014200, // DPLL DCO Lock Detection - 0x014300, // DPLL DCO Lock Detection - 0x014400, // DPLL DCO Lock Detection - 0x014501, // DPLL DCO Lock Detection - 0x014606, // DPLL DCO Lock Detection - 0x014735, // DPLL DCO Lock Detection - 0x014875, // DPLL DCO Lock Detection - 0x01490B, // DPLL DCO Lock Detection - 0x014A00, // DPLL DCO Unlock Detection - 0x014B64, // DPLL DCO Unlock Detection - 0x014C00, // DPLL DCO Unlock Detection - - 0x014D00, - 0x014E61, /* PLL2 den */ - 0x014FA8, - - 0x015006, // DPLL DCO Unlock Detection - 0x015135, // DPLL DCO Unlock Detection - 0x015275, // DPLL DCO Unlock Detection - - 0x01530B, /* PLL1 num*/ - - 0x015400, // DPLL_REF_SYNC_PH_OFFSET - 0x015500, // DPLL_REF_SYNC_PH_OFFSET - 0x015600, // DPLL_REF_SYNC_PH_OFFSET - 0x015700, // DPLL_REF_SYNC_PH_OFFSET - 0x015800, // DPLL_REF_SYNC_PH_OFFSET - 0x015900, // DPLL REF Zero Delay Mode Phase Offset - 0x015A00, // DPLL Freq Incr/Decr enable via pin or reg control - 0x015B00, // DPLL_FDEV - 0x015C00, // DPLL_FDEV - 0x015D00, // DPLL_FDEV - 0x015E00, // DPLL_FDEV - 0x015F00, // DPLL Freq Incr/Decr Numerator Step Word - 0x016000, // DPLL Freq Incr/Decr register control - //0x016500, R - //0x016F00, R - //0x019B00, R -}; - - - -static const uint32_t lmk05318_rom_test[] = -{ - //0x000010, - //0x00010B, - //0x000235, - //0x000332, - //0x000404, - //0x00050E, - //0x000617, - //0x00078E, - //0x000802, - //0x000AC8, - //0x000B00, - 0x000C1B, - 0x000D08, - 0x000E00, - 0x000F00, - 0x001000, - 0x00111D, - 0x0012FF, - 0x001308, - 0x001420, - 0x001501, - 0x001600, - 0x001755, - 0x001855, - 0x001900, - 0x001A00, - 0x001B00, - 0x001C01, - 0x001D13, - 0x001E40, - 0x002044, - 0x002300, - 0x002403, - 0x002500, - 0x002600, - 0x002703, - 0x002802, - 0x002900, - 0x002A11, - 0x002BC2, - 0x002C00, - 0x002D03, - 0x002E11, - 0x002F07, - 0x003050, - 0x00314A, - 0x003280, - 0x003310, - 0x003410, - 0x003513, - 0x003610, - 0x003710, - 0x003809, - 0x003900, - 0x003A0F, - 0x003B80, - 0x003CE1, - 0x003DBE, - 0x003EE1, - 0x003F3E, - 0x004095, - 0x004102, - 0x0042F8, - 0x0043FF, - 0x004408, - 0x004500, - 0x004607, - 0x00473F, - 0x004833, - 0x004900, - 0x004A00, - 0x004B00, - 0x004C00, - 0x004D0F, - 0x004E00, - 0x004F11, - 0x005080, - 0x00510A, - 0x005200, - 0x00530E, - 0x0054A6, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D0E, - 0x005EA6, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - 0x006428, - 0x006501, - 0x006611, - 0x00670F, - 0x00681F, - 0x006905, - 0x006A00, - 0x006B64, - 0x006C00, - 0x006D32, - 0x006E00, - 0x006F00, - 0x007000, - 0x007127, - 0x007210, - 0x007303, - 0x007400, - 0x007500, - 0x007600, - 0x007700, - 0x007800, - 0x007900, - 0x007A00, - 0x007B28, - 0x007C00, - 0x007D11, - 0x007E79, - 0x007F7A, - 0x008000, - 0x008101, - 0x008200, - 0x008301, - 0x008401, - 0x008577, - 0x008600, - 0x00872A, - 0x00884E, - 0x0089A4, - 0x008AAC, - 0x008B03, - 0x008C02, - 0x008D00, - 0x008E01, - 0x008F01, - 0x009077, - 0x009101, - 0x009289, - 0x009320, - 0x00950D, - 0x009600, - 0x009701, - 0x00980D, - 0x009929, - 0x009A24, - 0x009B32, - 0x009C01, - //0x009D00, - 0x009E00, - 0x009F00, - 0x00A0FC, - 0x00A132, - 0x00A200, - //0x00A400, - 0x00A500, - 0x00A701, - 0x00B200, - 0x00B400, - 0x00B500, - 0x00B600, - 0x00B700, - 0x00B800, - 0x00B905, - 0x00BA08, - 0x00BB00, - 0x00BC00, - 0x00BD00, - 0x00BE2C, - 0x00BF00, - 0x00C050, - 0x00C100, - 0x00C200, - 0x00C300, - 0x00C400, - 0x00C51D, - 0x00C600, - 0x00C700, - 0x00C81D, - 0x00C900, - 0x00CA00, - 0x00CB00, - 0x00CC15, - 0x00CD00, - 0x00CE00, - 0x00CF15, - 0x00D000, - 0x00D114, - 0x00D200, - 0x00D316, - 0x00D400, - 0x00D514, - 0x00D600, - 0x00D716, - 0x00D80F, - 0x00D900, - 0x00DA00, - 0x00DB19, - 0x00DC6E, - 0x00DD00, - 0x00DE03, - 0x00DF0D, - 0x00E047, - 0x00E100, - 0x00E200, - 0x00E319, - 0x00E46E, - 0x00E500, - 0x00E603, - 0x00E70D, - 0x00E847, - 0x00E90A, - 0x00EA0A, - 0x00EB00, - 0x00ECC3, - 0x00ED50, - 0x00EE00, - 0x00EF00, - 0x00F0C3, - 0x00F150, - 0x00F200, - 0x00F300, - 0x00F400, - 0x00F912, - 0x00FA00, - 0x00FB13, - 0x00FC2C, - 0x00FD00, - 0x00FE00, - 0x00FF00, - 0x010000, - 0x010101, - 0x010200, - 0x010301, - 0x010402, - 0x010580, - 0x010600, - 0x010700, - 0x010800, - 0x010900, - 0x010AC8, - 0x010BA0, - 0x010C0C, - 0x010D0A, - 0x010E02, - 0x010F14, - 0x011000, - 0x011100, - 0x011200, - 0x01130E, - 0x01140C, - 0x01150E, - 0x011609, - 0x011708, - 0x011809, - 0x011907, - 0x011A0D, - 0x011B07, - 0x011C1E, - 0x011D1E, - 0x011E02, - 0x011F30, - 0x012000, - 0x0121EE, - 0x012202, - 0x0123CA, - 0x012409, - 0x012501, - 0x012600, - 0x01272C, - 0x012808, - 0x01290C, - 0x012A08, - 0x012B01, - 0x012C00, - 0x012D1C, - 0x012E20, - 0x012F01, - 0x013001, - 0x013100, - 0x013200, - 0x013300, - 0x013410, - 0x0135AA, - 0x0136AA, - 0x0137AA, - 0x0138AA, - 0x0139AA, - 0x013AFF, - 0x013BFF, - 0x013CFF, - 0x013DFF, - 0x013EFF, - 0x013F03, - 0x014000, - 0x01410A, - 0x014200, - 0x014324, - 0x01449F, - 0x014500, - 0x014600, - 0x014798, - 0x014896, - 0x014980, - 0x014A00, - 0x014B64, - 0x014C00, - 0x014D00, - 0x014E61, - 0x014FA8, - 0x015000, - 0x015100, - 0x015200, - 0x015300, - 0x015400, - 0x015500, - 0x015600, - 0x015700, - 0x015800, - 0x015900, - 0x015A01, - 0x015B00, - 0x015C00, - 0x015D00, - 0x015E00, - 0x015F00, - 0x016000, - 0x016528, - 0x016F00, - 0x019B0C, - -#if 0 - //0x000010, - //0x00010B, - //0x000235, - //0x000332, - //0x000404, - //0x00050E, - //0x000617, - //0x00078E, - //0x000802, - //0x000AC8, - //0x000B00, - 0x000C1B, - 0x000D08, - 0x000E00, - 0x000F00, - 0x001000, - 0x00111D, - 0x0012FF, - 0x001308, - 0x001420, - 0x001501, - 0x001600, - 0x001755, - 0x001855, - 0x001900, - 0x001A00, - 0x001B00, - 0x001C01, - 0x001D13, - 0x001E40, - 0x002044, - 0x002300, - 0x002403, - 0x002500, - 0x002600, - 0x002703, - 0x002803, - 0x002900, - 0x002A11, - 0x002BC2, - 0x002C00, - 0x002D03, - 0x002E11, - 0x002F07, - 0x003050, - 0x00314A, - 0x003200, - 0x003310, - 0x003410, - 0x003513, - 0x003610, - 0x003710, - 0x003809, - 0x003900, - 0x003A0F, - 0x003B00, - 0x003C0F, - 0x003D3E, - 0x003EF9, - 0x003F3E, - 0x004095, - 0x004102, - 0x0042F8, - 0x0043FF, - 0x004408, - 0x004500, - 0x004600, - 0x004700, - 0x004833, - 0x004900, - 0x004A00, - 0x004B00, - 0x004C00, - 0x004D0F, - 0x004E00, - 0x004F11, - 0x005080, - 0x00510A, - 0x005200, - 0x00530E, - 0x0054A6, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D0E, - 0x005EA6, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - 0x006429, - 0x006501, - 0x006622, - 0x00670F, - 0x00681F, - 0x006905, - 0x006A00, - 0x006B64, - 0x006C00, - 0x006D32, - 0x006E00, - 0x006F00, - 0x007000, - 0x007127, - 0x007210, - 0x007303, - 0x007400, - 0x007500, - 0x007600, - 0x007700, - 0x007800, - 0x007900, - 0x007A00, - 0x007B28, - 0x007C00, - 0x007D11, - 0x007E79, - 0x007F7A, - 0x008000, - 0x008101, - 0x008200, - 0x008301, - 0x008401, - 0x008577, - 0x008600, - 0x00872B, - 0x008800, - 0x008928, - 0x008AE5, - 0x008B03, - 0x008C02, - 0x008D00, - 0x008E01, - 0x008F01, - 0x009077, - 0x009101, - 0x009289, - 0x009320, - 0x00950D, - 0x009600, - 0x009701, - 0x00980D, - 0x009929, - 0x009A24, - 0x009B32, - 0x009C01, - //0x009D00, - 0x009E00, - 0x009F00, - 0x00A0FC, - 0x00A132, - 0x00A200, - //0x00A400, - 0x00A500, - 0x00A701, - 0x00B200, - 0x00B400, - 0x00B500, - 0x00B600, - 0x00B700, - 0x00B800, - 0x00B905, - 0x00BA08, - 0x00BB00, - 0x00BC00, - 0x00BD00, - 0x00BE2C, - 0x00BF00, - 0x00C050, - 0x00C100, - 0x00C200, - 0x00C300, - 0x00C400, - 0x00C51D, - 0x00C600, - 0x00C700, - 0x00C81D, - 0x00C900, - 0x00CA00, - 0x00CB00, - 0x00CC15, - 0x00CD00, - 0x00CE00, - 0x00CF15, - 0x00D000, - 0x00D114, - 0x00D200, - 0x00D316, - 0x00D400, - 0x00D514, - 0x00D600, - 0x00D716, - 0x00D80F, - 0x00D900, - 0x00DA00, - 0x00DB19, - 0x00DC6E, - 0x00DD00, - 0x00DE03, - 0x00DF0D, - 0x00E047, - 0x00E100, - 0x00E200, - 0x00E319, - 0x00E46E, - 0x00E500, - 0x00E603, - 0x00E70D, - 0x00E847, - 0x00E90A, - 0x00EA0A, - 0x00EB00, - 0x00ECC3, - 0x00ED50, - 0x00EE00, - 0x00EF00, - 0x00F0C3, - 0x00F150, - 0x00F200, - 0x00F300, - 0x00F400, - 0x00F912, - 0x00FA00, - 0x00FB13, - 0x00FC2C, - 0x00FD00, - 0x00FE00, - 0x00FF00, - 0x010000, - 0x010101, - 0x010200, - 0x010301, - 0x010402, - 0x010580, - 0x010600, - 0x010700, - 0x010800, - 0x010900, - 0x010AC8, - 0x010BA0, - 0x010C0C, - 0x010D0A, - 0x010E02, - 0x010F14, - 0x011000, - 0x011100, - 0x011200, - 0x01130E, - 0x01140C, - 0x01150E, - 0x011609, - 0x011708, - 0x011809, - 0x011907, - 0x011A0D, - 0x011B07, - 0x011C1E, - 0x011D1E, - 0x011E02, - 0x011F30, - 0x012000, - 0x0121EE, - 0x012202, - 0x0123CA, - 0x012409, - 0x012501, - 0x012600, - 0x01272C, - 0x012808, - 0x01290C, - 0x012A08, - 0x012B01, - 0x012C00, - 0x012D1C, - 0x012E20, - 0x012F01, - 0x013001, - 0x013100, - 0x013200, - 0x013300, - 0x013410, - 0x0135AA, - 0x0136AA, - 0x0137AA, - 0x0138AA, - 0x0139AA, - 0x013AFF, - 0x013BFF, - 0x013CFF, - 0x013DFF, - 0x013EFF, - 0x013F03, - 0x014000, - 0x01410A, - 0x014200, - 0x014324, - 0x01449F, - 0x014500, - 0x014600, - 0x014798, - 0x014896, - 0x014980, - 0x014A00, - 0x014B64, - 0x014C00, - 0x014D00, - 0x014E3D, - 0x014F09, - 0x015000, - 0x015100, - 0x015200, - 0x015300, - 0x015400, - 0x015500, - 0x015600, - 0x015700, - 0x015800, - 0x015900, - 0x015A02, - 0x015B00, - 0x015C00, - 0x015D00, - 0x015E00, - 0x015F00, - 0x016000, - 0x016528, - 0x016F00, - 0x019B0C, -#endif -}; - - -static const uint32_t lmk05318_rom[] = { -// 0x000010, -// 0x00010B, -// 0x000235, -// 0x000332, -// 0x000404, -// 0x00050E, -// 0x000617, -// 0x00078E, -// 0x000802, -// 0x000AC8, -// 0x000B00, - 0x000C1B, - 0x000D08, - 0x000E00, - 0x000F00, - 0x001000, - 0x00111D, - 0x0012FF, - 0x001308, - 0x001420, - 0x001500, - 0x001600, - 0x001755, - 0x001855, - 0x001900, - 0x001A00, - 0x001B00, - 0x001C01, - 0x001D13, - 0x001E40, - 0x002044, - 0x002300, - 0x002403, - 0x002500, - 0x002600, - 0x002702, - 0x00280C, - 0x002900, - 0x002A01, - 0x002BE2, - 0x002C00, - 0x002D02, - 0x002E11, - 0x002F07, - 0x003050, - 0x00314A, - 0x003200, - 0x003310, - 0x003410, - 0x003504, - 0x003610, - 0x003710, - 0x003804, - 0x00393E, - 0x003A31, - 0x003B3E, - 0x003C31, - 0x003D3E, - 0x003E31, - 0x003F3E, - 0x004000, - 0x004100, - 0x004200, - 0x004331, - 0x004408, - 0x004500, - 0x004600, - 0x004700, - 0x004833, - 0x004900, - 0x004A00, - 0x004B00, - 0x004C00, - 0x004D0F, - 0x004E00, - 0x004F11, - 0x005080, - 0x00510A, - 0x005200, - 0x005307, - 0x00549E, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D07, - 0x005E9E, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - 0x006429, - 0x006501, - 0x006622, - 0x00670F, - 0x00681F, - 0x006905, - 0x006A00, - 0x006B64, - 0x006C00, - 0x006D60, - 0x006E27, - 0x006F62, - 0x007076, - 0x007127, - 0x007262, - 0x007303, - 0x007401, - 0x007500, - 0x007600, - 0x007700, - 0x007800, - 0x007900, - 0x007A00, - 0x007B28, - 0x007C00, - 0x007D11, - 0x007E79, - 0x007F7A, - 0x008000, - 0x008101, - 0x008200, - 0x008301, - 0x008401, - 0x008577, - 0x008600, - 0x008728, - 0x008800, - 0x00891D, - 0x008A18, - 0x008B03, - 0x008C02, - 0x008D00, - 0x008E01, - 0x008F01, - 0x009077, - 0x009101, - 0x009289, - 0x009320, - 0x00950D, - 0x009600, - 0x009701, - 0x00980D, - 0x009929, - 0x009A24, - 0x009B32, - 0x009C01, - // 0x009D00, - 0x009E00, - 0x009F00, - 0x00A0FC, - 0x00A132, - 0x00A200, - // 0x00A400, - 0x00A500, - 0x00A701, - 0x00B200, - 0x00B400, - 0x00B500, - 0x00B600, - 0x00B700, - 0x00B800, - 0x00B9F5, - 0x00BA01, - 0x00BB00, - 0x00BC00, - 0x00BD00, - 0x00BE00, - 0x00BF00, - 0x00C050, - 0x00C110, - 0x00C200, - 0x00C300, - 0x00C400, - 0x00C51D, - 0x00C600, - 0x00C700, - 0x00C81D, - 0x00C900, - 0x00CA00, - 0x00CB00, - 0x00CC15, - 0x00CD00, - 0x00CE00, - 0x00CF15, - 0x00D000, - 0x00D114, - 0x00D200, - 0x00D316, - 0x00D400, - 0x00D514, - 0x00D600, - 0x00D716, - 0x00D80F, - 0x00D900, - 0x00DA00, - 0x00DB19, - 0x00DC6E, - 0x00DD00, - 0x00DE03, - 0x00DF0D, - 0x00E047, - 0x00E100, - 0x00E200, - 0x00E319, - 0x00E46E, - 0x00E500, - 0x00E603, - 0x00E70D, - 0x00E847, - 0x00E90A, - 0x00EA0A, - 0x00EB01, - 0x00EC8C, - 0x00EDBA, - 0x00EE80, - 0x00EF00, - 0x00F0C3, - 0x00F150, - 0x00F200, - 0x00F33F, - 0x00F400, - 0x00F921, - 0x00FA00, - 0x00FB03, - 0x00FC2D, - 0x00FD00, - 0x00FE00, - 0x00FF00, - 0x010000, - 0x010101, - 0x010200, - 0x010300, - 0x010402, - 0x010580, - 0x010601, - 0x01072A, - 0x010805, - 0x0109F2, - 0x010A00, - 0x010BA0, - 0x010C04, - 0x010D00, - 0x010E02, - 0x010F8C, - 0x011000, - 0x011100, - 0x011200, - 0x011316, - 0x011416, - 0x011516, - 0x011600, - 0x011700, - 0x011800, - 0x011900, - 0x011A00, - 0x011B00, - 0x011C1E, - 0x011D1E, - 0x011E00, - 0x011F00, - 0x012000, - 0x012100, - 0x012203, - 0x012322, - 0x012409, - 0x012501, - 0x012600, - 0x01272C, - 0x012809, - 0x012909, - 0x012A09, - 0x012B01, - 0x012C00, - 0x012D1B, - 0x012E1E, - 0x012F01, - 0x01300F, - 0x013104, - 0x013261, - 0x0133F8, - 0x013443, - 0x0135C3, - 0x0136C3, - 0x0137C3, - 0x0138C3, - 0x0139C3, - 0x013AFF, - 0x013BFF, - 0x013CFF, - 0x013DFF, - 0x013EFF, - 0x013F03, - 0x014000, - 0x01410A, - 0x014200, - 0x014300, - 0x014400, - 0x014501, - 0x014606, - 0x014735, - 0x014875, - 0x01490B, - 0x014A00, - 0x014B64, - 0x014C00, - 0x014D00, - 0x014E3D, - 0x014F09, - 0x015000, - 0x015198, - 0x015296, - 0x015300, - 0x015400, - 0x015500, - 0x015600, - 0x015700, - 0x015800, - 0x015900, - 0x015A02, - 0x015B00, - 0x015C00, - 0x015D00, - 0x015E00, - 0x015F00, - 0x016000, - 0x016528, - 0x016F00, - 0x019B0C, -}; - -static const uint32_t lmk05318_rom_49152_12288_384[] = { -// 0x000010, -// 0x00010B, -// 0x000235, -// 0x000332, -// 0x000404, -// 0x00050E, -// 0x000617, -// 0x00078E, -// 0x000802, -// 0x000AC8, -// 0x000B00, - 0x000C1B, - 0x000D08, - 0x000E00, - 0x000F00, - 0x001000, - 0x00111D, - 0x0012FF, - 0x001308, - 0x001420, - 0x001500, - 0x001600, - 0x001755, - 0x001855, - 0x001900, - 0x001A00, - 0x001B00, - 0x001C01, - 0x001D13, - 0x001E40, - 0x002044, - 0x002300, - 0x002403, - 0x002500, - 0x002600, - 0x002703, - 0x002807, - 0x002900, - 0x002A01, - 0x002BC2, - 0x002C01, - 0x002D02, - 0x002E11, - 0x002F07, - 0x003050, - 0x00314A, - 0x003200, - 0x003380, - 0x003410, - 0x003501, - 0x003690, - 0x003700, - 0x0038FF, - 0x003910, - 0x003A07, - 0x003B90, - 0x003C07, - 0x003D90, - 0x003EFF, - 0x003F90, - 0x004000, - 0x004100, - 0x004200, - 0x004307, - 0x004408, - 0x004500, - 0x004600, - 0x004700, - 0x004833, - 0x004900, - 0x004A00, - 0x004B00, - 0x004C00, - 0x004D0F, - 0x004E00, - 0x004F11, - 0x005080, - 0x00510A, - 0x005200, - 0x005307, - 0x00549E, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D07, - 0x005E9E, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - 0x006428, - 0x006501, - 0x006655, - 0x00670F, - 0x00681F, - 0x006905, - 0x006A00, - 0x006B64, - 0x006C00, - 0x006D60, - 0x006E07, - 0x006FD0, - 0x007000, - 0x007132, - 0x0072C8, - 0x007303, - 0x007400, - 0x007500, - 0x007600, - 0x007700, - 0x007800, - 0x007900, - 0x007A00, - 0x007B28, - 0x007C00, - 0x007D11, - 0x007E79, - 0x007F7A, - 0x008000, - 0x008101, - 0x008200, - 0x008301, - 0x008401, - 0x008577, - 0x008600, - 0x00872A, - 0x008800, - 0x00891C, - 0x008A86, - 0x008B03, - 0x008C02, - 0x008D00, - 0x008E01, - 0x008F01, - 0x009077, - 0x009101, - 0x009289, - 0x009320, - 0x00950D, - 0x009600, - 0x009701, - 0x00980D, - 0x009929, - 0x009A24, - 0x009B32, - 0x009C01, -// 0x009D00, - 0x009E00, - 0x009F00, - 0x00A0FC, - 0x00A132, - 0x00A200, -// 0x00A400, - 0x00A500, - 0x00A701, - 0x00B200, - 0x00B400, - 0x00B500, - 0x00B600, - 0x00B700, - 0x00B800, - 0x00B9F5, - 0x00BA01, - 0x00BB00, - 0x00BC00, - 0x00BD00, - 0x00BE00, - 0x00BF00, - 0x00C050, - 0x00C100, - 0x00C200, - 0x00C300, - 0x00C400, - 0x00C51D, - 0x00C600, - 0x00C700, - 0x00C81D, - 0x00C900, - 0x00CA00, - 0x00CB00, - 0x00CC15, - 0x00CD00, - 0x00CE00, - 0x00CF15, - 0x00D000, - 0x00D114, - 0x00D200, - 0x00D316, - 0x00D400, - 0x00D514, - 0x00D600, - 0x00D716, - 0x00D80F, - 0x00D900, - 0x00DA00, - 0x00DB19, - 0x00DC6E, - 0x00DD00, - 0x00DE03, - 0x00DF0D, - 0x00E047, - 0x00E100, - 0x00E200, - 0x00E319, - 0x00E46E, - 0x00E500, - 0x00E603, - 0x00E70D, - 0x00E847, - 0x00E90A, - 0x00EA0A, - 0x00EB01, - 0x00EC8C, - 0x00EDBA, - 0x00EE80, - 0x00EF00, - 0x00F0C3, - 0x00F150, - 0x00F200, - 0x00F300, - 0x00F400, - 0x00F921, - 0x00FA00, - 0x00FB03, - 0x00FC2C, - 0x00FD00, - 0x00FE00, - 0x00FF00, - 0x010000, - 0x010101, - 0x010200, - 0x010300, - 0x010402, - 0x010580, - 0x010601, - 0x01072A, - 0x010805, - 0x0109F2, - 0x010A00, - 0x010BA0, - 0x010C04, - 0x010D00, - 0x010E02, - 0x010F8C, - 0x011000, - 0x011100, - 0x011200, - 0x011316, - 0x011416, - 0x011516, - 0x011600, - 0x011700, - 0x011800, - 0x011900, - 0x011A00, - 0x011B00, - 0x011C1E, - 0x011D1E, - 0x011E00, - 0x011F00, - 0x012000, - 0x012100, - 0x012203, - 0x012322, - 0x012409, - 0x012501, - 0x012600, - 0x01272C, - 0x012809, - 0x012909, - 0x012A09, - 0x012B01, - 0x012C00, - 0x012D1B, - 0x012E1E, - 0x012F01, - 0x01300F, - 0x013104, - 0x013261, - 0x0133F8, - 0x013443, - 0x0135C3, - 0x0136C3, - 0x0137C3, - 0x0138C3, - 0x0139C3, - 0x013AFF, - 0x013BFF, - 0x013CFF, - 0x013DFF, - 0x013EFF, - 0x013F03, - 0x014000, - 0x01410A, - 0x014200, - 0x014300, - 0x014400, - 0x014501, - 0x014606, - 0x014735, - 0x014875, - 0x01490B, - 0x014A00, - 0x014B64, - 0x014C00, - 0x014D00, - 0x014E3D, - 0x014F09, - 0x015000, - 0x015198, - 0x015296, - 0x015300, - 0x015400, - 0x015500, - 0x015600, - 0x015700, - 0x015800, - 0x015900, - 0x015A02, - 0x015B00, - 0x015C00, - 0x015D00, - 0x015E00, - 0x015F00, - 0x016000, - 0x016528, - 0x016F00, - 0x019B0C, -}; diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index a60cc1a5..12c1e26d 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -9,9 +9,7 @@ #include "lmx1204.h" #include "usdr_logging.h" #include "../cal/opt_func.h" - #include "../common/common.h" -#include "lmx1204_dump.h" #define FREQ_EPS 1.0f @@ -66,76 +64,6 @@ static int lmx1204_spi_get(lmx1204_state_t* obj, uint16_t addr, uint16_t* out) return common_spi_get(obj, MAKE_LMX1204_REG_RD((uint32_t)addr), out); } -int lmx1204_loaddump(lmx1204_state_t* st) -{ - int res = lmx1204_spi_post(st, lmx1204_rom_with_mult, SIZEOF_ARRAY(lmx1204_rom_with_mult)); - if(res) - { - USDR_LOG("1204", USDR_LOG_ERROR, "lmx1204_loaddump() err:%d", res); - } - else - { - USDR_LOG("1204", USDR_LOG_DEBUG, "lmx1204_loaddump() OK"); - } - - st->clk_mux = CLK_MUX_MULTIPLIER_MODE; - - return res; -} - -UNUSED static int lmx1204_read_all_regs(lmx1204_state_t* st) -{ - uint8_t regs[] = - { - R0, - R2, - R3, - R4, - R5, - R6, - R7, - R8, - R9, - R11, - R12, - R13, - R14, - R15, - R16, - R17, - R18, - R19, - R20, - R21, - R22, - R23, - R24, - R25, - R28, - R29, - R33, - R34, - R65, - R67, - R72, - R75, - R79, - R86, - R90, - }; - - for(unsigned i = 0; i < SIZEOF_ARRAY(regs); ++i) - { - uint16_t regval; - int res = lmx1204_spi_get(st, regs[i], ®val); - if(res) - return res; - USDR_LOG("1204", USDR_LOG_DEBUG, "READ R%02u = 0x%04x", regs[i], regval); - } - - return 0; -} - int lmx1204_reset_main_divider(lmx1204_state_t* st, bool set_flag) { uint16_t r25; @@ -746,15 +674,7 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) MAKE_LMX1204_R16(0x1, st->sysref_div), //0x1 == sysref pulse count MAKE_LMX1204_R15(0, st->sysref_div_pre, 0x3, st->sysref_en ? 1 : 0, 0, 0), MAKE_LMX1204_R13(0, lmx1204_get_delay_step_size(st)), -/* - //according do doc: program R79 and R90 before setting logiclk_div_bypass - //desc order is broken here! - MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->ch_en[LMX1204_CH_LOGIC] ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), - MAKE_LMX1204_R79(0, st->logiclk_div_bypass ? 0x5 : 0x104), - MAKE_LMX1204_REG_WR(R90, st->logiclk_div_bypass ? 0x60 : 0x00), - MAKE_LMX1204_R9(0, 0, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), - // -*/ + MAKE_LMX1204_R9(0, 0, 0, st->logiclk_div_bypass ? 1 : 0, 0, st->logiclk_div), MAKE_LMX1204_R8(0, st->logiclk_div_pre, 1, st->ch_en[LMX1204_CH_LOGIC] ? 1 : 0, st->logisysrefout_fmt, st->logiclkout_fmt), MAKE_LMX1204_R7(0, 0, 0, 0, 0, 0, 0, st->sysrefout_en[LMX1204_CH_LOGIC] ? 1 : 0), diff --git a/src/lib/hw/lmx1204/lmx1204.h b/src/lib/hw/lmx1204/lmx1204.h index a9e3d908..b9b1c654 100644 --- a/src/lib/hw/lmx1204/lmx1204.h +++ b/src/lib/hw/lmx1204/lmx1204.h @@ -115,6 +115,4 @@ int lmx1204_sysref_windowing_beforesync(lmx1204_state_t* st); int lmx1204_sysref_windowing_capture(lmx1204_state_t* st); int lmx1204_sysref_windowing_aftersync(lmx1204_state_t* st); -int lmx1204_loaddump(lmx1204_state_t* st); - #endif // LMX1204_H diff --git a/src/lib/hw/lmx1204/lmx1204_dump.h b/src/lib/hw/lmx1204/lmx1204_dump.h deleted file mode 100644 index b9300bbd..00000000 --- a/src/lib/hw/lmx1204/lmx1204_dump.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef LMX1204_DUMP_H -#define LMX1204_DUMP_H - -#include - -static uint32_t lmx1204_rom_with_mult[] = -{ - //1GHz input, 4GHz outclk, 3.125M refclk, 125M logiclk - - /*R90*/ 0x5A0000, - /*R86*/ 0x560004, - /*R79*/ 0x4F0005, - /*R76*/ 0x4C0000, - /*R75*/ 0x4B0003, - /*R72*/ 0x480000, - /*R67*/ 0x4351CB, - /*R65*/ 0x416410, - /*R34*/ 0x220005, - /*R33*/ 0x216666, - /*R29*/ 0x1D05FF, - ///*R28*/ 0x1C0A08, - /*R25*/ 0x190223, - /*R24*/ 0x180001, - /*R23*/ 0x17E040, - /*R22*/ 0x160078, - /*R21*/ 0x150EF8, - /*R20*/ 0x140EF8, - /*R19*/ 0x130EF8, - /*R18*/ 0x120EF8, - /*R17*/ 0x110074, - /*R16*/ 0x101140, - /*R15*/ 0x0F0380, - /*R14*/ 0x0E0002, - /*R13*/ 0x0D0000, - /*R12*/ 0x0C0000, - /*R11*/ 0x0B0000, - /*R9 */ 0x090004, - /*R8 */ 0x0800B0, - /*R7 */ 0x070001, - /*R6 */ 0x06C924, - /*R5 */ 0x054936, - /*R4 */ 0x0436FF, - /*R3 */ 0x03FF85, - /*R2 */ 0x0200A3, - /*R0 */ 0x000000, -}; - - -static uint32_t lmx1204_rom_test[] = -{ - //500M inputs, 500M outclk, 3.125M refclk, 125M logiclk - - /*R90*/ 0x5A0000, - /*R86*/ 0x560004, - /*R79*/ 0x4F0005, - /*R76*/ 0x4C0000, - /*R75*/ 0x4B0003, - /*R72*/ 0x480000, - /*R67*/ 0x4351CB, - /*R65*/ 0x416410, - /*R34*/ 0x220005, - /*R33*/ 0x216666, - /*R29*/ 0x1D05FF, - /*R28*/ 0x1C0A08, - /*R25*/ 0x190221, - /*R24*/ 0x180001, - /*R23*/ 0x17E055, - /*R22*/ 0x165078, - /*R21*/ 0x150EF8, - /*R20*/ 0x140EF8, - /*R19*/ 0x130EF8, - /*R18*/ 0x120EF8, - /*R17*/ 0x110074, - /*R16*/ 0x1010A0, - /*R15*/ 0x0F0380, - /*R14*/ 0x0E0002, - /*R13*/ 0x0D0000, - /*R12*/ 0x0C0000, - /*R11*/ 0x0B0000, - /*R9 */ 0x090002, - /*R8 */ 0x0800B0, - /*R7 */ 0x070001, - /*R6 */ 0x06C924, - /*R5 */ 0x054936, - /*R4 */ 0x0436FF, - /*R3 */ 0x03FF85, - /*R2 */ 0x020083, - /*R0 */ 0x000000, -}; - -#endif // LMX1204_DUMP_H diff --git a/src/lib/hw/lmx1214/lmx1214.c b/src/lib/hw/lmx1214/lmx1214.c index 3dff6480..5dea8159 100644 --- a/src/lib/hw/lmx1214/lmx1214.c +++ b/src/lib/hw/lmx1214/lmx1214.c @@ -10,8 +10,6 @@ #include "usdr_logging.h" #include "../common/common.h" -#include "lmx1214_dump.h" - #define FREQ_EPS 1.0f enum @@ -92,20 +90,6 @@ UNUSED static int lmx1214_read_all_regs(lmx1214_state_t* st) return 0; } -int lmx1214_loaddump(lmx1214_state_t* st) -{ - int res = lmx1214_spi_post(st, lmx1214_rom_test, SIZEOF_ARRAY(lmx1214_rom_test)); - if(res) - { - USDR_LOG("1214", USDR_LOG_ERROR, "lmx1214_loaddump() err:%d", res); - } - else - { - USDR_LOG("1214", USDR_LOG_DEBUG, "lmx1214_loaddump() OK"); - } - return res; -} - int lmx1214_get_temperature(lmx1214_state_t* st, float* value) { if(!value) diff --git a/src/lib/hw/lmx1214/lmx1214.h b/src/lib/hw/lmx1214/lmx1214.h index a02d0001..b4aeba6a 100644 --- a/src/lib/hw/lmx1214/lmx1214.h +++ b/src/lib/hw/lmx1214/lmx1214.h @@ -61,6 +61,4 @@ int lmx1214_sysref_windowing_beforesync(lmx1214_state_t* st); int lmx1214_sysref_windowing_capture(lmx1214_state_t* st); int lmx1214_sysref_windowing_aftersync(lmx1214_state_t* st); -int lmx1214_loaddump(lmx1214_state_t* st); - #endif // LMX1214_H diff --git a/src/lib/hw/lmx1214/lmx1214_dump.h b/src/lib/hw/lmx1214/lmx1214_dump.h deleted file mode 100644 index 5ef3e05c..00000000 --- a/src/lib/hw/lmx1214/lmx1214_dump.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef LMX1214_DUMP_H -#define LMX1214_DUMP_H - -#include - -static uint32_t lmx1214_rom_test[] = -{ - /*R90*/ 0x5A0060, - /*R86*/ 0x560000, - /*R79*/ 0x4F0005, - /*R75*/ 0x4B0006, - /*R25*/ 0x190209, - /*R24*/ 0x180001, - /*R23*/ 0x17E040, - /*R15*/ 0x0F0B00, - /*R14*/ 0x0E0002, - /*R13*/ 0x0D0003, - /*R12*/ 0x0C0000, - /*R11*/ 0x0B0000, - /*R9 */ 0x092802, - /*R8 */ 0x080050, - /*R7 */ 0x07543F, - /*R5 */ 0x0536F6, - /*R4 */ 0x0436FF, - /*R3 */ 0x03FF86, - /*R2 */ 0x020223, - /*R0 */ 0x000000, -}; - -#endif // LMX1214_DUMP_H diff --git a/src/lib/hw/lmx2820/lmx2820.c b/src/lib/hw/lmx2820/lmx2820.c index 69756e4d..c05c2cb1 100644 --- a/src/lib/hw/lmx2820/lmx2820.c +++ b/src/lib/hw/lmx2820/lmx2820.c @@ -10,8 +10,6 @@ #include "def_lmx2820.h" #include #include "../cal/opt_func.h" - -#include "lmx2820_dump.h" #include "../common/common.h" enum { @@ -209,14 +207,7 @@ int lmx2820_sync(lmx2820_state_t* st) return lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); } -//#define LMX2820_RESET_SKIP - int lmx2820_reset(lmx2820_state_t* st) -#ifdef LMX2820_RESET_SKIP -{ - return 0; -} -#else { uint16_t r0; @@ -237,7 +228,6 @@ int lmx2820_reset(lmx2820_state_t* st) usleep(10000); //reset takes <1us return 0; } -#endif static int lmx2820_calibrate(lmx2820_state_t* st, bool set_flag) { @@ -341,20 +331,6 @@ int lmx2820_read_status(lmx2820_state_t* st, lmx2820_stats_t* status) return 0; } -UNUSED static int lmx2820_loaddump(lmx2820_state_t* st) -{ - int res = lmx2820_spi_post(st, lmx2820_rom_sysref, SIZEOF_ARRAY(lmx2820_rom_sysref)); - if(res) - { - USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_loaddump() err:%d", res); - } - else - { - USDR_LOG("2820", USDR_LOG_DEBUG, "lmx2820_loaddump() OK"); - } - return res; -} - int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_t* st) { memset(st, 0, sizeof(*st)); @@ -369,7 +345,6 @@ int lmx2820_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx2820_state_ if(res) return res; - //this list is incompleted uint32_t regs[] = { MAKE_LMX2820_R19(0x109, TEMPSENSE_EN_ENABLED, 0x0), //enable temperature sensor @@ -900,13 +875,7 @@ static int lmx2820_calculate_systef_chain(lmx2820_state_t* st) sr->srout_fact = fvco / sr->div_pre / sr->div / 4; lmx2820_fill_jesd(); - /* - for(unsigned i = 0; i < JESD_SIZE; ++i) - { - USDR_LOG("2820", USDR_LOG_DEBUG, "PHASE_SHIFT:%03u -> DAC1_CTRL:%02u DAC2_CTRL:%02u DAC3_CTRL:%02u DAC4_CTRL:%02u", - i, JESD[i].DAC1_CTRL, JESD[i].DAC2_CTRL, JESD[i].DAC3_CTRL, JESD[i].DAC4_CTRL); - } - */ + double delay_per_inc = (double)sr->div_pre / 126.0 / fvco; sr->delay = delay_per_inc * sr->delay_ctrl; @@ -1178,27 +1147,16 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned MAKE_LMX2820_R0 (1, 1, 0, HP_fd_adj, LP_fd_adj, DBLR_CAL_EN_ENABLED, 1, FCAL_EN_ENABLED, 0, RESET_NORMAL_OPERATION, POWERDOWN_NORMAL_OPERATION) }; -#if 1 res = lmx2820_spi_post(st, regs, SIZEOF_ARRAY(regs)); if(res) { USDR_LOG("2820", USDR_LOG_ERROR, "Registers set lmx2820_spi_post() failed, err:%d", res); return res; } -#else - lmx2820_loaddump(st); -#endif //Wait 10 ms to allow the internal LDOs to power up. usleep(10000); -/* - res = lmx2820_calibrate(st, true); - if(res) - { - USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_calibrate(1) failed, err:%d", res); - return res; - } -*/ + res = lmx2820_wait_pll_lock(st, 1000000); if(res) { @@ -1206,14 +1164,7 @@ static int lmx2820_tune_internal(lmx2820_state_t* st, uint64_t osc_in, unsigned res, (res == -ETIMEDOUT ? "TIMEOUT" : "ERROR")); return res; } -/* - res = lmx2820_sync(st); - if(res) - { - USDR_LOG("2820", USDR_LOG_ERROR, "lmx2820_sync() failed, err:%d", res); - return res; - } -*/ + if(use_instcal) { res = lmx2820_calibrate(st, false); diff --git a/src/lib/hw/lmx2820/lmx2820_dump.h b/src/lib/hw/lmx2820/lmx2820_dump.h deleted file mode 100644 index 1054a771..00000000 --- a/src/lib/hw/lmx2820/lmx2820_dump.h +++ /dev/null @@ -1,263 +0,0 @@ -#ifndef LMX2820_DUMP_H -#define LMX2820_DUMP_H - -#include - -static uint32_t lmx2820_rom_sysref[] = -{ - // osc_in = 150M out_a = out_b = 1G sr_out = 25M - // - /*R122*/ 0x7A0000, - /*R121*/ 0x790000, - /*R120*/ 0x780000, - /*R119*/ 0x770000, - /*R118*/ 0x760000, - /*R117*/ 0x750000, - /*R116*/ 0x740000, - /*R115*/ 0x730000, - /*R114*/ 0x720000, - /*R113*/ 0x710000, - /*R112*/ 0x70FFFF, - /*R111*/ 0x6F0000, - /*R110*/ 0x6E001F, - /*R109*/ 0x6D0000, - /*R108*/ 0x6C0000, - /*R107*/ 0x6B0000, - /*R106*/ 0x6A0000, - /*R105*/ 0x69000A, - /*R104*/ 0x680014, - /*R103*/ 0x670014, - /*R102*/ 0x660028, - /*R101*/ 0x6503E8, - /*R100*/ 0x640533, - /*R99 */ 0x6319B9, - /*R98 */ 0x621C80, - /*R97 */ 0x610000, - /*R96 */ 0x6017F8, - /*R95 */ 0x5F0000, - /*R94 */ 0x5E0000, - /*R93 */ 0x5D1000, - /*R92 */ 0x5C0000, - /*R91 */ 0x5B0000, - /*R90 */ 0x5A0000, - /*R89 */ 0x590000, - /*R88 */ 0x5803FF, - /*R87 */ 0x57FF00, - /*R86 */ 0x560040, - /*R85 */ 0x550000, - /*R84 */ 0x540040, - /*R83 */ 0x530F00, - /*R82 */ 0x520000, - /*R81 */ 0x510000, - /*R80 */ 0x5001C0, - /*R79 */ 0x4F000E, - /*R78 */ 0x4E0000, - /*R77 */ 0x4D0608, - /*R76 */ 0x4C0000, - /*R75 */ 0x4B0000, - /*R74 */ 0x4A0000, - /*R73 */ 0x490000, - /*R72 */ 0x480000, - /*R71 */ 0x470000, - /*R70 */ 0x46000E, - /*R69 */ 0x450001, - /*R68 */ 0x440000, - /*R67 */ 0x431000, - /*R66 */ 0x42003F, - /*R65 */ 0x410008, - /*R64 */ 0x400284, - /*R63 */ 0x3FC350, - /*R62 */ 0x3E0000, - /*R61 */ 0x3D03E8, - /*R60 */ 0x3C01F4, - /*R59 */ 0x3B1388, - /*R58 */ 0x3A0000, - /*R57 */ 0x390001, - /*R56 */ 0x380001, - /*R55 */ 0x370002, - /*R54 */ 0x360000, - /*R53 */ 0x350000, - /*R52 */ 0x340000, - /*R51 */ 0x33203F, - /*R50 */ 0x320080, - /*R49 */ 0x310000, - /*R48 */ 0x304180, - /*R47 */ 0x2F0300, - /*R46 */ 0x2E0300, - /*R45 */ 0x2D0000, - /*R44 */ 0x2C8000, - /*R43 */ 0x2B0002, - /*R42 */ 0x2A0000, - /*R41 */ 0x290000, - /*R40 */ 0x280000, - /*R39 */ 0x270003, - /*R38 */ 0x260000, - /*R37 */ 0x250500, - /*R36 */ 0x24001A, - /*R35 */ 0x233100, - /*R34 */ 0x220010, - /*R33 */ 0x210000, - /*R32 */ 0x201481, - /*R31 */ 0x1F0401, - /*R30 */ 0x1EB18C, - /*R29 */ 0x1D318C, - /*R28 */ 0x1C0639, - /*R27 */ 0x1B8001, - /*R26 */ 0x1A0DB0, - /*R25 */ 0x190624, - /*R24 */ 0x180E34, - /*R23 */ 0x171102, - /*R22 */ 0x16E2BF, - /*R21 */ 0x151C64, - /*R20 */ 0x14272C, - /*R19 */ 0x132120, - /*R18 */ 0x120000, - /*R17 */ 0x1115C0, - /*R16 */ 0x10171C, - /*R15 */ 0x0F2001, - /*R14 */ 0x0E3001, - /*R13 */ 0x0D0038, - /*R12 */ 0x0C0408, - /*R11 */ 0x0B0612, - /*R10 */ 0x0A0000, - /*R9 */0x090005, - /*R8 */0x08C802, - /*R7 */0x070000, - /*R6 */0x060A43, - /*R5 */0x050032, - /*R4 */0x044204, - /*R3 */0x030041, - /*R2 */0x0283E8, - /*R1 */0x01D7A0, - /*R0 */0x006630, -}; - - -static uint32_t lmx2820_rom_test[] = -{ - /*R122*/ 0x7A0000, - /*R121*/ 0x790000, - /*R120*/ 0x780000, - /*R119*/ 0x770000, - /*R118*/ 0x760000, - /*R117*/ 0x750000, - /*R116*/ 0x740000, - /*R115*/ 0x730000, - /*R114*/ 0x720000, - /*R113*/ 0x710000, - /*R112*/ 0x70FFFF, - /*R111*/ 0x6F0000, - /*R110*/ 0x6E001F, - /*R109*/ 0x6D0000, - /*R108*/ 0x6C0000, - /*R107*/ 0x6B0000, - /*R106*/ 0x6A0000, - /*R105*/ 0x69000A, - /*R104*/ 0x680014, - /*R103*/ 0x670014, - /*R102*/ 0x660028, - /*R101*/ 0x6503E8, - /*R100*/ 0x640533, - /*R99*/ 0x6319B9, - /*R98*/ 0x621C80, - /*R97*/ 0x610000, - /*R96*/ 0x6017F8, - /*R95*/ 0x5F0000, - /*R94*/ 0x5E0000, - /*R93*/ 0x5D1000, - /*R92*/ 0x5C0000, - /*R91*/ 0x5B0000, - /*R90*/ 0x5A0000, - /*R89*/ 0x590000, - /*R88*/ 0x5803FF, - /*R87*/ 0x57FF00, - /*R86*/ 0x560040, - /*R85*/ 0x550000, - /*R84*/ 0x540040, - /*R83*/ 0x530F00, - /*R82*/ 0x520000, - /*R81*/ 0x510000, - /*R80*/ 0x5001C0, - /*R79*/ 0x4F000E, - /*R78*/ 0x4E0000, - /*R77*/ 0x4D0608, - /*R76*/ 0x4C0000, - /*R75*/ 0x4B0000, - /*R74*/ 0x4A0000, - /*R73*/ 0x490000, - /*R72*/ 0x480000, - /*R71*/ 0x470000, - /*R70*/ 0x46000E, - /*R69*/ 0x450011, - /*R68*/ 0x440020, - /*R67*/ 0x431000, - /*R66*/ 0x42003F, - /*R65*/ 0x410000, - /*R64*/ 0x400080, - /*R63*/ 0x3FC350, - /*R62*/ 0x3E0000, - /*R61*/ 0x3D03E8, - /*R60*/ 0x3C01F4, - /*R59*/ 0x3B1388, - /*R58*/ 0x3A0000, - /*R57*/ 0x390001, - /*R56*/ 0x380001, - /*R55*/ 0x370002, - /*R54*/ 0x360000, - /*R53*/ 0x350000, - /*R52*/ 0x340000, - /*R51*/ 0x33203F, - /*R50*/ 0x320080, - /*R49*/ 0x310000, - /*R48*/ 0x304180, - /*R47*/ 0x2F0300, - /*R46*/ 0x2E0300, - /*R45*/ 0x2D51EC, - /*R44*/ 0x2C1EB8, - /*R43*/ 0x2B0003, - /*R42*/ 0x2A0000, - /*R41*/ 0x290000, - /*R40*/ 0x280000, - /*R39*/ 0x270019, - /*R38*/ 0x260000, - /*R37*/ 0x250500, - /*R36*/ 0x240025, - /*R35*/ 0x233100, - /*R34*/ 0x220010, - /*R33*/ 0x210000, - /*R32*/ 0x201AC1, - /*R31*/ 0x1F0401, - /*R30*/ 0x1EB18C, - /*R29*/ 0x1D318C, - /*R28*/ 0x1C0639, - /*R27*/ 0x1B8001, - /*R26*/ 0x1A0DB0, - /*R25*/ 0x190624, - /*R24*/ 0x180E34, - /*R23*/ 0x171102, - /*R22*/ 0x16E2BF, - /*R21*/ 0x151C64, - /*R20*/ 0x14272C, - /*R19*/ 0x132120, - /*R18*/ 0x120000, - /*R17*/ 0x1115C0, - /*R16*/ 0x10171C, - /*R15*/ 0x0F2001, - /*R14*/ 0x0E3002, - /*R13*/ 0x0D0038, - /*R12*/ 0x0C0408, - /*R11*/ 0x0B0612, - /*R10*/ 0x0A0000, - /*R9*/ 0x090005, - /*R8*/ 0x08C802, - /*R7*/ 0x070000, - /*R6*/ 0x060A43, - /*R5*/ 0x050032, - /*R4*/ 0x044204, - /*R3*/ 0x030041, - /*R2*/ 0x0291F4, - /*R1*/ 0x0157A2, - /*R0*/ 0x006670, -}; - -#endif // LMX2820_DUMP_H From 1dfd824d2dcdb7d9ec491220f0518b9c4b872942 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 19 May 2025 21:17:43 +0300 Subject: [PATCH 129/397] cleaning before merge [2] --- .../device/ext_simplesync/ext_simplesync.c | 2 +- src/lib/device/pe_sync/pe_sync.c | 3 +- src/lib/hw/lmk05318/lmk05318.c | 12 ++-- src/lib/hw/lmk05318/lmk05318.h | 12 ++-- src/utests/lmk05318_solver_test.c | 68 +++++-------------- src/utests/lmx1204_solver_test.c | 8 +-- src/utests/lmx1214_solver_test.c | 12 ++-- src/utests/lmx2820_solver_test.c | 5 +- src/utests/test_suite.c | 4 -- 9 files changed, 41 insertions(+), 85 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 4f4b3ff7..0fb15e09 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -97,7 +97,7 @@ int board_ext_simplesync_init(lldev_t dev, lmk05318_dpll_settings_t dpll; dpll.enabled = false; - res = lmk05318_create_ex(dev, subdev, i2ca, &xo, &dpll, cfg, 4, &ob->lmk, false /*dry_run*/); + res = lmk05318_create(dev, subdev, i2ca, &xo, &dpll, cfg, 4, &ob->lmk, false /*dry_run*/); res = res ? res : lmk05318_reset_los_flags(&ob->lmk); res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index a8dcaafe..26a8b24f 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -266,7 +266,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const // OUT5: LVDS OFF 156.250 Mhz | OFF by default // OUT6: Dual CMOS 10.000 Mhz // OUT7: Dual CMOS 1 Hz - // res = res ? res : lmk05318_create() if(res) return res; @@ -309,7 +308,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, lmk_freq[6], false, LVCMOS); res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, lmk_freq[7], false, LVCMOS); - res = res ? res : lmk05318_create_ex(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); + res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); if(res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index cb5df253..cb853306 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -774,10 +774,10 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett return lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); } -int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, - const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, - lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, - lmk05318_state_t* out, bool dry_run) +int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, + const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, + lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, + lmk05318_state_t* out, bool dry_run) { int res; uint8_t dummy[4] = {0,0,0,0}; @@ -1239,7 +1239,7 @@ static inline const char* lmk05318_decode_fmt(unsigned f) return "UNKNOWN"; } -static int lmk05318_set_out_mux_ex(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) +static int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) { unsigned ot; switch (otype) { @@ -2025,7 +2025,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned USDR_LOG("5318", USDR_LOG_DEBUG, "OUT%u port:%u div:%" PRIu64 " fmt:%u(%s)", i, out->port, out->result.out_div, out->wanted.type, lmk05318_decode_fmt(out->wanted.type)); - res = lmk05318_set_out_mux_ex(d, out->port, out->result.mux, out->wanted.type); + res = lmk05318_set_out_mux(d, out->port, out->result.mux, out->wanted.type); res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); if(res) { diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index b1c59d2f..1a07126d 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -192,9 +192,6 @@ static inline int lmk05318_set_port_affinity(lmk05318_out_config_t* cfg, unsigne return 0; } -int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t div); -int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, bool pll1, unsigned otype); - enum lock_msk { LMK05318_LOS_XO = 1, LMK05318_LOL_PLL1 = 2, @@ -206,6 +203,7 @@ enum lock_msk { LMK05318_BAW_LOCK = 64, }; +int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t div); int lmk05318_sync(lmk05318_state_t* out); int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask); int lmk05318_reset_los_flags(lmk05318_state_t* d); @@ -223,10 +221,10 @@ int lmk05318_tune_apll1(lmk05318_state_t* d); int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs); -int lmk05318_create_ex(lldev_t dev, unsigned subdev, unsigned lsaddr, - const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, - lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, - lmk05318_state_t* out, bool dry_run); +int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, + const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, + lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, + lmk05318_state_t* out, bool dry_run); int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll); int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index d1079c97..01a81bf4 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -6,6 +6,8 @@ static lmk05318_out_config_t cfg[OUTS_LEN]; static lmk05318_state_t dev; +void lmk05318_registers_map_reset(); + static void setup() { memset(cfg, 0, sizeof(cfg)); @@ -24,6 +26,8 @@ static void setup() res = res ? res : lmk05318_port_request(cfg, 6, 491520000, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 7, 1, true, OUT_OFF); ck_assert_int_eq( res, 0 ); + + lmk05318_registers_map_reset(); } static void teardown() @@ -32,26 +36,11 @@ static void teardown() START_TEST(lmk05318_solver_test1) { + lmk05318_registers_map_reset(); int res = lmk05318_solver(&dev, cfg, OUTS_LEN); ck_assert_int_eq( res, 0 ); } -START_TEST(lmk05318_solver_test2) -{ - int res = 0; - const uint64_t f = 5650000000ull; - - res = res ? res : lmk05318_port_request(cfg, 2, f/7/256, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, f/7/256, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, f/2/4, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, f/7/17, false, OUT_OFF); - ck_assert_int_eq( res, 0 ); - - res = lmk05318_solver(&dev, cfg, OUTS_LEN); - ck_assert_int_eq( res, 0 ); -} - - START_TEST(lmk05318_solver_test3) { uint64_t fvco1 = 2500000000ull; @@ -79,6 +68,7 @@ START_TEST(lmk05318_solver_test3) res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); ck_assert_int_eq( res, 0 ); + lmk05318_registers_map_reset(); res = lmk05318_solver(&dev, cfg, OUTS_LEN); ck_assert_int_eq( res, 0 ); } @@ -94,11 +84,9 @@ START_TEST(lmk05318_solver_test4) int res = 0; res = res ? res : lmk05318_port_request(cfg, 0, f0_3, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 1, f0_3, false, OUT_OFF); - //res = res ? res : lmk05318_port_request(cfg, 2, f0_3, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 3, f0_3, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 4, f4_7, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 5, f4_7, false, OUT_OFF); - //res = res ? res : lmk05318_port_request(cfg, 6, f4_7, false, OUT_OFF); res = res ? res : lmk05318_port_request(cfg, 7, f4_7, false, OUT_OFF); ck_assert_int_eq( res, 0 ); @@ -112,29 +100,17 @@ START_TEST(lmk05318_solver_test4) res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); ck_assert_int_eq( res, 0 ); + lmk05318_registers_map_reset(); res = lmk05318_solver(&dev, cfg, 4); ck_assert_int_eq( res, 0 ); + lmk05318_registers_map_reset(); res = lmk05318_solver(&dev, cfg + 4, 4); ck_assert_int_eq( res, 0 ); } START_TEST(lmk05318_solver_test5) { -/* // TODO: Initialize LMK05318B - // XO: 25Mhz - // - // OUT0: LVDS 125.000 Mhz - // OUT1: LVDS 125.000 Mhz - // OUT2: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 - // OUT3: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 - // OUT4: LVDS OFF 156.250 Mhz | OFF by default - // OUT5: LVDS OFF 156.250 Mhz | OFF by default - // OUT6: Dual CMOS 10.000 Mhz - // OUT7: Dual CMOS 1 Hz - // res = res ? res : lmk05318_create() - */ - int res = 0; res = res ? res : lmk05318_port_request(cfg, 0, 125000000, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 1, 125000000, false, LVDS); @@ -146,6 +122,7 @@ START_TEST(lmk05318_solver_test5) res = res ? res : lmk05318_port_request(cfg, 7, 1, false, LVCMOS); ck_assert_int_eq( res, 0 ); + lmk05318_registers_map_reset(); res = lmk05318_solver(&dev, cfg, OUTS_LEN); ck_assert_int_eq( res, 0 ); @@ -153,20 +130,6 @@ START_TEST(lmk05318_solver_test5) START_TEST(lmk05318_solver_test6) { - /* // TODO: Initialize LMK05318B - // XO: 25Mhz - // - // OUT0: LVDS 125.000 Mhz - // OUT1: LVDS 125.000 Mhz - // OUT2: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 - // OUT3: LVDS 250.000 Mhz MASH_ORD 0/1/2 | 156.250 Mhz MASH_ORD 3 - // OUT4: LVDS OFF 156.250 Mhz | OFF by default - // OUT5: LVDS OFF 156.250 Mhz | OFF by default - // OUT6: Dual CMOS 10.000 Mhz - // OUT7: Dual CMOS 1 Hz - // res = res ? res : lmk05318_create() - */ - int res = 0; res = res ? res : lmk05318_port_request(cfg, 0, 125000000, false, LVDS); res = res ? res : lmk05318_port_request(cfg, 1, 125000000, false, LVDS); @@ -197,7 +160,7 @@ START_TEST(lmk05318_solver_test6) lmk05318_state_t st; memset(&st, 0, sizeof(st)); - res = lmk05318_create_ex(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } @@ -210,6 +173,9 @@ START_TEST(lmk05318_dpll_test1) dpll.enabled = true; dpll.en[LMK05318_PRIREF] = true; dpll.fref[LMK05318_PRIREF] = 1; + dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; + dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; + dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; int res = lmk05318_dpll_config(&dev, &dpll); ck_assert_int_eq( res, 0 ); @@ -224,15 +190,13 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); -/* + tcase_add_test(tc_core, lmk05318_solver_test1); - ////////tcase_add_test(tc_core, lmk05318_solver_test2); tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); tcase_add_test(tc_core, lmk05318_solver_test5); -*/ tcase_add_test(tc_core, lmk05318_solver_test6); - - //tcase_add_test(tc_core, lmk05318_dpll_test1); + tcase_add_test(tc_core, lmk05318_solver_test6); + tcase_add_test(tc_core, lmk05318_dpll_test1); suite_add_tcase(s, tc_core); return s; diff --git a/src/utests/lmx1204_solver_test.c b/src/utests/lmx1204_solver_test.c index b86ecf0c..7bb4b6fc 100644 --- a/src/utests/lmx1204_solver_test.c +++ b/src/utests/lmx1204_solver_test.c @@ -126,10 +126,10 @@ Suite * lmx1204_solver_suite(void) tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - //tcase_add_test(tc_core, lmx1204_solver_test1); - //tcase_add_test(tc_core, lmx1204_solver_test2); - //tcase_add_test(tc_core, lmx1204_solver_test3); - //tcase_add_test(tc_core, lmx1204_solver_test4); + tcase_add_test(tc_core, lmx1204_solver_test1); + tcase_add_test(tc_core, lmx1204_solver_test2); + tcase_add_test(tc_core, lmx1204_solver_test3); + tcase_add_test(tc_core, lmx1204_solver_test4); tcase_add_test(tc_core, lmx1204_solver_test5); suite_add_tcase(s, tc_core); diff --git a/src/utests/lmx1214_solver_test.c b/src/utests/lmx1214_solver_test.c index deff490d..0f65f122 100644 --- a/src/utests/lmx1214_solver_test.c +++ b/src/utests/lmx1214_solver_test.c @@ -126,12 +126,12 @@ Suite * lmx1214_solver_suite(void) tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); -// tcase_add_test(tc_core, lmx1214_solver_test1); -// tcase_add_test(tc_core, lmx1214_solver_test2); -// tcase_add_test(tc_core, lmx1214_solver_test3); -// tcase_add_test(tc_core, lmx1214_solver_test4_pesync0); -// tcase_add_test(tc_core, lmx1214_solver_test4_pesync1); -// tcase_add_test(tc_core, lmx1214_solver_test4_pesync2); + tcase_add_test(tc_core, lmx1214_solver_test1); + tcase_add_test(tc_core, lmx1214_solver_test2); + tcase_add_test(tc_core, lmx1214_solver_test3); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync0); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync1); + tcase_add_test(tc_core, lmx1214_solver_test4_pesync2); tcase_add_test(tc_core, lmx1214_solver_test4_pesync3); suite_add_tcase(s, tc_core); diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index e636c599..f3655069 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -159,7 +159,7 @@ START_TEST(lmx2820_solver_test13_pesync) START_TEST(lmx2820_solver_test14_pesync) { - const uint64_t osc_in = 250000000ull; + const uint64_t osc_in = 25000000ull; const int mash_order = 2; uint64_t out_freq1 = 4000000000ull; uint64_t out_freq2 = 4000000000ull; @@ -183,7 +183,7 @@ Suite * lmx2820_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); -/* + tcase_add_test(tc_core, lmx2820_solver_test1); tcase_add_test(tc_core, lmx2820_solver_test2); tcase_add_test(tc_core, lmx2820_solver_test3); @@ -197,7 +197,6 @@ Suite * lmx2820_solver_suite(void) tcase_add_loop_test(tc_core, lmx2820_solver_test11_mash_order, 1, 4); tcase_add_test(tc_core, lmx2820_solver_test12_instcal); tcase_add_test(tc_core, lmx2820_solver_test13_pesync); -*/ tcase_add_test(tc_core, lmx2820_solver_test14_pesync); suite_add_tcase(s, tc_core); diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index b5239091..eb1f4209 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -29,7 +29,6 @@ int main(int argc, char** argv) usdrlog_setlevel(NULL, (argc > 1) ? USDR_LOG_TRACE : USDR_LOG_INFO); usdrlog_enablecolorize(NULL); -#if 0 sr = srunner_create(ring_buffer_suite()); srunner_add_suite(sr, trig_suite()); srunner_add_suite(sr, clockgen_suite()); @@ -37,9 +36,6 @@ int main(int argc, char** argv) srunner_add_suite(sr, lmx2820_solver_suite()); srunner_add_suite(sr, lmx1214_solver_suite()); srunner_add_suite(sr, lmx1204_solver_suite()); -#else - sr = srunner_create(lmx2820_solver_suite()); -#endif srunner_set_fork_status (sr, CK_NOFORK); From 34f414d9354810c6e3fb389c50247fe31d16bc6b Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 19 May 2025 22:52:41 +0300 Subject: [PATCH 130/397] cleaning before merge [3] + simplesync/dsdr --- .../device/ext_simplesync/ext_simplesync.c | 8 +- src/lib/device/m2_dsdr/m2_dsdr.c | 87 +++++++++++++++---- src/lib/device/pe_sync/pe_sync.c | 2 +- src/utests/lmk05318_solver_test.c | 78 +++++++++++++++++ 4 files changed, 156 insertions(+), 19 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 0fb15e09..2ed28daf 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -78,7 +78,7 @@ int board_ext_simplesync_init(lldev_t dev, usleep(50000); lmk05318_xo_settings_t xo; - xo.doubler_enabled = true; + xo.doubler_enabled = false; xo.fdet_bypass = false; xo.fref = 26000000; xo.pll1_fref_rdiv = 1; @@ -102,6 +102,9 @@ int board_ext_simplesync_init(lldev_t dev, res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); + unsigned los_msk; + lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + if (res) return res; @@ -131,5 +134,8 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); + unsigned los_msk; + lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + return res; } diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 241e5adb..ab8240d2 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1406,26 +1406,82 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } usleep(40000); + // + //LMK05318 init start + lmk05318_xo_settings_t xo; + xo.doubler_enabled = false; + xo.fdet_bypass = false; + xo.fref = 26000000; + xo.pll1_fref_rdiv = 1; + xo.type = XO_CMOS; + + //set true to enable IN_REF1 40M + bool enable_in_ref = false; + + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + dpll.enabled = enable_in_ref; + dpll.en[LMK05318_PRIREF] = true; + dpll.fref[LMK05318_PRIREF] = 40000000; + dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; + dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; + dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; + + lmk05318_out_config_t lmk05318_outs_cfg[8]; + lmk05318_port_request(lmk05318_outs_cfg, 0, 491520000, false, OUT_OFF); + lmk05318_port_request(lmk05318_outs_cfg, 1, 491520000, false, LVDS); + lmk05318_port_request(lmk05318_outs_cfg, 2, 3840000, false, LVDS); + lmk05318_port_request(lmk05318_outs_cfg, 3, 3840000, false, OUT_OFF); + lmk05318_port_request(lmk05318_outs_cfg, 4, 0, false, OUT_OFF); + lmk05318_port_request(lmk05318_outs_cfg, 5, d->dac_rate / 2, false, LVDS); + lmk05318_port_request(lmk05318_outs_cfg, 6, 3840000, false, LVDS); + lmk05318_port_request(lmk05318_outs_cfg, 7, d->dac_rate / 2, false, LVDS); + + res = lmk05318_create(dev, d->subdev, I2C_LMK, &xo, &dpll, lmk05318_outs_cfg, 8, &d->lmk, false /*dry_run*/); + + usleep(10000); //wait until lmk digests all this + + //reset LOS flags after soft-reset (inside lmk05318_create()) + res = lmk05318_reset_los_flags(&d->lmk); + if(res) + return res; - for (unsigned j = 0; j < 25; j++) { - usleep(40000); - res = res ? res : lmk05318_create(dev, d->subdev, I2C_LMK, - (d->type == DSDR_PCIE_HIPER_R0) ? 2 : 1 /* TODO FIXME!!! */, &d->lmk); - if (res == 0) - break; + //wait for PRIREF/SECREF validation + res = lmk05318_wait_dpll_ref_stat(&d->lmk, 100000); + if(res) + { + USDR_LOG("DSDR", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); + return res; } - // Update deviders for 245/491MSPS rate - if (d->jesdv == DSDR_JESD204C_6664_491) { - // GT should be 245.76 - // FPGA SYSCLK should be 245.76 - res = res ? res : lmk05318_set_out_div(&d->lmk, LMK_FPGA_GT_AFEREF, 4); - res = res ? res : lmk05318_set_out_div(&d->lmk, LMK_FPGA_1PPS, 4); + //wait for lock + //APLL1/DPLL + res = lmk05318_wait_apll1_lock(&d->lmk, 100000); + + //APLL2 (if needed) + if(res == 0 && d->lmk.vco2_freq) + { + //reset LOS flags once again because APLL2 LOS is set after APLL1 tuning + res = lmk05318_reset_los_flags(&d->lmk); + res = res ? res : lmk05318_wait_apll2_lock(&d->lmk, 100000); } - usleep(1000); + lmk05318_check_lock(&d->lmk, &los, false /*silent*/); //just to log state - res = res ? res : lmk05318_check_lock(&d->lmk, &los, false /*silent*/); + if(res) + { + USDR_LOG("DSDR", USDR_LOG_ERROR, "LMK03518 PLLs not locked during specified timeout"); + return res; + } + + //sync to make APLL1/APLL2 & out channels in-phase + res = lmk05318_sync(&d->lmk); + if(res) + return res; + + USDR_LOG("DSDR", USDR_LOG_INFO, "LMK03518 outputs synced"); + //LMK05318 init end + // for (int i = 0; i < 5; i++) { uint32_t clk = 0; @@ -1435,9 +1491,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(0.5 * 1e6); } - res = res ? res : lmk05318_check_lock(&d->lmk, &los, false /*silent*/); - // res = res ? res : lmk05318_set_out_mux(&d->lmk, LMK_FPGA_SYSREF, false, LVDS); - usleep(1000); res = res ? res : dev_gpi_get32(dev, IGPI_PGOOD, &pg); diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 26a8b24f..cf1a45e7 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -314,7 +314,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const usleep(10000); //wait until lmk digests all this - //reset LOS flags after soft-reset (inside lmk05318_create_ex()) + //reset LOS flags after soft-reset (inside lmk05318_create()) res = lmk05318_reset_los_flags(&d->gen); if(res) return res; diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 01a81bf4..d64d6870 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -181,6 +181,82 @@ START_TEST(lmk05318_dpll_test1) ck_assert_int_eq( res, 0 ); } +START_TEST(lmk05318_dsdr_test1) +{ + int res = 0; + + lmk05318_xo_settings_t xo; + xo.fref = 26000000; + xo.doubler_enabled = false; + xo.fdet_bypass = false; + xo.pll1_fref_rdiv = 1; + xo.type = XO_CMOS; + + res = res ? res : lmk05318_port_request(cfg, 0, 491520000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 2, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 3, 3840000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 122880000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 6, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 7, 122880000, false, LVDS); + ck_assert_int_eq( res, 0 ); + + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + + dpll.enabled = true; + dpll.en[LMK05318_PRIREF] = true; + dpll.fref[LMK05318_PRIREF] = 40000000; + dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; + dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; + dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; + + lmk05318_state_t st; + memset(&st, 0, sizeof(st)); + + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmk05318_dsdr_test2) +{ + int res = 0; + + lmk05318_xo_settings_t xo; + xo.fref = 26000000; + xo.doubler_enabled = false; + xo.fdet_bypass = false; + xo.pll1_fref_rdiv = 1; + xo.type = XO_CMOS; + + res = res ? res : lmk05318_port_request(cfg, 0, 491520000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 1, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 2, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 3, 3840000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 4, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(cfg, 5, 122880000 * 2, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 6, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(cfg, 7, 122880000 * 2, false, LVDS); + ck_assert_int_eq( res, 0 ); + + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + + dpll.enabled = true; + dpll.en[LMK05318_PRIREF] = true; + dpll.fref[LMK05318_PRIREF] = 40000000; + dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; + dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; + dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; + + lmk05318_state_t st; + memset(&st, 0, sizeof(st)); + + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); +} + Suite * lmk05318_solver_suite(void) { Suite *s; @@ -197,6 +273,8 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_solver_test5); tcase_add_test(tc_core, lmk05318_solver_test6); tcase_add_test(tc_core, lmk05318_dpll_test1); + tcase_add_test(tc_core, lmk05318_dsdr_test1); + tcase_add_test(tc_core, lmk05318_dsdr_test2); suite_add_tcase(s, tc_core); return s; From 1d33334d3ab28aa7b7ff534e5e4f06c003782411 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 21 May 2025 00:29:14 +0300 Subject: [PATCH 131/397] lmk05318 fixpack for simplesync, dsdr & pe_sync --- .../device/ext_simplesync/ext_simplesync.c | 93 ++++-- src/lib/device/m2_dsdr/m2_dsdr.c | 24 +- src/lib/device/pe_sync/pe_sync.c | 22 +- src/lib/hw/lmk05318/lmk05318.c | 2 +- src/lib/hw/lmk05318/lmk05318.h | 11 +- src/utests/lmk05318_solver_test.c | 278 +++++++++++++----- 6 files changed, 297 insertions(+), 133 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 2ed28daf..d10d4c94 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -41,6 +41,17 @@ enum { I2C_ADDR_LMK = 0x65, }; +static int simplesync_pd_low_chs(board_ext_simplesync_t* ob) +{ + int res = 0; + res = res ? res : lmk05318_set_out_mux(&ob->lmk, 0, 0, OUT_OFF); + res = res ? res : lmk05318_set_out_mux(&ob->lmk, 1, 0, OUT_OFF); + res = res ? res : lmk05318_set_out_mux(&ob->lmk, 2, 0, OUT_OFF); + res = res ? res : lmk05318_set_out_mux(&ob->lmk, 3, 0, OUT_OFF); + res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); + return res; +} + int board_ext_simplesync_init(lldev_t dev, unsigned subdev, unsigned gpio_base, @@ -85,19 +96,29 @@ int board_ext_simplesync_init(lldev_t dev, xo.type = XO_CMOS; lmk05318_out_config_t cfg[4]; - lmk05318_port_request(cfg, 4, 25000000, false, LVCMOS); - lmk05318_port_request(cfg, 5, 25000000, false, LVCMOS); - lmk05318_port_request(cfg, 6, 25000000, false, LVCMOS); - lmk05318_port_request(cfg, 7, 25000000, false, LVCMOS); - lmk05318_set_port_affinity(cfg, 4, AFF_APLL1); - lmk05318_set_port_affinity(cfg, 5, AFF_APLL1); - lmk05318_set_port_affinity(cfg, 6, AFF_APLL1); - lmk05318_set_port_affinity(cfg, 7, AFF_APLL1); + lmk05318_out_config_t* p = &cfg[0]; + + lmk05318_port_request(p++, 4, 25000000, false, LVCMOS); + lmk05318_port_request(p++, 5, 25000000, false, LVCMOS); + lmk05318_port_request(p++, 6, 25000000, false, LVCMOS); + lmk05318_port_request(p++, 7, 25000000, false, LVCMOS); + + p = &cfg[0]; + + lmk05318_set_port_affinity(p++, AFF_APLL1); + lmk05318_set_port_affinity(p++, AFF_APLL1); + lmk05318_set_port_affinity(p++, AFF_APLL1); + lmk05318_set_port_affinity(p++, AFF_APLL1); lmk05318_dpll_settings_t dpll; dpll.enabled = false; - res = lmk05318_create(dev, subdev, i2ca, &xo, &dpll, cfg, 4, &ob->lmk, false /*dry_run*/); + res = lmk05318_create(dev, subdev, i2ca, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &ob->lmk, false /*dry_run*/); + if(res) + return res; + + res = simplesync_pd_low_chs(ob); //power down chs 0..3 + res = res ? res : lmk05318_reset_los_flags(&ob->lmk); res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); @@ -116,26 +137,42 @@ int board_ext_simplesync_init(lldev_t dev, int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) { + int res = 0; - lmk05318_out_config_t cfg[4]; - lmk05318_port_request(cfg, 0, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_port_request(cfg, 1, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_port_request(cfg, 2, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_port_request(cfg, 3, meas_lo, false, meas_lo < 1e6 ? OUT_OFF : LVDS); - lmk05318_set_port_affinity(cfg, 0, AFF_APLL2); - lmk05318_set_port_affinity(cfg, 1, AFF_APLL2); - lmk05318_set_port_affinity(cfg, 2, AFF_APLL2); - lmk05318_set_port_affinity(cfg, 3, AFF_APLL2); - - int res = lmk05318_solver(&ob->lmk, cfg, 4); - res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); - res = res ? res : lmk05318_softreset(&ob->lmk); - res = res ? res : lmk05318_reset_los_flags(&ob->lmk); - res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); - res = res ? res : lmk05318_sync(&ob->lmk); - - unsigned los_msk; - lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + if(meas_lo < 1e6) + { + res = simplesync_pd_low_chs(ob); //power down chs 0..3 + } + else + { + lmk05318_out_config_t cfg[4]; + lmk05318_out_config_t* p = &cfg[0]; + + lmk05318_port_request(p++, 0, meas_lo, false, LVDS); + lmk05318_port_request(p++, 1, meas_lo, false, LVDS); + lmk05318_port_request(p++, 2, meas_lo, false, LVDS); + lmk05318_port_request(p++, 3, meas_lo, false, LVDS); + + p = &cfg[0]; + + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + + res = lmk05318_solver(&ob->lmk, cfg, SIZEOF_ARRAY(cfg)); + res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); + if(res) + return res; + + res = res ? res : lmk05318_softreset(&ob->lmk); + res = res ? res : lmk05318_reset_los_flags(&ob->lmk); + res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); + res = res ? res : lmk05318_sync(&ob->lmk); + + unsigned los_msk; + lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + } return res; } diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index cd86e368..3e456920 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1445,16 +1445,20 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; lmk05318_out_config_t lmk05318_outs_cfg[8]; - lmk05318_port_request(lmk05318_outs_cfg, 0, 491520000, false, OUT_OFF); - lmk05318_port_request(lmk05318_outs_cfg, 1, 491520000, false, LVDS); - lmk05318_port_request(lmk05318_outs_cfg, 2, 3840000, false, LVDS); - lmk05318_port_request(lmk05318_outs_cfg, 3, 3840000, false, OUT_OFF); - lmk05318_port_request(lmk05318_outs_cfg, 4, 0, false, OUT_OFF); - lmk05318_port_request(lmk05318_outs_cfg, 5, d->dac_rate / 2, false, LVDS); - lmk05318_port_request(lmk05318_outs_cfg, 6, 3840000, false, LVDS); - lmk05318_port_request(lmk05318_outs_cfg, 7, d->dac_rate / 2, false, LVDS); - - res = lmk05318_create(dev, d->subdev, I2C_LMK, &xo, &dpll, lmk05318_outs_cfg, 8, &d->lmk, false /*dry_run*/); + lmk05318_out_config_t* p = &lmk05318_outs_cfg[0]; + + lmk05318_port_request(p++, 0, 491520000, false, OUT_OFF); + lmk05318_port_request(p++, 1, 491520000, false, LVDS); + lmk05318_port_request(p++, 2, 3840000, false, LVDS); + lmk05318_port_request(p++, 3, 3840000, false, OUT_OFF); + lmk05318_port_request(p++, 4, 0, false, OUT_OFF); + lmk05318_port_request(p++, 5, d->dac_rate / 2, false, LVDS); + lmk05318_port_request(p++, 6, 3840000, false, LVDS); + lmk05318_port_request(p++, 7, d->dac_rate / 2, false, LVDS); + + res = lmk05318_create(dev, d->subdev, I2C_LMK, &xo, &dpll, lmk05318_outs_cfg, SIZEOF_ARRAY(lmk05318_outs_cfg), &d->lmk, false /*dry_run*/); + if(res) + return res; usleep(10000); //wait until lmk digests all this diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index cf1a45e7..bcebceaa 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -299,16 +299,18 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const }; lmk05318_out_config_t lmk05318_outs_cfg[8]; - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 0, lmk_freq[0], false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 1, lmk_freq[1], false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 2, lmk_freq[2], false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 3, lmk_freq[3], false, LVDS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 4, lmk_freq[4], false, OUT_OFF); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 5, lmk_freq[5], false, OUT_OFF); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 6, lmk_freq[6], false, LVCMOS); - res = res ? res : lmk05318_port_request(lmk05318_outs_cfg, 7, lmk_freq[7], false, LVCMOS); - - res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk05318_outs_cfg, 8, &d->gen, false /*dry_run*/); + lmk05318_out_config_t* p = &lmk05318_outs_cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, lmk_freq[0], false, LVDS); + res = res ? res : lmk05318_port_request(p++, 1, lmk_freq[1], false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, lmk_freq[2], false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, lmk_freq[3], false, LVDS); + res = res ? res : lmk05318_port_request(p++, 4, lmk_freq[4], false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, lmk_freq[5], false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, lmk_freq[6], false, LVCMOS); + res = res ? res : lmk05318_port_request(p++, 7, lmk_freq[7], false, LVCMOS); + + res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk05318_outs_cfg, SIZEOF_ARRAY(lmk05318_outs_cfg), &d->gen, false /*dry_run*/); if(res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index cb853306..d7ea6a34 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1239,7 +1239,7 @@ static inline const char* lmk05318_decode_fmt(unsigned f) return "UNKNOWN"; } -static int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) +int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) { unsigned ot; switch (otype) { diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 1a07126d..7d911419 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -159,7 +159,7 @@ typedef struct lmk05318_out_config lmk05318_out_config_t; #define LMK05318_FREQ_DELTA 2 -static inline int lmk05318_port_request(lmk05318_out_config_t* cfg, +static inline int lmk05318_port_request(lmk05318_out_config_t* p, unsigned port, uint32_t freq, bool revert_phase, @@ -168,7 +168,6 @@ static inline int lmk05318_port_request(lmk05318_out_config_t* cfg, if(port > LMK05318_MAX_OUT_PORTS - 1) return -EINVAL; - lmk05318_out_config_t* p = cfg + port; memset(p, 0, sizeof(*p)); p->port = port; p->wanted.freq = freq; @@ -181,14 +180,9 @@ static inline int lmk05318_port_request(lmk05318_out_config_t* cfg, return 0; } -static inline int lmk05318_set_port_affinity(lmk05318_out_config_t* cfg, unsigned port, lmk05318_port_affinity_t aff) +static inline int lmk05318_set_port_affinity(lmk05318_out_config_t* p, lmk05318_port_affinity_t aff) { - if(port > LMK05318_MAX_OUT_PORTS - 1) - return -EINVAL; - - lmk05318_out_config_t* p = cfg + port; p->wanted.pll_affinity = aff; - return 0; } @@ -211,6 +205,7 @@ int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout); int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout); int lmk05318_softreset(lmk05318_state_t* out); +int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype); int lmk05318_reg_wr(lmk05318_state_t* d, uint16_t reg, uint8_t out); int lmk05318_reg_rd(lmk05318_state_t* d, uint16_t reg, uint8_t* val); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index d64d6870..fc2015a9 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -17,14 +17,15 @@ static void setup() dev.fref_pll2_div_rs = 6; int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, 100000000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, 100000000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 2, 122880000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, 122880000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, 31250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 3840000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 491520000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 7, 1, true, OUT_OFF); + lmk05318_out_config_t* p = &cfg[0]; + res = res ? res : lmk05318_port_request(p++, 0, 100000000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 1, 100000000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 2, 122880000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 3, 122880000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 4, 31250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 3840000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, 491520000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 7, 1, true, OUT_OFF); ck_assert_int_eq( res, 0 ); lmk05318_registers_map_reset(); @@ -37,7 +38,7 @@ static void teardown() START_TEST(lmk05318_solver_test1) { lmk05318_registers_map_reset(); - int res = lmk05318_solver(&dev, cfg, OUTS_LEN); + int res = lmk05318_solver(&dev, cfg, SIZEOF_ARRAY(cfg)); ck_assert_int_eq( res, 0 ); } @@ -48,28 +49,31 @@ START_TEST(lmk05318_solver_test3) uint64_t f4_7 = 12500000; //3840000; int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, f0_3, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, f0_3, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 2, f0_3, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, f0_3, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, f4_7, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, f4_7, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, f4_7, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 7, f4_7, false, OUT_OFF); + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 1, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 2, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 3, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 4, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 7, f4_7, false, OUT_OFF); ck_assert_int_eq( res, 0 ); - res = res ? res : lmk05318_set_port_affinity(cfg, 0, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 1, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 2, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 3, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 4, AFF_APLL2); - res = res ? res : lmk05318_set_port_affinity(cfg, 5, AFF_APLL2); - res = res ? res : lmk05318_set_port_affinity(cfg, 6, AFF_APLL2); - res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); + p = &cfg[0]; + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); ck_assert_int_eq( res, 0 ); lmk05318_registers_map_reset(); - res = lmk05318_solver(&dev, cfg, OUTS_LEN); + res = lmk05318_solver(&dev, cfg, SIZEOF_ARRAY(cfg)); ck_assert_int_eq( res, 0 ); } @@ -82,22 +86,27 @@ START_TEST(lmk05318_solver_test4) memset(cfg, 0, sizeof(cfg)); int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, f0_3, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, f0_3, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 3, f0_3, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, f4_7, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, f4_7, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 7, f4_7, false, OUT_OFF); + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 1, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 2, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 3, f0_3, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 4, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, f4_7, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 7, f4_7, false, OUT_OFF); ck_assert_int_eq( res, 0 ); - res = res ? res : lmk05318_set_port_affinity(cfg, 0, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 1, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 2, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 3, AFF_APLL1); - res = res ? res : lmk05318_set_port_affinity(cfg, 4, AFF_APLL2); - res = res ? res : lmk05318_set_port_affinity(cfg, 5, AFF_APLL2); - res = res ? res : lmk05318_set_port_affinity(cfg, 6, AFF_APLL2); - res = res ? res : lmk05318_set_port_affinity(cfg, 7, AFF_APLL2); + p = &cfg[0]; + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(p++, AFF_APLL2); ck_assert_int_eq( res, 0 ); lmk05318_registers_map_reset(); @@ -112,18 +121,20 @@ START_TEST(lmk05318_solver_test4) START_TEST(lmk05318_solver_test5) { int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, 125000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 1, 125000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 2, 250000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 3, 250000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 4, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 10000000, false, LVCMOS); - res = res ? res : lmk05318_port_request(cfg, 7, 1, false, LVCMOS); + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 1, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 4, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, 10000000, false, LVCMOS); + res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS); ck_assert_int_eq( res, 0 ); lmk05318_registers_map_reset(); - res = lmk05318_solver(&dev, cfg, OUTS_LEN); + res = lmk05318_solver(&dev, cfg, SIZEOF_ARRAY(cfg)); ck_assert_int_eq( res, 0 ); } @@ -131,14 +142,16 @@ START_TEST(lmk05318_solver_test5) START_TEST(lmk05318_solver_test6) { int res = 0; - res = res ? res : lmk05318_port_request(cfg, 0, 125000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 1, 125000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 2, 250000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 3, 250000000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 4, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 6, 10000000, false, LVCMOS); - res = res ? res : lmk05318_port_request(cfg, 7, 1, false, LVCMOS); + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 1, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 4, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, 10000000, false, LVCMOS); + res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS); ck_assert_int_eq( res, 0 ); lmk05318_xo_settings_t xo; @@ -160,7 +173,7 @@ START_TEST(lmk05318_solver_test6) lmk05318_state_t st; memset(&st, 0, sizeof(st)); - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } @@ -192,14 +205,16 @@ START_TEST(lmk05318_dsdr_test1) xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; - res = res ? res : lmk05318_port_request(cfg, 0, 491520000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, 491520000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 2, 3840000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 3, 3840000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, 0, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 122880000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 6, 3840000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 7, 122880000, false, LVDS); + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 491520000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 1, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 3840000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 4, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 122880000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 6, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 7, 122880000, false, LVDS); ck_assert_int_eq( res, 0 ); lmk05318_dpll_settings_t dpll; @@ -215,7 +230,7 @@ START_TEST(lmk05318_dsdr_test1) lmk05318_state_t st; memset(&st, 0, sizeof(st)); - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } @@ -230,14 +245,16 @@ START_TEST(lmk05318_dsdr_test2) xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; - res = res ? res : lmk05318_port_request(cfg, 0, 491520000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 1, 491520000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 2, 3840000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 3, 3840000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 4, 0, false, OUT_OFF); - res = res ? res : lmk05318_port_request(cfg, 5, 122880000 * 2, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 6, 3840000, false, LVDS); - res = res ? res : lmk05318_port_request(cfg, 7, 122880000 * 2, false, LVDS); + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 491520000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 1, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 3840000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 4, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 122880000 * 2, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 6, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 7, 122880000 * 2, false, LVDS); ck_assert_int_eq( res, 0 ); lmk05318_dpll_settings_t dpll; @@ -253,8 +270,116 @@ START_TEST(lmk05318_dsdr_test2) lmk05318_state_t st; memset(&st, 0, sizeof(st)); - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, 8, &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); +} + +static int simplesync_pd_low_chs(lmk05318_state_t* st) +{ + int res = 0; + res = res ? res : lmk05318_set_out_mux(st, 0, 0, OUT_OFF); + res = res ? res : lmk05318_set_out_mux(st, 1, 0, OUT_OFF); + res = res ? res : lmk05318_set_out_mux(st, 2, 0, OUT_OFF); + res = res ? res : lmk05318_set_out_mux(st, 3, 0, OUT_OFF); + res = res ? res : lmk05318_reg_wr_from_map(st, true /*dry_run*/); + return res; +} + +START_TEST(lmk05318_simplesync_test1) +{ + int res = 0; + + lmk05318_xo_settings_t xo; + xo.fref = 26000000; + xo.doubler_enabled = false; + xo.fdet_bypass = false; + xo.pll1_fref_rdiv = 1; + xo.type = XO_CMOS; + + lmk05318_out_config_t cfg1[4]; + lmk05318_out_config_t* p = &cfg1[0]; + + lmk05318_port_request(p++, 4, 25000000, false, LVCMOS); + lmk05318_port_request(p++, 5, 25000000, false, LVCMOS); + lmk05318_port_request(p++, 6, 25000000, false, LVCMOS); + lmk05318_port_request(p++, 7, 25000000, false, LVCMOS); + + p = &cfg1[0]; + + lmk05318_set_port_affinity(p++, AFF_APLL1); + lmk05318_set_port_affinity(p++, AFF_APLL1); + lmk05318_set_port_affinity(p++, AFF_APLL1); + lmk05318_set_port_affinity(p++, AFF_APLL1); + + lmk05318_dpll_settings_t dpll; + dpll.enabled = false; + + lmk05318_state_t st; + memset(&st, 0, sizeof(st)); + + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg1, SIZEOF_ARRAY(cfg1), &st, true /*dry_run*/); + res = res ? res : simplesync_pd_low_chs(&st); + ck_assert_int_eq( res, 0 ); + + uint64_t meas_lo = 122800000; + + if(meas_lo < 1e6) + { + res = simplesync_pd_low_chs(&st); + } + else + { + lmk05318_out_config_t cfg2[4]; + p = cfg2; + + lmk05318_port_request(p++, 0, meas_lo, false, LVDS); + lmk05318_port_request(p++, 1, meas_lo, false, LVDS); + lmk05318_port_request(p++, 2, meas_lo, false, LVDS); + lmk05318_port_request(p++, 3, meas_lo, false, LVDS); + + p = cfg2; + + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + + res = lmk05318_solver(&st, cfg2, SIZEOF_ARRAY(cfg2)); + res = res ? res : lmk05318_reg_wr_from_map(&st, true /*dry_run*/); + } + + ck_assert_int_eq( res, 0 ); + + meas_lo = 122800; + + if(meas_lo < 1e6) + { + res = simplesync_pd_low_chs(&st); + } + else + { + lmk05318_out_config_t cfg2[4]; + p = cfg2; + + lmk05318_port_request(p++, 0, meas_lo, false, LVDS); + lmk05318_port_request(p++, 1, meas_lo, false, LVDS); + lmk05318_port_request(p++, 2, meas_lo, false, LVDS); + lmk05318_port_request(p++, 3, meas_lo, false, LVDS); + + p = cfg2; + + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(p++, AFF_APLL2); + + res = lmk05318_solver(&st, cfg2, SIZEOF_ARRAY(cfg2)); + res = res ? res : lmk05318_reg_wr_from_map(&st, true /*dry_run*/); + } + + ck_assert_int_eq( res, 0 ); + } Suite * lmk05318_solver_suite(void) @@ -275,6 +400,7 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_dpll_test1); tcase_add_test(tc_core, lmk05318_dsdr_test1); tcase_add_test(tc_core, lmk05318_dsdr_test2); + tcase_add_test(tc_core, lmk05318_simplesync_test1); suite_add_tcase(s, tc_core); return s; From d66111c1265b83c344f413a961c7d2b408606737 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 21 May 2025 01:38:33 +0300 Subject: [PATCH 132/397] code a bit more safe --- .../device/ext_simplesync/ext_simplesync.c | 46 ++++++++----------- src/lib/device/m2_dsdr/m2_dsdr.c | 25 +++++----- src/lib/device/pe_sync/pe_sync.c | 25 +++++----- 3 files changed, 44 insertions(+), 52 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index d10d4c94..e0746003 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -95,25 +95,22 @@ int board_ext_simplesync_init(lldev_t dev, xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; - lmk05318_out_config_t cfg[4]; - lmk05318_out_config_t* p = &cfg[0]; + lmk05318_out_config_t lmk_out[4]; - lmk05318_port_request(p++, 4, 25000000, false, LVCMOS); - lmk05318_port_request(p++, 5, 25000000, false, LVCMOS); - lmk05318_port_request(p++, 6, 25000000, false, LVCMOS); - lmk05318_port_request(p++, 7, 25000000, false, LVCMOS); + lmk05318_port_request(&lmk_out[0], 4, 25000000, false, LVCMOS); + lmk05318_port_request(&lmk_out[1], 5, 25000000, false, LVCMOS); + lmk05318_port_request(&lmk_out[2], 6, 25000000, false, LVCMOS); + lmk05318_port_request(&lmk_out[3], 7, 25000000, false, LVCMOS); - p = &cfg[0]; - - lmk05318_set_port_affinity(p++, AFF_APLL1); - lmk05318_set_port_affinity(p++, AFF_APLL1); - lmk05318_set_port_affinity(p++, AFF_APLL1); - lmk05318_set_port_affinity(p++, AFF_APLL1); + lmk05318_set_port_affinity(&lmk_out[0], AFF_APLL1); + lmk05318_set_port_affinity(&lmk_out[1], AFF_APLL1); + lmk05318_set_port_affinity(&lmk_out[2], AFF_APLL1); + lmk05318_set_port_affinity(&lmk_out[3], AFF_APLL1); lmk05318_dpll_settings_t dpll; dpll.enabled = false; - res = lmk05318_create(dev, subdev, i2ca, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &ob->lmk, false /*dry_run*/); + res = lmk05318_create(dev, subdev, i2ca, &xo, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &ob->lmk, false /*dry_run*/); if(res) return res; @@ -145,22 +142,19 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) } else { - lmk05318_out_config_t cfg[4]; - lmk05318_out_config_t* p = &cfg[0]; - - lmk05318_port_request(p++, 0, meas_lo, false, LVDS); - lmk05318_port_request(p++, 1, meas_lo, false, LVDS); - lmk05318_port_request(p++, 2, meas_lo, false, LVDS); - lmk05318_port_request(p++, 3, meas_lo, false, LVDS); + lmk05318_out_config_t lmk_out[4]; - p = &cfg[0]; + lmk05318_port_request(&lmk_out[0], 0, meas_lo, false, LVDS); + lmk05318_port_request(&lmk_out[1], 1, meas_lo, false, LVDS); + lmk05318_port_request(&lmk_out[2], 2, meas_lo, false, LVDS); + lmk05318_port_request(&lmk_out[3], 3, meas_lo, false, LVDS); - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); + lmk05318_set_port_affinity(&lmk_out[0], AFF_APLL2); + lmk05318_set_port_affinity(&lmk_out[1], AFF_APLL2); + lmk05318_set_port_affinity(&lmk_out[2], AFF_APLL2); + lmk05318_set_port_affinity(&lmk_out[3], AFF_APLL2); - res = lmk05318_solver(&ob->lmk, cfg, SIZEOF_ARRAY(cfg)); + res = lmk05318_solver(&ob->lmk, lmk_out, SIZEOF_ARRAY(lmk_out)); res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); if(res) return res; diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 3e456920..7fa7369c 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1444,19 +1444,18 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; - lmk05318_out_config_t lmk05318_outs_cfg[8]; - lmk05318_out_config_t* p = &lmk05318_outs_cfg[0]; - - lmk05318_port_request(p++, 0, 491520000, false, OUT_OFF); - lmk05318_port_request(p++, 1, 491520000, false, LVDS); - lmk05318_port_request(p++, 2, 3840000, false, LVDS); - lmk05318_port_request(p++, 3, 3840000, false, OUT_OFF); - lmk05318_port_request(p++, 4, 0, false, OUT_OFF); - lmk05318_port_request(p++, 5, d->dac_rate / 2, false, LVDS); - lmk05318_port_request(p++, 6, 3840000, false, LVDS); - lmk05318_port_request(p++, 7, d->dac_rate / 2, false, LVDS); - - res = lmk05318_create(dev, d->subdev, I2C_LMK, &xo, &dpll, lmk05318_outs_cfg, SIZEOF_ARRAY(lmk05318_outs_cfg), &d->lmk, false /*dry_run*/); + lmk05318_out_config_t lmk_out[8]; + + lmk05318_port_request(&lmk_out[0], 0, 491520000, false, OUT_OFF); + lmk05318_port_request(&lmk_out[1], 1, 491520000, false, LVDS); + lmk05318_port_request(&lmk_out[2], 2, 3840000, false, LVDS); + lmk05318_port_request(&lmk_out[3], 3, 3840000, false, OUT_OFF); + lmk05318_port_request(&lmk_out[4], 4, 0, false, OUT_OFF); + lmk05318_port_request(&lmk_out[5], 5, d->dac_rate / 2, false, LVDS); + lmk05318_port_request(&lmk_out[6], 6, 3840000, false, LVDS); + lmk05318_port_request(&lmk_out[7], 7, d->dac_rate / 2, false, LVDS); + + res = lmk05318_create(dev, d->subdev, I2C_LMK, &xo, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->lmk, false /*dry_run*/); if(res) return res; diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index bcebceaa..b25b1246 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -298,19 +298,18 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const 1 }; - lmk05318_out_config_t lmk05318_outs_cfg[8]; - lmk05318_out_config_t* p = &lmk05318_outs_cfg[0]; - - res = res ? res : lmk05318_port_request(p++, 0, lmk_freq[0], false, LVDS); - res = res ? res : lmk05318_port_request(p++, 1, lmk_freq[1], false, LVDS); - res = res ? res : lmk05318_port_request(p++, 2, lmk_freq[2], false, LVDS); - res = res ? res : lmk05318_port_request(p++, 3, lmk_freq[3], false, LVDS); - res = res ? res : lmk05318_port_request(p++, 4, lmk_freq[4], false, OUT_OFF); - res = res ? res : lmk05318_port_request(p++, 5, lmk_freq[5], false, OUT_OFF); - res = res ? res : lmk05318_port_request(p++, 6, lmk_freq[6], false, LVCMOS); - res = res ? res : lmk05318_port_request(p++, 7, lmk_freq[7], false, LVCMOS); - - res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk05318_outs_cfg, SIZEOF_ARRAY(lmk05318_outs_cfg), &d->gen, false /*dry_run*/); + lmk05318_out_config_t lmk_out[8]; + + res = res ? res : lmk05318_port_request(&lmk_out[0], 0, lmk_freq[0], false, LVDS); + res = res ? res : lmk05318_port_request(&lmk_out[1], 1, lmk_freq[1], false, LVDS); + res = res ? res : lmk05318_port_request(&lmk_out[2], 2, lmk_freq[2], false, LVDS); + res = res ? res : lmk05318_port_request(&lmk_out[3], 3, lmk_freq[3], false, LVDS); + res = res ? res : lmk05318_port_request(&lmk_out[4], 4, lmk_freq[4], false, OUT_OFF); + res = res ? res : lmk05318_port_request(&lmk_out[5], 5, lmk_freq[5], false, OUT_OFF); + res = res ? res : lmk05318_port_request(&lmk_out[6], 6, lmk_freq[6], false, LVCMOS); + res = res ? res : lmk05318_port_request(&lmk_out[7], 7, lmk_freq[7], false, LVCMOS); + + res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->gen, false /*dry_run*/); if(res) return res; From f78763b1813756dd10835dfa96cb2cb71393a390 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 21 May 2025 12:40:47 +0300 Subject: [PATCH 133/397] simplesync cut-off frequency corrected --- .../device/ext_simplesync/ext_simplesync.c | 4 +- src/utests/lmk05318_solver_test.c | 89 ++++++++----------- 2 files changed, 38 insertions(+), 55 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index e0746003..8a16a93c 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -130,13 +130,13 @@ int board_ext_simplesync_init(lldev_t dev, return 0; } - +#define LO_FREQ_CUTOFF 3500000ul // VCO2_MIN / 7 / 256 = 3069196.43 Hz int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) { int res = 0; - if(meas_lo < 1e6) + if(meas_lo < LO_FREQ_CUTOFF) { res = simplesync_pd_low_chs(ob); //power down chs 0..3 } diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index fc2015a9..d7fc010a 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -285,6 +285,36 @@ static int simplesync_pd_low_chs(lmk05318_state_t* st) return res; } +#define LO_FREQ_CUTOFF 3500000ul // VCO2_MIN / 7 / 256 = 3069196.43 Hz + +static int lmk05318_simplesync_set_lo_freq(lmk05318_state_t* st, uint64_t meas_lo) +{ + int res; + if(meas_lo < LO_FREQ_CUTOFF) + { + res = simplesync_pd_low_chs(st); + } + else + { + lmk05318_out_config_t cfg2[4]; + + lmk05318_port_request(&cfg2[0], 0, meas_lo, false, LVDS); + lmk05318_port_request(&cfg2[1], 1, meas_lo, false, LVDS); + lmk05318_port_request(&cfg2[2], 2, meas_lo, false, LVDS); + lmk05318_port_request(&cfg2[3], 3, meas_lo, false, LVDS); + + lmk05318_set_port_affinity(&cfg2[0], AFF_APLL2); + lmk05318_set_port_affinity(&cfg2[1], AFF_APLL2); + lmk05318_set_port_affinity(&cfg2[2], AFF_APLL2); + lmk05318_set_port_affinity(&cfg2[3], AFF_APLL2); + + res = lmk05318_solver(st, cfg2, SIZEOF_ARRAY(cfg2)); + res = res ? res : lmk05318_reg_wr_from_map(st, true /*dry_run*/); + } + + return res; +} + START_TEST(lmk05318_simplesync_test1) { int res = 0; @@ -322,64 +352,17 @@ START_TEST(lmk05318_simplesync_test1) ck_assert_int_eq( res, 0 ); - uint64_t meas_lo = 122800000; - - if(meas_lo < 1e6) - { - res = simplesync_pd_low_chs(&st); - } - else - { - lmk05318_out_config_t cfg2[4]; - p = cfg2; - - lmk05318_port_request(p++, 0, meas_lo, false, LVDS); - lmk05318_port_request(p++, 1, meas_lo, false, LVDS); - lmk05318_port_request(p++, 2, meas_lo, false, LVDS); - lmk05318_port_request(p++, 3, meas_lo, false, LVDS); - - p = cfg2; - - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - - res = lmk05318_solver(&st, cfg2, SIZEOF_ARRAY(cfg2)); - res = res ? res : lmk05318_reg_wr_from_map(&st, true /*dry_run*/); - } - + res = lmk05318_simplesync_set_lo_freq(&st, 122800000); ck_assert_int_eq( res, 0 ); - meas_lo = 122800; - - if(meas_lo < 1e6) - { - res = simplesync_pd_low_chs(&st); - } - else - { - lmk05318_out_config_t cfg2[4]; - p = cfg2; - - lmk05318_port_request(p++, 0, meas_lo, false, LVDS); - lmk05318_port_request(p++, 1, meas_lo, false, LVDS); - lmk05318_port_request(p++, 2, meas_lo, false, LVDS); - lmk05318_port_request(p++, 3, meas_lo, false, LVDS); - - p = cfg2; - - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - lmk05318_set_port_affinity(p++, AFF_APLL2); - - res = lmk05318_solver(&st, cfg2, SIZEOF_ARRAY(cfg2)); - res = res ? res : lmk05318_reg_wr_from_map(&st, true /*dry_run*/); - } + res = lmk05318_simplesync_set_lo_freq(&st, 3500000); + ck_assert_int_eq( res, 0 ); + res = lmk05318_simplesync_set_lo_freq(&st, 3000000); ck_assert_int_eq( res, 0 ); + res = lmk05318_simplesync_set_lo_freq(&st, 0); + ck_assert_int_eq( res, 0 ); } Suite * lmk05318_solver_suite(void) From 960925ddc9d423c8f26570b0ddcd57a60ceeabca Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 21 May 2025 22:08:36 +0300 Subject: [PATCH 134/397] increase LMK max out freq setting + new unit-test --- src/lib/hw/lmk05318/lmk05318.c | 2 +- src/utests/lmk05318_solver_test.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index d7ea6a34..0b96fd47 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -34,7 +34,7 @@ enum { APLL2_PD_MIN = 10000000, APLL2_PD_MAX = 150000000, - OUT_FREQ_MAX = 800000000ull, + OUT_FREQ_MAX = 1250000000ull, XO_FREF_MAX = 100000000ull, XO_FREF_MIN = 10000000ull, diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index d7fc010a..17ca9526 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -365,6 +365,30 @@ START_TEST(lmk05318_simplesync_test1) ck_assert_int_eq( res, 0 ); } +START_TEST(lmk05318_solver_test7) +{ + int res = 0; + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 1, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 2, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 3, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 4, 1000666000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 5, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, 25000000, false, LVCMOS); + res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS); + + res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); + + ck_assert_int_eq( res, 0 ); + + lmk05318_registers_map_reset(); + res = lmk05318_solver(&dev, cfg, SIZEOF_ARRAY(cfg)); + ck_assert_int_eq( res, 0 ); + +} + Suite * lmk05318_solver_suite(void) { Suite *s; @@ -384,6 +408,8 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_dsdr_test1); tcase_add_test(tc_core, lmk05318_dsdr_test2); tcase_add_test(tc_core, lmk05318_simplesync_test1); + tcase_add_test(tc_core, lmk05318_solver_test7); + suite_add_tcase(s, tc_core); return s; From 1a7b91af0a4b846847facb2d62ace50543826e90 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 21 May 2025 23:16:33 +0400 Subject: [PATCH 135/397] xmass: add initial support --- src/lib/device/CMakeLists.txt | 1 + src/lib/device/device_fe.c | 133 +++++++++-- src/lib/device/ext_xmass/CMakeLists.txt | 24 ++ src/lib/device/ext_xmass/ext_xmass.c | 226 +++++++++++++++++++ src/lib/device/ext_xmass/ext_xmass.h | 53 +++++ src/lib/device/ext_xmass/ext_xmass_ctrl.yaml | 71 ++++++ src/lib/hw/CMakeLists.txt | 4 +- src/lib/hw/tca9555/tca9555.c | 46 ++++ src/lib/hw/tca9555/tca9555.h | 27 +++ src/lib/hw/tca9555/tca9555.yaml | 87 +++++++ 10 files changed, 648 insertions(+), 24 deletions(-) create mode 100644 src/lib/device/ext_xmass/CMakeLists.txt create mode 100644 src/lib/device/ext_xmass/ext_xmass.c create mode 100644 src/lib/device/ext_xmass/ext_xmass.h create mode 100644 src/lib/device/ext_xmass/ext_xmass_ctrl.yaml create mode 100644 src/lib/hw/tca9555/tca9555.c create mode 100644 src/lib/hw/tca9555/tca9555.h create mode 100644 src/lib/hw/tca9555/tca9555.yaml diff --git a/src/lib/device/CMakeLists.txt b/src/lib/device/CMakeLists.txt index 4ae4b9a4..1192cd3c 100644 --- a/src/lib/device/CMakeLists.txt +++ b/src/lib/device/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(ext_pciefe) add_subdirectory(ext_supersync) add_subdirectory(ext_simplesync) add_subdirectory(ext_fe_100_5000) +add_subdirectory(ext_xmass) add_subdirectory(u3_limesdr) diff --git a/src/lib/device/device_fe.c b/src/lib/device/device_fe.c index d44d521d..a76ac86f 100644 --- a/src/lib/device/device_fe.c +++ b/src/lib/device/device_fe.c @@ -9,6 +9,7 @@ #include "ext_supersync/ext_supersync.h" #include "ext_simplesync/ext_simplesync.h" #include "ext_fe_100_5000/ext_fe_100_5000.h" +#include "ext_xmass/ext_xmass.h" #include #include @@ -24,13 +25,22 @@ static int _debug_ext_fe_100_5000_cmd_set(pdevice_t ud, pusdr_vfs_obj_t obj, uin static int _debug_ext_fe_100_5000_cmd_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); -static int _debug_lmk05318_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); -static int _debug_lmk05318_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int _debug_simplesync_lmk05318_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int _debug_simplesync_lmk05318_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int _debug_xmass_lmk05318_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int _debug_xmass_lmk05318_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); + static int _debug_lmk05318_calfreq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int _debug_lmk5c33216_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int _debug_lmk5c33216_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int _debug_xmass_ctrl_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int _debug_xmass_ctrl_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); + +static int _debug_xmass_calfreq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int _debug_xmass_calfreq_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); + static int _debug_typefe_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); static int _debug_ll_mdev_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -41,32 +51,35 @@ const usdr_dev_param_func_t s_fe_params[] = { { "/ll/mdev", { _debug_ll_mdev_set, NULL}}, }; -static -const usdr_dev_param_func_t s_fe_pcie_params[] = { +static const usdr_dev_param_func_t s_fe_pcie_params[] = { { "/debug/hw/pciefe/0/reg", { _debug_pciefe_reg_set, _debug_pciefe_reg_get }}, { "/debug/hw/pciefe_cmd/0/reg", { _debug_pciefe_cmd_set, _debug_pciefe_cmd_get }}, }; -static -const usdr_dev_param_func_t s_lmk05318_params[] = { - { "/debug/hw/lmk05318/0/reg", { _debug_lmk05318_reg_set, _debug_lmk05318_reg_get }}, +static const usdr_dev_param_func_t s_simplesync_params[] = { + { "/debug/hw/lmk05318/0/reg", { _debug_simplesync_lmk05318_reg_set, _debug_simplesync_lmk05318_reg_get }}, { "/dm/sync/cal/freq", { _debug_lmk05318_calfreq_set, NULL }}, }; -static -const usdr_dev_param_func_t s_lmk5c33216_params[] = { +static const usdr_dev_param_func_t s_lmk5c33216_params[] = { { "/debug/hw/lmk5c33216/0/reg", { _debug_lmk5c33216_reg_set, _debug_lmk5c33216_reg_get }}, }; - -static -const usdr_dev_param_func_t s_ext_fe_100_5000_params[] = { +static const usdr_dev_param_func_t s_ext_fe_100_5000_params[] = { { "/debug/hw/fe_100_5000_cmd/0/reg", { _debug_ext_fe_100_5000_cmd_set, _debug_ext_fe_100_5000_cmd_get }}, }; +static const usdr_dev_param_func_t s_xmass_params[] = { + { "/debug/hw/lmk05318/0/reg", { _debug_xmass_lmk05318_reg_set, _debug_xmass_lmk05318_reg_get }}, + { "/debug/hw/xmass_ctrl/0/reg", { _debug_xmass_ctrl_reg_set, _debug_xmass_ctrl_reg_get }}, + { "/dm/sync/cal/freq", { _debug_xmass_calfreq_set, _debug_xmass_calfreq_get }}, + { "/dm/sdr/0/sync/cal/freq", { _debug_xmass_calfreq_set, _debug_xmass_calfreq_get }}, +}; + enum fe_type { FET_PCIE_DEVBOARD, + FET_PCIE_XMASS, FET_PCIE_SUPER_SYNC, FET_PCIE_SIMPLE_SYNC, FET_PICE_BREAKOUT, @@ -78,6 +91,7 @@ typedef enum fe_type fe_type_t; static const char* s_fe_names[] = { "pciefe", + "xmass", "supersync", "simplesync", "exm2pe", @@ -95,6 +109,7 @@ struct dev_fe { board_ext_simplesync_t simplesync; board_ext_supersync_t supersync; ext_fe_100_5000_t fe_100_5000; + board_xmass_t xmass; } fe; uint32_t debug_pciefe_last; @@ -102,6 +117,7 @@ struct dev_fe { uint32_t debug_ext_fe_100_5000_cmd_last; uint32_t debug_lmk05318_last; uint32_t debug_lmk5c33216_last; + uint32_t debug_xmass_ctrl_last; }; typedef struct dev_fe dev_fe_t; @@ -183,6 +199,7 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi case FET_PCIE_SUPER_SYNC: res = board_ext_supersync_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe.fe.supersync); break; case FET_PCIE_SIMPLE_SYNC: res = board_ext_simplesync_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe.fe.simplesync); break; case FET_PCIE_FE1005000: res = ext_fe_100_5000_init(dev, 0, gpiobase, spiext_cfg, 4, hint_strip, compat, &dfe.fe.fe_100_5000); break; + case FET_PCIE_XMASS: res = board_xmass_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe.fe.xmass); break; default: return -EIO; } @@ -230,8 +247,8 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi case FET_PCIE_SIMPLE_SYNC: res = usdr_vfs_obj_param_init_array_param(base, (void*)n, - s_lmk05318_params, - SIZEOF_ARRAY(s_lmk05318_params)); + s_simplesync_params, + SIZEOF_ARRAY(s_simplesync_params)); break; case FET_PCIE_SUPER_SYNC: res = usdr_vfs_obj_param_init_array_param(base, @@ -245,6 +262,12 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi s_ext_fe_100_5000_params, SIZEOF_ARRAY(s_ext_fe_100_5000_params)); break; + case FET_PCIE_XMASS: + res = usdr_vfs_obj_param_init_array_param(base, + (void*)n, + s_xmass_params, + SIZEOF_ARRAY(s_xmass_params)); + break; default: break; } @@ -371,18 +394,24 @@ int _debug_pciefe_cmd_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) return res; } - -int _debug_lmk05318_reg_get(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t* ovalue) +static int _debug_lmk05318_reg_get(dev_fe_t* o, uint64_t* ovalue) { - dev_fe_t* o = (dev_fe_t*)obj->object; *ovalue = o->debug_lmk05318_last; return 0; } +int _debug_simplesync_lmk05318_reg_get(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + return _debug_lmk05318_reg_get((dev_fe_t*)obj->object, ovalue); +} -int _debug_lmk05318_reg_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) +int _debug_xmass_lmk05318_reg_get(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + return _debug_lmk05318_reg_get((dev_fe_t*)obj->object, ovalue); +} + +int _debug_lmk05318_reg_set(dev_fe_t* o, lmk05318_state_t* lmk, uint64_t value) { - dev_fe_t* o = (dev_fe_t*)obj->object; int res; unsigned addr = (value >> 8) & 0x7fff; unsigned data = value & 0xff; @@ -391,13 +420,13 @@ int _debug_lmk05318_reg_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) o->debug_lmk05318_last = ~0u; if (value & 0x800000) { - res = lmk05318_reg_wr(&o->fe.simplesync.lmk, addr, data); + res = lmk05318_reg_wr(lmk, addr, data); USDR_LOG("XDEV", USDR_LOG_WARNING, "LMK05318 WR REG %04x => %04x\n", - (unsigned)addr, data); + (unsigned)addr, data); } else { d = 0xff; - res = lmk05318_reg_rd(&o->fe.simplesync.lmk, addr, &d); + res = lmk05318_reg_rd(lmk, addr, &d); o->debug_lmk05318_last = d; USDR_LOG("XDEV", USDR_LOG_WARNING, "LMK05318 RD REG %04x <= %04x\n", @@ -408,6 +437,66 @@ int _debug_lmk05318_reg_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) return res; } +int _debug_simplesync_lmk05318_reg_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) +{ + dev_fe_t* o = (dev_fe_t*)obj->object; + return _debug_lmk05318_reg_set(o, &o->fe.simplesync.lmk, value); +} + +int _debug_xmass_lmk05318_reg_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) +{ + dev_fe_t* o = (dev_fe_t*)obj->object; + return _debug_lmk05318_reg_set(o, &o->fe.xmass.lmk, value); +} + +int _debug_xmass_ctrl_reg_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) +{ + dev_fe_t* o = (dev_fe_t*)obj->object; + unsigned addr = (value >> 24) & 0x7f; + unsigned data = value & 0xffffff; + int res; + board_xmass_t* board = &o->fe.xmass; + uint32_t d; + o->debug_xmass_ctrl_last = ~0u; + + if (value & 0x80000000) { + res = board_xmass_ctrl_cmd_wr(board, addr, data); + + USDR_LOG("XDEV", USDR_LOG_WARNING, "XMASS_CTRL WR REG %04x => %04x\n", + (unsigned)addr, data); + } else { + d = 0xffffff; + res = board_xmass_ctrl_cmd_rd(board, addr, &d); + o->debug_xmass_ctrl_last = d; + + USDR_LOG("XDEV", USDR_LOG_WARNING, "XMASS_CTRL RD REG %04x <= %04x\n", + (unsigned)addr, + o->debug_xmass_ctrl_last); + } + + return res; +} + +int _debug_xmass_ctrl_reg_get(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + dev_fe_t* o = (dev_fe_t*)obj->object; + *ovalue = o->debug_xmass_ctrl_last; + return 0; +} + +int _debug_xmass_calfreq_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) +{ + dev_fe_t* o = (dev_fe_t*)obj->object; + return board_xmass_tune_cal_lo(&o->fe.xmass, value); +} + +int _debug_xmass_calfreq_get(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + dev_fe_t* o = (dev_fe_t*)obj->object; + *ovalue = o->fe.xmass.calfreq; + return 0; +} + int _debug_lmk05318_calfreq_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) { dev_fe_t* o = (dev_fe_t*)obj->object; diff --git a/src/lib/device/ext_xmass/CMakeLists.txt b/src/lib/device/ext_xmass/CMakeLists.txt new file mode 100644 index 00000000..f95299d3 --- /dev/null +++ b/src/lib/device/ext_xmass/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (c) 2023-2025 Wavelet Lab +# SPDX-License-Identifier: MIT + +set(BOARD_XMASS_LIB_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/ext_xmass.c +) + +set(HW_FILES ext_xmass_ctrl) +foreach(I ${HW_FILES}) + message(STATUS "Generating header for ${I}") + GENERATE_YAML_H(${CMAKE_CURRENT_SOURCE_DIR}/${I}.yaml ${CMAKE_CURRENT_BINARY_DIR}/def_${I}.h) + + list(APPEND USDR_DEPEND_TARGETS generate_${I}) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${I}.yaml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/usdr/schema/) +endforeach() + +list(APPEND USDR_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) +list(APPEND USDR_LIBRARY_FILES ${BOARD_XMASS_LIB_FILES}) +set(USDR_LIBRARY_FILES ${USDR_LIBRARY_FILES} PARENT_SCOPE) +set(USDR_DEPEND_TARGETS ${USDR_DEPEND_TARGETS} PARENT_SCOPE) +set(USDR_INCLUDE_DIRS ${USDR_INCLUDE_DIRS} PARENT_SCOPE) + + + diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c new file mode 100644 index 00000000..7e3b3eae --- /dev/null +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -0,0 +1,226 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "ext_xmass.h" +#include "../ipblks/gpio.h" + +#include +#include +#include + +#include "../hw/tca9555/tca9555.h" +#include "../hw/lmk05318/lmk05318.h" + +#include "def_ext_xmass_ctrl.h" + +// XRA1201IL24TR-F (0x28 I2C) +// Port0: +// 0 GPIO_BDISTRIB : Enable OUT_REF_B[0:3] and OUT_SYREF_B[0:3] for 4 board sync +// 1 GPIO_BLOCAL : Enable local PPS and REF distribution +// 2 RF_CAL_DST_SEL : 0 - RF_CAL_EXT (general rx port) / 1 - RF_CAL_INT (LNA3 port) +// 3 RF_CAL_SRC_SEL : 0 - RF_LO_SRC (from LMK) / 1 - RF_NOISE_SRC (from NOISE GEN) +// 4 GPS_PWREN : Enable GPS module + DC-bias +// 5 GPIO_SYNC : LMK05318B GPIO0/SYNC_N +// 6 SYSREF_1PPS_SEL : 0 - LMK_1PPS, 1 - From SDR_A +// 7 EN_LMX : Enable LMK05318B +// +// Port1: +// 8 RF_EN : Enables Power Amplifiers +// 9 RF_CAL_SW : 0 - Use RF cal source as FB, 1 - Use XSDR TX as FB +// 10 RF_LB_SW : 0 - Normal operation, 1 - use LB path to XSDR RX +// 11 RF_NOISE_EN : Enable 12V generator for Zener +// 12 SYSREF_GPSRX_SEL : TX_SYREF_MUX => demuliplexed to ( == 0) ? CLK_SYSREF_OUT : GPS_RX +// 13 M3_RTS +// 14 M2_RTS +// 15 M1_RTS +// +// LMK05318 (0x65 I2C) +// OUT[0:3] unused +// OUT4 RF / LVDS +// OUT5 aux_p + aux_n +// OUT6 REF / LVCMOS +// OUT7 1PPS / LVCMOS +// +// M2_Connector (master) +// LED1/SDA CLK_SDA +// LED1/SCL CLK_SCL +// GPIO0/SDA M1_CTS +// GPIO1/SCL M2_CTS +// GPIO3/RX TX_SYREF_MUX +// GPIO2/PPS 1PPS_IN +// GPIO4/TX GPS_TX +// GPIO5 M3_RXD +// GPIO6 M3_TXD +// GPIO7 M3_CTS +// GPIO8 M1_TXD +// GPIO9 M1_RXD +// GPIO10 M2_TXD +// GPIO11 M2_RXD +// +// M2_Connector (slaves) +// GPIO2/PPS 1PPS_IN +// GPIO8 Mx_RXD +// GPIO9 Mx_RTS +// GPIO10 Mx_CTS +// GPIO11 Mx_TXD + + +enum { + I2C_ADDR_LMK = 0x65, + I2C_ADDR_XRA1201 = 0x14, + I2C_GPS_RX = 0x20, + I2C_GPS_TX = 0x21, +}; + +static int _board_xmass_fill_lmk05318(board_xmass_t* ob, lmk05318_out_config_t lmk05318_outs_cfg[8]) +{ + unsigned cfreq = (ob->calfreq < 3.1e6) ? 0 : ob->calfreq; + lmk05318_port_request(&lmk05318_outs_cfg[0], 0, 0, false, OUT_OFF); + lmk05318_port_request(&lmk05318_outs_cfg[1], 1, 0, false, OUT_OFF); + lmk05318_port_request(&lmk05318_outs_cfg[2], 2, 0, false, OUT_OFF); + lmk05318_port_request(&lmk05318_outs_cfg[3], 3, 0, false, OUT_OFF); + lmk05318_port_request(&lmk05318_outs_cfg[4], 4, cfreq, false, cfreq == 0 ? OUT_OFF : LVDS); + lmk05318_port_request(&lmk05318_outs_cfg[5], 5, 0, false, OUT_OFF); + lmk05318_port_request(&lmk05318_outs_cfg[6], 6, ob->refclk, false, LVCMOS); + lmk05318_port_request(&lmk05318_outs_cfg[7], 7, 1, false, LVCMOS); + + lmk05318_set_port_affinity(&lmk05318_outs_cfg[4], AFF_APLL2); + return 0; +} + +int board_xmass_init(lldev_t dev, + unsigned subdev, + unsigned gpio_base, + const char* compat, + unsigned int i2c_loc, + board_xmass_t* ob) +{ + int res = 0; + + // This breakout is compatible with M.2 key A/E or A+E boards + if ((strcmp(compat, "m2a+e") != 0) && (strcmp(compat, "m2e") != 0) && (strcmp(compat, "m2a") != 0)) + return -ENODEV; + + + // Configure external SDA/SCL + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO0, GPIO_CFG_IN); + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO1, GPIO_CFG_IN); + + // Configure 1PPS input + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO2, GPIO_CFG_ALT0); + + unsigned i2c_lmka = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_LMK); + unsigned i2c_xraa = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_XRA1201); + uint16_t val; + uint16_t out_msk = 0xe000 | (1 << 5); + + res = (res) ? res : tca9555_reg16_get(dev, subdev, i2c_xraa, TCA9555_CFG0, &val); + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_CFG0, out_msk); + res = (res) ? res : tca9555_reg16_get(dev, subdev, i2c_xraa, TCA9555_CFG0, &val); + + if (res) + return res; + + if (val != out_msk) { + USDR_LOG("XMSS", USDR_LOG_INFO, "GPIO expander initialization failed! Reported mask %04x != %04x\n", val, out_msk); + return -ENODEV; + } + + // En LMK to ckeck it + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0,(3) | (1<<4) | (1 << 7) | (1 << 5) | (1 << 11)); + + usleep(250000); + + ob->refclk = 25e6; + ob->calfreq = 444e6; + + //LMK05318 init start + lmk05318_xo_settings_t xo; + xo.doubler_enabled = false; + xo.fdet_bypass = false; + xo.fref = 26000000; + xo.pll1_fref_rdiv = 1; + xo.type = XO_AC_DIFF_EXT; + + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + dpll.enabled = false; + dpll.en[LMK05318_PRIREF] = true; + dpll.fref[LMK05318_PRIREF] = 1; + dpll.type[LMK05318_PRIREF] = DPLL_REF_TYPE_DIFF_NOTERM; + dpll.dc_mode[LMK05318_PRIREF] = DPLL_REF_DC_COUPLED_INT; + dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; + + lmk05318_out_config_t lmk05318_outs_cfg[8]; + res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); + res = res ? res : lmk05318_create(dev, subdev, i2c_lmka, &xo, &dpll, lmk05318_outs_cfg, 8, &ob->lmk, false); + + ob->i2c_xraa = i2c_xraa; + + if (res) { + USDR_LOG("XMSS", USDR_LOG_ERROR, "Unable to initialize XMASS\n"); + } + return res; +} + +int board_xmass_ctrl_cmd_wr(board_xmass_t* ob, uint32_t addr, uint32_t reg) +{ + int res; + + switch (addr) { + case P0: + case P1: + res = tca9555_reg8_set(ob->lmk.dev, ob->lmk.subdev, ob->i2c_xraa, TCA9555_OUT0 + addr - P0, reg); + break; + default: + return -EINVAL; + } + + // TODO update internal state!!! + return res; +} + +int board_xmass_ctrl_cmd_rd(board_xmass_t* ob, uint32_t addr, uint32_t* preg) +{ + uint8_t oval; + int res; + + switch (addr) { + case P0: + case P1: + res = tca9555_reg8_get(ob->lmk.dev, ob->lmk.subdev, ob->i2c_xraa, TCA9555_OUT0 + addr - P0, &oval); + break; + default: + return -EINVAL; + } + + *preg = oval; + return res; +} + + +int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) +{ + int res = 0; + unsigned los_msk; + lmk05318_out_config_t lmk05318_outs_cfg[8]; + + ob->calfreq = callo; + + res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); + res = res ? res : lmk05318_solver(&ob->lmk, lmk05318_outs_cfg, 8); + res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false); + res = res ? res : lmk05318_softreset(&ob->lmk); + res = res ? res : lmk05318_reset_los_flags(&ob->lmk); + res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); + res = res ? res : lmk05318_sync(&ob->lmk); + res = res ? res : lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + + return res; +} + + + + + + diff --git a/src/lib/device/ext_xmass/ext_xmass.h b/src/lib/device/ext_xmass/ext_xmass.h new file mode 100644 index 00000000..2a56a364 --- /dev/null +++ b/src/lib/device/ext_xmass/ext_xmass.h @@ -0,0 +1,53 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef EXT_XMASS_H +#define EXT_XMASS_H + +#include +#include +#include +#include "../device.h" +#include "../device_vfs.h" + +#include "../hw/lmk05318/lmk05318.h" + +struct board_xmass { + lmk05318_state_t lmk; + + // Board configuration + bool distrib_ext; + bool distrib_local; + bool pwr_gps_en; + bool pwr_pa_en; + bool pwr_noise_en; + + bool cal_dst_lna3; // 0 -- CAL_TO_RX; 1 -- CAL_TO_LNA3 + bool cal_src_noise; // 0 -- CAL_CW; 1 -- CAL_NOISE + bool pps_from_sdra; // 0 -- PPS_LMK; 1 -- PPS_SDRA + bool loopback_en; // 0 -- Normal; 1 -- Loopback (TX & Cal) + bool loopback_mode_tx; // 0 -- RF_CAL_SOURCE; 1 -- TX_SOURCE + + unsigned gpio_base; + unsigned i2c_xraa; + + unsigned refclk; + unsigned calfreq; +}; +typedef struct board_xmass board_xmass_t; + +int board_xmass_init(lldev_t dev, + unsigned subdev, + unsigned gpio_base, + const char* compat, + unsigned int i2c_loc, + board_xmass_t* ob); + + +// High level contorl interface +int board_xmass_ctrl_cmd_wr(board_xmass_t* ob, uint32_t addr, uint32_t reg); +int board_xmass_ctrl_cmd_rd(board_xmass_t* ob, uint32_t addr, uint32_t* preg); + +int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo); + +#endif diff --git a/src/lib/device/ext_xmass/ext_xmass_ctrl.yaml b/src/lib/device/ext_xmass/ext_xmass_ctrl.yaml new file mode 100644 index 00000000..74f89f52 --- /dev/null +++ b/src/lib/device/ext_xmass/ext_xmass_ctrl.yaml @@ -0,0 +1,71 @@ +# Copyright (c) 2023-2024 Wavelet Lab +# SPDX-License-Identifier: MIT + +# Register desc and visual map +name: XMASS_CTRL +desc: XMass Debug control GPIOs +revision: "0.0.1" +processors: [ c ] +bus: + type: VIRTUAL + usdr_path: /debug/hw/xmass_ctrl/0/reg + wr_mask: 0x80000000 +addr_width: 8 +data_width: 24 +# page_prefix: True +field_prefix: [ RegName ] +field_macros: True + +pages: + - name: I2C_GPIO + regs: +# + - addr: 0x00 + name: P0 + fields: + - bits: "0" + name: BDISTRIB + desc: Enable OUT_REF_B and OUT_SYREF_B[0 for 4 sync boards + - bits: "1" + name: BLOCAL + desc: Enable local PPS and REF distribution + - bits: "2" + name: RF_CAL_DST_SEL + desc: 0 - RF_CAL_EXT (general rx port) / 1 - RF_CAL_INT (LNA3 port) + - bits: "3" + name: RF_CAL_SRC_SEL + desc: 0 - RF_LO_SRC (from LMK) / 1 - RF_NOISE_SRC (from NOISE GEN) + - bits: "4" + name: GPS_PWREN + desc: Enable GPS module + DC-bias + - bits: "5" + name: LMK_SYNCN + desc: Set LMK05318B SYNC_N port + - bits: "6" + name: SYSREF_1PPS_SEL + desc: 0 - LMK_1PPS, 1 - From SDR_A + - bits: "7" + name: EN_LMX + desc: Enable LMK05318B +# + - addr: 0x01 + name: P1 + fields: + - bits: "0" + name: RF_EN + desc: Enables Power Amplifiers + - bits: "1" + name: RF_CAL_SW + desc: 0 - Use RF cal source as FB, 1 - Use XSDR TX as FB + - bits: "2" + name: RF_LB_SW + desc: 0 - Normal operation, 1 - use LB path to XSDR RX + - bits: "3" + name: RF_NOISE_EN + desc: Enable 14V generator for Zener noise source + - bits: "4" + name: SYSREF_GPSRX_SEL + desc: 0 - TX_SYREF_MUX demuliplexing to CLK_SYSREF_OUT, 1 TX_SYREF_MUX to GPS_RX + - bits: "7:5" + name: RTS + desc: Interboard sync logic diff --git a/src/lib/hw/CMakeLists.txt b/src/lib/hw/CMakeLists.txt index cbe453b1..5d3fcfcf 100644 --- a/src/lib/hw/CMakeLists.txt +++ b/src/lib/hw/CMakeLists.txt @@ -2,10 +2,10 @@ # SPDX-License-Identifier: MIT set(HW_FILES common si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 - lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820) + lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820 tca9555) # YAML registers generators set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 - lmk04832 xra1405 tca6424a adf4002b lp875484 lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820) + lmk04832 xra1405 tca6424a adf4002b lp875484 lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820 tca9555) foreach(I ${HW_FILES}) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/${I} HW_DIR_FILES) diff --git a/src/lib/hw/tca9555/tca9555.c b/src/lib/hw/tca9555/tca9555.c new file mode 100644 index 00000000..6146fd4e --- /dev/null +++ b/src/lib/hw/tca9555/tca9555.c @@ -0,0 +1,46 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "tca9555.h" +#include "def_tca9555.h" + +#include + +int tca9555_reg8_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint8_t value) +{ + uint8_t data[2] = { reg, value }; + return lowlevel_ls_op(dev, subdev, + USDR_LSOP_I2C_DEV, ls_op_addr, + 0, NULL, 2, data); +} + +int tca9555_reg8_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint8_t* oval) +{ + return lowlevel_ls_op(dev, subdev, + USDR_LSOP_I2C_DEV, ls_op_addr, + 1, oval, 1, ®); +} + +int tca9555_reg16_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint16_t value) +{ + uint8_t data[3] = { reg, value, value >> 8 }; + return lowlevel_ls_op(dev, subdev, + USDR_LSOP_I2C_DEV, ls_op_addr, + 0, NULL, 3, data); +} + +int tca9555_reg16_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint16_t* oval) +{ + uint8_t data[1] = { reg }; + uint8_t odata[2] = { 0x00, 0x00 }; + int res = lowlevel_ls_op(dev, subdev, + USDR_LSOP_I2C_DEV, ls_op_addr, + 2, odata, 1, data); + + *oval = (((unsigned)odata[0]) << 8) | odata[1]; + return res; +} diff --git a/src/lib/hw/tca9555/tca9555.h b/src/lib/hw/tca9555/tca9555.h new file mode 100644 index 00000000..6528bef6 --- /dev/null +++ b/src/lib/hw/tca9555/tca9555.h @@ -0,0 +1,27 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef TCA9555_H +#define TCA9555_H + +#include + +enum tca9555_regs { + TCA9555_IN0 = 0, + TCA9555_OUT0 = 2, + TCA9555_INV0 = 4, + TCA9555_CFG0 = 6, // 0 - Output, 1 - Input/Hi-Z +}; + +int tca9555_reg8_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint8_t value); +int tca9555_reg8_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint8_t* oval); + +int tca9555_reg16_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint16_t value); +int tca9555_reg16_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t reg, uint16_t* oval); + + +#endif diff --git a/src/lib/hw/tca9555/tca9555.yaml b/src/lib/hw/tca9555/tca9555.yaml new file mode 100644 index 00000000..74f3cf67 --- /dev/null +++ b/src/lib/hw/tca9555/tca9555.yaml @@ -0,0 +1,87 @@ +# Copyright (c) 2023-2024 Wavelet Lab +# SPDX-License-Identifier: MIT + +# Register desc and visual map +name: TCA9555 +desc: GPIO +revision: "0.0.1" +processors: [ c ] +bus: + type: I2C + rd_mask: 0x8000 + usdr_path: /debug/hw/tca9555/0/reg +addr_width: 8 +data_width: 8 +# page_prefix: True +# field_prefix: [ Page, RegName ] +field_macros: True + +pages: + - name: Top + regs: + - addr: 0x00 + name: GSR1 + + - addr: 0x01 + name: GSR2 + + - addr: 0x02 + name: OCR1 + + - addr: 0x03 + name: OCR2 + + - addr: 0x04 + name: PIR1 + + - addr: 0x05 + name: PIR2 + + - addr: 0x06 + name: GCR1 + + - addr: 0x07 + name: GCR2 + + - addr: 0x08 + name: PUR1 + + - addr: 0x09 + name: PUR2 + + - addr: 0x0A + name: IER1 + + - addr: 0x0B + name: IER2 + + - addr: 0x0C + name: TSCR1 + + - addr: 0x0D + name: TSCR2 + + - addr: 0x0E + name: ISR1 + + - addr: 0x0F + name: ISR2 + + - addr: 0x10 + name: REIR1 + + - addr: 0x11 + name: REIR2 + + - addr: 0x12 + name: FEIR1 + + - addr: 0x13 + name: FEIR2 + + - addr: 0x14 + name: IFR1 + + - addr: 0x15 + name: IFR2 + From 3b192c4ccf83b49fc84f180a0a8baf7f33f8d5a4 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 21 May 2025 23:16:59 +0400 Subject: [PATCH 136/397] fix for multithreading accesing the same bus --- src/lib/lowlevel/usb_uram/usb_uram_generic.c | 8 +++++--- src/lib/lowlevel/usb_uram/usb_uram_libusb.c | 15 ++++++--------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/lib/lowlevel/usb_uram/usb_uram_generic.c b/src/lib/lowlevel/usb_uram/usb_uram_generic.c index 870d0dc6..493d1ede 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_generic.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_generic.c @@ -5,6 +5,7 @@ #include #include #include "../../device/generic_usdr/generic_regs.h" +#include usb_uram_generic_t* get_uram_generic(lldev_t dev); @@ -261,18 +262,19 @@ int usb_uram_read_wait(lldev_t dev, unsigned lsop, lsopaddr_t ls_op_addr, size_t usb_uram_generic_t* gen = get_uram_generic(dev); unsigned int_number, reg; - char busname[4]; + const char* busname; + switch(lsop) { case USDR_LSOP_SPI: int_number = gen->spi_int_number[ls_op_addr]; reg = gen->db.spi_core[ls_op_addr]; - strcpy(busname, "SPI"); + busname = "SPI"; break; case USDR_LSOP_I2C_DEV: int_number = gen->i2c_int_number[ls_op_addr]; reg = gen->db.i2c_base[ls_op_addr]; - strcpy(busname, "I2C"); + busname = "I2C"; break; default: return -EOPNOTSUPP; diff --git a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c index 237de7a6..9fbc730b 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c @@ -62,7 +62,7 @@ enum { IN_NTFY_SIZE = 64, //256, IN_RB_SIZE = 256, - MAX_NTFY_REQS = 1, + MAX_NTFY_REQS = 32, MAX_RB_REQS = 1, MAX_REQUEST_RB_SIZE = 256, @@ -83,7 +83,7 @@ enum { enum { STREAM_MAX_SLOTS = 64, - MAX_RB_THREADS = 8, + MAX_RB_THREADS = MAX_NTFY_REQS, }; struct stream_params { @@ -129,6 +129,7 @@ struct usb_dev unsigned rx_buffer_missed[1]; uint32_t rb_valid_idx; + uint32_t rb_req_idx; uint32_t tx_stat_prev[4]; uint32_t tx_stat_cnt; @@ -190,6 +191,7 @@ int usb_async_start(usb_dev_t* dev) } dev->rb_valid_idx = 0; + dev->rb_req_idx = 0; dev->tx_stat_cnt = 0; dev->tx_stat_rate = 64; // TX stat update rate return libusb_generic_create_thread(&dev->gdev); @@ -450,8 +452,8 @@ static int usb_read_bus(lldev_t dev, unsigned interrupt_number, UNUSED unsigned { int res; usb_dev_t* d = (usb_dev_t*)dev; - - res = libusb_to_errno(libusb_submit_transfer(d->transfer_ntfy[0])); + unsigned idx = __atomic_fetch_add(&d->rb_req_idx, 1, __ATOMIC_SEQ_CST) & (MAX_NTFY_REQS - 1); + res = libusb_to_errno(libusb_submit_transfer(d->transfer_ntfy[idx])); if (res) return res; @@ -461,11 +463,6 @@ static int usb_read_bus(lldev_t dev, unsigned interrupt_number, UNUSED unsigned if (meminsz != 0) { *(uint32_t*)pin = d->rbvalue[interrupt_number]; -#if 0 - res = usb_uram_reg_in(dev, reg, (uint32_t*)pin); - if (res) - return res; -#endif } return res; } From 0d102d4746e90b855eeeb229759f78df665059c1 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 21 May 2025 22:34:48 +0300 Subject: [PATCH 137/397] add check APLL locks for XMASS --- src/lib/device/ext_xmass/ext_xmass.c | 48 ++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 7e3b3eae..242a52f3 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -155,11 +155,55 @@ int board_xmass_init(lldev_t dev, res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); res = res ? res : lmk05318_create(dev, subdev, i2c_lmka, &xo, &dpll, lmk05318_outs_cfg, 8, &ob->lmk, false); - ob->i2c_xraa = i2c_xraa; - if (res) { USDR_LOG("XMSS", USDR_LOG_ERROR, "Unable to initialize XMASS\n"); } + + usleep(10000); //wait until lmk digests all this + + //reset LOS flags after soft-reset (inside lmk05318_create()) + res = lmk05318_reset_los_flags(&ob->lmk); + if(res) + return res; + + //wait for PRIREF/SECREF validation + res = lmk05318_wait_dpll_ref_stat(&ob->lmk, 4*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on + if(res) + { + USDR_LOG("XMSS", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); + return res; + } + + //wait for lock + //APLL1/DPLL + res = lmk05318_wait_apll1_lock(&ob->lmk, 100000); + + //APLL2 (if needed) + if(res == 0 && ob->lmk.vco2_freq) + { + //reset LOS flags once again because APLL2 LOS is set after APLL1 tuning + res = lmk05318_reset_los_flags(&ob->lmk); + res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 100000); + } + + unsigned los_msk; + lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + + if(res) + { + USDR_LOG("XMSS", USDR_LOG_ERROR, "LMK03518 PLLs not locked during specified timeout"); + return res; + } + + //sync to make APLL1/APLL2 & out channels in-phase + res = lmk05318_sync(&ob->lmk); + if(res) + return res; + + USDR_LOG("XMSS", USDR_LOG_INFO, "LMK03518 outputs synced"); + + ob->i2c_xraa = i2c_xraa; + return res; } From 9c71c09638d22c7fa59d3228be835b31a3ad4839 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 21 May 2025 23:32:43 +0300 Subject: [PATCH 138/397] LMK - add settings for XO=26M --- .../device/ext_simplesync/ext_simplesync.c | 2 +- src/lib/device/ext_xmass/ext_xmass.c | 2 +- src/lib/device/m2_dsdr/m2_dsdr.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 109 ++++++++++++++---- src/utests/lmk05318_solver_test.c | 20 +++- 5 files changed, 104 insertions(+), 31 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 8a16a93c..5e9e15e8 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -89,7 +89,7 @@ int board_ext_simplesync_init(lldev_t dev, usleep(50000); lmk05318_xo_settings_t xo; - xo.doubler_enabled = false; + xo.doubler_enabled = true; xo.fdet_bypass = false; xo.fref = 26000000; xo.pll1_fref_rdiv = 1; diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 242a52f3..dbfd2721 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -136,7 +136,7 @@ int board_xmass_init(lldev_t dev, //LMK05318 init start lmk05318_xo_settings_t xo; - xo.doubler_enabled = false; + xo.doubler_enabled = true; xo.fdet_bypass = false; xo.fref = 26000000; xo.pll1_fref_rdiv = 1; diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 7fa7369c..469a03b7 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1426,7 +1426,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // //LMK05318 init start lmk05318_xo_settings_t xo; - xo.doubler_enabled = false; + xo.doubler_enabled = true; xo.fdet_bypass = false; xo.fref = 26000000; xo.pll1_fref_rdiv = 1; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 0b96fd47..696f062b 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -29,7 +29,7 @@ enum { VCO_APLL2_MAX = 6250000000ull, APLL1_PD_MIN = 1000000, - APLL1_PD_MAX = 50000000, + APLL1_PD_MAX = 80000000, APLL2_PD_MIN = 10000000, APLL2_PD_MAX = 150000000, @@ -77,6 +77,12 @@ enum SDM_ORDER_FORTH = 0x4, }; +enum +{ + XO25 = 25000000, + XO26 = 26000000, +}; + #define DPLL_FDIV_FRAC_MAX 0.9375f #define DPLL_FDIV_FRAC_MIN 0.0625f @@ -487,6 +493,82 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett if(d->dpll.enabled == false) { // WITHOUT DPLL + + switch(d->xo.fref) + { + case XO25: + { + USDR_LOG("5318", USDR_LOG_INFO, "XO=25M, applying specific settings..."); + + uint32_t bawlock_regs[] = + { + 0x00510A, //R81 + 0x005200, // | + 0x00530E, // | + 0x0054A6, // | + 0x005500, // | + 0x005600, // | + 0x00571E, // | + 0x005884, // | + 0x005980, // | BAW lock&unlock detection, may depend on XO params + 0x005A00, // | + 0x005B14, // | + 0x005C00, // | + 0x005D0E, // | + 0x005EA6, // | + 0x005F00, // | + 0x006000, // | + 0x00611E, // | + 0x006284, // | + 0x006380, //R99 + }; + + res = lmk05318_add_reg_to_map(d, bawlock_regs, SIZEOF_ARRAY(bawlock_regs)); + if(res) + return res; + + break; + } + case XO26: + { + USDR_LOG("5318", USDR_LOG_INFO, "XO=26M, applying specific settings..."); + + uint32_t bawlock_regs[] = + { + 0x00510A, + 0x005200, + 0x00530F, + 0x00543C, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D0F, + 0x005E3C, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + }; + + res = lmk05318_add_reg_to_map(d, bawlock_regs, SIZEOF_ARRAY(bawlock_regs)); + if(res) + return res; + + break; + } + default: + { + USDR_LOG("5318", USDR_LOG_ERROR, "XO=%" PRIu64 " not supported! Use 25 or 26M", (uint64_t)d->xo.fref); + return -EINVAL; + } + } + uint32_t no_dpll_regs[] = { MAKE_LMK05318_DEV_CTL(0, 0, 0/*SYNC_AUTO_DPLL*/, 1, 1, 1, 1), //R12 set APLL1 mode - NO DPLL @@ -495,27 +577,6 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett MAKE_LMK05318_DPLL_GEN_CTL(0, 0, 0, 0, 0, 0, 0), //R252 disable DPLL MAKE_LMK05318_PLL1_CALCTRL0(1, 0, 1), //R79 BAW_LOCKDET_EN=1 PLL1_VCOWAIT=1 MAKE_LMK05318_BAW_LOCKDET_PPM_MAX_BY1(1, 0), //R80 BAW_LOCK=1 - - 0x00510A, //R81 - 0x005200, // | - 0x00530E, // | - 0x0054A6, // | - 0x005500, // | - 0x005600, // | - 0x00571E, // | - 0x005884, // | - 0x005980, // | BAW lock&unlock detection, may depend on XO params - 0x005A00, // | - 0x005B14, // | - 0x005C00, // | - 0x005D0E, // | - 0x005EA6, // | - 0x005F00, // | - 0x006000, // | - 0x00611E, // | - 0x006284, // | - 0x006380, //R99 - }; res = lmk05318_add_reg_to_map(d, no_dpll_regs, SIZEOF_ARRAY(no_dpll_regs)); } @@ -907,7 +968,7 @@ static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, return fvco2_fact; } -static int lmk05318_tune_apll2_ex(lmk05318_state_t* d) +static int lmk05318_tune_apll2(lmk05318_state_t* d) { int res; @@ -2007,7 +2068,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned } //tune APLL2 - res = lmk05318_tune_apll2_ex(d); + res = lmk05318_tune_apll2(d); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "error %d tuning APLL2", res); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 17ca9526..fc1cd3fd 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -368,6 +368,14 @@ START_TEST(lmk05318_simplesync_test1) START_TEST(lmk05318_solver_test7) { int res = 0; + + lmk05318_xo_settings_t xo; + xo.fref = 26000000; + xo.doubler_enabled = true; + xo.fdet_bypass = false; + xo.pll1_fref_rdiv = 1; + xo.type = XO_CMOS; + lmk05318_out_config_t* p = &cfg[0]; res = res ? res : lmk05318_port_request(p++, 0, 0, false, OUT_OFF); @@ -380,11 +388,16 @@ START_TEST(lmk05318_solver_test7) res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS); res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); - ck_assert_int_eq( res, 0 ); - lmk05318_registers_map_reset(); - res = lmk05318_solver(&dev, cfg, SIZEOF_ARRAY(cfg)); + lmk05318_dpll_settings_t dpll; + dpll.enabled = false; + + lmk05318_state_t st; + memset(&st, 0, sizeof(st)); + + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); } @@ -410,7 +423,6 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_simplesync_test1); tcase_add_test(tc_core, lmk05318_solver_test7); - suite_add_tcase(s, tc_core); return s; } From fc4a60fd8d86587953bed07b9a10514750ed4c6c Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 22 May 2025 17:21:44 +0400 Subject: [PATCH 139/397] fix minor issuies --- src/lib/device/device_fe.c | 4 ++-- src/lib/device/ext_xmass/ext_xmass.c | 4 ++-- src/lib/device/m2_dsdr/m2_dsdr.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib/device/device_fe.c b/src/lib/device/device_fe.c index a76ac86f..55737a6b 100644 --- a/src/lib/device/device_fe.c +++ b/src/lib/device/device_fe.c @@ -419,13 +419,13 @@ int _debug_lmk05318_reg_set(dev_fe_t* o, lmk05318_state_t* lmk, uint64_t value) o->debug_lmk05318_last = ~0u; - if (value & 0x800000) { + if (!(value & 0x800000)) { res = lmk05318_reg_wr(lmk, addr, data); USDR_LOG("XDEV", USDR_LOG_WARNING, "LMK05318 WR REG %04x => %04x\n", (unsigned)addr, data); } else { - d = 0xff; + d = 0xffffffff; res = lmk05318_reg_rd(lmk, addr, &d); o->debug_lmk05318_last = d; diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index dbfd2721..4232c850 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -112,7 +112,7 @@ int board_xmass_init(lldev_t dev, unsigned i2c_lmka = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_LMK); unsigned i2c_xraa = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_XRA1201); uint16_t val; - uint16_t out_msk = 0xe000 | (1 << 5); + uint16_t out_msk = 0xe000; res = (res) ? res : tca9555_reg16_get(dev, subdev, i2c_xraa, TCA9555_CFG0, &val); res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_CFG0, out_msk); @@ -127,7 +127,7 @@ int board_xmass_init(lldev_t dev, } // En LMK to ckeck it - res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0,(3) | (1<<4) | (1 << 7) | (1 << 5) | (1 << 11)); + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5)); usleep(250000); diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 469a03b7..79b3edca 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1105,7 +1105,7 @@ int _debug_lmk05318_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return 0; } - if (value & 0x800000) { + if (!(value & 0x800000)) { res = lmk05318_reg_wr(&o->lmk, addr, data); USDR_LOG("XDEV", USDR_LOG_WARNING, "LMK05318 WR REG %04x => %04x\n", From 98d8e335a1dc06e36f0633d0970ca04af84185f0 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 22 May 2025 17:28:08 +0300 Subject: [PATCH 140/397] try te fix XMASS freq change, +extra diagnostic +lite refact --- src/lib/device/ext_xmass/ext_xmass.c | 23 +++++++---------------- src/lib/hw/lmk05318/lmk05318.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 4232c850..2c816806 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -161,11 +161,6 @@ int board_xmass_init(lldev_t dev, usleep(10000); //wait until lmk digests all this - //reset LOS flags after soft-reset (inside lmk05318_create()) - res = lmk05318_reset_los_flags(&ob->lmk); - if(res) - return res; - //wait for PRIREF/SECREF validation res = lmk05318_wait_dpll_ref_stat(&ob->lmk, 4*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on if(res) @@ -177,14 +172,7 @@ int board_xmass_init(lldev_t dev, //wait for lock //APLL1/DPLL res = lmk05318_wait_apll1_lock(&ob->lmk, 100000); - - //APLL2 (if needed) - if(res == 0 && ob->lmk.vco2_freq) - { - //reset LOS flags once again because APLL2 LOS is set after APLL1 tuning - res = lmk05318_reset_los_flags(&ob->lmk); - res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 100000); - } + res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 100000); unsigned los_msk; lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state @@ -255,11 +243,14 @@ int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) res = res ? res : lmk05318_solver(&ob->lmk, lmk05318_outs_cfg, 8); res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false); res = res ? res : lmk05318_softreset(&ob->lmk); - res = res ? res : lmk05318_reset_los_flags(&ob->lmk); + usleep(10000); //wait until lmk digests all this + + res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); - res = res ? res : lmk05318_sync(&ob->lmk); - res = res ? res : lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state + + res = res ? res : lmk05318_sync(&ob->lmk); return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 696f062b..408816f8 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -2163,6 +2163,10 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout) unsigned los_msk; bool pll1_vm_inside; + res = lmk05318_reset_los_flags(d); + if(res) + return res; + while(timeout == 0 || elapsed < timeout) { uint64_t tk = clock_get_time(); @@ -2213,6 +2217,12 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout) int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) { + if(d->vco2_freq == 0) + { + USDR_LOG("5318", USDR_LOG_DEBUG, "APLL2 disabled, check lock ignored"); + return 0; + } + int res = 0; unsigned elapsed = 0; bool locked = false; @@ -2220,6 +2230,10 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) unsigned los_msk; bool pll2_vm_inside; + res = lmk05318_reset_los_flags(d); + if(res) + return res; + while(timeout == 0 || elapsed < timeout) { uint64_t tk = clock_get_time(); From 9502516f215eb47785e851134b62de44f5fbbc93 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 22 May 2025 18:40:48 +0400 Subject: [PATCH 141/397] xmass: lmk05318b soft reset fails retune APPL2 on preconfigured system, ignore it --- src/lib/device/ext_xmass/ext_xmass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 2c816806..b827b2e6 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -242,7 +242,7 @@ int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); res = res ? res : lmk05318_solver(&ob->lmk, lmk05318_outs_cfg, 8); res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false); - res = res ? res : lmk05318_softreset(&ob->lmk); + // res = res ? res : lmk05318_softreset(&ob->lmk); usleep(10000); //wait until lmk digests all this res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); From bd43313e99834e299c9738a2d3e628a63c5de98d Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 22 May 2025 18:13:07 +0300 Subject: [PATCH 142/397] add extra LMK out types --- .../device/ext_simplesync/ext_simplesync.c | 8 ++-- src/lib/device/ext_xmass/ext_xmass.c | 6 +-- src/lib/device/pe_sync/pe_sync.c | 4 +- src/lib/hw/lmk05318/lmk05318.c | 42 ++++++++++++++----- src/lib/hw/lmk05318/lmk05318.h | 17 +++++++- src/utests/lmk05318_solver_test.c | 20 ++++----- 6 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 5e9e15e8..33d88020 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -97,10 +97,10 @@ int board_ext_simplesync_init(lldev_t dev, lmk05318_out_config_t lmk_out[4]; - lmk05318_port_request(&lmk_out[0], 4, 25000000, false, LVCMOS); - lmk05318_port_request(&lmk_out[1], 5, 25000000, false, LVCMOS); - lmk05318_port_request(&lmk_out[2], 6, 25000000, false, LVCMOS); - lmk05318_port_request(&lmk_out[3], 7, 25000000, false, LVCMOS); + lmk05318_port_request(&lmk_out[0], 4, 25000000, false, LVCMOS_P_N); + lmk05318_port_request(&lmk_out[1], 5, 25000000, false, LVCMOS_P_N); + lmk05318_port_request(&lmk_out[2], 6, 25000000, false, LVCMOS_P_N); + lmk05318_port_request(&lmk_out[3], 7, 25000000, false, LVCMOS_P_N); lmk05318_set_port_affinity(&lmk_out[0], AFF_APLL1); lmk05318_set_port_affinity(&lmk_out[1], AFF_APLL1); diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index b827b2e6..a756635d 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -81,8 +81,8 @@ static int _board_xmass_fill_lmk05318(board_xmass_t* ob, lmk05318_out_config_t l lmk05318_port_request(&lmk05318_outs_cfg[3], 3, 0, false, OUT_OFF); lmk05318_port_request(&lmk05318_outs_cfg[4], 4, cfreq, false, cfreq == 0 ? OUT_OFF : LVDS); lmk05318_port_request(&lmk05318_outs_cfg[5], 5, 0, false, OUT_OFF); - lmk05318_port_request(&lmk05318_outs_cfg[6], 6, ob->refclk, false, LVCMOS); - lmk05318_port_request(&lmk05318_outs_cfg[7], 7, 1, false, LVCMOS); + lmk05318_port_request(&lmk05318_outs_cfg[6], 6, ob->refclk, false, LVCMOS_P_N); + lmk05318_port_request(&lmk05318_outs_cfg[7], 7, 1, false, LVCMOS_P_N); lmk05318_set_port_affinity(&lmk05318_outs_cfg[4], AFF_APLL2); return 0; @@ -242,8 +242,6 @@ int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); res = res ? res : lmk05318_solver(&ob->lmk, lmk05318_outs_cfg, 8); res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false); - // res = res ? res : lmk05318_softreset(&ob->lmk); - usleep(10000); //wait until lmk digests all this res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index b25b1246..865b64cb 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -306,8 +306,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : lmk05318_port_request(&lmk_out[3], 3, lmk_freq[3], false, LVDS); res = res ? res : lmk05318_port_request(&lmk_out[4], 4, lmk_freq[4], false, OUT_OFF); res = res ? res : lmk05318_port_request(&lmk_out[5], 5, lmk_freq[5], false, OUT_OFF); - res = res ? res : lmk05318_port_request(&lmk_out[6], 6, lmk_freq[6], false, LVCMOS); - res = res ? res : lmk05318_port_request(&lmk_out[7], 7, lmk_freq[7], false, LVCMOS); + res = res ? res : lmk05318_port_request(&lmk_out[6], 6, lmk_freq[6], false, LVCMOS_P_N); + res = res ? res : lmk05318_port_request(&lmk_out[7], 7, lmk_freq[7], false, LVCMOS_P_N); res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->gen, false /*dry_run*/); if(res) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 408816f8..3b7ee4ec 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1291,10 +1291,21 @@ int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) static inline const char* lmk05318_decode_fmt(unsigned f) { switch (f) { - case LVDS: return "OUT_OPTS_AC_LVDS"; - case CML: return "OUT_OPTS_AC_CML"; - case LVPECL: return "OUT_OPTS_AC_LVPECL"; - case LVCMOS: return "OUT_OPTS_LVCMOS_P_N"; + case LVDS: return "OUT_OPTS_AC_LVDS"; + case CML: return "OUT_OPTS_AC_CML"; + case LVPECL: return "OUT_OPTS_AC_LVPECL"; + case HCSL_EXT_50: return "OUT_OPTS_HCSL_EXT_50"; + case HCSL_INT_50: return "OUT_OPTS_HCSL_INT_50"; + case LVCMOS_HIZ_HIZ: return "OUT_OPTS_LVCMOS_HIZ_HIZ"; + case LVCMOS_HIZ_N: return "OUT_OPTS_LVCMOS_HIZ_N"; + case LVCMOS_HIZ_P: return "OUT_OPTS_LVCMOS_HIZ_P"; + case LVCMOS_LOW_LOW: return "OUT_OPTS_LVCMOS_LOW_LOW"; + case LVCMOS_N_HIZ: return "OUT_OPTS_LVCMOS_N_HIZ"; + case LVCMOS_N_N: return "OUT_OPTS_LVCMOS_N_N"; + case LVCMOS_N_P: return "OUT_OPTS_LVCMOS_N_P"; + case LVCMOS_P_HIZ: return "OUT_OPTS_LVCMOS_P_HIZ"; + case LVCMOS_P_N: return "OUT_OPTS_LVCMOS_P_N"; + case LVCMOS_P_P: return "OUT_OPTS_LVCMOS_P_P"; default: return "OUT_OPTS_Disabled"; } return "UNKNOWN"; @@ -1304,11 +1315,22 @@ int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, unsigned mux, unsig { unsigned ot; switch (otype) { - case LVDS: ot = OUT_OPTS_AC_LVDS; break; - case CML: ot = OUT_OPTS_AC_CML; break; - case LVPECL: ot = OUT_OPTS_AC_LVPECL; break; - case LVCMOS: ot = OUT_OPTS_LVCMOS_P_N; break; - default: ot = OUT_OPTS_Disabled; break; + case LVDS: ot = OUT_OPTS_AC_LVDS; break; + case CML: ot = OUT_OPTS_AC_CML; break; + case LVPECL: ot = OUT_OPTS_AC_LVPECL; break; + case HCSL_EXT_50: ot = OUT_OPTS_HCSL_EXT_50; break; + case HCSL_INT_50: ot = OUT_OPTS_HCSL_INT_50; break; + case LVCMOS_HIZ_HIZ: ot = OUT_OPTS_LVCMOS_HIZ_HIZ; break; + case LVCMOS_HIZ_N: ot = OUT_OPTS_LVCMOS_HIZ_N; break; + case LVCMOS_HIZ_P: ot = OUT_OPTS_LVCMOS_HIZ_P; break; + case LVCMOS_LOW_LOW: ot = OUT_OPTS_LVCMOS_LOW_LOW; break; + case LVCMOS_N_HIZ: ot = OUT_OPTS_LVCMOS_N_HIZ; break; + case LVCMOS_N_N: ot = OUT_OPTS_LVCMOS_N_N; break; + case LVCMOS_N_P: ot = OUT_OPTS_LVCMOS_N_P; break; + case LVCMOS_P_HIZ: ot = OUT_OPTS_LVCMOS_P_HIZ; break; + case LVCMOS_P_N: ot = OUT_OPTS_LVCMOS_P_N; break; + case LVCMOS_P_P: ot = OUT_OPTS_LVCMOS_P_P; break; + default: ot = OUT_OPTS_Disabled; } if (port > 7) @@ -1874,7 +1896,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned return -EINVAL; } - if(out->wanted.type == LVCMOS && out->port < 4) + if(out->wanted.type > HCSL_INT_50 && out->port < 4) { USDR_LOG("5318", USDR_LOG_ERROR, "LVCMOS output type supported for ports# 4..7 only"); return -EINVAL; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 7d911419..48f69460 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -107,11 +107,24 @@ struct lmk05318_state { }; enum lmk05318_type { + OUT_OFF = 0, + // LVDS, CML, LVPECL, - LVCMOS, - OUT_OFF, + HCSL_EXT_50, + HCSL_INT_50, + // formats below supported by ports 4..7 only + LVCMOS_HIZ_HIZ, + LVCMOS_HIZ_N, + LVCMOS_HIZ_P, + LVCMOS_LOW_LOW, + LVCMOS_N_HIZ, + LVCMOS_N_N, + LVCMOS_N_P, + LVCMOS_P_HIZ, + LVCMOS_P_N, + LVCMOS_P_P, }; typedef struct lmk05318_state lmk05318_state_t; diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index fc1cd3fd..abbfbb1c 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -129,8 +129,8 @@ START_TEST(lmk05318_solver_test5) res = res ? res : lmk05318_port_request(p++, 3, 250000000, false, LVDS); res = res ? res : lmk05318_port_request(p++, 4, 156250000, false, OUT_OFF); res = res ? res : lmk05318_port_request(p++, 5, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(p++, 6, 10000000, false, LVCMOS); - res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS); + res = res ? res : lmk05318_port_request(p++, 6, 10000000, false, LVCMOS_P_N); + res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS_P_N); ck_assert_int_eq( res, 0 ); lmk05318_registers_map_reset(); @@ -150,8 +150,8 @@ START_TEST(lmk05318_solver_test6) res = res ? res : lmk05318_port_request(p++, 3, 250000000, false, LVDS); res = res ? res : lmk05318_port_request(p++, 4, 156250000, false, OUT_OFF); res = res ? res : lmk05318_port_request(p++, 5, 156250000, false, OUT_OFF); - res = res ? res : lmk05318_port_request(p++, 6, 10000000, false, LVCMOS); - res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS); + res = res ? res : lmk05318_port_request(p++, 6, 10000000, false, LVCMOS_P_N); + res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS_P_N); ck_assert_int_eq( res, 0 ); lmk05318_xo_settings_t xo; @@ -329,10 +329,10 @@ START_TEST(lmk05318_simplesync_test1) lmk05318_out_config_t cfg1[4]; lmk05318_out_config_t* p = &cfg1[0]; - lmk05318_port_request(p++, 4, 25000000, false, LVCMOS); - lmk05318_port_request(p++, 5, 25000000, false, LVCMOS); - lmk05318_port_request(p++, 6, 25000000, false, LVCMOS); - lmk05318_port_request(p++, 7, 25000000, false, LVCMOS); + lmk05318_port_request(p++, 4, 25000000, false, LVCMOS_P_N); + lmk05318_port_request(p++, 5, 25000000, false, LVCMOS_P_N); + lmk05318_port_request(p++, 6, 25000000, false, LVCMOS_P_N); + lmk05318_port_request(p++, 7, 25000000, false, LVCMOS_P_N); p = &cfg1[0]; @@ -384,8 +384,8 @@ START_TEST(lmk05318_solver_test7) res = res ? res : lmk05318_port_request(p++, 3, 0, false, OUT_OFF); res = res ? res : lmk05318_port_request(p++, 4, 1000666000, false, LVDS); res = res ? res : lmk05318_port_request(p++, 5, 0, false, OUT_OFF); - res = res ? res : lmk05318_port_request(p++, 6, 25000000, false, LVCMOS); - res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS); + res = res ? res : lmk05318_port_request(p++, 6, 25000000, false, LVCMOS_P_N); + res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS_P_N); res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); ck_assert_int_eq( res, 0 ); From f45dde8257767af62c2fe2f2c741a7b7cce4ab40 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 22 May 2025 18:40:31 +0300 Subject: [PATCH 143/397] make LMK APLL1 fdiv calculation more flexible --- src/lib/hw/lmk05318/lmk05318.c | 24 +++++++++++++++++++++++- src/utests/lmk05318_solver_test.c | 7 ++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 3b7ee4ec..4781af72 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1146,8 +1146,30 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator else { - den = ((uint64_t)1 << 24) - 1; //max 24-bit + den = d->xo.fref * (d->xo.doubler_enabled ? 2 : 1); num = (uint64_t)(n_frac * den + 0.5); + + uint64_t nod = find_gcd(num, den); + if(nod > 1) + { +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_DEBUG, "PLL1 NUM/DEN reduced NOD:%" PRIu64 ": %" PRIu64 "/%" PRIu64" -> %" PRIu64 "/%" PRIu64, + nod, num, den, num/nod, den/nod); +#endif + num /= nod; + den /= nod; + } + + static const uint64_t MAX_DEN = ((uint64_t)1 << 24) - 1; + + if(den > MAX_DEN) + { +#ifdef LMK05318_SOLVER_DEBUG + USDR_LOG("5318", USDR_LOG_ERROR, "PLL1_DEN overflow, cannot solve in integer values"); +#endif + return -EINVAL; + } + apll1_sdm_order = num ? SDM_ORDER_THIRD : SDM_ORDER_INT; } diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index abbfbb1c..5958a69a 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -365,7 +365,7 @@ START_TEST(lmk05318_simplesync_test1) ck_assert_int_eq( res, 0 ); } -START_TEST(lmk05318_solver_test7) +START_TEST(lmk05318_solver_test_xmass) { int res = 0; @@ -411,7 +411,7 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - +/* tcase_add_test(tc_core, lmk05318_solver_test1); tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); @@ -421,7 +421,8 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_dsdr_test1); tcase_add_test(tc_core, lmk05318_dsdr_test2); tcase_add_test(tc_core, lmk05318_simplesync_test1); - tcase_add_test(tc_core, lmk05318_solver_test7); +*/ + tcase_add_test(tc_core, lmk05318_solver_test_xmass); suite_add_tcase(s, tc_core); return s; From f711f29186202dadd44a1fd2a8bc561b3b5b0f54 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 22 May 2025 21:07:54 +0300 Subject: [PATCH 144/397] LMK refactoring, disable if freq==0, new api to enable/disable ports --- .../device/ext_simplesync/ext_simplesync.c | 12 +- src/lib/device/ext_xmass/ext_xmass.c | 2 +- src/lib/hw/lmk05318/lmk05318.c | 143 +++++++++++++----- src/lib/hw/lmk05318/lmk05318.h | 2 + src/utests/lmk05318_solver_test.c | 3 +- 5 files changed, 114 insertions(+), 48 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 33d88020..c24c68a6 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -44,11 +44,10 @@ enum { static int simplesync_pd_low_chs(board_ext_simplesync_t* ob) { int res = 0; - res = res ? res : lmk05318_set_out_mux(&ob->lmk, 0, 0, OUT_OFF); - res = res ? res : lmk05318_set_out_mux(&ob->lmk, 1, 0, OUT_OFF); - res = res ? res : lmk05318_set_out_mux(&ob->lmk, 2, 0, OUT_OFF); - res = res ? res : lmk05318_set_out_mux(&ob->lmk, 3, 0, OUT_OFF); - res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); + res = res ? res : lmk05318_disable_port(&ob->lmk, 0); + res = res ? res : lmk05318_disable_port(&ob->lmk, 1); + res = res ? res : lmk05318_disable_port(&ob->lmk, 2); + res = res ? res : lmk05318_disable_port(&ob->lmk, 3); return res; } @@ -159,8 +158,7 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) if(res) return res; - res = res ? res : lmk05318_softreset(&ob->lmk); - res = res ? res : lmk05318_reset_los_flags(&ob->lmk); + res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index a756635d..b5fb1613 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -245,10 +245,10 @@ int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); + res = res ? res : lmk05318_sync(&ob->lmk); lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state - res = res ? res : lmk05318_sync(&ob->lmk); return res; } diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 4781af72..f669d925 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1310,7 +1310,7 @@ int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t udiv) return lmk05318_add_reg_to_map(d, ®, 1); } -static inline const char* lmk05318_decode_fmt(unsigned f) +static inline const char* lmk05318_decode_fmt_to_string(unsigned f) { switch (f) { case LVDS: return "OUT_OPTS_AC_LVDS"; @@ -1333,31 +1333,88 @@ static inline const char* lmk05318_decode_fmt(unsigned f) return "UNKNOWN"; } -int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) +static inline uint8_t lmk05318_decode_fmt(unsigned f) +{ + switch (f) { + case LVDS: return OUT_OPTS_AC_LVDS; + case CML: return OUT_OPTS_AC_CML; + case LVPECL: return OUT_OPTS_AC_LVPECL; + case HCSL_EXT_50: return OUT_OPTS_HCSL_EXT_50; + case HCSL_INT_50: return OUT_OPTS_HCSL_INT_50; + case LVCMOS_HIZ_HIZ: return OUT_OPTS_LVCMOS_HIZ_HIZ; + case LVCMOS_HIZ_N: return OUT_OPTS_LVCMOS_HIZ_N; + case LVCMOS_HIZ_P: return OUT_OPTS_LVCMOS_HIZ_P; + case LVCMOS_LOW_LOW: return OUT_OPTS_LVCMOS_LOW_LOW; + case LVCMOS_N_HIZ: return OUT_OPTS_LVCMOS_N_HIZ; + case LVCMOS_N_N: return OUT_OPTS_LVCMOS_N_N; + case LVCMOS_N_P: return OUT_OPTS_LVCMOS_N_P; + case LVCMOS_P_HIZ: return OUT_OPTS_LVCMOS_P_HIZ; + case LVCMOS_P_N: return OUT_OPTS_LVCMOS_P_N; + case LVCMOS_P_P: return OUT_OPTS_LVCMOS_P_P; + } + return OUT_OPTS_Disabled; +} + +int lmk05318_disable_port(lmk05318_state_t* d, unsigned port) +{ + uint16_t regno; + switch(port) + { + case 0: regno = OUTCTL_0; break; + case 1: regno = OUTCTL_1; break; + case 2: regno = OUTCTL_2; break; + case 3: regno = OUTCTL_3; break; + case 4: regno = OUTCTL_4; break; + case 5: regno = OUTCTL_5; break; + case 6: regno = OUTCTL_6; break; + case 7: regno = OUTCTL_7; break; + default: + return -EINVAL; + } + + uint8_t regval; + int res = lmk05318_reg_rd(d, regno, ®val); + if(res) + return res; + + return lmk05318_reg_wr(d, regno, regval & ~OUT0_FMT_MSK); +} + +int lmk05318_enable_port(lmk05318_state_t* d, unsigned port, unsigned fmt) { - unsigned ot; - switch (otype) { - case LVDS: ot = OUT_OPTS_AC_LVDS; break; - case CML: ot = OUT_OPTS_AC_CML; break; - case LVPECL: ot = OUT_OPTS_AC_LVPECL; break; - case HCSL_EXT_50: ot = OUT_OPTS_HCSL_EXT_50; break; - case HCSL_INT_50: ot = OUT_OPTS_HCSL_INT_50; break; - case LVCMOS_HIZ_HIZ: ot = OUT_OPTS_LVCMOS_HIZ_HIZ; break; - case LVCMOS_HIZ_N: ot = OUT_OPTS_LVCMOS_HIZ_N; break; - case LVCMOS_HIZ_P: ot = OUT_OPTS_LVCMOS_HIZ_P; break; - case LVCMOS_LOW_LOW: ot = OUT_OPTS_LVCMOS_LOW_LOW; break; - case LVCMOS_N_HIZ: ot = OUT_OPTS_LVCMOS_N_HIZ; break; - case LVCMOS_N_N: ot = OUT_OPTS_LVCMOS_N_N; break; - case LVCMOS_N_P: ot = OUT_OPTS_LVCMOS_N_P; break; - case LVCMOS_P_HIZ: ot = OUT_OPTS_LVCMOS_P_HIZ; break; - case LVCMOS_P_N: ot = OUT_OPTS_LVCMOS_P_N; break; - case LVCMOS_P_P: ot = OUT_OPTS_LVCMOS_P_P; break; - default: ot = OUT_OPTS_Disabled; + uint16_t regno; + switch(port) + { + case 0: regno = OUTCTL_0; break; + case 1: regno = OUTCTL_1; break; + case 2: regno = OUTCTL_2; break; + case 3: regno = OUTCTL_3; break; + case 4: regno = OUTCTL_4; break; + case 5: regno = OUTCTL_5; break; + case 6: regno = OUTCTL_6; break; + case 7: regno = OUTCTL_7; break; + default: + return -EINVAL; } + uint8_t ot = lmk05318_decode_fmt(fmt); + + uint8_t regval; + int res = lmk05318_reg_rd(d, regno, ®val); + if(res) + return res; + + return lmk05318_reg_wr(d, regno, regval | ((ot << OUT0_FMT_OFF) & OUT0_FMT_MSK)); +} + + +int lmk05318_set_out_mux(lmk05318_state_t* d, unsigned port, unsigned mux, unsigned otype) +{ if (port > 7) return -EINVAL; + uint8_t ot = lmk05318_decode_fmt(otype); + uint32_t regs[] = { (port == 0) ? MAKE_LMK05318_OUTCTL_0(mux, ot) : (port == 1) ? MAKE_LMK05318_OUTCTL_1(ot) : @@ -1906,19 +1963,13 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned { lmk05318_out_config_t* out = _outs + i; - if(out->wanted.freq == 0) - { - USDR_LOG("5318", USDR_LOG_DEBUG, "skipping port#%d freq=0", out->port); - continue; - } - if(out->port > LMK05318_MAX_OUT_PORTS - 1) { USDR_LOG("5318", USDR_LOG_ERROR, "port value should be in [0; %d] diap", (LMK05318_MAX_OUT_PORTS - 1)); return -EINVAL; } - if(out->wanted.type > HCSL_INT_50 && out->port < 4) + if(out->wanted.type > HCSL_INT_50 && out->port < 4 && out->wanted.freq) { USDR_LOG("5318", USDR_LOG_ERROR, "LVCMOS output type supported for ports# 4..7 only"); return -EINVAL; @@ -1947,10 +1998,17 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned return -EINVAL; } - range_t r = lmk05318_get_freq_range(out); - out->freq_min = r.min; - out->freq_max = r.max; - out->max_odiv = lmk05318_max_odiv(out->port); + if(out->wanted.freq == 0) + { + USDR_LOG("5318", USDR_LOG_DEBUG, "skipping port#%d freq=0", out->port); + } + else + { + range_t r = lmk05318_get_freq_range(out); + out->freq_min = r.min; + out->freq_max = r.max; + out->max_odiv = lmk05318_max_odiv(out->port); + } *norm_out = *out; norm_out->solved = false; @@ -1961,7 +2019,8 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) { outs[i].solved = outs[i].wanted.freq == 0; - USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d freq:%d (-%d, +%d) *%s*", + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%s%d freq:%d (-%d, +%d) *%s*", + outs[i].port == 1 ? "0-" : (outs[i].port == 3 ? "2-" : " "), outs[i].port, outs[i].wanted.freq, outs[i].wanted.freq_delta_minus, outs[i].wanted.freq_delta_plus, outs[i].solved ? "not used" : "active"); } @@ -2093,7 +2152,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.8f mux:%d(%s) fmt:%u(%s)] %s", out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux, - lmk05318_decode_mux(out_dst->result.mux), out_dst->wanted.type, lmk05318_decode_fmt(out_dst->wanted.type), + lmk05318_decode_mux(out_dst->result.mux), out_dst->wanted.type, lmk05318_decode_fmt_to_string(out_dst->wanted.type), is_freq_ok ? "**OK**" : "**BAD**"); } @@ -2125,13 +2184,21 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned const lmk05318_out_config_t* out = _outs + i; if(out->wanted.freq == 0) - continue; + { + USDR_LOG("5318", USDR_LOG_DEBUG, "OUT%u port:%u DISABLED fmt:%u(%s)", + i, out->port, OUT_OFF, lmk05318_decode_fmt_to_string(OUT_OFF)); + + res = lmk05318_set_out_mux(d, out->port, 0, OUT_OFF); + } + else + { + USDR_LOG("5318", USDR_LOG_DEBUG, "OUT%u port:%u div:%" PRIu64 " fmt:%u(%s)", + i, out->port, out->result.out_div, out->wanted.type, lmk05318_decode_fmt_to_string(out->wanted.type)); - USDR_LOG("5318", USDR_LOG_DEBUG, "OUT%u port:%u div:%" PRIu64 " fmt:%u(%s)", - i, out->port, out->result.out_div, out->wanted.type, lmk05318_decode_fmt(out->wanted.type)); + res = lmk05318_set_out_mux(d, out->port, out->result.mux, out->wanted.type); + res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); + } - res = lmk05318_set_out_mux(d, out->port, out->result.mux, out->wanted.type); - res = res ? res : lmk05318_set_out_div(d, out->port, out->result.out_div); if(res) { USDR_LOG("5318", USDR_LOG_ERROR, "error %d setting mux/div for port#%d", res, out->port); diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 48f69460..805de5b7 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -213,6 +213,8 @@ enum lock_msk { int lmk05318_set_out_div(lmk05318_state_t* d, unsigned port, uint64_t div); int lmk05318_sync(lmk05318_state_t* out); int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask); +int lmk05318_disable_port(lmk05318_state_t* d, unsigned port); +int lmk05318_enable_port(lmk05318_state_t* d, unsigned port, unsigned fmt); int lmk05318_reset_los_flags(lmk05318_state_t* d); int lmk05318_check_lock(lmk05318_state_t* d, unsigned* los_msk, bool silent); int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 5958a69a..5f861bd0 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -411,7 +411,7 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); -/* + tcase_add_test(tc_core, lmk05318_solver_test1); tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); @@ -421,7 +421,6 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_dsdr_test1); tcase_add_test(tc_core, lmk05318_dsdr_test2); tcase_add_test(tc_core, lmk05318_simplesync_test1); -*/ tcase_add_test(tc_core, lmk05318_solver_test_xmass); suite_add_tcase(s, tc_core); From fd7d36806bbe4989612fe77f055a8b4143818207 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 23 May 2025 17:37:55 +0300 Subject: [PATCH 145/397] add & correct LMK APLL1 checks for dpll-mode --- src/lib/hw/lmk05318/lmk05318.c | 25 +++++++++++++++++++++++-- src/utests/lmk05318_solver_test.c | 9 ++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index f669d925..fc792872 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -85,6 +85,7 @@ enum #define DPLL_FDIV_FRAC_MAX 0.9375f #define DPLL_FDIV_FRAC_MIN 0.0625f +#define DPLL_MIN_BAW_DIFF 2500000ul struct range { @@ -1135,13 +1136,33 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) num = (uint64_t)(n_frac * den + 0.5); apll1_sdm_order = SDM_ORDER_THIRD; //for DPLL correction - //additional check for DPLL mode - if(num && ((double)num / den <= DPLL_FDIV_FRAC_MIN || (double)num / den >= DPLL_FDIV_FRAC_MAX)) + //additional checks for DPLL mode + if((double)num / den <= DPLL_FDIV_FRAC_MIN || (double)num / den >= DPLL_FDIV_FRAC_MAX) { USDR_LOG("5318", USDR_LOG_ERROR, "[APLL1] NUM/DEN ratio:%.8f out of range (%.4f;%.4f)", (double)num / den, DPLL_FDIV_FRAC_MIN, DPLL_FDIV_FRAC_MAX); return -EINVAL; } + else + { + USDR_LOG("5318", USDR_LOG_INFO, "[APLL1] NUM/DEN ratio:%.8f within valid range (%.4f;%.4f)", + (double)num / den, DPLL_FDIV_FRAC_MIN, DPLL_FDIV_FRAC_MAX); + } + + const double f_lo = fpd1 * floor(r); + const double f_hi = fpd1 * ceil(r); + const double min_diff = MIN(fabs(f_lo - fvco), fabs(f_hi - fvco)); + if(min_diff <= DPLL_MIN_BAW_DIFF) + { + USDR_LOG("5318", USDR_LOG_ERROR, "[APLL1] Min difference between VCO1 and FPD* = %.4f <= %lu", + min_diff, DPLL_MIN_BAW_DIFF); + return -EINVAL; + } + else + { + USDR_LOG("5318", USDR_LOG_INFO, "[APLL1] Integer boundary spur = %.2fMHz (>%.2fMHz)", + min_diff / 1e6, (double)DPLL_MIN_BAW_DIFF / 1e6); + } } // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator else diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 5f861bd0..919db363 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -155,7 +155,7 @@ START_TEST(lmk05318_solver_test6) ck_assert_int_eq( res, 0 ); lmk05318_xo_settings_t xo; - xo.fref = 25000000; + xo.fref = 12800000; xo.doubler_enabled = true; xo.fdet_bypass = false; xo.pll1_fref_rdiv = 1; @@ -200,7 +200,7 @@ START_TEST(lmk05318_dsdr_test1) lmk05318_xo_settings_t xo; xo.fref = 26000000; - xo.doubler_enabled = false; + xo.doubler_enabled = true; xo.fdet_bypass = false; xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; @@ -240,7 +240,7 @@ START_TEST(lmk05318_dsdr_test2) lmk05318_xo_settings_t xo; xo.fref = 26000000; - xo.doubler_enabled = false; + xo.doubler_enabled = true; xo.fdet_bypass = false; xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; @@ -321,7 +321,7 @@ START_TEST(lmk05318_simplesync_test1) lmk05318_xo_settings_t xo; xo.fref = 26000000; - xo.doubler_enabled = false; + xo.doubler_enabled = true; xo.fdet_bypass = false; xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; @@ -411,7 +411,6 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, lmk05318_solver_test1); tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); From 022e27aa92feda1ed63b7338f66e65b36a02e690 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 23 May 2025 18:05:50 +0300 Subject: [PATCH 146/397] add define macro for disabling dpll-mode checks (XO25M case) --- src/lib/hw/lmk05318/lmk05318.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index fc792872..694b2173 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -19,6 +19,9 @@ //define this for solver extra logging #undef LMK05318_SOLVER_DEBUG +//remove this to enable additional checks for dpll mode +#define DISABLE_ADDITIONAL_DPLL_CHECKS + enum { VCO_APLL1 = 2500000000ull, VCO_APLL1_DELTA_MAX = 250000, @@ -1136,6 +1139,7 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) num = (uint64_t)(n_frac * den + 0.5); apll1_sdm_order = SDM_ORDER_THIRD; //for DPLL correction +#ifndef DISABLE_ADDITIONAL_DPLL_CHECKS //additional checks for DPLL mode if((double)num / den <= DPLL_FDIV_FRAC_MIN || (double)num / den >= DPLL_FDIV_FRAC_MAX) { @@ -1163,6 +1167,8 @@ int lmk05318_tune_apll1(lmk05318_state_t* d) USDR_LOG("5318", USDR_LOG_INFO, "[APLL1] Integer boundary spur = %.2fMHz (>%.2fMHz)", min_diff / 1e6, (double)DPLL_MIN_BAW_DIFF / 1e6); } +#endif //DISABLE_ADDITIONAL_DPLL_CHECKS + } // without DPLL we use programmed 24-bit numerator & programmed 24-bit denominator else From 009340789314dbf43d3bd65741e60c74e418f402 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 24 May 2025 20:26:56 +0300 Subject: [PATCH 147/397] LMK: improving XO chain solver, refactoring, XO=12.8M settings --- .../device/ext_simplesync/ext_simplesync.c | 7 +- src/lib/device/ext_xmass/ext_xmass.c | 4 +- src/lib/device/m2_dsdr/m2_dsdr.c | 19 +- src/lib/device/pe_sync/pe_sync.c | 19 +- src/lib/hw/lmk05318/lmk05318.c | 200 +++++++++++------- src/utests/lmk05318_solver_test.c | 57 +++-- 6 files changed, 168 insertions(+), 138 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index c24c68a6..89e068c9 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -88,10 +88,8 @@ int board_ext_simplesync_init(lldev_t dev, usleep(50000); lmk05318_xo_settings_t xo; - xo.doubler_enabled = true; - xo.fdet_bypass = false; + memset(&xo, 0, sizeof(xo)); xo.fref = 26000000; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_out_config_t lmk_out[4]; @@ -114,9 +112,8 @@ int board_ext_simplesync_init(lldev_t dev, return res; res = simplesync_pd_low_chs(ob); //power down chs 0..3 - - res = res ? res : lmk05318_reset_los_flags(&ob->lmk); res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); + res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); unsigned los_msk; diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index b5fb1613..0d78eda6 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -136,10 +136,8 @@ int board_xmass_init(lldev_t dev, //LMK05318 init start lmk05318_xo_settings_t xo; - xo.doubler_enabled = true; - xo.fdet_bypass = false; + memset(&xo, 0, sizeof(xo)); xo.fref = 26000000; - xo.pll1_fref_rdiv = 1; xo.type = XO_AC_DIFF_EXT; lmk05318_dpll_settings_t dpll; diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 79b3edca..a04d7707 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1426,10 +1426,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // //LMK05318 init start lmk05318_xo_settings_t xo; - xo.doubler_enabled = true; - xo.fdet_bypass = false; + memset(&xo, 0, sizeof(xo)); xo.fref = 26000000; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; //set true to enable IN_REF1 40M @@ -1461,11 +1459,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(10000); //wait until lmk digests all this - //reset LOS flags after soft-reset (inside lmk05318_create()) - res = lmk05318_reset_los_flags(&d->lmk); - if(res) - return res; - //wait for PRIREF/SECREF validation res = lmk05318_wait_dpll_ref_stat(&d->lmk, 100000); if(res) @@ -1475,16 +1468,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } //wait for lock - //APLL1/DPLL res = lmk05318_wait_apll1_lock(&d->lmk, 100000); - - //APLL2 (if needed) - if(res == 0 && d->lmk.vco2_freq) - { - //reset LOS flags once again because APLL2 LOS is set after APLL1 tuning - res = lmk05318_reset_los_flags(&d->lmk); - res = res ? res : lmk05318_wait_apll2_lock(&d->lmk, 100000); - } + res = res ? res : lmk05318_wait_apll2_lock(&d->lmk, 100000); lmk05318_check_lock(&d->lmk, &los, false /*silent*/); //just to log state diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 865b64cb..318970bb 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -271,10 +271,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const return res; lmk05318_xo_settings_t xo; + memset(&xo, 0, sizeof(xo)); xo.fref = 25000000; - xo.doubler_enabled = true; - xo.fdet_bypass = false; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_dpll_settings_t dpll; @@ -315,11 +313,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const usleep(10000); //wait until lmk digests all this - //reset LOS flags after soft-reset (inside lmk05318_create()) - res = lmk05318_reset_los_flags(&d->gen); - if(res) - return res; - //wait for PRIREF/SECREF validation res = lmk05318_wait_dpll_ref_stat(&d->gen, 4*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on if(res) @@ -329,16 +322,8 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const } //wait for lock - //APLL1/DPLL res = lmk05318_wait_apll1_lock(&d->gen, 100000); - - //APLL2 (if needed) - if(res == 0 && d->gen.vco2_freq) - { - //reset LOS flags once again because APLL2 LOS is set after APLL1 tuning - res = lmk05318_reset_los_flags(&d->gen); - res = res ? res : lmk05318_wait_apll2_lock(&d->gen, 100000); - } + res = res ? res : lmk05318_wait_apll2_lock(&d->gen, 100000); unsigned los_msk; lmk05318_check_lock(&d->gen, &los_msk, false /*silent*/); //just to log state diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 694b2173..319867f7 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -82,8 +82,9 @@ enum enum { - XO25 = 25000000, - XO26 = 26000000, + XO12_8 = 12800000, + XO25 = 25000000, + XO26 = 26000000, }; #define DPLL_FDIV_FRAC_MAX 0.9375f @@ -490,89 +491,119 @@ int lmk05318_reset_los_flags(lmk05318_state_t* d) return lmk05318_reg_wr_n(d, regs, SIZEOF_ARRAY(regs)); } -static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) +static int lmk05318_set_xo_bawdetect_registers(lmk05318_state_t* d) { int res = 0; - if(d->dpll.enabled == false) + switch(d->xo.fref) { - // WITHOUT DPLL + case XO12_8: + { + USDR_LOG("5318", USDR_LOG_INFO, "XO=12.8M, applying specific settings..."); - switch(d->xo.fref) + static uint32_t regs[] = { - case XO25: - { - USDR_LOG("5318", USDR_LOG_INFO, "XO=25M, applying specific settings..."); + 0x00510A, + 0x005200, + 0x005307, + 0x005480, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D07, + 0x005E80, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + }; - uint32_t bawlock_regs[] = - { - 0x00510A, //R81 - 0x005200, // | - 0x00530E, // | - 0x0054A6, // | - 0x005500, // | - 0x005600, // | - 0x00571E, // | - 0x005884, // | - 0x005980, // | BAW lock&unlock detection, may depend on XO params - 0x005A00, // | - 0x005B14, // | - 0x005C00, // | - 0x005D0E, // | - 0x005EA6, // | - 0x005F00, // | - 0x006000, // | - 0x00611E, // | - 0x006284, // | - 0x006380, //R99 - }; - - res = lmk05318_add_reg_to_map(d, bawlock_regs, SIZEOF_ARRAY(bawlock_regs)); - if(res) - return res; + res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + break; + } + case XO25: + { + USDR_LOG("5318", USDR_LOG_INFO, "XO=25M, applying specific settings..."); - break; - } - case XO26: + static uint32_t regs[] = { - USDR_LOG("5318", USDR_LOG_INFO, "XO=26M, applying specific settings..."); + 0x00510A, //R81 + 0x005200, // | + 0x00530E, // | + 0x0054A6, // | + 0x005500, // | + 0x005600, // | + 0x00571E, // | + 0x005884, // | + 0x005980, // | BAW lock&unlock detection, may depend on XO params + 0x005A00, // | + 0x005B14, // | + 0x005C00, // | + 0x005D0E, // | + 0x005EA6, // | + 0x005F00, // | + 0x006000, // | + 0x00611E, // | + 0x006284, // | + 0x006380, //R99 + }; - uint32_t bawlock_regs[] = - { - 0x00510A, - 0x005200, - 0x00530F, - 0x00543C, - 0x005500, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D0F, - 0x005E3C, - 0x005F00, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - }; - - res = lmk05318_add_reg_to_map(d, bawlock_regs, SIZEOF_ARRAY(bawlock_regs)); - if(res) - return res; + res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + break; + } + case XO26: + { + USDR_LOG("5318", USDR_LOG_INFO, "XO=26M, applying specific settings..."); - break; - } - default: + static uint32_t regs[] = { - USDR_LOG("5318", USDR_LOG_ERROR, "XO=%" PRIu64 " not supported! Use 25 or 26M", (uint64_t)d->xo.fref); - return -EINVAL; - } - } + 0x00510A, + 0x005200, + 0x00530F, + 0x00543C, + 0x005500, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D0F, + 0x005E3C, + 0x005F00, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + }; + + res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + break; + } + default: + { + USDR_LOG("5318", USDR_LOG_ERROR, "XO=%.2fMHz not supported! Use 12.8, 25 or 26M", (double)d->xo.fref / 1e6); + return -EINVAL; + } + } + + return res; +} + +static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) +{ + int res = 0; + if(d->dpll.enabled == false) + { + // WITHOUT DPLL uint32_t no_dpll_regs[] = { MAKE_LMK05318_DEV_CTL(0, 0, 0/*SYNC_AUTO_DPLL*/, 1, 1, 1, 1), //R12 set APLL1 mode - NO DPLL @@ -1056,7 +1087,6 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) { const uint32_t xo_fref = d->xo.fref; const int xo_type = d->xo.type; - const bool xo_doubler_enabled = d->xo.doubler_enabled; const bool xo_fdet_bypass = d->xo.fdet_bypass; if(xo_fref < XO_FREF_MIN || xo_fref > XO_FREF_MAX) @@ -1066,7 +1096,20 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) return -EINVAL; } - if(d->xo.pll1_fref_rdiv < APLL1_DIVIDER_MIN || d->xo.pll1_fref_rdiv > APLL1_DIVIDER_MAX) + if(xo_fref * 2 <= APLL1_PD_MAX) + { + //use XO doubler + d->xo.doubler_enabled = true; + d->xo.pll1_fref_rdiv = 1; + } + else + { + //use XO divider + d->xo.doubler_enabled = false; + d->xo.pll1_fref_rdiv = ceil((double)xo_fref / APLL1_PD_MAX); + } + + if(d->xo.pll1_fref_rdiv > APLL1_DIVIDER_MAX) { USDR_LOG("5318", USDR_LOG_ERROR, "[XO] APPL1_RDIV:%d out of range [%d;%d]", d->xo.pll1_fref_rdiv, (int)APLL1_DIVIDER_MIN, (int)APLL1_DIVIDER_MAX); return -EINVAL; @@ -1089,19 +1132,18 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) USDR_LOG("5318", USDR_LOG_INFO, "[XO] FREF:%u TYPE:%u(%s) DOUBLER:%u RDIV:%u FDET_BYPASS:%u", xo_fref, xo_type_raw, lmk05318_decode_xo_type(xo_type_raw), - xo_doubler_enabled, d->xo.pll1_fref_rdiv, xo_fdet_bypass); + d->xo.doubler_enabled, d->xo.pll1_fref_rdiv, xo_fdet_bypass); uint32_t regs[] = { - MAKE_LMK05318_XO_CLKCTL1(xo_doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0, 0, 1), //R42 + MAKE_LMK05318_XO_CLKCTL1(d->xo.doubler_enabled ? 1 : 0, xo_fdet_bypass ? 1 : 0, 0, 1),//R42 MAKE_LMK05318_XO_CLKCTL2(1, xo_type_raw, 2), //R43 MAKE_LMK05318_XO_CONFIG(d->xo.pll1_fref_rdiv - 1), //R44 }; int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); - if(res) - return res; + res = res ? res : lmk05318_set_xo_bawdetect_registers(d); - return 0; + return res; } int lmk05318_tune_apll1(lmk05318_state_t* d) diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 919db363..e42f9e6e 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -139,7 +139,7 @@ START_TEST(lmk05318_solver_test5) } -START_TEST(lmk05318_solver_test6) +START_TEST(lmk05318_solver_pesync) { int res = 0; lmk05318_out_config_t* p = &cfg[0]; @@ -155,10 +155,8 @@ START_TEST(lmk05318_solver_test6) ck_assert_int_eq( res, 0 ); lmk05318_xo_settings_t xo; + memset(&xo, 0, sizeof(xo)); xo.fref = 12800000; - xo.doubler_enabled = true; - xo.fdet_bypass = false; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_dpll_settings_t dpll; @@ -178,6 +176,38 @@ START_TEST(lmk05318_solver_test6) } +START_TEST(lmk05318_solver_pesync_free_run) +{ + int res = 0; + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 1, 125000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 250000000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 4, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 156250000, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 6, 10000000, false, LVCMOS_P_N); + res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS_P_N); + ck_assert_int_eq( res, 0 ); + + lmk05318_xo_settings_t xo; + memset(&xo, 0, sizeof(xo)); + xo.fref = 25000000; + xo.type = XO_CMOS; + + lmk05318_dpll_settings_t dpll; + memset(&dpll, 0, sizeof(dpll)); + dpll.enabled = false; + + lmk05318_state_t st; + memset(&st, 0, sizeof(st)); + + res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); + +} + START_TEST(lmk05318_dpll_test1) { lmk05318_dpll_settings_t dpll; @@ -199,10 +229,8 @@ START_TEST(lmk05318_dsdr_test1) int res = 0; lmk05318_xo_settings_t xo; + memset(&xo, 0, sizeof(xo)); xo.fref = 26000000; - xo.doubler_enabled = true; - xo.fdet_bypass = false; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_out_config_t* p = &cfg[0]; @@ -239,10 +267,8 @@ START_TEST(lmk05318_dsdr_test2) int res = 0; lmk05318_xo_settings_t xo; + memset(&xo, 0, sizeof(xo)); xo.fref = 26000000; - xo.doubler_enabled = true; - xo.fdet_bypass = false; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_out_config_t* p = &cfg[0]; @@ -320,10 +346,8 @@ START_TEST(lmk05318_simplesync_test1) int res = 0; lmk05318_xo_settings_t xo; + memset(&xo, 0, sizeof(xo)); xo.fref = 26000000; - xo.doubler_enabled = true; - xo.fdet_bypass = false; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_out_config_t cfg1[4]; @@ -370,10 +394,8 @@ START_TEST(lmk05318_solver_test_xmass) int res = 0; lmk05318_xo_settings_t xo; + memset(&xo, 0, sizeof(xo)); xo.fref = 26000000; - xo.doubler_enabled = true; - xo.fdet_bypass = false; - xo.pll1_fref_rdiv = 1; xo.type = XO_CMOS; lmk05318_out_config_t* p = &cfg[0]; @@ -415,7 +437,8 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); tcase_add_test(tc_core, lmk05318_solver_test5); - tcase_add_test(tc_core, lmk05318_solver_test6); + tcase_add_test(tc_core, lmk05318_solver_pesync); + tcase_add_test(tc_core, lmk05318_solver_pesync_free_run); tcase_add_test(tc_core, lmk05318_dpll_test1); tcase_add_test(tc_core, lmk05318_dsdr_test1); tcase_add_test(tc_core, lmk05318_dsdr_test2); From 570ff4eb8e96d89b476804e9dbc394d7f2335600 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 May 2025 15:37:54 +0400 Subject: [PATCH 148/397] xsdr wip --- src/lib/device/device_fe.c | 2 +- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 14 +- src/lib/device/m2_lm7_1/lms7002m_ctrl.h | 4 +- src/lib/device/m2_lm7_1/m2_lm7_1.c | 42 +++- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 311 ++++++++++++++++++------ src/lib/device/m2_lm7_1/xsdr_ctrl.h | 9 +- src/lib/lowlevel/usdr_lowlevel.c | 5 + src/lib/lowlevel/usdr_lowlevel.h | 3 +- 8 files changed, 303 insertions(+), 87 deletions(-) diff --git a/src/lib/device/device_fe.c b/src/lib/device/device_fe.c index 55737a6b..5eb7fb97 100644 --- a/src/lib/device/device_fe.c +++ b/src/lib/device/device_fe.c @@ -425,7 +425,7 @@ int _debug_lmk05318_reg_set(dev_fe_t* o, lmk05318_state_t* lmk, uint64_t value) USDR_LOG("XDEV", USDR_LOG_WARNING, "LMK05318 WR REG %04x => %04x\n", (unsigned)addr, data); } else { - d = 0xffffffff; + d = 0xff; res = lmk05318_reg_rd(lmk, addr, &d); o->debug_lmk05318_last = d; diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 41632e4b..bb7c7fe4 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -768,7 +768,7 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, USDR_LOG("XDEV", USDR_LOG_INFO, "%s: RBB Restore BW[%d]=%d\n", devstr, ich, d->rx_bw[ich].value); } else { - bandwidth = d->cgen_clk / d->rxcgen_div / d->rxtsp_div / d->rx_host_decim; + bandwidth = d->cgen_clk / d->rxcgen_div / d->rxtsp_div / d->rx_dsp_decim; USDR_LOG("XDEV", USDR_LOG_INFO, "%s: No RBB[%d] was set; defaulting to current rx samplerate %u\n", devstr, ich, bandwidth); } @@ -815,7 +815,7 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, devstr, ich, d->tx_bw[ich].value); bandwidth = d->tx_bw[ich].value; } else { - bandwidth = d->cgen_clk / d->txcgen_div / d->txtsp_div / d->tx_host_inter; + bandwidth = d->cgen_clk / d->txcgen_div / d->txtsp_div / d->tx_dsp_inter; USDR_LOG("XDEV", USDR_LOG_INFO, "%s: No TBB[%d] was set; defaulting to current rx samplerate %u\n", devstr, ich, bandwidth); } @@ -927,8 +927,8 @@ int lms7002m_samplerate(lms7002_dev_t *d, unsigned mpy_dac = 4; // Might be 4,2,1 unsigned rxdiv = 1; unsigned txdiv = 1; - unsigned tx_host_inter = 1; // Off chip extra interpolator - unsigned rx_host_decim = 1; // Off chip extra decimator + unsigned tx_dsp_inter = 1; // Off chip extra interpolator + unsigned rx_dsp_decim = 1; // Off chip extra decimator unsigned tx_host_mul = 1; unsigned rx_host_div = 1; unsigned txmaster_min = mpy_dac * dacclk; @@ -991,8 +991,8 @@ int lms7002m_samplerate(lms7002_dev_t *d, d->txcgen_div = mpy_dac; d->rxtsp_div = rxdiv; d->txtsp_div = txdiv; - d->tx_host_inter = tx_host_inter; - d->rx_host_decim = rx_host_decim; + d->tx_dsp_inter = tx_dsp_inter; + d->rx_dsp_decim = rx_dsp_decim; for (unsigned j = 0; j < 4; j++) { unsigned clkdiv = (mpy_dac == 1) ? 0 : @@ -1075,7 +1075,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, rxrate / 1e6, txrate / 1e6, rxdiv, rx_host_div, txdiv, tx_host_mul, cgen_rate / mpy_adc / 1e6, cgen_rate / mpy_dac / 1e6, - tx_host_inter, rx_host_decim, cgen_rate / 1e6, + tx_dsp_inter, rx_dsp_decim, cgen_rate / 1e6, rxtsp_div, txtsp_div, sisoddr_rx, sisoddr_tx, d->fref / 1e6); diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h index babd0ed9..785185a9 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h @@ -87,8 +87,8 @@ struct lms7002_dev uint8_t txcgen_div; uint8_t rxtsp_div; uint8_t txtsp_div; - uint8_t tx_host_inter; - uint8_t rx_host_decim; + uint8_t tx_dsp_inter; + uint8_t rx_dsp_decim; uint8_t rx_no_siso_map; uint8_t tx_no_siso_map; diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index a72b81e3..81055db5 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -225,6 +225,9 @@ static int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uin static int dev_m2_lm7_1_revision_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm7_1_sdr_tx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/rate/master", { dev_m2_lm7_1_rate_set, NULL }}, @@ -242,6 +245,10 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/refclk/frequency", {dev_m2_lm7_1_sdr_refclk_frequency_set, dev_m2_lm7_1_sdr_refclk_frequency_get}}, { "/dm/sdr/refclk/path", {dev_m2_lm7_1_sdr_refclk_path_set, NULL}}, + + { "/dm/sdr/0/vio", { dev_m2_lm7_1_sdr_vio_set, NULL }}, + { "/dm/sdr/0/tx/phase_ovr", { dev_m2_lm7_1_sdr_tx_phase_ovr_set, NULL }}, + { "/dm/sdr/0/rx/dccorr", { dev_m2_lm7_1_sdr_rx_dccorr_set, NULL }}, { "/dm/sdr/0/tx/dccorr", { dev_m2_lm7_1_sdr_tx_dccorr_set, NULL }}, { "/dm/sdr/0/rx/phgaincorr",{ dev_m2_lm7_1_sdr_rx_phgaincorr_set, NULL }}, @@ -343,7 +350,7 @@ int dev_m2_lm7_1_dev_dac_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t int dev_m2_lm7_1_phyrxlm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - return xsdr_phy_tune(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); + return xsdr_phy_tune_rx(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); } int dev_m2_lm7_1_lms7002rxlml_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -371,6 +378,18 @@ int dev_m2_lm7_1_dev_atcrbs_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* val return res; } +int dev_m2_lm7_1_sdr_tx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + d->xdev.tx_override_phase = value; + return 0; +} + +int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + return xsdr_set_vio(&d->xdev, value); +} int dev_m2_lm7_1_debug_lms7002m_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { @@ -967,6 +986,24 @@ int dev_m2_lm7_1_sensor_freqpps_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t return res; } +static +int usdr_device_m2_lm7_1_lsop(lldev_t dev, subdev_t subdev, + unsigned ls_op, lsopaddr_t ls_op_addr, + size_t meminsz, void* pin, size_t memoutsz, + const void* pout) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)lowlevel_get_device(dev); + int res = -ENOENT; + if (ls_op == USDR_LSOP_DRP) { + res = xsdr_override_drp(&d->xdev, ls_op_addr, meminsz, pin, memoutsz, pout); + } + + if (res != -ENOENT) + return res; + + return d->p_original_ops->ls_op(dev, subdev, ls_op, ls_op_addr, meminsz, pin, memoutsz, pout); +} + static int usdr_device_m2_lm7_1_stream_initialize(lldev_t dev, subdev_t subdev, lowlevel_stream_params_t* params, stream_t* channel) { @@ -1050,6 +1087,7 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* // Proxy operations memcpy(&d->my_ops, lowlevel_get_ops(dev), sizeof (lowlevel_ops_t)); + d->my_ops.ls_op = &usdr_device_m2_lm7_1_lsop; d->my_ops.stream_initialize = &usdr_device_m2_lm7_1_stream_initialize; d->my_ops.stream_deinitialize = &usdr_device_m2_lm7_1_stream_deinitialize; d->p_original_ops = lowlevel_get_ops(dev); @@ -1138,6 +1176,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha if (rxcfg.bifurcation_valid && d->bifurcation_en) { d->xdev.siso_sdr_active_rx = true; flags |= DMS_FLAG_BIFURCATION; + // TODO: update samplerate settings } // Reset samplerate with proper bifurcation flags @@ -1177,6 +1216,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha if (txcfg.bifurcation_valid && d->bifurcation_en) { d->xdev.siso_sdr_active_tx = true; flags |= DMS_FLAG_BIFURCATION; + // TODO: update samplerate settings } res = create_sfetrx4_stream(dev, CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index b57334f5..aade888c 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -24,6 +24,10 @@ #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif +enum { + DRP_MMCM_PORT_RX = 0, + DRP_MMCM_PORT_TX = 1, +}; // TXA RXB // TXB RXA @@ -124,7 +128,161 @@ int xsdr_set_samplerate(xsdr_dev_t *d, return xsdr_set_samplerate_ex(d, rxrate, txrate, adcclk, dacclk, 0); } -int xsdr_configure_lml_mmcm(xsdr_dev_t *d) + +enum { + PHY_REG_PORT_CTRL = 0, + PHY_REG_MMCM_DRP = 1, + PHY_REG_MMCM_CTRL = 2, + PHY_REG_MMCM_PSINC = 3, + PHY_REG_DLY_VALUE = 4, + PHY_REG_PORT_IQSEL = 5, +}; + +int xsdr_phy_tx_reg(xsdr_dev_t *d, uint8_t addr, uint32_t val) +{ + return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_1, (((uint32_t)addr) << 24) | (val & 0xffffff)); +} + +int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, + size_t meminsz, void* pin, size_t memoutsz, + const void* pout) +{ + int res = 0; + lldev_t dev = d->base.lmsstate.dev; + unsigned subdev = d->base.lmsstate.subdev; + unsigned port = (ls_op_addr >> 16) & 0xff; + if (port != DRP_MMCM_PORT_TX) + return -ENOENT; + + uint32_t drp_cmd = (ls_op_addr & 0x7f) << 16; + if (meminsz == 2 && memoutsz == 0) { + } else if (meminsz == 0 && memoutsz == 2) { + drp_cmd |= (1 << 23) | (*((uint16_t*)pout)); + } else { + return -EINVAL; + } + + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_DRP, drp_cmd); + + // Wait for transaction to process + uint32_t rb; + for (unsigned i = 0; i < 1000; i++) { + res = res ? res : lowlevel_reg_rd32(dev, subdev, REG_CFG_PHY_1, &rb); + if (res || (!(rb & (1 << 9)))) + break; + + usleep(1000); + } + + if (res) + return res; + + USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM DRP_TX CMD=%08x RB=%08x\n", drp_cmd, rb); + + if (meminsz) { + *((uint16_t*)pin) = rb >> 16; + } + return 0; +} + +int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) +{ + bool nomul = d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); + unsigned tx_mclk = d->base.cgen_clk / d->base.txcgen_div / d->base.lml_mode.txdiv; + unsigned io_clk = (nomul) ? tx_mclk : tx_mclk * 2; + unsigned vco_div_io_m = (MMCM_VCO_MAX + io_clk - 1) / io_clk; + if (vco_div_io_m > 63) + vco_div_io_m = 63; + + unsigned vco_div_io = vco_div_io_m & 0xfc; //Multiply of 4 + int res = 0; + struct mmcm_config_raw cfg_raw; + memset(&cfg_raw, 0, sizeof(cfg_raw)); + + if (vco_div_io * io_clk < MMCM_VCO_MIN) { + if ((vco_div_io + 2) * io_clk > MMCM_VCO_MAX) { + vco_div_io += 1; + } else { + vco_div_io += 2; + } + } + + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); + + cfg_raw.type = MT_7SERIES_MMCM; + cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; + cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; + cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; + cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; + + cfg_raw.ports[CLKOUT_PORT_2].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_2].period_h = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_3].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_3].period_h = vco_div_io; + + cfg_raw.ports[CLKOUT_PORT_4].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_5].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_6].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io; + + cfg_raw.ports[CLKOUT_PORT_0].phase = ((vco_div_io & 3) == 0) ? 0 : + ((vco_div_io & 3) == 1) ? 2 : + ((vco_div_io & 3) == 2) ? 4 : 6; + cfg_raw.ports[CLKOUT_PORT_0].delay = vco_div_io / 4; + + cfg_raw.ports[CLKOUT_PORT_3].phase = cfg_raw.ports[CLKOUT_PORT_0].phase; + cfg_raw.ports[CLKOUT_PORT_3].delay = vco_div_io / 2; + + if (d->tx_override_phase) { + unsigned raw = d->tx_override_phase - 1; + cfg_raw.ports[CLKOUT_PORT_0].phase = raw & 7; + cfg_raw.ports[CLKOUT_PORT_3].phase = raw & 7; + cfg_raw.ports[CLKOUT_PORT_0].delay = (raw >> 3); + cfg_raw.ports[CLKOUT_PORT_3].delay = 2 * (raw >> 3); + } + + if (nomul) { + cfg_raw.ports[CLKOUT_PORT_FB].period_l =(vco_div_io + 1) / 2; + cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io / 2; + } else { + cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; + } + USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d\n", + tx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io, + (d->tx_override_phase) ? "_OVR" : "", + cfg_raw.ports[CLKOUT_PORT_0].delay, cfg_raw.ports[CLKOUT_PORT_0].phase, + d->base.lml_mode.txsisoddr); + + res = res ? res : mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &cfg_raw); + + // Reset MMCM + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 1); + usleep(100); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); + + for (unsigned k = 0; k < 10; k++) { + // Wait for lock + uint32_t rb; + res = res ? res : lowlevel_reg_rd32(d->base.lmsstate.dev, d->base.lmsstate.subdev, + REG_CFG_PHY_1, &rb); + if (res) + break; + + USDR_LOG("XDEV", USDR_LOG_INFO, "MMCM FLAGS:%08x\n", rb); + if (rb & (1 << 8)) + return 0; + + usleep(5000); + } + + return res; +} + +int xsdr_configure_lml_mmcm_rx(xsdr_dev_t *d) { bool nomul = d->base.lml_mode.rxsisoddr || (d->base.rxtsp_div > 1); unsigned rx_mclk = d->base.cgen_clk / d->base.rxcgen_div / d->base.lml_mode.rxdiv; @@ -165,7 +323,7 @@ int xsdr_configure_lml_mmcm(xsdr_dev_t *d) cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; } - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d\n", + USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_RX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d\n", rx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io); res = (res) ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, @@ -181,7 +339,7 @@ int xsdr_configure_lml_mmcm(xsdr_dev_t *d) return res; usleep(1000); - res = mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, 0, &cfg_raw); + res = mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_RX, &cfg_raw); if (res) return res; @@ -198,7 +356,8 @@ int xsdr_configure_lml_mmcm(xsdr_dev_t *d) // Wait for lock res = lowlevel_reg_rd32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, &rb); - + if (res) + break; USDR_LOG("XDEV", USDR_LOG_INFO, "MMCM FLAGS:%08x\n", rb); if (rb & (1 << 16)) @@ -206,43 +365,13 @@ int xsdr_configure_lml_mmcm(xsdr_dev_t *d) usleep(5000); } - return 0; - - return -ERANGE; -#if 0 - res = lowlevel_reg_wr32(d->base.base.dev, d->base.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0x1); - if (res) - return res; - res = lowlevel_reg_wr32(d->base.base.dev, d->base.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0x0); - if (res) - return res; - - - - //////////////////// - - res = (res) ? res : lowlevel_reg_wr32(d->base.base.dev, d->base.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0x1); - usleep(1000); - res = (res) ? res : lowlevel_reg_wr32(d->base.base.dev, d->base.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0x0); - res = (res) ? res : lowlevel_reg_wr32(d->base.base.dev, d->base.subdev, REG_CFG_PHY_0, - 0x01000000); - for (unsigned k = 0; k < 10; k++) { - // Wait for lock - res = lowlevel_reg_rd32(d->base.base.dev, d->base.subdev, - REG_CFG_PHY_0, &rb); - } -#endif return res; } -int xsdr_phy_tune(xsdr_dev_t *d, unsigned val) +int xsdr_phy_tune_rx(xsdr_dev_t *d, unsigned val) { - int res = mmcm_set_phdigdelay_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, 0, CLKOUT_PORT_0, val); + int res = mmcm_set_phdigdelay_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_RX, CLKOUT_PORT_0, val); return res; } @@ -263,22 +392,33 @@ int xsdr_hwchans_cnt(xsdr_dev_t *d, bool rx, unsigned chans) return 0; } +enum { + PHY_CFG_VALID_MSK = 0x80, + PHY_CFG_LML2_IS_RX = 0x40, + PHY_CFG_TX_MMCM = 0x20, + PHY_CFG_RX_MMCM = 0x10, +}; + int xsdr_set_samplerate_ex(xsdr_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, unsigned flags) { - const unsigned l1_pid = (d->hwid) & 0x7; - const unsigned l2_pid = (d->hwid >> 4) & 0x7; - const bool lml1_rx_valid = (l1_pid == 3 || l1_pid == 4 || l1_pid == 5 || l1_pid == 6) || l1_pid == 7; - const bool lml2_rx_valid = (l2_pid == 3 || l2_pid == 4 || l2_pid == 5 || l2_pid == 6) || l2_pid == 7; - const unsigned rx_port = (lml2_rx_valid && !lml1_rx_valid) ? 2 : 1; - const unsigned rx_port_1 = (rx_port == 1); + const uint8_t phycfg_id = (d->hwid) & 0xff; + const bool rx_port_is_1 = ((phycfg_id & PHY_CFG_LML2_IS_RX) != PHY_CFG_LML2_IS_RX); + const bool tx_mmcm = ((phycfg_id & PHY_CFG_TX_MMCM) == PHY_CFG_TX_MMCM); + const bool rx_mmcm = ((phycfg_id & PHY_CFG_RX_MMCM) == PHY_CFG_RX_MMCM); + lldev_t dev = d->base.lmsstate.dev; subdev_t subdev = d->base.lmsstate.subdev; unsigned sisosdrflag; int res; + if (!(phycfg_id & PHY_CFG_VALID_MSK)) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "Incompatible firmware, please update to 20250501 at least!\n"); + return -ENOTSUP; + } + res = _xsdr_checkpwr(d); if (res) return res; @@ -287,12 +427,10 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, rxrate = 1e6; } - // TODO: Check if MMCM is present - bool mmcmrx = false; unsigned m_flags = flags | ((d->siso_sdr_active_rx && d->hwchans_rx == 1) ? XSDR_LML_SISO_DDR_RX : 0) | ((d->siso_sdr_active_tx && d->hwchans_tx == 1) ? XSDR_LML_SISO_DDR_TX : 0); - res = lms7002m_samplerate(&d->base, rxrate, txrate, adcclk, dacclk, m_flags, rx_port_1); + res = lms7002m_samplerate(&d->base, rxrate, txrate, adcclk, dacclk, m_flags, rx_port_is_1); if (res) return res; @@ -312,47 +450,58 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, d->afe_active = true; } - if (mmcmrx) { - res = xsdr_configure_lml_mmcm(d); - if (res) - return res; - } + if (rxrate) { + if (rx_mmcm) { + res = res ? res : xsdr_configure_lml_mmcm_rx(d); + } - sisosdrflag = d->base.lml_mode.rxsisoddr ? 8 : 0; - res = lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); - usleep(100); - res = lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); + sisosdrflag = d->base.lml_mode.rxsisoddr ? 8 : 0; + res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); + usleep(100); + res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); - if (mmcmrx) { - // Configure PHY (reset) - // TODO phase search - for (unsigned h = 0; h < 16; h++) { - res = lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); - usleep(100); - res = lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); + if (rx_mmcm) { + // Configure PHY (reset) + // TODO phase search + for (unsigned h = 0; h < 16; h++) { + res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); + usleep(100); + res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=%d\n", h); - res = lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x00000000); - unsigned tmp; //, tmp2; - for (unsigned k = 0; k < 100; k++) { - res = lowlevel_reg_rd32(dev, subdev, REG_CFG_PHY_0, &tmp); - } - mmcm_set_digdelay_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, 0, CLKOUT_PORT_0, h); + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=%d\n", h); + res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x00000000); + unsigned tmp; //, tmp2; + for (unsigned k = 0; k < 100; k++) { + res = res ? res : lowlevel_reg_rd32(dev, subdev, REG_CFG_PHY_0, &tmp); + } + + res = res ? res : mmcm_set_digdelay_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_RX, CLKOUT_PORT_0, h); + } } + + // Switch to clock meas + res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); } - // Switch to clock meas - res = lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); + if (txrate) { + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); - // uint32_t m; - // res = lowlevel_reg_rd32(dev, subdev, REG_CFG_PHY_0, &m); - // USDR_LOG("XDEV", USDR_LOG_INFO, "MEAS=%08x\n", m); + if (tx_mmcm) { + res = res ? res : xsdr_configure_lml_mmcm_tx(d); + } else { + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x8f); + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x8f); + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x0f); - return res; + unsigned dly = (d->tx_override_phase) ? d->tx_override_phase : 3; + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_DLY_VALUE, dly); + } + } + return res; } @@ -1075,6 +1224,20 @@ int _xsdr_pwren_revo(xsdr_dev_t *d, bool on) return 0; } +int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) +{ + if (!d->new_rev) + return -EINVAL; + + if (vio_mv > 2100) + vio_mv = 2100; + else if (vio_mv < 1600) + vio_mv = 1600; + + USDR_LOG("XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); + return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, vio_mv); +} + int xsdr_pwren(xsdr_dev_t *d, bool on) { int res; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 0d98c67d..01f165da 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -49,6 +49,8 @@ struct xsdr_dev unsigned lms7_lob; + int tx_override_phase; + bool afe_active; bool siso_sdr_active_rx; bool siso_sdr_active_tx; @@ -124,6 +126,7 @@ int xsdr_dtor(xsdr_dev_t *d); int xsdr_set_extref(xsdr_dev_t *d, bool ext, uint32_t freq); +int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv); // Enable RFIC, no streaming int xsdr_pwren(xsdr_dev_t *d, bool on); @@ -148,11 +151,15 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int //int (*set_tx_testsig_fs8)(void* param, int channel); -int xsdr_phy_tune(xsdr_dev_t *d, unsigned val); +int xsdr_phy_tune_rx(xsdr_dev_t *d, unsigned val); int xsdr_clk_debug_info(xsdr_dev_t *d); int xsdr_hwchans_cnt(xsdr_dev_t *d, bool rx, unsigned chans); +int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, + size_t meminsz, void* pin, size_t memoutsz, + const void* pout); + enum { XSDR_CAL_RXLO = 1, XSDR_CAL_TXLO = 2, diff --git a/src/lib/lowlevel/usdr_lowlevel.c b/src/lib/lowlevel/usdr_lowlevel.c index 9af43a76..e1307d71 100644 --- a/src/lib/lowlevel/usdr_lowlevel.c +++ b/src/lib/lowlevel/usdr_lowlevel.c @@ -107,6 +107,11 @@ int lowlevel_discovery(unsigned pcount, const char** devparam, const char **devv return count; } +void lowlevel_ops_set_custom(lldev_t obj, lowlevel_ops_t* newops) +{ + obj->ops = newops; +} + void __attribute__ ((constructor(110))) setup_lowlevel(void) { lowlevel_initialize_plugins(); } diff --git a/src/lib/lowlevel/usdr_lowlevel.h b/src/lib/lowlevel/usdr_lowlevel.h index daaf4235..89fa5e2f 100644 --- a/src/lib/lowlevel/usdr_lowlevel.h +++ b/src/lib/lowlevel/usdr_lowlevel.h @@ -226,7 +226,6 @@ int lowlevel_discovery(unsigned pcount, const char** devparam, const char **devv unsigned maxbuf, char* buf); int lowlevel_create(unsigned pcount, const char** devparam, const char **devval, lldev_t* odev, unsigned vidpid, void* webops, uintptr_t param); - device_t* lowlevel_get_device(lldev_t obj); // Basic object @@ -236,5 +235,7 @@ struct lowlevel_dev { }; typedef struct lowlevel_dev lowlevel_dev_t; +// Set new low-level device filter to specifically process some exceptions +void lowlevel_ops_set_custom(lldev_t obj, lowlevel_ops_t* newops); #endif From 5ff19fadc417a0114da19cf84d2bd02aa5a5dfec Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 May 2025 15:39:38 +0400 Subject: [PATCH 149/397] fix --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index aade888c..b4bfbcb0 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -496,7 +496,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x8f); res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x0f); - unsigned dly = (d->tx_override_phase) ? d->tx_override_phase : 3; + unsigned dly = (d->tx_override_phase) ? (d->tx_override_phase - 1) : 3; res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_DLY_VALUE, dly); } } From c6bf96a3ed9ab3749c02c73be575169dcec38969 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 27 May 2025 01:34:34 +0400 Subject: [PATCH 150/397] lmk05138b: skip soft sync since it fails somehow --- src/lib/device/ext_xmass/ext_xmass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 0d78eda6..64fa5703 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -243,7 +243,7 @@ int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); - res = res ? res : lmk05318_sync(&ob->lmk); + //res = res ? res : lmk05318_sync(&ob->lmk); lmk05318_check_lock(&ob->lmk, &los_msk, false /*silent*/); //just to log state From a9e521f338caa86235391c22c0b7b771a3ba848a Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 27 May 2025 17:20:09 +0300 Subject: [PATCH 151/397] LMK create() refactored, xo params simplified --- .../device/ext_simplesync/ext_simplesync.c | 10 +-- src/lib/device/ext_xmass/ext_xmass.c | 7 +- src/lib/device/m2_dsdr/m2_dsdr.c | 6 +- src/lib/device/pe_sync/pe_sync.c | 7 +- src/lib/hw/lmk05318/lmk05318.c | 13 +++- src/lib/hw/lmk05318/lmk05318.h | 3 +- src/utests/lmk05318_solver_test.c | 71 ++++--------------- 7 files changed, 29 insertions(+), 88 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index 89e068c9..ef6f2730 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -87,11 +87,6 @@ int board_ext_simplesync_init(lldev_t dev, // Wait for power up usleep(50000); - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 26000000; - xo.type = XO_CMOS; - lmk05318_out_config_t lmk_out[4]; lmk05318_port_request(&lmk_out[0], 4, 25000000, false, LVCMOS_P_N); @@ -104,10 +99,7 @@ int board_ext_simplesync_init(lldev_t dev, lmk05318_set_port_affinity(&lmk_out[2], AFF_APLL1); lmk05318_set_port_affinity(&lmk_out[3], AFF_APLL1); - lmk05318_dpll_settings_t dpll; - dpll.enabled = false; - - res = lmk05318_create(dev, subdev, i2ca, &xo, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &ob->lmk, false /*dry_run*/); + res = lmk05318_create(dev, subdev, i2ca, 26000000, XO_CMOS, false, NULL, lmk_out, SIZEOF_ARRAY(lmk_out), &ob->lmk, false /*dry_run*/); if(res) return res; diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 0d78eda6..2f31c455 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -135,11 +135,6 @@ int board_xmass_init(lldev_t dev, ob->calfreq = 444e6; //LMK05318 init start - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 26000000; - xo.type = XO_AC_DIFF_EXT; - lmk05318_dpll_settings_t dpll; memset(&dpll, 0, sizeof(dpll)); dpll.enabled = false; @@ -151,7 +146,7 @@ int board_xmass_init(lldev_t dev, lmk05318_out_config_t lmk05318_outs_cfg[8]; res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); - res = res ? res : lmk05318_create(dev, subdev, i2c_lmka, &xo, &dpll, lmk05318_outs_cfg, 8, &ob->lmk, false); + res = res ? res : lmk05318_create(dev, subdev, i2c_lmka, 26000000, XO_AC_DIFF_EXT, false, &dpll, lmk05318_outs_cfg, 8, &ob->lmk, false); if (res) { USDR_LOG("XMSS", USDR_LOG_ERROR, "Unable to initialize XMASS\n"); diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index a04d7707..5b448403 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1425,10 +1425,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // //LMK05318 init start - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 26000000; - xo.type = XO_CMOS; //set true to enable IN_REF1 40M bool enable_in_ref = false; @@ -1453,7 +1449,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** lmk05318_port_request(&lmk_out[6], 6, 3840000, false, LVDS); lmk05318_port_request(&lmk_out[7], 7, d->dac_rate / 2, false, LVDS); - res = lmk05318_create(dev, d->subdev, I2C_LMK, &xo, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->lmk, false /*dry_run*/); + res = lmk05318_create(dev, d->subdev, I2C_LMK, 26000000, XO_CMOS, false, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->lmk, false /*dry_run*/); if(res) return res; diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 318970bb..a48cae1c 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -270,11 +270,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 25000000; - xo.type = XO_CMOS; - lmk05318_dpll_settings_t dpll; memset(&dpll, 0, sizeof(dpll)); dpll.enabled = true; @@ -307,7 +302,7 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const res = res ? res : lmk05318_port_request(&lmk_out[6], 6, lmk_freq[6], false, LVCMOS_P_N); res = res ? res : lmk05318_port_request(&lmk_out[7], 7, lmk_freq[7], false, LVCMOS_P_N); - res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, &xo, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->gen, false /*dry_run*/); + res = res ? res : lmk05318_create(dev, 0, I2C_BUS_LMK05318B, 25000000, XO_CMOS, false, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->gen, false /*dry_run*/); if(res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 319867f7..e22c4d65 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -601,6 +601,11 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett { int res = 0; + if(!dpll) + { + d->dpll.enabled = false; + } + if(d->dpll.enabled == false) { // WITHOUT DPLL @@ -871,7 +876,8 @@ static int lmk05318_set_common_registers(lmk05318_state_t* d, lmk05318_dpll_sett } int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, - const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, + uint32_t xo_freq, xo_input_type_t xo_fmttype, bool xo_fdet_bypass, + lmk05318_dpll_settings_t* dpll, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, lmk05318_state_t* out, bool dry_run) { @@ -889,7 +895,10 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, out->pd2 = 0; out->fref_pll2_div_rp = 3; out->fref_pll2_div_rs = (((VCO_APLL1 + APLL2_PD_MAX - 1) / APLL2_PD_MAX) + out->fref_pll2_div_rp - 1) / out->fref_pll2_div_rp; - out->xo = *xo; + + out->xo.fref = xo_freq; + out->xo.type = xo_fmttype; + out->xo.fdet_bypass = xo_fdet_bypass; res = dry_run ? 0 : lmk05318_reg_get_u32(out, 0, &dummy[0]); if (res) diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 805de5b7..8c6866fc 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -232,7 +232,8 @@ int lmk05318_tune_apll1(lmk05318_state_t* d); int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned n_outs); int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, - const lmk05318_xo_settings_t* xo, lmk05318_dpll_settings_t* dpll, + uint32_t xo_freq, xo_input_type_t xo_fmttype, bool xo_fdet_bypass, + lmk05318_dpll_settings_t* dpll, lmk05318_out_config_t* out_ports_cfg, unsigned out_ports_len, lmk05318_state_t* out, bool dry_run); diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index e42f9e6e..b7994a73 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -154,11 +154,6 @@ START_TEST(lmk05318_solver_pesync) res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS_P_N); ck_assert_int_eq( res, 0 ); - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 12800000; - xo.type = XO_CMOS; - lmk05318_dpll_settings_t dpll; memset(&dpll, 0, sizeof(dpll)); dpll.enabled = true; @@ -169,9 +164,7 @@ START_TEST(lmk05318_solver_pesync) dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; lmk05318_state_t st; - memset(&st, 0, sizeof(st)); - - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, 12800000, XO_CMOS, false, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } @@ -191,21 +184,9 @@ START_TEST(lmk05318_solver_pesync_free_run) res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS_P_N); ck_assert_int_eq( res, 0 ); - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 25000000; - xo.type = XO_CMOS; - - lmk05318_dpll_settings_t dpll; - memset(&dpll, 0, sizeof(dpll)); - dpll.enabled = false; - lmk05318_state_t st; - memset(&st, 0, sizeof(st)); - - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, 25000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); - } START_TEST(lmk05318_dpll_test1) @@ -228,11 +209,6 @@ START_TEST(lmk05318_dsdr_test1) { int res = 0; - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 26000000; - xo.type = XO_CMOS; - lmk05318_out_config_t* p = &cfg[0]; res = res ? res : lmk05318_port_request(p++, 0, 491520000, false, OUT_OFF); @@ -256,9 +232,7 @@ START_TEST(lmk05318_dsdr_test1) dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; lmk05318_state_t st; - memset(&st, 0, sizeof(st)); - - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } @@ -266,11 +240,6 @@ START_TEST(lmk05318_dsdr_test2) { int res = 0; - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 26000000; - xo.type = XO_CMOS; - lmk05318_out_config_t* p = &cfg[0]; res = res ? res : lmk05318_port_request(p++, 0, 491520000, false, OUT_OFF); @@ -294,9 +263,7 @@ START_TEST(lmk05318_dsdr_test2) dpll.buf_mode[LMK05318_PRIREF] = DPLL_REF_AC_BUF_HYST50_DC_EN; lmk05318_state_t st; - memset(&st, 0, sizeof(st)); - - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } @@ -345,11 +312,6 @@ START_TEST(lmk05318_simplesync_test1) { int res = 0; - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 26000000; - xo.type = XO_CMOS; - lmk05318_out_config_t cfg1[4]; lmk05318_out_config_t* p = &cfg1[0]; @@ -365,13 +327,8 @@ START_TEST(lmk05318_simplesync_test1) lmk05318_set_port_affinity(p++, AFF_APLL1); lmk05318_set_port_affinity(p++, AFF_APLL1); - lmk05318_dpll_settings_t dpll; - dpll.enabled = false; - lmk05318_state_t st; - memset(&st, 0, sizeof(st)); - - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg1, SIZEOF_ARRAY(cfg1), &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, NULL, cfg1, SIZEOF_ARRAY(cfg1), &st, true /*dry_run*/); res = res ? res : simplesync_pd_low_chs(&st); ck_assert_int_eq( res, 0 ); @@ -393,11 +350,6 @@ START_TEST(lmk05318_solver_test_xmass) { int res = 0; - lmk05318_xo_settings_t xo; - memset(&xo, 0, sizeof(xo)); - xo.fref = 26000000; - xo.type = XO_CMOS; - lmk05318_out_config_t* p = &cfg[0]; res = res ? res : lmk05318_port_request(p++, 0, 0, false, OUT_OFF); @@ -412,16 +364,16 @@ START_TEST(lmk05318_solver_test_xmass) res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); ck_assert_int_eq( res, 0 ); - lmk05318_dpll_settings_t dpll; - dpll.enabled = false; - lmk05318_state_t st; - memset(&st, 0, sizeof(st)); - - res = lmk05318_create(NULL, 0, 0, &xo, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); + res = lmk05318_port_request(&cfg[4], 4, 4000000, false, LVDS); + res = res ? res : lmk05318_solver(&st, cfg, 8); + res = res ? res : lmk05318_reg_wr_from_map(&st, true); + + ck_assert_int_eq( res, 0 ); } Suite * lmk05318_solver_suite(void) @@ -433,6 +385,7 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); + tcase_add_test(tc_core, lmk05318_solver_test1); tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); From 176ff7208626a43bd5e58dff8a1d9cba8761742e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 27 May 2025 21:38:12 +0400 Subject: [PATCH 152/397] xmass: initial fix --- src/lib/device/device_fe.c | 9 +++++ src/lib/device/ext_xmass/ext_xmass.c | 58 ++++++++++++++++++++++++++-- src/lib/device/ext_xmass/ext_xmass.h | 8 ++++ src/lib/device/mdev.c | 11 ++++-- 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/src/lib/device/device_fe.c b/src/lib/device/device_fe.c index 5eb7fb97..5176701c 100644 --- a/src/lib/device/device_fe.c +++ b/src/lib/device/device_fe.c @@ -41,6 +41,8 @@ static int _debug_xmass_ctrl_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t static int _debug_xmass_calfreq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int _debug_xmass_calfreq_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int _debug_xmass_calpath_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int _debug_typefe_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); static int _debug_ll_mdev_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -74,6 +76,7 @@ static const usdr_dev_param_func_t s_xmass_params[] = { { "/debug/hw/xmass_ctrl/0/reg", { _debug_xmass_ctrl_reg_set, _debug_xmass_ctrl_reg_get }}, { "/dm/sync/cal/freq", { _debug_xmass_calfreq_set, _debug_xmass_calfreq_get }}, { "/dm/sdr/0/sync/cal/freq", { _debug_xmass_calfreq_set, _debug_xmass_calfreq_get }}, + { "/dm/sdr/0/sync/cal/path", { _debug_xmass_calpath_set, NULL }}, }; @@ -490,6 +493,12 @@ int _debug_xmass_calfreq_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value return board_xmass_tune_cal_lo(&o->fe.xmass, value); } +int _debug_xmass_calpath_set(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t value) +{ + dev_fe_t* o = (dev_fe_t*)obj->object; + return board_xmass_sync_source(&o->fe.xmass, value); +} + int _debug_xmass_calfreq_get(pdevice_t ud_x, pusdr_vfs_obj_t obj, uint64_t* ovalue) { dev_fe_t* o = (dev_fe_t*)obj->object; diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 64fa5703..1689fc5f 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -13,6 +13,16 @@ #include "def_ext_xmass_ctrl.h" + +enum { + XMASS_GPIO_RF_CAL_DST_SEL = 2, // 0 - RF_CAL_EXT (general rx port) / 1 - RF_CAL_INT (LNA3 port) + XMASS_GPIO_RF_CAL_SRC_SEL = 3, // 0 - RF_LO_SRC (from LMK) / 1 - RF_NOISE_SRC (from NOISE GEN) + + XMASS_GPIO_RF_CAL_SW = 9, // 0 - Use RF cal source as FB, 1 - Use XSDR TX as FB + XMASS_GPIO_RF_LB_SW = 10, // 0 - Normal operation, 1 - use LB path to XSDR RX + XMASS_GPIO_RF_NOISE_EN = 11, // Enable 14V generator for Zener +}; + // XRA1201IL24TR-F (0x28 I2C) // Port0: // 0 GPIO_BDISTRIB : Enable OUT_REF_B[0:3] and OUT_SYREF_B[0:3] for 4 board sync @@ -82,7 +92,8 @@ static int _board_xmass_fill_lmk05318(board_xmass_t* ob, lmk05318_out_config_t l lmk05318_port_request(&lmk05318_outs_cfg[4], 4, cfreq, false, cfreq == 0 ? OUT_OFF : LVDS); lmk05318_port_request(&lmk05318_outs_cfg[5], 5, 0, false, OUT_OFF); lmk05318_port_request(&lmk05318_outs_cfg[6], 6, ob->refclk, false, LVCMOS_P_N); - lmk05318_port_request(&lmk05318_outs_cfg[7], 7, 1, false, LVCMOS_P_N); + // lmk05318_port_request(&lmk05318_outs_cfg[7], 7, 1, false, LVCMOS_P_N); + lmk05318_port_request(&lmk05318_outs_cfg[7], 7, 0, false, OUT_OFF); lmk05318_set_port_affinity(&lmk05318_outs_cfg[4], AFF_APLL2); return 0; @@ -182,17 +193,22 @@ int board_xmass_init(lldev_t dev, } //sync to make APLL1/APLL2 & out channels in-phase - res = lmk05318_sync(&ob->lmk); - if(res) - return res; + //res = lmk05318_sync(&ob->lmk); + //if(res) + // return res; + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (0 << 5)); + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5)); USDR_LOG("XMSS", USDR_LOG_INFO, "LMK03518 outputs synced"); ob->i2c_xraa = i2c_xraa; + //res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5) | (1 << 10)); return res; } + + int board_xmass_ctrl_cmd_wr(board_xmass_t* ob, uint32_t addr, uint32_t reg) { int res; @@ -228,6 +244,40 @@ int board_xmass_ctrl_cmd_rd(board_xmass_t* ob, uint32_t addr, uint32_t* preg) return res; } +// 0 - off +// 1 - LO +// 2 - noise +// 3 - LO - LNA3 +// 4 - noise - LNA3 + +int board_xmass_sync_source(board_xmass_t* ob, unsigned sync_src) +{ + int res; + unsigned default_cmd = (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5); + + switch (sync_src) { + case 0: + res = tca9555_reg16_set(ob->lmk.dev, ob->lmk.subdev, ob->i2c_xraa, TCA9555_OUT0, default_cmd); + break; + case 2: + res = tca9555_reg16_set(ob->lmk.dev, ob->lmk.subdev, ob->i2c_xraa, TCA9555_OUT0, default_cmd | (1 << XMASS_GPIO_RF_LB_SW) | (1 << XMASS_GPIO_RF_NOISE_EN) | (1 << XMASS_GPIO_RF_CAL_SRC_SEL)); + break; + case 1: + res = tca9555_reg16_set(ob->lmk.dev, ob->lmk.subdev, ob->i2c_xraa, TCA9555_OUT0, default_cmd | (1 << XMASS_GPIO_RF_LB_SW)); + break; + case 4: + res = tca9555_reg16_set(ob->lmk.dev, ob->lmk.subdev, ob->i2c_xraa, TCA9555_OUT0, default_cmd | (1 << XMASS_GPIO_RF_LB_SW) | (1 << XMASS_GPIO_RF_CAL_DST_SEL) | (1 << XMASS_GPIO_RF_NOISE_EN) | (1 << XMASS_GPIO_RF_CAL_SRC_SEL)); + break; + case 3: + res = tca9555_reg16_set(ob->lmk.dev, ob->lmk.subdev, ob->i2c_xraa, TCA9555_OUT0, default_cmd | (1 << XMASS_GPIO_RF_LB_SW) | (1 << XMASS_GPIO_RF_CAL_DST_SEL)); + break; + default: + return -EINVAL; + } + + return res; +} + int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) { diff --git a/src/lib/device/ext_xmass/ext_xmass.h b/src/lib/device/ext_xmass/ext_xmass.h index 2a56a364..1c45e08d 100644 --- a/src/lib/device/ext_xmass/ext_xmass.h +++ b/src/lib/device/ext_xmass/ext_xmass.h @@ -50,4 +50,12 @@ int board_xmass_ctrl_cmd_rd(board_xmass_t* ob, uint32_t addr, uint32_t* preg); int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo); +// 0 - off +// 1 - LO +// 2 - noise +// 3 - LO - LNA3 +// 4 - noise - LNA3 +int board_xmass_sync_source(board_xmass_t* ob, unsigned sync_src); + + #endif diff --git a/src/lib/device/mdev.c b/src/lib/device/mdev.c index 9bf8c9eb..1f3f6c2a 100644 --- a/src/lib/device/mdev.c +++ b/src/lib/device/mdev.c @@ -380,10 +380,10 @@ int _mdev_create_stream(device_t* dev, const char* sid, const char* dformat, // TODO proper parse with specific chnnel mixing for (unsigned k = 0; k < chans_per_dev; k++) { if (channels->phys_names) { - phys_names[k] = channels->phys_names[chans_per_dev * i + k]; + phys_names[k] = channels->phys_names[k]; } if (channels->phys_nums) { - phys_nums[k] = channels->phys_nums[chans_per_dev * i + k]; + phys_nums[k] = channels->phys_nums[k]; } } @@ -400,12 +400,15 @@ int _mdev_create_stream(device_t* dev, const char* sid, const char* dformat, return -EBUSY; } - USDR_LOG("MDEV", USDR_LOG_ERROR, "Creating stream for dev %d with %d channels\n", i, chans_per_dev); + USDR_LOG("MDEV", USDR_LOG_INFO, "Creating stream for dev %d with %d channels\n", i, chans_per_dev); pdevice_t child_dev = obj->real[i]->pdev; res = child_dev->create_stream(child_dev, sid, dformat, &subdev_info, pktsyms, flags, parameters, &real_str[i]); - if (res) + if (res) { + USDR_LOG("MDEV", USDR_LOG_ERROR, "Failed to create strem for dev %d: FMT %s, syms %d SI={CNT=%d FLAGS=%d}: Error %d\n", + i, dformat, pktsyms, subdev_info.count, subdev_info.flags, res); return res; + } mstr->dev_mask[i] = true; From 653e6251560f193b697be62b751665f3a04772ee Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 28 May 2025 00:56:59 +0400 Subject: [PATCH 153/397] xmass: fix sysref_gen routing --- src/lib/device/ext_xmass/ext_xmass.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 1689fc5f..0cdadc97 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -120,6 +120,9 @@ int board_xmass_init(lldev_t dev, // Configure 1PPS input res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO2, GPIO_CFG_ALT0); + // Configure SYSREF_GEN + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO3, GPIO_CFG_ALT0); + unsigned i2c_lmka = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_LMK); unsigned i2c_xraa = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_XRA1201); uint16_t val; @@ -138,7 +141,7 @@ int board_xmass_init(lldev_t dev, } // En LMK to ckeck it - res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5)); + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 5)); usleep(250000); @@ -197,8 +200,8 @@ int board_xmass_init(lldev_t dev, //if(res) // return res; - res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (0 << 5)); - res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5)); + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 6) | (0 << 5)); + res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 5)); USDR_LOG("XMSS", USDR_LOG_INFO, "LMK03518 outputs synced"); ob->i2c_xraa = i2c_xraa; @@ -253,7 +256,7 @@ int board_xmass_ctrl_cmd_rd(board_xmass_t* ob, uint32_t addr, uint32_t* preg) int board_xmass_sync_source(board_xmass_t* ob, unsigned sync_src) { int res; - unsigned default_cmd = (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5); + unsigned default_cmd = (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 5); switch (sync_src) { case 0: From 98f438cb0a8baa06cfa969887e3b283dfd510a73 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 31 May 2025 22:20:01 +0300 Subject: [PATCH 154/397] refactoring --- .../device/ext_simplesync/ext_simplesync.c | 3 +- src/lib/device/ext_xmass/ext_xmass.c | 7 +- src/lib/device/m2_dsdr/m2_dsdr.c | 2 - src/lib/device/pe_sync/pe_sync.c | 2 - src/lib/hw/lmk05318/lmk05318.c | 70 ++++++++++++++++--- src/lib/hw/lmk05318/lmk05318.h | 3 + src/utests/lmk05318_solver_test.c | 21 +++++- 7 files changed, 88 insertions(+), 20 deletions(-) diff --git a/src/lib/device/ext_simplesync/ext_simplesync.c b/src/lib/device/ext_simplesync/ext_simplesync.c index ef6f2730..8b0e1e49 100644 --- a/src/lib/device/ext_simplesync/ext_simplesync.c +++ b/src/lib/device/ext_simplesync/ext_simplesync.c @@ -142,12 +142,11 @@ int simplesync_tune_lo(board_ext_simplesync_t* ob, uint32_t meas_lo) lmk05318_set_port_affinity(&lmk_out[2], AFF_APLL2); lmk05318_set_port_affinity(&lmk_out[3], AFF_APLL2); - res = lmk05318_solver(&ob->lmk, lmk_out, SIZEOF_ARRAY(lmk_out)); + res = res ? res : lmk05318_solver(&ob->lmk, lmk_out, SIZEOF_ARRAY(lmk_out)); res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false /*dry_run*/); if(res) return res; - res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 2f31c455..096ca045 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -85,6 +85,8 @@ static int _board_xmass_fill_lmk05318(board_xmass_t* ob, lmk05318_out_config_t l lmk05318_port_request(&lmk05318_outs_cfg[7], 7, 1, false, LVCMOS_P_N); lmk05318_set_port_affinity(&lmk05318_outs_cfg[4], AFF_APLL2); + lmk05318_set_port_affinity(&lmk05318_outs_cfg[6], AFF_APLL1); + lmk05318_set_port_affinity(&lmk05318_outs_cfg[7], AFF_APLL1); return 0; } @@ -147,13 +149,10 @@ int board_xmass_init(lldev_t dev, lmk05318_out_config_t lmk05318_outs_cfg[8]; res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); res = res ? res : lmk05318_create(dev, subdev, i2c_lmka, 26000000, XO_AC_DIFF_EXT, false, &dpll, lmk05318_outs_cfg, 8, &ob->lmk, false); - if (res) { USDR_LOG("XMSS", USDR_LOG_ERROR, "Unable to initialize XMASS\n"); } - usleep(10000); //wait until lmk digests all this - //wait for PRIREF/SECREF validation res = lmk05318_wait_dpll_ref_stat(&ob->lmk, 4*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on if(res) @@ -235,8 +234,8 @@ int board_xmass_tune_cal_lo(board_xmass_t* ob, uint32_t callo) res = res ? res : _board_xmass_fill_lmk05318(ob, lmk05318_outs_cfg); res = res ? res : lmk05318_solver(&ob->lmk, lmk05318_outs_cfg, 8); res = res ? res : lmk05318_reg_wr_from_map(&ob->lmk, false); + usleep(10000); - res = res ? res : lmk05318_wait_apll1_lock(&ob->lmk, 10000); res = res ? res : lmk05318_wait_apll2_lock(&ob->lmk, 10000); res = res ? res : lmk05318_sync(&ob->lmk); diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 5b448403..65a3db8e 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1453,8 +1453,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** if(res) return res; - usleep(10000); //wait until lmk digests all this - //wait for PRIREF/SECREF validation res = lmk05318_wait_dpll_ref_stat(&d->lmk, 100000); if(res) diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index a48cae1c..3865fa71 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -306,8 +306,6 @@ static int usdr_device_pe_sync_initialize(pdevice_t udev, unsigned pcount, const if(res) return res; - usleep(10000); //wait until lmk digests all this - //wait for PRIREF/SECREF validation res = lmk05318_wait_dpll_ref_stat(&d->gen, 4*60000000); //60s - searching for satellites may take a lot of time if GPS in just turned on if(res) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index e22c4d65..42536c6f 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -427,6 +427,26 @@ int lmk05318_reg_wr_from_map(lmk05318_state_t* d, bool dry_run) } +static int lmk05318_trigger_reg_with_sleep(lmk05318_state_t* out, uint32_t regs[2]) +{ + int res = lmk05318_reg_wr_n(out, ®s[0], 1); + if(res) + return res; + + usleep(10000); + + res = lmk05318_reg_wr_n(out, ®s[1], 1); + if(res) + return res; + + usleep(10000); + return res; +} + +UNUSED static int lmk05318_trigger_reg(lmk05318_state_t* out, uint32_t regs[2]) +{ + return lmk05318_reg_wr_n(out, ®s[0], 2); +} int lmk05318_softreset(lmk05318_state_t* out) @@ -438,13 +458,13 @@ int lmk05318_softreset(lmk05318_state_t* out) if(res) return res; - uint32_t regs[] = + uint32_t regs[2] = { MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl | mask), MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl & ~mask), }; - return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; + return lmk05318_trigger_reg_with_sleep(out, regs); } int lmk05318_sync(lmk05318_state_t* out) @@ -456,13 +476,13 @@ int lmk05318_sync(lmk05318_state_t* out) if(res) return res; - uint32_t regs[] = - { - MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl | mask), - MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl & ~mask), - }; + uint32_t regs[2] = + { + MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl | mask), + MAKE_LMK05318_REG_WR(DEV_CTL, reg_ctrl & ~mask), + }; - return lmk05318_reg_wr_n(out, regs, SIZEOF_ARRAY(regs));; + return lmk05318_trigger_reg_with_sleep(out, regs); } int lmk05318_mute(lmk05318_state_t* out, uint8_t chmask) @@ -952,6 +972,8 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, return res; } + usleep(10000); //wait for LMK digests it all + res = dry_run ? 0 : lmk05318_softreset(out); if(res) { @@ -1012,6 +1034,28 @@ static inline double lmk05318_calc_vco2_div(lmk05318_state_t* d, uint64_t fvco2, return fvco2_fact; } +int lmk05318_apll1_calibrate(lmk05318_state_t* d) +{ + uint32_t regs[2] = + { + MAKE_LMK05318_PLL1_CTRL0(1), + MAKE_LMK05318_PLL1_CTRL0(0), + }; + + return lmk05318_trigger_reg_with_sleep(d, regs); +} + +int lmk05318_apll2_calibrate(lmk05318_state_t* d) +{ + uint32_t regs[2] = + { + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 1), + MAKE_LMK05318_PLL2_CTRL0(d->fref_pll2_div_rs - 1, d->fref_pll2_div_rp - 3, 0), + }; + + return lmk05318_trigger_reg_with_sleep(d, regs); +} + static int lmk05318_tune_apll2(lmk05318_state_t* d) { int res; @@ -1150,7 +1194,7 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) }; int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); - res = res ? res : lmk05318_set_xo_bawdetect_registers(d); + //res = res ? res : lmk05318_set_xo_bawdetect_registers(d); return res; } @@ -2352,6 +2396,10 @@ int lmk05318_wait_apll1_lock(lmk05318_state_t* d, unsigned timeout) unsigned los_msk; bool pll1_vm_inside; + res = lmk05318_apll1_calibrate(d); + if(res) + return res; + res = lmk05318_reset_los_flags(d); if(res) return res; @@ -2419,6 +2467,10 @@ int lmk05318_wait_apll2_lock(lmk05318_state_t* d, unsigned timeout) unsigned los_msk; bool pll2_vm_inside; + res = lmk05318_apll2_calibrate(d); + if(res) + return res; + res = lmk05318_reset_los_flags(d); if(res) return res; diff --git a/src/lib/hw/lmk05318/lmk05318.h b/src/lib/hw/lmk05318/lmk05318.h index 8c6866fc..e9b14153 100644 --- a/src/lib/hw/lmk05318/lmk05318.h +++ b/src/lib/hw/lmk05318/lmk05318.h @@ -240,4 +240,7 @@ int lmk05318_create(lldev_t dev, unsigned subdev, unsigned lsaddr, int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll); int lmk05318_wait_dpll_ref_stat(lmk05318_state_t* d, unsigned timeout); +int lmk05318_apll1_calibrate(lmk05318_state_t* d); +int lmk05318_apll2_calibrate(lmk05318_state_t* d); + #endif diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index b7994a73..1e90a07f 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -362,6 +362,8 @@ START_TEST(lmk05318_solver_test_xmass) res = res ? res : lmk05318_port_request(p++, 7, 1, false, LVCMOS_P_N); res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); + res = res ? res : lmk05318_set_port_affinity(&cfg[6], AFF_APLL1); + res = res ? res : lmk05318_set_port_affinity(&cfg[7], AFF_APLL1); ck_assert_int_eq( res, 0 ); lmk05318_state_t st; @@ -370,11 +372,28 @@ START_TEST(lmk05318_solver_test_xmass) ck_assert_int_eq( res, 0 ); res = lmk05318_port_request(&cfg[4], 4, 4000000, false, LVDS); + res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); res = res ? res : lmk05318_solver(&st, cfg, 8); res = res ? res : lmk05318_reg_wr_from_map(&st, true); + ck_assert_int_eq( res, 0 ); + res = lmk05318_port_request(&cfg[4], 4, 5000000, false, LVDS); + res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); + res = res ? res : lmk05318_solver(&st, &cfg[4], 1); + res = res ? res : lmk05318_reg_wr_from_map(&st, true); ck_assert_int_eq( res, 0 ); -} + + res = lmk05318_port_request(&cfg[4], 4, 0, false, LVDS); + res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); + res = res ? res : lmk05318_solver(&st, cfg, 8); + res = res ? res : lmk05318_reg_wr_from_map(&st, true); + ck_assert_int_eq( res, 0 ); + + res = lmk05318_port_request(&cfg[4], 4, 6000000, false, LVDS); + res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); + res = res ? res : lmk05318_solver(&st, cfg, 8); + res = res ? res : lmk05318_reg_wr_from_map(&st, true); + ck_assert_int_eq( res, 0 );} Suite * lmk05318_solver_suite(void) { From 1f437b889abebccf9442879ba2b79a7a6c909552 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 2 Jun 2025 23:29:59 +0300 Subject: [PATCH 155/397] Fix potential error in lmk05318_get_output_divider() + new dsdr unit-test --- src/lib/hw/lmk05318/lmk05318.c | 4 ++-- src/utests/lmk05318_solver_test.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 42536c6f..20627088 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1194,7 +1194,7 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) }; int res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); - //res = res ? res : lmk05318_set_xo_bawdetect_registers(d); + res = res ? res : lmk05318_set_xo_bawdetect_registers(d); return res; } @@ -1572,7 +1572,7 @@ static inline int lmk05318_get_output_divider(const lmk05318_out_config_t* cfg, return 1; double factf = ifreq / (*div); - return (factf == cfg->wanted.freq) ? 0 : 1; + return (fabs(factf - (double)cfg->wanted.freq) < 1E-6) ? 0 : 1; } VWLT_ATTRIBUTE(optimize("-Ofast")) diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 1e90a07f..8ad4b8d9 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -267,6 +267,28 @@ START_TEST(lmk05318_dsdr_test2) ck_assert_int_eq( res, 0 ); } +START_TEST(lmk05318_dsdr_test3) +{ + int res = 0; + + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 1, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 4, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 245760000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 6, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 7, 245760000, false, LVDS); + ck_assert_int_eq( res, 0 ); + + lmk05318_state_t st; + res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); +} + + static int simplesync_pd_low_chs(lmk05318_state_t* st) { int res = 0; @@ -414,6 +436,7 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_dpll_test1); tcase_add_test(tc_core, lmk05318_dsdr_test1); tcase_add_test(tc_core, lmk05318_dsdr_test2); + tcase_add_test(tc_core, lmk05318_dsdr_test3); tcase_add_test(tc_core, lmk05318_simplesync_test1); tcase_add_test(tc_core, lmk05318_solver_test_xmass); From 407991e8e69644d6e7bfd044d34e5ccac2f7e0c8 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 3 Jun 2025 00:43:44 +0300 Subject: [PATCH 156/397] fix in lmk solver, comparing int and double --- src/lib/hw/lmk05318/lmk05318.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 20627088..0d9a0d70 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -1985,13 +1985,13 @@ static inline int lmk05318_solver_helper(lmk05318_out_config_t* outs, unsigned c for(uint64_t f = sol->fvco2.min; f <= sol->fvco2.max; ++f) { - unsigned n, num, den; + unsigned n = 0, num = 0, den = 0; double fvco2 = lmk05318_calc_vco2_div(lmkst, f, &n, &num, &den); if(fvco2 < sol->fvco2.min || fvco2 > sol->fvco2.max) continue; - if(fvco2 != (uint64_t)fvco2) + if(fabs(fvco2 - (uint64_t)fvco2) > 1E-6) continue; bool ok_flag = true; From a6c1081355927138586147800a3d7cd83bc4132e Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 5 Jun 2025 13:33:36 +0300 Subject: [PATCH 157/397] xdsp test refactoring & cleaning --- src/lib/xdsp/utests/conv_2cf32_ci12_utest.c | 28 ++++++------- src/lib/xdsp/utests/conv_2cf32_ci16_utest.c | 26 +++++------- src/lib/xdsp/utests/conv_2ci16_ci12_utest.c | 28 ++++++------- src/lib/xdsp/utests/conv_2ci16_ci16_utest.c | 26 +++++------- src/lib/xdsp/utests/conv_4cf32_ci12_utest.c | 35 ++++++++-------- src/lib/xdsp/utests/conv_4cf32_ci16_utest.c | 32 +++++++-------- src/lib/xdsp/utests/conv_4ci16_ci12_utest.c | 32 +++++++-------- src/lib/xdsp/utests/conv_4ci16_ci16_utest.c | 34 +++++++--------- src/lib/xdsp/utests/conv_ci12_2cf32_utest.c | 40 ++++++------------ src/lib/xdsp/utests/conv_ci12_2ci16_utest.c | 30 +++++++------- src/lib/xdsp/utests/conv_ci12_4cf32_utest.c | 41 ++++++++----------- src/lib/xdsp/utests/conv_ci12_4ci16_utest.c | 41 +++++++++---------- src/lib/xdsp/utests/conv_ci16_2cf32_utest.c | 30 +++++++------- src/lib/xdsp/utests/conv_ci16_2ci16_utest.c | 28 ++++++------- src/lib/xdsp/utests/conv_ci16_4cf32_utest.c | 38 ++++++++--------- src/lib/xdsp/utests/conv_ci16_4ci16_utest.c | 44 ++++++++++---------- src/lib/xdsp/utests/conv_f32_i12_utest.c | 27 ++++++------- src/lib/xdsp/utests/conv_f32_i16_utest.c | 27 ++++++------- src/lib/xdsp/utests/conv_i12_f32_utest.c | 33 +++++++-------- src/lib/xdsp/utests/conv_i12_i16_utest.c | 26 +++++------- src/lib/xdsp/utests/conv_i16_f32_utest.c | 23 +++++------ src/lib/xdsp/utests/conv_i16_i12_utest.c | 25 +++++------- src/lib/xdsp/utests/fft_window_cf32_utest.c | 45 ++++++--------------- src/lib/xdsp/utests/wvlt_sincos_i16_utest.c | 40 +++++++++--------- src/lib/xdsp/utests/xdsp_utest_common.h | 32 +++++++++++++++ src/lib/xdsp/utests/xfft_fftad_utest.c | 30 +++++++------- src/lib/xdsp/utests/xfft_rtsa_utest.c | 38 ++++++++--------- 27 files changed, 397 insertions(+), 482 deletions(-) diff --git a/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c b/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c index 5549cbc7..03b8751c 100644 --- a/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_2cf32_ci12_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define PACKET_SIZE (8192u) #define OUT_BZ (PACKET_SIZE * sizeof(float) * 3 / 8) @@ -34,10 +34,12 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); - posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -175,7 +177,9 @@ START_TEST(conv_2cf32_ci12_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out_etalon, out, bzout); while(opt != OPT_GENERIC) @@ -233,18 +237,12 @@ END_TEST Suite * conv_2cf32_ci12_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_2cf32_ci12"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_2cf32_ci12_check_simd); - tcase_add_loop_test(tc_core, conv_2cf32_ci12_speed, 0, 3); + Suite* s = suite_create("conv_2cf32_ci12"); + + ADD_REGRESS_TEST(s, conv_2cf32_ci12_check_simd); + ADD_PERF_LOOP_TEST(s, conv_2cf32_ci12_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c b/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c index 65b90ded..631acd8c 100644 --- a/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c @@ -8,7 +8,7 @@ #include #include #include "xdsp_utest_common.h" -#include "../conv_2cf32_ci16_2.h" +#include "conv_2cf32_ci16_2.h" #undef DEBUG_PRINT @@ -34,10 +34,12 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); - posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -182,18 +184,12 @@ END_TEST Suite * conv_2cf32_ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_2cf32_ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_2cf32_ci16_check_simd); - tcase_add_loop_test(tc_core, conv_2cf32_ci16_speed, 0, 3); + Suite* s = suite_create("conv_2cf32_ci16"); + + ADD_REGRESS_TEST(s, conv_2cf32_ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_2cf32_ci16_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c b/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c index ac2bc13f..a41b08bc 100644 --- a/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_2ci16_ci12_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define PACKET_SIZE (8192u) #define OUT_BZ (PACKET_SIZE * sizeof(int16_t) * 3 / 4) @@ -31,10 +31,12 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 2); - posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 2); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 2); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 2); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -122,7 +124,9 @@ START_TEST(conv_2ci16_ci12_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out_etalon, out, bzout); while(opt != OPT_GENERIC) @@ -179,18 +183,12 @@ END_TEST Suite * conv_2ci16_ci12_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_2ci16_ci12"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_2ci16_ci12_check_simd); - tcase_add_loop_test(tc_core, conv_2ci16_ci12_speed, 0, 3); + Suite* s = suite_create("conv_2ci16_ci12"); + + ADD_REGRESS_TEST(s, conv_2ci16_ci12_check_simd); + ADD_PERF_LOOP_TEST(s, conv_2ci16_ci12_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c b/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c index aca7ce24..9e1afca6 100644 --- a/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c @@ -8,7 +8,7 @@ #include #include #include "xdsp_utest_common.h" -#include "../conv_2ci16_ci16_2.h" +#include "conv_2ci16_ci16_2.h" #undef DEBUG_PRINT @@ -31,10 +31,12 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, OUT_BZ / 2); - posix_memalign((void**)&in_1, ALIGN_BYTES, OUT_BZ / 2); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, OUT_BZ / 2); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, OUT_BZ / 2); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -160,18 +162,12 @@ END_TEST Suite * conv_2ci16_ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_2ci16_ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_2ci16_ci16_check_simd); - tcase_add_loop_test(tc_core, conv_2ci16_ci16_speed, 0, 3); + Suite* s = suite_create("conv_2ci16_ci16"); + + ADD_REGRESS_TEST(s, conv_2ci16_ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_2ci16_ci16_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c index 1d9085fc..996ab03b 100644 --- a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_4cf32_ci12_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define PACKET_SIZE (8192u) #define OUT_BZ (PACKET_SIZE * sizeof(float) * 3 / 8) @@ -36,12 +36,14 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 2); - posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 4); - posix_memalign((void**)&in_2, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 4); - posix_memalign((void**)&in_3, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 4); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&in_2, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&in_3, ALIGN_BYTES, PACKET_SIZE * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -185,7 +187,9 @@ START_TEST(conv_4cf32_ci12_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out_etalon, out, bzout); while(opt != OPT_GENERIC) @@ -197,8 +201,7 @@ START_TEST(conv_4cf32_ci12_check_simd) (*fn)(pin, bzin, &pout, bzout); #ifdef DEBUG_PRINT printer(NULL); -#endif \ - //int res = memcmp(out, out_etalon, bzout); +#endif int res = is_equal(); res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); ck_assert_int_eq( res, 0 ); @@ -243,18 +246,12 @@ END_TEST Suite * conv_4cf32_ci12_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_4cf32_ci12"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_4cf32_ci12_check_simd); - tcase_add_loop_test(tc_core, conv_4cf32_ci12_speed, 0, 3); + Suite* s = suite_create("conv_4cf32_ci12"); + + ADD_REGRESS_TEST(s, conv_4cf32_ci12_check_simd); + ADD_PERF_LOOP_TEST(s, conv_4cf32_ci12_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c b/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c index a8358eda..98c7cff7 100644 --- a/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c @@ -8,9 +8,9 @@ #include #include #include "xdsp_utest_common.h" -#include "../conv_4cf32_ci16_2.h" +#include "conv_4cf32_ci16_2.h" -#define DEBUG_PRINT +#undef DEBUG_PRINT #define WORD_COUNT (8192u) #define OUT_BZ (WORD_COUNT * sizeof(int16_t)) @@ -36,12 +36,14 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); - posix_memalign((void**)&in_1, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); - posix_memalign((void**)&in_2, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); - posix_memalign((void**)&in_3, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&in_2, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&in_3, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 4); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -214,18 +216,12 @@ END_TEST Suite * conv_4cf32_ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_4cf32_ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_4cf32_ci16_check_simd); - tcase_add_loop_test(tc_core, conv_4cf32_ci16_speed, 0, 3); + Suite* s = suite_create("conv_4cf32_ci16"); + + ADD_REGRESS_TEST(s, conv_4cf32_ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_4cf32_ci16_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c b/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c index 32fe7cc2..a019b800 100644 --- a/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_4ci16_ci12_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define PACKET_SIZE (8192u) #define OUT_BZ (PACKET_SIZE * sizeof(int16_t) * 3 / 4) @@ -33,12 +33,14 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 2); - posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); - posix_memalign((void**)&in_2, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); - posix_memalign((void**)&in_3, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 2); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); + res = res ? res : posix_memalign((void**)&in_2, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); + res = res ? res : posix_memalign((void**)&in_3, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -133,7 +135,9 @@ START_TEST(conv_4ci16_ci12_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out_etalon, out, bzout); while(opt != OPT_GENERIC) @@ -190,18 +194,12 @@ END_TEST Suite * conv_4ci16_ci12_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_4ci16_ci12"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_4ci16_ci12_check_simd); - tcase_add_loop_test(tc_core, conv_4ci16_ci12_speed, 0, 3); + Suite* s = suite_create("conv_4ci16_ci12"); + + ADD_REGRESS_TEST(s, conv_4ci16_ci12_check_simd); + ADD_PERF_LOOP_TEST(s, conv_4ci16_ci12_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c b/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c index f6778887..81cf800b 100644 --- a/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c @@ -8,7 +8,7 @@ #include #include #include "xdsp_utest_common.h" -#include "../conv_4ci16_ci16_2.h" +#include "conv_4ci16_ci16_2.h" #undef DEBUG_PRINT @@ -33,12 +33,14 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_0, ALIGN_BYTES, OUT_BZ / 4); - posix_memalign((void**)&in_1, ALIGN_BYTES, OUT_BZ / 4); - posix_memalign((void**)&in_2, ALIGN_BYTES, OUT_BZ / 4); - posix_memalign((void**)&in_3, ALIGN_BYTES, OUT_BZ / 4); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, OUT_BZ / 4); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, OUT_BZ / 4); + res = res ? res : posix_memalign((void**)&in_2, ALIGN_BYTES, OUT_BZ / 4); + res = res ? res : posix_memalign((void**)&in_3, ALIGN_BYTES, OUT_BZ / 4); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); in[0] = in_0; in[1] = in_1; @@ -132,7 +134,7 @@ START_TEST(conv_4ci16_ci16_check_simd) (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); memcpy(out_etalon, out, bzout); -#if 0 +#ifdef DEBUG_PRINT print_data("ETALON DATA"); #endif @@ -143,7 +145,7 @@ START_TEST(conv_4ci16_ci16_check_simd) { memset(out, 0, bzout); (*fn)(pin, bzin, &pout, bzout); -#if 0 +#ifdef DEBUG_PRINT print_data(NULL); #endif int res = memcmp(out, out_etalon, bzout); @@ -190,18 +192,12 @@ END_TEST Suite * conv_4ci16_ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_4ci16_ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_4ci16_ci16_check_simd); - tcase_add_loop_test(tc_core, conv_4ci16_ci16_speed, 0, 4); + Suite* s = suite_create("conv_4ci16_ci16"); + + ADD_REGRESS_TEST(s, conv_4ci16_ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_4ci16_ci16_speed, 60, 0, 4); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c b/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c index 55f1e78f..5eeadf5f 100644 --- a/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c @@ -8,16 +8,13 @@ #include #include #include "xdsp_utest_common.h" -#include "../conv_ci12_2cf32_2.h" +#include "conv_ci12_2cf32_2.h" #undef DEBUG_PRINT #define WORD_COUNT (20u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * 12u / 8u) -//#define IN_STREAM_SIZE_BZ 29u -//#define WORD_COUNT (IN_STREAM_SIZE_BZ * 8u / 12u) // 88 i12 words - #define SPEED_WORD_COUNT (8192u) #define SPEED_SIZE_BZ (SPEED_WORD_COUNT * 12u / 8u) @@ -37,11 +34,13 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -115,13 +114,6 @@ START_TEST(conv_ci12_2cf32_check) for(uint16_t i = 0; i < WORD_COUNT / 2; ++i) { fprintf(stderr, "%.6f ", out[0][i]); - -// float v = (float)(i << 4); -// v *= CONV_SCALE; -// v = (i % 4) ? v : -v; - -// fprintf(stderr, "\ni=%u\tout=%.6f\texpected=%.6f", i, out[i], v); - //ck_assert_float_eq(v, out[i]); } fprintf(stderr, "\n"); for(uint16_t i = 0; i < WORD_COUNT / 2; ++i) @@ -222,19 +214,13 @@ END_TEST Suite * conv_ci12_2cf32_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci12_2cf32"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci12_2cf32_check); - tcase_add_test(tc_core, conv_ci12_2cf32_check_simd); - tcase_add_loop_test(tc_core, conv_ci12_2cf32_speed, 0, 3); + Suite* s = suite_create("conv_ci12_2cf32"); + + ADD_REGRESS_TEST(s, conv_ci12_2cf32_check); + ADD_REGRESS_TEST(s, conv_ci12_2cf32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci12_2cf32_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c b/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c index 00ff2fd0..ec2cd16f 100644 --- a/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_ci12_2ci16_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define WORD_COUNT (20u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * 12u / 8u) @@ -34,11 +34,13 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/2); + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -130,7 +132,9 @@ START_TEST(conv_ci12_2ci16_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out1_etalon, out[0], bzout / 2); memcpy(out2_etalon, out[1], bzout / 2); @@ -189,18 +193,12 @@ END_TEST Suite * conv_ci12_2ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci12_2ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci12_2ci16_check_simd); - tcase_add_loop_test(tc_core, conv_ci12_2ci16_speed, 0, 3); + Suite* s = suite_create("conv_ci12_2ci16"); + + ADD_REGRESS_TEST(s, conv_ci12_2ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci12_2ci16_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c index 243e938f..be3b8394 100644 --- a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c @@ -10,14 +10,11 @@ #include "xdsp_utest_common.h" #include "conv_ci12_4cf32_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define WORD_COUNT (32u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * 12u / 8u) -//#define IN_STREAM_SIZE_BZ 29u -//#define WORD_COUNT (IN_STREAM_SIZE_BZ * 8u / 12u) // 88 i12 words - #define SPEED_WORD_COUNT (8192u) #define SPEED_SIZE_BZ (SPEED_WORD_COUNT * 12u / 8u) @@ -42,15 +39,17 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -224,19 +223,13 @@ END_TEST Suite * conv_ci12_4cf32_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci12_2cf32"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci12_4cf32_check); - tcase_add_test(tc_core, conv_ci12_4cf32_check_simd); - tcase_add_loop_test(tc_core, conv_ci12_4cf32_speed, 0, 3); + Suite* s = suite_create("conv_ci12_2cf32"); + + ADD_REGRESS_TEST(s, conv_ci12_4cf32_check); + ADD_REGRESS_TEST(s, conv_ci12_4cf32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci12_4cf32_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c b/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c index 5ff17a26..9273d761 100644 --- a/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c @@ -10,14 +10,11 @@ #include "xdsp_utest_common.h" #include "conv_ci12_4ci16_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define WORD_COUNT (32u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * 12u / 8u) -//#define IN_STREAM_SIZE_BZ 29u -//#define WORD_COUNT (IN_STREAM_SIZE_BZ * 8u / 12u) // 88 i12 words - #define SPEED_WORD_COUNT (8192u) #define SPEED_SIZE_BZ (SPEED_WORD_COUNT * 12u / 8u) @@ -42,15 +39,17 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/4); + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -148,7 +147,9 @@ START_TEST(conv_ci12_4ci16_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out1_etalon, out[0], bzout / 4); memcpy(out2_etalon, out[1], bzout / 4); memcpy(out3_etalon, out[2], bzout / 4); @@ -212,18 +213,12 @@ END_TEST Suite * conv_ci12_4ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci12_4ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci12_4ci16_check_simd); - tcase_add_loop_test(tc_core, conv_ci12_4ci16_speed, 0, 3); + Suite* s = suite_create("conv_ci12_4ci16"); + + ADD_REGRESS_TEST(s, conv_ci12_4ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci12_4ci16_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c index 22fbbab4..889cde91 100644 --- a/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_ci16_2cf32_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define WORD_COUNT (4096u + 77u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) @@ -34,11 +34,13 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/2); + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -113,7 +115,9 @@ START_TEST(conv_ci16_2cf32_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out1_etalon, out[0], bzout / 2); memcpy(out2_etalon, out[1], bzout / 2); @@ -172,18 +176,12 @@ END_TEST Suite * conv_ci16_2cf32_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci16_2cf32"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci16_2cf32_check_simd); - tcase_add_loop_test(tc_core, conv_ci16_2cf32_speed, 0, 3); + Suite* s = suite_create("conv_ci16_2cf32"); + + ADD_REGRESS_TEST(s, conv_ci16_2cf32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_2cf32_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c index 181fa8e7..25313122 100644 --- a/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c @@ -8,7 +8,7 @@ #include #include #include "xdsp_utest_common.h" -#include "../conv_ci16_2ci16_2.h" +#include "conv_ci16_2ci16_2.h" #undef DEBUG_PRINT @@ -34,11 +34,13 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1, ALIGN_BYTES, SPEED_SIZE_BZ/2); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, SPEED_SIZE_BZ/2); - posix_memalign((void**)&out2, ALIGN_BYTES, SPEED_SIZE_BZ/2); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, SPEED_SIZE_BZ/2); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, SPEED_SIZE_BZ/2); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, SPEED_SIZE_BZ/2); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, SPEED_SIZE_BZ/2); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, SPEED_SIZE_BZ/2); + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -173,18 +175,12 @@ END_TEST Suite * conv_ci16_2ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci16_2ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci16_2ci16_check_simd); - tcase_add_loop_test(tc_core, conv_ci16_2ci16_speed, 0, 3); + Suite* s = suite_create("conv_ci16_2ci16"); + + ADD_REGRESS_TEST(s, conv_ci16_2ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_2ci16_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c index 19fa718b..e892076b 100644 --- a/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c @@ -10,9 +10,9 @@ #include "xdsp_utest_common.h" #include "conv_ci16_4cf32_2.h" -#define DEBUG_PRINT +#undef DEBUG_PRINT -#define WORD_COUNT (4096u + 77u) +#define WORD_COUNT (4096u + 80u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) #define SPEED_WORD_COUNT (32768u) @@ -38,15 +38,17 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); - posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/4); + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -195,18 +197,12 @@ END_TEST Suite * conv_ci16_4cf32_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci16_4cf32"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci16_4cf32_check_simd); - tcase_add_loop_test(tc_core, conv_ci16_4cf32_speed, 0, 3); + Suite* s = suite_create("conv_ci16_4cf32"); + + ADD_REGRESS_TEST(s, conv_ci16_4cf32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_4cf32_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c index 265dd560..0a086305 100644 --- a/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c @@ -10,9 +10,9 @@ #include "xdsp_utest_common.h" #include "conv_ci16_4ci16_2.h" -#define DEBUG_PRINT +#undef DEBUG_PRINT -#define CHECK_WORD_COUNT (4096u + 77u) +#define CHECK_WORD_COUNT (4096u + 80u) //must be a multiple of 4 #define CHECK_SIZE_BZ (CHECK_WORD_COUNT * sizeof(int16_t)) #define SPEED_WORD_COUNT (65536u) @@ -38,17 +38,21 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + int res = 0; - posix_memalign((void**)&out1, ALIGN_BYTES, SPEED_SIZE_BZ/4); - posix_memalign((void**)&out2, ALIGN_BYTES, SPEED_SIZE_BZ/4); - posix_memalign((void**)&out3, ALIGN_BYTES, SPEED_SIZE_BZ/4); - posix_memalign((void**)&out4, ALIGN_BYTES, SPEED_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out1_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); - posix_memalign((void**)&out2_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); - posix_memalign((void**)&out3_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); - posix_memalign((void**)&out4_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, SPEED_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, SPEED_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, SPEED_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, SPEED_SIZE_BZ/4); + + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/4); + + ck_assert_int_eq(res, 0); out[0] = out1; out[1] = out2; @@ -61,7 +65,6 @@ static void setup() for(unsigned i = 0; i < SPEED_WORD_COUNT; ++i) { int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; - //in[i] = sign * 32767 * ((float)(rand()) / (float)RAND_MAX); in[i] = sign * i; } } @@ -133,8 +136,9 @@ START_TEST(conv_ci16_4ci16_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT print_data("ETALON"); - +#endif memcpy(out1_etalon, out[0], bzout / 4); memcpy(out2_etalon, out[1], bzout / 4); memcpy(out3_etalon, out[2], bzout / 4); @@ -198,18 +202,12 @@ END_TEST Suite * conv_ci16_4ci16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_ci16_4ci16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_ci16_4ci16_check_simd); - tcase_add_loop_test(tc_core, conv_ci16_4ci16_speed, 0, 4); + Suite* s = suite_create("conv_ci16_4ci16"); + + ADD_REGRESS_TEST(s, conv_ci16_4ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_4ci16_speed, 60, 0, 4); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_f32_i12_utest.c b/src/lib/xdsp/utests/conv_f32_i12_utest.c index b4f009e7..60789696 100644 --- a/src/lib/xdsp/utests/conv_f32_i12_utest.c +++ b/src/lib/xdsp/utests/conv_f32_i12_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_f32_i12_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define PACKET_SIZE (8192u) #define OUT_BZ (PACKET_SIZE * sizeof(float) * 3 / 8) @@ -31,9 +31,11 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, PACKET_SIZE * sizeof(float)); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, PACKET_SIZE * sizeof(float)); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); //fill srand( time(0) ); @@ -159,7 +161,9 @@ START_TEST(conv_f32_i12_check_simd) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(&pin, bzin, &pout, bzout); +#ifdef DEBUG_PRINT printer("HEADER:"); +#endif memcpy(out_etalon, out, bzout); while(opt != OPT_GENERIC) @@ -173,7 +177,6 @@ START_TEST(conv_f32_i12_check_simd) printer(NULL); #endif int res = is_equal(); - //int res = memcmp(out, out_etalon, bzout); res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); ck_assert_int_eq( res, 0 ); } @@ -217,18 +220,12 @@ END_TEST Suite * conv_f32_i12_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_f32_i12"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_f32_i12_check_simd); - tcase_add_loop_test(tc_core, conv_f32_i12_speed, 0, 3); + Suite* s = suite_create("conv_f32_i12"); + + ADD_REGRESS_TEST(s, conv_f32_i12_check_simd); + ADD_PERF_LOOP_TEST(s, conv_f32_i12_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_f32_i16_utest.c b/src/lib/xdsp/utests/conv_f32_i16_utest.c index 9127f983..2fe28921 100644 --- a/src/lib/xdsp/utests/conv_f32_i16_utest.c +++ b/src/lib/xdsp/utests/conv_f32_i16_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_f32_i16_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define STREAM_SIZE (8192 + 16 + 8 + 7) #define STREAM_SIZE_CHECK STREAM_SIZE @@ -32,9 +32,11 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, sizeof(float) * STREAM_SIZE_SPEED); - posix_memalign((void**)&out, ALIGN_BYTES, sizeof(int16_t) * STREAM_SIZE_SPEED); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(int16_t) * STREAM_SIZE_SPEED); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, sizeof(float) * STREAM_SIZE_SPEED); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(int16_t) * STREAM_SIZE_SPEED); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(int16_t) * STREAM_SIZE_SPEED); + ck_assert_int_eq(res, 0); srand( time(0) ); @@ -113,7 +115,9 @@ START_TEST(conv_f32_i16_check) //get etalon output data (generic foo) (*get_fn(OPT_GENERIC, 0))(&pin, bzin, &pout, bzout); +#ifdef DEBUG_PRINT printer("ETALON:"); +#endif memcpy(out_etalon, out, bzout); while(opt != OPT_GENERIC) @@ -176,17 +180,12 @@ END_TEST Suite * conv_f32_i16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_f32_i16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_f32_i16_check); - tcase_add_loop_test(tc_core, conv_f32_i16_speed, 0, 3); - suite_add_tcase(s, tc_core); + Suite* s = suite_create("conv_f32_i16"); + + ADD_REGRESS_TEST(s, conv_f32_i16_check); + ADD_PERF_LOOP_TEST(s, conv_f32_i16_speed, 60, 0, 3); + return s; } diff --git a/src/lib/xdsp/utests/conv_i12_f32_utest.c b/src/lib/xdsp/utests/conv_i12_f32_utest.c index 77a33b5b..bc52b8a9 100644 --- a/src/lib/xdsp/utests/conv_i12_f32_utest.c +++ b/src/lib/xdsp/utests/conv_i12_f32_utest.c @@ -8,9 +8,9 @@ #include #include #include "xdsp_utest_common.h" -#include "../conv_i12_f32_2.h" +#include "conv_i12_f32_2.h" -#define DEBUG_PRINT +#undef DEBUG_PRINT #define IN_STREAM_SIZE_BZ (132u) // (6 + 3 + 2)*12 = 132 bytes #define WORD_COUNT (IN_STREAM_SIZE_BZ * 8u / 12u) // 88 i12 words @@ -31,9 +31,11 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT); + ck_assert_int_eq(res, 0); //fill @@ -104,9 +106,10 @@ START_TEST(conv_i12_f32_check) v *= CONV_SCALE; v = (i % 4) ? v : -v; - int16_t i12 = (int16_t)(out[i] / CONV_SCALE) >> 4; - +#ifdef DEBUG_PRINT + int16_t i12 = (int16_t)(out[i] / CONV_SCALE) >> 4; fprintf(stderr, "\ni=%u\ti12=%d\tout=%.6f\texpected=%.6f", i, i12, out[i], v); +#endif #ifdef ck_assert_float_eq ck_assert_float_eq(v, out[i]); #else @@ -200,19 +203,13 @@ END_TEST Suite * conv_i12_f32_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_i12_f32"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_i12_f32_check); - tcase_add_test(tc_core, conv_i12_f32_check_simd); - tcase_add_loop_test(tc_core, conv_i12_f32_speed, 0, 3); + Suite* s = suite_create("conv_i12_f32"); + + ADD_REGRESS_TEST(s, conv_i12_f32_check); + ADD_REGRESS_TEST(s, conv_i12_f32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_i12_f32_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_i12_i16_utest.c b/src/lib/xdsp/utests/conv_i12_i16_utest.c index f87a154d..0a1c402a 100644 --- a/src/lib/xdsp/utests/conv_i12_i16_utest.c +++ b/src/lib/xdsp/utests/conv_i12_i16_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_i12_i16_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define IN_STREAM_SIZE_BZ (132u) // (6 + 3 + 2)*12 = 132 bytes #define WORD_COUNT (IN_STREAM_SIZE_BZ * 8u / 12u) // 88 i12 words @@ -31,9 +31,11 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&out, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT); + ck_assert_int_eq(res, 0); //fill @@ -194,19 +196,13 @@ END_TEST Suite * conv_i12_i16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_i12_i16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_i12_i16_check); - tcase_add_test(tc_core, conv_i12_i16_check_simd); - tcase_add_loop_test(tc_core, conv_i12_i16_speed, 0, 3); + Suite* s = suite_create("conv_i12_i16"); + + ADD_REGRESS_TEST(s, conv_i12_i16_check); + ADD_REGRESS_TEST(s, conv_i12_i16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_i12_i16_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/conv_i16_f32_utest.c b/src/lib/xdsp/utests/conv_i16_f32_utest.c index 6c54685b..f7ddcdd5 100644 --- a/src/lib/xdsp/utests/conv_i16_f32_utest.c +++ b/src/lib/xdsp/utests/conv_i16_f32_utest.c @@ -29,9 +29,11 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, sizeof(int16_t) * STREAM_SIZE_SPEED); - posix_memalign((void**)&out, ALIGN_BYTES, sizeof(float) * STREAM_SIZE_SPEED); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(float) * STREAM_SIZE_SPEED); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, sizeof(int16_t) * STREAM_SIZE_SPEED); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(float) * STREAM_SIZE_SPEED); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(float) * STREAM_SIZE_SPEED); + ck_assert_int_eq(res, 0); srand( time(0) ); @@ -139,17 +141,12 @@ END_TEST Suite * conv_i16_f32_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_i16_f32"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_i16_f32_check); - tcase_add_loop_test(tc_core, conv_i16_f32_speed, 0, 3); - suite_add_tcase(s, tc_core); + Suite* s = suite_create("conv_i16_f32"); + + ADD_REGRESS_TEST(s, conv_i16_f32_check); + ADD_PERF_LOOP_TEST(s, conv_i16_f32_speed, 60, 0, 3); + return s; } diff --git a/src/lib/xdsp/utests/conv_i16_i12_utest.c b/src/lib/xdsp/utests/conv_i16_i12_utest.c index bf103bbe..c35f4f0a 100644 --- a/src/lib/xdsp/utests/conv_i16_i12_utest.c +++ b/src/lib/xdsp/utests/conv_i16_i12_utest.c @@ -10,12 +10,11 @@ #include "xdsp_utest_common.h" #include "conv_i16_i12_2.h" -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define PACKET_SIZE (8192u) #define OUT_BZ (PACKET_SIZE * sizeof(int16_t) * 3 / 4) - static const unsigned packet_lens[3] = { 1111u, 4123u, PACKET_SIZE }; #define SPEED_MEASURE_ITERS 1000000 @@ -29,9 +28,11 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t)); - posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t)); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); //fill for(int i = 0; i < PACKET_SIZE; ++i) @@ -158,18 +159,12 @@ END_TEST Suite * conv_i16_i12_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("conv_i16_i12"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, conv_i16_i12_check_simd); - tcase_add_loop_test(tc_core, conv_i16_i12_speed, 0, 3); + Suite* s = suite_create("conv_i16_i12"); + + ADD_REGRESS_TEST(s, conv_i16_i12_check_simd); + ADD_PERF_LOOP_TEST(s, conv_i16_i12_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/fft_window_cf32_utest.c b/src/lib/xdsp/utests/fft_window_cf32_utest.c index 3c137c66..2125c9ad 100644 --- a/src/lib/xdsp/utests/fft_window_cf32_utest.c +++ b/src/lib/xdsp/utests/fft_window_cf32_utest.c @@ -6,7 +6,7 @@ #include #include #include "xdsp_utest_common.h" -#include "../fft_window_functions.h" +#include "fft_window_functions.h" #define FFT_SIZE (65536) static const unsigned packet_lens[3] = { 256, 4096, FFT_SIZE }; @@ -30,31 +30,15 @@ static void recalcWnd(unsigned fft_size) wnd[i+1] = (1 - cos(2 * M_PI * (i + 1) / fft_size)) / 2; } } -#if 0 -static void recalcWnd(unsigned fft_size) -{ - float wc = 0.f; - for(unsigned i = 0; i < fft_size; ++i) - { - //Hann - wnd[i] = (1 - cos(2 * M_PI * i / fft_size)) / 2; - wc += wnd[i] * wnd[i]; - } - - float corr = 1.0f / sqrt(wc / fft_size); - for(unsigned i = 0; i < fft_size; ++i) - { - wnd[i] *= corr; - } -} -#endif static void setup() { - posix_memalign((void**)&in, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); - posix_memalign((void**)&out, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); - posix_memalign((void**)&wnd, ALIGN_BYTES, sizeof(float) * 2 * FFT_SIZE); + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); + res = res ? res : posix_memalign((void**)&wnd, ALIGN_BYTES, sizeof(float) * 2 * FFT_SIZE); + ck_assert_int_eq(res, 0); for(unsigned i = 0; i < FFT_SIZE; ++i) { @@ -165,17 +149,12 @@ END_TEST Suite * fft_window_cf32_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("fft_window_cf32_functions"); - tc_core = tcase_create("XFFT"); - tcase_set_timeout(tc_core, 300); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, wnd_check); - tcase_add_loop_test(tc_core, wnd_speed, 0, 3); - suite_add_tcase(s, tc_core); + Suite* s = suite_create("fft_window_cf32_functions"); + + ADD_REGRESS_TEST(s, wnd_check); + ADD_PERF_LOOP_TEST(s, wnd_speed, 300, 0, 3); + return s; } diff --git a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c index d962e9a9..678d76c7 100644 --- a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c +++ b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c @@ -11,7 +11,7 @@ #include "sincos_functions.h" #include -//#define DEBUG_PRINT +#undef DEBUG_PRINT #define WORD_COUNT (65536) #define STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) @@ -43,15 +43,17 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { - posix_memalign((void**)&in_check, ALIGN_BYTES, STREAM_SIZE_BZ); - posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&sindata, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&sindata_etalon, ALIGN_BYTES, STREAM_SIZE_BZ); - posix_memalign((void**)&cosdata, ALIGN_BYTES, SPEED_SIZE_BZ); - posix_memalign((void**)&cosdata_etalon, ALIGN_BYTES, STREAM_SIZE_BZ); - - posix_memalign((void**)&sincosdata, ALIGN_BYTES, SPEED_WORD_COUNT * 2 * sizeof(int16_t)); - posix_memalign((void**)&sincosdata_etalon, ALIGN_BYTES, WORD_COUNT * 2 * sizeof(int16_t)); + int res = 0; + res = res ? res : posix_memalign((void**)&in_check, ALIGN_BYTES, STREAM_SIZE_BZ); + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&sindata, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&sindata_etalon, ALIGN_BYTES, STREAM_SIZE_BZ); + res = res ? res : posix_memalign((void**)&cosdata, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&cosdata_etalon, ALIGN_BYTES, STREAM_SIZE_BZ); + + res = res ? res : posix_memalign((void**)&sincosdata, ALIGN_BYTES, SPEED_WORD_COUNT * 2 * sizeof(int16_t)); + res = res ? res : posix_memalign((void**)&sincosdata_etalon, ALIGN_BYTES, WORD_COUNT * 2 * sizeof(int16_t)); + ck_assert_int_eq(res, 0); srand( time(0) ); @@ -341,20 +343,14 @@ END_TEST Suite * wvlt_sincos_i16_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("wvlt_sincos_i16"); - tc_core = tcase_create("XDSP"); - tcase_set_timeout(tc_core, 60); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, wvlt_sincos_i16_check_simd); - tcase_add_loop_test(tc_core, wvlt_sincos_i16_speed, 0, 3); - tcase_add_test(tc_core, wvlt_sincos_i16_interleaved_ctrl_check_simd); - tcase_add_loop_test(tc_core, wvlt_sincos_i16_interleaved_ctrl_speed, 0, 3); + Suite* s = suite_create("wvlt_sincos_i16"); + + ADD_REGRESS_TEST(s, wvlt_sincos_i16_check_simd); + ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_speed, 60, 0, 3); + ADD_REGRESS_TEST(s, wvlt_sincos_i16_interleaved_ctrl_check_simd); + ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_interleaved_ctrl_speed, 60, 0, 3); - suite_add_tcase(s, tc_core); return s; } diff --git a/src/lib/xdsp/utests/xdsp_utest_common.h b/src/lib/xdsp/utests/xdsp_utest_common.h index cad9e06e..3ca9f84c 100644 --- a/src/lib/xdsp/utests/xdsp_utest_common.h +++ b/src/lib/xdsp/utests/xdsp_utest_common.h @@ -7,7 +7,39 @@ #include #include #include "../../cal/opt_func.h" +#include "conv.h" #define ALIGN_BYTES (size_t)64 +#define ADD_REGRESS_TEST(suitename, testname) \ +{ \ + TCase* tc_regress = tcase_create("REGRESS"); \ + tcase_set_tags(tc_regress, "REGRESS"); \ + tcase_add_unchecked_fixture(tc_regress, setup, teardown); \ + tcase_add_test(tc_regress, testname); \ + suite_add_tcase(suitename, tc_regress); \ +} + +#define ADD_PERF_LOOP_TEST(suitename, testname, timeout, from, to) \ +{ \ + TCase* tc_perf = tcase_create("PERFORMANCE"); \ + tcase_set_tags(tc_perf, "PERFORMANCE"); \ + tcase_add_unchecked_fixture(tc_perf, setup, teardown); \ + tcase_set_timeout(tc_perf, timeout); \ + tcase_add_loop_test(tc_perf, testname, from, to); \ + suite_add_tcase(suitename, tc_perf); \ +} + +#define ADD_PERF_TEST(suitename, testname, timeout) \ +{ \ + TCase* tc_perf = tcase_create("PERFORMANCE"); \ + tcase_set_tags(tc_perf, "PERFORMANCE"); \ + tcase_add_unchecked_fixture(tc_perf, setup, teardown); \ + tcase_set_timeout(tc_perf, timeout); \ + tcase_add_test(tc_perf, testname); \ + suite_add_tcase(suitename, tc_perf); \ +} + +typedef conv_function_t (*conv_wrapper_fn_t)(generic_opts_t cpu_cap, const char** sfunc); + #endif // XDSP_UTEST_COMMON_H diff --git a/src/lib/xdsp/utests/xfft_fftad_utest.c b/src/lib/xdsp/utests/xfft_fftad_utest.c index 502893df..c675e4bc 100644 --- a/src/lib/xdsp/utests/xfft_fftad_utest.c +++ b/src/lib/xdsp/utests/xfft_fftad_utest.c @@ -9,7 +9,7 @@ #include #include #include "xdsp_utest_common.h" -#include "../fftad_functions.h" +#include "fftad_functions.h" #undef DEBUG_PRINT @@ -35,11 +35,14 @@ static void setup(void) { srand( time(0) ); - posix_memalign((void**)&in, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * STREAM_SIZE); - posix_memalign((void**)&f_mant, ALIGN_BYTES, sizeof(float) * STREAM_SIZE); - posix_memalign((void**)&f_pwr, ALIGN_BYTES, sizeof(int32_t) * STREAM_SIZE); - posix_memalign((void**)&out, ALIGN_BYTES, sizeof(float) * STREAM_SIZE); - posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(float) * STREAM_SIZE); + int res = 0; + + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * STREAM_SIZE); + res = res ? res : posix_memalign((void**)&f_mant, ALIGN_BYTES, sizeof(float) * STREAM_SIZE); + res = res ? res : posix_memalign((void**)&f_pwr, ALIGN_BYTES, sizeof(int32_t) * STREAM_SIZE); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(float) * STREAM_SIZE); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(float) * STREAM_SIZE); + ck_assert_int_eq(res, 0); //init input data for(unsigned i = 0; i < STREAM_SIZE; ++i) @@ -198,17 +201,12 @@ END_TEST Suite * fftad_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("xfft_ftad_functions"); - tc_core = tcase_create("XFFT"); - tcase_set_timeout(tc_core, 300); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, fftad_check); - tcase_add_loop_test(tc_core, fftad_speed, 0, 3); - suite_add_tcase(s, tc_core); + Suite* s = suite_create("xfft_ftad_functions"); + + ADD_REGRESS_TEST(s, fftad_check); + ADD_PERF_LOOP_TEST(s, fftad_speed, 300, 0, 3); + return s; } diff --git a/src/lib/xdsp/utests/xfft_rtsa_utest.c b/src/lib/xdsp/utests/xfft_rtsa_utest.c index e892c1f6..1bb67831 100644 --- a/src/lib/xdsp/utests/xfft_rtsa_utest.c +++ b/src/lib/xdsp/utests/xfft_rtsa_utest.c @@ -8,7 +8,7 @@ #include #include #include "xdsp_utest_common.h" -#include "../rtsa_functions.h" +#include "rtsa_functions.h" #undef DEBUG_PRINT @@ -27,7 +27,8 @@ static const unsigned packet_lens[4] = { 512, 1024, 2048, STREAM_SIZE }; #define SPEED_MEASURE_ITERS 256 -#define EPSILON MAX_RTSA_PWR / 10 +#define EPSILON MAX_RTSA_PWR / 10000 +#define MAX_ERRS 10 static const char* last_fn_name = NULL; static generic_opts_t max_opt = OPT_GENERIC; @@ -52,7 +53,7 @@ static void setup(void) int res = 0; res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * STREAM_SIZE * AVGS); res = res ? res : posix_memalign((void**)&in16, ALIGN_BYTES, sizeof(uint16_t) * STREAM_SIZE * AVGS); - assert(res == 0); + ck_assert_int_eq(res, 0); //init input data srand( time(0) ); @@ -88,7 +89,7 @@ static void setup(void) res = 0; res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(rtsa_pwr_t) * STREAM_SIZE * st->rtsa_depth); res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(rtsa_pwr_t) * STREAM_SIZE * st->rtsa_depth); - assert(res == 0); + ck_assert_int_eq(res, 0); memset(out , 0, sizeof(rtsa_pwr_t) * STREAM_SIZE * st->rtsa_depth); memset(out_etalon, 0, sizeof(rtsa_pwr_t) * STREAM_SIZE * st->rtsa_depth); @@ -107,9 +108,13 @@ static void teardown(void) static int32_t is_equal() { + int errs = 0; + for(unsigned i = 0; i < STREAM_SIZE * rtsa_settings.rtsa_depth; i++) { - if(abs(out[i] - out_etalon[i]) > EPSILON) return i; + errs += (abs(out[i] - out_etalon[i]) > EPSILON); + if(errs > MAX_ERRS) + return i; } return -1; } @@ -168,8 +173,6 @@ START_TEST(rtsa_check) fprintf(stderr, "%sTEST > i:%u in=(%.6f,%.6f) out=%u <---> out_etalon=%u\n", j == res ? ">>>>>>>>> " : "", j, in[j][0], in[j][1], out[j], out_etalon[j]); - - exit(1); } #endif ck_assert_int_eq( res, -1 ); @@ -305,24 +308,15 @@ START_TEST(rtsa_speed_u16) END_TEST - - Suite * rtsa_suite(void) { - Suite *s; - TCase *tc_core; - max_opt = cpu_vcap_get(); - s = suite_create("xfft_rtsa_functions"); - tc_core = tcase_create("XFFT"); - tcase_set_timeout(tc_core, 300); - tcase_add_unchecked_fixture(tc_core, setup, teardown); - tcase_add_test(tc_core, rtsa_check); - //tcase_add_loop_test(tc_core, rtsa_speed, 0, 4); - tcase_add_loop_test(tc_core, rtsa_speed_u16, 0, 4); - suite_add_tcase(s, tc_core); - return s; -} + Suite* s = suite_create("xfft_rtsa_functions"); + ADD_REGRESS_TEST(s, rtsa_check); + //ADD_PERF_LOOP_TEST(s, rtsa_speed, 300, 0, 4); + ADD_PERF_LOOP_TEST(s, rtsa_speed_u16, 300, 0, 4); + return s; +} From 61ff3d2cfa4f5ff80852f36983c196d781546fa0 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 5 Jun 2025 15:02:32 +0300 Subject: [PATCH 158/397] xdsp test refactoring & cleaning --- src/lib/xdsp/utests/README | 23 +++++++++++++++++++++ src/lib/xdsp/utests/conv_2cf32_ci12_utest.c | 13 +----------- src/lib/xdsp/utests/conv_2cf32_ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_2ci16_ci12_utest.c | 13 +----------- src/lib/xdsp/utests/conv_2ci16_ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_4cf32_ci12_utest.c | 13 +----------- src/lib/xdsp/utests/conv_4cf32_ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_4ci16_ci12_utest.c | 13 +----------- src/lib/xdsp/utests/conv_4ci16_ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci12_2cf32_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci12_2ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci12_4cf32_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci12_4ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci16_2cf32_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci16_2ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci16_4cf32_utest.c | 13 +----------- src/lib/xdsp/utests/conv_ci16_4ci16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_f32_i12_utest.c | 13 +----------- src/lib/xdsp/utests/conv_f32_i16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_i12_f32_utest.c | 13 +----------- src/lib/xdsp/utests/conv_i12_i16_utest.c | 13 +----------- src/lib/xdsp/utests/conv_i16_f32_utest.c | 13 +----------- src/lib/xdsp/utests/conv_i16_i12_utest.c | 13 +----------- src/lib/xdsp/utests/wvlt_sincos_i16_utest.c | 13 +----------- src/lib/xdsp/utests/xdsp_utest_common.h | 20 ++++++++++++++++++ 25 files changed, 66 insertions(+), 276 deletions(-) create mode 100644 src/lib/xdsp/utests/README diff --git a/src/lib/xdsp/utests/README b/src/lib/xdsp/utests/README new file mode 100644 index 00000000..75b67bc7 --- /dev/null +++ b/src/lib/xdsp/utests/README @@ -0,0 +1,23 @@ +==XDSP conversion functions unit tests suite.== + +You can restrict the test subset specifying special tags. +Regression tests are tagged as REGRESS. +Performance tests are tagged as PERFORMANCE. +You can select tags by setting environment variables CK_INCLUDE_TAGS and CK_EXCLUDE_TAGS. + +For example: + +Run all tests: +./xdsp_utest_suite +or +CK_INCLUDE_TAGS="REGRESS PERFORMANCE" ./xdsp_utest_suite + +Run only regression tests: +CK_INCLUDE_TAGS=REGRESS ./xdsp_utest_suite +or +CK_EXCLUDE_TAGS=PERFORMANCE ./xdsp_utest_suite + +Run only performance tests: +CK_INCLUDE_TAGS=PERFORMANCE ./xdsp_utest_suite +or +CK_EXCLUDE_TAGS=REGRESS ./xdsp_utest_suite diff --git a/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c b/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c index 03b8751c..16594123 100644 --- a/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c @@ -69,18 +69,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_2cf32_ci12_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_2cf32_ci12_c, &last_fn_name); } static int is_equal() diff --git a/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c b/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c index 631acd8c..42332c8b 100644 --- a/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_2cf32_ci16_utest.c @@ -67,18 +67,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_2cf32_ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_2cf32_ci16_c, &last_fn_name); } static int is_equal() diff --git a/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c b/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c index a41b08bc..b338195a 100644 --- a/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c @@ -66,18 +66,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_2ci16_ci12_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_2ci16_ci12_c, &last_fn_name); } static void printer(const char* header) diff --git a/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c b/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c index 9e1afca6..9eb478d6 100644 --- a/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_2ci16_ci16_utest.c @@ -65,18 +65,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_2ci16_ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_2ci16_ci16_c, &last_fn_name); } diff --git a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c index 996ab03b..345298ba 100644 --- a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c @@ -79,18 +79,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_4cf32_ci12_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_4cf32_ci12_c, &last_fn_name); } static int is_equal() diff --git a/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c b/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c index 98c7cff7..9de597d8 100644 --- a/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_4cf32_ci16_utest.c @@ -83,18 +83,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_4cf32_ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_4cf32_ci16_c, &last_fn_name); } static int is_equal() diff --git a/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c b/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c index a019b800..821a9504 100644 --- a/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c @@ -76,18 +76,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_4ci16_ci12_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_4ci16_ci12_c, &last_fn_name); } diff --git a/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c b/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c index 81cf800b..fabd79ab 100644 --- a/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c +++ b/src/lib/xdsp/utests/conv_4ci16_ci16_utest.c @@ -81,18 +81,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_4ci16_ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_4ci16_ci16_c, &last_fn_name); } static void print_data(const char* header) diff --git a/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c b/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c index 5eeadf5f..d75e37d6 100644 --- a/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c @@ -80,18 +80,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci12_2cf32_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci12_2cf32_c, &last_fn_name); } #define CONV_SCALE (1.0f/32767) diff --git a/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c b/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c index ec2cd16f..b7862819 100644 --- a/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c @@ -74,18 +74,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci12_2ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci12_2ci16_c, &last_fn_name); } static void printer(const char* header) diff --git a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c index be3b8394..3cbb02cb 100644 --- a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c @@ -95,18 +95,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci12_4cf32_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci12_4cf32_c, &last_fn_name); } #define CONV_SCALE (1.0f/32767) diff --git a/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c b/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c index 9273d761..1ace2bb4 100644 --- a/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c @@ -89,18 +89,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci12_4ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci12_4ci16_c, &last_fn_name); } static void printer(const char* header) diff --git a/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c index 889cde91..20e53647 100644 --- a/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_2cf32_utest.c @@ -70,18 +70,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci16_2cf32_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci16_2cf32_c, &last_fn_name); } #define CONV_SCALE (1.0f/32767) diff --git a/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c index 25313122..a532489a 100644 --- a/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_2ci16_utest.c @@ -70,18 +70,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci16_2ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci16_2ci16_c, &last_fn_name); } #define CONV_SCALE (1.0f/32767) diff --git a/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c index e892076b..3d9a264f 100644 --- a/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c @@ -87,18 +87,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci16_4cf32_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci16_4cf32_c, &last_fn_name); } #define CONV_SCALE (1.0f/32767) diff --git a/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c index 0a086305..0901e8d8 100644 --- a/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_4ci16_utest.c @@ -84,18 +84,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_ci16_4ci16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_ci16_4ci16_c, &last_fn_name); } diff --git a/src/lib/xdsp/utests/conv_f32_i12_utest.c b/src/lib/xdsp/utests/conv_f32_i12_utest.c index 60789696..98b6f0d1 100644 --- a/src/lib/xdsp/utests/conv_f32_i12_utest.c +++ b/src/lib/xdsp/utests/conv_f32_i12_utest.c @@ -56,18 +56,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_f32_i12_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_f32_i12_c, &last_fn_name); } static int is_equal() diff --git a/src/lib/xdsp/utests/conv_f32_i16_utest.c b/src/lib/xdsp/utests/conv_f32_i16_utest.c index 2fe28921..072cc52b 100644 --- a/src/lib/xdsp/utests/conv_f32_i16_utest.c +++ b/src/lib/xdsp/utests/conv_f32_i16_utest.c @@ -76,18 +76,7 @@ static int is_equal() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_f32_i16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_f32_i16_c, &last_fn_name); } static void printer(const char* header) diff --git a/src/lib/xdsp/utests/conv_i12_f32_utest.c b/src/lib/xdsp/utests/conv_i12_f32_utest.c index bc52b8a9..23ca462a 100644 --- a/src/lib/xdsp/utests/conv_i12_f32_utest.c +++ b/src/lib/xdsp/utests/conv_i12_f32_utest.c @@ -70,18 +70,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_i12_f32_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_i12_f32_c, &last_fn_name); } #define CONV_SCALE (1.0f/32767) diff --git a/src/lib/xdsp/utests/conv_i12_i16_utest.c b/src/lib/xdsp/utests/conv_i12_i16_utest.c index 0a1c402a..53546797 100644 --- a/src/lib/xdsp/utests/conv_i12_i16_utest.c +++ b/src/lib/xdsp/utests/conv_i12_i16_utest.c @@ -64,18 +64,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_i12_i16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_i12_i16_c, &last_fn_name); } START_TEST(conv_i12_i16_check) diff --git a/src/lib/xdsp/utests/conv_i16_f32_utest.c b/src/lib/xdsp/utests/conv_i16_f32_utest.c index f7ddcdd5..adc9d556 100644 --- a/src/lib/xdsp/utests/conv_i16_f32_utest.c +++ b/src/lib/xdsp/utests/conv_i16_f32_utest.c @@ -53,18 +53,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_i16_f32_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_i16_f32_c, &last_fn_name); } START_TEST(conv_i16_f32_check) diff --git a/src/lib/xdsp/utests/conv_i16_i12_utest.c b/src/lib/xdsp/utests/conv_i16_i12_utest.c index c35f4f0a..0c040460 100644 --- a/src/lib/xdsp/utests/conv_i16_i12_utest.c +++ b/src/lib/xdsp/utests/conv_i16_i12_utest.c @@ -50,18 +50,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = conv_get_i16_i12_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, conv_get_i16_i12_c, &last_fn_name); } static void printer(const char* header) diff --git a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c index 678d76c7..a9c83ce4 100644 --- a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c +++ b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c @@ -101,18 +101,7 @@ static void teardown() static conv_function_t get_fn(generic_opts_t o, int log) { - const char* fn_name = NULL; - conv_function_t fn = get_wvlt_sincos_i16_c(o, &fn_name); - - //ignore dups - if(last_fn_name && !strcmp(last_fn_name, fn_name)) - return NULL; - - if(log) - fprintf(stderr, "%-20s\t", fn_name); - - last_fn_name = fn_name; - return fn; + return generic_get_fn(o, log, get_wvlt_sincos_i16_c, &last_fn_name); } static sincos_i16_interleaved_ctrl_function_t get_fn_interleaved(generic_opts_t o, int log) diff --git a/src/lib/xdsp/utests/xdsp_utest_common.h b/src/lib/xdsp/utests/xdsp_utest_common.h index 3ca9f84c..22fd488f 100644 --- a/src/lib/xdsp/utests/xdsp_utest_common.h +++ b/src/lib/xdsp/utests/xdsp_utest_common.h @@ -6,9 +6,13 @@ #include #include +#include +#include + #include "../../cal/opt_func.h" #include "conv.h" + #define ALIGN_BYTES (size_t)64 #define ADD_REGRESS_TEST(suitename, testname) \ @@ -42,4 +46,20 @@ typedef conv_function_t (*conv_wrapper_fn_t)(generic_opts_t cpu_cap, const char** sfunc); +static inline conv_function_t generic_get_fn(generic_opts_t o, int log, conv_wrapper_fn_t wfn, const char** last_fn_name) +{ + const char* fn_name = NULL; + conv_function_t fn = wfn(o, &fn_name); + + //ignore dups + if(*last_fn_name && !strcmp(*last_fn_name, fn_name)) + return NULL; + + if(log) + fprintf(stderr, "%-20s\t", fn_name); + + *last_fn_name = fn_name; + return fn; +} + #endif // XDSP_UTEST_COMMON_H From 5067598da9dc483265a9feb8ca296778b615a82f Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:08:00 +0400 Subject: [PATCH 159/397] Startup fix --- src/lib/device/m2_dsdr/m2_dsdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 65a3db8e..f5cb2c90 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1421,7 +1421,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** break; } } - usleep(40000); + usleep(100000); // //LMK05318 init start From 3af934c01031910604d11b99040912b992d6695e Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 6 Jun 2025 22:25:16 +0300 Subject: [PATCH 160/397] fix build warnings (except 2) --- src/lib/common/ring_buffer.c | 4 ++-- src/lib/device/device_vfs.c | 4 ++-- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 2 +- src/lib/device/mdev.c | 2 +- src/lib/ipblks/streams/stream_limesdr.c | 5 +++-- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 5 +++-- src/lib/ipblks/streams/streams.c | 4 ++-- src/lib/lowlevel/pcie_uram/pcie_uram_main.c | 3 ++- src/lib/models/dm_debug.c | 8 +++++++- src/lib/models/dm_dev.c | 2 +- 10 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/lib/common/ring_buffer.c b/src/lib/common/ring_buffer.c index a23c00f1..0322a6ef 100644 --- a/src/lib/common/ring_buffer.c +++ b/src/lib/common/ring_buffer.c @@ -92,7 +92,7 @@ unsigned ring_buffer_pwait(struct ring_buffer* rb, int usecs) void ring_buffer_ppost(struct ring_buffer* rb) { - int res = sem_post(&rb->consumer); + __attribute__((unused)) int res = sem_post(&rb->consumer); assert(res == 0); } @@ -110,7 +110,7 @@ unsigned ring_buffer_cwait(struct ring_buffer* rb, int usecs) void ring_buffer_cpost(struct ring_buffer* rb) { - int res = sem_post(&rb->producer); + __attribute__((unused)) int res = sem_post(&rb->producer); assert(res == 0); } diff --git a/src/lib/device/device_vfs.c b/src/lib/device/device_vfs.c index 7bb900b9..b705a419 100644 --- a/src/lib/device/device_vfs.c +++ b/src/lib/device/device_vfs.c @@ -35,7 +35,7 @@ int vfs_folder_init(vfs_object_t* o, const char* path, void* user) if (o->data.obj == NULL) return -ENOMEM; - strncpy(o->full_path, path, sizeof(o->full_path)); + snprintf(o->full_path, sizeof(o->full_path), "%s", path); return 0; } @@ -90,7 +90,7 @@ static int _vfs_alloc_object(vfs_object_t* root, vfs_object_t** newobj, uint8_t memset(obj, 0, sizeof(vfs_object_t)); obj->type = type; - strncpy(obj->full_path, path, sizeof(obj->full_path)); + snprintf(obj->full_path, sizeof(obj->full_path), "%s", path); *newobj = obj; return 0; diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index bb7c7fe4..5d8fe79b 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -679,7 +679,7 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, lms7002m_mac_mode_t rx_chs_i, unsigned rx_flags, lms7002m_mac_mode_t tx_chs_i, unsigned tx_flags) { - unsigned rx_chs, tx_chs; + unsigned rx_chs = LMS7_CH_NONE, tx_chs = LMS7_CH_NONE; bool rxafen_a = d->rx_run[0]; bool rxafen_b = d->rx_run[1]; diff --git a/src/lib/device/mdev.c b/src/lib/device/mdev.c index 1f3f6c2a..1809876b 100644 --- a/src/lib/device/mdev.c +++ b/src/lib/device/mdev.c @@ -193,7 +193,7 @@ int _mdev_get_obj(pdevice_t dev, const char* fullpath, pusdr_vfs_obj_t *vfsobj) vfso->ops.sai64 = NULL; vfso->ops.gai64 = NULL; vfso->data.i64 = 0; - strncpy(vfso->full_path, fullpath, sizeof(vfso->full_path)); + snprintf(vfso->full_path, sizeof(vfso->full_path), "%s", fullpath); *vfsobj = vfso; return 0; diff --git a/src/lib/ipblks/streams/stream_limesdr.c b/src/lib/ipblks/streams/stream_limesdr.c index ac5f1fc6..4668bd02 100644 --- a/src/lib/ipblks/streams/stream_limesdr.c +++ b/src/lib/ipblks/streams/stream_limesdr.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -103,7 +104,7 @@ int _limestr_stream_recv(stream_handle_t* str, unsigned bidx; //Burst index in the lowlevel buffer //unsigned - uint64_t brst_time; + uint64_t brst_time = ~0ULL; uint64_t fsym_time = ~0ULL; do { @@ -412,7 +413,7 @@ int create_limesdr_stream(device_t* device, stream_limesdr_t* strdev; stream_t sid; char dfmt[256]; - strncpy(dfmt, dformat, sizeof(dfmt)); + snprintf(dfmt, sizeof(dfmt), "%s", dformat); struct parsed_data_format pfmt; if (stream_parse_dformat(dfmt, &pfmt)) { diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 24dd3ac1..ca95c9cb 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -620,7 +621,7 @@ int parse_sfetrx4(const char* dformat, const channel_info_t *channels, unsigned bool bifurcation = true; struct parsed_data_format pfmt; - strncpy(out->dfmt, dformat, sizeof(out->dfmt)); + snprintf(out->dfmt, sizeof(out->dfmt), "%s", dformat); if (stream_parse_dformat(out->dfmt, &pfmt)) { return -EINVAL; } @@ -1149,7 +1150,7 @@ int create_sfetrx4_stream(device_t* device, fecfg.cfg_base = fe_base; fecfg.cfg_fifomaxbytes = fe_fifobsz; - strncpy(dfmt, dformat, sizeof(dfmt)); + snprintf(dfmt, sizeof(dfmt), "%s", dformat); struct parsed_data_format pfmt; if (stream_parse_dformat(dfmt, &pfmt)) { return -EINVAL; diff --git a/src/lib/ipblks/streams/streams.c b/src/lib/ipblks/streams/streams.c index 6222e399..9d250b62 100644 --- a/src/lib/ipblks/streams/streams.c +++ b/src/lib/ipblks/streams/streams.c @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT #include "streams.h" -#include +#include struct bitsfmt get_bits_fmt(const char* fmt) { @@ -17,7 +17,7 @@ struct bitsfmt get_bits_fmt(const char* fmt) else if (strcasecmp(fmt, "i16") == 0) bmft.bits = 16; else - strncpy((char*)bmft.func, fmt, sizeof(bmft.func)); + snprintf((char*)bmft.func, sizeof(bmft.func), "%s", fmt); return bmft; } diff --git a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c index 2d7b615c..3143a099 100644 --- a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c +++ b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c @@ -918,7 +918,8 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** dev->ll.ops = &s_pcie_uram_ops; dev->fd = fd; - strncpy(dev->name, devname, sizeof(dev->name) - 1); + + snprintf(dev->name, sizeof(dev->name), "%s", devname); // Get UUID device_id_t did; diff --git a/src/lib/models/dm_debug.c b/src/lib/models/dm_debug.c index 626b73c7..97f4bb72 100644 --- a/src/lib/models/dm_debug.c +++ b/src/lib/models/dm_debug.c @@ -162,7 +162,13 @@ static void* usdr_dif_thread(void* param) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); if (replen > 0) { - write(data_socket, reply, replen); + int wres = write(data_socket, reply, replen); + if(wres < 0) + { + wres = errno; + USDR_LOG("DBGS", USDR_LOG_ERROR, "write() error:%d!", wres); + goto connection_closed; + } } ssize_t ech = end - (p + buffer); diff --git a/src/lib/models/dm_dev.c b/src/lib/models/dm_dev.c index 028aca67..3f63d7a0 100644 --- a/src/lib/models/dm_dev.c +++ b/src/lib/models/dm_dev.c @@ -164,7 +164,7 @@ int usdr_dmd_create_string(const char* connection_string, pdm_dev_t* odev) break; } else if (strcmp(par.params[k], "bus") == 0) { bus_idx = k; - strncpy(bus_buffer, par.value[k], sizeof(bus_buffer)); + snprintf(bus_buffer, sizeof(bus_buffer), "%s", par.value[k]); unsigned j; char *str, *token, *saveptr; From db17c2895645ece133335bfcc442e29d4d366e41 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 13 Jun 2025 18:51:25 +0300 Subject: [PATCH 161/397] Add LMK05313 BAW settings for XO=52M --- src/lib/hw/lmk05318/lmk05318.c | 33 ++++++++++++++++++++++++++++++- src/utests/lmk05318_solver_test.c | 25 ++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 0d9a0d70..a662c239 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -85,6 +85,7 @@ enum XO12_8 = 12800000, XO25 = 25000000, XO26 = 26000000, + XO52 = 52000000, }; #define DPLL_FDIV_FRAC_MAX 0.9375f @@ -607,9 +608,39 @@ static int lmk05318_set_xo_bawdetect_registers(lmk05318_state_t* d) res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); break; } + case XO52: + { + USDR_LOG("5318", USDR_LOG_INFO, "XO=52M, applying specific settings..."); + + static uint32_t regs[] = + { + 0x00510A, + 0x005200, + 0x00530F, + 0x00543C, + 0x005540, + 0x005600, + 0x00571E, + 0x005884, + 0x005980, + 0x005A00, + 0x005B14, + 0x005C00, + 0x005D0F, + 0x005E3C, + 0x005F40, + 0x006000, + 0x00611E, + 0x006284, + 0x006380, + }; + + res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); + break; + } default: { - USDR_LOG("5318", USDR_LOG_ERROR, "XO=%.2fMHz not supported! Use 12.8, 25 or 26M", (double)d->xo.fref / 1e6); + USDR_LOG("5318", USDR_LOG_ERROR, "XO=%.2fMHz not supported! Use 12.8, 25, 26 or 52M", (double)d->xo.fref / 1e6); return -EINVAL; } } diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 8ad4b8d9..a3cc94dc 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -415,7 +415,29 @@ START_TEST(lmk05318_solver_test_xmass) res = res ? res : lmk05318_set_port_affinity(&cfg[4], AFF_APLL2); res = res ? res : lmk05318_solver(&st, cfg, 8); res = res ? res : lmk05318_reg_wr_from_map(&st, true); - ck_assert_int_eq( res, 0 );} + ck_assert_int_eq( res, 0 ); +} + +START_TEST(lmk05318_hyper_test1) +{ + int res = 0; + + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 1, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 4, 0, false, OUT_OFF); + res = res ? res : lmk05318_port_request(p++, 5, 245760000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 6, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 7, 245760000, false, LVDS); + ck_assert_int_eq( res, 0 ); + + lmk05318_state_t st; + res = lmk05318_create(NULL, 0, 0, 52000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); +} Suite * lmk05318_solver_suite(void) { @@ -439,6 +461,7 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_dsdr_test3); tcase_add_test(tc_core, lmk05318_simplesync_test1); tcase_add_test(tc_core, lmk05318_solver_test_xmass); + tcase_add_test(tc_core, lmk05318_hyper_test1); suite_add_tcase(s, tc_core); return s; From 128a034333c9e01b70a81fe33dfd7b6663c052c4 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 13 Jun 2025 23:34:34 +0300 Subject: [PATCH 162/397] Fix LMK05313 BAW settings for XO=52M --- src/lib/hw/lmk05318/lmk05318.c | 39 +++------------------------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index a662c239..370e7175 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -520,8 +520,6 @@ static int lmk05318_set_xo_bawdetect_registers(lmk05318_state_t* d) { case XO12_8: { - USDR_LOG("5318", USDR_LOG_INFO, "XO=12.8M, applying specific settings..."); - static uint32_t regs[] = { 0x00510A, @@ -550,8 +548,6 @@ static int lmk05318_set_xo_bawdetect_registers(lmk05318_state_t* d) } case XO25: { - USDR_LOG("5318", USDR_LOG_INFO, "XO=25M, applying specific settings..."); - static uint32_t regs[] = { 0x00510A, //R81 @@ -579,9 +575,8 @@ static int lmk05318_set_xo_bawdetect_registers(lmk05318_state_t* d) break; } case XO26: + case XO52: // both these XOs result in FPD1=52M, so we can use just the same setting { - USDR_LOG("5318", USDR_LOG_INFO, "XO=26M, applying specific settings..."); - static uint32_t regs[] = { 0x00510A, @@ -608,36 +603,6 @@ static int lmk05318_set_xo_bawdetect_registers(lmk05318_state_t* d) res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); break; } - case XO52: - { - USDR_LOG("5318", USDR_LOG_INFO, "XO=52M, applying specific settings..."); - - static uint32_t regs[] = - { - 0x00510A, - 0x005200, - 0x00530F, - 0x00543C, - 0x005540, - 0x005600, - 0x00571E, - 0x005884, - 0x005980, - 0x005A00, - 0x005B14, - 0x005C00, - 0x005D0F, - 0x005E3C, - 0x005F40, - 0x006000, - 0x00611E, - 0x006284, - 0x006380, - }; - - res = lmk05318_add_reg_to_map(d, regs, SIZEOF_ARRAY(regs)); - break; - } default: { USDR_LOG("5318", USDR_LOG_ERROR, "XO=%.2fMHz not supported! Use 12.8, 25, 26 or 52M", (double)d->xo.fref / 1e6); @@ -645,6 +610,8 @@ static int lmk05318_set_xo_bawdetect_registers(lmk05318_state_t* d) } } + USDR_LOG("5318", USDR_LOG_INFO, "XO=%.2fMHz, applying specific settings...", (double)d->xo.fref / 1e6); + return res; } From d13f931561c86e51dabbc6a6459b2201cfe818b2 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 14 Jun 2025 22:15:57 +0400 Subject: [PATCH 163/397] dsdr: fix lmk05318b usage for dsdr/hiper --- src/lib/device/m2_dsdr/m2_dsdr.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index f5cb2c90..fc282b7b 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1330,9 +1330,9 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->type = devid; break; - case 0xff: - d->type = DSDR_PCIE_HIPER_R0; - break; + //case 0xff: + // d->type = DSDR_PCIE_HIPER_R0; + // break; default: USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported HWID = %08x, skipping initialization!\n", hwid); @@ -1403,8 +1403,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return res; } - - res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0xf); + // Put LMK into PD but enable all LDOs to settle + res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0xbf); for (unsigned j = 0; j < 10; j++) { usleep(10000); @@ -1421,7 +1421,9 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** break; } } - usleep(100000); + + usleep(200000); //TODO monitor power good signal!!! + res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0xff); // //LMK05318 init start @@ -1449,7 +1451,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** lmk05318_port_request(&lmk_out[6], 6, 3840000, false, LVDS); lmk05318_port_request(&lmk_out[7], 7, d->dac_rate / 2, false, LVDS); - res = lmk05318_create(dev, d->subdev, I2C_LMK, 26000000, XO_CMOS, false, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->lmk, false /*dry_run*/); + res = lmk05318_create(dev, d->subdev, I2C_LMK, (d->type == DSDR_PCIE_HIPER_R0) ? 52000000 : 26000000, XO_CMOS, + false, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->lmk, false /*dry_run*/); if(res) return res; @@ -1462,10 +1465,9 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } //wait for lock - res = lmk05318_wait_apll1_lock(&d->lmk, 100000); - res = res ? res : lmk05318_wait_apll2_lock(&d->lmk, 100000); - - lmk05318_check_lock(&d->lmk, &los, false /*silent*/); //just to log state + res = lmk05318_wait_apll1_lock(&d->lmk, 200000); + res = res ? res : lmk05318_wait_apll2_lock(&d->lmk, 200000); + res = res ? res : lmk05318_check_lock(&d->lmk, &los, false /*silent*/); //just to log state if(res) { @@ -1475,10 +1477,12 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** //sync to make APLL1/APLL2 & out channels in-phase res = lmk05318_sync(&d->lmk); + //res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0x7f); + //res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0xff); if(res) return res; - USDR_LOG("DSDR", USDR_LOG_INFO, "LMK03518 outputs synced"); + USDR_LOG("DSDR", USDR_LOG_INFO, "LMK03518 outputs synced, LOS=%x", los); //LMK05318 init end // From d9067a274236a55f50ca01ada7e6ec1ddd0142ad Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 14 Jun 2025 22:16:34 +0400 Subject: [PATCH 164/397] usdr_flash: do not overwrite image with the same ID --- src/tools/usdr_flash.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tools/usdr_flash.c b/src/tools/usdr_flash.c index 474b560b..1790118b 100644 --- a/src/tools/usdr_flash.c +++ b/src/tools/usdr_flash.c @@ -239,6 +239,15 @@ int main(int argc, char** argv) fprintf(stderr, "Looks like you're using latest firmware already\n"); return 9; } + if (image.usr_access2 == file.usr_access2 && golden && !force) { + fprintf(stderr, "Looks like GOLD image %08x is already flashed!\n", file.usr_access2); + return 9; + } + if (image_master.usr_access2 == file.usr_access2 && !golden && !force) { + fprintf(stderr, "Looks like MASTER image %08x is already flashed!\n", file.usr_access2); + return 9; + } + if (corrupt) { memset(outa + 512*1024, -1, 512*1024); fprintf(stderr, "CORRUPTING IMAGE!!!\n\n"); From ac88557f3626e6b9470d356ac1cf5d779554a8bf Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 14 Jun 2025 22:18:04 +0400 Subject: [PATCH 165/397] xsdr/ssdr: lml autocalibration wip --- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 6 +- src/lib/device/m2_lm7_1/m2_lm7_1.c | 38 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 193 ++++-- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 7 + src/lib/hw/lms7002m/lms7002m.c | 24 +- src/lib/hw/lms7002m/lms7002m.h | 2 +- src/lib/hw/lms7002m/lms7002m.yaml | 73 +++ src/tools/CMakeLists.txt | 3 + src/tools/lms7002_dm_limelight.c | 814 ++++++++++++++++++++++++ 9 files changed, 1107 insertions(+), 53 deletions(-) create mode 100644 src/tools/lms7002_dm_limelight.c diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 5d8fe79b..c1c9f386 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -1063,9 +1063,9 @@ int lms7002m_samplerate(lms7002_dev_t *d, return res; // Set ADS for bypass mode - res = lms7002m_cds_set(&d->lmsstate, rxtsp_div == 1, rxtsp_div == 1); - if (res) - return res; + // res = lms7002m_cds_set(&d->lmsstate, rxtsp_div == 1, rxtsp_div == 1); + // if (res) + // return res; d->lml_mode = cfg; USDR_LOG("XDEV", USDR_LOG_INFO, "rxrate=%.3fMHz txrate=%.3fMHz" diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 81055db5..d08f6555 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -220,12 +220,17 @@ static int dev_m2_lm7_1_dev_atcrbs_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 static int dev_m2_lm7_1_dev_dac_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_phyrxlm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_lm7_1_lms7002rxlml_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_revision_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); static int dev_m2_lm7_1_sdr_tx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_sdr_rx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static @@ -248,6 +253,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/vio", { dev_m2_lm7_1_sdr_vio_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr", { dev_m2_lm7_1_sdr_tx_phase_ovr_set, NULL }}, + { "/dm/sdr/0/tx/phase_ovr_iq", { dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set, NULL }}, + { "/dm/sdr/0/rx/phase_ovr", { dev_m2_lm7_1_sdr_rx_phase_ovr_set, NULL }}, { "/dm/sdr/0/rx/dccorr", { dev_m2_lm7_1_sdr_rx_dccorr_set, NULL }}, { "/dm/sdr/0/tx/dccorr", { dev_m2_lm7_1_sdr_tx_dccorr_set, NULL }}, @@ -309,6 +316,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/dac_vctcxo", { dev_m2_lm7_1_dev_dac_vctcxo_set, NULL }}, + { "/dm/sdr/0/phy_rx_dly", { dev_m2_lm7_1_phy_rx_dly_set, NULL }}, { "/dm/sdr/0/phyrxlml", { dev_m2_lm7_1_phyrxlm_set, NULL }}, { "/debug/hw/lms7002m/0/rxlml", { dev_m2_lm7_1_lms7002rxlml_set, NULL }}, @@ -353,6 +361,14 @@ int dev_m2_lm7_1_phyrxlm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return xsdr_phy_tune_rx(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); } +int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + unsigned type = (value >> 8) & 0x1f; + unsigned val = (value & 0x1f); + + return xsdr_config_rcvdly(&((struct dev_m2_lm7_1_gps *)ud)->xdev, type, val); +} + int dev_m2_lm7_1_lms7002rxlml_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { return lms7002m_set_lmlrx_mode(&((struct dev_m2_lm7_1_gps *)ud)->xdev.base, value); @@ -385,6 +401,20 @@ int dev_m2_lm7_1_sdr_tx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ return 0; } +int dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + d->xdev.tx_override_phase_iq = value; + return 0; +} + +int dev_m2_lm7_1_sdr_rx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + d->xdev.rx_override_phase = value; + return 0; +} + int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; @@ -398,6 +428,8 @@ int dev_m2_lm7_1_debug_lms7002m_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint6 unsigned chan = (unsigned)(value >> 32); res = lms7002m_mac_set(&d->xdev.base.lmsstate, chan); + if (res) + return res; d->debug_lms7002m_last = ~0u; res = lowlevel_spi_tr32(d->base.dev, 0, SPI_LMS7, value & 0xffffffff, &d->debug_lms7002m_last); @@ -709,8 +741,9 @@ int dev_m2_lm7_1_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - //Simple SISO RX only + //Simple SISO RX only return xsdr_set_samplerate_ex(&d->xdev, (unsigned)value, (unsigned)value, 0, 0, + (d->bifurcation_en) ? (XSDR_LML_SISO_DDR_RX | XSDR_LML_SISO_DDR_TX) : 0 | (d->nodecint ? 0 : XSDR_SR_MAXCONVRATE) | XSDR_SR_EXTENDED_CGEN); } @@ -735,6 +768,7 @@ int dev_m2_lm7_1_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return -ERANGE; return xsdr_set_samplerate_ex(&d->xdev, rx_rate, tx_rate, adc_rate, dac_rate, + (d->bifurcation_en) ? (XSDR_LML_SISO_DDR_RX | XSDR_LML_SISO_DDR_TX) : 0 | (d->nodecint ? 0 : XSDR_SR_MAXCONVRATE) | XSDR_SR_EXTENDED_CGEN); } @@ -1058,7 +1092,7 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* fe = devval[i]; } if (strcmp(devparam[i], "bifurcation") == 0) { - d->bifurcation_en = atoi(devval[i]); + d->bifurcation_en = (devval[i]) ? atoi(devval[i]) : 1; } if (strcmp(devparam[i], "nodec") == 0) { d->nodecint = true; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index b4bfbcb0..e4fbf5c7 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -121,6 +121,16 @@ static int _xsdr_checkpwr(xsdr_dev_t *d) return 0; } +int xsdr_config_rcvdly(xsdr_dev_t *d, unsigned type, unsigned val) +{ + lldev_t dev = d->base.lmsstate.dev; + unsigned subdev = d->base.lmsstate.subdev; + + uint32_t cmd = (1 << 31) | (((type + 14) & 0x7f) << 24) | (val & 0xffff); + + return lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, cmd); +} + int xsdr_set_samplerate(xsdr_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk) @@ -138,6 +148,35 @@ enum { PHY_REG_PORT_IQSEL = 5, }; +enum { + PHY_REG_RXBANK_CTRL = 0, // Control registers + PHY_REG_RXBANK_MMCM = 1, // MMCM registers + PHY_REG_RXBANK_CLKMEAS = 2, + PHY_REG_RXBANK_LFSRCHK = 3, // LFSR cntrol + + PHY_REG_RXBANK_CLKDLY = 14, // Clock delay + PHY_REG_RXBANK_FRMDLY = 15, // Frame delay +}; + + +int xsdr_phy_rx_reg(xsdr_dev_t *d, bool wr, uint8_t bank, uint8_t addr, uint16_t val) +{ + uint32_t reg = (wr ? 0x80000000 : 0) | (((uint32_t)bank & 0x7f) << 24) | ((uint32_t)addr << 16) | val; + return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, reg); +} + +static int xsdr_phy_en_lfsr_mimo(xsdr_dev_t *d, bool en) +{ + int res = 0; + if (!en) { + return xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0x0f); + } + + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0x0f); + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0xf0); + return res; +} + int xsdr_phy_tx_reg(xsdr_dev_t *d, uint8_t addr, uint32_t val) { return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_1, (((uint32_t)addr) << 24) | (val & 0xffffff)); @@ -185,6 +224,27 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, return 0; } +static struct mmcm_config_raw g_tx_cfg_raw; + + +int xsdr_upd_phase(xsdr_dev_t *d) +{ + if (d->tx_override_phase) { + unsigned raw = d->tx_override_phase - 1; + g_tx_cfg_raw.ports[CLKOUT_PORT_0].phase = raw & 7; + g_tx_cfg_raw.ports[CLKOUT_PORT_0].delay = (raw >> 3); + } + + USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set phase to %d.%d\n", g_tx_cfg_raw.ports[CLKOUT_PORT_0].delay, g_tx_cfg_raw.ports[CLKOUT_PORT_0].phase); + mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &g_tx_cfg_raw); + + // Reset MMCM + xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 1); + usleep(1); + xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); + return 0; +} + int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) { bool nomul = d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); @@ -210,38 +270,57 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); + // 0 - IO_TX_IQSEL (individual phase delay) + // 1 - IO_TX + // 2 - IO_RX + // 3 - LOGIC_TX + // 4 - n/a + // 5 - FCLK_RX + // 6 - FCLK_TX + cfg_raw.type = MT_7SERIES_MMCM; cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; - cfg_raw.ports[CLKOUT_PORT_2].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_2].period_h = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_2].period_l = (vco_div_io + 1) / 2; + cfg_raw.ports[CLKOUT_PORT_2].period_h = vco_div_io / 2; cfg_raw.ports[CLKOUT_PORT_3].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_3].period_h = vco_div_io; cfg_raw.ports[CLKOUT_PORT_4].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_5].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_6].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io; - - cfg_raw.ports[CLKOUT_PORT_0].phase = ((vco_div_io & 3) == 0) ? 0 : - ((vco_div_io & 3) == 1) ? 2 : - ((vco_div_io & 3) == 2) ? 4 : 6; - cfg_raw.ports[CLKOUT_PORT_0].delay = vco_div_io / 4; - - cfg_raw.ports[CLKOUT_PORT_3].phase = cfg_raw.ports[CLKOUT_PORT_0].phase; - cfg_raw.ports[CLKOUT_PORT_3].delay = vco_div_io / 2; + cfg_raw.ports[CLKOUT_PORT_5].period_l = (vco_div_io + 1) / 2; + cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io / 2; + cfg_raw.ports[CLKOUT_PORT_6].period_l = (vco_div_io + 1) / 2; + cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io / 2; + + unsigned total_budget = 8 * vco_div_io; + unsigned phase = (((tx_mclk < 2*35e6) || (tx_mclk > 2*60e6)) ? 4 : 5) * total_budget / 6; + unsigned phase_iq = 4; + + cfg_raw.ports[CLKOUT_PORT_6].phase = phase % 8; + cfg_raw.ports[CLKOUT_PORT_6].delay = phase / 8; + cfg_raw.ports[CLKOUT_PORT_0].phase = phase_iq % 8; + cfg_raw.ports[CLKOUT_PORT_0].delay = phase_iq / 8; + + if (d->tx_override_phase_iq) { + unsigned raw = d->tx_override_phase_iq - 1; + cfg_raw.ports[CLKOUT_PORT_0].phase = raw % 8; + cfg_raw.ports[CLKOUT_PORT_0].delay = raw / 8; + } if (d->tx_override_phase) { unsigned raw = d->tx_override_phase - 1; - cfg_raw.ports[CLKOUT_PORT_0].phase = raw & 7; - cfg_raw.ports[CLKOUT_PORT_3].phase = raw & 7; - cfg_raw.ports[CLKOUT_PORT_0].delay = (raw >> 3); - cfg_raw.ports[CLKOUT_PORT_3].delay = 2 * (raw >> 3); + cfg_raw.ports[CLKOUT_PORT_6].phase = raw % 8; + cfg_raw.ports[CLKOUT_PORT_6].delay = raw / 8; + } + + if (d->rx_override_phase) { + unsigned raw = d->rx_override_phase - 1; + cfg_raw.ports[CLKOUT_PORT_2].phase = raw % 8; + cfg_raw.ports[CLKOUT_PORT_2].delay = raw / 8; } if (nomul) { @@ -251,17 +330,20 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; } - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d\n", + USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d VCO=%.3f MHZ\n", tx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io, (d->tx_override_phase) ? "_OVR" : "", cfg_raw.ports[CLKOUT_PORT_0].delay, cfg_raw.ports[CLKOUT_PORT_0].phase, - d->base.lml_mode.txsisoddr); + d->base.lml_mode.txsisoddr, + tx_mclk * (cfg_raw.ports[CLKOUT_PORT_FB].period_l + cfg_raw.ports[CLKOUT_PORT_FB].period_h) / 1.0e6); res = res ? res : mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &cfg_raw); + + // Reset MMCM res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 1); - usleep(100); + usleep(10); res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); for (unsigned k = 0; k < 10; k++) { @@ -279,6 +361,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) usleep(5000); } + g_tx_cfg_raw = cfg_raw; return res; } @@ -492,15 +575,23 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, if (tx_mmcm) { res = res ? res : xsdr_configure_lml_mmcm_tx(d); } else { - res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x8f); - res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x8f); - res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, 0x0f); unsigned dly = (d->tx_override_phase) ? (d->tx_override_phase - 1) : 3; res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_DLY_VALUE, dly); } } + + xsdr_phy_en_lfsr_mimo(d, true); +/* + + xsdr_config_rcvdly(d, 1, (rxrate >= 65e6) ? 21 : 0); // D0 + for (unsigned h = 0; h < 12; h++) { + xsdr_config_rcvdly(d, 2 + h, (rxrate >= 65e6) ? 21 : 0); // D0 + } + +*/ + return res; } @@ -512,16 +603,32 @@ int xsdr_clk_debug_info(xsdr_dev_t *d) unsigned crx, ctx, caux; int res = 0; + uint32_t dump[12]; + res = res ? res : dev_gpi_get32(dev, IGPI_MEAS_RXCLK, &crx); res = res ? res : dev_gpi_get32(dev, IGPI_MEAS_TXCLK, &ctx); res = res ? res : dev_gpi_get32(dev, IGPI_CLK1PPS, &caux); if (res) return res; - USDR_LOG("XDEV", USDR_LOG_WARNING, "PHY - RX %08x (%d) / TX %08x (%d) / AUX %08x (%d)\n", + + for (unsigned h = 0; h < 12; h++) { + unsigned p = ((h & 0x3) << 2) | (h >> 2); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + + res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &dump[h]); + } + + + USDR_LOG("XDEV", USDR_LOG_WARNING, "PHY - RX %08x (%d) / TX %08x (%d) / AUX %08x (%d) %d/%d/%d/%d %d/%d/%d/%d %d/%d/%d/%d \n", crx, crx & 0xfffffff, ctx, ctx & 0xfffffff, - caux, caux & 0xfffffff); + caux, caux & 0xfffffff, + dump[0], dump[1], dump[2], dump[3], dump[4], dump[5], dump[6], dump[7], dump[8], dump[9], dump[10], dump[11] + ); return res; } @@ -866,7 +973,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) { lldev_t dev = d->base.lmsstate.dev; unsigned subdev = 0; - int res; + int res = 0; bool pg = false; enum tx_switch_cfg { @@ -927,7 +1034,8 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) d->base.cfg_auto_rx[1].swlb = 1; } - res = dev_gpo_set(dev, IGPO_LMS_PWR, 0); + res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0x80); + res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0x00); if (res) return res; @@ -951,7 +1059,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) } // LMS Vcore boost to 1.25V - res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 2, 1260); + res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 2, 1280); res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 3, 1850); res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 0, 1, 1); //1v0 -- less affected @@ -1066,6 +1174,10 @@ int _xsdr_init_revo(xsdr_dev_t *d) strncpy(d->base.cfg_auto_tx[1].name0, "H", sizeof(d->base.cfg_auto_tx[1].name0)); strncpy(d->base.cfg_auto_tx[1].name1, "B1", sizeof(d->base.cfg_auto_tx[1].name1)); + + // Reset + res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0x80); + // Set external GPIOs to 3.3V res = res ? res : dev_gpo_set(dev, IGPO_IOVCCSEL, 1); // Take control of second I2C bus @@ -1226,16 +1338,23 @@ int _xsdr_pwren_revo(xsdr_dev_t *d, bool on) int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) { - if (!d->new_rev) - return -EINVAL; + if (!d->new_rev) { + if (vio_mv > 3300) + vio_mv = 3300; + else if (vio_mv < 1600) + vio_mv = 1600; + + USDR_LOG("XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); + return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, vio_mv); + } - if (vio_mv > 2100) - vio_mv = 2100; - else if (vio_mv < 1600) - vio_mv = 1600; + if (vio_mv > 2100) + vio_mv = 2100; + else if (vio_mv < 1600) + vio_mv = 1600; - USDR_LOG("XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); - return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, vio_mv); + USDR_LOG("XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); + return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, vio_mv); } int xsdr_pwren(xsdr_dev_t *d, bool on) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 01f165da..29fa247e 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -50,6 +50,8 @@ struct xsdr_dev unsigned lms7_lob; int tx_override_phase; + int tx_override_phase_iq; + int rx_override_phase; bool afe_active; bool siso_sdr_active_rx; @@ -160,6 +162,11 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, size_t meminsz, void* pin, size_t memoutsz, const void* pout); + +int xsdr_upd_phase(xsdr_dev_t *d); + +int xsdr_config_rcvdly(xsdr_dev_t *d, unsigned type, unsigned val); + enum { XSDR_CAL_RXLO = 1, XSDR_CAL_TXLO = 2, diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index 4cfc4e46..d35ffeff 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -350,7 +350,7 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t unsigned rxmux = params.rx_lfsr ? LML_0X002A_RX_MUX_LFSR : params.rx_tx_dig_loopback ? LML_0X002A_RX_MUX_TXFIFO : LML_0X002A_RX_MUX_RXTSP; - unsigned rdclk = (params.rx_ext_rd_fclk || params.rx_tx_dig_loopback) ? + unsigned rdclk = (params.rx_ext_rd_fclk /* || params.rx_tx_dig_loopback */ ) ? ((params.rx_port) ? LML_0X002A_RXRDCLK_MUX_FCLK1 : LML_0X002A_RXRDCLK_MUX_FCLK2) : ((params.rx_port) ? LML_0X002A_RXRDCLK_MUX_MCLK1 : LML_0X002A_RXRDCLK_MUX_MCLK2); uint16_t reg_mac = m->reg_mac; @@ -395,6 +395,8 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t (params.txdiv > 1) ? 1u : 0, (params.rxdiv > 1) ? 1u : 0), MAKE_LMS7002M_LML_0x002C( params.txdiv / 2u - 1u, params.rxdiv / 2u - 1u ), + MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, params.rxdiv == 1 ? 0 : 1, 1, 1), + MAKE_LMS7002M_CDS_0x00AE(3, 3, 0, 0, 0, 0, 0, 0), MAKE_LMS7002M_REG_WR(LML_0x0020, reg_mac), MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac) }; @@ -402,6 +404,17 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); } +/* +int lms7002m_cds_set(lms7002m_state_t* m, bool rxalml, bool rxblml) +{ + uint32_t regs[] = { + // 0x80AD03ff ^ ((rxalml ? 1 : 0) << 2) , //^ ((rxblml ? 1 : 0) << 3), + 0x80AD03ff ^ ((rxalml ? 1 : 0) << 2), + 0x80AE0C00, + }; + return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); +} +*/ int _lms7002m_fill_pos(lms7002m_lml_map_t l, lms7002m_lml_map_t* o) { @@ -747,15 +760,6 @@ int lms7002m_dc_corr(lms7002m_state_t* m, unsigned p, int16_t v) } -int lms7002m_cds_set(lms7002m_state_t* m, bool rxalml, bool rxblml) -{ - uint32_t regs[] = { - // 0x80AD03ff ^ ((rxalml ? 1 : 0) << 2) , //^ ((rxblml ? 1 : 0) << 3), - 0x80AD03ff ^ ((rxalml ? 1 : 0) << 2), - 0x80AE0C00, - }; - return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); -} // xxTSP diff --git a/src/lib/hw/lms7002m/lms7002m.h b/src/lib/hw/lms7002m/lms7002m.h index 2d69a2df..2a55703f 100644 --- a/src/lib/hw/lms7002m/lms7002m.h +++ b/src/lib/hw/lms7002m/lms7002m.h @@ -156,7 +156,7 @@ enum dc_param { int lms7002m_dc_corr(lms7002m_state_t* m, unsigned p, int16_t v); // CDS -int lms7002m_cds_set(lms7002m_state_t* m, bool rxalml, bool rxblml); +// int lms7002m_cds_set(lms7002m_state_t* m, bool rxalml, bool rxblml); // This functions is sensible to A/B channel selection enum lms7002m_xxtsp { diff --git a/src/lib/hw/lms7002m/lms7002m.yaml b/src/lib/hw/lms7002m/lms7002m.yaml index 8773f7d7..33c00b5d 100644 --- a/src/lib/hw/lms7002m/lms7002m.yaml +++ b/src/lib/hw/lms7002m/lms7002m.yaml @@ -1918,3 +1918,76 @@ pages: name: PD_XBUF_TX - bits: 0 name: EN_G_XBUF +- name: CDS + regs: + - addr: '0x00AD' + name: '0x00AD' + fields: + - bits: '15:14' + name: MCLK2 + desc: MCLK2 clock delay + - bits: '13:12' + name: MCLK1 + desc: MCLK1 clock delay + - bits: '11:10' + name: RESERVED + - bits: 9 + name: NTXBTSP + desc: TX TSPB clock inversion control + - bits: 8 + name: NTXATSP + desc: TX TSPA clock inversion control + - bits: 7 + name: NRXBTSP + desc: RX TSPB clock inversion control + - bits: 6 + name: NRXATSP + desc: RX TSPA clock inversion control + - bits: 5 + name: NTXBLML + desc: TX LMLB clock inversion control + - bits: 4 + name: NTXALML + desc: TX LMLA clock inversion control + - bits: 3 + name: NRXBLML + desc: RX LMLB clock inversion control + - bits: 2 + name: NRXALML + desc: RX LMLA clock inversion control + - bits: 1 + name: NMCLK2 + desc: MCLK2 clock inversion control + - bits: 0 + name: NMCLK1 + desc: MCLK1 clock inversion control + - addr: '0x00AE' + name: '0x00AE' + fields: + - bits: '15:14' + name: TXBTSP + desc: TX TSP B clock delay + - bits: '13:12' + name: TXATSP + desc: TX TSP A clock delay + - bits: '11:10' + name: RXBTSP + desc: RX TSP B clock delay + - bits: '9:8' + name: RXATSP + desc: RX TSP A clock delay + - bits: '7:6' + name: TXBLML + desc: TX LML B clock delay + - bits: '5:4' + name: TXALML + desc: TX LML A clock delay + - bits: '3:2' + name: RXBLML + desc: RX LML B clock delay + - bits: '1:0' + name: RXALML + desc: RX LML A clock delay + + + diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index fca5deb1..5a4d210a 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -22,6 +22,9 @@ add_executable(usdr_dm_sensors usdr_dm_sensors.c) target_link_libraries(usdr_dm_sensors usdr) install(TARGETS usdr_dm_sensors RUNTIME) +add_executable(usdr_lml7_test lms7002_dm_limelight.c) +target_link_libraries(usdr_lml7_test usdr) + list(APPEND WVLT_SCRIPTS wvlt_sdr_wrapper.py ) diff --git a/src/tools/lms7002_dm_limelight.c b/src/tools/lms7002_dm_limelight.c new file mode 100644 index 00000000..b45f6f6d --- /dev/null +++ b/src/tools/lms7002_dm_limelight.c @@ -0,0 +1,814 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#define _GNU_SOURCE +#include +#include + +#include +#include +#include +#include "../ipblks/streams/streams.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../common/ring_buffer.h" +#include "sincos_functions.h" +#include "fast_math.h" + +#define LOG_TAG "LML7" + +#define MAX_CHS 2 +#define MAX_PATTERN 16384 + +static unsigned num_rx = 2; + +static uint16_t s_pattern_r0[2 * MAX_PATTERN]; +static uint16_t s_pattern_r1[2 * MAX_PATTERN]; + +static uint16_t s_pattern_t0[2 * MAX_PATTERN]; +static uint16_t s_pattern_t1[2 * MAX_PATTERN]; + +static size_t d_off = 0; +static uint16_t* d_pattern_r0 = NULL; +static uint16_t* d_pattern_r1 = NULL; + +static const uint32_t s_dtest[] = { + // Single + 0x00000000, + 0xFFFFFFFF, + 0xAAAAAAAA, + 0x55555555, + 0xA5A5A5A5, + 0x5A5A5A5A, + 0x11111111, + 0x44444444, + + // Dual + 0x0000FFFF, + 0x0000AAAA, + 0x00005555, + 0x0000A55A, + 0xAAAAFFFF, + 0xFFFFAAAA, + 0xFFFF5555, + 0xFFFFA55A, + 0xAAAA5555, +}; + +#define DUAL_TESTS SIZEOF_ARRAY(s_dtest) + +static void fill_test(uint16_t* ptr, unsigned test_no) +{ + if (test_no >= DUAL_TESTS) + return; + + uint32_t* pc = (uint32_t*)ptr; + uint32_t c = s_dtest[test_no]; + for (unsigned i = 0; i < MAX_PATTERN; i++) { + pc[i] = c; + } +} + +static uint32_t s_sync = 0; +static uint32_t s_sync_errs = 0; +static uint32_t s_off = 0; +static uint32_t s_resync = 0; +static uint32_t s_sbit_err = 0; +static uint32_t s_mbit_err = 0; +static uint32_t s_bpos_err[16]; + +struct bit_error_stat { + unsigned bit_errors[16]; // Bit error counts + unsigned bit_pos_errors[16]; // Individual bit pos errors +}; +typedef struct bit_error_stat bit_error_stat_t; + +__attribute__((optimize("-O3"))) +static int bitcount(unsigned v) +{ + unsigned c = 0; + for (unsigned i = 32; i != 0; i--) { + if (v & 1) + c++; + v >>= 1; + } + return c; +} + +static void bit_error_init(bit_error_stat_t* p) +{ + for (unsigned i = 0; i < 16; i++) { + p->bit_errors[i] = 0; + p->bit_pos_errors[i] = 0; + } +} + +__attribute__((optimize("-O3"))) +static unsigned bit_error_check(bit_error_stat_t* p, uint16_t a, uint16_t b) +{ + unsigned diff = (a ^ b); + if (diff == 0) { + return 0; + } + + unsigned bcnt = bitcount(diff); + p->bit_errors[bcnt]++; + + for (unsigned i = 0; i != 16; i++) { + if (diff & (1 << i)) { + p->bit_pos_errors[i]++; + } + } + return bcnt; +} + +static void check_test(const uint16_t* data, uint16_t mask, unsigned count, unsigned test_no) +{ + if (test_no >= DUAL_TESTS) + return; + + const uint32_t* pc = (const uint32_t*)data; + uint32_t c = s_dtest[test_no]; + uint16_t p0 = c >> 16; + uint16_t p1 = c; + unsigned j = s_off; + unsigned l = 0; + unsigned errs = 0; + + if (!s_sync) { + for (j = 0; j < count; j++) { + if (data[j] == p0) { + s_sync = 0; + goto synced; + } + s_sync_errs ++; + } + return; + } + +synced: + + for (; j < count; j++, l++) { + uint16_t p = ((l % 2) ? p1 : p0) & mask; + unsigned diff = (p ^ data[j]); + if (diff == 0) { + errs = 0; + continue; + } + + errs++; + if (bitcount(diff) > 1) { + s_mbit_err++; + } else { + s_sbit_err++; + } + + for (unsigned i = 0; i != 16; i--) { + if (diff & (1 << i)) { + s_bpos_err[i]++; + } + } + } + + s_off = l % 2; +} + +enum LML_MODE { + LML_MODE_NORMAL = 0, + LML_MODE_LOOPBACK = 1, + LML_MODE_LFSR = 2, +}; + +static pdm_dev_t dev = NULL; +static int mode = 0; +static bool mimo_mode = true; +static const char* fmt_rx = "ci16"; +static const char* fmt_tx = "ci16"; + +static unsigned samples_rx = MAX_PATTERN; +static unsigned samples_tx = MAX_PATTERN; +static pusdr_dms_t usds_rx = NULL; +static pusdr_dms_t usds_tx = NULL; +static pusdr_dms_t strms[2] = { NULL, NULL }; +static FILE* files_r[2] = { NULL, NULL }; + +static float specific_rate = 10.0e6; +static unsigned maximum_iterations = 10; +static bool memcached = false; // Store data in RAM before doing processing + +static void dev_exit() +{ + exit(EXIT_FAILURE); +} + +static void dev_set_rate(unsigned rate) +{ + int res; + + for (unsigned k = 0; ; k ++) { + res = !dev ? 0 : usdr_dmr_rate_set(dev, NULL, rate); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device rate: errno %d", res); + + if (k == 10) + dev_exit(); + } else { + break; + } + } + + res = !dev ? 0 : usdr_dme_set_uint(dev, "/debug/hw/lms7002m/0/rxlml", mode); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device mode: errno %d", res); + dev_exit(); + } + + +} + +static void dev_set_vio(unsigned mv) +{ + int res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/vio", mv); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device LML VIO: errno %d", res); + dev_exit(); + } +} + +static void dev_set_rx_dly(unsigned type, unsigned val) +{ + unsigned mode = ((type) << 8) | val; + int res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/phy_rx_dly", mode); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device LML RX DLY: errno %d", res); + dev_exit(); + } +} + +static void dev_set_rx_phase(unsigned val) +{ + unsigned mode = val + 1; + int res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/rx/phase_ovr", mode); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device LML RX DLY: errno %d", res); + dev_exit(); + } +} + + +static void dev_deinit() +{ + if (dev == NULL) return; + int res; + + if (usds_rx) { + res = usdr_dms_op(usds_rx, USDR_DMS_STOP, 0); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to stop RX data stream: errno %d", res); + dev_exit(); + } + } + + if (usds_tx) { + res = usdr_dms_op(usds_tx, USDR_DMS_STOP, 0); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to stop TX data stream: errno %d", res); + dev_exit(); + } + } + + if (strms[1]) usdr_dms_destroy(strms[1]); + if (strms[0]) usdr_dms_destroy(strms[0]); + + usds_rx = usds_tx = NULL; + strms[0] = strms[1] = NULL; +} + +static void dev_init() +{ + if (dev == NULL) return; + + const char* synctype = "all"; + int res; + bool tx = (mode != LML_MODE_LFSR); + + usdr_channel_info_t chans_rx; + usdr_channel_info_t chans_tx; + + chans_rx.count = 2; + chans_rx.flags = 0; + chans_rx.phys_names = NULL; + chans_rx.phys_nums = NULL; + + chans_tx.count = 2; + chans_tx.flags = 0; + chans_tx.phys_names = NULL; + chans_tx.phys_nums = NULL; + + res = usdr_dms_create_ex2(dev, "/ll/srx/0", fmt_rx, &chans_rx, samples_rx, 0, NULL, &usds_rx); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to initialize RX data stream: errno %d", res); + dev_exit(); + } + + if (tx) { + res = usdr_dms_create_ex2(dev, "/ll/stx/0", fmt_tx, &chans_tx, samples_tx, 0, NULL, &usds_tx); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to initialize TX data stream: errno %d", res); + dev_exit(); + } + } else { + usds_tx = NULL; + } + + strms[1] = usds_tx; + strms[0] = usds_rx; + res = usdr_dms_sync(dev, "off", 2, strms); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to sync data streams: errno %d", res); + dev_exit(); + } + + //Start RX streaming + res = usdr_dms_op(usds_rx, USDR_DMS_START, 0); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to start RX data stream: errno %d", res); + dev_exit(); + } + + //Start TX streaming + if (tx) { + res = usdr_dms_op(usds_tx, USDR_DMS_START, 0); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to start TX data stream: errno %d", res); + dev_exit(); + } + } + + //Sync TX&RX data streams + res = usdr_dms_sync(dev, synctype, 2, strms); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to sync data streams: errno %d", res); + dev_exit(); + } +} + +void bits16_to_str(uint16_t v, char str[17]) +{ + for (unsigned h = 0; h < 16; h++) { + str[h] = '0' + (((v << h) & 0x8000) ? 1 : 0); + } + str[16] = 0; +} + +void bits32_to_str(uint32_t v, char str[33]) +{ + for (unsigned h = 0; h < 32; h++) { + str[h] = '0' + (((v << h) & 0x80000000) ? 1 : 0); + } + str[32] = 0; +} + + + +static uint32_t lfsr24_next(uint32_t lfsr) +{ + // Feedback taps: 24, 23, 22, 17 (zero-indexed: 23, 22, 21, 16) + uint32_t bit = ((lfsr >> 23) ^ (lfsr >> 22) ^ (lfsr >> 21) ^ (lfsr >> 16)) & 1; + lfsr = ((lfsr << 1) | bit); + return lfsr; +} + +static uint32_t lfsr16_next(uint32_t lfsr) { + // Feedback taps at 16, 14, 13, 11 (zero-indexed: 15, 13, 12, 10) + uint32_t bit = ((lfsr >> 15) ^ (lfsr >> 13) ^ (lfsr >> 12) ^ (lfsr >> 10)) & 1; + lfsr = ((lfsr << 1) | bit); + return lfsr; +} + +__attribute__((optimize("-O3"))) +static uint32_t lfsr15_next(uint32_t lfsr) { + // Feedback taps at 15 and 14 (zero-indexed: 14, 13) + uint32_t bit = ((lfsr >> 14) ^ (lfsr >> 13)) & 1; + lfsr = ((lfsr << 1) | bit); + return lfsr; +} + +static uint32_t lfsr14_next(uint32_t lfsr) { + // Feedback taps at 14, 13, 11, 10 (zero-indexed: 13, 12, 10, 9) + uint32_t bit = ((lfsr >> 13) ^ (lfsr >> 12) ^ (lfsr >> 10) ^ (lfsr >> 9)) & 1; + lfsr = ((lfsr << 1) | bit); + return lfsr; +} + +static uint32_t lfsr12_next(uint32_t lfsr) { + // Feedback taps at 12, 11, 10, 4 (zero-indexed: 11, 10, 9, 3) + uint32_t bit = ((lfsr >> 11) ^ (lfsr >> 10) ^ (lfsr >> 9) ^ (lfsr >> 3)) & 1; + lfsr = ((lfsr << 1) | bit); + return lfsr; +} + +static uint32_t lfsr8_next(uint32_t lfsr) { + // Feedback taps at 8, 6, 5, 4 (zero-indexed: 7, 5, 4, 3) + uint32_t bit = ((lfsr >> 7) ^ (lfsr >> 5) ^ (lfsr >> 4) ^ (lfsr >> 3)) & 1; + lfsr = ((lfsr << 1) | bit); + return lfsr; +} + +unsigned lfsr_off = 4; +unsigned lfsr_mask_ch = 0xffe; + +unsigned lfsr_g[2] = { 0, 0 }; +unsigned lfsr_r[2] = { 0, 0 }; +unsigned lfsr_xorm[2] = { 0, 1 }; + +struct lfsr_stream { + unsigned off; + unsigned mask_ch; + unsigned mask_lfsr; + + unsigned cnt_burst_good; + unsigned cnt_sync; // Number of sync + unsigned cnt_good; + unsigned cnt_resync; + unsigned xor_stage; + + unsigned state; // current state + unsigned next; // prediction for next + + bit_error_stat_t berr; +}; +typedef struct lfsr_stream lfsr_stream_t; + +void lfsr_init(lfsr_stream_t* d, unsigned off, unsigned m_check) +{ + d->off = off; + d->mask_ch = m_check; + d->mask_lfsr = m_check | 1; + + d->cnt_burst_good = 0; + d->cnt_resync = 0; + d->cnt_sync = 0; + d->xor_stage = 0; + + d->state = 0; + d->next = 0; + + bit_error_init(&d->berr); +} + +enum { + FLAGS_ERRORS = 1, + FLAGS_VERBOSE = 2, +}; + +__attribute__((optimize("-O3"))) +static void dump_lfsr_complex(const char* prefix, lfsr_stream_t* d, const uint16_t* pattern, unsigned sps_count, unsigned flags) +{ + char str[2][17]; + char str_f[2][33]; + bool show_error = (flags & FLAGS_ERRORS) == FLAGS_ERRORS; + bool verbose = (flags & FLAGS_VERBOSE) == FLAGS_VERBOSE; + + for (unsigned p = 0; p < sps_count; p++) { + unsigned a[2]; + bool match[2]; + + for (unsigned j = 0; j < 2; j++) { + a[j] = pattern[2 * p + j] >> d[j].off; + + if (d[j].cnt_burst_good == 0) { + // Resync + d[j].state = a[j]; + d[j].cnt_burst_good++; + } else { + + d[j].state <<= 1; + + if ((d[j].state & d[j].mask_ch) == (a[j] & d[j].mask_ch)) { + d[j].state |= a[j]; + d[j].cnt_burst_good++; + d[j].cnt_sync++; + } else if (d[j].cnt_sync < 20) { + // Bit error burins sync + d[j].state |= (a[j] & 1); + d[j].cnt_sync++; + } else { + unsigned bcnt = bit_error_check(&d[j].berr, a[j] & d->mask_lfsr, d[j].state & d->mask_lfsr); + if (bcnt >= 6) { + // Looks like we lost LFSR sync + d[j].state = 0; + d[j].cnt_resync++; + d[j].cnt_burst_good = 0; + d[j].cnt_sync = 0; + } else { + // Recover single bits error to continue checking BER + d[j].state = lfsr15_next(d[j].state >> 1) ^ d[j].xor_stage; + } + } + } + + match[j] = d[j].next == d[j].state; + d[j].next = lfsr15_next(d[j].state) ^ d[j].xor_stage; + } + + if ((show_error || verbose) && (!match[0] || !match[1] || verbose)) { + for (unsigned j = 0; j < 2; j++) { + bits16_to_str(a[j], str[j]); + bits32_to_str(d[j].state, str_f[j]); + } + + fprintf(stderr, "%s%3d: [%04x %04x]: %s %s -- [%08x %08x]: %s %s [%08x %08x] %c%c\n", prefix, p, a[0], a[1], str[0], str[1], + d[0].state, d[1].state, str_f[0], str_f[1], d[0].next, d[1].next, + match[0] ? '+' : '-', match[1] ? '+' : '-'); + } + + } +} + +static void do_receive_rst() +{ + if (d_pattern_r0 == NULL) { + d_pattern_r0 = malloc(2 * sizeof(uint16_t) * samples_rx * maximum_iterations); + } + if (d_pattern_r1 == NULL) { + d_pattern_r1 = malloc(2 * sizeof(uint16_t) * samples_rx * maximum_iterations); + } + + if (d_pattern_r0 == NULL || d_pattern_r1 == NULL) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "NOT ENOUGH MEMORY\n"); + dev_exit(); + } + + d_off = 0; +} +static int do_receive(bool do_rcv, void* buffers[MAX_CHS]) +{ + usdr_dms_recv_nfo_t rxstat; + int res = 0; + buffers[0] = memcached ? d_pattern_r0 + 2 * d_off : s_pattern_r0; + buffers[1] = memcached ? d_pattern_r1 + 2 * d_off : s_pattern_r1; + + d_off += samples_rx; + + if (!do_rcv) + return 0; + + res = usdr_dms_recv(strms[0], buffers, 2250, &rxstat); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "RX error, unable to recv data: errno %d", res); + return res; + } + + fprintf(stderr, "."); + for (unsigned i = 0; i < num_rx; i++) { + if (files_r[i]) { + fwrite(buffers[i], 2 * samples_rx, 1, files_r[i]); + } + } + + + return 0; +} + +enum { + IDX_AI, + IDX_AQ, + IDX_BI, + IDX_BQ, +}; +#define TOTAL_STREAMS 4 + + +void do_lfsr_test(lfsr_stream_t str[TOTAL_STREAMS]) +{ + int res; + unsigned flags = 0; //FLAGS_ERRORS; + for (unsigned i = 0; i < TOTAL_STREAMS; i++) { + lfsr_init(&str[i], 4, 0xffe); + str[i].xor_stage = i & 1; // LML interface invert bit in LFSR stream for Q components + } + + for (unsigned k = 0; k < (memcached ? 2 : 1); k++) { + if (k == 1) { + fprintf(stderr, "\nChecking..."); + } + do_receive_rst(); + + for (unsigned cnt = 0; cnt < maximum_iterations; cnt++) { + bool do_rcv = !memcached || (k == 0); + bool do_chk = !memcached || (k == 1); + void* buffers[MAX_CHS]; + + res = do_receive(do_rcv, buffers); + if (res) { + return; + } + + // Do inplace checks (for low samplerate) + if (do_chk) { + dump_lfsr_complex("A", &str[0], buffers[0], samples_rx, flags); + dump_lfsr_complex("B", &str[2], buffers[1], samples_rx, flags); + } + } + } + + + fprintf(stderr, "\n==============================================================\n"); + //Total statisics + const char* ch_names[TOTAL_STREAMS] = { "AI", "AQ", "BI", "BQ" }; + for (unsigned i = 0; i < TOTAL_STREAMS; i++) { + unsigned rest = 0; + for (unsigned k = 5; k < 16; k++) { + rest += str[i].berr.bit_errors[k]; + } + fprintf(stderr, " %s: Resync %8d [%8d %8d %8d %8d -- %8d]\n", + ch_names[i], str[i].cnt_resync, + str[i].berr.bit_errors[1], str[i].berr.bit_errors[2], str[i].berr.bit_errors[3], str[i].berr.bit_errors[4], rest); + for (unsigned j = 0; j < 16; j++) { + if (str[i].berr.bit_pos_errors[j]) { + fprintf(stderr, " %s: BITp[%2d]: %8d\n", ch_names[i], j, str[i].berr.bit_pos_errors[j]); + } + } + } +} + + +#define MAX_TAPS 64 + +void lfsr_tests() +{ + mode = LML_MODE_LFSR; + lfsr_stream_t str[MAX_TAPS][TOTAL_STREAMS]; + + dev_set_vio(2300); + float rate = specific_rate; + dev_set_rate(rate); + + // looks like MCLK comes later, we need to delay all the data + for (unsigned k = 0; k < MAX_TAPS; k++) { + dev_init(); + +#if 0 + dev_set_rx_dly(0, 0); // CLK + dev_set_rx_dly(1, k); // FRAME + for (unsigned h = 0; h < 12; h++) { + dev_set_rx_dly(h + 2, k); // D0 + } +#else + dev_set_rx_phase(k); // CLK + dev_set_rate(rate); +#endif + do_lfsr_test(str[k]); + + dev_deinit(); + } + + fprintf(stderr, "\nX_BITXX: "); + for (unsigned k = 0; k < MAX_TAPS; k++) { + fprintf(stderr, (MAX_TAPS <= 32) ? "%6d" : "%3d", k); + } + fprintf(stderr, "\nX_BITXX: "); + for (unsigned k = 0; k < MAX_TAPS; k++) { + float period = 1e9 / specific_rate / 2; + float off = 0.078 * k; + unsigned p = 1000 * off / period; + + fprintf(stderr, (MAX_TAPS <= 32) ? "%6d" : "%3d", p); + } + + // Individual bit errors first + // Total bit error distribution + for (unsigned h = 0; h < 2; h++) { + for (unsigned j = 0; j < 4; j++) { + for (unsigned b = 0; b < 12; b++) { + fprintf(stderr, "\n%d_BIT%c%2d: ", j, h == 0 ? 'p' : 't', b); + for (unsigned k = 0; k < MAX_TAPS; k++) { + unsigned ecnt = (h == 0) ? str[k][j].berr.bit_pos_errors[b] : str[k][j].berr.bit_errors[b + 1]; + + if (MAX_TAPS <= 32) { + if (ecnt <= 999999) { + fprintf(stderr, "%6d", ecnt); + } else { + fprintf(stderr, (k % 2) ? "xxxxxx" : "XXXXXX"); + } + } else if (MAX_TAPS <= 64) { + if (ecnt <= 999) { + fprintf(stderr, "%3d", ecnt); + } else { + fprintf(stderr, (k % 2) ? "xxx" : "XXX"); + } + } else { + if (ecnt <= 9) { + fprintf(stderr, "%1d", ecnt); + } else { + fprintf(stderr, (k % 2) ? "x" : "X"); + } + } + } + } + } + fprintf(stderr, "\n================== distribution of total bit errors =============================="); + } + fprintf(stderr, "\n"); + +} + + +int main(int argc, char** argv) +{ + bool dry_run = false; + float sbit_err_p = 0.0; // Emulation + float mbit_err_p = 0.0; // Emulation + + unsigned specific_test = 0; + + const char* device_name = NULL; + unsigned loglevel = USDR_LOG_INFO; + + unsigned statistics = 0; + + + bool dump_rx = false; + int opt, res; + + while ((opt = getopt(argc, argv, "Mi:r:j:D:t:l:do")) != -1) { + switch (opt) { + case 'M': + memcached = true; + break; + case 'i': + maximum_iterations = atoi(optarg); + break; + case 'r': + specific_rate = atof(optarg); + break; + case 'j': + statistics = atoi(optarg); + break; + case 'D': + device_name = optarg; + break; + case 't': + specific_test = atoi(optarg); + break; + case 'l': + loglevel = atof(optarg); + usdrlog_setlevel(NULL, loglevel); + break; + case 'd': + dry_run = true; + break; + case 'o': + dump_rx = true; + break; + default: + exit(EXIT_FAILURE); + } + } + + usdrlog_setlevel(NULL, loglevel); + // Check if is tty + usdrlog_enablecolorize(NULL); + + //Open device & create dev handle + res = dry_run ? 0 : usdr_dmd_create_string(device_name, &dev); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to create device: errno %d", res); + return 1; + } + + if (dump_rx) { + for (unsigned i = 0; i < num_rx; i++) { + files_r[i] = fopen(i == 0 ? "out_lml7_0.dat" : "out_lml7_1.dat", "wb+c"); + if (!files_r[i]) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to create RX storage data file!\n"); + return 3; + } + } + } + + + // Tests + lfsr_tests(); + + res = dry_run ? 0 : usdr_dmd_close(dev); + return res; +} + + + + + + + + From 61ecff3f4fdc73d831495d9037bf953bfafded85 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 16 Jun 2025 15:36:16 +0400 Subject: [PATCH 166/397] dsdr: wait tps6381x PG signal --- src/lib/device/m2_dsdr/m2_dsdr.c | 19 ++++++++++++++++++- src/lib/hw/tps6381x/tps6381x.c | 7 +++++++ src/lib/hw/tps6381x/tps6381x.h | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index fc282b7b..e5633673 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1414,15 +1414,32 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } if (d->type == DSDR_M2_R0) { + bool pg; for (unsigned j = 0; j < 20; j++) { usleep(10000); res = res ? res : tps6381x_init(dev, d->subdev, I2C_TPS63811, true, true, 3450); if (res == 0) break; } + if (res) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "Unable to intialize tps6381x booster!\n"); + return res; + } + + for (unsigned j = 0; j < 20; j++) { + res = res ? res : tps6381x_check_pg(dev, d->subdev, I2C_TPS63811, &pg); + if (!res || pg) { + break; + } + usleep(20000); + } + if (!pg) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "No PG signal in tps6381x booster!\n"); + return -EIO; + } } - usleep(200000); //TODO monitor power good signal!!! + usleep(20000); res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0xff); // diff --git a/src/lib/hw/tps6381x/tps6381x.c b/src/lib/hw/tps6381x/tps6381x.c index e4debc06..b30a00ce 100644 --- a/src/lib/hw/tps6381x/tps6381x.c +++ b/src/lib/hw/tps6381x/tps6381x.c @@ -33,6 +33,13 @@ static int tps6381x_reg_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, 0, NULL, 2, &tv); } +int tps6381x_check_pg(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, bool* ppg) +{ + uint8_t reg_status = 0xff; + int res = tps6381x_reg_get(dev, subdev, ls_op_addr, STATUS, ®_status); + *ppg = (reg_status == 0x00); + return res; +} int tps6381x_init(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, bool enable, bool force_pwm, int vout_mv) diff --git a/src/lib/hw/tps6381x/tps6381x.h b/src/lib/hw/tps6381x/tps6381x.h index 5afaf880..c48dd8f4 100644 --- a/src/lib/hw/tps6381x/tps6381x.h +++ b/src/lib/hw/tps6381x/tps6381x.h @@ -6,6 +6,7 @@ #include +int tps6381x_check_pg(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, bool* ppg); int tps6381x_init(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, bool enable, bool force_pwm, int vout_mv); From 68a2150bdb428d5e7326872d2d6f546497d06879 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 16 Jun 2025 15:37:35 +0400 Subject: [PATCH 167/397] ssdr/xsdr: automatic MMCM RX calibration --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 30 +++++++- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 114 ++++++++++++++++++++++------ src/lib/device/m2_lm7_1/xsdr_ctrl.h | 8 ++ src/lib/hw/lms7002m/lms7002m.c | 14 +--- src/lib/ipblks/xlnx_mmcm.c | 12 +-- src/tools/lms7002_dm_limelight.c | 76 ++++++++++++++++++- 6 files changed, 208 insertions(+), 46 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index d08f6555..1d5bb334 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -221,6 +221,9 @@ static int dev_m2_lm7_1_dev_dac_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, ui static int dev_m2_lm7_1_phyrxlm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_phy_rx_lfsr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_phy_rx_lfsr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); + static int dev_m2_lm7_1_lms7002rxlml_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -316,7 +319,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/dac_vctcxo", { dev_m2_lm7_1_dev_dac_vctcxo_set, NULL }}, - { "/dm/sdr/0/phy_rx_dly", { dev_m2_lm7_1_phy_rx_dly_set, NULL }}, + { "/dm/sdr/0/phy_rx_dly", { dev_m2_lm7_1_phy_rx_dly_set, NULL }}, + { "/dm/sdr/0/phy_rx_lfsr", { dev_m2_lm7_1_phy_rx_lfsr_set, dev_m2_lm7_1_phy_rx_lfsr_get }}, { "/dm/sdr/0/phyrxlml", { dev_m2_lm7_1_phyrxlm_set, NULL }}, { "/debug/hw/lms7002m/0/rxlml", { dev_m2_lm7_1_lms7002rxlml_set, NULL }}, @@ -369,6 +373,30 @@ int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu return xsdr_config_rcvdly(&((struct dev_m2_lm7_1_gps *)ud)->xdev, type, val); } +int dev_m2_lm7_1_phy_rx_lfsr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return xsdr_phy_en_lfsr_mimo(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value ? true : false); +} + +int dev_m2_lm7_1_phy_rx_lfsr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + uint32_t v[4]; + uint64_t val = 0; + int res = xsdr_phy_lfsr_mimo_state(&((struct dev_m2_lm7_1_gps *)ud)->xdev, LFSR_CNTR_BER, v); + if (res) + return res; + + for (unsigned i = 0; i < 4; i++) { + uint64_t k = v[i]; + if (k > UINT16_MAX) { + k = UINT16_MAX; + } + val |= k << (16 * i); + } + *ovalue = val; + return 0; +} + int dev_m2_lm7_1_lms7002rxlml_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { return lms7002m_set_lmlrx_mode(&((struct dev_m2_lm7_1_gps *)ud)->xdev.base, value); diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index e4fbf5c7..f0ccc7d3 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -165,7 +165,7 @@ int xsdr_phy_rx_reg(xsdr_dev_t *d, bool wr, uint8_t bank, uint8_t addr, uint16_t return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, reg); } -static int xsdr_phy_en_lfsr_mimo(xsdr_dev_t *d, bool en) +int xsdr_phy_en_lfsr_mimo(xsdr_dev_t *d, bool en) { int res = 0; if (!en) { @@ -177,6 +177,20 @@ static int xsdr_phy_en_lfsr_mimo(xsdr_dev_t *d, bool en) return res; } +int xsdr_phy_lfsr_mimo_state(xsdr_dev_t *d, int type, uint32_t v[4]) +{ + int res = 0; + // Get BER statistics + for (unsigned h = 0; h < 4; h++) { + unsigned p = ((type & 0x3) << 2) | (h); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + res = res ? res : usleep(1); + res = res ? res : lowlevel_reg_rd32(d->base.lmsstate.dev, 0, REG_CFG_PHY_0, &v[h]); + } + + return res; +} + int xsdr_phy_tx_reg(xsdr_dev_t *d, uint8_t addr, uint32_t val) { return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_1, (((uint32_t)addr) << 24) | (val & 0xffffff)); @@ -216,7 +230,7 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, if (res) return res; - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM DRP_TX CMD=%08x RB=%08x\n", drp_cmd, rb); + USDR_LOG("XDEV", USDR_LOG_DEBUG, "MMCM DRP_TX CMD=%08x RB=%08x\n", drp_cmd, rb); if (meminsz) { *((uint16_t*)pin) = rb >> 16; @@ -245,7 +259,7 @@ int xsdr_upd_phase(xsdr_dev_t *d) return 0; } -int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) +int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, unsigned rxphase) { bool nomul = d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); unsigned tx_mclk = d->base.cgen_clk / d->base.txcgen_div / d->base.lml_mode.txdiv; @@ -317,8 +331,8 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) cfg_raw.ports[CLKOUT_PORT_6].delay = raw / 8; } - if (d->rx_override_phase) { - unsigned raw = d->rx_override_phase - 1; + if (d->rx_override_phase || rxphase) { + unsigned raw = (rxphase != 0) ? rxphase - 1 : d->rx_override_phase - 1; cfg_raw.ports[CLKOUT_PORT_2].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_2].delay = raw / 8; } @@ -339,30 +353,32 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d) res = res ? res : mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &cfg_raw); - - // Reset MMCM res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 1); usleep(10); res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); + if (res) + return res; for (unsigned k = 0; k < 10; k++) { - // Wait for lock uint32_t rb; + + // Wait for lock res = res ? res : lowlevel_reg_rd32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_1, &rb); if (res) break; - USDR_LOG("XDEV", USDR_LOG_INFO, "MMCM FLAGS:%08x\n", rb); - if (rb & (1 << 8)) + USDR_LOG("XDEV", USDR_LOG_DEBUG, "MMCM FLAGS:%08x\n", rb); + if (rb & (1 << 8)) { + g_tx_cfg_raw = cfg_raw; return 0; + } usleep(5000); } - g_tx_cfg_raw = cfg_raw; - return res; + return -EIO; } int xsdr_configure_lml_mmcm_rx(xsdr_dev_t *d) @@ -482,6 +498,14 @@ enum { PHY_CFG_RX_MMCM = 0x10, }; +static bool noerrors_v4(unsigned errs[4], uint64_t* badness) +{ + if (badness) { + *badness = (errs[0]*errs[0]) + (errs[1]*errs[1]) + (errs[2]*errs[2]) + (errs[3]*errs[3]); + } + return errs[0] == 0 && errs[1] == 0 && errs[2] == 0 && errs[3] == 0; +} + int xsdr_set_samplerate_ex(xsdr_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, @@ -573,7 +597,60 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); if (tx_mmcm) { - res = res ? res : xsdr_configure_lml_mmcm_tx(d); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, 0); + + // Autocalibration if RX phase wasn't set + if (d->rx_override_phase == 0) { + + // Boost IO voltage for stable high speed link + if (!d->siso_sdr_active_rx && d->new_rev && rxrate > 85e6) { + res = res ? res : xsdr_set_vio(d, 1910); + } + + unsigned errs[4] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX }; + uint64_t badness; + uint64_t badness_m = UINT64_MAX; + unsigned phase_m = 0; + + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_lfsr_mimo(d, true); + res = res ? res : usleep(5000); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=AUTO [%d/%d/%d/%d]\n", + errs[0], errs[1], errs[2], errs[3]); + if (res || noerrors_v4(errs, &badness_m)) + goto phase_calibrated; + + for (unsigned ph = 1; ph < 64; ph++) { + res = res ? res : usleep(10); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, ph); + res = res ? res : xsdr_phy_en_lfsr_mimo(d, true); + res = res ? res : usleep(5000); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=%d [%d/%d/%d/%d]\n", ph - 1, + errs[0], errs[1], errs[2], errs[3]); + if (res || noerrors_v4(errs, &badness)) + goto phase_calibrated; + + if (badness < badness_m) { + badness = badness_m; + phase_m = ph; + } + } + + USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring pahse to %d (bandness=%" PRId64 ")\n", + phase_m, badness_m); + + // Try our best at least + res = res ? res : xsdr_configure_lml_mmcm_tx(d, phase_m); +phase_calibrated: + res = res ? res : xsdr_phy_en_lfsr_mimo(d, false); + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); + ; + } } else { unsigned dly = (d->tx_override_phase) ? (d->tx_override_phase - 1) : 3; @@ -581,17 +658,6 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, } } - - xsdr_phy_en_lfsr_mimo(d, true); -/* - - xsdr_config_rcvdly(d, 1, (rxrate >= 65e6) ? 21 : 0); // D0 - for (unsigned h = 0; h < 12; h++) { - xsdr_config_rcvdly(d, 2 + h, (rxrate >= 65e6) ? 21 : 0); // D0 - } - -*/ - return res; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 29fa247e..a750d48c 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -153,6 +153,14 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int //int (*set_tx_testsig_fs8)(void* param, int channel); +int xsdr_phy_en_lfsr_mimo(xsdr_dev_t *d, bool en); +enum lfsr_cntr_types { + LFSR_CNTR_SYNC = 0, + LFSR_CNTR_LOST = 1, + LFSR_CNTR_BER = 2, +}; + +int xsdr_phy_lfsr_mimo_state(xsdr_dev_t *d, int type, uint32_t v[4]); int xsdr_phy_tune_rx(xsdr_dev_t *d, unsigned val); int xsdr_clk_debug_info(xsdr_dev_t *d); diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index d35ffeff..a255c7f1 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -395,7 +395,7 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t (params.txdiv > 1) ? 1u : 0, (params.rxdiv > 1) ? 1u : 0), MAKE_LMS7002M_LML_0x002C( params.txdiv / 2u - 1u, params.rxdiv / 2u - 1u ), - MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, params.rxdiv == 1 ? 0 : 1, 1, 1), + MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, params.rxsisoddr && params.rxdiv == 1 ? 0 : 1, 1, 1), MAKE_LMS7002M_CDS_0x00AE(3, 3, 0, 0, 0, 0, 0, 0), MAKE_LMS7002M_REG_WR(LML_0x0020, reg_mac), MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac) @@ -404,18 +404,6 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); } -/* -int lms7002m_cds_set(lms7002m_state_t* m, bool rxalml, bool rxblml) -{ - uint32_t regs[] = { - // 0x80AD03ff ^ ((rxalml ? 1 : 0) << 2) , //^ ((rxblml ? 1 : 0) << 3), - 0x80AD03ff ^ ((rxalml ? 1 : 0) << 2), - 0x80AE0C00, - }; - return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); -} -*/ - int _lms7002m_fill_pos(lms7002m_lml_map_t l, lms7002m_lml_map_t* o) { lms7002m_lml_map_t p = {{0, 0, 0, 0}}; diff --git a/src/lib/ipblks/xlnx_mmcm.c b/src/lib/ipblks/xlnx_mmcm.c index acb2596e..7c872510 100644 --- a/src/lib/ipblks/xlnx_mmcm.c +++ b/src/lib/ipblks/xlnx_mmcm.c @@ -77,11 +77,13 @@ int mmcm_init_raw_clkout(lldev_t dev, subdev_t subdev, if (res) return res; - USDR_LOG("MMCM", USDR_LOG_ERROR, " CLKREG %02x OLD: PHASE=%d HIGH=%d LOW=%d | MX=%d EDGE=%d NO_CNT=%d DELAY=%d\n", - clkout_reg, - (clk1_reg_old >> 13) & 0x7, (clk1_reg_old >> 6) & 0x3f, clk1_reg_old & 0x3f, - (clk2_reg_old >> 8) & 0x3, (clk2_reg_old >> 7) & 1, (clk2_reg_old >> 6) & 1, - (clk2_reg_old & 0x3f)); + USDR_LOG("MMCM", USDR_LOG_NOTE, " CLKREG %02x OLD: PHASE=%d HIGH=%d LOW=%d MX=%d EDGE=%d NO_CNT=%d DELAY=%2d | NEW: PHASE=%d HIGH=%d LOW=%d MX=%d EDGE=%d NO_CNT=%d DELAY=%2d\n", + clkout_reg, + (clk1_reg_old >> 13) & 0x7, (clk1_reg_old >> 6) & 0x3f, clk1_reg_old & 0x3f, + (clk2_reg_old >> 8) & 0x3, (clk2_reg_old >> 7) & 1, (clk2_reg_old >> 6) & 1, (clk2_reg_old & 0x3f), + (clk1_reg_out >> 13) & 0x7, (clk1_reg_out >> 6) & 0x3f, clk1_reg_out & 0x3f, + (clk2_reg_out >> 8) & 0x3, (clk2_reg_out >> 7) & 1, (clk2_reg_out >> 6) & 1, (clk2_reg_out & 0x3f) + ); return 0; } diff --git a/src/tools/lms7002_dm_limelight.c b/src/tools/lms7002_dm_limelight.c index b45f6f6d..40cd495d 100644 --- a/src/tools/lms7002_dm_limelight.c +++ b/src/tools/lms7002_dm_limelight.c @@ -264,6 +264,28 @@ static void dev_set_rx_phase(unsigned val) } } +static void dev_set_rx_lfsr_hw_checker(bool en) +{ + int res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/phy_rx_lfsr", en); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set HW LFSR Checker: errno %d", res); + dev_exit(); + } +} + +static void dev_get_rx_lfsr_hw_checker(unsigned errs[4]) +{ + uint64_t v = 0; + int res = !dev ? 0 : usdr_dme_get_uint(dev, "/dm/sdr/0/phy_rx_lfsr", &v); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to get HW LFSR BER: errno %d", res); + dev_exit(); + } + + for (unsigned j = 0; j < 4; j++) { + errs[j] = (v >> (j * 16)) & 0xffff; + } +} static void dev_deinit() { @@ -645,6 +667,47 @@ void do_lfsr_test(lfsr_stream_t str[TOTAL_STREAMS]) #define MAX_TAPS 64 +void do_lfsr_hw_test(unsigned str[TOTAL_STREAMS]) +{ + dev_set_rx_lfsr_hw_checker(true); + usleep(1000 * maximum_iterations); + dev_get_rx_lfsr_hw_checker(str); +} + +void lfsr_test_hw() +{ + mode = LML_MODE_LFSR; + + float rate = specific_rate; + dev_set_rate(rate); + unsigned str[MAX_TAPS][TOTAL_STREAMS]; + + for (unsigned k = 0; k < MAX_TAPS; k++) { + dev_init(); + + dev_set_rx_phase(k); // CLK + dev_set_rate(rate); + + do_lfsr_hw_test(str[k]); + + dev_deinit(); + } + + for (unsigned j = 0; j < 4; j++) { + fprintf(stderr, "CH%d: ", j); + + for (unsigned k = 0; k < MAX_TAPS; k++) { + unsigned ecnt = str[k][j]; + + fprintf(stderr, "%c", (ecnt == 0) ? ' ' : (ecnt < 1000) ? 'x' : 'X'); + } + + fprintf(stderr, "\n"); + } + + +} + void lfsr_tests() { mode = LML_MODE_LFSR; @@ -737,11 +800,11 @@ int main(int argc, char** argv) unsigned statistics = 0; - + bool hw_tests = false; bool dump_rx = false; int opt, res; - while ((opt = getopt(argc, argv, "Mi:r:j:D:t:l:do")) != -1) { + while ((opt = getopt(argc, argv, "Mi:r:j:D:t:l:dow")) != -1) { switch (opt) { case 'M': memcached = true; @@ -771,6 +834,9 @@ int main(int argc, char** argv) case 'o': dump_rx = true; break; + case 'w': + hw_tests = true; + break; default: exit(EXIT_FAILURE); } @@ -799,7 +865,11 @@ int main(int argc, char** argv) // Tests - lfsr_tests(); + if (hw_tests) { + lfsr_test_hw(); + } else { + lfsr_tests(); + } res = dry_run ? 0 : usdr_dmd_close(dev); return res; From ae856da7e12d6c06d16dcd6333df94bdef7ac0ab Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 17 Jun 2025 11:28:32 +0400 Subject: [PATCH 168/397] xsdr/ssdr: improve LML RX calibration speed --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 34 +++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index f0ccc7d3..ac1b92dd 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -224,7 +224,7 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, if (res || (!(rb & (1 << 9)))) break; - usleep(1000); + usleep(10); } if (res) @@ -375,7 +375,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, unsigned rxphase) return 0; } - usleep(5000); + usleep(500); } return -EIO; @@ -601,6 +601,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, // Autocalibration if RX phase wasn't set if (d->rx_override_phase == 0) { + const unsigned check_to = 10; // Boost IO voltage for stable high speed link if (!d->siso_sdr_active_rx && d->new_rev && rxrate > 85e6) { @@ -608,15 +609,20 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, } unsigned errs[4] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX }; - uint64_t badness; + uint64_t badness_m = UINT64_MAX; unsigned phase_m = 0; + unsigned c; res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); res = res ? res : usleep(10); res = res ? res : xsdr_phy_en_lfsr_mimo(d, true); - res = res ? res : usleep(5000); - res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + for (c = 0; c < check_to; c++) { + res = res ? res : usleep(1000); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || !noerrors_v4(errs, &badness_m)) + break; + } USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=AUTO [%d/%d/%d/%d]\n", errs[0], errs[1], errs[2], errs[3]); @@ -624,14 +630,24 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, goto phase_calibrated; for (unsigned ph = 1; ph < 64; ph++) { + unsigned w; + uint64_t badness = UINT64_MAX; + res = res ? res : usleep(10); res = res ? res : xsdr_configure_lml_mmcm_tx(d, ph); res = res ? res : xsdr_phy_en_lfsr_mimo(d, true); - res = res ? res : usleep(5000); - res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=%d [%d/%d/%d/%d]\n", ph - 1, - errs[0], errs[1], errs[2], errs[3]); + for (w = 0; w < check_to; w++) { + res = res ? res : usleep(1000); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || !noerrors_v4(errs, &badness)) { + break; + } + } + badness *= 1.0 * check_to / (w + 1); // Rescale + + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%.3e\n", ph - 1, w, + errs[0], errs[1], errs[2], errs[3], (double)badness); if (res || noerrors_v4(errs, &badness)) goto phase_calibrated; From cc6fd7453761af95bcdc30bbc769feb7f61489d0 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 20 Jun 2025 18:02:12 +0300 Subject: [PATCH 169/397] Limiting unit-test: lmk05318 only, &lmk05318_customer_test1 --- src/utests/lmk05318_solver_test.c | 28 ++++++++++++++++++++++++++-- src/utests/test_suite.c | 4 +++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index a3cc94dc..678c5277 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -439,6 +439,28 @@ START_TEST(lmk05318_hyper_test1) ck_assert_int_eq( res, 0 ); } +START_TEST(lmk05318_customer_test1) +{ + int res = 0; + + lmk05318_out_config_t* p = &cfg[0]; + + res = res ? res : lmk05318_port_request(p++, 0, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 1, 491520000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 2, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 3, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 4, 312500000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 5, 245760000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 6, 3840000, false, LVDS); + res = res ? res : lmk05318_port_request(p++, 7, 245760000, false, LVDS); + ck_assert_int_eq( res, 0 ); + + lmk05318_state_t st; + res = lmk05318_create(NULL, 0, 0, 52000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); + ck_assert_int_eq( res, 0 ); +} + + Suite * lmk05318_solver_suite(void) { Suite *s; @@ -448,7 +470,7 @@ Suite * lmk05318_solver_suite(void) tc_core = tcase_create("HW"); tcase_set_timeout(tc_core, 1); tcase_add_checked_fixture(tc_core, setup, teardown); - +/* tcase_add_test(tc_core, lmk05318_solver_test1); tcase_add_test(tc_core, lmk05318_solver_test3); tcase_add_test(tc_core, lmk05318_solver_test4); @@ -461,7 +483,9 @@ Suite * lmk05318_solver_suite(void) tcase_add_test(tc_core, lmk05318_dsdr_test3); tcase_add_test(tc_core, lmk05318_simplesync_test1); tcase_add_test(tc_core, lmk05318_solver_test_xmass); - tcase_add_test(tc_core, lmk05318_hyper_test1); + tcase_add_test(tc_core, lmk05318_hyper_test1); */ + + tcase_add_test(tc_core, lmk05318_customer_test1); suite_add_tcase(s, tc_core); return s; diff --git a/src/utests/test_suite.c b/src/utests/test_suite.c index eb1f4209..6abfd781 100644 --- a/src/utests/test_suite.c +++ b/src/utests/test_suite.c @@ -28,7 +28,7 @@ int main(int argc, char** argv) fprintf(stderr, "Running with %s CPU features\n", buffer); usdrlog_setlevel(NULL, (argc > 1) ? USDR_LOG_TRACE : USDR_LOG_INFO); usdrlog_enablecolorize(NULL); - +/* sr = srunner_create(ring_buffer_suite()); srunner_add_suite(sr, trig_suite()); srunner_add_suite(sr, clockgen_suite()); @@ -36,6 +36,8 @@ int main(int argc, char** argv) srunner_add_suite(sr, lmx2820_solver_suite()); srunner_add_suite(sr, lmx1214_solver_suite()); srunner_add_suite(sr, lmx1204_solver_suite()); +*/ + sr = srunner_create(lmk05318_solver_suite()); srunner_set_fork_status (sr, CK_NOFORK); From c39d7cf97315f18b4cfc5b859e793f56f29b117a Mon Sep 17 00:00:00 2001 From: vd <33198864+vd2org@users.noreply.github.com> Date: Thu, 26 Jun 2025 19:01:40 +0400 Subject: [PATCH 170/397] Updated build version from main. --- packaging/debian-bookworm/changelog | 4 ++-- packaging/debian-bookworm/control | 2 +- packaging/ubuntu-bionic/changelog | 4 ++-- packaging/ubuntu-bionic/control | 2 +- packaging/ubuntu-focal/changelog | 4 ++-- packaging/ubuntu-focal/control | 2 +- packaging/ubuntu-jammy/changelog | 4 ++-- packaging/ubuntu-jammy/control | 2 +- packaging/ubuntu-noble/changelog | 4 ++-- packaging/ubuntu-noble/control | 2 +- src/Changelog.txt | 5 +++++ 11 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packaging/debian-bookworm/changelog b/packaging/debian-bookworm/changelog index ce33f529..29aeeb4c 100644 --- a/packaging/debian-bookworm/changelog +++ b/packaging/debian-bookworm/changelog @@ -1,5 +1,5 @@ -usdr (0.9.9~bookworm0) stable; urgency=low +usdr (0.9.10b~bookworm0) stable; urgency=low * Fixes and improvements - -- Ivan Kolesnikov Sun, 30 Jan 2025 00:00:00 +0000 + -- Ivan Kolesnikov Thu, 26 Jun 2025 00:00:00 +0000 diff --git a/packaging/debian-bookworm/control b/packaging/debian-bookworm/control index 762a98c0..fd306b65 100644 --- a/packaging/debian-bookworm/control +++ b/packaging/debian-bookworm/control @@ -2,7 +2,7 @@ Source: usdr Section: misc Priority: optional Maintainer: Ivan Kolesnikov -Standards-Version: 0.9.9 +Standards-Version: 0.9.10b Homepage: https://github.com/wavelet-lab/usdr-lib Vcs-Browser: https://github.com/wavelet-lab/usdr-lib Vcs-Git: https://github.com/wavelet-lab/usdr-lib.git diff --git a/packaging/ubuntu-bionic/changelog b/packaging/ubuntu-bionic/changelog index b883a498..e0128cee 100644 --- a/packaging/ubuntu-bionic/changelog +++ b/packaging/ubuntu-bionic/changelog @@ -1,5 +1,5 @@ -usdr (0.9.9~bionic0) bionic; urgency=low +usdr (0.9.10b~bionic0) bionic; urgency=low * Fixes and improvements - -- Ivan Kolesnikov Sun, 30 Jan 2025 00:00:00 +0000 + -- Ivan Kolesnikov Thu, 26 Jun 2025 00:00:00 +0000 diff --git a/packaging/ubuntu-bionic/control b/packaging/ubuntu-bionic/control index 7b2c6d56..5ed65dc3 100644 --- a/packaging/ubuntu-bionic/control +++ b/packaging/ubuntu-bionic/control @@ -2,7 +2,7 @@ Source: usdr Section: misc Priority: optional Maintainer: Ivan Kolesnikov -Standards-Version: 0.9.9 +Standards-Version: 0.9.10b Homepage: https://github.com/wavelet-lab/usdr-lib Vcs-Browser: https://github.com/wavelet-lab/usdr-lib Vcs-Git: https://github.com/wavelet-lab/usdr-lib.git diff --git a/packaging/ubuntu-focal/changelog b/packaging/ubuntu-focal/changelog index 899b3a53..cd3f1604 100644 --- a/packaging/ubuntu-focal/changelog +++ b/packaging/ubuntu-focal/changelog @@ -1,5 +1,5 @@ -usdr (0.9.9~focal0) focal; urgency=low +usdr (0.9.10b~focal0) focal; urgency=low * Fixes and improvements - -- Ivan Kolesnikov Sun, 30 Jan 2025 00:00:00 +0000 + -- Ivan Kolesnikov Thu, 26 Jun 2025 00:00:00 +0000 diff --git a/packaging/ubuntu-focal/control b/packaging/ubuntu-focal/control index 1457d8aa..22bf7ee7 100644 --- a/packaging/ubuntu-focal/control +++ b/packaging/ubuntu-focal/control @@ -2,7 +2,7 @@ Source: usdr Section: misc Priority: optional Maintainer: Ivan Kolesnikov -Standards-Version: 0.9.9 +Standards-Version: 0.9.10b Homepage: https://github.com/wavelet-lab/usdr-lib Vcs-Browser: https://github.com/wavelet-lab/usdr-lib Vcs-Git: https://github.com/wavelet-lab/usdr-lib.git diff --git a/packaging/ubuntu-jammy/changelog b/packaging/ubuntu-jammy/changelog index 765ce6f8..68fcd0e0 100644 --- a/packaging/ubuntu-jammy/changelog +++ b/packaging/ubuntu-jammy/changelog @@ -1,5 +1,5 @@ -usdr (0.9.9~jammy0) jammy; urgency=low +usdr (0.9.10b~jammy0) jammy; urgency=low * Fixes and improvements - -- Ivan Kolesnikov Sun, 30 Jan 2025 00:00:00 +0000 + -- Ivan Kolesnikov Thu, 26 Jun 2025 00:00:00 +0000 diff --git a/packaging/ubuntu-jammy/control b/packaging/ubuntu-jammy/control index 1457d8aa..22bf7ee7 100644 --- a/packaging/ubuntu-jammy/control +++ b/packaging/ubuntu-jammy/control @@ -2,7 +2,7 @@ Source: usdr Section: misc Priority: optional Maintainer: Ivan Kolesnikov -Standards-Version: 0.9.9 +Standards-Version: 0.9.10b Homepage: https://github.com/wavelet-lab/usdr-lib Vcs-Browser: https://github.com/wavelet-lab/usdr-lib Vcs-Git: https://github.com/wavelet-lab/usdr-lib.git diff --git a/packaging/ubuntu-noble/changelog b/packaging/ubuntu-noble/changelog index 97c5c4e1..14b08ad8 100644 --- a/packaging/ubuntu-noble/changelog +++ b/packaging/ubuntu-noble/changelog @@ -1,5 +1,5 @@ -usdr (0.9.9~noble0) noble; urgency=low +usdr (0.9.10b~noble0) noble; urgency=low * Fixes and improvements - -- Ivan Kolesnikov Sun, 30 Jan 2025 00:00:00 +0000 + -- Ivan Kolesnikov Thu, 26 Jun 2025 00:00:00 +0000 diff --git a/packaging/ubuntu-noble/control b/packaging/ubuntu-noble/control index 2ca6f20f..a334dba1 100644 --- a/packaging/ubuntu-noble/control +++ b/packaging/ubuntu-noble/control @@ -2,7 +2,7 @@ Source: usdr Section: misc Priority: optional Maintainer: Ivan Kolesnikov -Standards-Version: 0.9.9 +Standards-Version: 0.9.10b Homepage: https://github.com/wavelet-lab/usdr-lib Vcs-Browser: https://github.com/wavelet-lab/usdr-lib Vcs-Git: https://github.com/wavelet-lab/usdr-lib.git diff --git a/src/Changelog.txt b/src/Changelog.txt index a6caef95..c1491801 100644 --- a/src/Changelog.txt +++ b/src/Changelog.txt @@ -1,3 +1,8 @@ +Release 0.9.10b (2025-06-26) +========================== + +- Fixes and improvements + Release 0.9.9 (2025-01-30) ========================== From 993602f6b20b3b6b77590303614d36f754ddb174 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 19 Sep 2025 00:26:52 +0400 Subject: [PATCH 171/397] update lms7002m lml control --- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 13 +- src/lib/device/m2_lm7_1/m2_lm7_1.c | 84 ++-- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 583 ++++++++++++++++++------ src/lib/device/m2_lm7_1/xsdr_ctrl.h | 17 +- src/lib/hw/lms7002m/lms7002m.c | 96 ++++ src/lib/hw/lms7002m/lms7002m.h | 6 +- src/tools/lms7002_dm_limelight.c | 169 ++++++- 7 files changed, 777 insertions(+), 191 deletions(-) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index c1c9f386..36babca8 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -1106,12 +1106,17 @@ int lms7002m_samplerate(lms7002_dev_t *d, int lms7002m_set_lmlrx_mode(lms7002_dev_t *d, unsigned mode) { + d->lml_mode.rx_lfsr = 0; + d->lml_mode.rx_tx_dig_loopback = 0; + switch (mode) { - case XSDR_LMLRX_LFSR: d->lml_mode.rx_lfsr = 1; break; - case XSDR_LMLRX_DIGLOOPBACK: d->lml_mode.rx_tx_dig_loopback = 1; break; + case XSDR_LMLRX_LFSR: + d->lml_mode.rx_lfsr = 1; + break; + case XSDR_LMLRX_DIGLOOPBACK: + d->lml_mode.rx_tx_dig_loopback = 1; + break; default: - d->lml_mode.rx_lfsr = 0; - d->lml_mode.rx_tx_dig_loopback = 0; break; } diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 1d5bb334..591e803e 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -224,6 +224,8 @@ static int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 static int dev_m2_lm7_1_phy_rx_lfsr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_phy_rx_lfsr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm7_1_phy_tx_lfsr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_phy_tx_iqsel_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_lms7002rxlml_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -233,6 +235,8 @@ static int dev_m2_lm7_1_revision_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t static int dev_m2_lm7_1_sdr_tx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_rx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -257,6 +261,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/vio", { dev_m2_lm7_1_sdr_vio_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr", { dev_m2_lm7_1_sdr_tx_phase_ovr_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr_iq", { dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set, NULL }}, + { "/dm/sdr/0/tx/phase_ovr_rc", { dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set, NULL }}, { "/dm/sdr/0/rx/phase_ovr", { dev_m2_lm7_1_sdr_rx_phase_ovr_set, NULL }}, { "/dm/sdr/0/rx/dccorr", { dev_m2_lm7_1_sdr_rx_dccorr_set, NULL }}, @@ -321,6 +326,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/phy_rx_dly", { dev_m2_lm7_1_phy_rx_dly_set, NULL }}, { "/dm/sdr/0/phy_rx_lfsr", { dev_m2_lm7_1_phy_rx_lfsr_set, dev_m2_lm7_1_phy_rx_lfsr_get }}, + { "/dm/sdr/0/phy_tx_lfsr", { dev_m2_lm7_1_phy_tx_lfsr_set, NULL }}, + { "/dm/sdr/0/phy_tx_iqsel", { dev_m2_lm7_1_phy_tx_iqsel_set, NULL }}, { "/dm/sdr/0/phyrxlml", { dev_m2_lm7_1_phyrxlm_set, NULL }}, { "/debug/hw/lms7002m/0/rxlml", { dev_m2_lm7_1_lms7002rxlml_set, NULL }}, @@ -375,9 +382,22 @@ int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu int dev_m2_lm7_1_phy_rx_lfsr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - return xsdr_phy_en_lfsr_mimo(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value ? true : false); + return xsdr_phy_en_lfsr_checker_mimo(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value ? true : false); +} + +int dev_m2_lm7_1_phy_tx_lfsr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return xsdr_phy_en_lfsr_generator_mimo(&((struct dev_m2_lm7_1_gps *)ud)->xdev, + (value & 1) ? true : false, + (value & 2) ? true : false); +} + +int dev_m2_lm7_1_phy_tx_iqsel_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return xsdr_phy_tx_iqsel(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); } + int dev_m2_lm7_1_phy_rx_lfsr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { uint32_t v[4]; @@ -429,6 +449,13 @@ int dev_m2_lm7_1_sdr_tx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ return 0; } +int dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + return xsdr_txphase_ovr(&d->xdev, value); +} + + int dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; @@ -1066,38 +1093,6 @@ int usdr_device_m2_lm7_1_lsop(lldev_t dev, subdev_t subdev, return d->p_original_ops->ls_op(dev, subdev, ls_op, ls_op_addr, meminsz, pin, memoutsz, pout); } -static -int usdr_device_m2_lm7_1_stream_initialize(lldev_t dev, subdev_t subdev, lowlevel_stream_params_t* params, stream_t* channel) -{ - struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)lowlevel_get_device(dev); - int res; - unsigned streamno = params->streamno; - - if (getenv("USDR_BARE_DEV")) { - return -EOPNOTSUPP; - } - - res = xsdr_prepare(&d->xdev, true, true); - if (res) { - return res; - } - - res = d->p_original_ops->stream_initialize(dev, subdev, params, channel); - if (res) { - xsdr_rfic_streaming_down(&d->xdev, streamno == 0 ? RFIC_LMS7_RX : RFIC_LMS7_TX); - } - - return res; -} - -static -int usdr_device_m2_lm7_1_stream_deinitialize(lldev_t dev, subdev_t subdev, stream_t channel) -{ - struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)lowlevel_get_device(dev); - xsdr_rfic_streaming_down(&d->xdev, RFIC_LMS7_RX); - return d->p_original_ops->stream_deinitialize(dev, subdev, channel); -} - xsdr_dev_t* get_xsdr_dev(pdevice_t udev) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)udev; @@ -1150,8 +1145,6 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* // Proxy operations memcpy(&d->my_ops, lowlevel_get_ops(dev), sizeof (lowlevel_ops_t)); d->my_ops.ls_op = &usdr_device_m2_lm7_1_lsop; - d->my_ops.stream_initialize = &usdr_device_m2_lm7_1_stream_initialize; - d->my_ops.stream_deinitialize = &usdr_device_m2_lm7_1_stream_deinitialize; d->p_original_ops = lowlevel_get_ops(dev); dev->ops = &d->my_ops; @@ -1211,12 +1204,15 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha unsigned hwchs; channel_info_t lchans; + if (getenv("USDR_BARE_DEV")) { + return -EOPNOTSUPP; + } + res = xsdr_map_channels(channels, &lchans); if (res) { return res; } - if (strstr(sid, "rx") != NULL) { if (d->rx) { return -EBUSY; @@ -1254,8 +1250,15 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &hwchs); if (res) { + USDR_LOG("XSDR", USDR_LOG_ERROR, "Unable to create stream '%s': error=%d\n", sid, res); return res; } + + res = xsdr_prepare(&d->xdev, true, d->tx); + if (res) { + return res; + } + *out_handle = d->rx; } else if (strstr(sid, "tx") != NULL) { if (d->tx) { @@ -1281,6 +1284,11 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha // TODO: update samplerate settings } + res = xsdr_prepare(&d->xdev, d->rx, true); + if (res) { + return res; + } + res = create_sfetrx4_stream(dev, CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, flags, M2PCI_REG_WR_TXDMA_CNF_L, M2PCI_REG_WR_SYNC_CTRL, M2PCI_REG_RD_TXDMA_STAT, 0, 0, &d->tx, &hwchs); @@ -1300,9 +1308,13 @@ int usdr_device_m2_lm7_1_unregister_stream(device_t* dev, stream_handle_t* strea { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)dev; if (stream == d->tx) { + xsdr_rfic_streaming_down(&d->xdev, RFIC_LMS7_TX); + d->tx->ops->destroy(d->tx); d->tx = NULL; } else if (stream == d->rx) { + xsdr_rfic_streaming_down(&d->xdev, RFIC_LMS7_RX); + d->rx->ops->destroy(d->rx); d->rx = NULL; } else { diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index ac1b92dd..c0b81f6f 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -146,13 +146,16 @@ enum { PHY_REG_MMCM_PSINC = 3, PHY_REG_DLY_VALUE = 4, PHY_REG_PORT_IQSEL = 5, + PHY_REG_LFSR_GEN = 6, + PHY_REG_IQAB_GEN = 7, }; enum { PHY_REG_RXBANK_CTRL = 0, // Control registers PHY_REG_RXBANK_MMCM = 1, // MMCM registers PHY_REG_RXBANK_CLKMEAS = 2, - PHY_REG_RXBANK_LFSRCHK = 3, // LFSR cntrol + PHY_REG_RXBANK_LFSRCHK = 3, // LFSR control + PHY_REG_RXBANK_IQABCHK = 4, // IQAB control PHY_REG_RXBANK_CLKDLY = 14, // Clock delay PHY_REG_RXBANK_FRMDLY = 15, // Frame delay @@ -165,18 +168,40 @@ int xsdr_phy_rx_reg(xsdr_dev_t *d, bool wr, uint8_t bank, uint8_t addr, uint16_t return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, reg); } -int xsdr_phy_en_lfsr_mimo(xsdr_dev_t *d, bool en) +int xsdr_phy_en_lfsr_checker_mimo(xsdr_dev_t *d, bool en) { int res = 0; if (!en) { - return xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0x0f); + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_IQABCHK, 0, 0); + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0x0f); + return res; } + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_IQABCHK, 0, 0); res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0x0f); res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0xf0); return res; } +int xsdr_phy_en_iqab_checker_mimo(xsdr_dev_t *d, bool en) +{ + int res = 0; + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_LFSRCHK, 0, 0x0f); + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_IQABCHK, 0, 0); + usleep(1); + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_IQABCHK, 0, en ? 1 : 0); + return res; +} + +int xsdr_phy_lfsr_mimo_state_s(xsdr_dev_t *d, int ridx, uint32_t* v) +{ + int res = 0; + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, ridx, 0); + res = res ? res : usleep(1); + res = res ? res : lowlevel_reg_rd32(d->base.lmsstate.dev, 0, REG_CFG_PHY_0, v); + return res; +} + int xsdr_phy_lfsr_mimo_state(xsdr_dev_t *d, int type, uint32_t v[4]) { int res = 0; @@ -196,6 +221,17 @@ int xsdr_phy_tx_reg(xsdr_dev_t *d, uint8_t addr, uint32_t val) return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_1, (((uint32_t)addr) << 24) | (val & 0xffffff)); } +int xsdr_phy_en_lfsr_generator_mimo(xsdr_dev_t *d, bool en, bool lfsr) +{ + int res = 0; + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_LFSR_GEN, 0); + res = res ? res : usleep(1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_IQAB_GEN, lfsr ? 0 : 1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_LFSR_GEN, en ? 1 : 0); + + return res; +} + int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, size_t meminsz, void* pin, size_t memoutsz, const void* pout) @@ -259,9 +295,15 @@ int xsdr_upd_phase(xsdr_dev_t *d) return 0; } -int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, unsigned rxphase) +int xsdr_phy_tx_iqsel(xsdr_dev_t *d, uint8_t iqsel) +{ + return xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, iqsel); +} + +int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned txphase, unsigned txphase_off) { bool nomul = d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); + unsigned mmcm_ctrl_sel = (rx_master) ? 0 : 4; unsigned tx_mclk = d->base.cgen_clk / d->base.txcgen_div / d->base.lml_mode.txdiv; unsigned io_clk = (nomul) ? tx_mclk : tx_mclk * 2; unsigned vco_div_io_m = (MMCM_VCO_MAX + io_clk - 1) / io_clk; @@ -281,34 +323,34 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, unsigned rxphase) } } - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 0); res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); - // 0 - IO_TX_IQSEL (individual phase delay) + // 0 - n/a ( was IO_TX_IQSEL -- individual phase delay ) // 1 - IO_TX // 2 - IO_RX - // 3 - LOGIC_TX + // 3 - n/a ( was LOGIC_TX ) // 4 - n/a // 5 - FCLK_RX // 6 - FCLK_TX cfg_raw.type = MT_7SERIES_MMCM; - cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; - cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; - - cfg_raw.ports[CLKOUT_PORT_2].period_l = (vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_2].period_h = vco_div_io / 2; - cfg_raw.ports[CLKOUT_PORT_3].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_3].period_h = vco_div_io; - - cfg_raw.ports[CLKOUT_PORT_4].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; // IO_TX_IQSEL + cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; // IO_TX_IQSEL + cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; // IO_TX + cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; // IO_TX + + cfg_raw.ports[CLKOUT_PORT_2].period_l = (vco_div_io + 1) / 2; // IO_RX + cfg_raw.ports[CLKOUT_PORT_2].period_h = vco_div_io / 2; // IO_RX + cfg_raw.ports[CLKOUT_PORT_3].period_l = vco_div_io; // not used + cfg_raw.ports[CLKOUT_PORT_3].period_h = vco_div_io; // not used + + cfg_raw.ports[CLKOUT_PORT_4].period_l = vco_div_io; // not used + cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io; // not used cfg_raw.ports[CLKOUT_PORT_5].period_l = (vco_div_io + 1) / 2; cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io / 2; cfg_raw.ports[CLKOUT_PORT_6].period_l = (vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io / 2; + cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io / 2; // FCLK_TX unsigned total_budget = 8 * vco_div_io; unsigned phase = (((tx_mclk < 2*35e6) || (tx_mclk > 2*60e6)) ? 4 : 5) * total_budget / 6; @@ -319,22 +361,31 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, unsigned rxphase) cfg_raw.ports[CLKOUT_PORT_0].phase = phase_iq % 8; cfg_raw.ports[CLKOUT_PORT_0].delay = phase_iq / 8; - if (d->tx_override_phase_iq) { - unsigned raw = d->tx_override_phase_iq - 1; + if (d->tx_override_phase_iq || txphase) { + unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase_iq - 1; cfg_raw.ports[CLKOUT_PORT_0].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_0].delay = raw / 8; } - if (d->tx_override_phase) { - unsigned raw = d->tx_override_phase - 1; + // if (d->tx_override_phase || txphase) { + // unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase - 1; + // cfg_raw.ports[CLKOUT_PORT_1].phase = raw % 8; + // cfg_raw.ports[CLKOUT_PORT_1].delay = raw / 8; + // } + + if (d->tx_override_phase || txphase) { + unsigned raw = (txphase != 0) ? ((txphase - 1 + txphase_off) % 64) : d->tx_override_phase - 1; cfg_raw.ports[CLKOUT_PORT_6].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = raw / 8; } if (d->rx_override_phase || rxphase) { unsigned raw = (rxphase != 0) ? rxphase - 1 : d->rx_override_phase - 1; - cfg_raw.ports[CLKOUT_PORT_2].phase = raw % 8; - cfg_raw.ports[CLKOUT_PORT_2].delay = raw / 8; + cfg_raw.ports[CLKOUT_PORT_2].phase = raw % 8; + cfg_raw.ports[CLKOUT_PORT_2].delay = raw / 8; + +// cfg_raw.ports[CLKOUT_PORT_FB].phase = raw % 8; +// cfg_raw.ports[CLKOUT_PORT_FB].delay = raw / 8; } if (nomul) { @@ -344,23 +395,24 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, unsigned rxphase) cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; } - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d VCO=%.3f MHZ\n", + USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d VCO=%.3f MHZ OFF=%d\n", tx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io, (d->tx_override_phase) ? "_OVR" : "", cfg_raw.ports[CLKOUT_PORT_0].delay, cfg_raw.ports[CLKOUT_PORT_0].phase, d->base.lml_mode.txsisoddr, - tx_mclk * (cfg_raw.ports[CLKOUT_PORT_FB].period_l + cfg_raw.ports[CLKOUT_PORT_FB].period_h) / 1.0e6); + tx_mclk * (cfg_raw.ports[CLKOUT_PORT_FB].period_l + cfg_raw.ports[CLKOUT_PORT_FB].period_h) / 1.0e6, + txphase_off); res = res ? res : mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &cfg_raw); // Reset MMCM - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 1); usleep(10); - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 0); if (res) return res; - for (unsigned k = 0; k < 10; k++) { + for (unsigned k = 0; k < 100; k++) { uint32_t rb; // Wait for lock @@ -375,9 +427,10 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, unsigned rxphase) return 0; } - usleep(500); + usleep(10); } + USDR_LOG("XDEV", USDR_LOG_WARNING, "MMCM Redy flag timed out!\n"); return -EIO; } @@ -506,22 +559,316 @@ static bool noerrors_v4(unsigned errs[4], uint64_t* badness) return errs[0] == 0 && errs[1] == 0 && errs[2] == 0 && errs[3] == 0; } +int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v) +{ + int res = 0; + d->tx_override_phase_iq = v; + d->tx_override_phase = v; + + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, 0, 0); + + // Reset OSERDESE2 + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); + res = res ? res : usleep(1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); + + return res; +} + +static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, + unsigned errs[4], unsigned *piqserrs, + uint64_t *pbadness) +{ + int res = 0; + unsigned w; + + // Reset OSERDESE2 + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); + res = res ? res : usleep(1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); + res = res ? res : usleep(1); + res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + //res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); + + + for (w = 0; w < check_to; w++) { + res = res ? res : usleep(100); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + res = res ? res : xsdr_phy_lfsr_mimo_state_s(d, LFSR_CNTR_IQS << 2, piqserrs); + if (res || (!noerrors_v4(errs, pbadness)) || *piqserrs) { + break; + } + } + *pbadness *= 1.0 * check_to / (w + 1); // Rescale + + return 0; +} + +static int _xsdr_calibrate_lml(xsdr_dev_t *d) +{ + int res = 0; + bool mmcm_rx_only_path = (!d->base.tx_run[0] && !d->base.tx_run[1]); + + if (d->mmcm_tx) { + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, 0, 0, 0); + res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); + + // Autocalibration if RX phase wasn't set + if (d->rx_override_phase == 0) { + const unsigned check_to = 10; + unsigned phase_m; + int ph_ty_m = 0; + unsigned iqserrs; + unsigned errs[4] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX }; + + for (unsigned rxrty = 0; rxrty < 4; rxrty++) { + + + // Boost IO voltage for stable high speed link + if (!d->siso_sdr_active_rx && d->new_rev && d->s_rxrate > 85e6) { + res = res ? res : xsdr_set_vio(d, 1910); + } + if (!d->siso_sdr_active_rx && !d->ssdr && d->s_rxrate > 60e6) { + res = res ? res : xsdr_set_vio(d, 1910); + res = res ? res : lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, 1320); + } + + uint64_t badness_m = UINT64_MAX; + unsigned c; + + phase_m = 0; + + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + for (c = 0; c < check_to; c++) { + res = res ? res : usleep(1000); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || !noerrors_v4(errs, &badness_m)) + break; + } + + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=AUTO [%d/%d/%d/%d]\n", + errs[0], errs[1], errs[2], errs[3]); + if (res || noerrors_v4(errs, &badness_m)) + goto phase_calibrated; + + + int phase_min; + int phase_max; + + //for (unsigned rty = 0; rty < 3; rty++) { + phase_min = 65; + phase_max = 0; + + badness_m = UINT64_MAX; + + for (unsigned ph = 1; ph < 65; ph++) { + unsigned w; + uint64_t badness = UINT64_MAX; + + res = res ? res : usleep(10); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, ph, 0, 0); + res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + + for (w = 0; w < check_to; w++) { + res = res ? res : usleep(100); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || !noerrors_v4(errs, &badness)) { + break; + } + } + badness *= 1.0 * check_to / (w + 1); // Rescale + + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", ph - 1, w, + errs[0], errs[1], errs[2], errs[3], (long long)badness); + if (res || noerrors_v4(errs, &badness)) { + phase_m = ph; + if (ph < phase_min) + phase_min = ph; + if (ph > phase_max) + phase_max = ph; + + // Got more than 7 phases, we're safe; skip searching + if (phase_max - phase_min > 7) + break; + } else if (phase_max >= phase_min) { + break; + } + + if (badness_m > badness) { + badness_m = badness; + phase_m = ph; + } + } + + if (phase_max > phase_min) { + phase_m = (phase_max + phase_min) / 2; + } + //if (badness_m == 0) + // break; + // + //USDR_LOG("XDEV", USDR_LOG_WARNING, " == RX RESETTING == \n"); + //lms7002m_limelight_reset(d); + //} + + USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring RX pahse to %d (bandness=%" PRId64 ") PH_MIN=%d PH_MAX=%d\n", + phase_m - 1, badness_m, phase_min, phase_max); + + // Try our best at least + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, phase_m, 0, 0); + res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + { + uint64_t badness = UINT64_MAX; + unsigned w; + for (w = 0; w < check_to; w++) { + res = res ? res : usleep(100); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || !noerrors_v4(errs, &badness)) { + break; + } + } + badness *= 1.0 * check_to / (w + 1); // Rescale + if (badness > badness_m * 2) { + USDR_LOG("XDEV", USDR_LOG_INFO, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, + errs[0], errs[1], errs[2], errs[3], (long long)badness); + continue; + } + } + break; + } + + phase_calibrated: + if (mmcm_rx_only_path) + goto no_tx; + + d->lmlcal_rx_phase = phase_m; + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_DIGLOOPBACK); + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + //res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); + + uint64_t badness_m = UINT64_MAX; + phase_m = 0; + for (unsigned rty = 0; rty < 64; rty++) { + for (unsigned ph = 1; ph < 64; ph++) { + //unsigned w; + uint64_t badness = UINT64_MAX; + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, rty); + res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness); + + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e\n", ph - 1, + errs[0], errs[1], errs[2], errs[3], iqserrs, (double)badness); + if (res || (noerrors_v4(errs, &badness) && (iqserrs == 0))) { + phase_m = ph; + + for (int g = 0; g < 50; g++) { + // Check A/B & I/Q aligment is ok + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); + res = res ? res : usleep(1000); + res = res ? res : xsdr_phy_lfsr_mimo_state_s(d, LFSR_CNTR_IQS << 2, &iqserrs); + if (res) + return res; + + if (iqserrs > 40) { + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); + + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph + 1, rty); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, rty); + + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); + res = res ? res : usleep(1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); + res = res ? res : usleep(1); + + // res = res ? res : lms7002m_limelight_l_reset(&d->base.lmsstate, false, true); + res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); + } else if (g > 0) { + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); + break; + } + } + + if (iqserrs > 40) { + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); + continue; + } + goto phase_tx_calibrated; + } + + if (badness_m > badness) { + badness_m = badness; + phase_m = ph; + ph_ty_m = rty; + } + } + // Try to toggle clock inversion + res = res ? res : lms7002m_limelight_toggle_ntx(&d->base.lmsstate); + } + USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring TX pahse to %d (bandness=%" PRId64 ")\n", + phase_m, badness_m); + + // Try our best at least + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, phase_m, ph_ty_m); + + // Make sure it's a good value + res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness_m); + + unsigned iqserrs2 = -1; + + // Check A/B & I/Q aligment is ok + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); + res = res ? res : usleep(1000); + res = res ? res : xsdr_phy_lfsr_mimo_state_s(d, LFSR_CNTR_IQS << 2, &iqserrs2); + if (res) + return res; + + USDR_LOG("XDEV", USDR_LOG_INFO, "RESTORE PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d - %6d] BD=%.3e\n", phase_m - 1, + errs[0], errs[1], errs[2], errs[3], iqserrs, iqserrs2, (double)badness_m); + + phase_tx_calibrated: + d->lmlcal_tx_phase = phase_m; + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, false, false); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, false); + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); + } + } else { + + unsigned dly = (d->tx_override_phase) ? (d->tx_override_phase - 1) : 3; + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_DLY_VALUE, dly); + } + +no_tx: + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); + + // Reset TSP + if (true) { + res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); + // res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); + } + + return res; +} + int xsdr_set_samplerate_ex(xsdr_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, unsigned flags) { - const uint8_t phycfg_id = (d->hwid) & 0xff; - const bool rx_port_is_1 = ((phycfg_id & PHY_CFG_LML2_IS_RX) != PHY_CFG_LML2_IS_RX); - const bool tx_mmcm = ((phycfg_id & PHY_CFG_TX_MMCM) == PHY_CFG_TX_MMCM); - const bool rx_mmcm = ((phycfg_id & PHY_CFG_RX_MMCM) == PHY_CFG_RX_MMCM); - lldev_t dev = d->base.lmsstate.dev; subdev_t subdev = d->base.lmsstate.subdev; unsigned sisosdrflag; int res; - if (!(phycfg_id & PHY_CFG_VALID_MSK)) { + if (!(((d->hwid) & 0xff) & PHY_CFG_VALID_MSK)) { USDR_LOG("XDEV", USDR_LOG_ERROR, "Incompatible firmware, please update to 20250501 at least!\n"); return -ENOTSUP; } @@ -537,7 +884,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, unsigned m_flags = flags | ((d->siso_sdr_active_rx && d->hwchans_rx == 1) ? XSDR_LML_SISO_DDR_RX : 0) | ((d->siso_sdr_active_tx && d->hwchans_tx == 1) ? XSDR_LML_SISO_DDR_TX : 0); - res = lms7002m_samplerate(&d->base, rxrate, txrate, adcclk, dacclk, m_flags, rx_port_is_1); + res = lms7002m_samplerate(&d->base, rxrate, txrate, adcclk, dacclk, m_flags, d->rx_port_is_1); if (res) return res; @@ -546,6 +893,8 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, d->s_adcclk = adcclk; d->s_dacclk = dacclk; d->s_flags = m_flags; + d->cfg_srate_siso_rx = (m_flags & XSDR_LML_SISO_DDR_RX) ? 1 : 0; + d->cfg_srate_siso_tx = (m_flags & XSDR_LML_SISO_DDR_TX) ? 1 : 0; if (d->afe_active == false) { // Need AFE for reference cloking @@ -554,11 +903,12 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, // wait for clock to stabilize usleep(10000); + // We need RxTSP & TxTSP configured for proper LML - TSP alignment before LFSR training d->afe_active = true; } if (rxrate) { - if (rx_mmcm) { + if (d->mmcm_rx) { res = res ? res : xsdr_configure_lml_mmcm_rx(d); } @@ -568,7 +918,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); - if (rx_mmcm) { + if (d->mmcm_rx) { // Configure PHY (reset) // TODO phase search @@ -594,84 +944,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, } if (txrate) { - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); - - if (tx_mmcm) { - res = res ? res : xsdr_configure_lml_mmcm_tx(d, 0); - - // Autocalibration if RX phase wasn't set - if (d->rx_override_phase == 0) { - const unsigned check_to = 10; - - // Boost IO voltage for stable high speed link - if (!d->siso_sdr_active_rx && d->new_rev && rxrate > 85e6) { - res = res ? res : xsdr_set_vio(d, 1910); - } - - unsigned errs[4] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX }; - - uint64_t badness_m = UINT64_MAX; - unsigned phase_m = 0; - unsigned c; - - res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); - res = res ? res : usleep(10); - res = res ? res : xsdr_phy_en_lfsr_mimo(d, true); - for (c = 0; c < check_to; c++) { - res = res ? res : usleep(1000); - res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - if (res || !noerrors_v4(errs, &badness_m)) - break; - } - - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=AUTO [%d/%d/%d/%d]\n", - errs[0], errs[1], errs[2], errs[3]); - if (res || noerrors_v4(errs, &badness_m)) - goto phase_calibrated; - - for (unsigned ph = 1; ph < 64; ph++) { - unsigned w; - uint64_t badness = UINT64_MAX; - - res = res ? res : usleep(10); - res = res ? res : xsdr_configure_lml_mmcm_tx(d, ph); - res = res ? res : xsdr_phy_en_lfsr_mimo(d, true); - - for (w = 0; w < check_to; w++) { - res = res ? res : usleep(1000); - res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - if (res || !noerrors_v4(errs, &badness)) { - break; - } - } - badness *= 1.0 * check_to / (w + 1); // Rescale - - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%.3e\n", ph - 1, w, - errs[0], errs[1], errs[2], errs[3], (double)badness); - if (res || noerrors_v4(errs, &badness)) - goto phase_calibrated; - - if (badness < badness_m) { - badness = badness_m; - phase_m = ph; - } - } - - USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring pahse to %d (bandness=%" PRId64 ")\n", - phase_m, badness_m); - - // Try our best at least - res = res ? res : xsdr_configure_lml_mmcm_tx(d, phase_m); -phase_calibrated: - res = res ? res : xsdr_phy_en_lfsr_mimo(d, false); - res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); - ; - } - } else { - - unsigned dly = (d->tx_override_phase) ? (d->tx_override_phase - 1) : 3; - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_DLY_VALUE, dly); - } + res = res ? res : _xsdr_calibrate_lml(d); } return res; @@ -685,7 +958,7 @@ int xsdr_clk_debug_info(xsdr_dev_t *d) unsigned crx, ctx, caux; int res = 0; - uint32_t dump[12]; + uint32_t dump[13]; res = res ? res : dev_gpi_get32(dev, IGPI_MEAS_RXCLK, &crx); res = res ? res : dev_gpi_get32(dev, IGPI_MEAS_TXCLK, &ctx); @@ -694,7 +967,7 @@ int xsdr_clk_debug_info(xsdr_dev_t *d) return res; - for (unsigned h = 0; h < 12; h++) { + for (unsigned h = 0; h < 13; h++) { unsigned p = ((h & 0x3) << 2) | (h >> 2); res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); @@ -705,11 +978,11 @@ int xsdr_clk_debug_info(xsdr_dev_t *d) } - USDR_LOG("XDEV", USDR_LOG_WARNING, "PHY - RX %08x (%d) / TX %08x (%d) / AUX %08x (%d) %d/%d/%d/%d %d/%d/%d/%d %d/%d/%d/%d \n", + USDR_LOG("XDEV", USDR_LOG_WARNING, "PHY - RX %08x (%d) / TX %08x (%d) / AUX %08x (%d) %d/%d/%d/%d %d/%d/%d/%d %d/%d/%d/%d -- %d \n", crx, crx & 0xfffffff, ctx, ctx & 0xfffffff, caux, caux & 0xfffffff, - dump[0], dump[1], dump[2], dump[3], dump[4], dump[5], dump[6], dump[7], dump[8], dump[9], dump[10], dump[11] + dump[0], dump[1], dump[2], dump[3], dump[4], dump[5], dump[6], dump[7], dump[8], dump[9], dump[10], dump[11], dump[12] ); return res; } @@ -929,7 +1202,12 @@ int xsdr_rfic_streaming_up(xsdr_dev_t *d, unsigned dir, unsigned rx_chs, unsigned rx_flags, unsigned tx_chs, unsigned tx_flags) { - return lms7002m_streaming_up(&d->base, dir, (lms7002m_mac_mode_t)rx_chs, rx_flags, (lms7002m_mac_mode_t)tx_chs, tx_flags); + int res = lms7002m_streaming_up(&d->base, dir, (lms7002m_mac_mode_t)rx_chs, rx_flags, (lms7002m_mac_mode_t)tx_chs, tx_flags); + if (res) + return res; + + d->afe_active = true; + return 0; } @@ -1130,7 +1408,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) d->pmic_ch145_valid = true; } - USDR_LOG("XDEV", USDR_LOG_INFO, "PMIC_RFIC ver %04x (%d)\n", + USDR_LOG("XDEV", (rev == 0xe001) ? USDR_LOG_INFO : USDR_LOG_ERROR, "PMIC_RFIC ver %04x (%d)\n", rev, d->pmic_ch145_valid); if (hwid == SSDR_DEV) { @@ -1396,9 +1674,18 @@ int _xsdr_pwren_revx(xsdr_dev_t *d, bool on) int res; lldev_t dev = d->base.lmsstate.dev; - USDR_LOG("XDEV", USDR_LOG_INFO, "RFIC PWR:%d\n", on); - if (on && !d->pmic_ch145_valid) + USDR_LOG("XDEV", (on && !d->pmic_ch145_valid) ? USDR_LOG_ERROR : USDR_LOG_INFO, + "RFIC PWR:%d CH145:%d\n", on, d->pmic_ch145_valid); + if (on && !d->pmic_ch145_valid) { + // 1V45 is cricial for Rev0 XSDR and can be ignored in Rev2 + int id = -1; + res = xsdr_gettemp_id(d, &id); + if (res == 0) { + USDR_LOG("XDEV", USDR_LOG_WARNING, "TEMP ID: %04x\n", id); + } + return -EIO; + } res = dev_gpo_set(dev, IGPO_LDOLMS_EN, on ? 1 : 0); // Enable LDOs if (res) @@ -1495,11 +1782,21 @@ int xsdr_init(xsdr_dev_t *d) hwcfg_devid = (hwid >> 16) & 0xff; USDR_LOG("XDEV", USDR_LOG_ERROR, "HWID %08x\n", hwid); + const uint8_t phycfg_id = hwid & 0xff; + const bool rx_port_is_1 = ((phycfg_id & PHY_CFG_LML2_IS_RX) != PHY_CFG_LML2_IS_RX); + const bool tx_mmcm = ((phycfg_id & PHY_CFG_TX_MMCM) == PHY_CFG_TX_MMCM); + const bool rx_mmcm = ((phycfg_id & PHY_CFG_RX_MMCM) == PHY_CFG_RX_MMCM); + d->hwid = hwid; d->hwchans_rx = 2; // Defaults to MIMO; d->hwchans_tx = 2; // Defaults to MIMO; d->siso_sdr_active_rx = false; d->siso_sdr_active_tx = false; + d->rx_port_is_1 = rx_port_is_1; + d->mmcm_rx = rx_mmcm; + d->mmcm_tx = tx_mmcm; + d->cfg_srate_siso_rx = 0; + d->cfg_srate_siso_tx = 0; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); if (res) @@ -1588,6 +1885,7 @@ int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen) return res; } + // TODO: Properly set mask for A/B channels d->base.rx_run[0] = rxen; d->base.rx_run[1] = rxen; d->base.tx_run[0] = txen; @@ -1607,16 +1905,22 @@ int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen) // 13 *idle* // 14 FCLK // 15 *idle* - const unsigned coeff = 0x40; - res = (res) ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_PHYCAL, coeff | 1); - usleep(1); - res = (res) ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_PHYCAL, coeff | 0); - if (res) { - return res; - } + // const unsigned coeff = 0x40; + // res = (res) ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_PHYCAL, coeff | 1); + // usleep(1); + // res = (res) ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_PHYCAL, coeff | 0); + // if (res) { + // return res; + // } + //} + + // res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); + + + //if (d->txrate) { + res = res ? res : _xsdr_calibrate_lml(d); //} - lms7002m_limelight_reset(&d->base.lmsstate); return res; } @@ -1986,6 +2290,15 @@ int xsdr_gettemp(xsdr_dev_t *d, int* temp256) } } +int xsdr_gettemp_id(xsdr_dev_t *d, int* id) +{ + if (d->new_rev) { + return tmp114_devid_get(d->base.lmsstate.dev, 0, I2C_BUS_TMP_114, id); + } else { + return tmp108_temp_get(d->base.lmsstate.dev, 0, I2C_BUS_TMP_108, id); + } +} + int xsdr_trim_dac_vctcxo(xsdr_dev_t *d, uint16_t val) { if (d->new_rev) { diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index a750d48c..60511660 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -53,9 +53,17 @@ struct xsdr_dev int tx_override_phase_iq; int rx_override_phase; + int lmlcal_tx_phase; + int lmlcal_rx_phase; + bool afe_active; + bool cfg_srate_siso_rx; + bool cfg_srate_siso_tx; bool siso_sdr_active_rx; bool siso_sdr_active_tx; + bool rx_port_is_1; + bool mmcm_tx; + bool mmcm_rx; bool pwr_en; bool new_rev; bool ssdr; @@ -136,6 +144,7 @@ int xsdr_pwren(xsdr_dev_t *d, bool on); int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen); int xsdr_gettemp(xsdr_dev_t *d, int* temp256); +int xsdr_gettemp_id(xsdr_dev_t *d, int* id); enum xsdr_tx_port_cfg_flags { MUTE_B = 0, @@ -152,12 +161,16 @@ int xsdrcal_set_corr_param(void* param, int channel, int corr_type, int value); int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int *func); //int (*set_tx_testsig_fs8)(void* param, int channel); +int xsdr_phy_tx_iqsel(xsdr_dev_t *d, uint8_t iqsel); -int xsdr_phy_en_lfsr_mimo(xsdr_dev_t *d, bool en); +int xsdr_phy_en_lfsr_generator_mimo(xsdr_dev_t *d, bool en, bool lfsr); +int xsdr_phy_en_lfsr_checker_mimo(xsdr_dev_t *d, bool en); +int xsdr_phy_en_iqab_checker_mimo(xsdr_dev_t *d, bool en); enum lfsr_cntr_types { LFSR_CNTR_SYNC = 0, LFSR_CNTR_LOST = 1, LFSR_CNTR_BER = 2, + LFSR_CNTR_IQS = 3, }; int xsdr_phy_lfsr_mimo_state(xsdr_dev_t *d, int type, uint32_t v[4]); @@ -237,7 +250,7 @@ enum { }; - +int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v); #endif diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index a255c7f1..2566a590 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -341,6 +341,66 @@ int lms7002m_limelight_reset(lms7002m_state_t* m) return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); } +int lms7002m_limelight_fifo_reset(lms7002m_state_t* m, bool rx, bool tx) +{ + uint16_t reg_mac_rst = m->reg_mac; + if (rx) + SET_LMS7002M_LML_0X0020_SRST_RXFIFO(reg_mac_rst, 1); + if (tx) + SET_LMS7002M_LML_0X0020_SRST_TXFIFO(reg_mac_rst, 1); + + uint32_t regs[] = { + // Reset LML FIFO + MAKE_LMS7002M_REG_WR(LML_0x0020, reg_mac_rst), + MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac), + }; + + return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); +} + +int lms7002m_limelight_l_reset(lms7002m_state_t* m, bool rx, bool tx) +{ + uint16_t reg_mac_rst = m->reg_mac; + if (rx) { + SET_LMS7002M_LML_0X0020_LRST_RX_B(reg_mac_rst, 1); + SET_LMS7002M_LML_0X0020_LRST_RX_A(reg_mac_rst, 1); + } + if (tx) { + SET_LMS7002M_LML_0X0020_LRST_TX_B(reg_mac_rst, 1); + SET_LMS7002M_LML_0X0020_LRST_TX_A(reg_mac_rst, 1); + } + + uint32_t regs[] = { + // Reset LML FIFO + MAKE_LMS7002M_REG_WR(LML_0x0020, reg_mac_rst), + //MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac), + }; + + lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); + + + usleep(1000); + + uint32_t regs2[] = { + // Reset LML FIFO + //MAKE_LMS7002M_REG_WR(LML_0x0020, reg_mac_rst), + MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac), + }; + + + return lms7002m_spi_post(m, regs2, SIZEOF_ARRAY(regs2)); + +} + +int lms7002m_limelight_toggle_ntx(lms7002m_state_t* m) +{ + uint32_t regs[] = { + MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1), + MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1), + }; + + return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); +} int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t params) { @@ -404,6 +464,8 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); } + + int _lms7002m_fill_pos(lms7002m_lml_map_t l, lms7002m_lml_map_t* o) { lms7002m_lml_map_t p = {{0, 0, 0, 0}}; @@ -748,7 +810,41 @@ int lms7002m_dc_corr(lms7002m_state_t* m, unsigned p, int16_t v) } +int lms7002m_xxtsp_bst(lms7002m_state_t* m, lms7002m_xxtsp_t tsp) +{ + uint32_t reg_rxmod = MAKE_LMS7002M_RXTSP_0x0400(0, + RXTSP_0X0400_CAPSEL_RSSI, //CAPSEL + RXTSP_0X0400_CAPSEL_ADC_RXTSP_INPUT, //CAPSEL_ADC + RXTSP_0X0400_TSGFC_NEG6DB, //TSGFC, + RXTSP_0X0400_TSGFCW_DIV8, //TSGFCW, + 0, //TSGDCLDQ + 0, //TSGDCLDI + 0, //TSGSWAPIQ, + RXTSP_0X0400_TSGMODE_DC, //TSGMODE, + RXTSP_0X0400_INSEL_LML, //INSEL, + 0, //BSTART, + 1); + uint32_t reg_rxmod_s = reg_rxmod; + SET_LMS7002M_RXTSP_0X0400_BSTART(reg_rxmod_s, 1); + + uint32_t reg_txmod = MAKE_LMS7002M_TXTSP_0x0200(TXTSP_0X0200_TSGFC_NEG6DB, //TSGFC, + TXTSP_0X0200_TSGFCW_DIV8, //TSGFCW, + 0, //TSGDCLDQ + 0, //TSGDCLDI + 0, //TSGSWAPIQ, + TXTSP_0X0200_TSGMODE_DC, //TSGMODE, + TXTSP_0X0200_INSEL_LML, //INSEL, + 0, //BSTART, + 1u); + uint32_t reg_txmod_s = reg_txmod; + SET_LMS7002M_TXTSP_0X0200_BSTART(reg_txmod_s, 1); + uint32_t xxtsp_regs[] = { + (tsp == LMS_RXTSP) ? reg_rxmod : reg_txmod, + (tsp == LMS_RXTSP) ? reg_rxmod_s : reg_txmod_s, + }; + return lms7002m_spi_post(m, xxtsp_regs, SIZEOF_ARRAY(xxtsp_regs)); +} // xxTSP int lms7002m_xxtsp_enable(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, bool enable) diff --git a/src/lib/hw/lms7002m/lms7002m.h b/src/lib/hw/lms7002m/lms7002m.h index 2a55703f..9431687f 100644 --- a/src/lib/hw/lms7002m/lms7002m.h +++ b/src/lib/hw/lms7002m/lms7002m.h @@ -99,8 +99,10 @@ struct lms7002m_lml_map { }; typedef struct lms7002m_lml_map lms7002m_lml_map_t; +int lms7002m_limelight_toggle_ntx(lms7002m_state_t* m); int lms7002m_limelight_reset(lms7002m_state_t* m); - +int lms7002m_limelight_fifo_reset(lms7002m_state_t* m, bool rx, bool tx); +int lms7002m_limelight_l_reset(lms7002m_state_t* m, bool rx, bool tx); struct lms7002m_limelight_conf { uint8_t rxsisoddr : 1; @@ -167,7 +169,7 @@ typedef enum lms7002m_xxtsp lms7002m_xxtsp_t; // TSTPs int lms7002m_rxtsp_dc_corr(lms7002m_state_t* m, bool byp, unsigned wnd); - +int lms7002m_xxtsp_bst(lms7002m_state_t* m, lms7002m_xxtsp_t tsp); int lms7002m_xxtsp_enable(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, bool enable); int lms7002m_xxtsp_int_dec(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, unsigned intdec_ord); diff --git a/src/tools/lms7002_dm_limelight.c b/src/tools/lms7002_dm_limelight.c index 40cd495d..0fd25b4f 100644 --- a/src/tools/lms7002_dm_limelight.c +++ b/src/tools/lms7002_dm_limelight.c @@ -186,6 +186,7 @@ enum LML_MODE { LML_MODE_NORMAL = 0, LML_MODE_LOOPBACK = 1, LML_MODE_LFSR = 2, + LML_MODE_LOOPBACK_GEN = 3, }; static pdm_dev_t dev = NULL; @@ -213,6 +214,7 @@ static void dev_exit() static void dev_set_rate(unsigned rate) { int res; + unsigned lmode = mode; for (unsigned k = 0; ; k ++) { res = !dev ? 0 : usdr_dmr_rate_set(dev, NULL, rate); @@ -226,7 +228,11 @@ static void dev_set_rate(unsigned rate) } } - res = !dev ? 0 : usdr_dme_set_uint(dev, "/debug/hw/lms7002m/0/rxlml", mode); + if (lmode == LML_MODE_LOOPBACK_GEN) { + lmode = LML_MODE_LOOPBACK; + } + + res = !dev ? 0 : usdr_dme_set_uint(dev, "/debug/hw/lms7002m/0/rxlml", lmode); if (res) { USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device mode: errno %d", res); dev_exit(); @@ -262,6 +268,33 @@ static void dev_set_rx_phase(unsigned val) USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device LML RX DLY: errno %d", res); dev_exit(); } + +} + +static void dev_set_tx_phase_rc(unsigned val) +{ + int res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/tx/phase_ovr_rc", val); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device LML TX VAL IQ: errno %d", res); + dev_exit(); + } +} + +static void dev_set_tx_phase(unsigned val, unsigned val_iq) +{ + unsigned mode = val + 1; + unsigned mode_iq = val_iq + 1; + int res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/tx/phase_ovr", mode); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device LML TX: errno %d", res); + dev_exit(); + } + + res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/tx/phase_ovr_iq", mode_iq); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device LML TX IQ: errno %d", res); + dev_exit(); + } } static void dev_set_rx_lfsr_hw_checker(bool en) @@ -273,6 +306,15 @@ static void dev_set_rx_lfsr_hw_checker(bool en) } } +static void dev_set_tx_lfsr_hw_generator(bool en) +{ + int res = !dev ? 0 : usdr_dme_set_uint(dev, "/dm/sdr/0/phy_tx_lfsr", en); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set HW LFSR Generator: errno %d", res); + dev_exit(); + } +} + static void dev_get_rx_lfsr_hw_checker(unsigned errs[4]) { uint64_t v = 0; @@ -321,7 +363,7 @@ static void dev_init() const char* synctype = "all"; int res; - bool tx = (mode != LML_MODE_LFSR); + bool tx = (mode == LML_MODE_LOOPBACK); usdr_channel_info_t chans_rx; usdr_channel_info_t chans_tx; @@ -614,7 +656,7 @@ enum { void do_lfsr_test(lfsr_stream_t str[TOTAL_STREAMS]) { int res; - unsigned flags = 0; //FLAGS_ERRORS; + unsigned flags = 0; //FLAGS_VERBOSE; for (unsigned i = 0; i < TOTAL_STREAMS; i++) { lfsr_init(&str[i], 4, 0xffe); str[i].xor_stage = i & 1; // LML interface invert bit in LFSR stream for Q components @@ -664,9 +706,89 @@ void do_lfsr_test(lfsr_stream_t str[TOTAL_STREAMS]) } } - #define MAX_TAPS 64 +void do_lfsr_hwtx_test(unsigned str[TOTAL_STREAMS]) +{ + dev_set_tx_lfsr_hw_generator(false); + usleep(1); + dev_set_tx_lfsr_hw_generator(true); + dev_set_rx_lfsr_hw_checker(true); + usleep(1000 * maximum_iterations); + dev_get_rx_lfsr_hw_checker(str); +} + +void lfsr_test_hw_tx() +{ + mode = LML_MODE_LOOPBACK_GEN; + float rate = specific_rate; + unsigned str[MAX_TAPS][TOTAL_STREAMS]; + + dev_set_rate(rate); + dev_init(); + + for (unsigned k = 0; k < MAX_TAPS; k++) { + //dev_init(); + //dev_set_tx_phase(k, 0); // CLK + //dev_set_rate(rate); + + dev_set_tx_phase_rc(k); + do_lfsr_hwtx_test(str[k]); + } + + dev_deinit(); + + for (unsigned j = 0; j < 4; j++) { + fprintf(stderr, "TXCH%d: ", j); + + for (unsigned k = 0; k < MAX_TAPS; k++) { + unsigned ecnt = str[k][j]; + + fprintf(stderr, "%c", (ecnt == 0) ? ' ' : (ecnt < 1000) ? 'x' : 'X'); + } + + fprintf(stderr, "\n"); + } +} + + +void lfsr_test_shw_tx() +{ + mode = LML_MODE_LOOPBACK_GEN; + float rate = specific_rate; + dev_set_rate(rate); + + unsigned str[MAX_TAPS][MAX_TAPS][TOTAL_STREAMS]; + + for (unsigned l = 0; l < MAX_TAPS; l++) { + for (unsigned k = 0; k < MAX_TAPS; k++) { + dev_init(); + + dev_set_tx_phase(k, l); // CLK + dev_set_rate(rate); + + do_lfsr_hwtx_test(str[l][k]); + + dev_deinit(); + } + } + + for (unsigned l = 0; l < MAX_TAPS; l++) { + for (unsigned j = 0; j < 4; j++) { + fprintf(stderr, "TX_IQ%d_CH%d: ", l, j); + + for (unsigned k = 0; k < MAX_TAPS; k++) { + unsigned ecnt = str[l][k][j]; + + fprintf(stderr, "%c", (ecnt == 0) ? ' ' : (ecnt < 1000) ? 'x' : 'X'); + } + fprintf(stderr, "\n"); + } + } + +} + + void do_lfsr_hw_test(unsigned str[TOTAL_STREAMS]) { dev_set_rx_lfsr_hw_checker(true); @@ -708,9 +830,9 @@ void lfsr_test_hw() } -void lfsr_tests() +void lfsr_tests(bool hwgen) { - mode = LML_MODE_LFSR; + mode = hwgen ? LML_MODE_LOOPBACK_GEN : LML_MODE_LFSR ; lfsr_stream_t str[MAX_TAPS][TOTAL_STREAMS]; dev_set_vio(2300); @@ -727,10 +849,17 @@ void lfsr_tests() for (unsigned h = 0; h < 12; h++) { dev_set_rx_dly(h + 2, k); // D0 } -#else - dev_set_rx_phase(k); // CLK - dev_set_rate(rate); #endif + if (hwgen) { + dev_set_tx_lfsr_hw_generator(true); + dev_set_tx_phase(k, k); // CLK + } else { + dev_set_rx_phase(k); // CLK + } + dev_set_rate(rate); + + +//#endif do_lfsr_test(str[k]); dev_deinit(); @@ -800,11 +929,14 @@ int main(int argc, char** argv) unsigned statistics = 0; + bool hwtxrx_tests = false; + bool shwtx_tests = false; + bool hwtx_tests = false; bool hw_tests = false; bool dump_rx = false; int opt, res; - while ((opt = getopt(argc, argv, "Mi:r:j:D:t:l:dow")) != -1) { + while ((opt = getopt(argc, argv, "Mi:r:j:D:t:l:dowWZz")) != -1) { switch (opt) { case 'M': memcached = true; @@ -834,9 +966,18 @@ int main(int argc, char** argv) case 'o': dump_rx = true; break; + case 'z': + hwtxrx_tests = true; + break; + case 'W': + hwtx_tests = true; + break; case 'w': hw_tests = true; break; + case 'Z': + shwtx_tests = true; + break; default: exit(EXIT_FAILURE); } @@ -865,10 +1006,14 @@ int main(int argc, char** argv) // Tests - if (hw_tests) { + if (shwtx_tests) { + lfsr_test_shw_tx(); + } else if (hwtx_tests) { + lfsr_test_hw_tx(); + } else if (hw_tests) { lfsr_test_hw(); } else { - lfsr_tests(); + lfsr_tests(hwtxrx_tests); } res = dry_run ? 0 : usdr_dmd_close(dev); From e472f5ce98ee70fdc4bd0d02405c360fd113f825 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 19 Sep 2025 22:53:13 +0400 Subject: [PATCH 172/397] xsdr: sync with new firmware --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 7 ++++ src/lib/device/m2_lm7_1/xsdr_ctrl.c | 53 ++++++++++++----------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 591e803e..66379c21 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -350,6 +350,7 @@ struct dev_m2_lm7_1_gps { struct dev_fe* fe; bool bifurcation_en; bool nodecint; + bool double_pump; int cal_data[8]; @@ -1109,6 +1110,7 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* d->bifurcation_en = false; d->nodecint = false; + d->double_pump = false; for (unsigned i = 0; i < pcount; i++) { if (strcmp(devparam[i], "fe") == 0) { @@ -1120,12 +1122,17 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* if (strcmp(devparam[i], "nodec") == 0) { d->nodecint = true; } + if (strcmp(devparam[i], "dpump") == 0) { + d->double_pump = true; + } } res = xsdr_init(&d->xdev); if (res) return res; + d->dpump = d->double_pump; + if (d->xdev.new_rev) { // Init FE res = device_fe_probe(udev, d->xdev.ssdr ? "m2b+m" : "m2a+e", fe, I2C_BUS_FRONTEND, &d->fe); diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index c0b81f6f..38adfb39 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -300,22 +300,31 @@ int xsdr_phy_tx_iqsel(xsdr_dev_t *d, uint8_t iqsel) return xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, iqsel); } +static int _xsdr_mmcm_pd(xsdr_dev_t *d) +{ + return xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 2); +} + int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned txphase, unsigned txphase_off) { - bool nomul = d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); + bool nomul = (rx_master) ? d->base.lml_mode.rxsisoddr || (d->base.rxtsp_div > 1) : + d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); unsigned mmcm_ctrl_sel = (rx_master) ? 0 : 4; unsigned tx_mclk = d->base.cgen_clk / d->base.txcgen_div / d->base.lml_mode.txdiv; - unsigned io_clk = (nomul) ? tx_mclk : tx_mclk * 2; + unsigned rx_mclk = d->base.cgen_clk / d->base.rxcgen_div / d->base.lml_mode.rxdiv; + unsigned io_mclk = (rx_master) ? rx_mclk : tx_mclk; + unsigned io_clk = (nomul) ? io_mclk : io_mclk * 2; unsigned vco_div_io_m = (MMCM_VCO_MAX + io_clk - 1) / io_clk; if (vco_div_io_m > 63) vco_div_io_m = 63; - unsigned vco_div_io = vco_div_io_m & 0xfc; //Multiply of 4 + //unsigned vco_div_io = vco_div_io_m & 0xfc; //Multiply of 4 + unsigned vco_div_io = vco_div_io_m & 0xff; // & 0xfc; //Multiply of 4 int res = 0; struct mmcm_config_raw cfg_raw; memset(&cfg_raw, 0, sizeof(cfg_raw)); - if (vco_div_io * io_clk < MMCM_VCO_MIN) { + if (vco_div_io * io_clk < MMCM_VCO_MIN && vco_div_io < 63) { if ((vco_div_io + 2) * io_clk > MMCM_VCO_MAX) { vco_div_io += 1; } else { @@ -908,16 +917,16 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, } if (rxrate) { +#if 0 if (d->mmcm_rx) { res = res ? res : xsdr_configure_lml_mmcm_rx(d); } - +#endif sisosdrflag = d->base.lml_mode.rxsisoddr ? 8 : 0; res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); usleep(100); res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); - - +#if 0 if (d->mmcm_rx) { // Configure PHY (reset) // TODO phase search @@ -938,6 +947,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : mmcm_set_digdelay_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_RX, CLKOUT_PORT_0, h); } } +#endif // Switch to clock meas res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); @@ -1797,6 +1807,7 @@ int xsdr_init(xsdr_dev_t *d) d->mmcm_tx = tx_mmcm; d->cfg_srate_siso_rx = 0; d->cfg_srate_siso_tx = 0; + d->dpump = false; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); if (res) @@ -1849,6 +1860,8 @@ int xsdr_dtor(xsdr_dev_t *d) res = (res) ? res : dev_gpo_set(dev, IGPO_LDOLMS_EN, 0); res = (res) ? res : dev_gpo_set(dev, IGPO_LED, 0); + res = (res) ? res : _xsdr_mmcm_pd(d); + if (d->ssdr) { res = res ? res : lp8758_vout_set(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, 900); res = res ? res : lp8758_vout_ctrl(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, 0, 1); @@ -1896,32 +1909,8 @@ int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen) LMS7_CH_AB, 0, LMS7_CH_AB, 0); - //if (txen) { - // TODO: Add proper delay calibration - // assign cfg_rx_idelay_addr = ~igp_phydly[3:0]; - // assign cfg_rx_idelay_data = { 1'b0, igp_phydly[7:4] }; - // 0..11 D0..D11 - // 12 IQSEL - // 13 *idle* - // 14 FCLK - // 15 *idle* - // const unsigned coeff = 0x40; - // res = (res) ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_PHYCAL, coeff | 1); - // usleep(1); - // res = (res) ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_PHYCAL, coeff | 0); - // if (res) { - // return res; - // } - //} - - // res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); - - - //if (d->txrate) { - res = res ? res : _xsdr_calibrate_lml(d); - //} - + res = res ? res : _xsdr_calibrate_lml(d); return res; } From 9f3bc43612074c50751766d0f879e298add24d68 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 19 Sep 2025 23:27:38 +0400 Subject: [PATCH 173/397] fix build --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 2 +- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 66379c21..c537af6a 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -1131,7 +1131,7 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* if (res) return res; - d->dpump = d->double_pump; + d->xdev.dpump = d->double_pump; if (d->xdev.new_rev) { // Init FE diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 60511660..4dda0263 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -67,6 +67,8 @@ struct xsdr_dev bool pwr_en; bool new_rev; bool ssdr; + + bool dpump; //Dual pump data union { bool pmic_ch145_valid; bool dac_old_r5; From d2a0f3d4e4da86654cf37a55659e3253b42d1830 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 22 Sep 2025 13:03:17 +0400 Subject: [PATCH 174/397] xsdr: update rx calibration --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 8 +++ src/lib/device/m2_lm7_1/xsdr_ctrl.c | 77 ++++++++++++++++++----------- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index c537af6a..abc13cff 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -1244,6 +1244,10 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha // TODO: update samplerate settings } + if (d->double_pump) { + d->xdev.siso_sdr_active_rx = true; + } + // Reset samplerate with proper bifurcation flags if (rxcfg.bifurcation_valid != ((d->xdev.s_flags & XSDR_LML_SISO_DDR_RX) ? true : false)) { res = xsdr_set_samplerate_ex(&d->xdev, d->xdev.s_rxrate, d->xdev.s_txrate, @@ -1291,6 +1295,10 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha // TODO: update samplerate settings } + if (d->double_pump) { + d->xdev.siso_sdr_active_tx = true; + } + res = xsdr_prepare(&d->xdev, d->rx, true); if (res) { return res; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 38adfb39..9268cd50 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -232,6 +232,15 @@ int xsdr_phy_en_lfsr_generator_mimo(xsdr_dev_t *d, bool en, bool lfsr) return res; } +static int _xsdr_rxserdes_reset(xsdr_dev_t *d) { + int res = 0; + unsigned sisosdrflag = d->dpump ? 16 : d->base.lml_mode.rxsisoddr ? 8 : 0; + res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); + res = res ? res : usleep(10); + res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); + return res; +} + int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, size_t meminsz, void* pin, size_t memoutsz, const void* pout) @@ -307,8 +316,9 @@ static int _xsdr_mmcm_pd(xsdr_dev_t *d) int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned txphase, unsigned txphase_off) { - bool nomul = (rx_master) ? d->base.lml_mode.rxsisoddr || (d->base.rxtsp_div > 1) : - d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); + bool nomul = d->dpump ? false : + (rx_master) ? d->base.lml_mode.rxsisoddr || (d->base.rxtsp_div > 1) : + d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); unsigned mmcm_ctrl_sel = (rx_master) ? 0 : 4; unsigned tx_mclk = d->base.cgen_clk / d->base.txcgen_div / d->base.lml_mode.txdiv; unsigned rx_mclk = d->base.cgen_clk / d->base.rxcgen_div / d->base.lml_mode.rxdiv; @@ -320,6 +330,9 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, //unsigned vco_div_io = vco_div_io_m & 0xfc; //Multiply of 4 unsigned vco_div_io = vco_div_io_m & 0xff; // & 0xfc; //Multiply of 4 + if (!nomul) { + vco_div_io = vco_div_io_m & 0xfe; + } int res = 0; struct mmcm_config_raw cfg_raw; memset(&cfg_raw, 0, sizeof(cfg_raw)); @@ -404,7 +417,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; } - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d VCO=%.3f MHZ OFF=%d\n", + USDR_LOG("XDEV", USDR_LOG_INFO, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d VCO=%.3f MHZ OFF=%d\n", tx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io, (d->tx_override_phase) ? "_OVR" : "", cfg_raw.ports[CLKOUT_PORT_0].delay, cfg_raw.ports[CLKOUT_PORT_0].phase, @@ -568,6 +581,14 @@ static bool noerrors_v4(unsigned errs[4], uint64_t* badness) return errs[0] == 0 && errs[1] == 0 && errs[2] == 0 && errs[3] == 0; } +static bool noerrors_v2(unsigned errs[4], uint64_t* badness) +{ + if (badness) { + *badness = (errs[0]*errs[0]) + (errs[1]*errs[1]); + } + return errs[0] == 0 && errs[1] == 0; +} + int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v) { int res = 0; @@ -597,10 +618,10 @@ static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); res = res ? res : usleep(1); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : _xsdr_rxserdes_reset(d); // In case of RX-TX in the same MMCM res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); //res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); - for (w = 0; w < check_to; w++) { res = res ? res : usleep(100); res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); @@ -622,6 +643,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (d->mmcm_tx) { res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, 0, 0, 0); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); + res = res ? res : _xsdr_rxserdes_reset(d); // Autocalibration if RX phase wasn't set if (d->rx_override_phase == 0) { @@ -631,18 +653,15 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) unsigned iqserrs; unsigned errs[4] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX }; - for (unsigned rxrty = 0; rxrty < 4; rxrty++) { - - // Boost IO voltage for stable high speed link - if (!d->siso_sdr_active_rx && d->new_rev && d->s_rxrate > 85e6) { + if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && d->s_rxrate > 85e6) { res = res ? res : xsdr_set_vio(d, 1910); - } - if (!d->siso_sdr_active_rx && !d->ssdr && d->s_rxrate > 60e6) { - res = res ? res : xsdr_set_vio(d, 1910); - res = res ? res : lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, 1320); + } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && d->s_rxrate > 60e6) { + res = res ? res : xsdr_set_vio(d, 1940); + res = res ? res : lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, 1340); } + for (unsigned rxrty = 0; rxrty < 4; rxrty++) { uint64_t badness_m = UINT64_MAX; unsigned c; @@ -654,13 +673,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) for (c = 0; c < check_to; c++) { res = res ? res : usleep(1000); res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - if (res || !noerrors_v4(errs, &badness_m)) + if (res || (d->dpump ? !noerrors_v2(errs, &badness_m) : !noerrors_v4(errs, &badness_m))) break; } - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=AUTO [%d/%d/%d/%d]\n", - errs[0], errs[1], errs[2], errs[3]); - if (res || noerrors_v4(errs, &badness_m)) + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=AUTO [%d/%d/%d/%d] DPUMP=%d res=%d\n", + errs[0], errs[1], errs[2], errs[3], d->dpump, res); + if (res || (d->dpump ? noerrors_v2(errs, &badness_m) : noerrors_v4(errs, &badness_m))) goto phase_calibrated; @@ -680,12 +699,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : usleep(10); res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, ph, 0, 0); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : _xsdr_rxserdes_reset(d); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); for (w = 0; w < check_to; w++) { res = res ? res : usleep(100); res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - if (res || !noerrors_v4(errs, &badness)) { + if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { break; } } @@ -693,7 +713,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", ph - 1, w, errs[0], errs[1], errs[2], errs[3], (long long)badness); - if (res || noerrors_v4(errs, &badness)) { + if (res || (d->dpump ? noerrors_v2(errs, &badness) : noerrors_v4(errs, &badness))) { phase_m = ph; if (ph < phase_min) phase_min = ph; @@ -703,6 +723,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) // Got more than 7 phases, we're safe; skip searching if (phase_max - phase_min > 7) break; + if (d->s_rxrate > 60e6) + goto phase_calibrated; } else if (phase_max >= phase_min) { break; } @@ -716,12 +738,6 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (phase_max > phase_min) { phase_m = (phase_max + phase_min) / 2; } - //if (badness_m == 0) - // break; - // - //USDR_LOG("XDEV", USDR_LOG_WARNING, " == RX RESETTING == \n"); - //lms7002m_limelight_reset(d); - //} USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring RX pahse to %d (bandness=%" PRId64 ") PH_MIN=%d PH_MAX=%d\n", phase_m - 1, badness_m, phase_min, phase_max); @@ -729,6 +745,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) // Try our best at least res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, phase_m, 0, 0); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : _xsdr_rxserdes_reset(d); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); { uint64_t badness = UINT64_MAX; @@ -736,7 +753,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) for (w = 0; w < check_to; w++) { res = res ? res : usleep(100); res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - if (res || !noerrors_v4(errs, &badness)) { + if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { break; } } @@ -874,7 +891,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, { lldev_t dev = d->base.lmsstate.dev; subdev_t subdev = d->base.lmsstate.subdev; - unsigned sisosdrflag; + // unsigned sisosdrflag; int res; if (!(((d->hwid) & 0xff) & PHY_CFG_VALID_MSK)) { @@ -890,8 +907,8 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, rxrate = 1e6; } - unsigned m_flags = flags | ((d->siso_sdr_active_rx && d->hwchans_rx == 1) ? XSDR_LML_SISO_DDR_RX : 0) - | ((d->siso_sdr_active_tx && d->hwchans_tx == 1) ? XSDR_LML_SISO_DDR_TX : 0); + unsigned m_flags = flags | (((d->siso_sdr_active_rx && d->hwchans_rx == 1) || d->dpump) ? XSDR_LML_SISO_DDR_RX : 0) + | (((d->siso_sdr_active_tx && d->hwchans_tx == 1) || d->dpump) ? XSDR_LML_SISO_DDR_TX : 0); res = lms7002m_samplerate(&d->base, rxrate, txrate, adcclk, dacclk, m_flags, d->rx_port_is_1); if (res) @@ -922,10 +939,12 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : xsdr_configure_lml_mmcm_rx(d); } #endif - sisosdrflag = d->base.lml_mode.rxsisoddr ? 8 : 0; +#if 0 + sisosdrflag = d->dpump ? 16 : d->base.lml_mode.rxsisoddr ? 8 : 0; res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); usleep(100); res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); +#endif #if 0 if (d->mmcm_rx) { // Configure PHY (reset) From 52c22c4ed70adb4a12f5652bc746da73020c721e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 22 Sep 2025 14:19:30 +0400 Subject: [PATCH 175/397] xsdr --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 51 ++++++++++++++++++----------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 9268cd50..a40d81b6 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -241,6 +241,15 @@ static int _xsdr_rxserdes_reset(xsdr_dev_t *d) { return res; } +static int _xsdr_txserdes_reset(xsdr_dev_t *d) { + int res = 0; + // Reset OSERDESE2 + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); + res = res ? res : usleep(1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); + return res; +} + int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, size_t meminsz, void* pin, size_t memoutsz, const void* pout) @@ -596,11 +605,7 @@ int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v) d->tx_override_phase = v; res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, 0, 0); - - // Reset OSERDESE2 - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); - res = res ? res : usleep(1); - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); + res = res ? res : _xsdr_txserdes_reset(d); return res; } @@ -613,12 +618,10 @@ static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, unsigned w; // Reset OSERDESE2 - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); - res = res ? res : usleep(1); - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); + res = res ? res : _xsdr_txserdes_reset(d); res = res ? res : usleep(1); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); - res = res ? res : _xsdr_rxserdes_reset(d); // In case of RX-TX in the same MMCM + //res = res ? res : _xsdr_rxserdes_reset(d); // In case of RX-TX in the same MMCM res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); //res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); @@ -639,8 +642,14 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) { int res = 0; bool mmcm_rx_only_path = (!d->base.tx_run[0] && !d->base.tx_run[1]); + bool old_rx_run[2] = { d->base.rx_run[0], d->base.rx_run[1] }; if (d->mmcm_tx) { + if (!(d->base.rx_run[0] || d->base.rx_run[1])) { + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, IGPO_LMS_PWR_LDOEN | IGPO_LMS_PWR_NRESET | IGPO_LMS_PWR_RXEN | IGPO_LMS_PWR_TXEN); + res = res ? res : lms7002m_streaming_up(&d->base, RFIC_LMS7_RX, LMS7_CH_AB, 0, 0, 0); + } + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, 0, 0, 0); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); res = res ? res : _xsdr_rxserdes_reset(d); @@ -806,14 +815,11 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph + 1, rty); res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, rty); - - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); - res = res ? res : usleep(1); - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); - res = res ? res : usleep(1); - // res = res ? res : lms7002m_limelight_l_reset(&d->base.lmsstate, false, true); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); + res = res ? res : _xsdr_txserdes_reset(d); + res = res ? res : usleep(1); + } else if (g > 0) { USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); break; @@ -873,13 +879,18 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } no_tx: - res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); + if (!old_rx_run[0] && !old_rx_run[1]) { + // No RX, disable it + res = res ? res : lms7002m_streaming_down(&d->base, RFIC_LMS7_RX); + } else { + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); + } // Reset TSP - if (true) { - res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); - // res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); - } + //if (true) { + // res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); + // // res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); + //} return res; } From 1c5474fc221821da693e7554badd2817beb65d17 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 22 Sep 2025 16:36:15 +0400 Subject: [PATCH 176/397] xsdr: lml cal --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index a40d81b6..92e23858 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -295,7 +295,7 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, static struct mmcm_config_raw g_tx_cfg_raw; -int xsdr_upd_phase(xsdr_dev_t *d) +int xsdr_upd_phase(xsdr_dev_t *d) { if (d->tx_override_phase) { unsigned raw = d->tx_override_phase - 1; @@ -404,7 +404,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, // cfg_raw.ports[CLKOUT_PORT_1].delay = raw / 8; // } - if (d->tx_override_phase || txphase) { + if (d->tx_override_phase || txphase || txphase_off) { unsigned raw = (txphase != 0) ? ((txphase - 1 + txphase_off) % 64) : d->tx_override_phase - 1; cfg_raw.ports[CLKOUT_PORT_6].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = raw / 8; @@ -647,6 +647,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (d->mmcm_tx) { if (!(d->base.rx_run[0] || d->base.rx_run[1])) { res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, IGPO_LMS_PWR_LDOEN | IGPO_LMS_PWR_NRESET | IGPO_LMS_PWR_RXEN | IGPO_LMS_PWR_TXEN); + res = res ? res : usleep(1000); res = res ? res : lms7002m_streaming_up(&d->base, RFIC_LMS7_RX, LMS7_CH_AB, 0, 0, 0); } @@ -777,10 +778,10 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } phase_calibrated: - if (mmcm_rx_only_path) + d->lmlcal_rx_phase = phase_m; + if (mmcm_rx_only_path) goto no_tx; - d->lmlcal_rx_phase = phase_m; res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_DIGLOOPBACK); res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); @@ -789,7 +790,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) uint64_t badness_m = UINT64_MAX; phase_m = 0; for (unsigned rty = 0; rty < 64; rty++) { - for (unsigned ph = 1; ph < 64; ph++) { + for (unsigned ph = 1; ph < 65; ph++) { //unsigned w; uint64_t badness = UINT64_MAX; res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, rty); From f16a756e0c86fbb9367790eb6171023fa00a275c Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 22 Sep 2025 17:03:30 +0400 Subject: [PATCH 177/397] xsdr lml cal --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 92e23858..3ce90fc1 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -339,9 +339,9 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, //unsigned vco_div_io = vco_div_io_m & 0xfc; //Multiply of 4 unsigned vco_div_io = vco_div_io_m & 0xff; // & 0xfc; //Multiply of 4 - if (!nomul) { - vco_div_io = vco_div_io_m & 0xfe; - } + //if (!nomul) { + // vco_div_io = vco_div_io_m & 0xfe; + //} int res = 0; struct mmcm_config_raw cfg_raw; memset(&cfg_raw, 0, sizeof(cfg_raw)); @@ -710,6 +710,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, ph, 0, 0); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); res = res ? res : _xsdr_rxserdes_reset(d); + res = res ? res : usleep(10); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); for (w = 0; w < check_to; w++) { @@ -756,6 +757,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, phase_m, 0, 0); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); res = res ? res : _xsdr_rxserdes_reset(d); + res = res ? res : usleep(10); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); { uint64_t badness = UINT64_MAX; From 543aadba34fd70c74f5cd704487cbf1be05c7721 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 22 Sep 2025 18:43:34 +0400 Subject: [PATCH 178/397] xsdr lml --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 3ce90fc1..de283d69 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -621,7 +621,8 @@ static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, res = res ? res : _xsdr_txserdes_reset(d); res = res ? res : usleep(1); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); - //res = res ? res : _xsdr_rxserdes_reset(d); // In case of RX-TX in the same MMCM + res = res ? res : _xsdr_rxserdes_reset(d); // In case of RX-TX in the same MMCM + res = res ? res : usleep(20); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); //res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); @@ -771,7 +772,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } badness *= 1.0 * check_to / (w + 1); // Rescale if (badness > badness_m * 2) { - USDR_LOG("XDEV", USDR_LOG_INFO, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, + USDR_LOG("XDEV", USDR_LOG_WARNING, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, errs[0], errs[1], errs[2], errs[3], (long long)badness); continue; } @@ -791,11 +792,14 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) uint64_t badness_m = UINT64_MAX; phase_m = 0; - for (unsigned rty = 0; rty < 64; rty++) { + for (unsigned rty = 0; rty < 8; rty++) { + const unsigned iq_phases[8] = { 0, 1, 2, 62, 63, 2, 1, 0}; + unsigned iq_ph = iq_phases[rty]; + for (unsigned ph = 1; ph < 65; ph++) { //unsigned w; uint64_t badness = UINT64_MAX; - res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, rty); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, iq_ph); res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness); USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e\n", ph - 1, @@ -816,8 +820,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (iqserrs > 40) { USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); - res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph + 1, rty); - res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, rty); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph + 1, iq_ph); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, iq_ph); // res = res ? res : lms7002m_limelight_l_reset(&d->base.lmsstate, false, true); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); res = res ? res : _xsdr_txserdes_reset(d); From eea46d0803e9bad72df5e35fd5636154d6071e96 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 24 Sep 2025 14:38:02 +0400 Subject: [PATCH 179/397] xsdr: oprimized for xsdr_r1_master_22092025_3_noiqp_nodiv_hstl_lpwr_hclk2.bin --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 146 +++++++++++++++++++++------- 1 file changed, 112 insertions(+), 34 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index de283d69..3135be5c 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -323,6 +323,7 @@ static int _xsdr_mmcm_pd(xsdr_dev_t *d) return xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 2); } +static int g_clk_reduce = 0; int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned txphase, unsigned txphase_off) { bool nomul = d->dpump ? false : @@ -334,6 +335,9 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned io_mclk = (rx_master) ? rx_mclk : tx_mclk; unsigned io_clk = (nomul) ? io_mclk : io_mclk * 2; unsigned vco_div_io_m = (MMCM_VCO_MAX + io_clk - 1) / io_clk; + + vco_div_io_m += g_clk_reduce; + if (vco_div_io_m > 63) vco_div_io_m = 63; @@ -365,9 +369,16 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, // 5 - FCLK_RX // 6 - FCLK_TX +#define SEP_CLKDIV + cfg_raw.type = MT_7SERIES_MMCM; +#ifndef SEP_CLKDIV cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; // IO_TX_IQSEL cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; // IO_TX_IQSEL +#else + cfg_raw.ports[CLKOUT_PORT_0].period_l = vco_div_io; // IO_TX CLKDIV + cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io; // IO_TX CLKDIV +#endif cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; // IO_TX cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; // IO_TX @@ -385,19 +396,26 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned total_budget = 8 * vco_div_io; unsigned phase = (((tx_mclk < 2*35e6) || (tx_mclk > 2*60e6)) ? 4 : 5) * total_budget / 6; - unsigned phase_iq = 4; + unsigned phase_iq = 0; //4; cfg_raw.ports[CLKOUT_PORT_6].phase = phase % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = phase / 8; + +#ifndef SEP_CLKDIV cfg_raw.ports[CLKOUT_PORT_0].phase = phase_iq % 8; cfg_raw.ports[CLKOUT_PORT_0].delay = phase_iq / 8; - if (d->tx_override_phase_iq || txphase) { - unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase_iq - 1; + if (d->tx_override_phase_iq || txphase || txphase_off) { + //unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase_iq - 1; + + unsigned raw = (txphase != 0) ? txphase_off : d->tx_override_phase_iq - 1; cfg_raw.ports[CLKOUT_PORT_0].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_0].delay = raw / 8; } - +#else + cfg_raw.ports[CLKOUT_PORT_0].phase = 0; + cfg_raw.ports[CLKOUT_PORT_0].delay = 0; +#endif // if (d->tx_override_phase || txphase) { // unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase - 1; // cfg_raw.ports[CLKOUT_PORT_1].phase = raw % 8; @@ -405,7 +423,9 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, // } if (d->tx_override_phase || txphase || txphase_off) { - unsigned raw = (txphase != 0) ? ((txphase - 1 + txphase_off) % 64) : d->tx_override_phase - 1; + //unsigned raw = (txphase != 0) ? ((txphase - 1 + txphase_off) % 64) : d->tx_override_phase - 1; + + unsigned raw = (txphase != 0) ? (txphase - 1) : d->tx_override_phase - 1; cfg_raw.ports[CLKOUT_PORT_6].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = raw / 8; } @@ -645,13 +665,28 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) bool mmcm_rx_only_path = (!d->base.tx_run[0] && !d->base.tx_run[1]); bool old_rx_run[2] = { d->base.rx_run[0], d->base.rx_run[1] }; + uint64_t rx_badness = UINT64_MAX; + uint64_t tx_badness = UINT64_MAX; + unsigned tx_iqerrs = UINT_MAX; + + g_clk_reduce = 0; + if (d->mmcm_tx) { + // Boost IO voltage for stable high speed link + if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && d->s_rxrate > 85e6) { + res = res ? res : xsdr_set_vio(d, 1910); + } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && d->s_rxrate > 50e6) { + res = res ? res : xsdr_set_vio(d, 1940); + res = res ? res : lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, 1340); + } + if (!(d->base.rx_run[0] || d->base.rx_run[1])) { res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, IGPO_LMS_PWR_LDOEN | IGPO_LMS_PWR_NRESET | IGPO_LMS_PWR_RXEN | IGPO_LMS_PWR_TXEN); res = res ? res : usleep(1000); res = res ? res : lms7002m_streaming_up(&d->base, RFIC_LMS7_RX, LMS7_CH_AB, 0, 0, 0); } + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, 0, 0, 0); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); res = res ? res : _xsdr_rxserdes_reset(d); @@ -664,20 +699,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) unsigned iqserrs; unsigned errs[4] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX }; - // Boost IO voltage for stable high speed link - if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && d->s_rxrate > 85e6) { - res = res ? res : xsdr_set_vio(d, 1910); - } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && d->s_rxrate > 60e6) { - res = res ? res : xsdr_set_vio(d, 1940); - res = res ? res : lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, 1340); - } for (unsigned rxrty = 0; rxrty < 4; rxrty++) { uint64_t badness_m = UINT64_MAX; unsigned c; phase_m = 0; - +#if 0 res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); res = res ? res : usleep(10); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); @@ -693,6 +721,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (res || (d->dpump ? noerrors_v2(errs, &badness_m) : noerrors_v4(errs, &badness_m))) goto phase_calibrated; +#endif + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); int phase_min; int phase_max; @@ -735,8 +765,10 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) // Got more than 7 phases, we're safe; skip searching if (phase_max - phase_min > 7) break; - if (d->s_rxrate > 60e6) - goto phase_calibrated; + //if (d->s_rxrate > 60e6) { + // rx_badness = badness; + // goto phase_calibrated; + //} } else if (phase_max >= phase_min) { break; } @@ -771,17 +803,22 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } } badness *= 1.0 * check_to / (w + 1); // Rescale - if (badness > badness_m * 2) { + rx_badness = badness; + if (badness > 100 /*badness_m * 2*/) { USDR_LOG("XDEV", USDR_LOG_WARNING, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, errs[0], errs[1], errs[2], errs[3], (long long)badness); + + g_clk_reduce++; continue; } } + break; } phase_calibrated: d->lmlcal_rx_phase = phase_m; + if (mmcm_rx_only_path) goto no_tx; @@ -790,7 +827,10 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); //res = res ? res : xsdr_phy_en_iqab_checker_mimo(d, true); + bool mmcx_rx_path = false; + bool check_rx = false; uint64_t badness_m = UINT64_MAX; + unsigned failed_rxcnt = 0; phase_m = 0; for (unsigned rty = 0; rty < 8; rty++) { const unsigned iq_phases[8] = { 0, 1, 2, 62, 63, 2, 1, 0}; @@ -799,15 +839,37 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) for (unsigned ph = 1; ph < 65; ph++) { //unsigned w; uint64_t badness = UINT64_MAX; - res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, iq_ph); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph, iq_ph); + if (check_rx) { + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); + res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : _xsdr_rxserdes_reset(d); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + res = res ? res : usleep(100); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { + USDR_LOG("XDEV", USDR_LOG_WARNING, "FAIL_PHASE_RX=%2d PH=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", d->lmlcal_rx_phase, ph - 1, + errs[0], errs[1], errs[2], errs[3], (long long)badness); + if (badness > 20) { + if (failed_rxcnt < 6) { + ph--; + failed_rxcnt++; + continue; + } + } + } + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_DIGLOOPBACK); + failed_rxcnt = 0; + } res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness); USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e\n", ph - 1, errs[0], errs[1], errs[2], errs[3], iqserrs, (double)badness); - if (res || (noerrors_v4(errs, &badness) && (iqserrs == 0))) { + if (res || (noerrors_v4(errs, &badness) /* && (iqserrs == 0)*/) || (rty > 1 && badness < 20)) { phase_m = ph; - for (int g = 0; g < 50; g++) { + for (int g = 0; g < 12/*50*/; g++) { // Check A/B & I/Q aligment is ok res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); res = res ? res : usleep(10); @@ -817,15 +879,25 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (res) return res; - if (iqserrs > 40) { - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); + if (rty == 0 && iqserrs != 0 || iqserrs > 40) { + USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX[%d]=%2d ABIQ=%d\n", g, ph - 1, iqserrs); - res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph + 1, iq_ph); - res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, ph, iq_ph); - // res = res ? res : lms7002m_limelight_l_reset(&d->base.lmsstate, false, true); + //goto phase_tx_calibrated; + unsigned msk[12] = { 0b1100, 0b0110, 0b0011, 0b1001, 0b1000, 0b0100, 0b0010, 0b0001, 0b1100, 0b0110, 0b1001, 0b1100 }; + + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : msk[g + 1]); + //res = res ? res : _xsdr_txserdes_reset(d); + res = res ? res : usleep(10); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); - res = res ? res : _xsdr_txserdes_reset(d); - res = res ? res : usleep(1); + res = res ? res : usleep(10); + + //res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph + 1, iq_ph); + //res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph, iq_ph); + // res = res ? res : lms7002m_limelight_l_reset(&d->base.lmsstate, false, true); + //res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); + //res = res ? res : _xsdr_txserdes_reset(d); + //res = res ? res : _xsdr_rxserdes_reset(d); + //res = res ? res : usleep(10); } else if (g > 0) { USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); @@ -833,11 +905,14 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } } - if (iqserrs > 40) { + if (rty == 0 && iqserrs != 0 || iqserrs > 40) { USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); continue; } + + tx_badness = badness; + tx_iqerrs = iqserrs; goto phase_tx_calibrated; } @@ -849,12 +924,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } // Try to toggle clock inversion res = res ? res : lms7002m_limelight_toggle_ntx(&d->base.lmsstate); + check_rx = true; } USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring TX pahse to %d (bandness=%" PRId64 ")\n", phase_m, badness_m); // Try our best at least - res = res ? res : xsdr_configure_lml_mmcm_tx(d, false, d->lmlcal_rx_phase, phase_m, ph_ty_m); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, phase_m, ph_ty_m); // Make sure it's a good value res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness_m); @@ -870,6 +946,9 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (res) return res; + tx_badness = badness_m; + tx_iqerrs = iqserrs2; + USDR_LOG("XDEV", USDR_LOG_INFO, "RESTORE PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d - %6d] BD=%.3e\n", phase_m - 1, errs[0], errs[1], errs[2], errs[3], iqserrs, iqserrs2, (double)badness_m); @@ -893,12 +972,11 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); } - // Reset TSP - //if (true) { - // res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); - // // res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); - //} - + if (rx_badness || !mmcm_rx_only_path && (tx_badness || tx_iqerrs)) { + bool severe = (rx_badness > 100) || (!mmcm_rx_only_path && (tx_badness > 100 || tx_iqerrs > 10)); + USDR_LOG("XDEV", severe ? USDR_LOG_ERROR : USDR_LOG_WARNING, "LML Calibration failed: RX_BADNESS=%"PRId64" TX_BADNESS=%"PRId64" TX_IQERRS=%d\n", + rx_badness, mmcm_rx_only_path ? 0 : tx_badness, mmcm_rx_only_path ? 0 : tx_iqerrs); + } return res; } From f29e24f4cf5c12faa5097cc67c88e3eae9fb7a47 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 26 Sep 2025 12:52:22 +0400 Subject: [PATCH 180/397] fix tests --- src/lib/xdsp/utests/xdsp_utest_common.h | 4 ++++ src/utests/lmk05318_solver_test.c | 14 ++++++++++++++ src/utests/lmx1204_solver_test.c | 5 +++++ src/utests/lmx1214_solver_test.c | 7 +++++++ src/utests/lmx2820_solver_test.c | 14 ++++++++++++++ 5 files changed, 44 insertions(+) diff --git a/src/lib/xdsp/utests/xdsp_utest_common.h b/src/lib/xdsp/utests/xdsp_utest_common.h index 22fd488f..74e63ead 100644 --- a/src/lib/xdsp/utests/xdsp_utest_common.h +++ b/src/lib/xdsp/utests/xdsp_utest_common.h @@ -12,6 +12,10 @@ #include "../../cal/opt_func.h" #include "conv.h" +// tcase_set_tags() was introduced in check 0.11.0 +#if CHECK_MINOR_VERSION < 11 +#define tcase_set_tags(x, y) +#endif #define ALIGN_BYTES (size_t)64 diff --git a/src/utests/lmk05318_solver_test.c b/src/utests/lmk05318_solver_test.c index 678c5277..abce5b17 100644 --- a/src/utests/lmk05318_solver_test.c +++ b/src/utests/lmk05318_solver_test.c @@ -41,6 +41,7 @@ START_TEST(lmk05318_solver_test1) int res = lmk05318_solver(&dev, cfg, SIZEOF_ARRAY(cfg)); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_solver_test3) { @@ -76,6 +77,7 @@ START_TEST(lmk05318_solver_test3) res = lmk05318_solver(&dev, cfg, SIZEOF_ARRAY(cfg)); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_solver_test4) { @@ -117,6 +119,7 @@ START_TEST(lmk05318_solver_test4) res = lmk05318_solver(&dev, cfg + 4, 4); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_solver_test5) { @@ -138,6 +141,7 @@ START_TEST(lmk05318_solver_test5) ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_solver_pesync) { @@ -168,6 +172,7 @@ START_TEST(lmk05318_solver_pesync) ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_solver_pesync_free_run) { @@ -188,6 +193,7 @@ START_TEST(lmk05318_solver_pesync_free_run) res = lmk05318_create(NULL, 0, 0, 25000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_dpll_test1) { @@ -204,6 +210,7 @@ START_TEST(lmk05318_dpll_test1) int res = lmk05318_dpll_config(&dev, &dpll); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_dsdr_test1) { @@ -235,6 +242,7 @@ START_TEST(lmk05318_dsdr_test1) res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_dsdr_test2) { @@ -266,6 +274,7 @@ START_TEST(lmk05318_dsdr_test2) res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, &dpll, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_dsdr_test3) { @@ -287,6 +296,7 @@ START_TEST(lmk05318_dsdr_test3) res = lmk05318_create(NULL, 0, 0, 26000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } +END_TEST static int simplesync_pd_low_chs(lmk05318_state_t* st) @@ -367,6 +377,7 @@ START_TEST(lmk05318_simplesync_test1) res = lmk05318_simplesync_set_lo_freq(&st, 0); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_solver_test_xmass) { @@ -417,6 +428,7 @@ START_TEST(lmk05318_solver_test_xmass) res = res ? res : lmk05318_reg_wr_from_map(&st, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_hyper_test1) { @@ -438,6 +450,7 @@ START_TEST(lmk05318_hyper_test1) res = lmk05318_create(NULL, 0, 0, 52000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmk05318_customer_test1) { @@ -459,6 +472,7 @@ START_TEST(lmk05318_customer_test1) res = lmk05318_create(NULL, 0, 0, 52000000, XO_CMOS, false, NULL, cfg, SIZEOF_ARRAY(cfg), &st, true /*dry_run*/); ck_assert_int_eq( res, 0 ); } +END_TEST Suite * lmk05318_solver_suite(void) diff --git a/src/utests/lmx1204_solver_test.c b/src/utests/lmx1204_solver_test.c index 7bb4b6fc..7406f69a 100644 --- a/src/utests/lmx1204_solver_test.c +++ b/src/utests/lmx1204_solver_test.c @@ -53,6 +53,7 @@ START_TEST(lmx1204_solver_test1) int res = lmx1204_solver(&st, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1204_solver_test2) { @@ -68,6 +69,7 @@ START_TEST(lmx1204_solver_test2) int res = lmx1204_solver(&st, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1204_solver_test3) { @@ -84,6 +86,7 @@ START_TEST(lmx1204_solver_test3) int res = lmx1204_solver(&st, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1204_solver_test4) { @@ -99,6 +102,7 @@ START_TEST(lmx1204_solver_test4) int res = lmx1204_solver(&st, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1204_solver_test5) { @@ -115,6 +119,7 @@ START_TEST(lmx1204_solver_test5) int res = lmx1204_solver(&st, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST Suite * lmx1204_solver_suite(void) { diff --git a/src/utests/lmx1214_solver_test.c b/src/utests/lmx1214_solver_test.c index 0f65f122..98b62db8 100644 --- a/src/utests/lmx1214_solver_test.c +++ b/src/utests/lmx1214_solver_test.c @@ -25,6 +25,7 @@ START_TEST(lmx1214_solver_test1) int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1214_solver_test2) { @@ -40,6 +41,7 @@ START_TEST(lmx1214_solver_test2) int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1214_solver_test3) { @@ -55,6 +57,7 @@ START_TEST(lmx1214_solver_test3) int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1214_solver_test4_pesync0) { @@ -70,6 +73,7 @@ START_TEST(lmx1214_solver_test4_pesync0) int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1214_solver_test4_pesync1) { @@ -85,6 +89,7 @@ START_TEST(lmx1214_solver_test4_pesync1) int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, true, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1214_solver_test4_pesync2) { @@ -100,6 +105,7 @@ START_TEST(lmx1214_solver_test4_pesync2) int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx1214_solver_test4_pesync3) { @@ -115,6 +121,7 @@ START_TEST(lmx1214_solver_test4_pesync3) int res = lmx1214_solver(&st, osc_in, out_freq, en, &aux, false, true); ck_assert_int_eq( res, 0 ); } +END_TEST Suite * lmx1214_solver_suite(void) { diff --git a/src/utests/lmx2820_solver_test.c b/src/utests/lmx2820_solver_test.c index f3655069..e6e2a725 100644 --- a/src/utests/lmx2820_solver_test.c +++ b/src/utests/lmx2820_solver_test.c @@ -21,6 +21,7 @@ START_TEST(lmx2820_solver_test1) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test2) { @@ -32,6 +33,7 @@ START_TEST(lmx2820_solver_test2) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test3) { @@ -43,6 +45,7 @@ START_TEST(lmx2820_solver_test3) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test4) { @@ -54,6 +57,7 @@ START_TEST(lmx2820_solver_test4) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test5) { @@ -65,6 +69,7 @@ START_TEST(lmx2820_solver_test5) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test6) { @@ -76,6 +81,7 @@ START_TEST(lmx2820_solver_test6) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test7) { @@ -87,6 +93,7 @@ START_TEST(lmx2820_solver_test7) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test8) { @@ -98,6 +105,7 @@ START_TEST(lmx2820_solver_test8) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test9_force_mult) { @@ -109,6 +117,7 @@ START_TEST(lmx2820_solver_test9_force_mult) int res = lmx2820_solver(&st, osc_in, mash_order, _i, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test10_mash_order) { @@ -119,6 +128,7 @@ START_TEST(lmx2820_solver_test10_mash_order) int res = lmx2820_solver(&st, osc_in, _i, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test11_mash_order) { @@ -129,6 +139,7 @@ START_TEST(lmx2820_solver_test11_mash_order) int res = lmx2820_solver(&st, osc_in, _i, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test12_instcal) { @@ -145,6 +156,7 @@ START_TEST(lmx2820_solver_test12_instcal) res = lmx2820_solver_instcal(&st, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test13_pesync) { @@ -156,6 +168,7 @@ START_TEST(lmx2820_solver_test13_pesync) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST START_TEST(lmx2820_solver_test14_pesync) { @@ -172,6 +185,7 @@ START_TEST(lmx2820_solver_test14_pesync) int res = lmx2820_solver(&st, osc_in, mash_order, 0, out_freq1, out_freq2); ck_assert_int_eq( res, 0 ); } +END_TEST Suite * lmx2820_solver_suite(void) From 6c866764aa49e3722b0c419834877beaac465791 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 26 Sep 2025 12:53:02 +0400 Subject: [PATCH 181/397] soapy: fix test SoapySDR application --- src/soapysdr/test_usdr_soapy.c | 53 +++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/src/soapysdr/test_usdr_soapy.c b/src/soapysdr/test_usdr_soapy.c index b30967f6..2670e304 100644 --- a/src/soapysdr/test_usdr_soapy.c +++ b/src/soapysdr/test_usdr_soapy.c @@ -1,33 +1,50 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT -#include -#include -#include + #include //printf #include //free #include #include +#include +#include +#include #define MAX_CHANS 16 -#define MAX_PACKETSIZE 4096 +#define MAX_PACKETSIZE 1024 * 1024 + +void decToString(int val, char* buf) +{ + snprintf(buf, 31, "%d", val); +} + +float buff[2 * MAX_CHANS * MAX_PACKETSIZE]; int main(int argc, char** argv) { int opt; const char* device = ""; unsigned channels = 1; + unsigned packetSize = 131072; + unsigned samplerate = 4e6; + double rxFreq = 912.3e6; size_t act_channels[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - while ((opt = getopt(argc, argv, "d:c:")) != -1) { + while ((opt = getopt(argc, argv, "d:c:i:r:")) != -1) { switch (opt) { + case 'r': + samplerate = atof(optarg); + break; case 'd': device = optarg; break; case 'c': channels = atoi(optarg); break; + case 'i': + packetSize = atoi(optarg); + break; } } @@ -36,6 +53,11 @@ int main(int argc, char** argv) exit(1); } + if (packetSize == 0 || packetSize > MAX_PACKETSIZE) { + printf("Incorrect packet size!\n"); + exit(1); + } + size_t length; //enumerate devices @@ -94,11 +116,13 @@ int main(int argc, char** argv) free(ranges); //apply settings - if (SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, 0, 1e6) != 0) { + if (SoapySDRDevice_setSampleRate(sdr, SOAPY_SDR_RX, 0, samplerate) != 0) { printf("setSampleRate fail: %s\n", SoapySDRDevice_lastError()); + exit(1); } - if (SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, 0, 912.3e6, NULL) != 0) { + if (SoapySDRDevice_setFrequency(sdr, SOAPY_SDR_RX, 0, rxFreq, NULL) != 0) { printf("setFrequency fail: %s\n", SoapySDRDevice_lastError()); + exit(1); } ranges = SoapySDRDevice_getFrequencyRangeComponent(sdr, SOAPY_SDR_RX, 0, "BB", &length); @@ -110,18 +134,25 @@ int main(int argc, char** argv) free(ranges); //setup a stream (complex floats) + char packetSizeStr[32]; + decToString(packetSize, packetSizeStr); + SoapySDRKwargs streamArgs = {}; + SoapySDRKwargs_set(&streamArgs, "bufferLength", packetSizeStr); + SoapySDRStream *rxStream; #if (SOAPY_SDR_API_VERSION < 0x00080000) - if (SoapySDRDevice_setupStream(sdr, &rxStream, SOAPY_SDR_RX, SOAPY_SDR_CF32, act_channels, channels, NULL) != 0) { + if (SoapySDRDevice_setupStream(sdr, &rxStream, SOAPY_SDR_RX, SOAPY_SDR_CF32, act_channels, channels, &streamArgs) != 0) { #else - if ((rxStream = SoapySDRDevice_setupStream(sdr, SOAPY_SDR_RX, SOAPY_SDR_CF32, act_channels, channels, NULL)) != NULL) { + if ((rxStream = SoapySDRDevice_setupStream(sdr, SOAPY_SDR_RX, SOAPY_SDR_CF32, act_channels, channels, &streamArgs)) != NULL) { #endif printf("setupStream fail: %s\n", SoapySDRDevice_lastError()); + exit(1); } SoapySDRDevice_activateStream(sdr, rxStream, 0, 0, 0); //start streaming + SoapySDRKwargs_clear(&streamArgs); + //create a re-usable buffer for rx samples - float buff[2 * MAX_CHANS * MAX_PACKETSIZE]; void* buffs[MAX_CHANS]; for (unsigned j = 0; j < MAX_CHANS; j++) { buffs[j] = &buff[2 * j * MAX_PACKETSIZE]; @@ -131,7 +162,7 @@ int main(int argc, char** argv) for (size_t i = 0; i < 10; i++) { int flags; //flags set by receive operation long long timeNs; //timestamp for receive buffer - int ret = SoapySDRDevice_readStream(sdr, rxStream, buffs, MAX_PACKETSIZE, &flags, &timeNs, 100000); + int ret = SoapySDRDevice_readStream(sdr, rxStream, buffs, packetSize, &flags, &timeNs, 100000); printf("ret=%d, flags=%d, timeNs=%lld\n", ret, flags, timeNs); } From ed96840e5f2ad73af49adcf751ee2e73d9d70fd2 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 30 Sep 2025 15:06:38 +0400 Subject: [PATCH 182/397] ssdr: sync with GW --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 128 ++++++++++-------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 23 +++- src/lib/ipblks/streams/sfe_rx_4.c | 16 ++- src/lib/ipblks/streams/sfe_rx_4.h | 2 +- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 19 ++- 5 files changed, 117 insertions(+), 71 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 3135be5c..b0b144cd 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -334,18 +334,13 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned rx_mclk = d->base.cgen_clk / d->base.rxcgen_div / d->base.lml_mode.rxdiv; unsigned io_mclk = (rx_master) ? rx_mclk : tx_mclk; unsigned io_clk = (nomul) ? io_mclk : io_mclk * 2; - unsigned vco_div_io_m = (MMCM_VCO_MAX + io_clk - 1) / io_clk; + unsigned vco_div_io = (MMCM_VCO_MAX + io_clk - 1) / io_clk; - vco_div_io_m += g_clk_reduce; + vco_div_io += g_clk_reduce; - if (vco_div_io_m > 63) - vco_div_io_m = 63; + if (vco_div_io > 63) + vco_div_io = 63; - //unsigned vco_div_io = vco_div_io_m & 0xfc; //Multiply of 4 - unsigned vco_div_io = vco_div_io_m & 0xff; // & 0xfc; //Multiply of 4 - //if (!nomul) { - // vco_div_io = vco_div_io_m & 0xfe; - //} int res = 0; struct mmcm_config_raw cfg_raw; memset(&cfg_raw, 0, sizeof(cfg_raw)); @@ -361,7 +356,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 0); res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); - // 0 - n/a ( was IO_TX_IQSEL -- individual phase delay ) + // 0 - IO_TX_DIV ( was IO_TX_IQSEL -- individual phase delay ) // 1 - IO_TX // 2 - IO_RX // 3 - n/a ( was LOGIC_TX ) @@ -396,7 +391,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned total_budget = 8 * vco_div_io; unsigned phase = (((tx_mclk < 2*35e6) || (tx_mclk > 2*60e6)) ? 4 : 5) * total_budget / 6; - unsigned phase_iq = 0; //4; + // unsigned phase_iq = 0; //4; cfg_raw.ports[CLKOUT_PORT_6].phase = phase % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = phase / 8; @@ -481,7 +476,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, usleep(10); } - USDR_LOG("XDEV", USDR_LOG_WARNING, "MMCM Redy flag timed out!\n"); + USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM Redy flag timed out!\n"); return -EIO; } @@ -673,11 +668,16 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (d->mmcm_tx) { // Boost IO voltage for stable high speed link - if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && d->s_rxrate > 85e6) { + if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && (d->s_rxrate > 85e6 || d->s_txrate > 85e6)) { res = res ? res : xsdr_set_vio(d, 1910); - } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && d->s_rxrate > 50e6) { + } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && (d->s_rxrate > 70e6 || d->s_txrate > 70e6)) { res = res ? res : xsdr_set_vio(d, 1940); - res = res ? res : lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, 1340); + res = res ? res : xsdr_set_lms125vdd(d, 1320); + } + + // Fixup for 53-58 MSPS range, but still 58 to 60 might be unoperable on some chips, and 60+ works fine again + if (!mmcm_rx_only_path && d->new_rev && !d->ssdr && (d->s_txrate >= 53e6 && d->s_txrate <= 60e6)) { + res = res ? res : xsdr_set_lms125vdd(d, 1360); } if (!(d->base.rx_run[0] || d->base.rx_run[1])) { @@ -686,11 +686,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_streaming_up(&d->base, RFIC_LMS7_RX, LMS7_CH_AB, 0, 0, 0); } - res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, 0, 0, 0); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); res = res ? res : _xsdr_rxserdes_reset(d); + if (res) + return res; + // Autocalibration if RX phase wasn't set if (d->rx_override_phase == 0) { const unsigned check_to = 10; @@ -702,26 +704,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) for (unsigned rxrty = 0; rxrty < 4; rxrty++) { uint64_t badness_m = UINT64_MAX; - unsigned c; phase_m = 0; -#if 0 - res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); - res = res ? res : usleep(10); - res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); - for (c = 0; c < check_to; c++) { - res = res ? res : usleep(1000); - res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - if (res || (d->dpump ? !noerrors_v2(errs, &badness_m) : !noerrors_v4(errs, &badness_m))) - break; - } - - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=AUTO [%d/%d/%d/%d] DPUMP=%d res=%d\n", - errs[0], errs[1], errs[2], errs[3], d->dpump, res); - if (res || (d->dpump ? noerrors_v2(errs, &badness_m) : noerrors_v4(errs, &badness_m))) - goto phase_calibrated; - -#endif res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); int phase_min; @@ -765,10 +749,6 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) // Got more than 7 phases, we're safe; skip searching if (phase_max - phase_min > 7) break; - //if (d->s_rxrate > 60e6) { - // rx_badness = badness; - // goto phase_calibrated; - //} } else if (phase_max >= phase_min) { break; } @@ -816,7 +796,6 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) break; } - phase_calibrated: d->lmlcal_rx_phase = phase_m; if (mmcm_rx_only_path) @@ -879,10 +858,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (res) return res; - if (rty == 0 && iqserrs != 0 || iqserrs > 40) { + if ((rty == 0 && iqserrs != 0) || iqserrs > 40) { USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX[%d]=%2d ABIQ=%d\n", g, ph - 1, iqserrs); - - //goto phase_tx_calibrated; unsigned msk[12] = { 0b1100, 0b0110, 0b0011, 0b1001, 0b1000, 0b0100, 0b0010, 0b0001, 0b1100, 0b0110, 0b1001, 0b1100 }; res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : msk[g + 1]); @@ -891,21 +868,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); res = res ? res : usleep(10); - //res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph + 1, iq_ph); - //res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph, iq_ph); - // res = res ? res : lms7002m_limelight_l_reset(&d->base.lmsstate, false, true); - //res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); - //res = res ? res : _xsdr_txserdes_reset(d); - //res = res ? res : _xsdr_rxserdes_reset(d); - //res = res ? res : usleep(10); - } else if (g > 0) { USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); break; } } - if (rty == 0 && iqserrs != 0 || iqserrs > 40) { + if ((rty == 0 && iqserrs != 0) || iqserrs > 40) { USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); continue; @@ -972,10 +941,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); } - if (rx_badness || !mmcm_rx_only_path && (tx_badness || tx_iqerrs)) { + if (rx_badness || (!mmcm_rx_only_path && (tx_badness || tx_iqerrs))) { bool severe = (rx_badness > 100) || (!mmcm_rx_only_path && (tx_badness > 100 || tx_iqerrs > 10)); USDR_LOG("XDEV", severe ? USDR_LOG_ERROR : USDR_LOG_WARNING, "LML Calibration failed: RX_BADNESS=%"PRId64" TX_BADNESS=%"PRId64" TX_IQERRS=%d\n", rx_badness, mmcm_rx_only_path ? 0 : tx_badness, mmcm_rx_only_path ? 0 : tx_iqerrs); + + if (res == 0 && severe) + res = -ERANGE; } return res; } @@ -1375,14 +1347,30 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, double freq, double *actualfreq) { - if (d->ssdr && freq > 3.7e9) { + if (d->ssdr && freq > 3.0e9) { + float bwef = d->lms8st_bwef_1000 / 1000.0; int res = 0; - d->lms7_lob = 1.01e9; + d->lms7_lob = 2.01e9; res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); - res = res ? res : lms8001_tune(&d->lms8, d->base.fref, freq - d->lms7_lob); - dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x80); +#if 0 + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 2, 0); + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 3, 0); +#else + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 0, 0, 0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 1, 0, 0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 2, 0, 0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 3, 0, 0); +#endif + res = res ? res : lms8001_core_enable(&d->lms8, 1); + res = res ? res : lms8001_ch_enable(&d->lms8, 0xf); + + //res = res ? res : lms8001_tune(&d->lms8, d->base.fref, freq - d->lms7_lob); + res = res ? res : lms8001_smart_tune(&d->lms8, 0, freq - d->lms7_lob, d->base.fref, + d->lms8st_loopbw, d->lms8st_phasemargin, bwef, d->lms8st_flock_n); + + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x80); if (res) return res; @@ -1451,6 +1439,17 @@ int xsdr_ctor(lldev_t dev, xsdr_dev_t *d) d->base.on_ant_port_sw = &_xsdr_antenna_port_switch; d->base.on_get_lml_portcfg = &lms7nfe_get_lml_portcfg; + d->lms8_rx_f_switchover = 3.5e9; + d->lms8_tx_f_switchover = 3.5e9; + + d->lms8st_loopbw = 300000; + d->lms8st_phasemargin = 50; + d->lms8st_bwef_1000 = 2000; + d->lms8st_flock_n = 100; + d->lms8st_iq_gen = 0; + d->lms8st_int_mod = 0; + d->lms8st_enabled = 1; + return 0; } @@ -1577,6 +1576,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x002F0000, &chipver); USDR_LOG("XDEV", USDR_LOG_INFO, "LMS7002 version %08x\n", chipver); +#if 0 res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x81); usleep(100000); @@ -1587,13 +1587,14 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : lms8001_create(dev, d->base.lmsstate.subdev, 0, &d->lms8); res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x80); + //res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x00); // res = res ? res : dev_gpo_set(dev, IGPO_LDOLMS_EN, 0); // Enable LDOs // res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0); if (chipver != 0x00004040) { USDR_LOG("XDEV", USDR_LOG_ERROR, "LMS8001 not detected!\n"); } - +#endif } return res; } @@ -1830,6 +1831,15 @@ int _xsdr_pwren_revo(xsdr_dev_t *d, bool on) return 0; } +int xsdr_set_lms125vdd(xsdr_dev_t *d, unsigned vdd_mv) +{ + if (d->new_rev && !d->ssdr) { + return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, vdd_mv); + } + + return -EINVAL; +} + int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) { if (!d->new_rev) { @@ -1925,9 +1935,9 @@ int xsdr_init(xsdr_dev_t *d) d->dpump = false; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); - if (res) + if (res) { return res; - + } switch (hwcfg_devid) { case XSDR_DEV: d->new_rev = true; d->ssdr = false; break; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 4dda0263..b7f3bc0c 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -16,9 +16,10 @@ #define RFIC_CHANS 2 enum xsdr_devices { - SSDR_DEV = 0x31, - XSDR_DEV = 0x30, - XTRX_DEV = 0x2e, + SSDR2_DEV = 0x32, + SSDR_DEV = 0x31, + XSDR_DEV = 0x30, + XTRX_DEV = 0x2e, }; @@ -73,6 +74,21 @@ struct xsdr_dev bool pmic_ch145_valid; bool dac_old_r5; }; + + // LMS8001 parameter + bool lms8_rx_path_active; + bool lms8_tx_path_active; + + uint32_t lms8_rx_f_switchover; + uint32_t lms8_tx_f_switchover; + uint32_t lms8st_loopbw; + uint32_t lms8st_phasemargin; + uint32_t lms8st_bwef_1000; + uint32_t lms8st_flock_n; + uint32_t lms8st_iq_gen; + uint32_t lms8st_int_mod; + uint32_t lms8st_enabled; + }; typedef struct xsdr_dev xsdr_dev_t; @@ -139,6 +155,7 @@ int xsdr_dtor(xsdr_dev_t *d); int xsdr_set_extref(xsdr_dev_t *d, bool ext, uint32_t freq); int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv); +int xsdr_set_lms125vdd(xsdr_dev_t *d, unsigned vdd_mv); // Enable RFIC, no streaming int xsdr_pwren(xsdr_dev_t *d, bool on); diff --git a/src/lib/ipblks/streams/sfe_rx_4.c b/src/lib/ipblks/streams/sfe_rx_4.c index 3857082e..cdaf5265 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.c +++ b/src/lib/ipblks/streams/sfe_rx_4.c @@ -355,7 +355,8 @@ static int _configure_simple_fe_generic(const sfe_cfg_t* fe, int sfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, - struct fifo_config* pfc) + struct fifo_config* pfc, + uint64_t *pwr_ch_mask) { struct bitsfmt bfmt = get_bits_fmt(psc->sfmt); if (strcmp((const char*)bfmt.func, &DSPFUNC_CFFT_LPWR_I16[1]) == 0) { @@ -430,8 +431,19 @@ int sfe_rx4_configure(const sfe_cfg_t* fe, return -EINVAL; } + switch (chfmt) { + case IFMT_CH_3210: *pwr_ch_mask = 0b1111; break; + case IFMT_CH_xx10: *pwr_ch_mask = 0b0011; break; + case IFMT_CH_xxx0: *pwr_ch_mask = 0b0001; break; + case IFMT_CH_xx1x: *pwr_ch_mask = 0b0010; break; + case IFMT_CH_x2x0: *pwr_ch_mask = 0b0101; break; + case IFMT_CH_32xx: *pwr_ch_mask = 0b1100; break; + case IFMT_CH_x2xx: *pwr_ch_mask = 0b0100; break; + case IFMT_CH_3xxx: *pwr_ch_mask = 0b1000; break; + } + unsigned fe_format = ((bfmt.bits == 8) ? IFMT_8BIT : (bfmt.bits == 12) ? IFMT_12BIT : IFMT_16BIT); - return _configure_simple_fe_generic(fe, psc, bfmt.bits, 1, fe_format,chfmt, chns, pfc); + return _configure_simple_fe_generic(fe, psc, bfmt.bits, 1, fe_format, chfmt, chns, pfc); } diff --git a/src/lib/ipblks/streams/sfe_rx_4.h b/src/lib/ipblks/streams/sfe_rx_4.h index 81c29d67..62fb3dd9 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.h +++ b/src/lib/ipblks/streams/sfe_rx_4.h @@ -10,7 +10,7 @@ int sfe_rx4_check_format(const struct stream_config* psc); int sfe_rx4_configure(const sfe_cfg_t *fe, const struct stream_config* psc, - struct fifo_config* pfc); + struct fifo_config* pfc, uint64_t *pwr_ch_mask); int sfe_rx4_throttle(const sfe_cfg_t* fe, bool enable, uint8_t send, uint8_t skip); diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index ca95c9cb..2349e630 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -87,6 +87,8 @@ struct stream_sfetrx_dma32 { } storage; extxcfg_cache_t cstx4; + + uint64_t hw_pwr_mask; // Powered chans (hw) }; typedef struct stream_sfetrx_dma32 stream_sfetrx_dma32_t; @@ -678,6 +680,7 @@ static int initialize_stream_rx_32(device_t* device, { int res; stream_sfetrx_dma32_t* strdev; + uint64_t hw_chan_msk = 0; res = dma_rx32_reset(device->dev, 0, sx_base); if (res) @@ -753,7 +756,7 @@ static int initialize_stream_rx_32(device_t* device, // TODO obtain exfe configuration constants res = (fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0) ? exfe_rx4_configure(fecfg, &sc, &fc) : - sfe_rx4_configure(fecfg, &sc, &fc); + sfe_rx4_configure(fecfg, &sc, &fc, &hw_chan_msk); if (res) return res; @@ -829,8 +832,10 @@ static int initialize_stream_rx_32(device_t* device, strdev->fe_complex = bfmt.complex; strdev->storage.srx4 = *fecfg; - USDR_LOG("DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%d WireBytes=%d HostBytes=%d Bursts=%d\n", - strdev->pkt_symbs, strdev->wire_bps, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count); + strdev->hw_pwr_mask = hw_chan_msk; + + USDR_LOG("DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64"\n", + strdev->pkt_symbs, strdev->wire_bps, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask); *outu = strdev; return 0; @@ -882,7 +887,7 @@ static int initialize_stream_tx_32(device_t* device, { int res; stream_sfetrx_dma32_t* strdev; - + uint64_t pwr_hw_mask = 0; struct stream_config sc; unsigned logicchs = chcount; @@ -975,6 +980,7 @@ static int initialize_stream_tx_32(device_t* device, } fe_old_tx_mute = (sc.chcnt == 1) ? (fe_old_tx_swap ? 1 : 2) : 0; + pwr_hw_mask = (sc.chcnt == 2) ? 0b1111 : (fe_old_tx_swap ? 0b1100 : 0b0011); } else { if (sc.chcnt > (fecfg->cfg_raw_chans / (bfmt.complex ? 2 : 1))) return -EINVAL; @@ -1111,8 +1117,9 @@ static int initialize_stream_tx_32(device_t* device, strdev->storage.srx4 = *fecfg; extxcfg_cache_init(&strdev->cstx4); - USDR_LOG("DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%d WireBytes=%d HostBytes=%d Bursts=%d\n", - strdev->pkt_symbs, strdev->wire_bps, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count); + strdev->hw_pwr_mask = pwr_hw_mask; + USDR_LOG("DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64"\n", + strdev->pkt_symbs, strdev->wire_bps, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask); *outu = strdev; return 0; From df57e9368acdc19eb73252012710bb3a3d89edf7 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 2 Oct 2025 15:17:37 +0400 Subject: [PATCH 183/397] ssdr: add fe_4ch support --- src/lib/device/CMakeLists.txt | 1 + src/lib/device/device_fe.c | 60 +- .../device/ext_fe_ch4_400_7200/CMakeLists.txt | 20 + .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c | 598 ++++++++++++++++++ .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h | 84 +++ .../ext_fe_ch4_400_7200_e.yaml | 249 ++++++++ .../ext_fe_ch4_400_7200_usr.yaml | 144 +++++ src/lib/device/m2_lm7_1/xsdr_ctrl.c | 2 +- src/lib/hw/tmp114/tmp114.h | 3 +- src/lib/ipblks/gpio.h | 1 + 10 files changed, 1135 insertions(+), 27 deletions(-) create mode 100644 src/lib/device/ext_fe_ch4_400_7200/CMakeLists.txt create mode 100644 src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c create mode 100644 src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h create mode 100644 src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml create mode 100644 src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml diff --git a/src/lib/device/CMakeLists.txt b/src/lib/device/CMakeLists.txt index 1192cd3c..4b452188 100644 --- a/src/lib/device/CMakeLists.txt +++ b/src/lib/device/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(ext_pciefe) add_subdirectory(ext_supersync) add_subdirectory(ext_simplesync) add_subdirectory(ext_fe_100_5000) +add_subdirectory(ext_fe_ch4_400_7200) add_subdirectory(ext_xmass) diff --git a/src/lib/device/device_fe.c b/src/lib/device/device_fe.c index 5176701c..aab41d5e 100644 --- a/src/lib/device/device_fe.c +++ b/src/lib/device/device_fe.c @@ -10,6 +10,7 @@ #include "ext_simplesync/ext_simplesync.h" #include "ext_fe_100_5000/ext_fe_100_5000.h" #include "ext_xmass/ext_xmass.h" +#include "ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h" #include #include @@ -87,7 +88,7 @@ enum fe_type { FET_PCIE_SIMPLE_SYNC, FET_PICE_BREAKOUT, FET_PCIE_FE1005000, - + FET_PCIE_FE4CH4007200, FET_COUNT }; typedef enum fe_type fe_type_t; @@ -99,6 +100,7 @@ static const char* s_fe_names[] = { "simplesync", "exm2pe", "fe1005000", + "fe4ch4007200", }; @@ -113,6 +115,7 @@ struct dev_fe { board_ext_supersync_t supersync; ext_fe_100_5000_t fe_100_5000; board_xmass_t xmass; + ext_fe_ch4_400_7200_t fe_4ch_400_7200; } fe; uint32_t debug_pciefe_last; @@ -154,7 +157,7 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi lldev_t dev = base->dev; unsigned i; int res; - dev_fe_t dfe; + dev_fe_t *dfe = (dev_fe_t*)malloc(sizeof(dev_fe_t)); unsigned vfidx = 0; const char* hint = fename; @@ -170,7 +173,7 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi const unsigned uartbase = 54; const unsigned spiext_cfg = 58; - memset(&dfe, 0, sizeof(dfe)); + memset(dfe, 0, sizeof(dev_fe_t)); usdr_core_info_t fe_gpio; usdr_core_info_t fe_uart; @@ -197,13 +200,14 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi } switch (i) { - case FET_PICE_BREAKOUT: res = board_exm2pe_init(dev, 0, gpiobase, uartbase, hint_strip, compat, def_i2c_loc, &dfe.fe.exm2pe); break; - case FET_PCIE_DEVBOARD: res = board_ext_pciefe_init(dev, 0, gpiobase, uartbase, hint_strip, compat, def_i2c_loc, &dfe.fe.devboard); break; - case FET_PCIE_SUPER_SYNC: res = board_ext_supersync_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe.fe.supersync); break; - case FET_PCIE_SIMPLE_SYNC: res = board_ext_simplesync_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe.fe.simplesync); break; - case FET_PCIE_FE1005000: res = ext_fe_100_5000_init(dev, 0, gpiobase, spiext_cfg, 4, hint_strip, compat, &dfe.fe.fe_100_5000); break; - case FET_PCIE_XMASS: res = board_xmass_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe.fe.xmass); break; - default: return -EIO; + case FET_PICE_BREAKOUT: res = board_exm2pe_init(dev, 0, gpiobase, uartbase, hint_strip, compat, def_i2c_loc, &dfe->fe.exm2pe); break; + case FET_PCIE_DEVBOARD: res = board_ext_pciefe_init(dev, 0, gpiobase, uartbase, hint_strip, compat, def_i2c_loc, &dfe->fe.devboard); break; + case FET_PCIE_SUPER_SYNC: res = board_ext_supersync_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe->fe.supersync); break; + case FET_PCIE_SIMPLE_SYNC: res = board_ext_simplesync_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe->fe.simplesync); break; + case FET_PCIE_FE1005000: res = ext_fe_100_5000_init(dev, 0, gpiobase, spiext_cfg, 4, hint_strip, compat, &dfe->fe.fe_100_5000); break; + case FET_PCIE_XMASS: res = board_xmass_init(dev, 0, gpiobase, compat, def_i2c_loc, &dfe->fe.xmass); break; + case FET_PCIE_FE4CH4007200: res = ext_fe_ch4_400_7200_init(dev, 0, gpiobase, hint_strip, compat, &dfe->fe.fe_4ch_400_7200); break; + default: res = -EIO; goto failed; } if (res == 0) { @@ -211,63 +215,61 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi } else if (res != -ENODEV) { USDR_LOG("DEFE", USDR_LOG_ERROR, "Unable to initialize %s, error %d\n", s_fe_names[i], res); if (hint != NULL) - return res; + goto failed; } } if (i == FET_COUNT) { if (hint == NULL) { USDR_LOG("DEFE", USDR_LOG_NOTE, "No external FE was detected, provide fe=`frontend` for a strong hint\n"); - *out = NULL; - return 0; + res = 0; + goto failed; } USDR_LOG("DEFE", USDR_LOG_WARNING, "No external FE was detected with `%s` hint and %s filter\n", hint, compat); return -ENODEV; } - dev_fe_t* n = (dev_fe_t*)malloc(sizeof(dev_fe_t)); - *n = dfe; - n->type = (fe_type_t)i; + dfe->type = (fe_type_t)i; USDR_LOG("DEFE", USDR_LOG_WARNING, "Detected external FE: %s\n", s_fe_names[i]); res = usdr_vfs_obj_param_init_array_param(base, - (void*)n, + (void*)dfe, s_fe_params, SIZEOF_ARRAY(s_fe_params)); if (res) - return res; + goto failed; vfidx += SIZEOF_ARRAY(s_fe_params); - switch (n->type) { + switch (dfe->type) { case FET_PCIE_DEVBOARD: res = usdr_vfs_obj_param_init_array_param(base, - (void*)n, + (void*)dfe, s_fe_pcie_params, SIZEOF_ARRAY(s_fe_pcie_params)); break; case FET_PCIE_SIMPLE_SYNC: res = usdr_vfs_obj_param_init_array_param(base, - (void*)n, + (void*)dfe, s_simplesync_params, SIZEOF_ARRAY(s_simplesync_params)); break; case FET_PCIE_SUPER_SYNC: res = usdr_vfs_obj_param_init_array_param(base, - (void*)n, + (void*)dfe, s_lmk5c33216_params, SIZEOF_ARRAY(s_lmk5c33216_params)); break; case FET_PCIE_FE1005000: res = usdr_vfs_obj_param_init_array_param(base, - (void*)n, + (void*)dfe, s_ext_fe_100_5000_params, SIZEOF_ARRAY(s_ext_fe_100_5000_params)); break; case FET_PCIE_XMASS: res = usdr_vfs_obj_param_init_array_param(base, - (void*)n, + (void*)dfe, s_xmass_params, SIZEOF_ARRAY(s_xmass_params)); break; @@ -275,7 +277,15 @@ int device_fe_probe(device_t* base, const char* compat, const char* fename, unsi break; } - *out = n; + if (res) + goto failed; + + *out = dfe; + return res; + +failed: + *out = NULL; + free(dfe); return res; } diff --git a/src/lib/device/ext_fe_ch4_400_7200/CMakeLists.txt b/src/lib/device/ext_fe_ch4_400_7200/CMakeLists.txt new file mode 100644 index 00000000..70fab040 --- /dev/null +++ b/src/lib/device/ext_fe_ch4_400_7200/CMakeLists.txt @@ -0,0 +1,20 @@ +set(EXT_FE_CH4_400_7200_LIB_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/ext_fe_ch4_400_7200.c +) + +set(HW_FILES ext_fe_ch4_400_7200_e ext_fe_ch4_400_7200_usr) +foreach(I ${HW_FILES}) + message(STATUS "Generating header for ${I}") + GENERATE_YAML_H(${CMAKE_CURRENT_SOURCE_DIR}/${I}.yaml ${CMAKE_CURRENT_BINARY_DIR}/def_${I}.h) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${I}.yaml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/usdr/schema/) + + list(APPEND USDR_DEPEND_TARGETS generate_${I}) +endforeach() + + +list(APPEND USDR_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) +list(APPEND USDR_LIBRARY_FILES ${EXT_FE_CH4_400_7200_LIB_FILES}) + +set(USDR_LIBRARY_FILES ${USDR_LIBRARY_FILES} PARENT_SCOPE) +set(USDR_DEPEND_TARGETS ${USDR_DEPEND_TARGETS} PARENT_SCOPE) +set(USDR_INCLUDE_DIRS ${USDR_INCLUDE_DIRS} PARENT_SCOPE) diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c new file mode 100644 index 00000000..a315d501 --- /dev/null +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c @@ -0,0 +1,598 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include + +#include +#include +#include + +#include "ext_fe_ch4_400_7200.h" +#include "../ipblks/gpio.h" +#include "../ipblks/spiext.h" +#include "../hw/tmp114/tmp114.h" +#include "../hw/dac80501/dac80501.h" +#include "../hw/tca6424a/tca6424a.h" + +#include "../generic_usdr/generic_regs.h" + +#include +#include + +// M.2 breakout +// ------------------------------------------------------------------------------------- +// M.2 pin sSDR dSDR +// 10 SSDR_GPLED0 GPIO33_0 EXT_I2C_SDA +// 20 SSDR_GPIO1 -------- AUX_MUX_GPIO1 -- *EXT2_I2C_SDA / FAN0_TACH +// 38 SSDR_GPLED1_P FGPIO_N +// 40 SSDR_GPLED1_N FGPIO_P +// 54 SSDR_GPIO6 GPIO33_1 EXT_I2C_SCL +// 56 SSDR_GPIO3_P -------- n/c GPS_TX +// 57 SSDR_GPIO3_N -------- n/c GPS_RX +// 68 SSDR_GPIO5 GPIO33_2 AUX_MUX_GPIO0 -- *EXT2_I2C_SCL / FAN1_TACH +// +// I2C3: +// SSDR_GPLED0 M1 +// SSDR_GPIO6 H2 +// I2C4: +// SSDR_GPIO1 L1 +// SSDR_GPIO5 J2 + + +enum { + // GPIO_I2C3_SDA = GPIO12, + GPIO_I2C3_SCL = GPIO6, + + GPIO_I2C4_SDA = GPIO1, + GPIO_I2C4_SCL = GPIO5, +}; + +enum { + TCA6424A_ADDR_L = 0x22, + TCA6424A_ADDR_H = 0x23, + + SC18IS606_ADDR = 0b0101111, +}; + +enum i2c_idx_extra { + I2C_TCA6424AR_U114 = MAKE_LSOP_I2C_ADDR(1, 0, TCA6424A_ADDR_L), + I2C_TCA6424AR_U110 = MAKE_LSOP_I2C_ADDR(1, 0, TCA6424A_ADDR_H), + I2C_TCA6424AR_U300 = MAKE_LSOP_I2C_ADDR(1, 1, TCA6424A_ADDR_L), //AB + I2C_TCA6424AR_U301 = MAKE_LSOP_I2C_ADDR(1, 1, TCA6424A_ADDR_H), //CD + + I2C_TEMP_U69 = MAKE_LSOP_I2C_ADDR(1, 0, I2C_DEV_TMP114NB), +}; + + +//------------------------ +// Low level expanders control + +static int _ext_fe_ch4_400_7200_exp_upd(ext_fe_ch4_400_7200_t *fe, unsigned addr, unsigned data) +{ + int res = 0; + switch (addr) { + case 0x0: + res = res ? res : tca6424a_reg16_set(fe->dev, fe->subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, data); + res = res ? res : tca6424a_reg8_set(fe->dev, fe->subdev, I2C_TCA6424AR_U114, TCA6424_OUT0 + 2, data >> 16); + break; + case 0x1: + case 0x2: + case 0x3: + res = tca6424a_reg8_set(fe->dev, fe->subdev, I2C_TCA6424AR_U110, TCA6424_OUT0 + (addr - 0x1), data); + break; + case 0x4: + case 0x5: + case 0x6: + // TODO: Fast path + res = tca6424a_reg8_set(fe->dev, fe->subdev, I2C_TCA6424AR_U300, TCA6424_OUT0 + (addr - 0x4), data); + break; + case 0x7: + case 0x8: + case 0x9: + // TODO: Fast path + res = tca6424a_reg8_set(fe->dev, fe->subdev, I2C_TCA6424AR_U301, TCA6424_OUT0 + (addr - 0x7), data); + break; + default: + return -EINVAL; + } + return res; +} + +static int _ext_fe_ch4_400_7200_exp_get(ext_fe_ch4_400_7200_t *fe, unsigned addr) +{ + int res = 0; + uint8_t di8 = 0; + uint16_t di16; + switch (addr) { + case 0x0: + res = res ? res : tca6424a_reg16_get(fe->dev, fe->subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, &di16); + res = res ? res : tca6424a_reg8_get(fe->dev, fe->subdev, I2C_TCA6424AR_U114, TCA6424_OUT0 + 2, &di8); + + fe->debug_fe_reg_last = (unsigned)di16 | (((unsigned)di8) << 16); + + USDR_LOG("FE4C", USDR_LOG_WARNING, "FE_4CH_EXP RD %02x => %08x\n", addr, fe->debug_fe_reg_last); + return res; + case 0x1: + case 0x2: + case 0x3: + res = tca6424a_reg8_get(fe->dev, fe->subdev, I2C_TCA6424AR_U110, TCA6424_OUT0 + (addr - 0x1), &di8); + break; + + case 0x4: + case 0x5: + case 0x6: + res = tca6424a_reg8_get(fe->dev, fe->subdev, I2C_TCA6424AR_U300, TCA6424_OUT0 + (addr - 0x4), &di8); + break; + + case 0x7: + case 0x8: + case 0x9: + res = tca6424a_reg8_get(fe->dev, fe->subdev, I2C_TCA6424AR_U301, TCA6424_OUT0 + (addr - 0x7), &di8); + break; + default: + return -EINVAL; + } + + USDR_LOG("FE4C", USDR_LOG_WARNING, "FE_4CH_EXP RD %02x => %02x\n", addr, di8); + fe->debug_fe_reg_last = di8; + return res; +} + +//--------------------------------- +// high level user friendly control +static void _ext_fe_fbank_map(unsigned filsel, unsigned *bout, unsigned *bin) +{ + // Sanity check YAML <-> internal ABI constants + CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_400_1000M, RX_FB_400_1000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_1000_2000M, RX_FB_1000_2000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_2000_3500M, RX_FB_2000_3500M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_2500_5000M, RX_FB_2500_5000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_3500_7100M, RX_FB_3500_7100M); + + CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_400_1000M, RX_FB_AUTO | RX_FB_400_1000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_1000_2000M, RX_FB_AUTO | RX_FB_1000_2000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_2000_3500M, RX_FB_AUTO | RX_FB_2000_3500M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_2500_5000M, RX_FB_AUTO | RX_FB_2500_5000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_3500_7100M, RX_FB_AUTO | RX_FB_3500_7100M); + + CHECK_CONSTANT_EQ(SW_RX_FILTER_IN_CHA_400_1000M, SW_RX_FILTER_OUT_CHA_400_1000M); + + unsigned fb_f_sel = (~RX_FB_AUTO & filsel); + switch (fb_f_sel) { + case RX_FB_400_1000M: *bout = SW_RX_FILTER_OUT_CHA_400_1000M; *bin = SW_RX_FILTER_IN_CHA_400_1000M; break; + case RX_FB_1000_2000M: *bout = SW_RX_FILTER_OUT_CHA_1000_2000M; *bin = SW_RX_FILTER_IN_CHA_1000_2000M; break; + case RX_FB_2000_3500M: *bout = SW_RX_FILTER_OUT_CHA_2000_3500M; *bin = SW_RX_FILTER_IN_CHA_2000_3500M; break; + case RX_FB_2500_5000M: *bout = SW_RX_FILTER_OUT_CHA_2500_5000M; *bin = SW_RX_FILTER_IN_CHA_2500_5000M; break; + case RX_FB_3500_7100M: *bout = SW_RX_FILTER_OUT_CHA_3500_7100M; *bin = SW_RX_FILTER_IN_CHA_3500_7100M; break; + default: *bout = SW_RX_FILTER_OUT_CHA_MUTE1; *bin = SW_RX_FILTER_IN_CHA_MUTE1; break; + } +} + +// Switch on RX path => ANT_RX external port / rfsw_rxtx / LB +enum rfsw_tddfdd_bits { + EXP_TDDFDD_SD = 0b00, // LB SW is on + EXP_TDDFDD_P2_TRX_SW = 0b01, + EXP_TDDFDD_P1_LB_SW = 0b10, // LB SW is on + EXP_TDDFDD_P3_ANT_RX = 0b11, +}; + +// Switch on ANT_TRX external port => rfsw_tddfdd / rfsw_tx_onoff +enum rfsw_rxtx_bits { + EXP_RXTX_SW_P2_RX = 1, + EXP_RXTX_SW_P1_TX = 0, +}; + +// Switch TX path => rfsw_rxtx / LB +enum rfsw_tx_onoff_bits { + EXP_TX_ONOFF_P2_LB_SW = 1, + EXP_TX_ONOFF_P1_TRX_SW = 0, +}; + +enum led_rtx_vals { + LED_TRX_RXO = 0, + LED_TRX_OFF = 1, + LED_TRX_TRX = 2, + LED_TRX_TXO = 3, +}; + +enum led_rx_cals { + LED_RX_ON = 0, + LED_RX_OFF = 1, +}; + +static void _ext_fe_antenna_sw_map_exp(unsigned antenna, bool rxen, bool txen, + uint8_t* exp_tddfdd, uint8_t* exp_rxtx, uint8_t* exp_tx_onoff, + uint8_t* exp_led_trx, uint8_t* exp_led_rx, + unsigned *arx, unsigned *atx) +{ + CHECK_CONSTANT_EQ(ANT_OPTS_RX_TO_RX_AND_TX_TO_TRX, ANT_RX_TRX); + CHECK_CONSTANT_EQ(ANT_OPTS_RX_TO_TRX_AND_TX_TERM, ANT_TRX_TERM); + CHECK_CONSTANT_EQ(ANT_OPTS_RX_TO_RX_AND_TX_TERM, ANT_RX_TERM); + CHECK_CONSTANT_EQ(ANT_OPTS_RX_TX_LOOPBACK, ANT_LOOPBACK); + CHECK_CONSTANT_EQ(ANT_OPTS_TDD_DRIVEN_AUTO, ANT_HW_TDD); + + switch (antenna) { + case ANT_RX_TRX: + *exp_tx_onoff = EXP_TX_ONOFF_P1_TRX_SW; + *exp_rxtx = EXP_RXTX_SW_P1_TX; + *exp_tddfdd = EXP_TDDFDD_P3_ANT_RX; + *exp_led_trx = LED_TRX_TXO; + *exp_led_rx = LED_RX_ON; + *arx = rxen; + *atx = txen; + break; + + case ANT_TRX_TERM: + *exp_tx_onoff = EXP_TX_ONOFF_P2_LB_SW; + *exp_rxtx = EXP_RXTX_SW_P2_RX; + *exp_tddfdd = EXP_TDDFDD_P2_TRX_SW; + *exp_led_trx = LED_TRX_RXO; + *exp_led_rx = LED_RX_OFF; + *arx = rxen; + *atx = 0; + break; + + case ANT_RX_TERM: + *exp_tx_onoff = EXP_TX_ONOFF_P2_LB_SW; + *exp_rxtx = EXP_RXTX_SW_P1_TX; + *exp_tddfdd = EXP_TDDFDD_P3_ANT_RX; + *exp_led_trx = LED_TRX_OFF; + *exp_led_rx = LED_RX_ON; + *arx = rxen; + *atx = 0; + break; + + case ANT_LOOPBACK: + *exp_tx_onoff = EXP_TX_ONOFF_P2_LB_SW; + *exp_rxtx = EXP_RXTX_SW_P1_TX; + *exp_tddfdd = EXP_TDDFDD_P1_LB_SW; + *exp_led_trx = LED_TRX_OFF; + *exp_led_rx = LED_RX_OFF; + *arx = rxen; + *atx = txen; + break; + + case ANT_HW_TDD: + // TODO + *exp_led_trx = LED_TRX_TRX; + *exp_led_rx = LED_RX_OFF; + *arx = rxen; + *atx = txen; + break; + + default: + *exp_tx_onoff = EXP_TX_ONOFF_P2_LB_SW; + *exp_rxtx = EXP_RXTX_SW_P1_TX; + *exp_tddfdd = EXP_TDDFDD_P1_LB_SW; + + *exp_led_trx = LED_TRX_OFF; + *exp_led_rx = LED_RX_OFF; + *arx = 0; + *atx = 0; + break; + } +} + + + +// This function just update states of internal HW and I2C expander registers, +// all calculation of band, filter, lofreq, etc. has been done before this call +int ext_fe_update_user(ext_fe_ch4_400_7200_t* fe) +{ + unsigned fbanksel_out[FE_MAX_HW_CHANS]; + unsigned fbanksel_in[FE_MAX_HW_CHANS]; + + uint8_t exp_tx_onoff[FE_MAX_HW_CHANS]; + uint8_t exp_rxtx[FE_MAX_HW_CHANS]; + uint8_t exp_tddfdd[FE_MAX_HW_CHANS]; + + unsigned act_rx[FE_MAX_HW_CHANS]; + unsigned act_tx[FE_MAX_HW_CHANS]; + + uint8_t rx_led[FE_MAX_HW_CHANS]; + uint8_t trx_led[FE_MAX_HW_CHANS]; + + uint8_t enanble_rx = 0; + uint8_t enanble_tx = 0; + + int res = 0; + + for (unsigned i = 0; i < FE_MAX_HW_CHANS; i++) { + unsigned rxen = fe->ucfg[i].rx_en; + unsigned txen = fe->ucfg[i].tx_en; + + // RX filterbank + _ext_fe_fbank_map(fe->ucfg[i].rx_fb_sel, &fbanksel_out[i], &fbanksel_in[i]); // SW_RX_FILTER_OUT_CHA_MUTE1 if not enabled? + + // Antanna switch, RF PA/LNA switch, loopback switch + _ext_fe_antenna_sw_map_exp(fe->ucfg[i].ant_sel, rxen, txen, &exp_tddfdd[i], &exp_rxtx[i], &exp_tx_onoff[i], + &trx_led[i], &rx_led[i], &act_rx[i], &act_tx[i]); + + enanble_rx |= rxen; + enanble_tx |= txen; + }; + + // RX filter Bank + fe->fe_exp_regs[0] = MAKE_EXT_FE_CH4_400_7200_E_SW_RX_FILTER( + fbanksel_in[H_CHD], fbanksel_in[H_CHC], fbanksel_in[H_CHB], fbanksel_in[H_CHA], + fbanksel_out[H_CHA], fbanksel_out[H_CHB], fbanksel_out[H_CHC], fbanksel_out[H_CHD]); + + // Gobal enable + fe->fe_exp_regs[1] = MAKE_EXT_FE_CH4_400_7200_E_ENABLE( + fe->ucfg[H_CHD].tx_ss, fe->ucfg[H_CHC].tx_ss, fe->ucfg[H_CHB].tx_ss, fe->ucfg[H_CHA].tx_ss, + fe->if_vbyp, fe->ref_gps, enanble_tx, enanble_rx); + + // TRX leds + fe->fe_exp_regs[2] = MAKE_EXT_FE_CH4_400_7200_E_LED_TRX_CTRL(trx_led[H_CHD], trx_led[H_CHC], trx_led[H_CHB], trx_led[H_CHA]); + fe->fe_exp_regs[3] = MAKE_EXT_FE_CH4_400_7200_E_LEDRX_CH_CTRL( + rx_led[H_CHD], rx_led[H_CHC], rx_led[H_CHB], rx_led[H_CHA], + fe->ucfg[H_CHD].rx_en, fe->ucfg[H_CHC].rx_en, fe->ucfg[H_CHB].rx_en, fe->ucfg[H_CHA].rx_en); + + + // Expander & HIGH-speed IO + // AB / CD control pairs + for (unsigned pair = 0; pair < 2; pair++) { + unsigned idx = P_A_EN_AB - SW_RX_FILTER + (P_A_EN_CD - P_A_EN_AB) * pair; + + fe->fe_exp_regs[idx + 0] = MAKE_EXT_FE_CH4_400_7200_E_REG_WR(idx + SW_RX_FILTER, MAKE_EXT_FE_CH4_400_7200_E_P_A_EN_AB( + act_tx[2 * pair + 0], act_tx[2 * pair + 1])); + fe->fe_exp_regs[idx + 1] = MAKE_EXT_FE_CH4_400_7200_E_REG_WR(idx + SW_RX_FILTER, MAKE_EXT_FE_CH4_400_7200_E_ATTN_RX_CH_AB( + fe->ucfg[2 * pair + 0].rx_dsa, fe->ucfg[2 * pair + 1].rx_dsa)); + + fe->fe_exp_regs[idx + 2] = MAKE_EXT_FE_CH4_400_7200_E_REG_WR(idx + SW_RX_FILTER, MAKE_EXT_FE_CH4_400_7200_E_SW_AB( + exp_rxtx[2 * pair + 1], exp_tx_onoff[2 * pair + 1], + exp_rxtx[2 * pair + 0], exp_tx_onoff[2 * pair + 0], + exp_tddfdd[2 * pair + 0], exp_tddfdd[2 * pair + 1])); + } + + // TODO add control for high speed IO + for (unsigned addr = 0; addr < FE_CTRL_REGS; addr++) { + res = res ? res : _ext_fe_ch4_400_7200_exp_upd(fe, addr, fe->fe_exp_regs[addr]); + } + return res; +} + + +int ext_fe_ch4_sens_get(ext_fe_ch4_400_7200_t* fe, uint64_t *ovalue) +{ + int temp256 = 127*256, res; + res = tmp114_temp_get(fe->dev, fe->subdev, I2C_TEMP_U69, &temp256); + *ovalue = (int64_t)temp256; + return res; +} + + + + +static int ext_fe_ch4_400_7200_ctrl_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + ext_fe_ch4_400_7200_t* fe = (ext_fe_ch4_400_7200_t*)obj->object; + int res; + unsigned addr = (value >> 24) & 0x7f; + unsigned data = value & 0xffffff; + + fe->debug_fe_reg_last = ~0u; + + if (value & 0x80000000) { + USDR_LOG("FE4C", USDR_LOG_WARNING, "FE_CH4_CTRL %08x => %08x\n", addr, data); + + if (addr < SW_RX_FILTER || addr >= SW_RX_FILTER + FE_CTRL_REGS) { + return -EINVAL; + } + res = _ext_fe_ch4_400_7200_exp_upd(fe, addr - SW_RX_FILTER, data); + } else { + res = _ext_fe_ch4_400_7200_exp_get(fe, addr - SW_RX_FILTER); + } + + return res; +} + +static int ext_fe_ch4_400_7200_ctrl_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + ext_fe_ch4_400_7200_t* fe = (ext_fe_ch4_400_7200_t*)obj->object; + *ovalue = fe->debug_fe_reg_last; + return 0; +} + +int ext_fe_ch4_400_7200_temp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + return ext_fe_ch4_sens_get((ext_fe_ch4_400_7200_t*)obj->object, ovalue); +} + + +static int ext_fe_ch4_400_7200_usr_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + ext_fe_ch4_400_7200_t* fe = (ext_fe_ch4_400_7200_t*)obj->object; + int res = 0; + unsigned addr = (value >> 24) & 0x7f; + unsigned data = value & 0xffffff; + + fe->debug_fe_usr_last = ~0u; + + if (value & 0x80000000) { + USDR_LOG("FE4C", USDR_LOG_WARNING, "EXFE_4CH_USER %08x => %08x\n", addr, data); + + switch (addr) { + case RX_FILTER_BANK: + fe->ucfg[H_CHA].rx_fb_sel = GET_EXT_FE_CH4_400_7200_USR_RX_FILTER_BANK_A(data); + fe->ucfg[H_CHB].rx_fb_sel = GET_EXT_FE_CH4_400_7200_USR_RX_FILTER_BANK_B(data); + fe->ucfg[H_CHC].rx_fb_sel = GET_EXT_FE_CH4_400_7200_USR_RX_FILTER_BANK_C(data); + fe->ucfg[H_CHD].rx_fb_sel = GET_EXT_FE_CH4_400_7200_USR_RX_FILTER_BANK_D(data); + break; + case RX_ATTN: + fe->ucfg[H_CHA].rx_dsa = GET_EXT_FE_CH4_400_7200_USR_RX_ATTN_A(data); + fe->ucfg[H_CHB].rx_dsa = GET_EXT_FE_CH4_400_7200_USR_RX_ATTN_B(data); + fe->ucfg[H_CHC].rx_dsa = GET_EXT_FE_CH4_400_7200_USR_RX_ATTN_C(data); + fe->ucfg[H_CHD].rx_dsa = GET_EXT_FE_CH4_400_7200_USR_RX_ATTN_D(data); + break; + case ANT_SEL: + fe->ucfg[H_CHA].ant_sel = GET_EXT_FE_CH4_400_7200_USR_ANT_SEL_A(data); + fe->ucfg[H_CHB].ant_sel = GET_EXT_FE_CH4_400_7200_USR_ANT_SEL_B(data); + fe->ucfg[H_CHC].ant_sel = GET_EXT_FE_CH4_400_7200_USR_ANT_SEL_C(data); + fe->ucfg[H_CHD].ant_sel = GET_EXT_FE_CH4_400_7200_USR_ANT_SEL_D(data); + break; + case RX_CHEN: + fe->ucfg[H_CHA].rx_en = GET_EXT_FE_CH4_400_7200_USR_RX_CHEN_A(data); + fe->ucfg[H_CHB].rx_en = GET_EXT_FE_CH4_400_7200_USR_RX_CHEN_B(data); + fe->ucfg[H_CHC].rx_en = GET_EXT_FE_CH4_400_7200_USR_RX_CHEN_C(data); + fe->ucfg[H_CHD].rx_en = GET_EXT_FE_CH4_400_7200_USR_RX_CHEN_D(data); + break; + case TX_CHEN: + fe->ucfg[H_CHA].tx_en = GET_EXT_FE_CH4_400_7200_USR_TX_CHEN_A(data); + fe->ucfg[H_CHB].tx_en = GET_EXT_FE_CH4_400_7200_USR_TX_CHEN_B(data); + fe->ucfg[H_CHC].tx_en = GET_EXT_FE_CH4_400_7200_USR_TX_CHEN_C(data); + fe->ucfg[H_CHD].tx_en = GET_EXT_FE_CH4_400_7200_USR_TX_CHEN_D(data); + break; + case TX_2STAGE: + fe->ucfg[H_CHA].tx_ss = GET_EXT_FE_CH4_400_7200_USR_TX_2STAGE_A(data); + fe->ucfg[H_CHB].tx_ss = GET_EXT_FE_CH4_400_7200_USR_TX_2STAGE_B(data); + fe->ucfg[H_CHC].tx_ss = GET_EXT_FE_CH4_400_7200_USR_TX_2STAGE_C(data); + fe->ucfg[H_CHD].tx_ss = GET_EXT_FE_CH4_400_7200_USR_TX_2STAGE_D(data); + break; + default: + return -EINVAL; + } + + // Update state + res = ext_fe_update_user(fe); + } else { + switch (addr) { + case RX_FILTER_BANK: + fe->debug_fe_usr_last = MAKE_EXT_FE_CH4_400_7200_USR_RX_FILTER_BANK( + fe->ucfg[H_CHD].rx_fb_sel, fe->ucfg[H_CHC].rx_fb_sel, fe->ucfg[H_CHB].rx_fb_sel, fe->ucfg[H_CHA].rx_fb_sel); + break; + case RX_ATTN: + fe->debug_fe_usr_last = MAKE_EXT_FE_CH4_400_7200_USR_RX_ATTN( + fe->ucfg[H_CHD].rx_dsa, fe->ucfg[H_CHC].rx_dsa, fe->ucfg[H_CHB].rx_dsa, fe->ucfg[H_CHA].rx_dsa); + break; + case ANT_SEL: + fe->debug_fe_usr_last = MAKE_EXT_FE_CH4_400_7200_USR_ANT_SEL( + fe->ucfg[H_CHD].ant_sel, fe->ucfg[H_CHC].ant_sel, fe->ucfg[H_CHB].ant_sel, fe->ucfg[H_CHA].ant_sel); + break; + case RX_CHEN: + fe->debug_fe_usr_last = MAKE_EXT_FE_CH4_400_7200_USR_RX_CHEN( + fe->ucfg[H_CHD].rx_en, fe->ucfg[H_CHC].rx_en, fe->ucfg[H_CHB].rx_en, fe->ucfg[H_CHA].rx_en); + break; + case TX_CHEN: + fe->debug_fe_usr_last = MAKE_EXT_FE_CH4_400_7200_USR_TX_CHEN( + fe->ucfg[H_CHD].tx_en, fe->ucfg[H_CHC].tx_en, fe->ucfg[H_CHB].tx_en, fe->ucfg[H_CHA].tx_en); + break; + case TX_2STAGE: + fe->debug_fe_usr_last = MAKE_EXT_FE_CH4_400_7200_USR_TX_2STAGE( + fe->ucfg[H_CHD].tx_ss, fe->ucfg[H_CHC].tx_ss, fe->ucfg[H_CHB].tx_ss, fe->ucfg[H_CHA].tx_ss); + break; + default: + return -EINVAL; + }; + } + + return res; +} + +static int ext_fe_ch4_400_7200_usr_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + ext_fe_ch4_400_7200_t* fe = (ext_fe_ch4_400_7200_t*)obj->object; + *ovalue = fe->debug_fe_usr_last; + + return 0; +} + + +static const usdr_dev_param_func_t s_fe_parameters[] = { + { "/dm/sensor/temp_fe0", { NULL, ext_fe_ch4_400_7200_temp_get }}, + { "/debug/hw/exfe10_4ch_exp/0/reg" , { ext_fe_ch4_400_7200_ctrl_reg_set, ext_fe_ch4_400_7200_ctrl_reg_get } }, + { "/debug/hw/exfe10_4ch_usr/0/reg" , { ext_fe_ch4_400_7200_usr_reg_set, ext_fe_ch4_400_7200_usr_reg_get } }, +}; + + + +int ext_fe_ch4_400_7200_init(lldev_t dev, + unsigned subdev, + unsigned gpio_base, + const char *params, + const char *compat, + ext_fe_ch4_400_7200_t* ob) +{ + int res = 0; + int val = 0; + uint16_t val16[4] = { 0xbad, 0xbad, 0xbad, 0xbad }; + device_t* base = lowlevel_get_device(dev); + ob->dev = dev; + ob->subdev = subdev; + + USDR_LOG("FE4C", USDR_LOG_INFO, "Initializing FE_4CH_400_7200 front end...\n"); + + // if (strcmp(compat, "m2m") != 0) { + // return -ENODEV; + // } + // TODO sSDR/dSDR specific + + // Configure external I2C bus + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO_I2C3_SCL, GPIO_CFG_ALT1); + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO_I2C4_SDA, GPIO_CFG_ALT1); + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO_I2C4_SCL, GPIO_CFG_ALT1); + if (res) + return res; + + res = (res) ? res : tmp114_devid_get(dev, subdev, I2C_TEMP_U69, &val); + + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U114, TCA6424_CFG0, &val16[0]); + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U110, TCA6424_CFG0, &val16[1]); + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U300, TCA6424_CFG0, &val16[2]); + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U301, TCA6424_CFG0, &val16[3]); + + USDR_LOG("FE4C", USDR_LOG_ERROR, "Temp ID = %4x, {U114/U110/U300/U301}_Cfg0 = %4x/%4x/%4x/%4x\n", val, + val16[0], val16[1], val16[2], val16[3]); + + if (res || val != TMP114_DEVICE_ID) + return res; + + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, 0); + res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0 + 2, 0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0, 0); + res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0 + 2, 0); + + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_CFG0, 0); + res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_CFG0 + 2, 0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_CFG0, 0); + res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_CFG0 + 2, 0); + + res = (res) ? res : tmp114_temp_get(dev, subdev, I2C_TEMP_U69, &val); + USDR_LOG("FE4C", USDR_LOG_ERROR, "Temp %.2fC\n", val / 256.0); + + // User initialization + ob->ref_gps = 0; + ob->if_vbyp = 1; + for (unsigned ch = 0; ch < FE_MAX_HW_CHANS; ch++) { + ob->ucfg[ch].rx_fb_sel = RX_FB_AUTO; // rx_filterbank + ob->ucfg[ch].rx_dsa = 0; + ob->ucfg[ch].ant_sel = ANT_OFF; + ob->ucfg[ch].tx_ss = 0; // Single stage PA + ob->ucfg[ch].tx_en = 0; // Channel enabled on device side + ob->ucfg[ch].rx_en = 0; // Channel enabled on device side + ob->ucfg[ch].rx_freq = 0; + } + + res = (res) ? res : ext_fe_update_user(ob); + + // TODO: HighSpeed IO + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U300, TCA6424_CFG0, 0); + res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U300, TCA6424_CFG0 + 2, 0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U301, TCA6424_CFG0, 0); + res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U301, TCA6424_CFG0 + 2, 0); + + res = (res) ? res : usdr_vfs_obj_param_init_array_param(base, + (void*)ob, + s_fe_parameters, + SIZEOF_ARRAY(s_fe_parameters)); + if (res) + return res; + + ob->dev = dev; + ob->subdev = subdev; + ob->gpio_base = gpio_base; + ob->hsgpio_base = 0; + return 0; +} diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h new file mode 100644 index 00000000..9cce207e --- /dev/null +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h @@ -0,0 +1,84 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef EXT_FE_CH4_400_7200_H +#define EXT_FE_CH4_400_7200_H + +#include +#include +#include +#include "../device.h" +#include "../device_vfs.h" + + +#define H_CHA 0 +#define H_CHB 1 +#define H_CHC 2 +#define H_CHD 3 + +#define FE_MAX_HW_CHANS 4 + +#define FE_CTRL_REGS 10 + +enum rx_filterbank { + RX_FB_400_1000M, + RX_FB_1000_2000M, + RX_FB_2000_3500M, + RX_FB_2500_5000M, + RX_FB_3500_7100M, + + RX_FB_AUTO = 8, +}; + +enum antenna_cfg { + ANT_RX_TRX, // RX connected to RX antenna and TX connected to TRX antenna + ANT_TRX_TERM, // RX connected to TRX antenna and TX terminated + ANT_RX_TERM, // RX connected to RX antenna and TX terminated + ANT_LOOPBACK, // RX connected to TX port through attenuator + + ANT_HW_TDD, // TRX antenna is dynamically switched to TX/RX ports based on burst information + ANT_OFF, +}; + +struct fe_chan_config { + uint8_t rx_fb_sel; // rx_filterbank + uint8_t rx_dsa; + uint8_t ant_sel; // antenna selector + uint8_t tx_ss; // Single stage PA + + uint8_t tx_en; // Channel enabled on device side + uint8_t rx_en; // Channel enabled on device side + + // For auto band & filter selection + uint64_t rx_freq; +}; +typedef struct fe_chan_config fe_chan_config_t; + +struct ext_fe_ch4_400_7200 { + lldev_t dev; + unsigned subdev; + + unsigned gpio_base; + unsigned hsgpio_base; // HighSpeed gpio over LVDS + + + uint32_t fe_exp_regs[FE_CTRL_REGS]; + uint32_t debug_fe_reg_last; + uint32_t debug_fe_usr_last; + + // High level control + uint8_t ref_gps; // Globally enable GPS + uint8_t if_vbyp; // Globally enable IF BYP + fe_chan_config_t ucfg[FE_MAX_HW_CHANS]; +}; + +typedef struct ext_fe_ch4_400_7200 ext_fe_ch4_400_7200_t; + +int ext_fe_ch4_400_7200_init(lldev_t dev, + unsigned subdev, + unsigned gpio_base, + const char *params, + const char *compat, + ext_fe_ch4_400_7200_t* ob); + +#endif diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml new file mode 100644 index 00000000..2e1ccfed --- /dev/null +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml @@ -0,0 +1,249 @@ +# Copyright (c) 2023-2024 Wavelet Lab +# SPDX-License-Identifier: MIT + +# Register desc and visual map +name: M2_FE_4CH_BOARD +desc: sSDR/dSDR M.2 external FE board +revision: "0.0.1" +processors: [ c ] +bus: + type: VIRTUAL + usdr_path: /debug/hw/exfe10_4ch_exp/0/reg + wr_mask: 0x80000000 +addr_width: 8 +data_width: 24 +# page_prefix: True +field_prefix: [ RegName ] +field_macros: True + +x-rx-filt-in-opts: &rx-filt-in-opts + 0b000: MUTE0 + 0b011: 400_1000M + 0b010: 1000_2000M + 0b001: 2000_3500M + 0b101: 2500_5000M + 0b100: 3500_7100M + 0b110: MUTE1 + 0b111: MUTE2 + + +x-rx-filt-out-opts: &rx-filt-out-opts + 0b000: MUTE0 + 0b011: 400_1000M + 0b100: 1000_2000M + 0b101: 2000_3500M + 0b001: 2500_5000M + 0b010: 3500_7100M + 0b110: MUTE1 + 0b111: MUTE2 + + + +pages: + - name: V0 + regs: +# + - addr: 0x30 + name: SW_RX_FILTER + fields: +# +# RX filters switching +# ---IN--- ---OUT-- +# V3 V2 V1 V3 V2 V1 +# --+--+-- --+--+-- +# 0 1 1 0 1 1 = 0.4 - 1.0 GHz +# 0 1 0 1 0 0 = 1.0 - 2.0 GHz +# 0 0 1 1 0 1 = 2.0 - 3.5 GHz +# 1 0 1 0 0 1 = 2.5 - 5.0 GHz +# 1 0 0 0 1 0 = 3.5 - 7.0 GHz +# + - bits: "8,23,22" + name: IN_CHA + desc: RX IN filters switch for Channel A + opts: *rx-filt-in-opts +# + - bits: "15,6,7" + name: OUT_CHA + desc: RX OUT filters switch for Channel A + opts: *rx-filt-out-opts +# + - bits: "9,21,20" + name: IN_CHB + desc: RX IN filters switch for Channel B + opts: *rx-filt-in-opts +# + - bits: "14,4,5" + name: OUT_CHB + desc: RX OUT filters switch for Channel B + opts: *rx-filt-out-opts +# + - bits: "10,19,18" + name: IN_CHC + desc: RX IN filters switch for Channel C + opts: *rx-filt-in-opts +# + - bits: "13,3,2" + name: OUT_CHC + desc: RX OUT filters switch for Channel C + opts: *rx-filt-out-opts +# + - bits: "11,17,16" + name: IN_CHD + desc: RX IN filters switch for Channel D + opts: *rx-filt-in-opts +# + - bits: "12,0,1" + name: OUT_CHD + desc: RX OUT filters switch for Channel D + opts: *rx-filt-out-opts +# + - addr: 0x31 + name: ENABLE + fields: + - bits: "3" + name: IF_VBYP + desc: IF Bypass + - bits: "2" + name: REF_GPS + desc: Enable GPS module + - bits: "1" + name: P8V_TX + desc: Enable +8v power supply for TX amps + - bits: "0" + name: P6V_RX + desc: Enable +6v power supply for RX amps + - bits: "7" + name: PA_BYPASS_CHD + desc: Stage-2 PA bypass, channel D + - bits: "6" + name: PA_BYPASS_CHC + desc: Stage-2 PA bypass, channel C + - bits: "5" + name: PA_BYPASS_CHB + desc: Stage-2 PA bypass, channel B + - bits: "4" + name: PA_BYPASS_CHA + desc: Stage-2 PA bypass, channel A +# + - addr: 0x32 + name: LED_TRX_CTRL + fields: + - bits: "1:0" + name: LED_CHA + desc: LED CHA + - bits: "3:2" + name: LED_CHB + desc: LED CHB + - bits: "5:4" + name: LED_CHC + desc: LED CHC + - bits: "7:6" + name: LED_CHD + desc: LED CHD +# + - addr: 0x33 + name: LEDRX_CH_CTRL + fields: + - bits: "0" + name: EN_CHA + desc: Enable CHA + - bits: "1" + name: EN_CHB + desc: Enable CHB + - bits: "2" + name: EN_CHC + desc: Enable CHC + - bits: "3" + name: EN_CHD + desc: Enable CHD + - bits: "4" + name: LED_CHA + desc: LED CHA + - bits: "5" + name: LED_CHB + desc: LED CHB + - bits: "6" + name: LED_CHC + desc: LED CHC + - bits: "7" + name: LED_CHD + desc: LED CHD +# + - addr: 0x34 + name: P_A_EN_AB + fields: + - bits: "6" + name: B + desc: Enable CHB + - bits: "7" + name: A + desc: Enable CHA + - addr: 0x35 + name: ATTN_RX_CH_AB + fields: + - bits: "3:0" + name: B + desc: Attenuator CHB + - bits: "7:4" + name: A + desc: Attenuator CHA + - addr: 0x36 + name: SW_AB + fields: + - bits: "4,1" + name: TDDFDD_A + - bits: "7,0" + name: TDDFDD_B + - bits: "2" + name: PA_ON_A + - bits: "5" + name: PA_ON_B + - bits: "3" + name: RXTX_A + - bits: "6" + name: RXTX_B +# + - addr: 0x37 + name: P_A_EN_CD + fields: + - bits: "6" + name: D + desc: Enable CHD + - bits: "7" + name: C + desc: Enable CHC + - addr: 0x38 + name: ATTN_RX_CH_CD + fields: + - bits: "3:0" + name: D + desc: Attenuator CHD + - bits: "7:4" + name: C + desc: Attenuator CHC + - addr: 0x39 + name: SW_CD + fields: + - bits: "4,1" + name: TDDFDD_C + - bits: "7,0" + name: TDDFDD_D + - bits: "2" + name: PA_ON_C + - bits: "5" + name: PA_ON_D + - bits: "3" + name: RXTX_C + - bits: "6" + name: RXTX_D + + + + + + + + + + + diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml new file mode 100644 index 00000000..ea0ada57 --- /dev/null +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml @@ -0,0 +1,144 @@ +# Copyright (c) 2023-2025 Wavelet Lab +# SPDX-License-Identifier: MIT + +# Register desc and visual map +name: M2_FE_4CH_BOARD_USER +desc: sSDR/dSDR M.2 external FE board user friendly control +revision: "0.0.1" +processors: [ c ] +bus: + type: VIRTUAL + usdr_path: /debug/hw/exfe10_4ch_usr/0/reg + wr_mask: 0x80000000 +addr_width: 8 +data_width: 24 +# page_prefix: True +field_prefix: [ RegName ] +field_macros: True + +x-rx-filt-opts: &rx-filt-opts + 0b0000: FILT_400_1000M + 0b0001: FILT_1000_2000M + 0b0010: FILT_2000_3500M + 0b0011: FILT_2500_5000M + 0b0100: FILT_3500_7100M + 0b1000: AUTO_400_1000M + 0b1001: AUTO_1000_2000M + 0b1010: AUTO_2000_3500M + 0b1011: AUTO_2500_5000M + 0b1100: AUTO_3500_7100M + +x-ant-opts: &x-ant-opts + 0b000: RX_TO_RX_AND_TX_TO_TRX + 0b001: RX_TO_TRX_AND_TX_TERM + 0b010: RX_TO_RX_AND_TX_TERM + 0b011: RX_TX_LOOPBACK + 0b100: TDD_DRIVEN_AUTO + +pages: + - name: FEUSR + regs: +# + - addr: 0x50 + name: RX_FILTER_BANK + fields: + - bits: "3:0" + name: A + desc: Filter bank selector + opts: *rx-filt-opts + - bits: "7:4" + name: B + desc: Filter bank selector + opts: *rx-filt-opts + - bits: "11:8" + name: C + desc: Filter bank selector + opts: *rx-filt-opts + - bits: "15:12" + name: D + desc: Filter bank selector + opts: *rx-filt-opts +# + - addr: 0x51 + name: RX_ATTN + fields: + - bits: "3:0" + name: A + desc: RX attenuator settings in dB + - bits: "7:4" + name: B + desc: RX attenuator settings in dB + - bits: "11:8" + name: C + desc: RX attenuator settings in dB + - bits: "15:12" + name: D + desc: RX attenuator settings in dB +# + - addr: 0x52 + name: ANT_SEL + fields: + - bits: "2:0" + name: A + desc: Antenna path selector + opts: *x-ant-opts + - bits: "6:4" + name: B + desc: Antenna path selector + opts: *x-ant-opts + - bits: "10:8" + name: C + desc: Antenna path selector + opts: *x-ant-opts + - bits: "14:12" + name: D + desc: Antenna path selector + opts: *x-ant-opts +# + - addr: 0x53 + name: RX_CHEN + fields: + - bits: "0" + name: A + desc: FE Chan enabled + - bits: "1" + name: B + desc: FE Chan enabled + - bits: "2" + name: C + desc: FE Chan enabled + - bits: "3" + name: D + desc: FE Chan enabled +# + - addr: 0x54 + name: TX_CHEN + fields: + - bits: "0" + name: A + desc: FE Chan enabled + - bits: "1" + name: B + desc: FE Chan enabled + - bits: "2" + name: C + desc: FE Chan enabled + - bits: "3" + name: D + desc: FE Chan enabled +# + - addr: 0x55 + name: TX_2STAGE + fields: + - bits: "0" + name: A + desc: FE Chan 2nd stage enabled + - bits: "1" + name: B + desc: FE Chan 2nd stage enabled + - bits: "2" + name: C + desc: FE Chan 2nd stage enabled + - bits: "3" + name: D + desc: FE Chan 2nd stage enabled diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index b0b144cd..977f6d84 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1576,7 +1576,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x002F0000, &chipver); USDR_LOG("XDEV", USDR_LOG_INFO, "LMS7002 version %08x\n", chipver); -#if 0 +#if 1 res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x81); usleep(100000); diff --git a/src/lib/hw/tmp114/tmp114.h b/src/lib/hw/tmp114/tmp114.h index f3f19351..40d2433a 100644 --- a/src/lib/hw/tmp114/tmp114.h +++ b/src/lib/hw/tmp114/tmp114.h @@ -6,11 +6,12 @@ #include +#define TMP114_DEVICE_ID 0x1114 + int tmp114_temp_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, int* outtemp); int tmp114_devid_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, int* devid); - #endif diff --git a/src/lib/ipblks/gpio.h b/src/lib/ipblks/gpio.h index e11c8b73..92e60f72 100644 --- a/src/lib/ipblks/gpio.h +++ b/src/lib/ipblks/gpio.h @@ -12,6 +12,7 @@ enum gpio_config_vals { GPIO_CFG_IN = 0, GPIO_CFG_OUT = 1, GPIO_CFG_ALT0 = 2, + GPIO_CFG_ALT1 = 3, }; // Core supports gpio0 through gpio14 From 7fafc2cb022c4243fc46f37ebe62c86df3cf02ee Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 3 Oct 2025 18:01:18 +0400 Subject: [PATCH 184/397] add fe control --- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c | 101 +++++++++++++++++- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h | 8 ++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c index a315d501..4f7d91e2 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c @@ -65,6 +65,17 @@ enum i2c_idx_extra { I2C_TEMP_U69 = MAKE_LSOP_I2C_ADDR(1, 0, I2C_DEV_TMP114NB), }; +enum { + RX_DSA_MAX_ATTN = 15, +}; + +static const uint64_t s_filerbank_ranges[] = { + 400e6, 1000e6, + 1000e6, 2000e6, + 2000e6, 3500e6, + 2500e6, 5000e6, + 3500e6, 7100e6, +}; //------------------------ // Low level expanders control @@ -275,7 +286,36 @@ static void _ext_fe_antenna_sw_map_exp(unsigned antenna, bool rxen, bool txen, } } +void ext_fe_rx_filterbank_upd(ext_fe_ch4_400_7200_t* def, unsigned chno) +{ + if (def->ucfg[chno].rx_fb_sel < RX_FILT_OPTS_AUTO_400_1000M) + return; + + unsigned best_idx = 0; + unsigned best_off = 1000; + for (unsigned i = 0; i < SIZEOF_ARRAY(s_filerbank_ranges); i+= 2) { + if (s_filerbank_ranges[i] > def->ucfg[chno].rx_freq || def->ucfg[chno].rx_freq > s_filerbank_ranges[i + 1]) { + continue; + } + + int64_t doff = (int64_t)(s_filerbank_ranges[i] + s_filerbank_ranges[i + 1]) / 2 - def->ucfg[chno].rx_freq ; + if (doff < 0) + doff = 0 - doff; + + unsigned off = 1000 * doff / (s_filerbank_ranges[i + 1] - s_filerbank_ranges[i]); + if (off < best_off) { + best_off = off; + best_idx = i / 2; + } + + USDR_LOG("FE4C", USDR_LOG_WARNING, "F%d %.3f -- %.3f DOFF=%u OFF=%u\n", + i, s_filerbank_ranges[i] / 1.0e6, s_filerbank_ranges[i + 1] / 1.0e6, (unsigned)doff, off); + } + + def->ucfg[chno].rx_fb_sel = RX_FILT_OPTS_AUTO_400_1000M | best_idx; + USDR_LOG("FE4C", USDR_LOG_WARNING, "RXFBabk[%d] = %d\n", chno, def->ucfg[chno].rx_fb_sel); +} // This function just update states of internal HW and I2C expander registers, // all calculation of band, filter, lofreq, etc. has been done before this call @@ -355,6 +395,55 @@ int ext_fe_update_user(ext_fe_ch4_400_7200_t* fe) } +int ext_fe_rx_freq_set(ext_fe_ch4_400_7200_t* def, unsigned chno, uint64_t freq) +{ + if (chno >= FE_MAX_HW_CHANS) + return -EINVAL; + if (!def->ucfg[chno].rx_en) + return 0; + + def->ucfg[chno].rx_freq = freq; + + ext_fe_rx_filterbank_upd(def, chno); + return ext_fe_update_user(def); +} + +int ext_fe_rx_chan_en(ext_fe_ch4_400_7200_t* def, unsigned ch_fe_mask_rx) +{ + for (unsigned i = 0; i < FE_MAX_HW_CHANS; i++) { + def->ucfg[i].rx_en = (ch_fe_mask_rx & (1u << i)) ? 1 : 0; + } + return ext_fe_update_user(def); +} + +int ext_fe_tx_chan_en(ext_fe_ch4_400_7200_t* def, unsigned ch_fe_mask_tx) +{ + for (unsigned i = 0; i < FE_MAX_HW_CHANS; i++) { + def->ucfg[i].tx_en = (ch_fe_mask_tx & (1u << i)) ? 1 : 0; + } + return ext_fe_update_user(def); +} + +int ext_fe_rx_gain_set(ext_fe_ch4_400_7200_t* def, unsigned chno, unsigned gain, unsigned* actual_gain) +{ + if (chno >= FE_MAX_HW_CHANS) + return -EINVAL; + if (!def->ucfg[chno].rx_en) + return 0; + if (gain > RX_DSA_MAX_ATTN) + gain = RX_DSA_MAX_ATTN; + + def->ucfg[chno].rx_dsa = RX_DSA_MAX_ATTN - gain; + + if (actual_gain) { + *actual_gain = gain; + } + + return ext_fe_update_user(def); +} + + + int ext_fe_ch4_sens_get(ext_fe_ch4_400_7200_t* fe, uint64_t *ovalue) { int temp256 = 127*256, res; @@ -563,7 +652,7 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, USDR_LOG("FE4C", USDR_LOG_ERROR, "Temp %.2fC\n", val / 256.0); // User initialization - ob->ref_gps = 0; + ob->ref_gps = 1; ob->if_vbyp = 1; for (unsigned ch = 0; ch < FE_MAX_HW_CHANS; ch++) { ob->ucfg[ch].rx_fb_sel = RX_FB_AUTO; // rx_filterbank @@ -596,3 +685,13 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, ob->hsgpio_base = 0; return 0; } + +int ext_fe_destroy(ext_fe_ch4_400_7200_t* dfe) +{ + for (unsigned ch = 0; ch < FE_MAX_HW_CHANS; ch++) { + dfe->ucfg[ch].tx_en = 0; // Channel enabled on device side + dfe->ucfg[ch].rx_en = 0; // Channel enabled on device side + } + + return ext_fe_update_user(dfe); +} diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h index 9cce207e..26cf6c8f 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h @@ -80,5 +80,13 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, const char *params, const char *compat, ext_fe_ch4_400_7200_t* ob); +int ext_fe_destroy(ext_fe_ch4_400_7200_t* dfe); + +int ext_fe_rx_freq_set(ext_fe_ch4_400_7200_t* def, unsigned chno, uint64_t freq); +int ext_fe_rx_chan_en(ext_fe_ch4_400_7200_t* def, unsigned ch_fe_mask_rx); +int ext_fe_tx_chan_en(ext_fe_ch4_400_7200_t* def, unsigned ch_fe_mask_tx); + +int ext_fe_rx_gain_set(ext_fe_ch4_400_7200_t* def, unsigned chno, unsigned gain, unsigned* actual_gain); + #endif From 129f58410136bda822441c876a2c5f496715173d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 3 Oct 2025 19:42:57 +0400 Subject: [PATCH 185/397] DIRTY FIX for external i2c control --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 49 +++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index abc13cff..8ae3b130 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -46,17 +46,32 @@ enum { I2C_BUS_FRONTEND = MAKE_LSOP_I2C_ADDR(0, 1, 0), }; +static const usdr_dev_param_constant_t s_params_m2_lm7_1_rev_generic[] = { + { DNLL_I2C_COUNT, 1 }, + { DNLL_IRQ_COUNT, 8 }, +}; + +// sSDR external I2C bus (3/4) +static const usdr_dev_param_constant_t s_params_m2_lm7_1_rev_advanced[] = { + { DNLL_I2C_COUNT, 2 }, + { DNLL_IRQ_COUNT, 9 }, + + { "/ll/i2c/1/core", USDR_MAKE_COREID(USDR_CS_BUS, USDR_BS_DI2C_SIMPLE) }, + { "/ll/i2c/1/base", REG_SPI_I2C2 }, + { "/ll/i2c/1/irq", M2PCI_INT_I2C_1 }, +}; + // static const usdr_dev_param_constant_t s_params_m2_lm7_1_rev000[] = { { DNLL_SPI_COUNT, 1 }, - { DNLL_I2C_COUNT, 1 }, + // { DNLL_I2C_COUNT, 1 }, { DNLL_SRX_COUNT, 1 }, { DNLL_STX_COUNT, 1 }, { DNLL_RFE_COUNT, 1 }, { DNLL_TFE_COUNT, 0 }, { DNLL_IDX_REGSP_COUNT, 1 }, - { DNLL_IRQ_COUNT, 8 }, //TODO fix segfault when int count < configured + // { DNLL_IRQ_COUNT, 8 }, //TODO fix segfault when int count < configured { DNLL_DRP_COUNT, 2 }, { DNLL_BUCKET_COUNT, 1 }, { DNLL_GPO_COUNT, 1 }, @@ -1133,6 +1148,13 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* d->xdev.dpump = d->double_pump; + // Proxy operations + memcpy(&d->my_ops, lowlevel_get_ops(dev), sizeof (lowlevel_ops_t)); + d->my_ops.ls_op = &usdr_device_m2_lm7_1_lsop; + d->p_original_ops = lowlevel_get_ops(dev); + dev->ops = &d->my_ops; + + // Probe fe if (d->xdev.new_rev) { // Init FE res = device_fe_probe(udev, d->xdev.ssdr ? "m2b+m" : "m2a+e", fe, I2C_BUS_FRONTEND, &d->fe); @@ -1149,11 +1171,6 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* lowlevel_reg_wr32(dev, 0, 0, 0x02000000); #endif - // Proxy operations - memcpy(&d->my_ops, lowlevel_get_ops(dev), sizeof (lowlevel_ops_t)); - d->my_ops.ls_op = &usdr_device_m2_lm7_1_lsop; - d->p_original_ops = lowlevel_get_ops(dev); - dev->ops = &d->my_ops; return 0; } @@ -1343,6 +1360,7 @@ static int usdr_device_m2_lm7_1_create(lldev_t dev, device_id_t devid) { int res; + unsigned hwid; struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)malloc(sizeof(struct dev_m2_lm7_1_gps)); res = xsdr_ctor(dev, &d->xdev); @@ -1355,6 +1373,23 @@ int usdr_device_m2_lm7_1_create(lldev_t dev, device_id_t devid) goto failed_free; } + res = dev_gpi_get32(dev, IGPI_HWID, &hwid); + //if (res) { + // goto failed_free; + //} + + if ((res == 0) && ((hwid >> 16) & 0xff) == SSDR_DEV) { + res = vfs_add_const_i64_vec(&d->base.rootfs, + s_params_m2_lm7_1_rev_advanced, + SIZEOF_ARRAY(s_params_m2_lm7_1_rev_advanced)); + } else { + res = vfs_add_const_i64_vec(&d->base.rootfs, + s_params_m2_lm7_1_rev_generic, + SIZEOF_ARRAY(s_params_m2_lm7_1_rev_generic)); + } + if (res) + goto failed_tree_creation; + res = vfs_add_const_i64_vec(&d->base.rootfs, s_params_m2_lm7_1_rev000, SIZEOF_ARRAY(s_params_m2_lm7_1_rev000)); From 55588efc84e7d5a033cbc7e2880ce65a20c86be4 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 9 Oct 2025 14:29:54 +0400 Subject: [PATCH 186/397] ssdr: fe dac control --- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c | 26 +++++++++++++++++-- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h | 1 + src/lib/device/m2_lm7_1/m2_lm7_1.c | 14 ++++++++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c index 4f7d91e2..4886cb54 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c @@ -24,6 +24,8 @@ // M.2 breakout // ------------------------------------------------------------------------------------- // M.2 pin sSDR dSDR +// 8 SSDR_GPIO2 M2_1PPS_SYNC -- +// // 10 SSDR_GPLED0 GPIO33_0 EXT_I2C_SDA // 20 SSDR_GPIO1 -------- AUX_MUX_GPIO1 -- *EXT2_I2C_SDA / FAN0_TACH // 38 SSDR_GPLED1_P FGPIO_N @@ -42,6 +44,8 @@ enum { + GPIO_1PPS = GPIO2, + // GPIO_I2C3_SDA = GPIO12, GPIO_I2C3_SCL = GPIO6, @@ -63,6 +67,8 @@ enum i2c_idx_extra { I2C_TCA6424AR_U301 = MAKE_LSOP_I2C_ADDR(1, 1, TCA6424A_ADDR_H), //CD I2C_TEMP_U69 = MAKE_LSOP_I2C_ADDR(1, 0, I2C_DEV_TMP114NB), + + I2C_DAC = MAKE_LSOP_I2C_ADDR(1, 0, 0x48), }; enum { @@ -184,8 +190,8 @@ static void _ext_fe_fbank_map(unsigned filsel, unsigned *bout, unsigned *bin) // Switch on RX path => ANT_RX external port / rfsw_rxtx / LB enum rfsw_tddfdd_bits { EXP_TDDFDD_SD = 0b00, // LB SW is on - EXP_TDDFDD_P2_TRX_SW = 0b01, - EXP_TDDFDD_P1_LB_SW = 0b10, // LB SW is on + EXP_TDDFDD_P1_LB_SW = 0b01, // LB SW is on + EXP_TDDFDD_P2_TRX_SW = 0b10, EXP_TDDFDD_P3_ANT_RX = 0b11, }; @@ -638,6 +644,8 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, if (res || val != TMP114_DEVICE_ID) return res; + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO_1PPS, GPIO_CFG_ALT0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, 0); res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0 + 2, 0); res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0, 0); @@ -672,6 +680,14 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U301, TCA6424_CFG0, 0); res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U301, TCA6424_CFG0 + 2, 0); + + res = (res) ? res : dac80501_init(dev, subdev, I2C_DAC, DAC80501_CFG_REF_DIV_GAIN_MUL); + if (res) { + USDR_LOG("FE4C", USDR_LOG_WARNING, "External DAC not recognized error=%d\n", res); + //return -ENODEV; + // ob->dac_present = false; + } + res = (res) ? res : usdr_vfs_obj_param_init_array_param(base, (void*)ob, s_fe_parameters, @@ -695,3 +711,9 @@ int ext_fe_destroy(ext_fe_ch4_400_7200_t* dfe) return ext_fe_update_user(dfe); } + +int ext_fe_set_dac(ext_fe_ch4_400_7200_t* brd, unsigned value) +{ + USDR_LOG("M2PE", USDR_LOG_ERROR, "DAC set to: %d\n", value); + return dac80501_dac_set(brd->dev, brd->subdev, I2C_DAC, value); +} diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h index 26cf6c8f..0b2f97c4 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h @@ -88,5 +88,6 @@ int ext_fe_tx_chan_en(ext_fe_ch4_400_7200_t* def, unsigned ch_fe_mask_tx); int ext_fe_rx_gain_set(ext_fe_ch4_400_7200_t* def, unsigned chno, unsigned gain, unsigned* actual_gain); +int ext_fe_set_dac(ext_fe_ch4_400_7200_t* brd, unsigned value); #endif diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 8ae3b130..ba5a0dc1 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -24,7 +24,8 @@ #include "xsdr_ctrl.h" -//#include "../device/ext_exm2pe/board_exm2pe.h" +#include "../device/ext_exm2pe/board_exm2pe.h" +#include "../device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h" #define USBEN 1 @@ -380,7 +381,16 @@ int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t v int dev_m2_lm7_1_dev_dac_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - return xsdr_trim_dac_vctcxo(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + board_exm2pe_t* board = device_fe_to(d->fe, "exm2pe"); + ext_fe_ch4_400_7200_t* fe = device_fe_to(d->fe, "fe4ch4007200"); + if (board) { + return board_exm2pe_set_dac(board, value); + } else if (fe) { + return ext_fe_set_dac(fe, value); + } + + return xsdr_trim_dac_vctcxo(&d->xdev, value); } int dev_m2_lm7_1_phyrxlm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) From a425609e310c4cc8aaefeff4051d7b39da600460 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 9 Oct 2025 14:31:51 +0400 Subject: [PATCH 187/397] dsdr: Rev2 external buffer control --- src/lib/device/m2_dsdr/m2_dsdr.c | 70 +++++++++++++++++++++++++++----- src/lib/hw/afe79xx/afe79xx.c | 5 ++- src/lib/hw/afe79xx/afe79xx.h | 2 +- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index e5633673..eea2f488 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -36,8 +36,9 @@ // enum dsdr_type { - DSDR_KCU116_EVM = 0xce, + DSDR_KCU116_EVM = 0xc0, DSDR_M2_R0 = 0xc2, + DSDR_M2_R1 = 0xce, DSDR_PCIE_HIPER_R0 = 0xcf, }; @@ -155,6 +156,9 @@ enum { IGPO_TX_MAP = 37, //IGPO_RX_IQS = 38, + + IGPO_TX_CHEN = 39, + IGPO_RX_CHEN = 40, }; enum { @@ -266,6 +270,9 @@ const usdr_dev_param_constant_t s_params_m2_dsdr_rev000[] = { static int dev_m2_dsdr_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_dsdr_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_dsdr_rx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_dsdr_tx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_dsdr_gain_tx_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_dsdr_gain_rx_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -403,6 +410,9 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { { "/dm/rate/master", { dev_m2_dsdr_rate_set, NULL }}, { "/dm/rate/rxtxadcdac", { dev_m2_dsdr_rate_m_set, NULL }}, + { "/dm/sdr/0/rx_enchan", { dev_m2_dsdr_rx_enchan, NULL }}, + { "/dm/sdr/0/tx_enchan", { dev_m2_dsdr_tx_enchan, NULL }}, + { "/dm/sdr/0/rx/remap", { dev_m2_dsdr_sdr_rx_remap_set, dev_m2_dsdr_sdr_rx_remap_get }}, { "/dm/sdr/0/tx/remap", { dev_m2_dsdr_sdr_tx_remap_set, dev_m2_dsdr_sdr_tx_remap_get }}, @@ -608,6 +618,19 @@ bool dev_m2_dsdr_has_hiper(dev_m2_dsdr_t* d) return d->type == DSDR_PCIE_HIPER_R0; } + +int dev_m2_dsdr_rx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; + return dev_gpo_set(d->base.dev, IGPO_RX_CHEN, value); + +} +int dev_m2_dsdr_tx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; + return dev_gpo_set(d->base.dev, IGPO_TX_CHEN, value); +} + static int dsdr_update_rx_remap(dev_m2_dsdr_t* d) { // Mark corresponding RX chanel @@ -1298,6 +1321,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** lldev_t dev = d->base.dev; int res = 0; uint32_t hwid, usr2, pg, los, devid, jesdv; + unsigned afeType = 0; d->subdev = 0; d->hw_mask_fb = 0; @@ -1326,6 +1350,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** switch (devid) { case DSDR_KCU116_EVM: case DSDR_M2_R0: + case DSDR_M2_R1: case DSDR_PCIE_HIPER_R0: d->type = devid; break; @@ -1339,6 +1364,12 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return -EIO; } + // + if (getenv("DSDR_M2_R0")) { + d->type = DSDR_M2_R0; + } + + afeType = 7901; switch (jesdv) { case DSDR_JESD204B_810_245: d->max_rate = 260e6; @@ -1357,7 +1388,13 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->dac_rate = d->adc_rate = 491520000; d->afecongiguration = "Afe79xxPg1_6664_491.txt"; if (d->hw_mask_rx == 0x5 && d->hw_mask_tx == 0xA) { - d->afecongiguration = "Afe79xxPg1_dsdr_491_7903.txt"; + d->afecongiguration = "Afe79xxPg1_dsdr_491_7903.txt"; + afeType = 7903; + } + if (false) { + // AFE7950 + d->afecongiguration = "Afe79xxPg1_600_1.txt"; + afeType = 7950; } break; @@ -1367,6 +1404,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } d->jesdv = jesdv; + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s\n", d->afecongiguration); USDR_LOG("XDEV", USDR_LOG_WARNING, "AFE type JESD204%c CH_TX=%02x CH_RX=%02x\n", (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx); if (getenv("SKIPAFE")) { @@ -1413,7 +1451,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** break; } - if (d->type == DSDR_M2_R0) { + if (d->type == DSDR_M2_R0 || d->type == DSDR_M2_R1) { bool pg; for (unsigned j = 0; j < 20; j++) { usleep(10000); @@ -1473,14 +1511,15 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** if(res) return res; - //wait for PRIREF/SECREF validation + // wait for PRIREF/SECREF validation res = lmk05318_wait_dpll_ref_stat(&d->lmk, 100000); - if(res) - { + if (res) { USDR_LOG("DSDR", USDR_LOG_ERROR, "LMK03518 DPLL input reference freqs are not validated during specified timeout"); return res; } + //res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0x7f); + //wait for lock res = lmk05318_wait_apll1_lock(&d->lmk, 200000); res = res ? res : lmk05318_wait_apll2_lock(&d->lmk, 200000); @@ -1494,10 +1533,13 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** //sync to make APLL1/APLL2 & out channels in-phase res = lmk05318_sync(&d->lmk); + //usleep(1000); + //res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0x7f); + //usleep(1000); //res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0xff); - if(res) - return res; + //if(res) + // return res; USDR_LOG("DSDR", USDR_LOG_INFO, "LMK03518 outputs synced, LOS=%x", los); //LMK05318 init end @@ -1554,7 +1596,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // We don't have PG_1v2 routed in this rev // We don't have EN_1v8 routed in this rev - if (d->type == DSDR_PCIE_HIPER_R0) { + if (d->type == DSDR_PCIE_HIPER_R0 || d->type == DSDR_M2_R1) { usleep(25000); res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0xf); } @@ -1587,7 +1629,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(100000); - res = res ? res : afe79xx_create(dev, d->subdev, 0, &d->st); + res = res ? res : afe79xx_create(dev, d->subdev, 0, afeType, &d->st); if (res == 0) { res = res ? res : usdr_jesd204b_bringup_pre(d); @@ -1859,6 +1901,8 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char } } + // TODO: set actual antenna mask + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0xf); *out_handle = d->rx; } else if (strstr(sid, "tx") != NULL) { if (d->tx) { @@ -1924,6 +1968,8 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char } } + // TODO: set actual antenna mask + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0xf); *out_handle = d->tx; } @@ -1944,6 +1990,8 @@ int usdr_device_m2_dsdr_unregister_stream(device_t* dev, stream_handle_t* stream if (dev_m2_dsdr_has_hiper(d)) { res = dsdr_hiper_fe_rx_chan_en(&d->hiper, 0); } + + dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0); } else if (stream == d->tx) { d->tx = NULL; d->hw_enabled_rx = 0; @@ -1952,6 +2000,8 @@ int usdr_device_m2_dsdr_unregister_stream(device_t* dev, stream_handle_t* stream if (dev_m2_dsdr_has_hiper(d)) { res = dsdr_hiper_fe_tx_chan_en(&d->hiper, 0); } + + dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0); } else { return -EINVAL; } diff --git a/src/lib/hw/afe79xx/afe79xx.c b/src/lib/hw/afe79xx/afe79xx.c index 03c44ba5..508f79e2 100644 --- a/src/lib/hw/afe79xx/afe79xx.c +++ b/src/lib/hw/afe79xx/afe79xx.c @@ -88,10 +88,11 @@ int afe79xx_create_dummy(afe79xx_state_t* out) return 0; } -int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, afe79xx_state_t* out) +int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipType, afe79xx_state_t* out) { int res; const char* afe79xxlib = "liblibcapi79xx.so"; + unsigned g; out->dev = dev; out->subdev = subdev; @@ -148,7 +149,7 @@ int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, afe79xx_state_ } // TODO: version check - return out->libcapi79xx_create(&out->capi, AFE7903); + return out->libcapi79xx_create(&out->capi, (enum afe79xx_chip_type)chipType); } int afe79xx_init(afe79xx_state_t* afe, const char* configuration) diff --git a/src/lib/hw/afe79xx/afe79xx.h b/src/lib/hw/afe79xx/afe79xx.h index 31780abf..e019aa96 100644 --- a/src/lib/hw/afe79xx/afe79xx.h +++ b/src/lib/hw/afe79xx/afe79xx.h @@ -30,7 +30,7 @@ struct afe79xx_state { typedef struct afe79xx_state afe79xx_state_t; -int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, afe79xx_state_t* out); +int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipType, afe79xx_state_t* out); int afe79xx_init(afe79xx_state_t* afe, const char *configuration); From e10f3561ddc93fa0bf97e06a6dddf6cfeb65905e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 9 Oct 2025 20:40:14 +0400 Subject: [PATCH 188/397] dsdr update --- src/lib/device/m2_dsdr/m2_dsdr.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index eea2f488..79d0a21a 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1336,6 +1336,10 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return res; } + res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x0); + res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x0); + res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0x0); + // TODO check for AFE7903 if (getenv("DSDR_AFE7903")) { d->hw_mask_rx = 0x5; // RX_3 RX_1 @@ -1391,7 +1395,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->afecongiguration = "Afe79xxPg1_dsdr_491_7903.txt"; afeType = 7903; } - if (false) { + if (getenv("DSDR_M2_7950")) { // AFE7950 d->afecongiguration = "Afe79xxPg1_600_1.txt"; afeType = 7950; @@ -1479,6 +1483,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(20000); res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0xff); + usleep(200000); // //LMK05318 init start @@ -1592,6 +1597,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return -EIO; } + usleep(10000); + res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x7); // Enable DCDC 1.2V; // We don't have PG_1v2 routed in this rev // We don't have EN_1v8 routed in this rev From 54cdfae9d48328f5097e6f1a6137e2fd6dcfd34e Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 9 Oct 2025 22:15:53 +0400 Subject: [PATCH 189/397] Added GPSDO test utility --- src/lib/device/m2_lm6_1/usdr_ctrl.c | 2 +- src/lib/device/u3_limesdr/u3_limesdr.c | 16 ++ src/tools/CMakeLists.txt | 4 + src/tools/usdr_dm_gpsdo.c | 364 +++++++++++++++++++++++++ 4 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 src/tools/usdr_dm_gpsdo.c diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 2b70c714..902461d1 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -764,7 +764,7 @@ int usdr_rfic_fe_set_freq(struct usdr_dev *d, lms6002d_tune_pll(&d->lms, 0, freq); } // LDO may not be ready, check again - usleep(1000); + usleep(5000); res = lms6002d_tune_pll(&d->lms, dir_tx, freq); } if (res == -ENOLCK) { diff --git a/src/lib/device/u3_limesdr/u3_limesdr.c b/src/lib/device/u3_limesdr/u3_limesdr.c index 73899054..e43c5733 100644 --- a/src/lib/device/u3_limesdr/u3_limesdr.c +++ b/src/lib/device/u3_limesdr/u3_limesdr.c @@ -62,6 +62,9 @@ static int dev_limesdr_sdr_rx_gainvga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uin static int dev_limesdr_sdr_rx_gainlna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_limesdr_sdr_rx_gainlb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_limesdr_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_limesdr_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_mp_lm7_1_gps_sdr_rx_bandwidth_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_mp_lm7_1_gps_sdr_tx_bandwidth_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -88,6 +91,9 @@ const usdr_dev_param_func_t s_fparams_u3_limesdr_0[] = { { "/dm/sdr/0/tx/gain", { dev_limesdr_sdr_tx_gain_set, NULL }}, { "/dm/sdr/0/tx/gain/lb", { dev_limesdr_sdr_tx_gainlb_set, NULL }}, + { "/dm/sdr/0/rx/path", { dev_limesdr_sdr_rx_path_set, NULL }}, + { "/dm/sdr/0/tx/path", { dev_limesdr_sdr_tx_path_set, NULL }}, + { "/dm/sdr/0/rx/gain/pga", { dev_limesdr_sdr_rx_gainpga_set, NULL }}, { "/dm/sdr/0/rx/gain/vga", { dev_limesdr_sdr_rx_gainvga_set, NULL }}, { "/dm/sdr/0/rx/gain/lna", { dev_limesdr_sdr_rx_gainlna_set, NULL }}, @@ -225,6 +231,16 @@ int dev_limesdr_sdr_rx_gainlb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t va return lms7002m_set_gain(&d->limedev.base, LMS7_CH_AB, RFIC_LMS7_RX_LB_GAIN, value, NULL); } +int dev_limesdr_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return 0; +} + +int dev_limesdr_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return 0; +} + int dev_mp_lm7_1_gps_sdr_rx_bandwidth_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_limesdr *d = (struct dev_limesdr *)ud; diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 5a4d210a..83fa4400 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -25,6 +25,10 @@ install(TARGETS usdr_dm_sensors RUNTIME) add_executable(usdr_lml7_test lms7002_dm_limelight.c) target_link_libraries(usdr_lml7_test usdr) +add_executable(usdr_dm_gpsdo usdr_dm_gpsdo.c) +target_link_libraries(usdr_dm_gpsdo usdr) +install(TARGETS usdr_dm_gpsdo RUNTIME) + list(APPEND WVLT_SCRIPTS wvlt_sdr_wrapper.py ) diff --git a/src/tools/usdr_dm_gpsdo.c b/src/tools/usdr_dm_gpsdo.c new file mode 100644 index 00000000..39c1be8a --- /dev/null +++ b/src/tools/usdr_dm_gpsdo.c @@ -0,0 +1,364 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +// PID parameters +#define KP 0.75 // Proportional gain +#define KI 0.02 // Integral gain +#define KD 0.0075 // Derivative gain +#define DT 1.0 // Update interval (1 second) +#define HZ_PER_STEP 0.01 +#define INTEGRAL_MAX 1e6 +#define OUTPUT_MAX 1e-3 +#define DEVIATION_MAX 7e-6 + +typedef struct { + uint32_t bits; + uint32_t center; + uint32_t min_value; + uint32_t max_value; + double hz_per_step; // Hz per DAC step +} DAC; + +int dac_init(DAC *dac, uint32_t dac_bits, uint32_t freq) +{ + if (!dac) + return 1; + if (dac_bits < 8 || dac_bits > 16) + return 2; + dac->bits = dac_bits; + dac->min_value = 0; + dac->max_value = (1 << dac_bits) - 1; + dac->center = dac->max_value >> 1; + dac->hz_per_step = 2 * DEVIATION_MAX * (double)freq / dac->max_value; + return 0; +} + +// DAC control +uint32_t set_dac_value(pdm_dev_t dev, const DAC *dac, uint32_t dac_offset, double step) +{ + static const char *dac_vctcxo_path = "/dm/sdr/0/dac_vctcxo"; + static uint64_t old_dac_value = 0; + // double dac_delta = freq_offset / dac_gain; // Δdac = Δf / gain + // uint32_t dac_value = (uint32_t) (dac_mid + dac_delta); + uint32_t dac_value = (uint32_t) lround(dac_offset + step); + if (dac_value < 0) + dac_value = 0; + if (dac_value > dac->max_value) + dac_value = dac->max_value; + + if (dac_value != old_dac_value) { + // Send to DAC + printf( + "DAC value: %d (%d bits, dac_offset %d, step %f)\n", dac_value, dac->bits, dac_offset, step); + const int res = usdr_dme_set_uint(dev, dac_vctcxo_path, (uint64_t)dac_value); + if (res) { + fprintf(stderr, "Unable to set vctcxo dac value: errno %d\n", res); + return res; + } + old_dac_value = dac_value; + } + return dac_value; +} + +typedef struct +{ + double kp; + double ki; + double kd; + double integral; + double prev_error; + double integral_max; + double output_max; +} PID; + +void pid_init(PID *p, double kp, double ki, double kd, double integral_max, double output_max) +{ + p->kp = kp; + p->ki = ki; + p->kd = kd; + p->integral = 0.0; + p->prev_error = 0.0; + p->integral_max = integral_max; + p->output_max = output_max; +} + +double pid_update(PID *p, double error, double dt) +{ + double P = p->kp * error; + p->integral += error * dt; + if (p->integral > p->integral_max) + p->integral = p->integral_max; + if (p->integral < -p->integral_max) + p->integral = -p->integral_max; + double I = p->ki * p->integral; + double D = p->kd * (error - p->prev_error) / dt; + p->prev_error = error; + double out = P + I + D; + if (out > p->output_max) + out = p->output_max; + if (out < -p->output_max) + out = -p->output_max; + return out; +} + +// Stub for getting PPS count and measured frequency from FPGA +uint8_t get_pps_count(uint64_t ppsparm) +{ + return (ppsparm >> 28) & 0xf; +} + +uint32_t get_measured_freq(uint64_t ppsparm) +{ + return ppsparm & 0xfffffff; +} + +void show_usage(const char *procname) +{ + fprintf(stderr, "Usage %s:\n", procname); + fprintf(stderr, " Options:\n"); + fprintf(stderr, " -d - device\n"); + // fprintf(stderr, " -f - target frequency of oscillator [26e6] Hz\n"); + fprintf(stderr, " -r - target samplerate [4e6] Samples\n"); + fprintf(stderr, " -h - this help\n"); +} + +int main(int argc, char **argv) +{ + const char *pps_path = "/dm/sensor/freqpps"; + const char *ext_osc_path = "/dm/sdr/refclk/path"; + const char *ext_osc_parm = "external"; + const char *ext_freq_path = "/dm/sdr/refclk/frequency"; + const uint64_t ext_freq_value = 25000000ull; + const double dt = 1.0; // Update interval (1 second) + const int dac_bits = 16; // DAC bitness + + int res, opt; + uint64_t ppsparm = 0; + pdm_dev_t dev; + const char *device = "";//"fe=exm2pe:gps_on:osc_on"; + // double target_freq = 26e6; // Target frequency, 26 MHz + double target_freq = 4e6; // Target samplerate, 4 Msps + bool new_holdover_msg = true; + + while ((opt = getopt(argc, argv, "d:f:r:h")) != -1) { + switch (opt) { + case 'd': + device = optarg; + break; + // case 'f': + // target_freq = atof(optarg); + // if (target_freq < 100.0) + // target_freq *= 1e6; + // break; + case 'r': + target_freq = atof(optarg); + if (target_freq < 100.0) + target_freq *= 1e6; + break; + case 'h': + default: + show_usage(argv[0]); + return 1; + } + } + + usdrlog_setlevel(NULL, USDR_LOG_WARNING); + usdrlog_enablecolorize(NULL); + + res = usdr_dmd_create_string(device, &dev); + if (res) { + fprintf(stderr, "Unable to create device: errno %d\n", res); + return 1; + } + + res = usdr_dme_set_uint(dev, ext_freq_path, ext_freq_value); + if (res) { + fprintf(stderr, "Unable to setup external oscilator frequency %" PRId64 ": errno %d\n", ext_freq_value, res); + usdr_dmd_close(dev); + return 1; + } + + res = usdr_dme_set_uint(dev, ext_osc_path, (uint64_t) ext_osc_parm); + if (res) { + fprintf(stderr, "Unable to select external oscilator: errno %d\n", res); + usdr_dmd_close(dev); + return 1; + } + + res = usdr_dmr_rate_set(dev, NULL, (uint64_t) target_freq); + if (res) { + fprintf(stderr, "Unable to set device rate: errno %d", res); + usdr_dmd_close(dev); + return 1; + } + + pusdr_dms_t usds_rx = NULL; + res = usdr_dms_create(dev, "/ll/srx/0", "ci16", 1, 4096, &usds_rx); + if (res) { + fprintf(stderr, "Unable to initialize RX data stream: errno %d", res); + usdr_dmd_close(dev); + return 1; + } + + res = usdr_dms_sync(dev, "any", 1, &usds_rx); + if (res) { + fprintf(stderr, "Unable to sync data streams: errno %d", res); + usdr_dmd_close(dev); + return 1; + } + + res = usds_rx ? usdr_dms_op(usds_rx, USDR_DMS_START, 0) : -EPROTONOSUPPORT; + if (res) { + fprintf(stderr, "Unable to start RX data stream: errno %d", res); + usdr_dmd_close(dev); + return 1; + } + + res = usdr_dme_get_uint(dev, pps_path, &ppsparm); + if (res) { + fprintf(stderr, "Unable to get pps: errno %d\n", res); + usdr_dmd_close(dev); + return 1; + } + // Previous PPS count for trigger detection + int prev_pps_count = get_pps_count(ppsparm); + + DAC dac; + res = dac_init(&dac, dac_bits, target_freq); + if (res) { + fprintf(stderr, "Unable to init DAC for dac bits %d: errno %d", dac_bits, res); + usdr_dmd_close(dev); + return 1; + } + + PID pid; + pid_init(&pid, KP, KI, KD, INTEGRAL_MAX, OUTPUT_MAX); + + + struct timespec start_time; + clock_gettime(CLOCK_MONOTONIC, &start_time); + + // Create timerfd for 100 ms polling + int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (timer_fd == -1) { + perror("timerfd_create"); + return 1; + } + + struct itimerspec timer_spec; + timer_spec.it_value.tv_sec = 0; + timer_spec.it_value.tv_nsec = 100000000; // 100 ms + timer_spec.it_interval = timer_spec.it_value; // Repeat every 100 ms + if (timerfd_settime(timer_fd, 0, &timer_spec, NULL) == -1) { + perror("timerfd_settime"); + + return 1; + } + + struct pollfd fds[1]; + fds[0].fd = timer_fd; + fds[0].events = POLLIN; + + const double holdover_interval = 2 * dt; + uint32_t dac_offset = dac.center; // initial + double measured_freq = 0.0, error = 0.0; + + while (true) { + // Wait for timer event + int ret = poll(fds, 1, -1); + if (ret == -1) { + perror("poll"); + break; + } + + if (fds[0].revents & POLLIN) { + uint64_t expirations; + read(timer_fd, &expirations, sizeof(expirations)); // Clear timer event + + res = usdr_dme_get_uint(dev, pps_path, &ppsparm); + if (res) { + fprintf(stderr, "Unable to get pps: errno %d\n", res); + break; + } + + const uint8_t current_pps_count = get_pps_count(ppsparm); + + // int current_pps_count = get_pps_count(); + + // Check if PPS count changed (trigger for update) + if (current_pps_count != prev_pps_count) { + const uint8_t pps_delta = current_pps_count < prev_pps_count + ? current_pps_count + 0x10 - prev_pps_count + : current_pps_count - prev_pps_count; + measured_freq = (double)get_measured_freq(ppsparm); + error = (measured_freq - target_freq) / target_freq; + + printf("PPS=0x%" PRIx64 ", pps_count=%d, measured_freq = %.0f, error = %.3f ppm\n", + ppsparm, + current_pps_count, + measured_freq, + error * 1e6); + + if (error > 0.02) { + printf("Error more than 2%%, skip iteration\n"); + continue; + } + + double pout = pid_update(&pid, error, dt); + // map pid output (fractional) to Hz correction + double freq_corr_hz = -pout * target_freq; // desired Hz change + double steps_cmd = freq_corr_hz / dac.hz_per_step; + printf("POUT=%f, freq_corr_hz=%f, steps_cmd=%f\n", pout, freq_corr_hz, steps_cmd); + // limit steps + if (steps_cmd > 2000.0) + steps_cmd = 2000.0; + if (steps_cmd < -2000.0) + steps_cmd = -2000.0; + dac_offset = set_dac_value(dev, &dac, dac_offset, steps_cmd); + + prev_pps_count = current_pps_count; + + // Reset timer for holdover tracking + clock_gettime(CLOCK_MONOTONIC, &start_time); + } + + // Check elapsed time for holdover + struct timespec current_time; + clock_gettime(CLOCK_MONOTONIC, ¤t_time); + double elapsed = (current_time.tv_sec - start_time.tv_sec) + + (current_time.tv_nsec - start_time.tv_nsec) / 1e9; + if (elapsed > holdover_interval) { + // Apply last known offset or extrapolate + if (new_holdover_msg) { + printf("No PPS trigger for more than %.1f seconds - entering holdover mode\n", holdover_interval); + new_holdover_msg = false; + } + } else { + if (!new_holdover_msg) { + printf("Found PPS trigger\n"); + new_holdover_msg = true; + } + } + } + } + + close(timer_fd); + usdr_dmd_close(dev); + + return 0; +} From 169aaafd1423e4960c5ee7cabec23d995e1a50ed Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 10 Oct 2025 19:37:09 +0400 Subject: [PATCH 190/397] usdr_flash add warning --- src/tools/usdr_flash.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools/usdr_flash.c b/src/tools/usdr_flash.c index 1790118b..230b6635 100644 --- a/src/tools/usdr_flash.c +++ b/src/tools/usdr_flash.c @@ -130,8 +130,12 @@ int main(int argc, char** argv) } if (!(no_device)) { - usdr_device_vfs_obj_val_get_u64(dev->pdev, "/ll/qspi_flash/master_off", &master_offset); - usdr_device_vfs_obj_val_get_u64(dev->pdev, "/ll/qspi_flash/base", &qspi_base); + res = res ? res : usdr_device_vfs_obj_val_get_u64(dev->pdev, "/ll/qspi_flash/master_off", &master_offset); + res = res ? res : usdr_device_vfs_obj_val_get_u64(dev->pdev, "/ll/qspi_flash/base", &qspi_base); + + if (res) { + fprintf(stderr, "Unable to get board memory configuration, assuming MASTER_OFF=%x!\n", (unsigned)master_offset); + } } usleep(1000); From e1eb4eb8d0d1d6ad3e330adc3cfab76e9277f67d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sun, 12 Oct 2025 01:50:45 +0400 Subject: [PATCH 191/397] pciefe add DAC control --- src/lib/device/ext_pciefe/ext_pciefe.c | 8 ++++++++ src/lib/device/ext_pciefe/ext_pciefe.h | 2 ++ src/lib/device/m2_lm6_1/m2_lm6_1.c | 18 +++++++++++++++++- src/lib/device/m2_lm7_1/m2_lm7_1.c | 6 +++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/lib/device/ext_pciefe/ext_pciefe.c b/src/lib/device/ext_pciefe/ext_pciefe.c index 6e870d24..04a1e2ac 100644 --- a/src/lib/device/ext_pciefe/ext_pciefe.c +++ b/src/lib/device/ext_pciefe/ext_pciefe.c @@ -741,3 +741,11 @@ int board_ext_pciefe_best_path_set(board_ext_pciefe_t* ob, return -EINVAL; } + +int board_ext_pciefe_set_dac(board_ext_pciefe_t* brd, unsigned value) +{ + unsigned i2ca_dac = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(brd->i2c_loc), LSOP_I2C_BUSNO(brd->i2c_loc), I2C_ADDR_DAC); + + brd->dac = value; + return dac80501_dac_set(brd->dev, brd->subdev, i2ca_dac, brd->dac); +} diff --git a/src/lib/device/ext_pciefe/ext_pciefe.h b/src/lib/device/ext_pciefe/ext_pciefe.h index f60ba973..945f5ed7 100644 --- a/src/lib/device/ext_pciefe/ext_pciefe.h +++ b/src/lib/device/ext_pciefe/ext_pciefe.h @@ -101,5 +101,7 @@ int board_ext_pciefe_best_path_set(board_ext_pciefe_t* ob, unsigned txlo, unsigned txbw); +int board_ext_pciefe_set_dac(board_ext_pciefe_t* brd, unsigned value); + #endif diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index ae7dc237..c4bcc267 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -191,6 +191,7 @@ static int dev_m2_lm6_1_sdr_tx_bbloopbackm_set(pdevice_t ud, pusdr_vfs_obj_t obj static int dev_m2_lm6_1_sdr_senstemp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm6_1_sdr_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_clkmeas_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_clkmeas_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); @@ -257,7 +258,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/core/atcrbs/reg", { dev_m2_lm6_1_sdr_atcrbs_set, dev_m2_lm6_1_sdr_atcrbs_get }}, { "/dm/sdr/0/tx/bbloopbackm", { dev_m2_lm6_1_sdr_tx_bbloopbackm_set, NULL }}, - + { "/dm/sdr/0/dac_vctcxo", { dev_m2_lm6_1_sdr_vctcxo_set, NULL }}, { "/dm/sdr/0/clkmeas", { dev_m2_lm6_1_sdr_clkmeas_set, dev_m2_lm6_1_sdr_clkmeas_get }}, { "/dm/revision", { NULL, dev_m2_lm6_1_sdr_revision_get }}, @@ -884,6 +885,21 @@ usdr_dev_t* get_usdr_dev(pdevice_t udev) return &d->d; } +int dev_m2_lm6_1_sdr_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + board_ext_pciefe_t* board_fe = device_fe_to(d->fe, "pciefe"); + board_exm2pe_t* board = device_fe_to(d->fe, "exm2pe"); + if (board_fe) { + return board_ext_pciefe_set_dac(board_fe, value); + } else if (board) { + return board_exm2pe_set_dac(board, value); + } + + return -EINVAL; +} + + static int usdr_device_m2_lm6_1_initialize(pdevice_t udev, unsigned pcount, const char** devparam, const char** devval) { diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index ba5a0dc1..096d8d71 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -24,6 +24,7 @@ #include "xsdr_ctrl.h" +#include "../device/ext_pciefe/ext_pciefe.h" #include "../device/ext_exm2pe/board_exm2pe.h" #include "../device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h" @@ -382,9 +383,12 @@ int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t v int dev_m2_lm7_1_dev_dac_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + board_ext_pciefe_t* board_fe = device_fe_to(d->fe, "pciefe"); board_exm2pe_t* board = device_fe_to(d->fe, "exm2pe"); ext_fe_ch4_400_7200_t* fe = device_fe_to(d->fe, "fe4ch4007200"); - if (board) { + if (board_fe) { + return board_ext_pciefe_set_dac(board_fe, value); + } else if (board) { return board_exm2pe_set_dac(board, value); } else if (fe) { return ext_fe_set_dac(fe, value); From cd841e643e1b454224ed55dae59d1b032bfa6fb8 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Sun, 12 Oct 2025 02:31:05 +0400 Subject: [PATCH 192/397] Added external frequency parameter to GPSDO test utility --- src/tools/usdr_dm_gpsdo.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/tools/usdr_dm_gpsdo.c b/src/tools/usdr_dm_gpsdo.c index 39c1be8a..e17eb444 100644 --- a/src/tools/usdr_dm_gpsdo.c +++ b/src/tools/usdr_dm_gpsdo.c @@ -133,13 +133,14 @@ void show_usage(const char *procname) fprintf(stderr, " Options:\n"); fprintf(stderr, " -d - device\n"); // fprintf(stderr, " -f - target frequency of oscillator [26e6] Hz\n"); + fprintf(stderr, " -o - external oscilator frequency [25e6] Hz\n"); fprintf(stderr, " -r - target samplerate [4e6] Samples\n"); fprintf(stderr, " -h - this help\n"); } int main(int argc, char **argv) { - const char *pps_path = "/dm/sensor/freqpps"; + const char *pps_path = "/dm/sensor/freqpps";//"/dm/sdr/0/clkmeas"; const char *ext_osc_path = "/dm/sdr/refclk/path"; const char *ext_osc_parm = "external"; const char *ext_freq_path = "/dm/sdr/refclk/frequency"; @@ -152,10 +153,11 @@ int main(int argc, char **argv) pdm_dev_t dev; const char *device = "";//"fe=exm2pe:gps_on:osc_on"; // double target_freq = 26e6; // Target frequency, 26 MHz + double osc_freq = (double)ext_freq_value; double target_freq = 4e6; // Target samplerate, 4 Msps bool new_holdover_msg = true; - while ((opt = getopt(argc, argv, "d:f:r:h")) != -1) { + while ((opt = getopt(argc, argv, "d:f:o:r:h")) != -1) { switch (opt) { case 'd': device = optarg; @@ -165,6 +167,11 @@ int main(int argc, char **argv) // if (target_freq < 100.0) // target_freq *= 1e6; // break; + case 'o': + osc_freq = atof(optarg); + if (osc_freq < 100.0) + osc_freq *= 1e6; + break; case 'r': target_freq = atof(optarg); if (target_freq < 100.0) @@ -186,7 +193,7 @@ int main(int argc, char **argv) return 1; } - res = usdr_dme_set_uint(dev, ext_freq_path, ext_freq_value); + res = usdr_dme_set_uint(dev, ext_freq_path, (uint64_t)osc_freq); if (res) { fprintf(stderr, "Unable to setup external oscilator frequency %" PRId64 ": errno %d\n", ext_freq_value, res); usdr_dmd_close(dev); From 9498d39f645750898d7fd944bd0525842c29d25e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 13 Oct 2025 12:11:24 +0400 Subject: [PATCH 193/397] ssdr: wait lms8 bring up --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 38 ++++++++++++++++++----------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 1 + 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 977f6d84..35dde772 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1562,6 +1562,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) return -EIO; } + d->lms8_alive = false; // Enable internal clocking by default res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_CLK_CFG, 1); if (hwid == SSDR_DEV) { @@ -1576,25 +1577,34 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x002F0000, &chipver); USDR_LOG("XDEV", USDR_LOG_INFO, "LMS7002 version %08x\n", chipver); -#if 1 - res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x81); - usleep(100000); + for (unsigned j = 0; j < 5; j++) { + res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x81); + usleep(100000); - res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x800000ff, &chipver); - res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x000f0000, &chipver); - USDR_LOG("XDEV", USDR_LOG_INFO, "LMS8001 version %08x\n", chipver); + res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x800000ff, &chipver); + res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x000f0000, &chipver); + USDR_LOG("XDEV", USDR_LOG_INFO, "LMS8001 version %08x\n", chipver); - res = res ? res : lms8001_create(dev, d->base.lmsstate.subdev, 0, &d->lms8); + res = res ? res : lms8001_create(dev, d->base.lmsstate.subdev, 0, &d->lms8); - res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x80); - //res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x00); - // res = res ? res : dev_gpo_set(dev, IGPO_LDOLMS_EN, 0); // Enable LDOs - // res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0); + res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x80); + //res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x00); + // res = res ? res : dev_gpo_set(dev, IGPO_LDOLMS_EN, 0); // Enable LDOs + // res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0); - if (chipver != 0x00004040) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "LMS8001 not detected!\n"); + if (chipver != 0x00004040) { + usleep(100000); + } else { + d->lms8_alive = true; + break; + } } -#endif + + if (!d->lms8_alive) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "LMS8001 not detected, check the board!\n"); + return -EFAULT; + } + } return res; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index b7f3bc0c..3085c000 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -68,6 +68,7 @@ struct xsdr_dev bool pwr_en; bool new_rev; bool ssdr; + bool lms8_alive; bool dpump; //Dual pump data union { From 8d89f352723f1b1f6817f4a072340e380b520343 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 13 Oct 2025 18:53:09 +0400 Subject: [PATCH 194/397] ssdr fix path --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 57 ++++++++++++++++++++++++----- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 5 ++- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 096d8d71..d8b15117 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -182,8 +182,9 @@ static int dev_m2_lm7_1_sdr_rx_gainvga_set(pdevice_t ud, pusdr_vfs_obj_t obj, ui static int dev_m2_lm7_1_sdr_rx_gainlna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_rx_gainlb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_sdr_rfic_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); -//static int dev_m2_lm7_1_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_senstemp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); static int dev_m2_lm7_1_debug_lms7002m_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -301,8 +302,11 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/rx/gain/lna", { dev_m2_lm7_1_sdr_rx_gainlna_set, NULL }}, { "/dm/sdr/0/rx/gain/lb", { dev_m2_lm7_1_sdr_rx_gainlb_set, NULL }}, + { "/dm/sdr/0/rx/rfic_path", { dev_m2_lm7_1_sdr_rfic_path_set, NULL }}, + { "/dm/sdr/0/tx/rfic_path", { dev_m2_lm7_1_sdr_rfic_path_set, NULL }}, + { "/dm/sdr/0/rx/path", { dev_m2_lm7_1_sdr_rx_path_set, NULL }}, - { "/dm/sdr/0/tx/path", { dev_m2_lm7_1_sdr_rx_path_set, NULL }}, + { "/dm/sdr/0/tx/path", { dev_m2_lm7_1_sdr_tx_path_set, NULL }}, { "/dm/sdr/0/rx/dccorrmode", { dev_m2_lm7_1_sdr_rx_dccorrmode_set, NULL }}, @@ -1007,18 +1011,24 @@ static int find_param_list(const char* param, const param_list_idx_t* lst, unsig return -1; } +int _sdr_get_path(const char* param) +{ + int idx = find_param_list(param, s_path_list, SIZEOF_ARRAY(s_path_list)); + if (idx < 0) { + USDR_LOG("UDEV", USDR_LOG_WARNING, "m2_lm7_1_GPS: unknown '%s' path!\n", + param); + return -EINVAL; + } + return idx; +} -int dev_m2_lm7_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +int dev_m2_lm7_1_sdr_rfic_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; if (value > 4096) { - const char* param = (const char*)value; - int idx = find_param_list(param, s_path_list, SIZEOF_ARRAY(s_path_list)); - if (idx < 0) { - USDR_LOG("UDEV", USDR_LOG_WARNING, "m2_lm7_1_GPS: unknown '%s' path!\n", - param); - return -EINVAL; - } + int idx = _sdr_get_path((const char*)value); + if (idx < 0) + return idx; value = s_path_list[idx].param; } @@ -1026,6 +1036,33 @@ int dev_m2_lm7_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val return xsdr_rfic_fe_set_lna(&d->xdev, LMS7_CH_AB, value); } +int dev_m2_lm7_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + if (value > 4096) { + int idx = _sdr_get_path((const char*)value); + if (idx < 0) + return idx; + + value = s_path_list[idx].param; + } + + return xsdr_rfic_rfe_set_path(&d->xdev, value); +} + +int dev_m2_lm7_1_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + if (value > 4096) { + int idx = _sdr_get_path((const char*)value); + if (idx < 0) + return idx; + + value = s_path_list[idx].param; + } + + return xsdr_rfic_tfe_set_path(&d->xdev, value); +} int dev_m2_lm7_1_sdr_refclk_frequency_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 3085c000..3ebf4bb2 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -139,9 +139,12 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, int xsdr_rfic_fe_set_lna(xsdr_dev_t *d, unsigned channel, - //unsigned dir, unsigned lna); +int xsdr_rfic_rfe_set_path(xsdr_dev_t *d, + unsigned path); +int xsdr_rfic_tfe_set_path(xsdr_dev_t *d, + unsigned path); int xsdr_rfic_streaming_xflags(xsdr_dev_t *d, unsigned xor_rx_flags, From cd7ddd401d16847d8fa13adb34224b1ea5c46c47 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 13 Oct 2025 19:12:59 +0400 Subject: [PATCH 195/397] ssdr optimize PLL settings --- src/lib/hw/lms8001/lms8001.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index e05da8ea..92fb0716 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -20,13 +20,16 @@ enum lms8_vco_params { // Safe values for LO range LMS8_MIN_NIQ = 520000000U, - LMS8_MAX_NIQ = 9110000000ULL, + //LMS8_MAX_NIQ = 9110000000ULL, + LMS8_MAX_NIQ = 9400000000ULL, LMS8_MIN_IQ = LMS8_MIN_NIQ / 2, LMS8_MAX_IQ = LMS8_MAX_NIQ / 2, }; enum { LMS_LDO_1P25 = 101, + LMS_LDO_1P43 = 147, + LMS_LDO_VCO_REG = 207, }; @@ -332,9 +335,9 @@ int lms8001b_hlmix_loss_set(lms8001_state_t* state, unsigned chan, unsigned loss int lms8001_core_enable(lms8001_state_t* out, bool en) { uint32_t lms_init[] = { - MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P25), - MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P25), - MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P43), + MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P43), + MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P43), }; return lms8001_spi_post(out, lms_init, SIZEOF_ARRAY(lms_init)); } @@ -348,12 +351,13 @@ int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lms8001_state_ uint32_t lms_init[] = { MAKE_LMS8001_CHIPCONFIG_SPIConfig(1, 1, 1, 1, 1, 1, 1), - MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, 1, LMS_LDO_1P25), - MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, 1, LMS_LDO_1P25), - MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, 1, LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, 1, LMS_LDO_1P43), + MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, 1, LMS_LDO_1P43), + MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, 1, LMS_LDO_1P43), MAKE_LMS8001_PLL_CONFIGURATION_PLL_VREG(1, 0, 1, 1, 32), MAKE_LMS8001_PLL_CONFIGURATION_PLL_CFG_XBUF(1, 0, 1), + //MAKE_LMS8001_PLL_CONFIGURATION_PLL_CFG_XBUF(0, 0, 1), //////////////////////////////////////////////////////////////////////////////////// MAKE_LMS8001_PLL_PROFILE_0_PLL_ENABLE_n(1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1), From 1e65dd8f4bdd54cdb58c6d4afa21f6ba4edc3958 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 13 Oct 2025 22:26:18 +0400 Subject: [PATCH 196/397] ssdr: full support of MPW2015/2024 --- src/lib/device/m2_dsdr/dsdr_hiper.c | 8 +-- src/lib/device/m2_dsdr/dsdr_hiper.h | 2 +- src/lib/device/m2_dsdr/m2_dsdr.c | 6 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 6 +- src/lib/hw/lms8001/lms8001.c | 89 +++++++++++++++++------------ src/lib/hw/lms8001/lms8001.h | 10 +++- 6 files changed, 76 insertions(+), 45 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 341631c0..4285b073 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -719,7 +719,7 @@ int dsdr_hiper_sens2temp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue -static int dsdr_hiper_initialize_lms8(dsdr_hiper_fe_t* dfe, unsigned addr, lms8001_state_t* obj) +static int dsdr_hiper_initialize_lms8(dsdr_hiper_fe_t* dfe, unsigned addr, unsigned stepping, lms8001_state_t* obj) { uint32_t chipver = ~0; int res = 0; @@ -727,13 +727,13 @@ static int dsdr_hiper_initialize_lms8(dsdr_hiper_fe_t* dfe, unsigned addr, lms80 res = res ? res : lowlevel_spi_tr32(dfe->dev, dfe->subdev, addr, 0x000f0000, &chipver); USDR_LOG("HIPR", USDR_LOG_WARNING, "LMS8001.%08x: version %08x\n", addr, chipver); - res = res ? res : lms8001_create(dfe->dev, dfe->subdev, addr, obj); + res = res ? res : lms8001_create(dfe->dev, dfe->subdev, addr, stepping, obj); res = res ? res : lms8001_temp_start(obj); return res; } #include -int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, dsdr_hiper_fe_t* dfe) +int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, dsdr_hiper_fe_t* dfe) { int res = 0; device_t* base = lowlevel_get_device(dev); @@ -786,7 +786,7 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, dsdr_hiper_fe_t* df // LMS8 for (unsigned k = 0; k < 6; k++) { uint32_t cfg = MAKE_SPIEXT_LSOPADR(MAKE_SPIEXT_CFG(LMS8_BCNTZ, k, LMS8_DIV), 0, spix_num); - res = res ? res : dsdr_hiper_initialize_lms8(dfe, cfg, &dfe->lms8[k]); + res = res ? res : dsdr_hiper_initialize_lms8(dfe, cfg, lms8_chip, &dfe->lms8[k]); } // ADF4002 (MUX -> GND -> DVDD readback as a sanity check) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.h b/src/lib/device/m2_dsdr/dsdr_hiper.h index 040863f6..837ccce7 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.h +++ b/src/lib/device/m2_dsdr/dsdr_hiper.h @@ -101,7 +101,7 @@ struct dsdr_hiper_fe { typedef struct dsdr_hiper_fe dsdr_hiper_fe_t; -int dsdr_hiper_fe_create(lldev_t dev, unsigned spix_num, dsdr_hiper_fe_t* dfe); +int dsdr_hiper_fe_create(lldev_t dev, unsigned spix_num, unsigned lms8_chip, dsdr_hiper_fe_t* dfe); int dsdr_hiper_fe_destroy(dsdr_hiper_fe_t* dfe); int dsdr_hiper_fe_rx_freq_set(dsdr_hiper_fe_t* def, unsigned chno, uint64_t freq, uint64_t* ncotune, bool *p_swap_rxiq); diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 79d0a21a..b643cf94 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1322,6 +1322,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** int res = 0; uint32_t hwid, usr2, pg, los, devid, jesdv; unsigned afeType = 0; + unsigned lms8_step = LMS8_MPW2015; d->subdev = 0; d->hw_mask_fb = 0; @@ -1654,7 +1655,10 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } if (d->type == DSDR_PCIE_HIPER_R0) { - res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, &d->hiper); + if (getenv("LMS8_MPW2024")) { + lms8_step = LMS8_MPW2024; + } + res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, lms8_step, &d->hiper); } // check state diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 35dde772..9fc28b8e 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1567,6 +1567,10 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_CLK_CFG, 1); if (hwid == SSDR_DEV) { uint32_t chipver = ~0; + unsigned lms8_step = LMS8_MPW2024; + if (getenv("LMS8_MPW2015")) { + lms8_step = LMS8_MPW2015; + } // Check LMS8 presence res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x0); @@ -1585,7 +1589,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x000f0000, &chipver); USDR_LOG("XDEV", USDR_LOG_INFO, "LMS8001 version %08x\n", chipver); - res = res ? res : lms8001_create(dev, d->base.lmsstate.subdev, 0, &d->lms8); + res = res ? res : lms8001_create(dev, d->base.lmsstate.subdev, 0, lms8_step, &d->lms8); res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x80); //res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x00); diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index 92fb0716..ffe06450 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -9,26 +9,20 @@ #include enum lms8_vco_params { - LMS8_VCO1_MIN = 4100000000ULL, // 4400000000ULL, - LMS8_VCO1_MAX = 6600000000ULL, + LMS8_VCO1_MIN_MPW2015 = 4150000000ULL, + LMS8_VCO1_MIN_MPW2024 = 4550000000ULL, - LMS8_VCO2_MIN = 6200000000ULL, - LMS8_VCO2_MAX = 8300000000ULL, - - LMS8_VCO3_MIN = 7700000000ULL, - LMS8_VCO3_MAX = 10400000000ULL, - - // Safe values for LO range - LMS8_MIN_NIQ = 520000000U, - //LMS8_MAX_NIQ = 9110000000ULL, - LMS8_MAX_NIQ = 9400000000ULL, - LMS8_MIN_IQ = LMS8_MIN_NIQ / 2, - LMS8_MAX_IQ = LMS8_MAX_NIQ / 2, + LMS8_VCO3_MAX_MPW2015 = 9150000000ULL, + LMS8_VCO3_MAX_MPW2024 = 9650000000ULL, }; enum { LMS_LDO_1P25 = 101, - LMS_LDO_1P43 = 147, + + LMS_LDO_VDD_PLL_CP = 159, + LMS_LDO_VDD_PLL_DIV = 179, + LMS_LDO_VDD_PLL_CLKBUF = 215, + LMS_LDO_VCO_REG = 207, }; @@ -70,20 +64,29 @@ static int lms8001_spi_get(lms8001_state_t* obj, uint16_t addr, uint16_t* out) -static int _lms8001_check_lo_range(uint64_t flo, bool geniq) +static int _lms8001_check_lo_range(lms8001_state_t* obj, uint64_t flo, bool geniq) { + uint64_t LMS8_VCO1_MIN = (obj->stepping == LMS8_MPW2024) ? LMS8_VCO1_MIN_MPW2024 : LMS8_VCO1_MIN_MPW2015; + uint64_t LMS8_VCO3_MAX = (obj->stepping == LMS8_MPW2024) ? LMS8_VCO3_MAX_MPW2024 : LMS8_VCO3_MAX_MPW2015; + uint64_t LMS8_MIN_NIQ = LMS8_VCO1_MIN / 8; + uint64_t LMS8_MIN_IQ = LMS8_MIN_NIQ / 2; + uint64_t LMS8_MAX_IQ = LMS8_VCO3_MAX / 2; + if (geniq && (!((flo >= LMS8_MIN_IQ) && (flo <= LMS8_MAX_IQ)))) { - USDR_LOG("8001", USDR_LOG_ERROR, "LO frequency should be between 260 MHz and 4.55 GHz when GenIQ is selected.\n"); + USDR_LOG("8001", USDR_LOG_ERROR, "LO frequency should be between %d MHz and %d MHz when GenIQ is selected, requested %d Mhz\n", + (unsigned)(LMS8_MIN_IQ / 1000000), (unsigned)(LMS8_MAX_IQ / 1000000), (unsigned)(flo / 1000000)); return -EINVAL; } - if (!geniq && (!((flo >= LMS8_MIN_IQ) && (flo <= LMS8_MAX_NIQ)))) { - USDR_LOG("8001", USDR_LOG_ERROR, "LO frequency should be between 260 MHz and 9.11 GHz.\n"); + if (!geniq && (!((flo >= LMS8_MIN_IQ) && (flo <= LMS8_VCO3_MAX)))) { + USDR_LOG("8001", USDR_LOG_ERROR, "LO frequency should be between %d MHz and %d MHz, requested %d Mhz\n", + (unsigned)(LMS8_MIN_IQ / 1000000), (unsigned)(LMS8_VCO3_MAX / 1000000), (unsigned)(flo / 1000000)); return -EINVAL; } if (!geniq && (((flo >= LMS8_MIN_IQ) && (flo <= LMS8_MIN_NIQ)))) { - USDR_LOG("8001", USDR_LOG_ERROR, "LO frequency values between 260 MHz and 520 MHz can only be generated when IQ=True.\n"); + USDR_LOG("8001", USDR_LOG_ERROR, "LO frequency values between %d MHz and %d MHz can only be generated when IQ=True, requested %d Mhz\n", + (unsigned)(LMS8_MIN_IQ / 1000000), (unsigned)(LMS8_MIN_NIQ / 1000000), (unsigned)(flo / 1000000)); return -EINVAL; } @@ -96,8 +99,10 @@ struct lms8001_vco_settings { }; typedef struct lms8001_vco_settings lms8001_vco_settings_t; -static int _lms8001_calc_vco(uint64_t outfreq, lms8001_vco_settings_t* ro) +static int _lms8001_calc_vco(lms8001_state_t* obj, uint64_t outfreq, lms8001_vco_settings_t* ro) { + uint64_t LMS8_VCO1_MIN = (obj->stepping == LMS8_MPW2024) ? LMS8_VCO1_MIN_MPW2024 : LMS8_VCO1_MIN_MPW2015; + uint64_t LMS8_VCO3_MAX = (obj->stepping == LMS8_MPW2024) ? LMS8_VCO3_MAX_MPW2024 : LMS8_VCO3_MAX_MPW2015; lms8001_vco_settings_t r; r.divi = 0; @@ -150,12 +155,10 @@ int lms8001_tune(lms8001_state_t* state, unsigned fref, uint64_t out) { lms8001_vco_settings_t st; uint16_t rb; - int res = _lms8001_calc_vco(out, &st); + int res = _lms8001_calc_vco(state, out, &st); if (res) return res; - // uint64_t nint = st.fvco / fref; - // uint64_t frac = (st.fvco - nint * fref) * ((uint64_t)1 << 20) / fref; lms8001_pll_settings_t pll = _lms8001_calc_pll(st.fvco, fref, 0); if (pll.nint > 1023) { @@ -335,14 +338,14 @@ int lms8001b_hlmix_loss_set(lms8001_state_t* state, unsigned chan, unsigned loss int lms8001_core_enable(lms8001_state_t* out, bool en) { uint32_t lms_init[] = { - MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P43), - MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P43), - MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, en ? 1 : 0, LMS_LDO_1P43), + MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, en ? 1 : 0, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CLKBUF : LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, en ? 1 : 0, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_DIV : LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, en ? 1 : 0, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CP : LMS_LDO_1P25), }; return lms8001_spi_post(out, lms_init, SIZEOF_ARRAY(lms_init)); } -int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lms8001_state_t *out) +int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int stepping, lms8001_state_t *out) { int res; memset(&out->pll, 0, sizeof(out->pll)); @@ -351,11 +354,12 @@ int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lms8001_state_ uint32_t lms_init[] = { MAKE_LMS8001_CHIPCONFIG_SPIConfig(1, 1, 1, 1, 1, 1, 1), - MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, 1, LMS_LDO_1P43), - MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, 1, LMS_LDO_1P43), - MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, 1, LMS_LDO_1P43), + MAKE_LMS8001_BIASLDOCONFIG_BiasConfig(1, 0, 9, 0, 0, 0, 0, 0), + MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, 1, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CLKBUF : LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, 1, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_DIV : LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, 1, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CP : LMS_LDO_1P25), - MAKE_LMS8001_PLL_CONFIGURATION_PLL_VREG(1, 0, 1, 1, 32), + MAKE_LMS8001_PLL_CONFIGURATION_PLL_VREG(1, 0, 1, 1, 205), MAKE_LMS8001_PLL_CONFIGURATION_PLL_CFG_XBUF(1, 0, 1), //MAKE_LMS8001_PLL_CONFIGURATION_PLL_CFG_XBUF(0, 0, 1), @@ -363,6 +367,11 @@ int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lms8001_state_ MAKE_LMS8001_PLL_PROFILE_0_PLL_ENABLE_n(1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1), }; + if (stepping > LMS8_MPW2024) + return -EINVAL; + + out->stepping = stepping; + out->pll.PLL_VREG = lms_init[4]; out->pll.PLL_CFG_XBUF = lms_init[5]; @@ -432,8 +441,9 @@ static void _lms80001_tune_settings_def(lms80001_tune_settings_t* s) { s->freq_init = 0; s->freq_settling_N = 4; s->vtune_wait_N = 128; - s->vco_sel_freq_max = 250; - s->vco_sel_freq_min = 5; + s->vco_sel_freq_max = 255; + s->vco_sel_freq_min = 0; + } static uint32_t _mk_pav(lms8001_state_t* m, unsigned addr, uint16_t val) @@ -547,10 +557,12 @@ static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32 res = res ? res : lms8001_spi_post(m, lms_init, SIZEOF_ARRAY(lms_init)); } else { - USDR_LOG("8001", USDR_LOG_WARNING, "WARNING: Requested frequency fvco = %.3f Mhz could not be tuned.\n", fvco / 1.0e6); + USDR_LOG("8001", USDR_LOG_WARNING, "WARNING: Requested frequency fvco = %.3f Mhz could not be tuned FCAL/VCO/FREQ: %d/%d/%d.\n", + fvco / 1.0e6, FCAL_start, VCO_sel_final_val, freq_sel_final_val); res = -ERANGE; } + USDR_LOG("8001", USDR_LOG_NOTE, "VCO Calibration finished, VCO:%d CAP:%d\n", VCO_final, freq_final); if (actual) *actual = actual_freq; return res; @@ -997,8 +1009,8 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, double fc = loopBW / 1.65; // Check LO range (that was inside setLOFREQ) - res = (res) ? res : _lms8001_check_lo_range(flo, iq_gen); - res = (res) ? res : _lms8001_calc_vco(iq_gen ? (flo << 1) : flo, &pll_s); + res = (res) ? res : _lms8001_check_lo_range(m, flo, iq_gen); + res = (res) ? res : _lms8001_calc_vco(m, iq_gen ? (flo << 1) : flo, &pll_s); if (res) { return res; } @@ -1031,6 +1043,8 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, lms80001_tune_settings_t vco_settings; _lms80001_tune_settings_def(&vco_settings); + USDR_LOG("8001", USDR_LOG_NOTE, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); + // Step 1 - Tune PLL to generate F_LO frequency at LODIST outputs that should be manualy enabled // outside this method res = _lms8001_vco_tune(m, fvco, fref, tune_flags, &vco_settings, &actual_vco); @@ -1076,6 +1090,7 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, int lms8001_smart_tune(lms8001_state_t* m, unsigned tune_flags, uint64_t flo, int fref, int loopbw, float phasemargin, float bwef, int flock_N) { int res; + uint64_t LMS8_MIN_NIQ = ((m->stepping == LMS8_MPW2024) ? LMS8_VCO1_MIN_MPW2024 : LMS8_VCO1_MIN_MPW2015) / 8; // Set IQ gen for freq < 520 Mhz if (flo < LMS8_MIN_NIQ) { diff --git a/src/lib/hw/lms8001/lms8001.h b/src/lib/hw/lms8001/lms8001.h index beda9f58..af657b07 100644 --- a/src/lib/hw/lms8001/lms8001.h +++ b/src/lib/hw/lms8001/lms8001.h @@ -60,11 +60,19 @@ enum { LMS8001_PROFILES = 8, }; +enum lms8_stepping { + LMS8_MPW2015 = 0, + LMS8_MPW2024 = 1, +}; + struct lms8001_state { lldev_t dev; unsigned subdev; unsigned lsaddr; + // Chip stepping + unsigned stepping; + // Enabled channel masks unsigned chan_mask; @@ -78,7 +86,7 @@ struct lms8001_state { typedef struct lms8001_state lms8001_state_t; -int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lms8001_state_t *out); +int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned stepping, lms8001_state_t *out); int lms8001_destroy(lms8001_state_t* m); int lms8001_core_enable(lms8001_state_t* state, bool enable); From d7d8c761318865fa8f8a32b1fd512d2f7fde58b4 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 13 Oct 2025 23:32:01 +0400 Subject: [PATCH 197/397] ssdr: update pll settings --- src/lib/hw/lms8001/lms8001.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index ffe06450..4ac8e5c1 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -433,8 +433,8 @@ struct lms80001_tune_settings { }; typedef struct lms80001_tune_settings lms80001_tune_settings_t; -static void _lms80001_tune_settings_def(lms80001_tune_settings_t* s) { - s->vtune_vct = 1; +static void _lms80001_tune_settings_def(lms8001_state_t* m, lms80001_tune_settings_t* s) { + s->vtune_vct = m->stepping == LMS8_MPW2024 ? 2 : 1; s->vco_sel_force = 0; s->vco_sel_init = 2; s->freq_init_pos = 7; @@ -607,7 +607,7 @@ static int _lms8001_center_vtune(lms8001_state_t* m, uint64_t fvco, int fref, ui int res; lms8001_pll_state_t* curr = &m->pll_profiles[m->act_profile]; lms80001_tune_settings_t vco_settings; - _lms80001_tune_settings_def(&vco_settings); + _lms80001_tune_settings_def(m, &vco_settings); vco_settings.vtune_vct = 1; vco_settings.vco_sel_force = 1; vco_settings.freq_init_pos = 4; @@ -1041,7 +1041,7 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, // Calculate actual VCO frequency uint64_t fvco = (iq_gen) ? (flo << (pll_s.divi + 1)) : (flo << pll_s.divi); lms80001_tune_settings_t vco_settings; - _lms80001_tune_settings_def(&vco_settings); + _lms80001_tune_settings_def(m, &vco_settings); USDR_LOG("8001", USDR_LOG_NOTE, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); From 072d4fab37a3739d6705c4bc5c76be40ae24ac32 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 14 Oct 2025 03:03:38 +0400 Subject: [PATCH 198/397] dsdr: add afe7903 configuration --- src/lib/device/m2_dsdr/m2_dsdr.c | 106 ++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 16 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index b643cf94..5b725fff 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -260,11 +260,11 @@ const usdr_dev_param_constant_t s_params_m2_dsdr_rev000[] = { { "/ll/sync/0/base", M2PCI_REG_WR_SYNC_CTRL}, { "/ll/sdr/0/rfic/0", (uintptr_t)"afe79xx" }, - { "/ll/sdr/max_hw_rx_chans", 4 }, - { "/ll/sdr/max_hw_tx_chans", 4 }, + // { "/ll/sdr/max_hw_rx_chans", 4 }, + // { "/ll/sdr/max_hw_tx_chans", 4 }, - { "/ll/sdr/max_sw_rx_chans", 4 }, - { "/ll/sdr/max_sw_tx_chans", 4 }, + // { "/ll/sdr/max_sw_rx_chans", 4 }, + // { "/ll/sdr/max_sw_tx_chans", 4 }, }; static int dev_m2_dsdr_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -405,8 +405,16 @@ static int device_path_to_chmsk(const char* full_path, const char* basename, chm } #endif +static int dev_m2_dsdr_numchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); + static const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { + { "/ll/sdr/max_hw_rx_chans", { NULL, dev_m2_dsdr_numchans_get } }, + { "/ll/sdr/max_hw_tx_chans", { NULL, dev_m2_dsdr_numchans_get } }, + + { "/ll/sdr/max_sw_rx_chans", { NULL, dev_m2_dsdr_numchans_get } }, + { "/ll/sdr/max_sw_tx_chans", { NULL, dev_m2_dsdr_numchans_get } }, + { "/dm/rate/master", { dev_m2_dsdr_rate_set, NULL }}, { "/dm/rate/rxtxadcdac", { dev_m2_dsdr_rate_m_set, NULL }}, @@ -550,6 +558,10 @@ struct dev_m2_dsdr { afe79xx_state_t st; dsdr_hiper_fe_t hiper; + uint32_t cfg_afe_type; + uint32_t cfg_rx_lanemap; + uint32_t cfg_tx_lanemap; + uint32_t debug_lmk05318_last; const char* afecongiguration; @@ -565,6 +577,9 @@ struct dev_m2_dsdr { unsigned hw_fpga_jesd_rx_en; // Physical lanes enabled bitmask 0: X0Y4, 1: X0Y5, ... 3: X0Y7 unsigned hw_fpga_jesd_tx_en; // Physical lanes enabled bitmask 0: X0Y4, 1: X0Y5, ... 3: X0Y7 + uint8_t hw_rxch_route[8]; + uint8_t hw_txch_route[8]; + uint32_t adc_rate; unsigned rxbb_rate; unsigned rxbb_decim; @@ -619,6 +634,17 @@ bool dev_m2_dsdr_has_hiper(dev_m2_dsdr_t* d) } +int dev_m2_dsdr_numchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; + if (d->cfg_afe_type == 7903) + *ovalue = 2; + else + *ovalue = 4; + + return 0; +} + int dev_m2_dsdr_rx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; @@ -709,7 +735,7 @@ static int dsdr_iterate_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val, c for (unsigned i = 0; i < DSDR_CHANS_HW; i++) { if (chmsk_is_set(&hw_msk, i)) { - ph.full_path[1] = i; + ph.full_path[1] = rxchans ? d->hw_rxch_route[i] :d->hw_txch_route[i]; // i; res = res ? res : obj->ops.si64(&ph, val); } } @@ -724,7 +750,7 @@ static int dsdr_iterate_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val, c continue; } - ph.full_path[1] = i; + ph.full_path[1] = rxchans ? d->hw_rxch_route[i] :d->hw_txch_route[i]; //i; res = res ? res : obj->ops.si64(&ph, val); } else { // One logical TX channel can be mapped to many physical @@ -733,7 +759,7 @@ static int dsdr_iterate_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val, c if (d->tx_hw_to_logic[j] != i) continue; - ph.full_path[1] = i; + ph.full_path[1] = rxchans ? d->hw_rxch_route[i] :d->hw_txch_route[i]; //i; res = res ? res : obj->ops.si64(&ph, val); } } @@ -1256,11 +1282,17 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_BUFFER_RELDLY_0, 0); // 0 means autodetect and adjust - res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_0, 0x10); - res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_1, 0x32); + // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_0, 0x10); + // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_1, 0x32); + + // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_0, 0x10); + // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_1, 0x32); - res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_0, 0x10); - res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_1, 0x32); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_0, dd->cfg_rx_lanemap & 0xff); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_1, (dd->cfg_rx_lanemap >> 8) & 0xff); + + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_0, dd->cfg_tx_lanemap & 0xff); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_1, (dd->cfg_tx_lanemap >> 8) & 0xff); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_POLARITY, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_POLARITY, 0x0); @@ -1288,6 +1320,8 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) return -EIO; } + usleep(10000); + // TODO wait for PLL to lock.. res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_SYNC_RESET, 0); @@ -1340,14 +1374,16 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0x0); + res = res ? res : dev_gpo_set(dev, IGPO_RX_CHEN, 0x0); + res = res ? res : dev_gpo_set(dev, IGPO_TX_CHEN, 0x0); // TODO check for AFE7903 if (getenv("DSDR_AFE7903")) { d->hw_mask_rx = 0x5; // RX_3 RX_1 d->hw_mask_tx = 0xA; // TX_4 TX_2 - d->hw_fpga_jesd_rx_en = 0xc; - d->hw_fpga_jesd_tx_en = 0xc; + // d->hw_fpga_jesd_rx_en = 0xc; + // d->hw_fpga_jesd_tx_en = 0xc; } devid = (hwid >> 16) & 0xff; @@ -1374,6 +1410,14 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->type = DSDR_M2_R0; } + d->cfg_rx_lanemap = 0x76543210; + d->cfg_tx_lanemap = 0x76543210; + + for (unsigned h = 0; h < 8; h++) { + d->hw_rxch_route[h] = h; + d->hw_rxch_route[h] = h; + } + afeType = 7901; switch (jesdv) { case DSDR_JESD204B_810_245: @@ -1389,13 +1433,34 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** break; case DSDR_JESD204C_6664_491: + d->cfg_rx_lanemap = 0x75643210; + d->cfg_tx_lanemap = 0x75643210; + d->max_rate = 520e6; d->dac_rate = d->adc_rate = 491520000; d->afecongiguration = "Afe79xxPg1_6664_491.txt"; + if (d->hw_mask_rx == 0x5 && d->hw_mask_tx == 0xA) { - d->afecongiguration = "Afe79xxPg1_dsdr_491_7903.txt"; + // RX C/A + // TX D/B + // d->afecongiguration = "Afe79xxPg1_dsdr_491_7903.txt"; afeType = 7903; + + d->cfg_rx_lanemap = 0x75643120; + d->cfg_tx_lanemap = 0x75642031; + //d->hw_fpga_jesd_rx_en = 0x3; + //d->hw_fpga_jesd_tx_en = 0xc; + + d->hw_rxch_route[0] = 0; + d->hw_rxch_route[1] = 2; + d->hw_rxch_route[2] = 1; + d->hw_rxch_route[3] = 3; + d->hw_txch_route[0] = 1; + d->hw_txch_route[1] = 3; + d->hw_txch_route[2] = 0; + d->hw_txch_route[3] = 2; } + if (getenv("DSDR_M2_7950")) { // AFE7950 d->afecongiguration = "Afe79xxPg1_600_1.txt"; @@ -1408,6 +1473,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return -EIO; } + d->cfg_afe_type = afeType; d->jesdv = jesdv; USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s\n", d->afecongiguration); USDR_LOG("XDEV", USDR_LOG_WARNING, "AFE type JESD204%c CH_TX=%02x CH_RX=%02x\n", (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx); @@ -1577,7 +1643,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(10000); //res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x3); // Enable VIOSYS, hold RESET res = res ? res : lp875484_init(dev, d->subdev, I2C_AFE_PMIC); - res = res ? res : lp875484_set_vout(dev, d->subdev, I2C_AFE_PMIC, 900); + res = res ? res : lp875484_set_vout(dev, d->subdev, I2C_AFE_PMIC, 930); // Recomended 925mV res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x3); // Enable VIOSYS, release RESET if (res) return res; @@ -1598,7 +1664,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return -EIO; } - usleep(10000); + usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x7); // Enable DCDC 1.2V; // We don't have PG_1v2 routed in this rev @@ -1622,6 +1688,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return -EIO; } + usleep(100000); + res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x1f); if (res) return res; @@ -1632,6 +1700,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x0); + usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x1); usleep(100000); @@ -1661,6 +1730,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, lms8_step, &d->hiper); } + usleep(100000); + // check state res = res ? res : dev_m2_dsdr_afe_health_get(udev, NULL, NULL); USDR_LOG("DSDR", USDR_LOG_ERROR, "Initializing AFE done\n"); @@ -1914,6 +1985,8 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char // TODO: set actual antenna mask res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0xf); + //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0x0); + *out_handle = d->rx; } else if (strstr(sid, "tx") != NULL) { if (d->tx) { @@ -1981,6 +2054,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char // TODO: set actual antenna mask res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0xf); + //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0x0); *out_handle = d->tx; } From eeacb661d38f88cd2bf30e09d7f8adbfdf92a0c5 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 15 Oct 2025 01:17:20 +0400 Subject: [PATCH 199/397] fix typo --- src/lib/device/m2_dsdr/m2_dsdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 5b725fff..7f8bfe0f 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1415,7 +1415,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** for (unsigned h = 0; h < 8; h++) { d->hw_rxch_route[h] = h; - d->hw_rxch_route[h] = h; + d->hw_txch_route[h] = h; } afeType = 7901; From a7eb5932113103a36dac36ad89fe80b5faf5fb70 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 15 Oct 2025 01:17:39 +0400 Subject: [PATCH 200/397] fix typo --- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 2349e630..8508d9fc 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -712,6 +712,7 @@ static int initialize_stream_rx_32(device_t* device, // Wire format not supported, need transform function // suppose i16 but maintain complex / real format sc.sfmt = (*pfmt.host_fmt == 'C' || *pfmt.host_fmt == 'c') ? "ci16" : "i16"; + res = 0; } //Find transform function @@ -931,6 +932,7 @@ static int initialize_stream_tx_32(device_t* device, // Wire format not supported, need transform function // suppose i16 but maintain complex / real format sc.sfmt = (*pfmt.host_fmt == 'C' || *pfmt.host_fmt == 'c') ? "ci16" : "i16"; + res = 0; } //Find transform function From 5ab5115e4d3e2256d4e2924af4742a5bdebfb347 Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Wed, 15 Oct 2025 23:28:05 +0400 Subject: [PATCH 201/397] New yamls for usdr_registers. --- src/dmonitor/yamls/ext_fe_ch4_400_7200_e.yaml | 1 + src/dmonitor/yamls/ext_fe_ch4_400_7200_usr.yaml | 1 + 2 files changed, 2 insertions(+) create mode 120000 src/dmonitor/yamls/ext_fe_ch4_400_7200_e.yaml create mode 120000 src/dmonitor/yamls/ext_fe_ch4_400_7200_usr.yaml diff --git a/src/dmonitor/yamls/ext_fe_ch4_400_7200_e.yaml b/src/dmonitor/yamls/ext_fe_ch4_400_7200_e.yaml new file mode 120000 index 00000000..8e597490 --- /dev/null +++ b/src/dmonitor/yamls/ext_fe_ch4_400_7200_e.yaml @@ -0,0 +1 @@ +../../lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml \ No newline at end of file diff --git a/src/dmonitor/yamls/ext_fe_ch4_400_7200_usr.yaml b/src/dmonitor/yamls/ext_fe_ch4_400_7200_usr.yaml new file mode 120000 index 00000000..107176ae --- /dev/null +++ b/src/dmonitor/yamls/ext_fe_ch4_400_7200_usr.yaml @@ -0,0 +1 @@ +../../lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml \ No newline at end of file From 77f33060f32b790be7b06119a5360379553f3c60 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 21 Oct 2025 01:45:51 +0400 Subject: [PATCH 202/397] Add initial support of USDR_PRO --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 3 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 81 ++++++++++++++++++++--------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 4 +- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index d8b15117..9f50f649 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -1428,8 +1428,9 @@ int usdr_device_m2_lm7_1_create(lldev_t dev, device_id_t devid) //if (res) { // goto failed_free; //} + unsigned did = ((hwid >> 16) & 0xff); - if ((res == 0) && ((hwid >> 16) & 0xff) == SSDR_DEV) { + if ((res == 0) && (did == SSDR_DEV || did == SSDRPRO_DEV)) { res = vfs_add_const_i64_vec(&d->base.rootfs, s_params_m2_lm7_1_rev_advanced, SIZEOF_ARRAY(s_params_m2_lm7_1_rev_advanced)); diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 9fc28b8e..d4e34868 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -666,6 +666,14 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) g_clk_reduce = 0; + // Fixup for SSDR_PRO + if (d->ssdr_pro) { + // RX SISO DDR + res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, + d->siso_sdr_active_rx ? (1u << 9) : 0); + return res; + } + if (d->mmcm_tx) { // Boost IO voltage for stable high speed link if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && (d->s_rxrate > 85e6 || d->s_txrate > 85e6)) { @@ -1035,12 +1043,13 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, } } #endif - + if (!d->ssdr_pro) { // Switch to clock meas res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); + } } - if (txrate) { + if (txrate || d->ssdr_pro) { res = res ? res : _xsdr_calibrate_lml(d); } @@ -1063,15 +1072,18 @@ int xsdr_clk_debug_info(xsdr_dev_t *d) if (res) return res; + if (!d->ssdr_pro) { + for (unsigned h = 0; h < 13; h++) { + unsigned p = ((h & 0x3) << 2) | (h >> 2); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); - for (unsigned h = 0; h < 13; h++) { - unsigned p = ((h & 0x3) << 2) | (h >> 2); - res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); - res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); - res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); - res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_LFSRCHK, p, 0); - - res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &dump[h]); + res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &dump[h]); + } + } else { + memset(dump, 0, sizeof(dump)); } @@ -1505,7 +1517,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) strncpy(d->base.cfg_auto_tx[1].name0, "H", sizeof(d->base.cfg_auto_tx[1].name0)); strncpy(d->base.cfg_auto_tx[1].name1, "B2", sizeof(d->base.cfg_auto_tx[1].name1)); - if (hwid == SSDR_DEV) { + if (hwid == SSDR_DEV || hwid == SSDRPRO_DEV) { // QPC8019Q 0: RFC1 -- HF; 1: RFC2 -- LF d->base.cfg_auto_rx[0].stop_freq = 3000e6; @@ -1528,28 +1540,38 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) if (res) return res; - if (rev == 0xe001) { + bool good_pmic = (hwid == SSDRPRO_DEV) ? (rev == 0xe302) : (rev == 0xe001); + if (good_pmic) { d->pmic_ch145_valid = true; } - USDR_LOG("XDEV", (rev == 0xe001) ? USDR_LOG_INFO : USDR_LOG_ERROR, "PMIC_RFIC ver %04x (%d)\n", + USDR_LOG("XDEV", (good_pmic) ? USDR_LOG_INFO : USDR_LOG_ERROR, "PMIC_RFIC ver %04x (%d)\n", rev, d->pmic_ch145_valid); - if (hwid == SSDR_DEV) { + if (hwid == SSDRPRO_DEV) { + res = lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 3, 2040); + } if (hwid == SSDR_DEV) { res = lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 1, 2040); } else { // TODO check if we need this rail res = lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 1, 1480); } - // LMS Vcore boost to 1.25V - res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 2, 1280); - res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 3, 1850); + if (hwid == SSDRPRO_DEV) { + // TODO adjust VCORE to 0.88V + // res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 0, 880); + res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 1, 1280); + res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 2, 1850); + } else { + // LMS Vcore boost to 1.25V + res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 2, 1280); + res = res ? res : lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 3, 1850); + } - res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 0, 1, 1); //1v0 -- less affected - res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 1, 1, 1); //2v5 -- less affected - res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 2, 1, 1); //1v2 - res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 3, 1, 1); //1v8 + res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 0, 1, 1); //1v0 | 0v9 -- less affected + res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 1, 1, 1); //2v5 | 1v2 -- less affected + res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 2, 1, 1); //1v2 | 1v8 + res = res ? res : lp8758_vout_ctrl(dev, subdev, I2C_BUS_LP8758_FPGA, 3, 1, 1); //1v8 | 2v7 // Wait for power to settle for (unsigned i = 0; !res && !pg && (i < 100); i++) { @@ -1565,7 +1587,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) d->lms8_alive = false; // Enable internal clocking by default res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_CLK_CFG, 1); - if (hwid == SSDR_DEV) { + if (hwid == SSDR_DEV || hwid == SSDRPRO_DEV) { uint32_t chipver = ~0; unsigned lms8_step = LMS8_MPW2024; if (getenv("LMS8_MPW2015")) { @@ -1604,7 +1626,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) } } - if (!d->lms8_alive) { + if (!getenv("USDR_BARE_DEV") && (!d->lms8_alive)) { USDR_LOG("XDEV", USDR_LOG_ERROR, "LMS8001 not detected, check the board!\n"); return -EFAULT; } @@ -1848,7 +1870,8 @@ int _xsdr_pwren_revo(xsdr_dev_t *d, bool on) int xsdr_set_lms125vdd(xsdr_dev_t *d, unsigned vdd_mv) { if (d->new_rev && !d->ssdr) { - return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 2, vdd_mv); + return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, + d->ssdr_pro ? 1 : 2, vdd_mv); } return -EINVAL; @@ -1872,7 +1895,8 @@ int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) vio_mv = 1600; USDR_LOG("XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); - return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, vio_mv); + return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, + d->ssdr_pro ? 3 : 1, vio_mv); } int xsdr_pwren(xsdr_dev_t *d, bool on) @@ -1947,6 +1971,7 @@ int xsdr_init(xsdr_dev_t *d) d->cfg_srate_siso_rx = 0; d->cfg_srate_siso_tx = 0; d->dpump = false; + d->ssdr_pro = false; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); if (res) { @@ -1957,6 +1982,7 @@ int xsdr_init(xsdr_dev_t *d) case XSDR_DEV: d->new_rev = true; d->ssdr = false; break; case XTRX_DEV: d->new_rev = false; d->ssdr = false; break; case SSDR_DEV: d->new_rev = true; d->ssdr = true; break; + case SSDRPRO_DEV: d->new_rev = true; d->ssdr = true; d->ssdr_pro = true; break; default: USDR_LOG("XDEV", USDR_LOG_ERROR, "unsupported hwcfg_devid=%02x\n", hwcfg_devid); @@ -2001,7 +2027,10 @@ int xsdr_dtor(xsdr_dev_t *d) res = (res) ? res : _xsdr_mmcm_pd(d); - if (d->ssdr) { + if (d->ssdr_pro) { + res = res ? res : lp8758_vout_set(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, 900); + res = res ? res : lp8758_vout_ctrl(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, 0, 1); + } if (d->ssdr) { res = res ? res : lp8758_vout_set(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, 900); res = res ? res : lp8758_vout_ctrl(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, 0, 1); } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 3ebf4bb2..55ffcd75 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -16,7 +16,8 @@ #define RFIC_CHANS 2 enum xsdr_devices { - SSDR2_DEV = 0x32, + SSDRPRO_DEV = 0x33, + //SSDR2_DEV = 0x32, SSDR_DEV = 0x31, XSDR_DEV = 0x30, XTRX_DEV = 0x2e, @@ -68,6 +69,7 @@ struct xsdr_dev bool pwr_en; bool new_rev; bool ssdr; + bool ssdr_pro; bool lms8_alive; bool dpump; //Dual pump data From cb6150ffc6affd9135496db05926d68c5411968c Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 21 Oct 2025 13:36:24 +0400 Subject: [PATCH 203/397] ssdr_pro: add device id in PCIe driver --- src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index 05a838bf..22639668 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -1757,6 +1757,8 @@ static struct pci_device_id usdr_pci_table[] = { .driver_data = 3 }, { PCI_DEVICE(0x10EE, 0x7049), .driver_data = 4 }, + { PCI_DEVICE(0x10EE, 0x9049), + .driver_data = 4 }, { PCI_DEVICE(0x10EE, 0x9034), .driver_data = 5 }, { PCI_DEVICE(0x10EE, 0x9044), From b898f5c8f3382227ba8f40a62c4e65615f513819 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 24 Oct 2025 02:35:27 +0400 Subject: [PATCH 204/397] hiper_r2: initial support --- src/lib/device/m2_dsdr/dsdr_hiper.c | 243 ++++++++++++++++++++---- src/lib/device/m2_dsdr/dsdr_hiper.h | 14 +- src/lib/device/m2_dsdr/m2_dsdr_e.yaml | 133 +++++++++++-- src/lib/device/m2_dsdr/m2_dsdr_p.yaml | 39 ++-- src/lib/device/m2_dsdr/m2_dsdr_usr.yaml | 51 +++-- 5 files changed, 394 insertions(+), 86 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 4285b073..789e12dd 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -13,6 +13,7 @@ #include "../hw/dac80501/dac80501.h" #include "../hw/tca6424a/tca6424a.h" #include "../hw/adf4002b/adf4002b.h" +#include "../hw/lp8758/lp8758.h" #include "../ipblks/uart.h" #include "../ipblks/spiext.h" @@ -69,12 +70,14 @@ enum i2c_idx_extra { I2C_TCA6424AR_U114 = MAKE_LSOP_I2C_ADDR(1, 0, TCA6424A_ADDR_L), I2C_TCA6424AR_U113 = MAKE_LSOP_I2C_ADDR(1, 0, TCA6424A_ADDR_H), I2C_TCA6424AR_U115 = MAKE_LSOP_I2C_ADDR(1, 1, TCA6424A_ADDR_H), + I2C_TCA6424AR_U110 = MAKE_LSOP_I2C_ADDR(1, 1, TCA6424A_ADDR_L), I2C_TEMP_U69 = MAKE_LSOP_I2C_ADDR(1, 0, I2C_DEV_TMP114NB), I2C_TEMP_U70 = MAKE_LSOP_I2C_ADDR(1, 1, I2C_DEV_TMP114NB), I2C_TEMP_U71 = MAKE_LSOP_I2C_ADDR(0, 1, I2C_DEV_TMP114NB), I2C_DAC = MAKE_LSOP_I2C_ADDR(1, 1, I2C_DEV_DAC80501M_A0_GND), + I2C_PMIC_LMS8= MAKE_LSOP_I2C_ADDR(1, 0, I2C_DEV_PMIC_FPGA), }; enum spi_idx { @@ -320,7 +323,7 @@ int dsdr_hiper_dacvctcxo_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue static int _dsdr_hiper_senslms(dsdr_hiper_fe_t* fe, unsigned idx, uint64_t* ovalue) { - int res = 0, tmp256; + int res = 0, tmp256 = 0; res = res ? res : lms8001_temp_get(&fe->lms8[idx], &tmp256); res = res ? res : lms8001_temp_start(&fe->lms8[idx]); @@ -627,6 +630,15 @@ static int _hiper_update_expander_vreg(dsdr_hiper_fe_t* hiper, unsigned addr, un case 0x6: res = tca6424a_reg8_set(hiper->dev, hiper->subdev, I2C_TCA6424AR_U115, TCA6424_OUT0 + (addr - 0x4), data); break; + + case 0x7: + case 0x8: + case 0x9: + if (hiper->rev == HIPER_REV2) { + res = tca6424a_reg8_set(hiper->dev, hiper->subdev, I2C_TCA6424AR_U110, TCA6424_OUT0 + (addr - 0x7), data); + } + break; + default: return -EINVAL; } @@ -658,9 +670,10 @@ int dsdr_hiper_dsdr_hiper_exp_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ case 0x20: res = res ? res : tca6424a_reg16_get(hiper->dev, hiper->subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, &di16); res = res ? res : tca6424a_reg8_get(hiper->dev, hiper->subdev, I2C_TCA6424AR_U114, TCA6424_OUT0 + 2, &di8); + if (res) + return res; hiper->debug_exp_reg_last = di16 | (((unsigned)di8) << 16); - USDR_LOG("HIPR", USDR_LOG_WARNING, "HIPER_EXP RD %08x => %08x\n", addr, hiper->debug_exp_reg_last); return res; @@ -737,8 +750,11 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, { int res = 0; device_t* base = lowlevel_get_device(dev); + uint8_t check_byte = 0; + dfe->dev = dev; dfe->subdev = 0; + dfe->rev = HIPER_REV0; USDR_LOG("HIPR", USDR_LOG_INFO, "Initializing HIPER front end...\n"); dfe->ref_int_osc = DEF_OSC_INT_FREQ; @@ -764,6 +780,21 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, res = res ? res : tca6424a_reg8_set(dev, dfe->subdev, I2C_TCA6424AR_U114, TCA6424_CFG0 + 2, 0); res = res ? res : tca6424a_reg8_set(dev, dfe->subdev, I2C_TCA6424AR_U113, TCA6424_CFG0 + 2, 0); res = res ? res : tca6424a_reg8_set(dev, dfe->subdev, I2C_TCA6424AR_U115, TCA6424_CFG0 + 2, (1 << 0) | (1 << 2)); + + res = res ? res : tca6424a_reg16_set(dev, dfe->subdev, I2C_TCA6424AR_U110, TCA6424_CFG0, 0); + res = res ? res : tca6424a_reg8_set(dev, dfe->subdev, I2C_TCA6424AR_U110, TCA6424_CFG0 + 2, 0xf); + res = res ? res : tca6424a_reg8_get(dev, dfe->subdev, I2C_TCA6424AR_U110, TCA6424_CFG0 + 2, &check_byte); + if (res) { + USDR_LOG("HIPR", USDR_LOG_WARNING, "HIPER Expanders initialization failed: %d\n", res); + return res; + } + if (check_byte == 0xf) { + dfe->rev = HIPER_REV2; + res = res ? res : tca6424a_reg8_set(dev, dfe->subdev, I2C_TCA6424AR_U115, TCA6424_CFG0 + 2, 0); + + USDR_LOG("HIPR", USDR_LOG_WARNING, "Detected HIPER rev2 board\n"); + } + // TODO: sanity check // Reset all LMS8001 @@ -772,9 +803,9 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, // if (res) // return res; - dfe->fe_ctrl_regs[ENABLE - SW_RX_FILTER] = MAKE_M2_DSDR_E_ENABLE(1, 1, 1, 1); - dfe->fe_ctrl_regs[LMS8001_RESET - SW_RX_FILTER] = MAKE_M2_DSDR_E_LMS8001_RESET(1, 1, 1, 1, 1, 1); - dfe->fe_ctrl_regs[GPIO6 - SW_RX_FILTER] = MAKE_M2_DSDR_E_GPIO6(0, 0, 0, 0, 1, 0, 1, 0); + dfe->fe_ctrl_regs[ENABLE - SW_RX_FILTER] = MAKE_M2_DSDR_E_ENABLE(1, 0, 1, 1, 1, 1, 1, 1); + dfe->fe_ctrl_regs[LMS8001_RESET - SW_RX_FILTER] = MAKE_M2_DSDR_E_LMS8001_RESET(1, 1, 1, 1, 1, 1, 1); + dfe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER] = MAKE_M2_DSDR_E_AUX_CTRL(0, 0, 0, 0, 1, 1, 1, 1); for (unsigned k = 0; k < SIZEOF_ARRAY(dfe->fe_ctrl_regs); k++) { res = res ? res : _hiper_update_expander_vreg(dfe, k, dfe->fe_ctrl_regs[k]); } @@ -783,6 +814,32 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, return res; } + if (dfe->rev == HIPER_REV2) { + uint16_t rev = 0xfefe; + unsigned lms8_ldo_v = 2400; + bool pg = false; + + res = res ? res : lp8758_get_rev(dev, dfe->subdev, I2C_PMIC_LMS8, &rev); + + res = res ? res : lp8758_vout_set(dev, dfe->subdev, I2C_PMIC_LMS8, 0, lms8_ldo_v); + res = res ? res : lp8758_vout_set(dev, dfe->subdev, I2C_PMIC_LMS8, 1, lms8_ldo_v); + res = res ? res : lp8758_vout_set(dev, dfe->subdev, I2C_PMIC_LMS8, 2, lms8_ldo_v); + res = res ? res : lp8758_vout_set(dev, dfe->subdev, I2C_PMIC_LMS8, 3, lms8_ldo_v); + res = res ? res : lp8758_vout_ctrl(dev, dfe->subdev, I2C_PMIC_LMS8, 0, true, false); + res = res ? res : lp8758_vout_ctrl(dev, dfe->subdev, I2C_PMIC_LMS8, 1, true, false); + res = res ? res : lp8758_vout_ctrl(dev, dfe->subdev, I2C_PMIC_LMS8, 2, true, false); + res = res ? res : lp8758_vout_ctrl(dev, dfe->subdev, I2C_PMIC_LMS8, 3, true, false); + + for (unsigned t = 0; t < 20; t++) { + res = res ? res : lp8758_check_pg(dev, dfe->subdev, I2C_PMIC_LMS8, 0xf, &pg); + if (pg) + break; + res = res ? res : usleep(5000); + } + + USDR_LOG("HIPR", USDR_LOG_WARNING, "HIPER Rev2 board, PMIC REV=%04x PG=%x\n", rev, pg); + } + // LMS8 for (unsigned k = 0; k < 6; k++) { uint32_t cfg = MAKE_SPIEXT_LSOPADR(MAKE_SPIEXT_CFG(LMS8_BCNTZ, k, LMS8_DIV), 0, spix_num); @@ -881,7 +938,7 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, for (unsigned i = 0; i < HIPER_MAX_HW_CHANS; i++) { fe_chan_config_t* cfg = &dfe->ucfg[i]; cfg->rx_ifamp_bp = 0; - cfg->rx_band = IFBAND_AUTO; + cfg->rx_band = IFBAND_RX_AUTO; cfg->rx_fb_sel = RX_FB_AUTO; cfg->rx_dsa = 0; cfg->tx_band = IFBAND_AUTO; @@ -930,8 +987,8 @@ int dsdr_hiper_fe_destroy(dsdr_hiper_fe_t* dfe) { int res = 0; - dfe->fe_ctrl_regs[ENABLE - SW_RX_FILTER] = MAKE_M2_DSDR_E_ENABLE(0, 0, 0, 0); - dfe->fe_ctrl_regs[LMS8001_RESET - SW_RX_FILTER] = MAKE_M2_DSDR_E_LMS8001_RESET(0, 0, 0, 0, 0, 0); + dfe->fe_ctrl_regs[ENABLE - SW_RX_FILTER] = MAKE_M2_DSDR_E_ENABLE(0, 0, 0, 0, 0, 0, 0, 0); + dfe->fe_ctrl_regs[LMS8001_RESET - SW_RX_FILTER] = MAKE_M2_DSDR_E_LMS8001_RESET(0, 0, 0, 0, 0, 0, 0); res = res ? res : _hiper_update_expander_vreg(dfe, LMS8001_RESET - SW_RX_FILTER, dfe->fe_ctrl_regs[LMS8001_RESET - SW_RX_FILTER]); usleep(100); @@ -1096,6 +1153,13 @@ int dsdr_hiper_dsdr_hiper_usr_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ hiper->ucfg[H_CHC].lms8_tx_hlmix_gain = GET_M2_DSDR_USR_TX_8KB_C(data); hiper->ucfg[H_CHD].lms8_tx_hlmix_gain = GET_M2_DSDR_USR_TX_8KB_D(data); break; + case PA_2ND_BP: + hiper->ucfg[H_CHA].pa_2stage_bypass = GET_M2_DSDR_USR_PA_2ND_BP_A(data); + hiper->ucfg[H_CHB].pa_2stage_bypass = GET_M2_DSDR_USR_PA_2ND_BP_B(data); + hiper->ucfg[H_CHC].pa_2stage_bypass = GET_M2_DSDR_USR_PA_2ND_BP_C(data); + hiper->ucfg[H_CHD].pa_2stage_bypass = GET_M2_DSDR_USR_PA_2ND_BP_D(data); + break; + default: return -EINVAL; } @@ -1192,6 +1256,11 @@ int dsdr_hiper_dsdr_hiper_usr_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ hiper->ucfg[H_CHD].lms8_tx_hlmix_gain, hiper->ucfg[H_CHC].lms8_tx_hlmix_gain, hiper->ucfg[H_CHB].lms8_tx_hlmix_gain, hiper->ucfg[H_CHA].lms8_tx_hlmix_gain); break; + case PA_2ND_BP: + hiper->debug_usr_reg_last = MAKE_M2_DSDR_USR_PA_2ND_BP( + hiper->ucfg[H_CHD].pa_2stage_bypass, hiper->ucfg[H_CHC].pa_2stage_bypass, + hiper->ucfg[H_CHB].pa_2stage_bypass, hiper->ucfg[H_CHA].pa_2stage_bypass); + break; default: return -EINVAL; } @@ -1236,7 +1305,28 @@ static void _hiper_fbank_map(unsigned filsel, unsigned *bout, unsigned *bin) } } -static void _hiper_antenna_sw_map(unsigned antenna, bool rxen, bool txen, uint8_t* gpo_ctrl, unsigned* inswlb, unsigned *arx, unsigned *atx) +enum led_rtx_vals { + LED_TRX_RXO = 0, + LED_TRX_OFF = 1, + LED_TRX_TRX = 2, + LED_TRX_TXO = 3, +}; + +enum led_rx_cals { + LED_RX_ON = 0, + LED_RX_OFF = 1, +}; + +// Switch on RX path => ANT_RX external port / rfsw_rxtx / LB +enum rfsw_tddfdd_bits { + EXP_TDDFDD_SD = 0b00, // LB SW is on + EXP_TDDFDD_P1_LB_SW = 0b01, // LB SW is on + EXP_TDDFDD_P2_TRX_SW = 0b10, + EXP_TDDFDD_P3_ANT_RX = 0b11, +}; + +static void _hiper_antenna_sw_map(bool rev2, unsigned antenna, bool rxen, bool txen, uint8_t* gpo_ctrl, unsigned* inswlb, unsigned *arx, unsigned *atx, + uint8_t* exp_led_trx, uint8_t* exp_led_rx) { CHECK_CONSTANT_EQ(ANT_OPTS_RX_TO_RX_AND_TX_TO_TRX, ANT_RX_TRX); CHECK_CONSTANT_EQ(ANT_OPTS_RX_TO_TRX_AND_TX_TERM, ANT_TRX_TERM); @@ -1249,68 +1339,80 @@ static void _hiper_antenna_sw_map(unsigned antenna, bool rxen, bool txen, uint8_ SET_M2_DSDR_P_CHD_EN_TX(*gpo_ctrl, txen); SET_M2_DSDR_P_CHD_EN_VADJ(*gpo_ctrl, txen); SET_M2_DSDR_P_CHD_EN_RX(*gpo_ctrl, rxen); - SET_M2_DSDR_P_CHD_SW_HW_TDD_CTRL(*gpo_ctrl, 0); + SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, rev2 ? EXP_TDDFDD_P3_ANT_RX : 0); SET_M2_DSDR_P_CHD_SW_PA_ONOFF(*gpo_ctrl, 0); SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, 0); SET_M2_DSDR_P_CHD_SW_RXTX(*gpo_ctrl, 0); *inswlb = 0; *arx = rxen; *atx = txen; + *exp_led_trx = LED_TRX_TXO; + *exp_led_rx = LED_RX_ON; break; case ANT_TRX_TERM: SET_M2_DSDR_P_CHD_EN_TX(*gpo_ctrl, 0); SET_M2_DSDR_P_CHD_EN_VADJ(*gpo_ctrl, 0); SET_M2_DSDR_P_CHD_EN_RX(*gpo_ctrl, rxen); - SET_M2_DSDR_P_CHD_SW_HW_TDD_CTRL(*gpo_ctrl, 1); + SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, rev2 ? EXP_TDDFDD_P2_TRX_SW : 1); SET_M2_DSDR_P_CHD_SW_PA_ONOFF(*gpo_ctrl, 1); SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, 1); SET_M2_DSDR_P_CHD_SW_RXTX(*gpo_ctrl, 0); *inswlb = 0; *arx = rxen; *atx = 0; + *exp_led_trx = LED_TRX_RXO; + *exp_led_rx = LED_RX_OFF; break; case ANT_RX_TERM: SET_M2_DSDR_P_CHD_EN_TX(*gpo_ctrl, 0); SET_M2_DSDR_P_CHD_EN_VADJ(*gpo_ctrl, 0); SET_M2_DSDR_P_CHD_EN_RX(*gpo_ctrl, rxen); - SET_M2_DSDR_P_CHD_SW_HW_TDD_CTRL(*gpo_ctrl, 0); + SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, rev2 ? EXP_TDDFDD_P3_ANT_RX : 0); SET_M2_DSDR_P_CHD_SW_PA_ONOFF(*gpo_ctrl, 1); SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, 0); SET_M2_DSDR_P_CHD_SW_RXTX(*gpo_ctrl, 0); *inswlb = 0; *arx = rxen; *atx = 0; + *exp_led_trx = LED_TRX_OFF; + *exp_led_rx = LED_RX_ON; break; case ANT_LOOPBACK: SET_M2_DSDR_P_CHD_EN_TX(*gpo_ctrl, txen); SET_M2_DSDR_P_CHD_EN_VADJ(*gpo_ctrl, txen); SET_M2_DSDR_P_CHD_EN_RX(*gpo_ctrl, rxen); - SET_M2_DSDR_P_CHD_SW_HW_TDD_CTRL(*gpo_ctrl, 0); + SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, rev2 ? EXP_TDDFDD_P1_LB_SW : 0); SET_M2_DSDR_P_CHD_SW_PA_ONOFF(*gpo_ctrl, 1); SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, 1); SET_M2_DSDR_P_CHD_SW_RXTX(*gpo_ctrl, 0); *inswlb = 1; *arx = rxen; *atx = txen; + *exp_led_trx = LED_TRX_OFF; + *exp_led_rx = LED_RX_OFF; break; case AND_HW_TDD: SET_M2_DSDR_P_CHD_EN_TX(*gpo_ctrl, txen); SET_M2_DSDR_P_CHD_EN_VADJ(*gpo_ctrl, txen); SET_M2_DSDR_P_CHD_EN_RX(*gpo_ctrl, rxen); - SET_M2_DSDR_P_CHD_SW_HW_TDD_CTRL(*gpo_ctrl, 1); + SET_M2_DSDR_P_CHD_SW_RX_TDDFDD(*gpo_ctrl, rev2 ? EXP_TDDFDD_P2_TRX_SW : 1); *inswlb = 0; *arx = rxen; *atx = txen; + *exp_led_trx = LED_TRX_TRX; + *exp_led_rx = LED_RX_OFF; break; default: *inswlb = 0; *arx = 0; *atx = 0; + *exp_led_trx = LED_TRX_OFF; + *exp_led_rx = LED_RX_OFF; break; } } @@ -1336,6 +1438,10 @@ int dsdr_hiper_update_fe_user(dsdr_hiper_fe_t* fe) unsigned ifband_tx_h[HIPER_MAX_HW_CHANS]; unsigned ifband_rx_h[HIPER_MAX_HW_CHANS]; + uint8_t exp_led_trx[HIPER_MAX_HW_CHANS]; + uint8_t exp_led_rx[HIPER_MAX_HW_CHANS]; + bool rev2 = fe->rev == HIPER_REV2; + for (unsigned i = 0; i < HIPER_MAX_HW_CHANS; i++) { unsigned rxen = fe->ucfg[i].rx_en; unsigned txen = fe->ucfg[i].tx_en; @@ -1344,7 +1450,7 @@ int dsdr_hiper_update_fe_user(dsdr_hiper_fe_t* fe) _hiper_fbank_map(fe->ucfg[i].rx_fb_sel, &fbanksel_out[i], &fbanksel_in[i]); // SW_RX_FILTER_OUT_CHA_MUTE1 if not enabled? // Antanna switch, RF PA/LNA switch, loopback switch - _hiper_antenna_sw_map(fe->ucfg[i].ant_sel, rxen, txen, &fe->fe_gpo_regs[CHA - REFCTRL + i], &lbrxtx[i], &act_rx[i], &act_tx[i]); + _hiper_antenna_sw_map(rev2, fe->ucfg[i].ant_sel, rxen, txen, &fe->fe_gpo_regs[CHA - REFCTRL + i], &lbrxtx[i], &act_rx[i], &act_tx[i], &exp_led_trx[i], &exp_led_rx[i]); // Update RX DSA fe->fe_gpo_regs[ATT_RX_CHA - REFCTRL + i] = fe->ucfg[i].rx_dsa; @@ -1353,16 +1459,16 @@ int dsdr_hiper_update_fe_user(dsdr_hiper_fe_t* fe) ifband_tx_h[i] = fe->ucfg[i].tx_band & (~IFBAND_AUTO); // RX IF band sel - ifband_rx_h[i] = fe->ucfg[i].rx_band & (~IFBAND_AUTO); + ifband_rx_h[i] = fe->ucfg[i].rx_band & (~IFBAND_RX_AUTO); // RX IF amplifier config iflna[i] = act_rx[i] ? ( fe->ucfg[i].rx_ifamp_bp ? IF_LNA_OPTS_BYPASS : IF_LNA_OPTS_LNA) : IF_LNA_OPTS_Disable; }; - SET_M2_DSDR_E_GPIO6_ABSLNA_PA_CHA(fe->fe_ctrl_regs[GPIO6 - SW_RX_FILTER], lbrxtx[H_CHA]); - SET_M2_DSDR_E_GPIO6_ABSLNA_PA_CHB(fe->fe_ctrl_regs[GPIO6 - SW_RX_FILTER], lbrxtx[H_CHB]); - SET_M2_DSDR_E_GPIO6_ABSLNA_PA_CHC(fe->fe_ctrl_regs[GPIO6 - SW_RX_FILTER], lbrxtx[H_CHC]); - SET_M2_DSDR_E_GPIO6_ABSLNA_PA_CHD(fe->fe_ctrl_regs[GPIO6 - SW_RX_FILTER], lbrxtx[H_CHD]); + SET_M2_DSDR_E_AUX_CTRL_ABSLNA_PA_CHA(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], lbrxtx[H_CHA]); + SET_M2_DSDR_E_AUX_CTRL_ABSLNA_PA_CHB(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], lbrxtx[H_CHB]); + SET_M2_DSDR_E_AUX_CTRL_ABSLNA_PA_CHC(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], lbrxtx[H_CHC]); + SET_M2_DSDR_E_AUX_CTRL_ABSLNA_PA_CHD(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], lbrxtx[H_CHD]); fe->fe_ctrl_regs[SW_RX_FILTER - SW_RX_FILTER] = MAKE_M2_DSDR_E_SW_RX_FILTER( @@ -1391,6 +1497,54 @@ int dsdr_hiper_update_fe_user(dsdr_hiper_fe_t* fe) ifband_rx_h[H_CHB] ? 0 : 1, ifband_rx_h[H_CHA] ? 0 : 1); + if (rev2) { + unsigned sw_out_rx[4]; + unsigned sw_in_rx[4]; + for (unsigned i = 0; i < HIPER_MAX_HW_CHANS; i++) { + switch (ifband_rx_h[i]) { + case IFBAND_400_3500: + sw_in_rx[i] = R2RX_IN_OPTS_RX_LOW; + sw_out_rx[i] = R2RX_OUT_OPTS_RX_LOW; + break; + case IFBAND_2200_7200: + sw_in_rx[i] = R2RX_IN_OPTS_RX_HI; + sw_out_rx[i] = R2RX_OUT_OPTS_RX_HI; + break; + case IFBAND_R2RX_1580_2760: + sw_in_rx[i] = R2RX_IN_OPTS_RX_BYPASS; + sw_out_rx[i] = R2RX_OUT_OPTS_RX_BYPASS; + break; + default: + sw_in_rx[i] = R2RX_IN_OPTS_DISABLE; + sw_out_rx[i] = R2RX_OUT_OPTS_DISABLE; + break; + } + } + + SET_M2_DSDR_E_SW_IN_RX_L_CHD_R2A_V2(fe->fe_ctrl_regs[SW_IN - SW_RX_FILTER], (sw_out_rx[H_CHA] >> 1)); + SET_M2_DSDR_E_SW_IN_RX_L_CHC_R2A_V1(fe->fe_ctrl_regs[SW_IN - SW_RX_FILTER], (sw_out_rx[H_CHA] & 1)); + SET_M2_DSDR_E_SW_IN_RX_L_CHB_R2B_V2(fe->fe_ctrl_regs[SW_IN - SW_RX_FILTER], (sw_out_rx[H_CHB] >> 1)); + SET_M2_DSDR_E_SW_IN_RX_L_CHA_R2B_V1(fe->fe_ctrl_regs[SW_IN - SW_RX_FILTER], (sw_out_rx[H_CHB] & 1)); + + SET_M2_DSDR_E_SW_OUT_RX_H_CHD_R2C_V2(fe->fe_ctrl_regs[SW_OUT - SW_RX_FILTER], (sw_out_rx[H_CHC] >> 1)); + SET_M2_DSDR_E_SW_OUT_RX_H_CHC_R2C_V1(fe->fe_ctrl_regs[SW_OUT - SW_RX_FILTER], (sw_out_rx[H_CHC] & 1)); + SET_M2_DSDR_E_SW_OUT_RX_H_CHB_R2D_V2(fe->fe_ctrl_regs[SW_OUT - SW_RX_FILTER], (sw_out_rx[H_CHD] >> 1)); + SET_M2_DSDR_E_SW_OUT_RX_H_CHA_R2D_V1(fe->fe_ctrl_regs[SW_OUT - SW_RX_FILTER], (sw_out_rx[H_CHD] & 1)); + + SET_M2_DSDR_E_AUX_CTRL_PA_BYPASS_A(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], fe->ucfg[H_CHA].pa_2stage_bypass); + SET_M2_DSDR_E_AUX_CTRL_PA_BYPASS_B(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], fe->ucfg[H_CHB].pa_2stage_bypass); + SET_M2_DSDR_E_AUX_CTRL_PA_BYPASS_C(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], fe->ucfg[H_CHC].pa_2stage_bypass); + SET_M2_DSDR_E_AUX_CTRL_PA_BYPASS_D(fe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER], fe->ucfg[H_CHD].pa_2stage_bypass); + + fe->fe_ctrl_regs[SW_IN_RX - SW_RX_FILTER] = MAKE_M2_DSDR_E_SW_IN_RX(sw_in_rx[H_CHD], sw_in_rx[H_CHC], sw_in_rx[H_CHB], sw_in_rx[H_CHA]); + + fe->fe_ctrl_regs[LED_TRX_CTRL - SW_RX_FILTER] = MAKE_M2_DSDR_E_LED_TRX_CTRL( + exp_led_trx[H_CHD], exp_led_trx[H_CHC], exp_led_trx[H_CHB], exp_led_trx[H_CHA]); + + fe->fe_ctrl_regs[LEDRX_CH_CTRL - SW_RX_FILTER] = MAKE_M2_DSDR_E_LEDRX_CH_CTRL( + exp_led_rx[H_CHD], exp_led_rx[H_CHC], exp_led_rx[H_CHB], exp_led_rx[H_CHA], 0, 0, 0, 0); + } + // Update registers for (unsigned i = 0; i < FE_GPO_REGS; i++) { @@ -1445,14 +1599,16 @@ void dsdr_hiper_fe_rx_filterbank_upd(dsdr_hiper_fe_t* def, unsigned chno) USDR_LOG("HIPR", USDR_LOG_WARNING, "RXFBabk[%d] = %d\n", chno, def->ucfg[chno].rx_fb_sel); } -static void dsdr_hiper_fe_rx_band_upd(dsdr_hiper_fe_t* def, unsigned chno, bool band_high) +static void dsdr_hiper_fe_rx_band_upd(dsdr_hiper_fe_t* def, unsigned chno, unsigned band) { - if (def->ucfg[chno].rx_band < BAND_OPTS_BAND_AUTO_L) + if (def->ucfg[chno].rx_band < RXBAND_OPTS_BAND_AUTO_L) return; - def->ucfg[chno].rx_band = (band_high) ? BAND_OPTS_BAND_AUTO_H : BAND_OPTS_BAND_AUTO_L; + def->ucfg[chno].rx_band = (band == 0) ? RXBAND_OPTS_BAND_AUTO_L : (band == 1) ? RXBAND_OPTS_BAND_AUTO_H : RXBAND_OPTS_BAND_AUTO_BP; USDR_LOG("HIPR", USDR_LOG_WARNING, "RXBand[%d] switched to %c (%d)\n", chno, - def->ucfg[chno].rx_band == BAND_OPTS_BAND_AUTO_H ? 'H' : 'L', + def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_H ? 'H' : + def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_L ? 'L' : + def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_BP ? 'B' : 'D', def->ucfg[chno].rx_band); } @@ -1470,22 +1626,29 @@ static void dsdr_hiper_fe_tx_band_upd(dsdr_hiper_fe_t* def, unsigned chno, bool -int dsdr_hiper_fe_rxlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_rxiq, bool* p_high_path) +int dsdr_hiper_fe_rxlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_rxiq, unsigned* p_path) { int res = 0; bool fLOh = (def->ucfg[chno].rx_freq < 4700e6); - bool high_path; + unsigned rxpath; - if (def->ucfg[chno].rx_band < BAND_OPTS_BAND_AUTO_L) { - high_path = (def->ucfg[chno].rx_band == BAND_OPTS_BAND_400_3500) ? false : true; + if (def->ucfg[chno].rx_band < RXBAND_OPTS_BAND_AUTO_L) { + //high_path = (def->ucfg[chno].rx_band == BAND_OPTS_BAND_400_3500) ? false : true; + rxpath = def->ucfg[chno].rx_band; } else { - high_path = (def->ucfg[chno].rx_freq < 2600e6) ? false : true; + rxpath = (def->ucfg[chno].rx_freq < 2600e6) ? RXBAND_OPTS_BAND_AUTO_L : RXBAND_OPTS_BAND_AUTO_H; + + // Bypass only available in rev2 + if ((def->rev == HIPER_REV2) && (def->ucfg[chno].rx_freq > 1580e6) && (def->ucfg[chno].rx_freq < 2760e6)) { + rxpath = RXBAND_OPTS_BAND_AUTO_BP; + } } uint64_t fIF = 2075e6; uint64_t fLO = (fLOh) ? def->ucfg[chno].rx_freq + fIF : def->ucfg[chno].rx_freq - fIF; + bool high_path = ((rxpath & 0x3) == RXBAND_OPTS_BAND_2200_7200); if (high_path == false) { fIF = 1975e6; fLO = def->ucfg[chno].rx_freq + fIF; @@ -1502,6 +1665,20 @@ int dsdr_hiper_fe_rxlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_rxi unsigned zeroes[4] = {0, 0, 0, 0}; res = res ? res : lms8001a_ch_enable(&def->lms8[idx_off], 0x0, zeroes, zeroes); res = res ? res : lms8001_ch_enable(&def->lms8[idx], chmsk); + } else if ((def->rev == HIPER_REV2) && ((rxpath & 0x3) == RXBAND_OPTS_BAND_1580_2760_BP)) { + unsigned pas[4] = {~0, ~0, ~0, ~0}; + unsigned lnas[4] = {~0, ~0, ~0, ~0}; + + res = res ? res : lms8001_ch_enable(&def->lms8[idx_off], 0x0); + res = res ? res : lms8001a_ch_enable(&def->lms8[idx], 0, lnas, pas); + + def->ucfg[chno].rx_nco = 0; + + *p_path = rxpath; + *p_swap_rxiq = 0; + + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d] RX_BYPASS Mode\n", chno); + return res; } else { unsigned pas[4] = {0, 0, 0, 0}; unsigned lnas[4] = {0, 0, 0, 0}; @@ -1517,7 +1694,7 @@ int dsdr_hiper_fe_rxlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_rxi def->ucfg[chno].rx_nco = fIF; *p_swap_rxiq = (fLOh) ? 1 : 0; - *p_high_path = high_path; + *p_path = rxpath; USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d] RX_NCO=%.3f LO_%c=%.3f SWAP_IQ=%d PATH=%s LMS8[%d]_MSK=%x\n", chno, def->ucfg[chno].rx_nco / 1.0e6, fLOh ? 'H' : 'L', fLO / 1.0e6, *p_swap_rxiq, high_path ? "HIGH" : "LOW", idx, chmsk); @@ -1565,7 +1742,7 @@ int dsdr_hiper_fe_txlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_txi int dsdr_hiper_fe_rx_freq_set(dsdr_hiper_fe_t* def, unsigned chno, uint64_t freq, uint64_t* ncotune, bool* p_swap_rxiq) { - bool high_band = false; + unsigned band = 0; int res; if (chno >= HIPER_MAX_HW_CHANS) @@ -1576,11 +1753,11 @@ int dsdr_hiper_fe_rx_freq_set(dsdr_hiper_fe_t* def, unsigned chno, uint64_t freq def->ucfg[chno].rx_freq = freq; dsdr_hiper_fe_rx_filterbank_upd(def, chno); - res = dsdr_hiper_fe_rxlo_upd(def, chno, p_swap_rxiq, &high_band); + res = dsdr_hiper_fe_rxlo_upd(def, chno, p_swap_rxiq, &band); if (res) return res; - dsdr_hiper_fe_rx_band_upd(def, chno, high_band); + dsdr_hiper_fe_rx_band_upd(def, chno, band); *ncotune = def->ucfg[chno].rx_nco; return dsdr_hiper_update_fe_user(def); diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.h b/src/lib/device/m2_dsdr/dsdr_hiper.h index 837ccce7..f7886a43 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.h +++ b/src/lib/device/m2_dsdr/dsdr_hiper.h @@ -29,8 +29,11 @@ enum antenna_cfg { enum if_band { IFBAND_400_3500, IFBAND_2200_7200, + IFBAND_R2RX_1580_2760, + IFBAND_R2RX_OFF, IFBAND_AUTO = 2, + IFBAND_RX_AUTO = 4, }; struct fe_chan_config { @@ -52,6 +55,8 @@ struct fe_chan_config { uint64_t tx_freq; uint64_t tx_nco; + uint8_t pa_2stage_bypass; // For Rev.2 PA second stage bypass + uint8_t lms8_pa_gain; uint8_t lms8_lna_gain; uint8_t lms8_rx_hlmix_gain; @@ -60,12 +65,19 @@ struct fe_chan_config { typedef struct fe_chan_config fe_chan_config_t; #define FE_GPO_REGS 9 -#define FE_CTRL_REGS 7 +#define FE_CTRL_REGS 10 + +enum { + HIPER_REV0, + HIPER_REV2, +}; struct dsdr_hiper_fe { lldev_t dev; subdev_t subdev; + unsigned rev; + lms8001_state_t lms8[6]; uint64_t lo_lms8_freq[6]; diff --git a/src/lib/device/m2_dsdr/m2_dsdr_e.yaml b/src/lib/device/m2_dsdr/m2_dsdr_e.yaml index 77491146..6b09c1bd 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_e.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_e.yaml @@ -3,7 +3,7 @@ # Register desc and visual map name: M2_DSDR -desc: DSDR M2 board +desc: Hiper board control revision: "0.0.1" processors: [ c ] bus: @@ -44,6 +44,21 @@ x-if-lna-opts: &if-lna-opts 0b10: BYPASS 0b11: BYPASS2 + +x-r2rx-in-opts: &r2rx-in-opts + 0b00: DISABLE + 0b01: RX_HI + 0b10: RX_LOW + 0b11: RX_BYPASS + + +x-r2rx-out-opts: &r2rx-out-opts + 0b00: DISABLE + 0b01: RX_LOW + 0b10: RX_HI + 0b11: RX_BYPASS + + pages: - name: V0 regs: @@ -130,16 +145,16 @@ pages: fields: # - bits: "6" - name: RX_H_CHA + name: RX_H_CHA_R2D_V1 desc: Channel A RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) - bits: "7" - name: RX_H_CHB + name: RX_H_CHB_R2D_V2 desc: Channel B RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) - bits: "4" - name: RX_H_CHC + name: RX_H_CHC_R2C_V1 desc: Channel C RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) - bits: "5" - name: RX_H_CHD + name: RX_H_CHD_R2C_V2 desc: Channel D RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) - bits: "3" name: TX_L_CHA @@ -159,16 +174,16 @@ pages: fields: # - bits: "0" - name: RX_L_CHA + name: RX_L_CHA_R2B_V1 desc: Channel A RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) - bits: "1" - name: RX_L_CHB + name: RX_L_CHB_R2B_V2 desc: Channel B RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) - bits: "2" - name: RX_L_CHC + name: RX_L_CHC_R2A_V1 desc: Channel C RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) - bits: "3" - name: RX_L_CHD + name: RX_L_CHD_R2A_V2 desc: Channel D RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) - bits: "4" name: TX_H_CHA @@ -186,6 +201,18 @@ pages: - addr: 0x24 name: ENABLE fields: + - bits: "7" + name: REV2_P5V + desc: Rev2 Enable +5v power for (IF Amplifier) + - bits: "6" + name: REV2_P5V_EXTLO + desc: Rev2 Eanble +5v power for EXT_LO clock distributor + - bits: "5" + name: REV2_PG_6P0 + desc: PG signal for 6P0 line + - bits: "4" + name: REV2_PG_8P0 + desc: PG signal for 8P0 line - bits: "3" name: REF_OSC desc: Enable 25MHz reference clock oscillator @@ -197,7 +224,7 @@ pages: desc: Enable +8v power supply for TX amps - bits: "0" name: P5V_RX - desc: Enable +5v power supply for RX amps + desc: Enable +5v power supply for RX amps, Rev2 Enable 6V rail # - addr: 0x25 name: LMS8001_RESET @@ -220,9 +247,13 @@ pages: - bits: "1" name: TX_CHCD desc: TX circuit LMS8001B reset (channels C and D, 2.5-7.1 GHz (HIGH) mode) + - bits: "0" + name: REV2_DCDC + desc: Reset pin for DCDC module + # - addr: 0x26 - name: GPIO6 + name: AUX_CTRL fields: - bits: "7" name: ABSLNA_PA_CHD @@ -237,14 +268,78 @@ pages: name: ABSLNA_PA_CHA desc: 50 ohm absorptive LNA to PA switch selection, channel A - bits: "3" - name: FAN_PWM0 - desc: FAN0 PWM input + name: PA_BYPASS_D + desc: Rev0 FAN0 PWM input - bits: "2" - name: FAN_TACH0 - desc: FAN0 tachometer output + name: PA_BYPASS_C + desc: Rev0 FAN0 tachometer output - bits: "1" - name: FAN_PWM1 - desc: FAN1 PWM input + name: PA_BYPASS_B + desc: Rev0 FAN1 PWM input - bits: "0" - name: FAN_TACH1 - desc: FAN1 tachometer output + name: PA_BYPASS_A + desc: Rev0 FAN1 tachometer output +# + - addr: 0x27 + name: SW_IN_RX + fields: + - bits: "1:0" + name: CHA + desc: CHA + opts: *r2rx-in-opts + - bits: "3:2" + name: CHB + desc: CHB + opts: *r2rx-in-opts + - bits: "5:4" + name: CHC + desc: CHC + opts: *r2rx-in-opts + - bits: "7:6" + name: CHD + desc: CHD + opts: *r2rx-in-opts +# + - addr: 0x28 + name: LED_TRX_CTRL + fields: + - bits: "1:0" + name: LED_CHA + desc: LED CHA + - bits: "3:2" + name: LED_CHB + desc: LED CHB + - bits: "5:4" + name: LED_CHC + desc: LED CHC + - bits: "7:6" + name: LED_CHD + desc: LED CHD +# + - addr: 0x29 + name: LEDRX_CH_CTRL + fields: + - bits: "0" + name: EN_CHA + desc: Enable CHA + - bits: "1" + name: EN_CHB + desc: Enable CHB + - bits: "2" + name: EN_CHC + desc: Enable CHC + - bits: "3" + name: EN_CHD + desc: Enable CHD + - bits: "4" + name: LED_CHA + desc: LED CHA + - bits: "5" + name: LED_CHB + desc: LED CHB + - bits: "6" + name: LED_CHC + desc: LED CHC + - bits: "7" + name: LED_CHD + desc: LED CHD diff --git a/src/lib/device/m2_dsdr/m2_dsdr_p.yaml b/src/lib/device/m2_dsdr/m2_dsdr_p.yaml index 67eae93e..940bceed 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_p.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_p.yaml @@ -16,6 +16,13 @@ data_width: 24 field_prefix: [ RegName ] field_macros: True +x-tdd-fdd-opts: &tdd-fdd-opts + 0b00: REV0_LNA_TO_RX_____REV2_SHUTDOWN + 0b01: REV0_LNA_TO_TDDSW__REV2_LNA_TO_LB + 0b10: REV0_LNA_TO_RX_____REV2_LNA_TO_TDDSW + 0b11: REV0_LNA_TO_TDDSW__REV2_LNA_TO_RX + + pages: - name: FPGA_GPO regs: @@ -39,15 +46,13 @@ pages: - bits: "5" name: EN_RX desc: Enable RX LNA & post-attenuator RX_RF amp - - bits: "3" - name: SW_HW_TDD_CTRL - desc: Hardware control of TRX antenna to TX/RX port based on burst boundaries. SW_PA_ONOFF, SW_RX_TDDFDD, SW_RXTX wont take effect in this mode - bits: "2" name: SW_PA_ONOFF desc: Route post-amped TX to RX, 0=PA->ANT, 1=PA->RX_LB - - bits: "1" + - bits: "3,1" name: SW_RX_TDDFDD - desc: RX TDD-FDD switch (0:FDD=ANT_RX->LNA, 1:TDD=TDD_SW->LNA) + desc: RX TDD-FDD switch + opts: *tdd-fdd-opts - bits: "0" name: SW_RXTX desc: Switch TRX antenna to TX(0) or RX(1) @@ -64,15 +69,13 @@ pages: - bits: "5" name: EN_RX desc: Enable RX LNA & post-attenuator RX_RF amp - - bits: "3" - name: SW_HW_TDD_CTRL - desc: Hardware control of TRX antenna to TX/RX port based on burst boundaries. SW_PA_ONOFF, SW_RX_TDDFDD, SW_RXTX wont take effect in this mode - bits: "2" name: SW_PA_ONOFF desc: Route post-amped TX to RX, 0=PA->ANT, 1=PA->RX_LB - - bits: "1" + - bits: "3,1" name: SW_RX_TDDFDD - desc: RX TDD-FDD switch (0:FDD=ANT_RX->LNA, 1:TDD=TDD_SW->LNA) + desc: RX TDD-FDD switch + opts: *tdd-fdd-opts - bits: "0" name: SW_RXTX desc: Switch TRX antenna to TX(0) or RX(1) @@ -89,15 +92,13 @@ pages: - bits: "5" name: EN_RX desc: Enable RX LNA & post-attenuator RX_RF amp - - bits: "3" - name: SW_HW_TDD_CTRL - desc: Hardware control of TRX antenna to TX/RX port based on burst boundaries. SW_PA_ONOFF, SW_RX_TDDFDD, SW_RXTX wont take effect in this mode - bits: "2" name: SW_PA_ONOFF desc: Route post-amped TX to RX, 0=PA->ANT, 1=PA->RX_LB - - bits: "1" + - bits: "3,1" name: SW_RX_TDDFDD - desc: RX TDD-FDD switch (0:FDD=ANT_RX->LNA, 1:TDD=TDD_SW->LNA) + desc: RX TDD-FDD switch + opts: *tdd-fdd-opts - bits: "0" name: SW_RXTX desc: Switch TRX antenna to TX(0) or RX(1) @@ -114,15 +115,13 @@ pages: - bits: "5" name: EN_RX desc: Enable RX LNA & post-attenuator RX_RF amp - - bits: "3" - name: SW_HW_TDD_CTRL - desc: Hardware control of TRX antenna to TX/RX port based on burst boundaries. SW_PA_ONOFF, SW_RX_TDDFDD, SW_RXTX wont take effect in this mode - bits: "2" name: SW_PA_ONOFF desc: Route post-amped TX to RX, 0=PA->ANT, 1=PA->RX_LB - - bits: "1" + - bits: "3,1" name: SW_RX_TDDFDD - desc: RX TDD-FDD switch (0:FDD=ANT_RX->LNA, 1:TDD=TDD_SW->LNA) + desc: RX TDD-FDD switch + opts: *tdd-fdd-opts - bits: "0" name: SW_RXTX desc: Switch TRX antenna to TX(0) or RX(1) diff --git a/src/lib/device/m2_dsdr/m2_dsdr_usr.yaml b/src/lib/device/m2_dsdr/m2_dsdr_usr.yaml index 7a281fd6..b384bd9d 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_usr.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_usr.yaml @@ -41,7 +41,17 @@ x-band-opts: &x-band-opts 0b01: BAND_2200_7200 0b10: BAND_AUTO_L 0b11: BAND_AUTO_H - + +x-rxband-opts: &x-rxband-opts + 0b000: BAND_400_3500 + 0b001: BAND_2200_7200 + 0b010: BAND_1580_2760_BP + 0b011: DISABLE + 0b100: BAND_AUTO_L + 0b101: BAND_AUTO_H + 0b110: BAND_AUTO_BP + 0b111: BAND_AUTO_DIS + pages: - name: FEUSR regs: @@ -65,22 +75,22 @@ pages: - addr: 0x41 name: RX_H_BAND fields: - - bits: "1:0" + - bits: "2:0" name: A - desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector - opts: *x-band-opts - - bits: "5:4" + desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector or Bypass_Rev2 + opts: *x-rxband-opts + - bits: "6:4" name: B - desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector - opts: *x-band-opts - - bits: "9:8" + desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector or Bypass_Rev2 + opts: *x-rxband-opts + - bits: "10:8" name: C - desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector - opts: *x-band-opts - - bits: "13:12" + desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector or Bypass_Rev2 + opts: *x-rxband-opts + - bits: "14:12" name: D - desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector - opts: *x-band-opts + desc: Band 2.2G to 7.2G or 0.4G to 3.5G selector or Bypass_Rev2 + opts: *x-rxband-opts # - addr: 0x42 name: RX_FILTER_BANK @@ -254,5 +264,20 @@ pages: name: D desc: FE LMS8001A TX high band 0-15 PA Gain # + - addr: 0x4C + name: PA_2ND_BP + fields: + - bits: "0" + name: A + desc: Bypass 2nd stage PA + - bits: "1" + name: B + desc: Bypass 2nd stage PA + - bits: "2" + name: C + desc: Bypass 2nd stage PA + - bits: "3" + name: D + desc: Bypass 2nd stage PA From cad9714c0f4f3e5a82f317529f2087a085b6a59e Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 28 Oct 2025 17:18:36 +0300 Subject: [PATCH 205/397] Add avx512 simd xdsp convs for (c)i12 formats --- src/lib/xdsp/conv_2cf32_ci12_2.c | 8 + src/lib/xdsp/conv_2ci16_ci12_2.c | 8 + src/lib/xdsp/conv_4cf32_ci12_2.c | 8 + src/lib/xdsp/conv_4ci16_ci12_2.c | 8 + src/lib/xdsp/conv_ci12_2cf32_2.c | 12 +- src/lib/xdsp/conv_ci12_2ci16_2.c | 8 + src/lib/xdsp/conv_ci12_4cf32_2.c | 8 + src/lib/xdsp/conv_ci12_4ci16_2.c | 8 + src/lib/xdsp/conv_f32_i12_2.c | 8 + src/lib/xdsp/conv_i12_f32_2.c | 18 +-- src/lib/xdsp/conv_i12_i16_2.c | 8 + src/lib/xdsp/conv_i16_i12_2.c | 8 + .../xdsp/templates/conv_2cf32_ci12_avx2.inc | 15 ++ src/lib/xdsp/templates/conv_2cf32_ci12_avx2.t | 41 +---- .../templates/conv_2cf32_ci12_avx512bw.inc | 15 ++ .../xdsp/templates/conv_2cf32_ci12_avx512bw.t | 64 ++++++++ .../templates/conv_2cf32_ci12_generic.inc | 21 +++ .../xdsp/templates/conv_2cf32_ci12_generic.t | 22 +-- .../xdsp/templates/conv_2ci16_ci12_avx2.inc | 15 ++ src/lib/xdsp/templates/conv_2ci16_ci12_avx2.t | 38 +---- .../xdsp/templates/conv_2ci16_ci12_avx512bw.t | 69 ++++++++ .../templates/conv_2ci16_ci12_generic.inc | 21 +++ .../xdsp/templates/conv_2ci16_ci12_generic.t | 22 +-- .../xdsp/templates/conv_4cf32_ci12_avx2.inc | 25 +++ src/lib/xdsp/templates/conv_4cf32_ci12_avx2.t | 57 +------ .../templates/conv_4cf32_ci12_avx512bw.inc | 22 +++ .../xdsp/templates/conv_4cf32_ci12_avx512bw.t | 81 ++++++++++ .../templates/conv_4cf32_ci12_generic.inc | 29 ++++ .../xdsp/templates/conv_4cf32_ci12_generic.t | 31 +--- src/lib/xdsp/templates/conv_4ci16_ci12_avx2.t | 31 +--- .../xdsp/templates/conv_4ci16_ci12_avx512bw.t | 118 ++++++++++++++ .../templates/conv_4ci16_ci12_generic.inc | 29 ++++ .../xdsp/templates/conv_4ci16_ci12_generic.t | 30 +--- src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t | 26 +-- .../xdsp/templates/conv_ci12_2cf32_avx512bw.t | 88 ++++++++++ .../templates/conv_ci12_2cf32_generic.inc | 25 +++ .../xdsp/templates/conv_ci12_2cf32_generic.t | 26 +-- src/lib/xdsp/templates/conv_ci12_2ci16_avx2.t | 15 +- .../xdsp/templates/conv_ci12_2ci16_avx512bw.t | 79 +++++++++ .../templates/conv_ci12_2ci16_generic.inc | 13 ++ .../xdsp/templates/conv_ci12_2ci16_generic.t | 14 +- .../xdsp/templates/conv_ci12_4cf32_avx2.inc | 97 +++++++++++ src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t | 132 +-------------- .../xdsp/templates/conv_ci12_4cf32_avx512bw.t | 86 ++++++++++ .../templates/conv_ci12_4cf32_generic.inc | 27 ++++ .../xdsp/templates/conv_ci12_4cf32_generic.t | 28 +--- .../xdsp/templates/conv_ci12_4ci16_avx2.inc | 35 ++++ src/lib/xdsp/templates/conv_ci12_4ci16_avx2.t | 80 +--------- .../xdsp/templates/conv_ci12_4ci16_avx512bw.t | 98 ++++++++++++ .../templates/conv_ci12_4ci16_generic.inc | 16 ++ .../xdsp/templates/conv_ci12_4ci16_generic.t | 19 +-- src/lib/xdsp/templates/conv_f32_i12_avx2.inc | 15 ++ src/lib/xdsp/templates/conv_f32_i12_avx2.t | 45 +----- .../xdsp/templates/conv_f32_i12_avx512bw.inc | 16 ++ .../xdsp/templates/conv_f32_i12_avx512bw.t | 61 +++++++ .../xdsp/templates/conv_f32_i12_generic.inc | 22 +++ src/lib/xdsp/templates/conv_f32_i12_generic.t | 23 +-- src/lib/xdsp/templates/conv_i12_f32_avx2.inc | 50 ++++++ src/lib/xdsp/templates/conv_i12_f32_avx2.t | 105 ++---------- .../xdsp/templates/conv_i12_f32_avx512bw.inc | 16 ++ .../xdsp/templates/conv_i12_f32_avx512bw.t | 70 ++++++++ .../xdsp/templates/conv_i12_f32_generic.inc | 42 +++++ src/lib/xdsp/templates/conv_i12_f32_generic.t | 151 +----------------- src/lib/xdsp/templates/conv_i12_i16_avx2.inc | 21 +++ src/lib/xdsp/templates/conv_i12_i16_avx2.t | 78 +++------ .../xdsp/templates/conv_i12_i16_avx512bw.inc | 23 +++ .../xdsp/templates/conv_i12_i16_avx512bw.t | 70 ++++++++ .../xdsp/templates/conv_i12_i16_generic.inc | 42 +++++ src/lib/xdsp/templates/conv_i12_i16_generic.t | 43 +---- src/lib/xdsp/templates/conv_i16_i12_avx2.t | 22 +-- .../xdsp/templates/conv_i16_i12_avx512bw.inc | 27 ++++ .../xdsp/templates/conv_i16_i12_avx512bw.t | 68 ++++++++ .../xdsp/templates/conv_i16_i12_generic.inc | 21 +++ src/lib/xdsp/templates/conv_i16_i12_generic.t | 22 +-- src/lib/xdsp/utests/conv_2cf32_ci12_utest.c | 3 +- src/lib/xdsp/utests/conv_2ci16_ci12_utest.c | 3 +- src/lib/xdsp/utests/conv_4cf32_ci12_utest.c | 3 +- src/lib/xdsp/utests/conv_4ci16_ci12_utest.c | 9 +- src/lib/xdsp/utests/conv_ci12_2cf32_utest.c | 4 +- src/lib/xdsp/utests/conv_ci12_2ci16_utest.c | 4 +- src/lib/xdsp/utests/conv_ci12_4cf32_utest.c | 6 +- src/lib/xdsp/utests/conv_ci12_4ci16_utest.c | 6 +- src/lib/xdsp/utests/conv_f32_i12_utest.c | 3 +- src/lib/xdsp/utests/conv_i12_f32_utest.c | 3 +- src/lib/xdsp/utests/conv_i12_i16_utest.c | 3 +- src/lib/xdsp/utests/conv_i16_i12_utest.c | 3 +- src/lib/xdsp/vbase.h | 7 + 87 files changed, 1860 insertions(+), 1060 deletions(-) create mode 100644 src/lib/xdsp/templates/conv_2cf32_ci12_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.inc create mode 100644 src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_2cf32_ci12_generic.inc create mode 100644 src/lib/xdsp/templates/conv_2ci16_ci12_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_2ci16_ci12_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_2ci16_ci12_generic.inc create mode 100644 src/lib/xdsp/templates/conv_4cf32_ci12_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.inc create mode 100644 src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_4cf32_ci12_generic.inc create mode 100644 src/lib/xdsp/templates/conv_4ci16_ci12_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_4ci16_ci12_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_ci12_2cf32_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_ci12_2ci16_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci12_4cf32_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci12_4ci16_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_ci12_4ci16_generic.inc create mode 100644 src/lib/xdsp/templates/conv_f32_i12_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_f32_i12_avx512bw.inc create mode 100644 src/lib/xdsp/templates/conv_f32_i12_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_f32_i12_generic.inc create mode 100644 src/lib/xdsp/templates/conv_i12_f32_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc create mode 100644 src/lib/xdsp/templates/conv_i12_f32_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_i12_f32_generic.inc create mode 100644 src/lib/xdsp/templates/conv_i12_i16_avx2.inc create mode 100644 src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc create mode 100644 src/lib/xdsp/templates/conv_i12_i16_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_i12_i16_generic.inc create mode 100644 src/lib/xdsp/templates/conv_i16_i12_avx512bw.inc create mode 100644 src/lib/xdsp/templates/conv_i16_i12_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_i16_i12_generic.inc diff --git a/src/lib/xdsp/conv_2cf32_ci12_2.c b/src/lib/xdsp/conv_2cf32_ci12_2.c index 75f1f48c..ec15fa56 100644 --- a/src/lib/xdsp/conv_2cf32_ci12_2.c +++ b/src/lib/xdsp/conv_2cf32_ci12_2.c @@ -11,6 +11,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_2cf32_ci12_generic.t" DECLARE_TR_FUNC_2_1(conv_2cf32_ci12_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_2cf32_ci12_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_2cf32_ci12_avx512bw.t" +DECLARE_TR_FUNC_2_1(conv_2cf32_ci12_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_2cf32_ci12_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -32,6 +39,7 @@ conv_function_t conv_get_2cf32_ci12_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_2cf32_ci12_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_2cf32_ci12_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_2cf32_ci12_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_2cf32_ci12_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_2ci16_ci12_2.c b/src/lib/xdsp/conv_2ci16_ci12_2.c index c358452d..1609d4b3 100644 --- a/src/lib/xdsp/conv_2ci16_ci12_2.c +++ b/src/lib/xdsp/conv_2ci16_ci12_2.c @@ -9,6 +9,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_2ci16_ci12_generic.t" DECLARE_TR_FUNC_2_1(conv_2ci16_ci12_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_2ci16_ci12_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_2ci16_ci12_avx512bw.t" +DECLARE_TR_FUNC_2_1(conv_2ci16_ci12_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_2ci16_ci12_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -30,6 +37,7 @@ conv_function_t conv_get_2ci16_ci12_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_2ci16_ci12_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_2ci16_ci12_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_2ci16_ci12_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_2ci16_ci12_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_4cf32_ci12_2.c b/src/lib/xdsp/conv_4cf32_ci12_2.c index 9d141c35..b4c3ec3e 100644 --- a/src/lib/xdsp/conv_4cf32_ci12_2.c +++ b/src/lib/xdsp/conv_4cf32_ci12_2.c @@ -11,6 +11,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_4cf32_ci12_generic.t" DECLARE_TR_FUNC_4_1(conv_4cf32_ci12_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_4cf32_ci12_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_4cf32_ci12_avx512bw.t" +DECLARE_TR_FUNC_4_1(conv_4cf32_ci12_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_4cf32_ci12_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -32,6 +39,7 @@ conv_function_t conv_get_4cf32_ci12_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_4cf32_ci12_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_4cf32_ci12_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_4cf32_ci12_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_4cf32_ci12_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_4ci16_ci12_2.c b/src/lib/xdsp/conv_4ci16_ci12_2.c index 26e69ccc..18e32f94 100644 --- a/src/lib/xdsp/conv_4ci16_ci12_2.c +++ b/src/lib/xdsp/conv_4ci16_ci12_2.c @@ -9,6 +9,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_4ci16_ci12_generic.t" DECLARE_TR_FUNC_4_1(conv_4ci16_ci12_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_4ci16_ci12_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_4ci16_ci12_avx512bw.t" +DECLARE_TR_FUNC_4_1(conv_4ci16_ci12_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_4ci16_ci12_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -30,6 +37,7 @@ conv_function_t conv_get_4ci16_ci12_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_4ci16_ci12_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_4ci16_ci12_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_4ci16_ci12_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_4ci16_ci12_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_ci12_2cf32_2.c b/src/lib/xdsp/conv_ci12_2cf32_2.c index 49f21f87..8bf8898e 100644 --- a/src/lib/xdsp/conv_ci12_2cf32_2.c +++ b/src/lib/xdsp/conv_ci12_2cf32_2.c @@ -23,11 +23,11 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci12_2cf32_generic.t" DECLARE_TR_FUNC_1_2(conv_ci12_2cf32_generic) -#ifdef WVLT_SSSE3 -#define TEMPLATE_FUNC_NAME conv_ci12_2cf32_ssse3 -VWLT_ATTRIBUTE(optimize("-O3"), target("ssse3")) -#include "templates/conv_ci12_2cf32_ssse3.t" -DECLARE_TR_FUNC_1_2(conv_ci12_2cf32_ssse3) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_ci12_2cf32_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw,avx512vl")) +#include "templates/conv_ci12_2cf32_avx512bw.t" +DECLARE_TR_FUNC_1_2(conv_ci12_2cf32_avx512bw) #endif #ifdef WVLT_AVX2 @@ -50,8 +50,8 @@ conv_function_t conv_get_ci12_2cf32_c(generic_opts_t cpu_cap, const char** sfunc conv_function_t fn; SELECT_GENERIC_FN(fn, fname, tr_conv_ci12_2cf32_generic, cpu_cap); - SELECT_SSSE3_FN(fn, fname, tr_conv_ci12_2cf32_ssse3, cpu_cap); SELECT_AVX_FN(fn, fname, tr_conv_ci12_2cf32_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_ci12_2cf32_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_ci12_2cf32_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_ci12_2ci16_2.c b/src/lib/xdsp/conv_ci12_2ci16_2.c index e0102066..078590c2 100644 --- a/src/lib/xdsp/conv_ci12_2ci16_2.c +++ b/src/lib/xdsp/conv_ci12_2ci16_2.c @@ -10,6 +10,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci12_2ci16_generic.t" DECLARE_TR_FUNC_1_2(conv_ci12_2ci16_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_ci12_2ci16_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw,avx512vl")) +#include "templates/conv_ci12_2ci16_avx512bw.t" +DECLARE_TR_FUNC_1_2(conv_ci12_2ci16_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_ci12_2ci16_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -31,6 +38,7 @@ conv_function_t conv_get_ci12_2ci16_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_ci12_2ci16_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_ci12_2ci16_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_ci12_2ci16_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_ci12_2ci16_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_ci12_4cf32_2.c b/src/lib/xdsp/conv_ci12_4cf32_2.c index 243aa31c..b51688e8 100644 --- a/src/lib/xdsp/conv_ci12_4cf32_2.c +++ b/src/lib/xdsp/conv_ci12_4cf32_2.c @@ -11,6 +11,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci12_4cf32_generic.t" DECLARE_TR_FUNC_1_4(conv_ci12_4cf32_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_ci12_4cf32_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_ci12_4cf32_avx512bw.t" +DECLARE_TR_FUNC_1_4(conv_ci12_4cf32_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_ci12_4cf32_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -32,6 +39,7 @@ conv_function_t conv_get_ci12_4cf32_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_ci12_4cf32_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_ci12_4cf32_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_ci12_4cf32_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_ci12_4cf32_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_ci12_4ci16_2.c b/src/lib/xdsp/conv_ci12_4ci16_2.c index 3acb37f3..4f8a3361 100644 --- a/src/lib/xdsp/conv_ci12_4ci16_2.c +++ b/src/lib/xdsp/conv_ci12_4ci16_2.c @@ -9,6 +9,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci12_4ci16_generic.t" DECLARE_TR_FUNC_1_4(conv_ci12_4ci16_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_ci12_4ci16_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw,avx512vl")) +#include "templates/conv_ci12_4ci16_avx512bw.t" +DECLARE_TR_FUNC_1_4(conv_ci12_4ci16_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_ci12_4ci16_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -30,6 +37,7 @@ conv_function_t conv_get_ci12_4ci16_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_ci12_4ci16_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_ci12_4ci16_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_ci12_4ci16_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_ci12_4ci16_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_f32_i12_2.c b/src/lib/xdsp/conv_f32_i12_2.c index ee5dea83..7e7443ff 100644 --- a/src/lib/xdsp/conv_f32_i12_2.c +++ b/src/lib/xdsp/conv_f32_i12_2.c @@ -11,6 +11,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_f32_i12_generic.t" DECLARE_TR_FUNC_1_1(conv_f32_i12_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_f32_i12_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_f32_i12_avx512bw.t" +DECLARE_TR_FUNC_1_1(conv_f32_i12_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_f32_i12_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -32,6 +39,7 @@ conv_function_t conv_get_f32_i12_c(generic_opts_t cpu_cap, const char** sfunc) SELECT_GENERIC_FN(fn, fname, tr_conv_f32_i12_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_f32_i12_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_f32_i12_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_f32_i12_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_i12_f32_2.c b/src/lib/xdsp/conv_i12_f32_2.c index 1b5ae9ce..a5903943 100644 --- a/src/lib/xdsp/conv_i12_f32_2.c +++ b/src/lib/xdsp/conv_i12_f32_2.c @@ -23,13 +23,11 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_i12_f32_generic.t" DECLARE_TR_FUNC_1_1(conv_i12_f32_generic) -#if 0 -#ifdef WVLT_SSSE3 -#define TEMPLATE_FUNC_NAME conv_i12_f32_ssse3 -VWLT_ATTRIBUTE(optimize("-O3"), target("ssse3")) -#include "templates/conv_i12_f32_ssse3.t" -DECLARE_TR_FUNC_1_1(conv_i12_f32_ssse3) -#endif +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_i12_f32_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_i12_f32_avx512bw.t" +DECLARE_TR_FUNC_1_1(conv_i12_f32_avx512bw) #endif #ifdef WVLT_AVX2 @@ -44,7 +42,7 @@ DECLARE_TR_FUNC_1_1(conv_i12_f32_avx2) VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_i12_f32_neon.t" DECLARE_TR_FUNC_1_1(conv_i12_f32_neon) -#endif //WVLT_NEON +#endif conv_function_t conv_get_i12_f32_c(generic_opts_t cpu_cap, const char** sfunc) { @@ -52,10 +50,8 @@ conv_function_t conv_get_i12_f32_c(generic_opts_t cpu_cap, const char** sfunc) conv_function_t fn; SELECT_GENERIC_FN(fn, fname, tr_conv_i12_f32_generic, cpu_cap); -#if 0 - SELECT_SSSE3_FN(fn, fname, tr_conv_i12_f32_ssse3, cpu_cap); -#endif SELECT_AVX2_FN(fn, fname, tr_conv_i12_f32_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_i12_f32_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_i12_f32_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_i12_i16_2.c b/src/lib/xdsp/conv_i12_i16_2.c index 9e0013aa..4366927e 100644 --- a/src/lib/xdsp/conv_i12_i16_2.c +++ b/src/lib/xdsp/conv_i12_i16_2.c @@ -9,6 +9,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_i12_i16_generic.t" DECLARE_TR_FUNC_1_1(conv_i12_i16_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_i12_i16_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_i12_i16_avx512bw.t" +DECLARE_TR_FUNC_1_1(conv_i12_i16_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_i12_i16_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -30,6 +37,7 @@ conv_function_t conv_get_i12_i16_c(generic_opts_t cpu_cap, const char** sfunc) SELECT_GENERIC_FN(fn, fname, tr_conv_i12_i16_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_i12_i16_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_i12_i16_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_i12_i16_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_i16_i12_2.c b/src/lib/xdsp/conv_i16_i12_2.c index 8f05d5d9..215fb081 100644 --- a/src/lib/xdsp/conv_i16_i12_2.c +++ b/src/lib/xdsp/conv_i16_i12_2.c @@ -9,6 +9,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_i16_i12_generic.t" DECLARE_TR_FUNC_1_1(conv_i16_i12_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_i16_i12_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_i16_i12_avx512bw.t" +DECLARE_TR_FUNC_1_1(conv_i16_i12_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_i16_i12_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -30,6 +37,7 @@ conv_function_t conv_get_i16_i12_c(generic_opts_t cpu_cap, const char** sfunc) SELECT_GENERIC_FN(fn, fname, tr_conv_i16_i12_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_i16_i12_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_i16_i12_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_i16_i12_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/templates/conv_2cf32_ci12_avx2.inc b/src/lib/xdsp/templates/conv_2cf32_ci12_avx2.inc new file mode 100644 index 00000000..9169c888 --- /dev/null +++ b/src/lib/xdsp/templates/conv_2cf32_ci12_avx2.inc @@ -0,0 +1,15 @@ +const __m256 scale = _mm256_set1_ps(1.0f / CONV_SCALE); + +#define CONVERT_2F32_I12_BLOCK(v0, v1) \ +{ \ + v0 = _mm256_mul_ps(v0, scale); \ + v1 = _mm256_mul_ps(v1, scale); \ +\ + __m256i i0 = _mm256_cvtps_epi32(v0); \ + __m256i i1 = _mm256_cvtps_epi32(v1); \ +\ + __m256i ii0 = _mm256_packs_epi32(i0, i1); \ + ii0 = _mm256_shuffle_epi32(ii0, _MM_SHUFFLE(3,1,2,0)); \ +\ + CONVERT_I16_I12_BLOCK(ii0, out64); \ +} diff --git a/src/lib/xdsp/templates/conv_2cf32_ci12_avx2.t b/src/lib/xdsp/templates/conv_2cf32_ci12_avx2.t index 04789485..afdda200 100644 --- a/src/lib/xdsp/templates/conv_2cf32_ci12_avx2.t +++ b/src/lib/xdsp/templates/conv_2cf32_ci12_avx2.t @@ -13,24 +13,8 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, const float* indata_1 = (const float*)indata_1_p; uint64_t *out64 = (uint64_t*)outdata_p; - const __m256 scale = _mm256_set1_ps(1.0f / CONV_SCALE); - #include "conv_i16_i12_avx2.inc" - -#define CONVERT_2F32_I12_BLOCK(v0, v1) \ - { \ - v0 = _mm256_mul_ps(v0, scale); \ - v1 = _mm256_mul_ps(v1, scale); \ - \ - __m256i i0 = _mm256_cvtps_epi32(v0); \ - __m256i i1 = _mm256_cvtps_epi32(v1); \ - \ - __m256i ii0 = _mm256_packs_epi32(i0, i1); \ - ii0 = _mm256_shuffle_epi32(ii0, _MM_SHUFFLE(3,1,2,0)); \ - \ - CONVERT_I16_I12_BLOCK(ii0, out64); \ - } -// CONVERT_2F32_I12_BLOCK end +#include "conv_2cf32_ci12_avx2.inc" __m256 v0, v1, v2, v3; @@ -64,27 +48,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, #define I16RND(x) x > 0 ? (int16_t)(x + 0.5f) : (int16_t)(x - 0.5f) uint8_t* outdata = (uint8_t*)out64; - - for (; i >= 16; i -= 16) { - - float f0 = *(indata_0++) / CONV_SCALE; - float f1 = *(indata_0++) / CONV_SCALE; - float f2 = *(indata_1++) / CONV_SCALE; - float f3 = *(indata_1++) / CONV_SCALE; - - wu_i16u32_t a0 = {{I16RND(f0), I16RND(f1)}}; - wu_i16u32_t a1 = {{I16RND(f2), I16RND(f3)}}; - - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - - *(outdata++) = c0.b[1]; - *(outdata++) = c0.b[2]; - *(outdata++) = c0.b[3]; - - *(outdata++) = c1.b[1]; - *(outdata++) = c1.b[2]; - *(outdata++) = c1.b[3]; - } + #include "conv_2cf32_ci12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.inc b/src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.inc new file mode 100644 index 00000000..b7049f97 --- /dev/null +++ b/src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.inc @@ -0,0 +1,15 @@ +const __m512 scale = _mm512_set1_ps(1.0f / CONV_SCALE); + +#define CONVERT_2F32_I12_BLOCK(v0, v1) \ +{ \ + v0 = _mm512_mul_ps(v0, scale); \ + v1 = _mm512_mul_ps(v1, scale); \ +\ + __m512i i0 = _mm512_cvtps_epi32(v0); \ + __m512i i1 = _mm512_cvtps_epi32(v1); \ +\ + __m512i ii0 = _mm512_packs_epi32(i0, i1); \ + ii0 = _mm512_shuffle_epi32(ii0, _MM_SHUFFLE(3,1,2,0)); \ +\ + CONVERT_I16_I12_BLOCK(ii0, out64); \ +} diff --git a/src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.t b/src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.t new file mode 100644 index 00000000..9f52f690 --- /dev/null +++ b/src/lib/xdsp/templates/conv_2cf32_ci12_avx512bw.t @@ -0,0 +1,64 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 8 / 3) < i) + i = (outdatabsz * 8 / 3); + + const float* indata_0 = (const float*)indata_0_p; + const float* indata_1 = (const float*)indata_1_p; + uint64_t *out64 = (uint64_t*)outdata_p; + + //AVX512 block + { + #include "conv_i16_i12_avx512bw.inc" + #include "conv_2cf32_ci12_avx512bw.inc" + + __m512 v0, v1; + + for (; i >= 64*2; i -= 64*2) + { + v0 = _mm512_loadu_ps(indata_0 + 0); + v1 = _mm512_loadu_ps(indata_1 + 0); + indata_0 += 16; + indata_1 += 16; + CONVERT_2F32_I12_BLOCK(v0, v1); + } + + #undef CONVERT_2F32_I12_BLOCK + #undef CONVERT_I16_I12_BLOCK + } + + //AVX2 block + { + #include "conv_i16_i12_avx2.inc" + #include "conv_2cf32_ci12_avx2.inc" + + if(i >= 32*2) + { + __m256 v0 = _mm256_loadu_ps(indata_0 + 0); + __m256 v1 = _mm256_loadu_ps(indata_1 + 0); + indata_0 += 8; + indata_1 += 8; + i -= 32*2; + CONVERT_2F32_I12_BLOCK(v0, v1); + } + + #undef CONVERT_2F32_I12_BLOCK + #undef CONVERT_I16_I12_BLOCK + } + + //Generic block + { + #undef I16RND + #define I16RND(x) x > 0 ? (int16_t)(x + 0.5f) : (int16_t)(x - 0.5f) + + uint8_t* outdata = (uint8_t*)out64; + #include "conv_2cf32_ci12_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_2cf32_ci12_generic.inc b/src/lib/xdsp/templates/conv_2cf32_ci12_generic.inc new file mode 100644 index 00000000..ef99f9b2 --- /dev/null +++ b/src/lib/xdsp/templates/conv_2cf32_ci12_generic.inc @@ -0,0 +1,21 @@ +for (; i >= 16; i -= 16) { + + float f0 = *(indata_0++) / CONV_SCALE; + float f1 = *(indata_0++) / CONV_SCALE; + float f2 = *(indata_1++) / CONV_SCALE; + float f3 = *(indata_1++) / CONV_SCALE; + + wu_i16u32_t a0 = {{I16RND(f0), I16RND(f1)}}; + wu_i16u32_t a1 = {{I16RND(f2), I16RND(f3)}}; + + wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; + wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; + + *(outdata++) = c0.b[1]; + *(outdata++) = c0.b[2]; + *(outdata++) = c0.b[3]; + + *(outdata++) = c1.b[1]; + *(outdata++) = c1.b[2]; + *(outdata++) = c1.b[3]; +} diff --git a/src/lib/xdsp/templates/conv_2cf32_ci12_generic.t b/src/lib/xdsp/templates/conv_2cf32_ci12_generic.t index 4885d950..c712a3b9 100644 --- a/src/lib/xdsp/templates/conv_2cf32_ci12_generic.t +++ b/src/lib/xdsp/templates/conv_2cf32_ci12_generic.t @@ -13,26 +13,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, const float* indata_1 = (const float*)indata_1_p; uint8_t* outdata = (uint8_t*)outdata_p; - for (; i >= 16; i -= 16) { - - float f0 = *(indata_0++) / CONV_SCALE; - float f1 = *(indata_0++) / CONV_SCALE; - float f2 = *(indata_1++) / CONV_SCALE; - float f3 = *(indata_1++) / CONV_SCALE; - - wu_i16u32_t a0 = {{I16RND(f0), I16RND(f1)}}; - wu_i16u32_t a1 = {{I16RND(f2), I16RND(f3)}}; - - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - - *(outdata++) = c0.b[1]; - *(outdata++) = c0.b[2]; - *(outdata++) = c0.b[3]; - - *(outdata++) = c1.b[1]; - *(outdata++) = c1.b[2]; - *(outdata++) = c1.b[3]; - } + #include "conv_2cf32_ci12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_2ci16_ci12_avx2.inc b/src/lib/xdsp/templates/conv_2ci16_ci12_avx2.inc new file mode 100644 index 00000000..90cf0f5a --- /dev/null +++ b/src/lib/xdsp/templates/conv_2ci16_ci12_avx2.inc @@ -0,0 +1,15 @@ +#define STORE_2CI16_CI12_BLOCK(v0, v1) \ +{ \ + __m256i i0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(v0), _mm256_castsi256_pd(v1), 0b0000)); \ + __m256i i1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(v0), _mm256_castsi256_pd(v1), 0b1111)); \ +\ + i0 = _mm256_shuffle_epi32(i0, _MM_SHUFFLE(3,1,2,0)); \ + i1 = _mm256_shuffle_epi32(i1, _MM_SHUFFLE(3,1,2,0)); \ +\ + __m256i z0 = _mm256_permute2x128_si256(i0, i1, 0b00100000); \ + __m256i z1 = _mm256_permute2x128_si256(i0, i1, 0b00110001); \ +\ + CONVERT_I16_I12_BLOCK(z0, out64); \ + CONVERT_I16_I12_BLOCK(z1, out64); \ +} +// STORE_2CI16_CI12_BLOCK end \ No newline at end of file diff --git a/src/lib/xdsp/templates/conv_2ci16_ci12_avx2.t b/src/lib/xdsp/templates/conv_2ci16_ci12_avx2.t index c5fa0aad..3f7fde16 100644 --- a/src/lib/xdsp/templates/conv_2ci16_ci12_avx2.t +++ b/src/lib/xdsp/templates/conv_2ci16_ci12_avx2.t @@ -14,22 +14,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, uint64_t *out64 = (uint64_t*)outdata_p; #include "conv_i16_i12_avx2.inc" - -#define STORE_2CI16_CI12_BLOCK(v0, v1) \ - { \ - __m256i i0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(v0), _mm256_castsi256_pd(v1), 0b0000)); \ - __m256i i1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(v0), _mm256_castsi256_pd(v1), 0b1111)); \ - \ - i0 = _mm256_shuffle_epi32(i0, _MM_SHUFFLE(3,1,2,0)); \ - i1 = _mm256_shuffle_epi32(i1, _MM_SHUFFLE(3,1,2,0)); \ - \ - __m256i z0 = _mm256_permute2x128_si256(i0, i1, 0b00100000); \ - __m256i z1 = _mm256_permute2x128_si256(i0, i1, 0b00110001); \ - \ - CONVERT_I16_I12_BLOCK(z0, out64); \ - CONVERT_I16_I12_BLOCK(z1, out64); \ - } -// STORE_2CI16_CI12_BLOCK end +#include "conv_2ci16_ci12_avx2.inc" __m256i v0, v1, v2, v3; @@ -61,26 +46,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, uint8_t* outdata = (uint8_t*)out64; - for (; i >= 8; i -= 8) { - - const int16_t i0 = *indata_0++; - const int16_t q0 = *indata_0++; - const int16_t i1 = *indata_1++; - const int16_t q1 = *indata_1++; - - wu_i16u32_t a0 = {{i0, q0}}; - wu_i16u32_t a1 = {{i1, q1}}; +#include "conv_2ci16_ci12_generic.inc" - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - - *(outdata++) = c0.b[1]; - *(outdata++) = c0.b[2]; - *(outdata++) = c0.b[3]; - - *(outdata++) = c1.b[1]; - *(outdata++) = c1.b[2]; - *(outdata++) = c1.b[3]; - } } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_2ci16_ci12_avx512bw.t b/src/lib/xdsp/templates/conv_2ci16_ci12_avx512bw.t new file mode 100644 index 00000000..6fff0d95 --- /dev/null +++ b/src/lib/xdsp/templates/conv_2ci16_ci12_avx512bw.t @@ -0,0 +1,69 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 4 / 3) < i) + i = (outdatabsz * 4 / 3); + + const int16_t* indata_0 = (const int16_t*)indata_0_p; + const int16_t* indata_1 = (const int16_t*)indata_1_p; + uint64_t *out64 = (uint64_t*)outdata_p; + + //AVX512 block + { + #include "conv_i16_i12_avx512bw.inc" + + const __m512i imask0 = _mm512_set_epi32(23, 7,22, 6, 21, 5,20, 4, 19, 3,18, 2, 17, 1,16, 0); + const __m512i imask1 = _mm512_set_epi32(31,15,30,14, 29,13,28,12, 27,11,26,10, 25, 9,24, 8); + __m512i v0, v1; + + for (; i >= 64*2; i -= 64*2) + { + v0 = _mm512_loadu_si512((__m512i*)indata_0); + v1 = _mm512_loadu_si512((__m512i*)indata_1); + indata_0 += 32; + indata_1 += 32; + + __m512i z0 = _mm512_permutex2var_epi32(v0, imask0, v1); + __m512i z1 = _mm512_permutex2var_epi32(v0, imask1, v1); + + CONVERT_I16_I12_BLOCK(z0, out64); + CONVERT_I16_I12_BLOCK(z1, out64); + } + + #undef CONVERT_I16_I12_BLOCK + } + + //AVX2 block + { + #include "conv_i16_i12_avx2.inc" + #include "conv_2ci16_ci12_avx2.inc" + + __m256i v0, v1; + + if(i >= 32*2) + { + v0 = _mm256_loadu_si256((__m256i*)indata_0); + v1 = _mm256_loadu_si256((__m256i*)indata_1); + indata_0 += 16; + indata_1 += 16; + i -= 64; + + STORE_2CI16_CI12_BLOCK(v0, v1); + } + + #undef STORE_2CI16_CI12_BLOCK + #undef CONVERT_I16_I12_BLOCK + } + + //Generic block + { + uint8_t* outdata = (uint8_t*)out64; + #include "conv_2ci16_ci12_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_2ci16_ci12_generic.inc b/src/lib/xdsp/templates/conv_2ci16_ci12_generic.inc new file mode 100644 index 00000000..8fd1a002 --- /dev/null +++ b/src/lib/xdsp/templates/conv_2ci16_ci12_generic.inc @@ -0,0 +1,21 @@ +for (; i >= 8; i -= 8) { + + const int16_t i0 = *indata_0++; + const int16_t q0 = *indata_0++; + const int16_t i1 = *indata_1++; + const int16_t q1 = *indata_1++; + + wu_i16u32_t a0 = {{i0, q0}}; + wu_i16u32_t a1 = {{i1, q1}}; + + wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; + wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; + + *(outdata++) = c0.b[1]; + *(outdata++) = c0.b[2]; + *(outdata++) = c0.b[3]; + + *(outdata++) = c1.b[1]; + *(outdata++) = c1.b[2]; + *(outdata++) = c1.b[3]; +} diff --git a/src/lib/xdsp/templates/conv_2ci16_ci12_generic.t b/src/lib/xdsp/templates/conv_2ci16_ci12_generic.t index cf0d764b..28371410 100644 --- a/src/lib/xdsp/templates/conv_2ci16_ci12_generic.t +++ b/src/lib/xdsp/templates/conv_2ci16_ci12_generic.t @@ -13,26 +13,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, const int16_t* indata_1 = (const int16_t*)indata_1_p; uint8_t* outdata = (uint8_t*)outdata_p; - for (; i >= 8; i -= 8) { - - const int16_t i0 = *indata_0++; - const int16_t q0 = *indata_0++; - const int16_t i1 = *indata_1++; - const int16_t q1 = *indata_1++; - - wu_i16u32_t a0 = {{i0, q0}}; - wu_i16u32_t a1 = {{i1, q1}}; - - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - - *(outdata++) = c0.b[1]; - *(outdata++) = c0.b[2]; - *(outdata++) = c0.b[3]; - - *(outdata++) = c1.b[1]; - *(outdata++) = c1.b[2]; - *(outdata++) = c1.b[3]; - } + #include "conv_2ci16_ci12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_4cf32_ci12_avx2.inc b/src/lib/xdsp/templates/conv_4cf32_ci12_avx2.inc new file mode 100644 index 00000000..0c6bd4b3 --- /dev/null +++ b/src/lib/xdsp/templates/conv_4cf32_ci12_avx2.inc @@ -0,0 +1,25 @@ +const __m256 scale = _mm256_set1_ps(1.0f / CONV_SCALE); + +#define CONVERT_4CF32_CI12_BLOCK(f0, f1, f2, f3) \ +{ \ + __m256i i0 = _mm256_cvtps_epi32(_mm256_mul_ps(f0, scale)); \ + __m256i i1 = _mm256_cvtps_epi32(_mm256_mul_ps(f1, scale)); \ + __m256i i2 = _mm256_cvtps_epi32(_mm256_mul_ps(f2, scale)); \ + __m256i i3 = _mm256_cvtps_epi32(_mm256_mul_ps(f3, scale)); \ + \ + /* 4-way CF32 deinterleave (see conv_4cf32_ci16_avx2.t */ \ + \ + __m256i ii0 = _mm256_shuffle_epi32(_mm256_packs_epi32(i0, i1), _MM_SHUFFLE(3,1,2,0)); \ + __m256i ii1 = _mm256_shuffle_epi32(_mm256_packs_epi32(i2, i3), _MM_SHUFFLE(3,1,2,0)); \ + \ + __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(ii0), _mm256_castsi256_pd(ii1), 0b0000)); \ + __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(ii0), _mm256_castsi256_pd(ii1), 0b1111)); \ + \ + __m256i d0 = _mm256_permute2x128_si256(z0, z1, 0b00100000); \ + __m256i d1 = _mm256_permute2x128_si256(z0, z1, 0b00110001); \ + \ + /* Convert linear data to CI12 */ \ + \ + CONVERT_I16_I12_BLOCK(d0, out64); \ + CONVERT_I16_I12_BLOCK(d1, out64); \ +} diff --git a/src/lib/xdsp/templates/conv_4cf32_ci12_avx2.t b/src/lib/xdsp/templates/conv_4cf32_ci12_avx2.t index d95f24f3..6e93f6b2 100644 --- a/src/lib/xdsp/templates/conv_4cf32_ci12_avx2.t +++ b/src/lib/xdsp/templates/conv_4cf32_ci12_avx2.t @@ -18,9 +18,8 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, uint64_t *out64 = (uint64_t*)outdata_p; - const __m256 scale = _mm256_set1_ps(1.0f / CONV_SCALE); - #include "conv_i16_i12_avx2.inc" +#include "conv_4cf32_ci12_avx2.inc" __m256 f0, f1, f2, f3; @@ -31,70 +30,22 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, f2 = _mm256_loadu_ps(indata_2); f3 = _mm256_loadu_ps(indata_3); - __m256i i0 = _mm256_cvtps_epi32(_mm256_mul_ps(f0, scale)); - __m256i i1 = _mm256_cvtps_epi32(_mm256_mul_ps(f1, scale)); - __m256i i2 = _mm256_cvtps_epi32(_mm256_mul_ps(f2, scale)); - __m256i i3 = _mm256_cvtps_epi32(_mm256_mul_ps(f3, scale)); - - /* 4-way CF32 deinterleave (see conv_4cf32_ci16_avx2.t */ - - __m256i ii0 = _mm256_shuffle_epi32(_mm256_packs_epi32(i0, i1), _MM_SHUFFLE(3,1,2,0)); - __m256i ii1 = _mm256_shuffle_epi32(_mm256_packs_epi32(i2, i3), _MM_SHUFFLE(3,1,2,0)); - - __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(ii0), _mm256_castsi256_pd(ii1), 0b0000)); - __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(ii0), _mm256_castsi256_pd(ii1), 0b1111)); - - __m256i d0 = _mm256_permute2x128_si256(z0, z1, 0b00100000); - __m256i d1 = _mm256_permute2x128_si256(z0, z1, 0b00110001); - - /* Convert linear data to CI12 */ - - CONVERT_I16_I12_BLOCK(d0, out64); - CONVERT_I16_I12_BLOCK(d1, out64); + CONVERT_4CF32_CI12_BLOCK(f0, f1, f2, f3); indata_0 += 8; indata_1 += 8; indata_2 += 8; indata_3 += 8; - i -= 32*4; } +#undef CONVERT_4CF32_CI12_BLOCK #undef CONVERT_I16_I12_BLOCK #undef I16RND #define I16RND(x) x > 0 ? (int16_t)(x + 0.5f) : (int16_t)(x - 0.5f) uint8_t* outdata = (uint8_t*)out64; - - for (; i >= 32; i -= 32) { - - float f0 = *(indata_0++) / CONV_SCALE; - float f1 = *(indata_0++) / CONV_SCALE; - float f2 = *(indata_1++) / CONV_SCALE; - float f3 = *(indata_1++) / CONV_SCALE; - float f4 = *(indata_2++) / CONV_SCALE; - float f5 = *(indata_2++) / CONV_SCALE; - float f6 = *(indata_3++) / CONV_SCALE; - float f7 = *(indata_3++) / CONV_SCALE; - - wu_i16u32_t a0 = {{I16RND(f0), I16RND(f1)}}; - wu_i16u32_t a1 = {{I16RND(f2), I16RND(f3)}}; - wu_i16u32_t a2 = {{I16RND(f4), I16RND(f5)}}; - wu_i16u32_t a3 = {{I16RND(f6), I16RND(f7)}}; - - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - wu_u32b_t c2 = {(a2.u & 0xfff00000) | ((a2.u << 4) & 0x000fff00)}; - wu_u32b_t c3 = {(a3.u & 0xfff00000) | ((a3.u << 4) & 0x000fff00)}; - - const wu_u32b_t arr[] = {c0, c1, c2, c3}; - for(unsigned j = 0; j < 4; ++j) - { - *(outdata++) = arr[j].b[1]; - *(outdata++) = arr[j].b[2]; - *(outdata++) = arr[j].b[3]; - } - } + #include "conv_4cf32_ci12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.inc b/src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.inc new file mode 100644 index 00000000..5d2c54d8 --- /dev/null +++ b/src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.inc @@ -0,0 +1,22 @@ +const __m512 scale = _mm512_set1_ps(1.0f / CONV_SCALE); +const __m512i imask0 = _mm512_set_epi32(23,21,7,5, 22,20,6,4, 19,17,3,1, 18,16,2,0); +const __m512i imask1 = _mm512_set_epi32(31,29,15,13, 30,28,14,12, 27,25,11,9, 26,24,10,8); + +#define CONVERT_4CF32_CI12_BLOCK(f0, f1, f2, f3) \ +{ \ + __m512i i0 = _mm512_cvtps_epi32(_mm512_mul_ps(f0, scale)); \ + __m512i i1 = _mm512_cvtps_epi32(_mm512_mul_ps(f1, scale)); \ + __m512i i2 = _mm512_cvtps_epi32(_mm512_mul_ps(f2, scale)); \ + __m512i i3 = _mm512_cvtps_epi32(_mm512_mul_ps(f3, scale)); \ + \ + __m512i ii0 = _mm512_packs_epi32(i0, i1); \ + __m512i ii1 = _mm512_packs_epi32(i2, i3); \ + \ + __m512i x0 = _mm512_permutex2var_epi32(ii0, imask0, ii1); \ + __m512i x1 = _mm512_permutex2var_epi32(ii0, imask1, ii1); \ + \ + /* Convert linear data to CI12 */ \ + \ + CONVERT_I16_I12_BLOCK(x0, out64); \ + CONVERT_I16_I12_BLOCK(x1, out64); \ +} diff --git a/src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.t b/src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.t new file mode 100644 index 00000000..b04a426f --- /dev/null +++ b/src/lib/xdsp/templates/conv_4cf32_ci12_avx512bw.t @@ -0,0 +1,81 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + const void *__restrict indata_2_p, + const void *__restrict indata_3_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 8 / 3) < i) + i = (outdatabsz * 8 / 3); + + const float* indata_0 = (const float*)indata_0_p; + const float* indata_1 = (const float*)indata_1_p; + const float* indata_2 = (const float*)indata_2_p; + const float* indata_3 = (const float*)indata_3_p; + + uint64_t *out64 = (uint64_t*)outdata_p; + + //AVX512 block + { + #include "conv_i16_i12_avx512bw.inc" + #include "conv_4cf32_ci12_avx512bw.inc" + + __m512 f0, f1, f2, f3; + + for(; i >= 64*4; i -= 64*4) + { + f0 = _mm512_loadu_ps(indata_0); + f1 = _mm512_loadu_ps(indata_1); + f2 = _mm512_loadu_ps(indata_2); + f3 = _mm512_loadu_ps(indata_3); + + CONVERT_4CF32_CI12_BLOCK(f0, f1, f2, f3); + + indata_0 += 16; + indata_1 += 16; + indata_2 += 16; + indata_3 += 16; + } + + #undef CONVERT_4CF32_CI12_BLOCK + #undef CONVERT_I16_I12_BLOCK + } + + //AVX2 block + { + #include "conv_i16_i12_avx2.inc" + #include "conv_4cf32_ci12_avx2.inc" + + if (i >= 32*4) + { + __m256 f0 = _mm256_loadu_ps(indata_0); + __m256 f1 = _mm256_loadu_ps(indata_1); + __m256 f2 = _mm256_loadu_ps(indata_2); + __m256 f3 = _mm256_loadu_ps(indata_3); + + CONVERT_4CF32_CI12_BLOCK(f0, f1, f2, f3); + + indata_0 += 8; + indata_1 += 8; + indata_2 += 8; + indata_3 += 8; + i -= 32*4; + } + + #undef CONVERT_4CF32_CI12_BLOCK + #undef CONVERT_I16_I12_BLOCK + } + + //Generic block + { + #undef I16RND + #define I16RND(x) x > 0 ? (int16_t)(x + 0.5f) : (int16_t)(x - 0.5f) + + uint8_t* outdata = (uint8_t*)out64; + #include "conv_4cf32_ci12_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_4cf32_ci12_generic.inc b/src/lib/xdsp/templates/conv_4cf32_ci12_generic.inc new file mode 100644 index 00000000..05585c3a --- /dev/null +++ b/src/lib/xdsp/templates/conv_4cf32_ci12_generic.inc @@ -0,0 +1,29 @@ +for (; i >= 32; i -= 32) { + + float f0 = *(indata_0++) / CONV_SCALE; + float f1 = *(indata_0++) / CONV_SCALE; + float f2 = *(indata_1++) / CONV_SCALE; + float f3 = *(indata_1++) / CONV_SCALE; + float f4 = *(indata_2++) / CONV_SCALE; + float f5 = *(indata_2++) / CONV_SCALE; + float f6 = *(indata_3++) / CONV_SCALE; + float f7 = *(indata_3++) / CONV_SCALE; + + wu_i16u32_t a0 = {{I16RND(f0), I16RND(f1)}}; + wu_i16u32_t a1 = {{I16RND(f2), I16RND(f3)}}; + wu_i16u32_t a2 = {{I16RND(f4), I16RND(f5)}}; + wu_i16u32_t a3 = {{I16RND(f6), I16RND(f7)}}; + + wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; + wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; + wu_u32b_t c2 = {(a2.u & 0xfff00000) | ((a2.u << 4) & 0x000fff00)}; + wu_u32b_t c3 = {(a3.u & 0xfff00000) | ((a3.u << 4) & 0x000fff00)}; + + const wu_u32b_t arr[] = {c0, c1, c2, c3}; + for(unsigned j = 0; j < 4; ++j) + { + *(outdata++) = arr[j].b[1]; + *(outdata++) = arr[j].b[2]; + *(outdata++) = arr[j].b[3]; + } +} \ No newline at end of file diff --git a/src/lib/xdsp/templates/conv_4cf32_ci12_generic.t b/src/lib/xdsp/templates/conv_4cf32_ci12_generic.t index 7d67575a..ba776e84 100644 --- a/src/lib/xdsp/templates/conv_4cf32_ci12_generic.t +++ b/src/lib/xdsp/templates/conv_4cf32_ci12_generic.t @@ -17,35 +17,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, const float* indata_3 = (const float*)indata_3_p; uint8_t* outdata = (uint8_t*)outdata_p; - - for (; i >= 32; i -= 32) { - - float f0 = *(indata_0++) / CONV_SCALE; - float f1 = *(indata_0++) / CONV_SCALE; - float f2 = *(indata_1++) / CONV_SCALE; - float f3 = *(indata_1++) / CONV_SCALE; - float f4 = *(indata_2++) / CONV_SCALE; - float f5 = *(indata_2++) / CONV_SCALE; - float f6 = *(indata_3++) / CONV_SCALE; - float f7 = *(indata_3++) / CONV_SCALE; - - wu_i16u32_t a0 = {{I16RND(f0), I16RND(f1)}}; - wu_i16u32_t a1 = {{I16RND(f2), I16RND(f3)}}; - wu_i16u32_t a2 = {{I16RND(f4), I16RND(f5)}}; - wu_i16u32_t a3 = {{I16RND(f6), I16RND(f7)}}; - - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - wu_u32b_t c2 = {(a2.u & 0xfff00000) | ((a2.u << 4) & 0x000fff00)}; - wu_u32b_t c3 = {(a3.u & 0xfff00000) | ((a3.u << 4) & 0x000fff00)}; - - const wu_u32b_t arr[] = {c0, c1, c2, c3}; - for(unsigned j = 0; j < 4; ++j) - { - *(outdata++) = arr[j].b[1]; - *(outdata++) = arr[j].b[2]; - *(outdata++) = arr[j].b[3]; - } - } + #include "conv_4cf32_ci12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_4ci16_ci12_avx2.t b/src/lib/xdsp/templates/conv_4ci16_ci12_avx2.t index 932552c6..c93039b5 100644 --- a/src/lib/xdsp/templates/conv_4ci16_ci12_avx2.t +++ b/src/lib/xdsp/templates/conv_4ci16_ci12_avx2.t @@ -62,35 +62,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, #undef CONVERT_I16_I12_BLOCK uint8_t* outdata = (uint8_t*)out64; - - for (; i >= 16; i -= 16) { - - const int16_t i0 = *indata_0++; - const int16_t q0 = *indata_0++; - const int16_t i1 = *indata_1++; - const int16_t q1 = *indata_1++; - const int16_t i2 = *indata_2++; - const int16_t q2 = *indata_2++; - const int16_t i3 = *indata_3++; - const int16_t q3 = *indata_3++; - - wu_i16u32_t a0 = {{i0, q0}}; - wu_i16u32_t a1 = {{i1, q1}}; - wu_i16u32_t a2 = {{i2, q2}}; - wu_i16u32_t a3 = {{i3, q3}}; - - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - wu_u32b_t c2 = {(a2.u & 0xfff00000) | ((a2.u << 4) & 0x000fff00)}; - wu_u32b_t c3 = {(a3.u & 0xfff00000) | ((a3.u << 4) & 0x000fff00)}; - - const wu_u32b_t arr[] = {c0, c1, c2, c3}; - for(unsigned j = 0; j < 4; ++j) - { - *(outdata++) = arr[j].b[1]; - *(outdata++) = arr[j].b[2]; - *(outdata++) = arr[j].b[3]; - } - } + #include "conv_4ci16_ci12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_4ci16_ci12_avx512bw.t b/src/lib/xdsp/templates/conv_4ci16_ci12_avx512bw.t new file mode 100644 index 00000000..113c2adb --- /dev/null +++ b/src/lib/xdsp/templates/conv_4ci16_ci12_avx512bw.t @@ -0,0 +1,118 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + const void *__restrict indata_2_p, + const void *__restrict indata_3_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 4 / 3) < i) + i = (outdatabsz * 4 / 3); + + const int16_t* indata_0 = (const int16_t*)indata_0_p; + const int16_t* indata_1 = (const int16_t*)indata_1_p; + const int16_t* indata_2 = (const int16_t*)indata_2_p; + const int16_t* indata_3 = (const int16_t*)indata_3_p; + + uint64_t *out64 = (uint64_t*)outdata_p; + + //AVX512 block + { + #include "conv_i16_i12_avx512bw.inc" + + __m512i v0, v1, v2, v3; + const __m512i idx = _mm512_set_epi32(15,11,7,3, 14,10,6,2, 13,9,5,1, 12,8,4,0); + const __m512i imask0 = _mm512_set_epi32(30,14,28,12,26,10,24,8,22,6,20,4,18,2,16,0); + const __m512i imask1 = _mm512_set_epi32(31,15,29,13,27,11,25,9,23,7,21,5,19,3,17,1); + + for (; i >= 64*4; i -= 64*4) + { + v0 = _mm512_loadu_si512((__m512i*)indata_0); + v1 = _mm512_loadu_si512((__m512i*)indata_1); + v2 = _mm512_loadu_si512((__m512i*)indata_2); + v3 = _mm512_loadu_si512((__m512i*)indata_3); + + indata_0 += 32; + indata_1 += 32; + indata_2 += 32; + indata_3 += 32; + + __m512i a0 = _mm512_permutexvar_epi32(idx, v0); + __m512i a1 = _mm512_permutexvar_epi32(idx, v1); + __m512i a2 = _mm512_permutexvar_epi32(idx, v2); + __m512i a3 = _mm512_permutexvar_epi32(idx, v3); + + __m512i b0 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a0), _mm512_castsi512_pd(a2), 0b00000000)); + __m512i b2 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a0), _mm512_castsi512_pd(a2), 0b11111111)); + __m512i b1 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a1), _mm512_castsi512_pd(a3), 0b00000000)); + __m512i b3 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a1), _mm512_castsi512_pd(a3), 0b11111111)); + + __m512i c0 = _mm512_permutex2var_epi32(b0, imask0, b1); + __m512i c1 = _mm512_permutex2var_epi32(b0, imask1, b1); + __m512i c2 = _mm512_permutex2var_epi32(b2, imask0, b3); + __m512i c3 = _mm512_permutex2var_epi32(b2, imask1, b3); + + CONVERT_I16_I12_BLOCK(c0, out64); + CONVERT_I16_I12_BLOCK(c1, out64); + CONVERT_I16_I12_BLOCK(c2, out64); + CONVERT_I16_I12_BLOCK(c3, out64); + } + + #undef CONVERT_I16_I12_BLOCK + } + + //AVX2 block + { + #include "conv_i16_i12_avx2.inc" + + if(i >= 32*4) + { + const __m256i permmask1 = _mm256_set_epi32(7,3,5,1,6,2,4,0); + + __m256i v0 = _mm256_loadu_si256((__m256i*)indata_0); + __m256i v1 = _mm256_loadu_si256((__m256i*)indata_1); + __m256i v2 = _mm256_loadu_si256((__m256i*)indata_2); + __m256i v3 = _mm256_loadu_si256((__m256i*)indata_3); + + __m256i z0 = _mm256_permute2x128_si256(v0, v1, 0b00100000); + __m256i z2 = _mm256_permute2x128_si256(v0, v1, 0b00110001); + __m256i z1 = _mm256_permute2x128_si256(v2, v3, 0b00100000); + __m256i z3 = _mm256_permute2x128_si256(v2, v3, 0b00110001); + + __m256i i0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z0), _mm256_castsi256_pd(z1), 0b0000)); + __m256i i1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z0), _mm256_castsi256_pd(z1), 0b1111)); + __m256i i2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z2), _mm256_castsi256_pd(z3), 0b0000)); + __m256i i3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z2), _mm256_castsi256_pd(z3), 0b1111)); + + i0 = _mm256_permutevar8x32_epi32(i0, permmask1); + i1 = _mm256_permutevar8x32_epi32(i1, permmask1); + i2 = _mm256_permutevar8x32_epi32(i2, permmask1); + i3 = _mm256_permutevar8x32_epi32(i3, permmask1); + + /* Convert linear data to CI12 */ + + CONVERT_I16_I12_BLOCK(i0, out64); + CONVERT_I16_I12_BLOCK(i1, out64); + CONVERT_I16_I12_BLOCK(i2, out64); + CONVERT_I16_I12_BLOCK(i3, out64); + + indata_0 += 16; + indata_1 += 16; + indata_2 += 16; + indata_3 += 16; + + i -= 32*4; + } + + #undef CONVERT_I16_I12_BLOCK + } + + //Generic block + { + uint8_t* outdata = (uint8_t*)out64; + #include "conv_4ci16_ci12_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_4ci16_ci12_generic.inc b/src/lib/xdsp/templates/conv_4ci16_ci12_generic.inc new file mode 100644 index 00000000..bfb853e9 --- /dev/null +++ b/src/lib/xdsp/templates/conv_4ci16_ci12_generic.inc @@ -0,0 +1,29 @@ +for (; i >= 16; i -= 16) +{ + const int16_t i0 = *indata_0++; + const int16_t q0 = *indata_0++; + const int16_t i1 = *indata_1++; + const int16_t q1 = *indata_1++; + const int16_t i2 = *indata_2++; + const int16_t q2 = *indata_2++; + const int16_t i3 = *indata_3++; + const int16_t q3 = *indata_3++; + + wu_i16u32_t a0 = {{i0, q0}}; + wu_i16u32_t a1 = {{i1, q1}}; + wu_i16u32_t a2 = {{i2, q2}}; + wu_i16u32_t a3 = {{i3, q3}}; + + wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; + wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; + wu_u32b_t c2 = {(a2.u & 0xfff00000) | ((a2.u << 4) & 0x000fff00)}; + wu_u32b_t c3 = {(a3.u & 0xfff00000) | ((a3.u << 4) & 0x000fff00)}; + + const wu_u32b_t arr[] = {c0, c1, c2, c3}; + for(unsigned j = 0; j < 4; ++j) + { + *(outdata++) = arr[j].b[1]; + *(outdata++) = arr[j].b[2]; + *(outdata++) = arr[j].b[3]; + } +} diff --git a/src/lib/xdsp/templates/conv_4ci16_ci12_generic.t b/src/lib/xdsp/templates/conv_4ci16_ci12_generic.t index efece148..511235eb 100644 --- a/src/lib/xdsp/templates/conv_4ci16_ci12_generic.t +++ b/src/lib/xdsp/templates/conv_4ci16_ci12_generic.t @@ -18,34 +18,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, uint8_t* outdata = (uint8_t*)outdata_p; - for (; i >= 16; i -= 16) { - - const int16_t i0 = *indata_0++; - const int16_t q0 = *indata_0++; - const int16_t i1 = *indata_1++; - const int16_t q1 = *indata_1++; - const int16_t i2 = *indata_2++; - const int16_t q2 = *indata_2++; - const int16_t i3 = *indata_3++; - const int16_t q3 = *indata_3++; - - wu_i16u32_t a0 = {{i0, q0}}; - wu_i16u32_t a1 = {{i1, q1}}; - wu_i16u32_t a2 = {{i2, q2}}; - wu_i16u32_t a3 = {{i3, q3}}; - - wu_u32b_t c0 = {(a0.u & 0xfff00000) | ((a0.u << 4) & 0x000fff00)}; - wu_u32b_t c1 = {(a1.u & 0xfff00000) | ((a1.u << 4) & 0x000fff00)}; - wu_u32b_t c2 = {(a2.u & 0xfff00000) | ((a2.u << 4) & 0x000fff00)}; - wu_u32b_t c3 = {(a3.u & 0xfff00000) | ((a3.u << 4) & 0x000fff00)}; - - const wu_u32b_t arr[] = {c0, c1, c2, c3}; - for(unsigned j = 0; j < 4; ++j) - { - *(outdata++) = arr[j].b[1]; - *(outdata++) = arr[j].b[2]; - *(outdata++) = arr[j].b[3]; - } - } + #include "conv_4ci16_ci12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t index d1b0a4e1..2014ea29 100644 --- a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t @@ -112,30 +112,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, #undef CONVERT_I12_F32_BLOCK const uint8_t *indata = (const uint8_t*)in; - float **dest = &outdata_0; - - while(i >= 3) - { - uint8_t v0 = *(indata++); - uint8_t v1 = *(indata++); - uint8_t v2 = *(indata++); - i -= 3; - - float a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); - float b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); - - *((*dest)++) = a * CONV_SCALE; - *((*dest)++) = b * CONV_SCALE; - - dest = (*dest == outdata_0) ? &outdata_1 : &outdata_0; - } - - if(i >= 2) - { - uint16_t v = *(const uint16_t*)indata; - float a = (int16_t)(v << 4); - *((*dest)++) = a * CONV_SCALE; - i -= 2; - } + #include "conv_ci12_2cf32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t new file mode 100644 index 00000000..cf0209ab --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t @@ -0,0 +1,88 @@ +static inline +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + /* 12 bits -> 32 bits => 3 -> 8 */ + if ((outdatabsz * 3 / 8) < i) + i = (outdatabsz * 3 / 8); + + const uint64_t *in = (const uint64_t*)indata_p; + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + + //AVX512 block + { + #include "conv_i12_i16_avx512bw.inc" + #include "conv_i12_f32_avx512bw.inc" + + __m512i y0, y1; + __m512 res0, res1, res2, res3; + + const __m512i idx0 = _mm512_set_epi64(14,12,10,8,6,4,2,0); + const __m512i idx1 = _mm512_set_epi64(15,13,11,9,7,5,3,1); + + for(; i >= 96; i -= 96) + { + y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); + y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); + in += 12; + + CONVERT_I12_F32_BLOCK(y0, res0, res1); + CONVERT_I12_F32_BLOCK(y1, res2, res3); + + _mm512_storeu_pd(outdata_0 + 0, _mm512_permutex2var_pd(_mm512_castps_pd(res0), idx0, _mm512_castps_pd(res1))); + _mm512_storeu_pd(outdata_1 + 0, _mm512_permutex2var_pd(_mm512_castps_pd(res0), idx1, _mm512_castps_pd(res1))); + _mm512_storeu_pd(outdata_0 + 16, _mm512_permutex2var_pd(_mm512_castps_pd(res2), idx0, _mm512_castps_pd(res3))); + _mm512_storeu_pd(outdata_1 + 16, _mm512_permutex2var_pd(_mm512_castps_pd(res2), idx1, _mm512_castps_pd(res3))); + outdata_0 += 32; + outdata_1 += 32; + } + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_I16_BLOCK + } + + //AVX2 block + { + #include "conv_i12_i16_avx2.inc" + #include "conv_i12_f32_avx2.inc" + + if(i >= 48) + { + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + in += 6; + i -= 48; + + __m256 res0, res1, res2, res3; + + CONVERT_I12_F32_BLOCK(y0, res0, res1); + CONVERT_I12_F32_BLOCK(y1, res2, res3); + + const __m256i idx0 = _mm256_set_epi64x(6,4,2,0); + const __m256i idx1 = _mm256_set_epi64x(7,5,3,1); + + _mm256_storeu_pd((double*)(outdata_0 + 0), _mm256_permutex2var_pd(_mm256_castps_pd(res0), idx0, _mm256_castps_pd(res1))); + _mm256_storeu_pd((double*)(outdata_1 + 0), _mm256_permutex2var_pd(_mm256_castps_pd(res0), idx1, _mm256_castps_pd(res1))); + _mm256_storeu_pd((double*)(outdata_0 + 8), _mm256_permutex2var_pd(_mm256_castps_pd(res2), idx0, _mm256_castps_pd(res3))); + _mm256_storeu_pd((double*)(outdata_1 + 8), _mm256_permutex2var_pd(_mm256_castps_pd(res2), idx1, _mm256_castps_pd(res3))); + outdata_0 += 16; + outdata_1 += 16; + } + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_I12_I16_BLOCK + } + + //Generic block + { + const uint8_t *indata = (const uint8_t*)in; + #include "conv_ci12_2cf32_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_generic.inc b/src/lib/xdsp/templates/conv_ci12_2cf32_generic.inc new file mode 100644 index 00000000..4f7a1a5f --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_generic.inc @@ -0,0 +1,25 @@ +float **dest = &outdata_0; + +while(i >= 3) +{ + uint8_t v0 = *(indata++); + uint8_t v1 = *(indata++); + uint8_t v2 = *(indata++); + i -= 3; + + float a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); + float b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); + + *((*dest)++) = a * CONV_SCALE; + *((*dest)++) = b * CONV_SCALE; + + dest = (*dest == outdata_0) ? &outdata_1 : &outdata_0; +} + +if(i >= 2) +{ + uint16_t v = *(const uint16_t*)indata; + float a = (int16_t)(v << 4); + *((*dest)++) = a * CONV_SCALE; + i -= 2; +} diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_generic.t b/src/lib/xdsp/templates/conv_ci12_2cf32_generic.t index 44c3d84a..1a23fe47 100644 --- a/src/lib/xdsp/templates/conv_ci12_2cf32_generic.t +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_generic.t @@ -31,31 +31,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, *(outdata_1++) = d * CONV_SCALE; } - float **dest = &outdata_0; - - while(i >= 3) - { - uint8_t v0 = *(indata++); - uint8_t v1 = *(indata++); - uint8_t v2 = *(indata++); - i -= 3; - - float a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); - float b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); - - *((*dest)++) = a * CONV_SCALE; - *((*dest)++) = b * CONV_SCALE; - - dest = (*dest == outdata_0) ? &outdata_1 : &outdata_0; - } - - if(i >= 2) - { - uint16_t v = *(const uint16_t*)indata; - float a = (int16_t)(v << 4); - *((*dest)++) = a * CONV_SCALE; - i -= 2; - } + #include "conv_ci12_2cf32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_2ci16_avx2.t b/src/lib/xdsp/templates/conv_ci12_2ci16_avx2.t index 99715143..78997a03 100644 --- a/src/lib/xdsp/templates/conv_ci12_2ci16_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_2ci16_avx2.t @@ -80,19 +80,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, #undef CONVERT_CI12_2CI16_BLOCK const uint8_t *indata = (const uint8_t*)in; - - for (; i >= 6; i -= 6) - { - /* read 48 bits -> 4 int16 (64 bits) */ - - uint64_t v = *(const uint64_t *)indata; - indata += 6; - - *(outdata_0++) = (int16_t)((v << 4) ); - *(outdata_0++) = (int16_t)((v >> 8) & 0xfff0); - *(outdata_1++) = (int16_t)((v >> 20) & 0xfff0); - *(outdata_1++) = (int16_t)((v >> 32) & 0xfff0); - } - // do nothing with tail + #include "conv_ci12_2ci16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t new file mode 100644 index 00000000..96681f8c --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t @@ -0,0 +1,79 @@ +static inline +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + /* 12 bits -> 16 bits => 3 -> 4 */ + if ((outdatabsz * 3 / 4) < i) + i = (outdatabsz * 3 / 4); + + const uint64_t *in = (const uint64_t*)indata_p; + int16_t* outdata_0 = (int16_t*)outdata_0_p; + int16_t* outdata_1 = (int16_t*)outdata_1_p; + + //AVX512BW block + { + #include "conv_i12_i16_avx512bw.inc" + + __m512i y0, y1; + __m512i rs0, rs1; + + const __m512i imask0 = _mm512_set_epi32(30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0); + const __m512i imask1 = _mm512_set_epi32(31,29,27,25,23,21,19,17,15,13,11,9,7,5,3,1); + + for(; i >= 96; i -= 96) + { + y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); + y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); + in += 12; + + CONVERT_I12_I16_BLOCK(y0, rs0); + CONVERT_I12_I16_BLOCK(y1, rs1); + + _mm512_store_si512((__m512i*)outdata_0, _mm512_permutex2var_epi32(rs0, imask0, rs1)); + _mm512_store_si512((__m512i*)outdata_1, _mm512_permutex2var_epi32(rs0, imask1, rs1)); + outdata_0 += 32; + outdata_1 += 32; + } + + #undef CONVERT_I12_I16_BLOCK + } + + //AVX2 block + { + #include "conv_i12_i16_avx2.inc" + + if(i >= 48) + { + const __m256i imask0 = _mm256_set_epi32(14,12,10,8,6,4,2,0); + const __m256i imask1 = _mm256_set_epi32(15,13,11,9,7,5,3,1); + + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); // 8 1/3 + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); // 8 1/3 + in += 6; + i -= 48; + + __m256i rs0, rs1; + + CONVERT_I12_I16_BLOCK(y0, rs0); + CONVERT_I12_I16_BLOCK(y1, rs1); + + _mm256_store_si256((__m256i*)outdata_0, _mm256_permutex2var_epi32(rs0, imask0, rs1)); + _mm256_store_si256((__m256i*)outdata_1, _mm256_permutex2var_epi32(rs0, imask1, rs1)); + outdata_0 += 16; + outdata_1 += 16; + } + + #undef CONVERT_I12_I16_BLOCK + } + + //Generic block + { + const uint8_t *indata = (const uint8_t*)in; + #include "conv_ci12_2ci16_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_2ci16_generic.inc b/src/lib/xdsp/templates/conv_ci12_2ci16_generic.inc new file mode 100644 index 00000000..3e1301b2 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_2ci16_generic.inc @@ -0,0 +1,13 @@ + for (; i >= 6; i -= 6) + { + /* read 48 bits -> 4 int16 (64 bits) */ + + uint64_t v = *(const uint64_t *)indata; + indata += 6; + + *(outdata_0++) = (int16_t)((v << 4) ); + *(outdata_0++) = (int16_t)((v >> 8) & 0xfff0); + *(outdata_1++) = (int16_t)((v >> 20) & 0xfff0); + *(outdata_1++) = (int16_t)((v >> 32) & 0xfff0); + } + // do nothing with tail diff --git a/src/lib/xdsp/templates/conv_ci12_2ci16_generic.t b/src/lib/xdsp/templates/conv_ci12_2ci16_generic.t index 7943d01a..33d9fd87 100644 --- a/src/lib/xdsp/templates/conv_ci12_2ci16_generic.t +++ b/src/lib/xdsp/templates/conv_ci12_2ci16_generic.t @@ -14,19 +14,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, int16_t* outdata_0 = (int16_t*)outdata_0_p; int16_t* outdata_1 = (int16_t*)outdata_1_p; - for (; i >= 6; i -= 6) - { - /* read 48 bits -> 4 int16 (64 bits) */ - - uint64_t v = *(const uint64_t *)indata; - indata += 6; - - *(outdata_0++) = (int16_t)((v << 4) ); - *(outdata_0++) = (int16_t)((v >> 8) & 0xfff0); - *(outdata_1++) = (int16_t)((v >> 20) & 0xfff0); - *(outdata_1++) = (int16_t)((v >> 32) & 0xfff0); - } - // do nothing with tail +#include "conv_ci12_2ci16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.inc b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.inc new file mode 100644 index 00000000..d95160be --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.inc @@ -0,0 +1,97 @@ +/* +* r0-r1: +* | (3) | (2) | (1) | (0) | +* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +* | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | +* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +* | 0 0 0 0 0 0 0 0 | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | +* | 0 0 0 0 0 0 0 0 | f31 | f30 | f29 | f28 | f27 | f26 | f25 | f24 | f23 | f22 | f21 | f20 | f19 | f18 | f17 | f16 | +* +* y0 -y1: _mm256_permutevar8x32_epi32 +* | | | | | +* | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | 0 0 0 0 0 0 0 0 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | +* | f31 | f30 | f29 | f28 | f27 | f26 | f25 | f24 | 0 0 0 0 0 0 0 0 | f23 | f22 | f21 | f20 | f19 | f18 | f17 | f16 | +* +* y0-y2: _mm256_shuffle_epi8 +* | | | | | +* | f15 | f14 | 0 | f13 | f12 | 0 | f11 | f10 | 0 | f9 | f8 | 0 | f7 | f6 | 0 | f5 | f4 | 0 | f3 | f2 | 0 | f1 | f0 | 0 | +* | f31 | f30 | 0 | f29 | f28 | 0 | f27 | f26 | 0 | f25 | f24 | 0 | f23 | f22 | 0 | f21 | f20 | 0 | f19 | f18 | 0 | f17 | f16 | 0 | +* +* a0-a1: +* | | | | | +* | f15 |0| 00 00 | f13 |0| 00 00 | f11 |0| 00 00 | f9 |0| 00 00 | f7 |0| 00 00 | f5 |0| 00 00 | f3 |0| 00 00 | f1 |0| 00 00 | +* | 00 00 | f14 |0| 00 00 | f12 |0| 00 00 | f10 |0| 00 00 | f8 |0| 00 00 | f6 |0| 00 00 | f4 |0| 00 00 | f2 |0| 00 00 | f0 |0| +* +* i0: _mm256_or_si256(a0, a1) +* i1: _mm256_or_si256(b0, b1) +* | | | | | +* | f15 |0| f14 |0| f13 |0| f12 |0| f11 |0| f10 |0| f9 |0| f8 |0| f7 |0| f6 |0| f5 |0| f4 |0| f3 |0| f2 |0| f1 |0| f0 |0| +* | f31 |0| f30 |0| f29 |0| f28 |0| f27 |0| f26 |0| f25 |0| f24 |0| f23 |0| f22 |0| f21 |0| f20 |0| f19 |0| f18 |0| f17 |0| f16 |0| +* +* i0-i1: _mm256_permutevar8x32_epi32 +* | | | | | +* | f15 |0| f14 |0| f7 |0| f6 |0| f11 |0| f10 |0| f3 |0| f2 |0| f13 |0| f12 |0| f5 |0| f4 |0| f9 |0| f8 |0| f1 |0| f0 |0| +* | f31 |0| f30 |0| f23 |0| f22 |0| f27 |0| f26 |0| f19 |0| f18 |0| f29 |0| f28 |0| f21 |0| f20 |0| f25 |0| f24 |0| f17 |0| f16 |0| +* +* z0-z1: _mm256_castpd_si256 +* | | | | | +* | f27 |0| f26 |0| f19 |0| f18 |0| f11 |0| f10 |0| f3 |0| f2 |0| f25 |0| f24 |0| f17 |0| f16 |0| f9 |0| f8 |0| f1 |0| f0 |0| +* | f31 |0| f30 |0| f23 |0| f22 |0| f15 |0| f14 |0| f7 |0| f6 |0| f29 |0| f28 |0| f21 |0| f20 |0| f13 |0| f12 |0| f5 |0| f4 |0| +*/ + +const __m256 scale = _mm256_set1_ps(CONV_SCALE); +const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); + +const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); +const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); + +const __m256i permmask0 = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); +const __m256i permmask1 = _mm256_set_epi32(7, 3, 5, 1, 6, 2, 4, 0); + +const __m256i shfl = _mm256_set_epi8( + 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, + 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, + 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, + 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); + +#define CONVERT_CI12_4F32_BLOCK(y0, y1) \ +{ \ + y0 = _mm256_permutevar8x32_epi32(y0, permmask0); \ + y1 = _mm256_permutevar8x32_epi32(y1, permmask0); \ + \ + y0 = _mm256_shuffle_epi8(y0, shfl); \ + y1 = _mm256_shuffle_epi8(y1, shfl); \ + \ + __m256i a0 = _mm256_and_si256(y0, mask0); \ + __m256i b0 = _mm256_and_si256(y1, mask0); \ + \ + __m256i a1 = _mm256_and_si256(_mm256_srli_epi64(y0, 4), mask1); \ + __m256i b1 = _mm256_and_si256(_mm256_srli_epi64(y1, 4), mask1); \ + \ + __m256i i0 = _mm256_or_si256(a0, a1); \ + __m256i i1 = _mm256_or_si256(b0, b1); \ + \ + /* Linear I12->F32 conv completed here */ \ + /* Next section dedicated to 4-way interleave processing */ \ + \ + i0 = _mm256_permutevar8x32_epi32(i0, permmask1); \ + i1 = _mm256_permutevar8x32_epi32(i1, permmask1); \ + \ + __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(i0), _mm256_castsi256_pd(i1), 0b0000)); \ + __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(i0), _mm256_castsi256_pd(i1), 0b1111)); \ + \ + __m256i d0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(z0)); \ + __m256i d1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(z0, 1)); \ + __m256i d2 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(z1)); \ + __m256i d3 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(z1, 1)); \ + \ + _mm256_storeu_ps(outdata_0, _mm256_mul_ps(_mm256_cvtepi32_ps(d0), scale)); \ + _mm256_storeu_ps(outdata_1, _mm256_mul_ps(_mm256_cvtepi32_ps(d1), scale)); \ + _mm256_storeu_ps(outdata_2, _mm256_mul_ps(_mm256_cvtepi32_ps(d2), scale)); \ + _mm256_storeu_ps(outdata_3, _mm256_mul_ps(_mm256_cvtepi32_ps(d3), scale)); \ + \ + outdata_0 += 8; \ + outdata_1 += 8; \ + outdata_2 += 8; \ + outdata_3 += 8; \ +} diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t index 2bc97411..f59b60d8 100644 --- a/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t @@ -17,108 +17,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, float* outdata_2 = (float*)outdata_2_p; float* outdata_3 = (float*)outdata_3_p; -/* -* r0-r1: -* | (3) | (2) | (1) | (0) | -* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -* | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | -* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -* | 0 0 0 0 0 0 0 0 | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | -* | 0 0 0 0 0 0 0 0 | f31 | f30 | f29 | f28 | f27 | f26 | f25 | f24 | f23 | f22 | f21 | f20 | f19 | f18 | f17 | f16 | -* -* y0 -y1: _mm256_permutevar8x32_epi32 -* | | | | | -* | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | 0 0 0 0 0 0 0 0 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | -* | f31 | f30 | f29 | f28 | f27 | f26 | f25 | f24 | 0 0 0 0 0 0 0 0 | f23 | f22 | f21 | f20 | f19 | f18 | f17 | f16 | -* -* y0-y2: _mm256_shuffle_epi8 -* | | | | | -* | f15 | f14 | 0 | f13 | f12 | 0 | f11 | f10 | 0 | f9 | f8 | 0 | f7 | f6 | 0 | f5 | f4 | 0 | f3 | f2 | 0 | f1 | f0 | 0 | -* | f31 | f30 | 0 | f29 | f28 | 0 | f27 | f26 | 0 | f25 | f24 | 0 | f23 | f22 | 0 | f21 | f20 | 0 | f19 | f18 | 0 | f17 | f16 | 0 | -* -* a0-a1: -* | | | | | -* | f15 |0| 00 00 | f13 |0| 00 00 | f11 |0| 00 00 | f9 |0| 00 00 | f7 |0| 00 00 | f5 |0| 00 00 | f3 |0| 00 00 | f1 |0| 00 00 | -* | 00 00 | f14 |0| 00 00 | f12 |0| 00 00 | f10 |0| 00 00 | f8 |0| 00 00 | f6 |0| 00 00 | f4 |0| 00 00 | f2 |0| 00 00 | f0 |0| -* -* i0: _mm256_or_si256(a0, a1) -* i1: _mm256_or_si256(b0, b1) -* | | | | | -* | f15 |0| f14 |0| f13 |0| f12 |0| f11 |0| f10 |0| f9 |0| f8 |0| f7 |0| f6 |0| f5 |0| f4 |0| f3 |0| f2 |0| f1 |0| f0 |0| -* | f31 |0| f30 |0| f29 |0| f28 |0| f27 |0| f26 |0| f25 |0| f24 |0| f23 |0| f22 |0| f21 |0| f20 |0| f19 |0| f18 |0| f17 |0| f16 |0| -* -* i0-i1: _mm256_permutevar8x32_epi32 -* | | | | | -* | f15 |0| f14 |0| f7 |0| f6 |0| f11 |0| f10 |0| f3 |0| f2 |0| f13 |0| f12 |0| f5 |0| f4 |0| f9 |0| f8 |0| f1 |0| f0 |0| -* | f31 |0| f30 |0| f23 |0| f22 |0| f27 |0| f26 |0| f19 |0| f18 |0| f29 |0| f28 |0| f21 |0| f20 |0| f25 |0| f24 |0| f17 |0| f16 |0| -* -* z0-z1: _mm256_castpd_si256 -* | | | | | -* | f27 |0| f26 |0| f19 |0| f18 |0| f11 |0| f10 |0| f3 |0| f2 |0| f25 |0| f24 |0| f17 |0| f16 |0| f9 |0| f8 |0| f1 |0| f0 |0| -* | f31 |0| f30 |0| f23 |0| f22 |0| f15 |0| f14 |0| f7 |0| f6 |0| f29 |0| f28 |0| f21 |0| f20 |0| f13 |0| f12 |0| f5 |0| f4 |0| -*/ - - const __m256 scale = _mm256_set1_ps(CONV_SCALE); - const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); - - const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); - const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); - - const __m256i permmask0 = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); - const __m256i permmask1 = _mm256_set_epi32(7, 3, 5, 1, 6, 2, 4, 0); - - const __m256i shfl = _mm256_set_epi8( - 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, - 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, - 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, - 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); - const uint64_t *in = (const uint64_t*)indata_p; - -#define CONVERT_CI12_4F32_BLOCK(y0, y1) \ - { \ - y0 = _mm256_permutevar8x32_epi32(y0, permmask0); \ - y1 = _mm256_permutevar8x32_epi32(y1, permmask0); \ - \ - y0 = _mm256_shuffle_epi8(y0, shfl); \ - y1 = _mm256_shuffle_epi8(y1, shfl); \ - \ - __m256i a0 = _mm256_and_si256(y0, mask0); \ - __m256i b0 = _mm256_and_si256(y1, mask0); \ - \ - __m256i a1 = _mm256_and_si256(_mm256_srli_epi64(y0, 4), mask1); \ - __m256i b1 = _mm256_and_si256(_mm256_srli_epi64(y1, 4), mask1); \ - \ - __m256i i0 = _mm256_or_si256(a0, a1); \ - __m256i i1 = _mm256_or_si256(b0, b1); \ - \ - /* Linear I12->F32 conv completed here */ \ - \ - /* Next section dedicated to 4-way interleave processing */ \ - \ - i0 = _mm256_permutevar8x32_epi32(i0, permmask1); \ - i1 = _mm256_permutevar8x32_epi32(i1, permmask1); \ - \ - __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(i0), _mm256_castsi256_pd(i1), 0b0000)); \ - __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(i0), _mm256_castsi256_pd(i1), 0b1111)); \ - \ - __m256i d0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(z0)); \ - __m256i d1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(z0, 1)); \ - __m256i d2 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(z1)); \ - __m256i d3 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(z1, 1)); \ - \ - _mm256_storeu_ps(outdata_0, _mm256_mul_ps(_mm256_cvtepi32_ps(d0), scale)); \ - _mm256_storeu_ps(outdata_1, _mm256_mul_ps(_mm256_cvtepi32_ps(d1), scale)); \ - _mm256_storeu_ps(outdata_2, _mm256_mul_ps(_mm256_cvtepi32_ps(d2), scale)); \ - _mm256_storeu_ps(outdata_3, _mm256_mul_ps(_mm256_cvtepi32_ps(d3), scale)); \ - \ - outdata_0 += 8; \ - outdata_1 += 8; \ - outdata_2 += 8; \ - outdata_3 += 8; \ - } -// CONVERT_CI12_4F32_BLOCK + #include "conv_ci12_4cf32_avx2.inc" __m256i r0, r1; @@ -133,35 +34,10 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, i -= 48; } - const uint8_t *indata = (const uint8_t*)in; - - for (; i >= 12; i -= 12) { - /* read 12 bytes -> 2*48 bits -> 4*2 floats -> 4cf32 */ - - uint64_t v0 = *(const uint64_t *)(indata + 0); - uint64_t v1 = *(const uint64_t *)(indata + 6); - indata += 12; - - float i0 = (int16_t)(v0 << 4); - float q0 = (int16_t)((v0 >> 8) & 0xfff0); - float i1 = (int16_t)((v0 >> 20) & 0xfff0); - float q1 = (int16_t)((v0 >> 32) & 0xfff0); - float i2 = (int16_t)(v1 << 4); - float q2 = (int16_t)((v1 >> 8) & 0xfff0); - float i3 = (int16_t)((v1 >> 20) & 0xfff0); - float q3 = (int16_t)((v1 >> 32) & 0xfff0); + #undef CONVERT_CI12_4F32_BLOCK - *(outdata_0++) = i0 * CONV_SCALE; - *(outdata_0++) = q0 * CONV_SCALE; - *(outdata_1++) = i1 * CONV_SCALE; - *(outdata_1++) = q1 * CONV_SCALE; - *(outdata_2++) = i2 * CONV_SCALE; - *(outdata_2++) = q2 * CONV_SCALE; - *(outdata_3++) = i3 * CONV_SCALE; - *(outdata_3++) = q3 * CONV_SCALE; - } - - // tail ignored + const uint8_t *indata = (const uint8_t*)in; + #include "conv_ci12_4cf32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t new file mode 100644 index 00000000..de7430fd --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t @@ -0,0 +1,86 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + /* 12 bits -> 32 bits => 3 -> 8 */ + if ((outdatabsz * 3 / 8) < i) + i = (outdatabsz * 3 / 8); + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + float* outdata_3 = (float*)outdata_3_p; + + const uint64_t *in = (const uint64_t*)indata_p; + + //AVX512 block + { + #include "conv_i12_i16_avx512bw.inc" + #include "conv_i12_f32_avx512bw.inc" + + __m512i y0, y1; + __m512 res0, res1, res2, res3; + + const __m512i idx0 = _mm512_set_epi64(13, 9,12, 8,5,1,4,0); + const __m512i idx1 = _mm512_set_epi64(15,11,14,10,7,3,6,2); + + for(; i >= 96; i -= 96) + { + y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); + y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); + in += 12; + + CONVERT_I12_F32_BLOCK(y0, res0, res1); + CONVERT_I12_F32_BLOCK(y1, res2, res3); + + __m512d d0 = _mm512_shuffle_pd(_mm512_castps_pd(res0), _mm512_castps_pd(res1), 0b00000000); + __m512d d1 = _mm512_shuffle_pd(_mm512_castps_pd(res0), _mm512_castps_pd(res1), 0b11111111); + __m512d d2 = _mm512_shuffle_pd(_mm512_castps_pd(res2), _mm512_castps_pd(res3), 0b00000000); + __m512d d3 = _mm512_shuffle_pd(_mm512_castps_pd(res2), _mm512_castps_pd(res3), 0b11111111); + + _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(d0, idx0, d2)); + _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(d1, idx0, d3)); + _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(d0, idx1, d2)); + _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(d1, idx1, d3)); + + outdata_0 += 16; + outdata_1 += 16; + outdata_2 += 16; + outdata_3 += 16; + } + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_I16_BLOCK + } + + //AVX2 block + { + #include "conv_ci12_4cf32_avx2.inc" + + if(i >= 48) + { + __m256i r0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); + __m256i r1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + in += 6; + i -= 48; + + CONVERT_CI12_4F32_BLOCK(r0, r1); + } + + #undef CONVERT_CI12_4F32_BLOCK + } + + //Generic block + { + const uint8_t *indata = (const uint8_t*)in; + #include "conv_ci12_4cf32_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc b/src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc new file mode 100644 index 00000000..266ce24d --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc @@ -0,0 +1,27 @@ +for (; i >= 12; i -= 12) { + /* read 12 bytes -> 2*48 bits -> 4*2 floats -> 4cf32 */ + + uint64_t v0 = *(const uint64_t *)(indata + 0); + uint64_t v1 = *(const uint64_t *)(indata + 6); + indata += 12; + + float i0 = (int16_t)(v0 << 4); + float q0 = (int16_t)((v0 >> 8) & 0xfff0); + float i1 = (int16_t)((v0 >> 20) & 0xfff0); + float q1 = (int16_t)((v0 >> 32) & 0xfff0); + float i2 = (int16_t)(v1 << 4); + float q2 = (int16_t)((v1 >> 8) & 0xfff0); + float i3 = (int16_t)((v1 >> 20) & 0xfff0); + float q3 = (int16_t)((v1 >> 32) & 0xfff0); + + *(outdata_0++) = i0 * CONV_SCALE; + *(outdata_0++) = q0 * CONV_SCALE; + *(outdata_1++) = i1 * CONV_SCALE; + *(outdata_1++) = q1 * CONV_SCALE; + *(outdata_2++) = i2 * CONV_SCALE; + *(outdata_2++) = q2 * CONV_SCALE; + *(outdata_3++) = i3 * CONV_SCALE; + *(outdata_3++) = q3 * CONV_SCALE; +} + +// tail ignored diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_generic.t b/src/lib/xdsp/templates/conv_ci12_4cf32_generic.t index 6e59f0b8..4040892c 100644 --- a/src/lib/xdsp/templates/conv_ci12_4cf32_generic.t +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_generic.t @@ -18,33 +18,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, float* outdata_2 = (float*)outdata_2_p; float* outdata_3 = (float*)outdata_3_p; - for (; i >= 12; i -= 12) { - /* read 12 bytes -> 2*48 bits -> 4*2 floats -> 4cf32 */ - - uint64_t v0 = *(const uint64_t *)(indata + 0); - uint64_t v1 = *(const uint64_t *)(indata + 6); - indata += 12; - - float i0 = (int16_t)(v0 << 4); - float q0 = (int16_t)((v0 >> 8) & 0xfff0); - float i1 = (int16_t)((v0 >> 20) & 0xfff0); - float q1 = (int16_t)((v0 >> 32) & 0xfff0); - float i2 = (int16_t)(v1 << 4); - float q2 = (int16_t)((v1 >> 8) & 0xfff0); - float i3 = (int16_t)((v1 >> 20) & 0xfff0); - float q3 = (int16_t)((v1 >> 32) & 0xfff0); - - *(outdata_0++) = i0 * CONV_SCALE; - *(outdata_0++) = q0 * CONV_SCALE; - *(outdata_1++) = i1 * CONV_SCALE; - *(outdata_1++) = q1 * CONV_SCALE; - *(outdata_2++) = i2 * CONV_SCALE; - *(outdata_2++) = q2 * CONV_SCALE; - *(outdata_3++) = i3 * CONV_SCALE; - *(outdata_3++) = q3 * CONV_SCALE; - } - - // tail ignored + #include "conv_ci12_4cf32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_4ci16_avx2.inc b/src/lib/xdsp/templates/conv_ci12_4ci16_avx2.inc new file mode 100644 index 00000000..5d50d319 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_4ci16_avx2.inc @@ -0,0 +1,35 @@ +const __m256i permmask1 = _mm256_set_epi32(7, 3, 5, 1, 6, 2, 4, 0); + +#define STORE_CI12_4CI16_BLOCK(reg0, reg1, reg2, reg3) \ +{ \ + __m256i rs0, rs1, rs2, rs3; \ + CONVERT_I12_I16_BLOCK(reg0, rs0); \ + CONVERT_I12_I16_BLOCK(reg1, rs1); \ + CONVERT_I12_I16_BLOCK(reg2, rs2); \ + CONVERT_I12_I16_BLOCK(reg3, rs3); \ + \ + rs0 = _mm256_permutevar8x32_epi32(rs0, permmask1); \ + rs1 = _mm256_permutevar8x32_epi32(rs1, permmask1); \ + rs2 = _mm256_permutevar8x32_epi32(rs2, permmask1); \ + rs3 = _mm256_permutevar8x32_epi32(rs3, permmask1); \ + \ + __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b0000)); \ + __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b1111)); \ + __m256i z2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs2), _mm256_castsi256_pd(rs3), 0b0000)); \ + __m256i z3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs2), _mm256_castsi256_pd(rs3), 0b1111)); \ + \ + __m256i i0 = _mm256_permute2x128_si256(z0, z2, 0b00100000); \ + __m256i i1 = _mm256_permute2x128_si256(z0, z2, 0b00110001); \ + __m256i i2 = _mm256_permute2x128_si256(z1, z3, 0b00100000); \ + __m256i i3 = _mm256_permute2x128_si256(z1, z3, 0b00110001); \ + \ + _mm256_storeu_si256((__m256i*)outdata_0, i0); \ + _mm256_storeu_si256((__m256i*)outdata_1, i1); \ + _mm256_storeu_si256((__m256i*)outdata_2, i2); \ + _mm256_storeu_si256((__m256i*)outdata_3, i3); \ + \ + outdata_0 += 16; \ + outdata_1 += 16; \ + outdata_2 += 16; \ + outdata_3 += 16; \ +} diff --git a/src/lib/xdsp/templates/conv_ci12_4ci16_avx2.t b/src/lib/xdsp/templates/conv_ci12_4ci16_avx2.t index 687a2d34..3a4ae291 100644 --- a/src/lib/xdsp/templates/conv_ci12_4ci16_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_4ci16_avx2.t @@ -18,63 +18,8 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, int16_t* outdata_2 = (int16_t*)outdata_2_p; int16_t* outdata_3 = (int16_t*)outdata_3_p; - const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); - - const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); - const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); - - const __m256i permmask0 = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); - const __m256i permmask1 = _mm256_set_epi32(7, 3, 5, 1, 6, 2, 4, 0); - - const __m256i shfl = _mm256_set_epi8( - 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, - 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, - 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, - 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); - -#define CONVERT_CI12_4CI16_BLOCK(reg, result) \ - { \ - __m256i v0 = _mm256_permutevar8x32_epi32(reg, permmask0); \ - __m256i r = _mm256_shuffle_epi8(v0, shfl); \ - \ - __m256i r0 = _mm256_and_si256(r, mask0); \ - __m256i r1 = _mm256_and_si256(_mm256_srli_epi64(r, 4), mask1); \ - result = _mm256_or_si256(r0, r1); \ - } - -#define STORE_CI12_4CI16_BLOCK(reg0, reg1, reg2, reg3) \ - { \ - __m256i rs0, rs1, rs2, rs3; \ - CONVERT_CI12_4CI16_BLOCK(reg0, rs0); \ - CONVERT_CI12_4CI16_BLOCK(reg1, rs1); \ - CONVERT_CI12_4CI16_BLOCK(reg2, rs2); \ - CONVERT_CI12_4CI16_BLOCK(reg3, rs3); \ - \ - rs0 = _mm256_permutevar8x32_epi32(rs0, permmask1); \ - rs1 = _mm256_permutevar8x32_epi32(rs1, permmask1); \ - rs2 = _mm256_permutevar8x32_epi32(rs2, permmask1); \ - rs3 = _mm256_permutevar8x32_epi32(rs3, permmask1); \ - \ - __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b0000)); \ - __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b1111)); \ - __m256i z2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs2), _mm256_castsi256_pd(rs3), 0b0000)); \ - __m256i z3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs2), _mm256_castsi256_pd(rs3), 0b1111)); \ - \ - __m256i i0 = _mm256_permute2x128_si256(z0, z2, 0b00100000); \ - __m256i i1 = _mm256_permute2x128_si256(z0, z2, 0b00110001); \ - __m256i i2 = _mm256_permute2x128_si256(z1, z3, 0b00100000); \ - __m256i i3 = _mm256_permute2x128_si256(z1, z3, 0b00110001); \ - \ - _mm256_storeu_si256((__m256i*)outdata_0, i0); \ - _mm256_storeu_si256((__m256i*)outdata_1, i1); \ - _mm256_storeu_si256((__m256i*)outdata_2, i2); \ - _mm256_storeu_si256((__m256i*)outdata_3, i3); \ - \ - outdata_0 += 16; \ - outdata_1 += 16; \ - outdata_2 += 16; \ - outdata_3 += 16; \ - } +#include "conv_i12_i16_avx2.inc" +#include "conv_ci12_4ci16_avx2.inc" __m256i y0, y1, y2, y3; @@ -103,26 +48,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef STORE_CI12_4CI16_BLOCK -#undef CONVERT_CI12_4CI16_BLOCK +#undef CONVERT_I12_I16_BLOCK const uint8_t *indata = (const uint8_t*)in; - - for (; i >= 12; i -= 12) { - /* read 12 bytes -> 4ci16 */ - - uint64_t v0 = *(const uint64_t *)(indata + 0); - uint64_t v1 = *(const uint64_t *)(indata + 6); - indata += 12; - - *(outdata_0++) = (int16_t)((v0 << 4) ); - *(outdata_0++) = (int16_t)((v0 >> 8) & 0xfff0); - *(outdata_1++) = (int16_t)((v0 >> 20) & 0xfff0); - *(outdata_1++) = (int16_t)((v0 >> 32) & 0xfff0); - *(outdata_2++) = (int16_t)((v1 << 4) ); - *(outdata_2++) = (int16_t)((v1 >> 8) & 0xfff0); - *(outdata_3++) = (int16_t)((v1 >> 20) & 0xfff0); - *(outdata_3++) = (int16_t)((v1 >> 32) & 0xfff0); - } - // do nothing with tail + #include "conv_ci12_4ci16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t new file mode 100644 index 00000000..1122a623 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t @@ -0,0 +1,98 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + /* 12 bits -> 16 bits => 3 -> 4 */ + if ((outdatabsz * 3 / 4) < i) + i = (outdatabsz * 3 / 4); + + const uint64_t *in = (const uint64_t*)indata_p; + int16_t* outdata_0 = (int16_t*)outdata_0_p; + int16_t* outdata_1 = (int16_t*)outdata_1_p; + int16_t* outdata_2 = (int16_t*)outdata_2_p; + int16_t* outdata_3 = (int16_t*)outdata_3_p; + + //AVX512BW block + { + #include "conv_i12_i16_avx512bw.inc" + + __m512i y0, y1, y2, y3; + __m512i rs0, rs1, rs2, rs3; + __m512i a0, a1, a2, a3; + __m512i b0, b1, b2, b3; + + const __m512i imask0 = _mm512_set_epi32(30,14,28,12,26,10,24,8,22,6,20,4,18,2,16,0); + const __m512i imask1 = _mm512_set_epi32(31,15,29,13,27,11,25,9,23,7,21,5,19,3,17,1); + const __m512i imask2 = _mm512_set_epi32(15,11,7,3, 14,10,6,2, 13,9,5,1, 12,8,4,0); + + for(; i >= 2*96; i -= 2*96) + { + y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); + y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); + y2 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 12)); + y3 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 18)); + in += 24; + + CONVERT_I12_I16_BLOCK(y0, rs0); + CONVERT_I12_I16_BLOCK(y1, rs1); + CONVERT_I12_I16_BLOCK(y2, rs2); + CONVERT_I12_I16_BLOCK(y3, rs3); + + a0 = _mm512_permutex2var_epi32(rs0, imask0, rs1); + a1 = _mm512_permutex2var_epi32(rs0, imask1, rs1); + a2 = _mm512_permutex2var_epi32(rs2, imask0, rs3); + a3 = _mm512_permutex2var_epi32(rs2, imask1, rs3); + + b0 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a0), _mm512_castsi512_pd(a2), 0b00000000)); //1 + b2 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a0), _mm512_castsi512_pd(a2), 0b11111111)); //1 + b1 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a1), _mm512_castsi512_pd(a3), 0b00000000)); //1 + b3 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a1), _mm512_castsi512_pd(a3), 0b11111111)); //1 + + _mm512_store_si512((__m512i*)outdata_0, _mm512_permutexvar_epi32(imask2, b0)); + _mm512_store_si512((__m512i*)outdata_1, _mm512_permutexvar_epi32(imask2, b1)); + _mm512_store_si512((__m512i*)outdata_2, _mm512_permutexvar_epi32(imask2, b2)); + _mm512_store_si512((__m512i*)outdata_3, _mm512_permutexvar_epi32(imask2, b3)); + + outdata_0 += 32; + outdata_1 += 32; + outdata_2 += 32; + outdata_3 += 32; + } + + #undef CONVERT_I12_I16_BLOCK + } + + //AVX2 block + { + #include "conv_i12_i16_avx2.inc" + #include "conv_ci12_4ci16_avx2.inc" + + if(i >= 96) + { + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); // 8 1/3 + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); // 8 1/3 + __m256i y2 = _mm256_maskload_epi64((const long long*)(in + 6), load_mask); // 8 1/3 + __m256i y3 = _mm256_maskload_epi64((const long long*)(in + 9), load_mask); // 8 1/3 + in += 12; + i -= 96; + + STORE_CI12_4CI16_BLOCK(y0, y1, y2, y3); + } + + #undef STORE_CI12_4CI16_BLOCK + #undef CONVERT_I12_I16_BLOCK + } + + //Generic block + { + const uint8_t *indata = (const uint8_t*)in; + #include "conv_ci12_4ci16_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci12_4ci16_generic.inc b/src/lib/xdsp/templates/conv_ci12_4ci16_generic.inc new file mode 100644 index 00000000..50859a93 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci12_4ci16_generic.inc @@ -0,0 +1,16 @@ +for (; i >= 12; i -= 12) { + /* read 12 bytes -> 4ci16 */ + + uint64_t v0 = *(const uint64_t *)(indata + 0); + uint64_t v1 = *(const uint64_t *)(indata + 6); + indata += 12; + + *(outdata_0++) = (int16_t)((v0 << 4) ); + *(outdata_0++) = (int16_t)((v0 >> 8) & 0xfff0); + *(outdata_1++) = (int16_t)((v0 >> 20) & 0xfff0); + *(outdata_1++) = (int16_t)((v0 >> 32) & 0xfff0); + *(outdata_2++) = (int16_t)((v1 << 4) ); + *(outdata_2++) = (int16_t)((v1 >> 8) & 0xfff0); + *(outdata_3++) = (int16_t)((v1 >> 20) & 0xfff0); + *(outdata_3++) = (int16_t)((v1 >> 32) & 0xfff0); +} diff --git a/src/lib/xdsp/templates/conv_ci12_4ci16_generic.t b/src/lib/xdsp/templates/conv_ci12_4ci16_generic.t index 74334ba5..71813e9b 100644 --- a/src/lib/xdsp/templates/conv_ci12_4ci16_generic.t +++ b/src/lib/xdsp/templates/conv_ci12_4ci16_generic.t @@ -18,24 +18,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, int16_t* outdata_2 = (int16_t*)outdata_2_p; int16_t* outdata_3 = (int16_t*)outdata_3_p; - for (; i >= 12; i -= 12) { - /* read 12 bytes -> 4ci16 */ - - uint64_t v0 = *(const uint64_t *)(indata + 0); - uint64_t v1 = *(const uint64_t *)(indata + 6); - indata += 12; - - *(outdata_0++) = (int16_t)((v0 << 4) ); - *(outdata_0++) = (int16_t)((v0 >> 8) & 0xfff0); - *(outdata_1++) = (int16_t)((v0 >> 20) & 0xfff0); - *(outdata_1++) = (int16_t)((v0 >> 32) & 0xfff0); - *(outdata_2++) = (int16_t)((v1 << 4) ); - *(outdata_2++) = (int16_t)((v1 >> 8) & 0xfff0); - *(outdata_3++) = (int16_t)((v1 >> 20) & 0xfff0); - *(outdata_3++) = (int16_t)((v1 >> 32) & 0xfff0); - } - - // tail ignored + #include "conv_ci12_4ci16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_f32_i12_avx2.inc b/src/lib/xdsp/templates/conv_f32_i12_avx2.inc new file mode 100644 index 00000000..1f9f9c3c --- /dev/null +++ b/src/lib/xdsp/templates/conv_f32_i12_avx2.inc @@ -0,0 +1,15 @@ +const __m256 scale = _mm256_set1_ps(1.0f / CONV_SCALE); + +#define CONVERT_F32_I12_BLOCK(v0, v1) \ +{ \ + v0 = _mm256_mul_ps(v0, scale); \ + v1 = _mm256_mul_ps(v1, scale); \ +\ + __m256i i0 = _mm256_cvtps_epi32(v0); \ + __m256i i1 = _mm256_cvtps_epi32(v1); \ +\ + __m256i ii0 = _mm256_packs_epi32(i0, i1); \ + ii0 = _mm256_permute4x64_epi64(ii0, _MM_SHUFFLE(3,1,2,0)); \ +\ + CONVERT_I16_I12_BLOCK(ii0, out64); \ +} diff --git a/src/lib/xdsp/templates/conv_f32_i12_avx2.t b/src/lib/xdsp/templates/conv_f32_i12_avx2.t index 1ce32d22..adf45b0f 100644 --- a/src/lib/xdsp/templates/conv_f32_i12_avx2.t +++ b/src/lib/xdsp/templates/conv_f32_i12_avx2.t @@ -11,24 +11,8 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const float *indata = (const float*)indata_p; uint64_t *out64 = (uint64_t*)outdata_p; - const __m256 scale = _mm256_set1_ps(1.0f / CONV_SCALE); - #include "conv_i16_i12_avx2.inc" - -#define CONVERT_F32_I12_BLOCK(v0, v1) \ - { \ - v0 = _mm256_mul_ps(v0, scale); \ - v1 = _mm256_mul_ps(v1, scale); \ - \ - __m256i i0 = _mm256_cvtps_epi32(v0); \ - __m256i i1 = _mm256_cvtps_epi32(v1); \ - \ - __m256i ii0 = _mm256_packs_epi32(i0, i1); \ - ii0 = _mm256_permute4x64_epi64(ii0, _MM_SHUFFLE(3,1,2,0)); \ - \ - CONVERT_I16_I12_BLOCK(ii0, out64); \ - } -// CONVERT_F32_I12_BLOCK end +#include "conv_f32_i12_avx2.inc" __m256 v0, v1, v2, v3; @@ -44,11 +28,12 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, CONVERT_F32_I12_BLOCK(v2, v3); } - for (; i >= 32*2; i -= 32*2) + if (i >= 32*2) { v0 = _mm256_loadu_ps(indata + 0); v1 = _mm256_loadu_ps(indata + 8); indata += 16; + i -= 32*2; CONVERT_F32_I12_BLOCK(v0, v1); } @@ -60,29 +45,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, #define I16RND(x) x > 0 ? (int16_t)(x + 0.5f) : (int16_t)(x - 0.5f) uint8_t* outdata = (uint8_t*)out64; - - for (; i >= 8; i -= 8) { - - float f0 = *(indata++) / CONV_SCALE; - float f1 = *(indata++) / CONV_SCALE; - - wu_i16u32_t a = {{I16RND(f0), I16RND(f1)}}; - wu_u32b_t c = {(a.u & 0xfff00000) | ((a.u << 4) & 0x000fff00)}; - - *(outdata++) = c.b[1]; - *(outdata++) = c.b[2]; - *(outdata++) = c.b[3]; - } - - if(i >= 4) - { - float f = *indata / CONV_SCALE; - wu_i16b_t c = {I16RND(f)}; - - *(outdata++) = c.b[0]; - *(outdata++) = c.b[1] >> 4; - i -= 4; - } + #include "conv_f32_i12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_f32_i12_avx512bw.inc b/src/lib/xdsp/templates/conv_f32_i12_avx512bw.inc new file mode 100644 index 00000000..4670f990 --- /dev/null +++ b/src/lib/xdsp/templates/conv_f32_i12_avx512bw.inc @@ -0,0 +1,16 @@ +const __m512 scale = _mm512_set1_ps(1.0f / CONV_SCALE); +const __m512i idx = _mm512_set_epi64(7,5,3,1,6,4,2,0); + +#define CONVERT_F32_I12_BLOCK(v0, v1) \ +{ \ + v0 = _mm512_mul_ps(v0, scale); \ + v1 = _mm512_mul_ps(v1, scale); \ +\ + __m512i i0 = _mm512_cvtps_epi32(v0); \ + __m512i i1 = _mm512_cvtps_epi32(v1); \ +\ + __m512i ii0 = _mm512_packs_epi32(i0, i1); \ + ii0 = _mm512_permutexvar_epi64(idx, ii0); \ +\ + CONVERT_I16_I12_BLOCK(ii0, out64); \ +} diff --git a/src/lib/xdsp/templates/conv_f32_i12_avx512bw.t b/src/lib/xdsp/templates/conv_f32_i12_avx512bw.t new file mode 100644 index 00000000..2b22c6f4 --- /dev/null +++ b/src/lib/xdsp/templates/conv_f32_i12_avx512bw.t @@ -0,0 +1,61 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 8 / 3) < i) + i = (outdatabsz * 8 / 3); + + const float *indata = (const float*)indata_p; + uint64_t *out64 = (uint64_t*)outdata_p; + + //AVX512 block + { + #include "conv_i16_i12_avx512bw.inc" + #include "conv_f32_i12_avx512bw.inc" + + __m512 v0, v1; + + for(; i >= 64*2; i -= 64*2) + { + v0 = _mm512_loadu_ps(indata + 0); + v1 = _mm512_loadu_ps(indata + 16); + indata += 32; + CONVERT_F32_I12_BLOCK(v0, v1); + } + + #undef CONVERT_F32_I12_BLOCK + #undef CONVERT_I16_I12_BLOCK + } + + //AVX2 block + { + #include "conv_i16_i12_avx2.inc" + #include "conv_f32_i12_avx2.inc" + + if(i >= 32*2) + { + __m256 v0 = _mm256_loadu_ps(indata + 0); + __m256 v1 = _mm256_loadu_ps(indata + 8); + indata += 16; + i -= 32*2; + CONVERT_F32_I12_BLOCK(v0, v1); + } + + #undef CONVERT_F32_I12_BLOCK + #undef CONVERT_I16_I12_BLOCK + } + + //Generic block + { + #undef I16RND + #define I16RND(x) x > 0 ? (int16_t)(x + 0.5f) : (int16_t)(x - 0.5f) + + uint8_t* outdata = (uint8_t*)out64; + #include "conv_f32_i12_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_f32_i12_generic.inc b/src/lib/xdsp/templates/conv_f32_i12_generic.inc new file mode 100644 index 00000000..98261fad --- /dev/null +++ b/src/lib/xdsp/templates/conv_f32_i12_generic.inc @@ -0,0 +1,22 @@ +for (; i >= 8; i -= 8) { + + float f0 = *(indata++) / CONV_SCALE; + float f1 = *(indata++) / CONV_SCALE; + + wu_i16u32_t a = {{I16RND(f0), I16RND(f1)}}; + wu_u32b_t c = {(a.u & 0xfff00000) | ((a.u << 4) & 0x000fff00)}; + + *(outdata++) = c.b[1]; + *(outdata++) = c.b[2]; + *(outdata++) = c.b[3]; +} + +if(i >= 4) +{ + float f = *indata / CONV_SCALE; + wu_i16b_t c = {I16RND(f)}; + + *(outdata++) = c.b[0]; + *(outdata++) = c.b[1] >> 4; + i -= 4; +} diff --git a/src/lib/xdsp/templates/conv_f32_i12_generic.t b/src/lib/xdsp/templates/conv_f32_i12_generic.t index aedb6b78..6bf80974 100644 --- a/src/lib/xdsp/templates/conv_f32_i12_generic.t +++ b/src/lib/xdsp/templates/conv_f32_i12_generic.t @@ -11,28 +11,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const float* indata = (const float*)indata_p; uint8_t* outdata = (uint8_t*)outdata_p; - for (; i >= 8; i -= 8) { - - float f0 = *(indata++) / CONV_SCALE; - float f1 = *(indata++) / CONV_SCALE; - - wu_i16u32_t a = {{I16RND(f0), I16RND(f1)}}; - wu_u32b_t c = {(a.u & 0xfff00000) | ((a.u << 4) & 0x000fff00)}; - - *(outdata++) = c.b[1]; - *(outdata++) = c.b[2]; - *(outdata++) = c.b[3]; - } - - if(i >= 4) - { - float f = *indata / CONV_SCALE; - wu_i16b_t c = {I16RND(f)}; - - *(outdata++) = c.b[0]; - *(outdata++) = c.b[1] >> 4; - i -= 4; - } + #include "conv_f32_i12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx2.inc b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc new file mode 100644 index 00000000..85c11a42 --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc @@ -0,0 +1,50 @@ +const __m256 scale = _mm256_set1_ps(CONV_SCALE); + +/* +* reg: +* | (3) | (2) | (1) | (0) | +* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +* | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | +* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ +* | 0 0 0 0 0 0 0 0 | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | +* +* v0: +* | | | | | +* | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | 0 0 0 0 0 0 0 0 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | +* r: +* | | | | | +* | f15 | f14 | 0 | f13 | f12 | 0 | f11 | f10 | 0 | f9 | f8 | 0 | f7 | f6 | 0 | f5 | f4 | 0 | f3 | f2 | 0 | f1 | f0 | 0 | +* r0: +* | | | | | +* | f15 |0| 00 00 | f13 |0| 00 00 | f11 |0| 00 00 | f9 |0| 00 00 | f7 |0| 00 00 | f5 |0| 00 00 | f3 |0| 00 00 | f1 |0| 00 00 | + r1: +* | | | | | +* | 00 00 | f14 |0| 00 00 | f12 |0| 00 00 | f10 |0| 00 00 | f8 |0| 00 00 | f6 |0| 00 00 | f4 |0| 00 00 | f2 |0| 00 00 | f0 |0| +* res: +* | | | | | +* | f15 |0| f14 |0| f13 |0| f12 |0| f11 |0| f10 |0| f9 |0| f8 |0| f7 |0| f6 |0| f5 |0| f4 |0| f3 |0| f2 |0| f1 |0| f0 |0| +*/ + +#define CONVERT_I12_F32_BLOCK(reg, res0, res1) \ +{ \ + __m256i result; \ + CONVERT_I12_I16_BLOCK(reg, result); \ + \ + __m256i d0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(result)); \ + __m256i d1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(result, 1)); \ + \ + res0 = _mm256_cvtepi32_ps(d0); /* 4 1|2 */ \ + res1 = _mm256_cvtepi32_ps(d1); /* 4 1|2 */ \ + \ + res0 = _mm256_mul_ps(res0, scale); /* 4 1|2 */ \ + res1 = _mm256_mul_ps(res1, scale); /* 4 1|2 */ \ +} + +#define CONVERT_I12_F32_BLOCK_STORE1(reg) \ +{ \ + __m256 res0, res1; \ + CONVERT_I12_F32_BLOCK(reg, res0, res1); \ + _MM256_STOREX_PS(outdata + 0, res0); \ + _MM256_STOREX_PS(outdata + 8, res1); \ + outdata += 16; \ +} diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx2.t b/src/lib/xdsp/templates/conv_i12_f32_avx2.t index d02d1d84..2f2062cd 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx2.t +++ b/src/lib/xdsp/templates/conv_i12_f32_avx2.t @@ -10,68 +10,10 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, i = (outdatabsz * 3 / 8); const uint64_t *in = (const uint64_t*)indata_p; - float* out = (float*)outdata_p; + float* outdata = (float*)outdata_p; - const __m256 scale = _mm256_set1_ps(CONV_SCALE); - const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); - - const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); - const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); - - const __m256i permmask = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); - const __m256i shfl = _mm256_set_epi8( - 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, - 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, - 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, - 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); - -/* -* reg: -* | (3) | (2) | (1) | (0) | -* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -* | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | -* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -* | 0 0 0 0 0 0 0 0 | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | -* -* v0: -* | | | | | -* | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | 0 0 0 0 0 0 0 0 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | -* r: -* | | | | | -* | f15 | f14 | 0 | f13 | f12 | 0 | f11 | f10 | 0 | f9 | f8 | 0 | f7 | f6 | 0 | f5 | f4 | 0 | f3 | f2 | 0 | f1 | f0 | 0 | -* r0: -* | | | | | -* | f15 |0| 00 00 | f13 |0| 00 00 | f11 |0| 00 00 | f9 |0| 00 00 | f7 |0| 00 00 | f5 |0| 00 00 | f3 |0| 00 00 | f1 |0| 00 00 | - r1: -* | | | | | -* | 00 00 | f14 |0| 00 00 | f12 |0| 00 00 | f10 |0| 00 00 | f8 |0| 00 00 | f6 |0| 00 00 | f4 |0| 00 00 | f2 |0| 00 00 | f0 |0| -* res: -* | | | | | -* | f15 |0| f14 |0| f13 |0| f12 |0| f11 |0| f10 |0| f9 |0| f8 |0| f7 |0| f6 |0| f5 |0| f4 |0| f3 |0| f2 |0| f1 |0| f0 |0| -*/ - -#define CONVERT_I12_F32_BLOCK(reg) \ - { \ - __m256i v0 = _mm256_permutevar8x32_epi32(reg, permmask); \ - __m256i r = _mm256_shuffle_epi8(v0, shfl); \ - \ - __m256i r0 = _mm256_and_si256(r, mask0); \ - __m256i r1 = _mm256_and_si256(_mm256_srli_epi64(r, 4), mask1); \ - __m256i result = _mm256_or_si256(r0, r1); \ - \ - __m256i d0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(result)); \ - __m256i d1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(result, 1)); \ - \ - __m256 f0 = _mm256_cvtepi32_ps(d0); /* 4 1|2 */ \ - __m256 f1 = _mm256_cvtepi32_ps(d1); /* 4 1|2 */ \ - \ - f0 = _mm256_mul_ps(f0, scale); /* 4 1|2 */ \ - f1 = _mm256_mul_ps(f1, scale); /* 4 1|2 */ \ - \ - _MM256_STOREX_PS(out, f0); out += 8; /* 1 1|2 */ \ - _MM256_STOREX_PS(out, f1); out += 8; /* 1 1|2 */ \ - } -// CONVERT_I12_F32_BLOCK end lat 40 +#include "conv_i12_i16_avx2.inc" +#include "conv_i12_f32_avx2.inc" __m256i y0, y1, y2, y3; @@ -85,10 +27,10 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, for (; i >= 2*96; i -= 96) { - CONVERT_I12_F32_BLOCK(y0); - CONVERT_I12_F32_BLOCK(y1); - CONVERT_I12_F32_BLOCK(y2); - CONVERT_I12_F32_BLOCK(y3); + CONVERT_I12_F32_BLOCK_STORE1(y0); + CONVERT_I12_F32_BLOCK_STORE1(y1); + CONVERT_I12_F32_BLOCK_STORE1(y2); + CONVERT_I12_F32_BLOCK_STORE1(y3); y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); // 8 1/3 y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); // 8 1/3 @@ -99,36 +41,17 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, i -= 96; - CONVERT_I12_F32_BLOCK(y0); - CONVERT_I12_F32_BLOCK(y1); - CONVERT_I12_F32_BLOCK(y2); - CONVERT_I12_F32_BLOCK(y3); + CONVERT_I12_F32_BLOCK_STORE1(y0); + CONVERT_I12_F32_BLOCK_STORE1(y1); + CONVERT_I12_F32_BLOCK_STORE1(y2); + CONVERT_I12_F32_BLOCK_STORE1(y3); } #undef CONVERT_I12_F32_BLOCK +#undef CONVERT_I12_F32_BLOCK_STORE1 +#undef CONVERT_I12_I16_BLOCK const uint8_t *indata = (const uint8_t*)in; - - while(i >= 3) - { - uint8_t v0 = *(indata++); - uint8_t v1 = *(indata++); - uint8_t v2 = *(indata++); - i -= 3; - - float a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); - float b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); - - *(out++) = a * CONV_SCALE; - *(out++) = b * CONV_SCALE; - } - - if(i >= 2) - { - uint16_t v = *(const uint16_t*)indata; - float a = (int16_t)(v << 4); - *(out++) = a * CONV_SCALE; - i -= 2; - } + #include "conv_i12_f32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc new file mode 100644 index 00000000..47110ff0 --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc @@ -0,0 +1,16 @@ +const __m512 scale = _mm512_set1_ps(CONV_SCALE); + +#define CONVERT_I12_F32_BLOCK(reg, res0, res1) \ +{ \ + __m512i result; \ + CONVERT_I12_I16_BLOCK(reg, result); \ + \ + __m512i d0 = _mm512_cvtepi16_epi32(_mm512_castsi512_si256(result)); \ + __m512i d1 = _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(result, 1)); \ + \ + res0 = _mm512_cvtepi32_ps(d0); \ + res1 = _mm512_cvtepi32_ps(d1); \ + \ + res0 = _mm512_mul_ps(res0, scale); \ + res1 = _mm512_mul_ps(res1, scale); \ +} diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.t b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.t new file mode 100644 index 00000000..fb42d4bf --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.t @@ -0,0 +1,70 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + /* 12 bits -> 32 bits => 3 -> 8 */ + if ((outdatabsz * 3 / 8) < i) + i = (outdatabsz * 3 / 8); + + const uint64_t *in = (const uint64_t*)indata_p; + float* outdata = (float*)outdata_p; + + //AVX512 block + { + #include "conv_i12_i16_avx512bw.inc" + #include "conv_i12_f32_avx512bw.inc" + + __m512i y0, y1; + __m512 res0, res1, res2, res3; + + for(; i >= 96; i -= 96) + { + y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); + y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); + in += 12; + + CONVERT_I12_F32_BLOCK(y0, res0, res1); + CONVERT_I12_F32_BLOCK(y1, res2, res3); + + _mm512_storeu_ps(outdata + 0, res0); + _mm512_storeu_ps(outdata + 16, res1); + _mm512_storeu_ps(outdata + 32, res2); + _mm512_storeu_ps(outdata + 48, res3); + outdata += 64; + } + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_I16_BLOCK + } + + //AVX2 block + { + #include "conv_i12_i16_avx2.inc" + #include "conv_i12_f32_avx2.inc" + + if(i >= 48) + { + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + in += 6; + i -= 48; + + CONVERT_I12_F32_BLOCK_STORE1(y0); + CONVERT_I12_F32_BLOCK_STORE1(y1); + } + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_I12_I16_BLOCK + } + + //Generic block + { + const uint8_t *indata = (const uint8_t*)in; + #include "conv_i12_f32_generic.inc" + } +} +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i12_f32_generic.inc b/src/lib/xdsp/templates/conv_i12_f32_generic.inc new file mode 100644 index 00000000..23b1463c --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_f32_generic.inc @@ -0,0 +1,42 @@ +/* memory stream: MSB...LSB +* 0x00 f0[7:0] +* 0x01 {f1[3:0],f0[11:8]} +* 0x02 f1[11:4] +* ..... +*/ + +/* v2 v1 v0 +* +-----+-----+-----+ +* | 8 | 8 | 8 | +* +-----+-----+-----+ +* | 12 | 12 | +* +-----+-----+-----+ +* +* +-----+-----+ +* as = |v1| v0 |00| +* +-----+-----+ +* bs = | v2 |v1|00| +* +-----+-----+ +*/ + +while(i >= 3) +{ + uint8_t v0 = *(indata++); + uint8_t v1 = *(indata++); + uint8_t v2 = *(indata++); + i -= 3; + + float a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); + float b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); + + *(outdata++) = a * CONV_SCALE; + *(outdata++) = b * CONV_SCALE; +} + +if(i >= 2) +{ + uint16_t v = *(const uint16_t*)indata; + float a = (int16_t)(v << 4); + *(outdata++) = a * CONV_SCALE; + i -= 2; +} diff --git a/src/lib/xdsp/templates/conv_i12_f32_generic.t b/src/lib/xdsp/templates/conv_i12_f32_generic.t index b579f98f..a447930a 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_generic.t +++ b/src/lib/xdsp/templates/conv_i12_f32_generic.t @@ -12,156 +12,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const uint8_t* indata = (const uint8_t*)indata_p; float* outdata = (float*)outdata_p; -#if 0 - uint64_t v0, v1, v2, a0, a1, a2, a3; - - typedef int16_t v4i16 __attribute__ ((vector_size (8))); - union u_v4i16 { uint64_t vect; v4i16 arr; }; - typedef union u_v4i16 u_v4i16_t; - - u_v4i16_t x[4]; -#endif - -#if 0 - for (; i >= 3 * sizeof(uint64_t); i -= 3 * sizeof(uint64_t)) { - /* read 64*3 = 192 bits -> 16 i32 & floats */ - - v0 = *(const uint64_t *)(indata + 0); - v1 = *(const uint64_t *)(indata + 8); - v2 = *(const uint64_t *)(indata + 16); - - indata += 3 * sizeof(uint64_t); - - a0 = (v0 << 4) & 0x000000000000fff0; - a1 = (v0 << 8) & 0x00000000fff00000; - a2 = (v0 << 12) & 0x0000fff000000000; - a3 = (v0 << 16) & 0xfff0000000000000; - - x[0].vect = a0 | a1 | a2 | a3; - - a0 = (v0 >> 44) & 0x000000000000fff0; - a1 = ((v0 >> 40) & 0x0000000000f00000) | ((v1 << 24) & 0x00000000ff000000); - a2 = (v1 << 28) & 0x0000fff000000000; - a3 = (v1 << 32) & 0xfff0000000000000; - - x[1].vect = a0 | a1 | a2 | a3; - - a0 = (v1 >> 28) & 0x000000000000fff0; - a1 = (v1 >> 24) & 0x00000000fff00000; - a2 = ((v1 >> 20) & 0x00000ff000000000) | ((v2 << 44) & 0x0000f00000000000); - a3 = (v2 << 48) & 0xfff0000000000000; - - x[2].vect = a0 | a1 | a2 | a3; - - a0 = (v2 >> 12) & 0x000000000000fff0; - a1 = (v2 >> 8) & 0x00000000fff00000; - a2 = (v2 >> 4) & 0x0000fff000000000; - a3 = v2 & 0xfff0000000000000; - - x[3].vect = a0 | a1 | a2 | a3; - - for(unsigned j = 0; j < 4; j++) - { - *(outdata++) = x[j].arr[0] * CONV_SCALE; - *(outdata++) = x[j].arr[1] * CONV_SCALE; - *(outdata++) = x[j].arr[2] * CONV_SCALE; - *(outdata++) = x[j].arr[3] * CONV_SCALE; - } - } -#endif - -#if 0 //this algorithm is slow - for (; i >= 3 * sizeof(uint64_t); i -= 3 * sizeof(uint64_t)) { - /* read 64*3 = 192 bits -> 16 i32 & floats */ - - v0 = *(const uint64_t *)(indata + 0); - v1 = *(const uint64_t *)(indata + 8); - v2 = *(const uint64_t *)(indata + 16); - - indata += 3 * sizeof(uint64_t); - - float f0 = (int16_t)(v0 << 4); - float f1 = (int16_t)((v0 >> 8) & 0xfff0); - float f2 = (int16_t)((v0 >> 20) & 0xfff0); - float f3 = (int16_t)((v0 >> 32) & 0xfff0); - float f4 = (int16_t)((v0 >> 44) & 0xfff0); - - float f5 = ((int16_t)(v0 >> 56) & 0x00f0) | (int16_t)(v1 << 8); - - float f6 = (int16_t)((v1 >> 4) & 0xfff0); - float f7 = (int16_t)((v1 >> 16) & 0xfff0); - float f8 = (int16_t)((v1 >> 28) & 0xfff0); - float f9 = (int16_t)((v1 >> 40) & 0xfff0); - - float f10 = (int16_t)((v1 >> 52) & 0x0ff0) | (int16_t)(v2 << 12); - - float f11 = (int16_t)(v2 & 0xfff0); - float f12 = (int16_t)((v2 >> 12) & 0xfff0); - float f13 = (int16_t)((v2 >> 24) & 0xfff0); - float f14 = (int16_t)((v2 >> 36) & 0xfff0); - float f15 = (int16_t)((v2 >> 48) & 0xfff0); - - *(outdata++) = f0 * CONV_SCALE; - *(outdata++) = f1 * CONV_SCALE; - *(outdata++) = f2 * CONV_SCALE; - *(outdata++) = f3 * CONV_SCALE; - *(outdata++) = f4 * CONV_SCALE; - *(outdata++) = f5 * CONV_SCALE; - *(outdata++) = f6 * CONV_SCALE; - *(outdata++) = f7 * CONV_SCALE; - *(outdata++) = f8 * CONV_SCALE; - *(outdata++) = f9 * CONV_SCALE; - *(outdata++) = f10 * CONV_SCALE; - *(outdata++) = f11 * CONV_SCALE; - *(outdata++) = f12 * CONV_SCALE; - *(outdata++) = f13 * CONV_SCALE; - *(outdata++) = f14 * CONV_SCALE; - *(outdata++) = f15 * CONV_SCALE; - } -#endif - - /* memory stream: MSB...LSB - * 0x00 f0[7:0] - * 0x01 {f1[3:0],f0[11:8]} - * 0x02 f1[11:4] - * ..... - */ - - /* v2 v1 v0 - * +-----+-----+-----+ - * | 8 | 8 | 8 | - * +-----+-----+-----+ - * | 12 | 12 | - * +-----+-----+-----+ - * - * +-----+-----+ - * as = |v1| v0 |00| - * +-----+-----+ - * bs = | v2 |v1|00| - * +-----+-----+ - */ - - while(i >= 3) - { - uint8_t v0 = *(indata++); - uint8_t v1 = *(indata++); - uint8_t v2 = *(indata++); - i -= 3; - - float a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); - float b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); - - *(outdata++) = a * CONV_SCALE; - *(outdata++) = b * CONV_SCALE; - } - - if(i >= 2) - { - uint16_t v = *(const uint16_t*)indata; - float a = (int16_t)(v << 4); - *(outdata++) = a * CONV_SCALE; - i -= 2; - } + #include "conv_i12_f32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx2.inc b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc new file mode 100644 index 00000000..dfddab87 --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc @@ -0,0 +1,21 @@ +const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); + +const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); +const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); + +const __m256i permmask = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); +const __m256i shfl = _mm256_set_epi8( + 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, + 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, + 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, + 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); + +#define CONVERT_I12_I16_BLOCK(reg, result) \ +{ \ + __m256i v0 = _mm256_permutevar8x32_epi32(reg, permmask); \ + __m256i r = _mm256_shuffle_epi8(v0, shfl); \ + \ + __m256i r0 = _mm256_and_si256(r, mask0); \ + __m256i r1 = _mm256_and_si256(_mm256_srli_epi64(r, 4), mask1); \ + result = _mm256_or_si256(r0, r1); \ +} diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx2.t b/src/lib/xdsp/templates/conv_i12_i16_avx2.t index a1319b22..eb29e34f 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx2.t +++ b/src/lib/xdsp/templates/conv_i12_i16_avx2.t @@ -12,33 +12,10 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const uint64_t *in = (const uint64_t*)indata_p; int16_t* outdata = (int16_t*)outdata_p; - const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); - - const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); - const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); - - const __m256i permmask = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); - const __m256i shfl = _mm256_set_epi8( - 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, - 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, - 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, - 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); - -#define CONVERT_I12_I16_BLOCK(reg) \ - { \ - __m256i v0 = _mm256_permutevar8x32_epi32(reg, permmask); \ - __m256i r = _mm256_shuffle_epi8(v0, shfl); \ - \ - __m256i r0 = _mm256_and_si256(r, mask0); \ - __m256i r1 = _mm256_and_si256(_mm256_srli_epi64(r, 4), mask1); \ - __m256i result = _mm256_or_si256(r0, r1); \ - \ - _mm256_store_si256((__m256i*)outdata, result); \ - outdata += 16; \ - } -// CONVERT_I12_I16_BLOCK end +#include "conv_i12_i16_avx2.inc" __m256i y0, y1, y2, y3; + __m256i rs0, rs1, rs2, rs3; if(i >= 96) { @@ -50,10 +27,16 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, for (; i >= 2*96; i -= 96) { - CONVERT_I12_I16_BLOCK(y0); - CONVERT_I12_I16_BLOCK(y1); - CONVERT_I12_I16_BLOCK(y2); - CONVERT_I12_I16_BLOCK(y3); + CONVERT_I12_I16_BLOCK(y0, rs0); + CONVERT_I12_I16_BLOCK(y1, rs1); + CONVERT_I12_I16_BLOCK(y2, rs2); + CONVERT_I12_I16_BLOCK(y3, rs3); + + _mm256_store_si256((__m256i*)(outdata + 0), rs0); + _mm256_store_si256((__m256i*)(outdata + 16), rs1); + _mm256_store_si256((__m256i*)(outdata + 32), rs2); + _mm256_store_si256((__m256i*)(outdata + 48), rs3); + outdata += 64; y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); // 8 1/3 y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); // 8 1/3 @@ -64,37 +47,22 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, i -= 96; - CONVERT_I12_I16_BLOCK(y0); - CONVERT_I12_I16_BLOCK(y1); - CONVERT_I12_I16_BLOCK(y2); - CONVERT_I12_I16_BLOCK(y3); + CONVERT_I12_I16_BLOCK(y0, rs0); + CONVERT_I12_I16_BLOCK(y1, rs1); + CONVERT_I12_I16_BLOCK(y2, rs2); + CONVERT_I12_I16_BLOCK(y3, rs3); + + _mm256_store_si256((__m256i*)(outdata + 0), rs0); + _mm256_store_si256((__m256i*)(outdata + 16), rs1); + _mm256_store_si256((__m256i*)(outdata + 32), rs2); + _mm256_store_si256((__m256i*)(outdata + 48), rs3); + outdata += 64; } #undef CONVERT_I12_I16_BLOCK const uint8_t* indata = (const uint8_t*)in; - - while(i >= 3) - { - const uint8_t v0 = *(indata++); - const uint8_t v1 = *(indata++); - const uint8_t v2 = *(indata++); - i -= 3; - - const int16_t a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); - const int16_t b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); - - *(outdata++) = a; - *(outdata++) = b; - } - - if(i >= 2) - { - const uint16_t v = *(const uint16_t*)indata; - const int16_t a = (int16_t)(v << 4); - *(outdata++) = a; - i -= 2; - } + #include "conv_i12_i16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc new file mode 100644 index 00000000..66f2aad4 --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc @@ -0,0 +1,23 @@ +const __m512i mask0 = _mm512_set1_epi64(0xfff00000fff00000); +const __m512i mask1 = _mm512_set1_epi64(0x0000fff00000fff0); + +const __m512i permmask = _mm512_set_epi32(11,10,9, 15,14, 8,7,6, 5,4,3, 13,12, 2,1,0); +const __m512i shfl = _mm512_set_epi8( + 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, + 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, + 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, + 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80, + 0x0f, 0x0e, 0x0d, 0x80, 0x0c, 0x0b, 0x0a, 0x80, + 0x09, 0x08, 0x07, 0x80, 0x06, 0x05, 0x04, 0x80, + 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, + 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); + +#define CONVERT_I12_I16_BLOCK(reg, result) \ +{ \ + __m512i v0 = _mm512_permutexvar_epi32(permmask, reg); \ + __m512i r = _mm512_shuffle_epi8(v0, shfl); \ + \ + __m512i r0 = _mm512_and_si512(r, mask0); \ + __m512i r1 = _mm512_and_si512(_mm512_srli_epi64(r, 4), mask1); \ + result = _mm512_or_si512(r0, r1); \ +} diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.t b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.t new file mode 100644 index 00000000..53be77fd --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.t @@ -0,0 +1,70 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + /* 12 bits -> 16 bits => 3 -> 4 */ + if ((outdatabsz * 3 / 4) < i) + i = (outdatabsz * 3 / 4); + + const uint64_t *in = (const uint64_t*)indata_p; + int16_t* outdata = (int16_t*)outdata_p; + + //AVX512BW block + { + #include "conv_i12_i16_avx512bw.inc" + + __m512i y0, y1; + __m512i rs0, rs1; + + for(; i >= 96; i -= 96) + { + y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); + y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); + in += 12; + + CONVERT_I12_I16_BLOCK(y0, rs0); + CONVERT_I12_I16_BLOCK(y1, rs1); + + _mm512_store_si512((__m512i*)(outdata + 0), rs0); + _mm512_store_si512((__m512i*)(outdata + 32), rs1); + outdata += 64; + } + + #undef CONVERT_I12_I16_BLOCK + } + + //AVX2 block + { + #include "conv_i12_i16_avx2.inc" + + if(i >= 48) + { + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); // 8 1/3 + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); // 8 1/3 + in += 6; + i -= 48; + + __m256i rs0, rs1; + + CONVERT_I12_I16_BLOCK(y0, rs0); + CONVERT_I12_I16_BLOCK(y1, rs1); + + _mm256_store_si256((__m256i*)(outdata + 0), rs0); + _mm256_store_si256((__m256i*)(outdata + 16), rs1); + outdata += 32; + } + + #undef CONVERT_I12_I16_BLOCK + } + + //Generic block + { + const uint8_t* indata = (const uint8_t*)in; + #include "conv_i12_i16_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i12_i16_generic.inc b/src/lib/xdsp/templates/conv_i12_i16_generic.inc new file mode 100644 index 00000000..e77b1e79 --- /dev/null +++ b/src/lib/xdsp/templates/conv_i12_i16_generic.inc @@ -0,0 +1,42 @@ +/* memory stream: MSB...LSB +* 0x00 f0[7:0] +* 0x01 {f1[3:0],f0[11:8]} +* 0x02 f1[11:4] +* ..... +*/ + +/* v2 v1 v0 +* +-----+-----+-----+ +* | 8 | 8 | 8 | +* +-----+-----+-----+ +* | 12 | 12 | +* +-----+-----+-----+ +* +* +-----+-----+ +* as = |v1| v0 |00| +* +-----+-----+ +* bs = | v2 |v1|00| +* +-----+-----+ +*/ + +while(i >= 3) +{ + const uint8_t v0 = *(indata++); + const uint8_t v1 = *(indata++); + const uint8_t v2 = *(indata++); + i -= 3; + + const int16_t a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); + const int16_t b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); + + *(outdata++) = a; + *(outdata++) = b; +} + +if(i >= 2) +{ + const uint16_t v = *(const uint16_t*)indata; + const int16_t a = (int16_t)(v << 4); + *(outdata++) = a; + i -= 2; +} diff --git a/src/lib/xdsp/templates/conv_i12_i16_generic.t b/src/lib/xdsp/templates/conv_i12_i16_generic.t index 75b0880f..cf6e7af3 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_generic.t +++ b/src/lib/xdsp/templates/conv_i12_i16_generic.t @@ -12,48 +12,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const uint8_t* indata = (const uint8_t*)indata_p; int16_t* outdata = (int16_t*)outdata_p; - /* memory stream: MSB...LSB - * 0x00 f0[7:0] - * 0x01 {f1[3:0],f0[11:8]} - * 0x02 f1[11:4] - * ..... - */ - - /* v2 v1 v0 - * +-----+-----+-----+ - * | 8 | 8 | 8 | - * +-----+-----+-----+ - * | 12 | 12 | - * +-----+-----+-----+ - * - * +-----+-----+ - * as = |v1| v0 |00| - * +-----+-----+ - * bs = | v2 |v1|00| - * +-----+-----+ - */ - - while(i >= 3) - { - const uint8_t v0 = *(indata++); - const uint8_t v1 = *(indata++); - const uint8_t v2 = *(indata++); - i -= 3; - - const int16_t a = (int16_t) (((uint16_t)v0 << 4) | ((uint16_t)v1 << 12)); - const int16_t b = (int16_t) (((uint16_t)v2 << 8) | (v1 & 0xf0)); - - *(outdata++) = a; - *(outdata++) = b; - } - - if(i >= 2) - { - const uint16_t v = *(const uint16_t*)indata; - const int16_t a = (int16_t)(v << 4); - *(outdata++) = a; - i -= 2; - } + #include "conv_i12_i16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i16_i12_avx2.t b/src/lib/xdsp/templates/conv_i16_i12_avx2.t index 8830620a..2368752a 100644 --- a/src/lib/xdsp/templates/conv_i16_i12_avx2.t +++ b/src/lib/xdsp/templates/conv_i16_i12_avx2.t @@ -44,27 +44,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const int16_t* indata = (const int16_t*)in256; uint8_t* outdata = (uint8_t*)out64; - for (; i >= 4; i -= 4) { - - const int16_t b0 = *indata++; - const int16_t b1 = *indata++; - - wu_i16u32_t a = {{b0, b1}}; - wu_u32b_t c = {(a.u & 0xfff00000) | ((a.u << 4) & 0x000fff00)}; - - *(outdata++) = c.b[1]; - *(outdata++) = c.b[2]; - *(outdata++) = c.b[3]; - } - - if(i >= 2) - { - wu_i16b_t c = {*indata}; - - *(outdata++) = c.b[0]; - *(outdata++) = c.b[1] >> 4; - i -= 2; - } +#include "conv_i16_i12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i16_i12_avx512bw.inc b/src/lib/xdsp/templates/conv_i16_i12_avx512bw.inc new file mode 100644 index 00000000..5f726d40 --- /dev/null +++ b/src/lib/xdsp/templates/conv_i16_i12_avx512bw.inc @@ -0,0 +1,27 @@ +const __m512i maske = _mm512_set1_epi64(0x0000fff00000fff0); +const __m512i masko = _mm512_set1_epi64(0xfff00000fff00000); + +const __m512i shfl0 = _mm512_set_epi8( + 0x80, 0x80, 0x80, 0x80, 0x0f, 0x0e, 0x0d, 0x0b, + 0x0a, 0x09, 0x07, 0x06, 0x05, 0x03, 0x02, 0x01, + 0x80, 0x80, 0x80, 0x80, 0x0f, 0x0e, 0x0d, 0x0b, + 0x0a, 0x09, 0x07, 0x06, 0x05, 0x03, 0x02, 0x01, + 0x80, 0x80, 0x80, 0x80, 0x0f, 0x0e, 0x0d, 0x0b, + 0x0a, 0x09, 0x07, 0x06, 0x05, 0x03, 0x02, 0x01, + 0x80, 0x80, 0x80, 0x80, 0x0f, 0x0e, 0x0d, 0x0b, + 0x0a, 0x09, 0x07, 0x06, 0x05, 0x03, 0x02, 0x01); + +const __m512i permmask0 = _mm512_set_epi32(/*zeros*/15,11,7,3, /*data*/14,13,12, 10,9,8, 6,5,4, 2,1,0); + +#define CONVERT_I16_I12_BLOCK(rin, pout64) \ +{ \ + __m512i ro0 = _mm512_and_si512(rin, masko); \ + __m512i re0 = _mm512_slli_epi64(_mm512_and_si512(rin, maske), 4); \ + __m512i r0 = _mm512_or_si512(ro0, re0); \ +\ + __m512i res = _mm512_shuffle_epi8(r0, shfl0); \ + res = _mm512_permutexvar_epi32(permmask0, res); \ +\ + _mm512_mask_storeu_epi64((long long *)pout64, 0b00111111, res); \ + pout64 += 6; \ +} diff --git a/src/lib/xdsp/templates/conv_i16_i12_avx512bw.t b/src/lib/xdsp/templates/conv_i16_i12_avx512bw.t new file mode 100644 index 00000000..1a142edf --- /dev/null +++ b/src/lib/xdsp/templates/conv_i16_i12_avx512bw.t @@ -0,0 +1,68 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 4 / 3) < i) + i = (outdatabsz * 4 / 3); + + const void* raw_ptr = indata_p; + uint64_t *out64 = (uint64_t*)outdata_p; + + //AVX512 block + { + #include "conv_i16_i12_avx512bw.inc" + + const __m512i *in512 = (__m512i*)raw_ptr; + __m512i v0, v1; + + for (; i >= 64*2; i -= 64*2) + { + v0 = _mm512_loadu_si512(in512 + 0); + v1 = _mm512_loadu_si512(in512 + 1); + in512 += 2; + + CONVERT_I16_I12_BLOCK(v0, out64); + CONVERT_I16_I12_BLOCK(v1, out64); + } + + for (; i >= 64; i -= 64) + { + v0 = _mm512_loadu_si512(in512++); + CONVERT_I16_I12_BLOCK(v0, out64); + } + + raw_ptr = (void*)in512; + #undef CONVERT_I16_I12_BLOCK + } + + //AVX2 block + { + #include "conv_i16_i12_avx2.inc" + + const __m256i *in256 = (__m256i*)raw_ptr; + __m256i v0; + + if(i >= 32) + { + v0 = _mm256_loadu_si256(in256++); + CONVERT_I16_I12_BLOCK(v0, out64); + i -= 32; + } + + raw_ptr = (void*)in256; + #undef CONVERT_I16_I12_BLOCK + } + + //Generic block + { + const int16_t* indata = (const int16_t*)raw_ptr; + uint8_t* outdata = (uint8_t*)out64; + + #include "conv_i16_i12_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_i16_i12_generic.inc b/src/lib/xdsp/templates/conv_i16_i12_generic.inc new file mode 100644 index 00000000..a61fe897 --- /dev/null +++ b/src/lib/xdsp/templates/conv_i16_i12_generic.inc @@ -0,0 +1,21 @@ +for (; i >= 4; i -= 4) { + + const int16_t b0 = *indata++; + const int16_t b1 = *indata++; + + wu_i16u32_t a = {{b0, b1}}; + wu_u32b_t c = {(a.u & 0xfff00000) | ((a.u << 4) & 0x000fff00)}; + + *(outdata++) = c.b[1]; + *(outdata++) = c.b[2]; + *(outdata++) = c.b[3]; +} + +if(i >= 2) +{ + wu_i16b_t c = {*indata}; + + *(outdata++) = c.b[0]; + *(outdata++) = c.b[1] >> 4; + i -= 2; +} diff --git a/src/lib/xdsp/templates/conv_i16_i12_generic.t b/src/lib/xdsp/templates/conv_i16_i12_generic.t index 4de4018d..76cf3df4 100644 --- a/src/lib/xdsp/templates/conv_i16_i12_generic.t +++ b/src/lib/xdsp/templates/conv_i16_i12_generic.t @@ -11,27 +11,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const int16_t* indata = (const int16_t*)indata_p; uint8_t* outdata = (uint8_t*)outdata_p; - for (; i >= 4; i -= 4) { - - const int16_t b0 = *indata++; - const int16_t b1 = *indata++; - - wu_i16u32_t a = {{b0, b1}}; - wu_u32b_t c = {(a.u & 0xfff00000) | ((a.u << 4) & 0x000fff00)}; - - *(outdata++) = c.b[1]; - *(outdata++) = c.b[2]; - *(outdata++) = c.b[3]; - } - - if(i >= 2) - { - wu_i16b_t c = {*indata}; - - *(outdata++) = c.b[0]; - *(outdata++) = c.b[1] >> 4; - i -= 2; - } + #include "conv_i16_i12_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c b/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c index 16594123..75c1808d 100644 --- a/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_2cf32_ci12_utest.c @@ -159,12 +159,13 @@ START_TEST(conv_2cf32_ci12_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = PACKET_SIZE * sizeof(float); + const size_t bzin = PACKET_SIZE * sizeof(float) - 64 + 32 + 10; const size_t bzout = OUT_BZ; fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); #ifdef DEBUG_PRINT printer("ETALON:"); diff --git a/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c b/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c index b338195a..481c6f3b 100644 --- a/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_2ci16_ci12_utest.c @@ -106,12 +106,13 @@ START_TEST(conv_2ci16_ci12_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = PACKET_SIZE * sizeof(int16_t); + const size_t bzin = PACKET_SIZE * sizeof(int16_t) - 64 + 32 + 10; //we should test all branches const size_t bzout = OUT_BZ; fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); #ifdef DEBUG_PRINT printer("ETALON:"); diff --git a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c index 345298ba..b421f577 100644 --- a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c @@ -169,12 +169,13 @@ START_TEST(conv_4cf32_ci12_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = PACKET_SIZE * sizeof(float); + const size_t bzin = PACKET_SIZE * sizeof(float) - 64 + 32 + 10; const size_t bzout = OUT_BZ; fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); #ifdef DEBUG_PRINT printer("ETALON:"); diff --git a/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c b/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c index 821a9504..6147e35c 100644 --- a/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_4ci16_ci12_utest.c @@ -34,7 +34,7 @@ static generic_opts_t max_opt = OPT_GENERIC; static void setup() { int res = 0; - res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 2); + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); res = res ? res : posix_memalign((void**)&in_2, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); res = res ? res : posix_memalign((void**)&in_3, ALIGN_BYTES, PACKET_SIZE * sizeof(int16_t) / 4); @@ -87,7 +87,7 @@ static void printer(const char* header) for(unsigned k = 0; k < 4; ++k) { fprintf(stderr, "in[%d]: ", k); - for(unsigned i = 0; i < 8; ++i) + for(unsigned i = 0; i < PACKET_SIZE / 4; ++i) { fprintf(stderr, "%.d ", in[k][i] >> 4); } @@ -95,7 +95,7 @@ static void printer(const char* header) } fprintf(stderr, "out : "); - for(unsigned i = 0; i < 48; i += 3) + for(unsigned i = 0; i < OUT_BZ; i += 3) { uint8_t v0 = out[i + 0]; uint8_t v1 = out[i + 1]; @@ -117,12 +117,13 @@ START_TEST(conv_4ci16_ci12_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = PACKET_SIZE * sizeof(int16_t); + const size_t bzin = PACKET_SIZE * sizeof(int16_t) - 64 + 32 + 10; //we should test all branches const size_t bzout = OUT_BZ; fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); #ifdef DEBUG_PRINT printer("ETALON:"); diff --git a/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c b/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c index d75e37d6..6716fc51 100644 --- a/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_2cf32_utest.c @@ -122,12 +122,14 @@ START_TEST(conv_ci12_2cf32_check_simd) void** pout = (void**)out; last_fn_name = NULL; - const size_t bzin = SPEED_SIZE_BZ; + const size_t bzin = SPEED_SIZE_BZ - 64 + 32 + 10; const size_t bzout = SPEED_WORD_COUNT * sizeof(float); fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out[0], 0, bzout / 2); + memset(out[1], 0, bzout / 2); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); memcpy(out1_etalon, out[0], bzout / 2); memcpy(out2_etalon, out[1], bzout / 2); diff --git a/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c b/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c index b7862819..a62aac89 100644 --- a/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_2ci16_utest.c @@ -114,12 +114,14 @@ START_TEST(conv_ci12_2ci16_check_simd) void** pout = (void**)out; last_fn_name = NULL; - const size_t bzin = SPEED_SIZE_BZ; + const size_t bzin = SPEED_SIZE_BZ - 64 + 32 + 10; const size_t bzout = SPEED_WORD_COUNT * sizeof(int16_t); fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out[0], 0, bzout / 2); + memset(out[1], 0, bzout / 2); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); #ifdef DEBUG_PRINT printer("ETALON:"); diff --git a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c index 3cbb02cb..f7a948f2 100644 --- a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c @@ -135,12 +135,16 @@ START_TEST(conv_ci12_4cf32_check_simd) void** pout = (void**)out; last_fn_name = NULL; - const size_t bzin = SPEED_SIZE_BZ; + const size_t bzin = SPEED_SIZE_BZ - 64 + 32 + 10; const size_t bzout = SPEED_WORD_COUNT * sizeof(float); fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out[0], 0, bzout / 4); + memset(out[1], 0, bzout / 4); + memset(out[2], 0, bzout / 4); + memset(out[3], 0, bzout / 4); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); memcpy(out1_etalon, out[0], bzout / 4); memcpy(out2_etalon, out[1], bzout / 4); diff --git a/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c b/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c index 1ace2bb4..c0af85de 100644 --- a/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_4ci16_utest.c @@ -129,12 +129,16 @@ START_TEST(conv_ci12_4ci16_check_simd) void** pout = (void**)out; last_fn_name = NULL; - const size_t bzin = SPEED_SIZE_BZ; + const size_t bzin = SPEED_SIZE_BZ - 64 + 32 + 10; const size_t bzout = SPEED_WORD_COUNT * sizeof(int16_t); fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out[0], 0, bzout / 4); + memset(out[1], 0, bzout / 4); + memset(out[2], 0, bzout / 4); + memset(out[3], 0, bzout / 4); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); #ifdef DEBUG_PRINT printer("ETALON:"); diff --git a/src/lib/xdsp/utests/conv_f32_i12_utest.c b/src/lib/xdsp/utests/conv_f32_i12_utest.c index 98b6f0d1..b8077252 100644 --- a/src/lib/xdsp/utests/conv_f32_i12_utest.c +++ b/src/lib/xdsp/utests/conv_f32_i12_utest.c @@ -143,12 +143,13 @@ START_TEST(conv_f32_i12_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = PACKET_SIZE * sizeof(float); + const size_t bzin = PACKET_SIZE * sizeof(float) - 64 + 32 + 10; const size_t bzout = OUT_BZ; fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, &pout, bzout); #ifdef DEBUG_PRINT printer("HEADER:"); diff --git a/src/lib/xdsp/utests/conv_i12_f32_utest.c b/src/lib/xdsp/utests/conv_i12_f32_utest.c index 23ca462a..c4373c49 100644 --- a/src/lib/xdsp/utests/conv_i12_f32_utest.c +++ b/src/lib/xdsp/utests/conv_i12_f32_utest.c @@ -117,12 +117,13 @@ START_TEST(conv_i12_f32_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = IN_STREAM_SIZE_BZ; + const size_t bzin = IN_STREAM_SIZE_BZ - 64 + 32 + 10; const size_t bzout = WORD_COUNT * sizeof(float); fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, &pout, bzout); memcpy(out_etalon, out, bzout); diff --git a/src/lib/xdsp/utests/conv_i12_i16_utest.c b/src/lib/xdsp/utests/conv_i12_i16_utest.c index 53546797..31b80176 100644 --- a/src/lib/xdsp/utests/conv_i12_i16_utest.c +++ b/src/lib/xdsp/utests/conv_i12_i16_utest.c @@ -102,12 +102,13 @@ START_TEST(conv_i12_i16_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = SPEED_SIZE_BZ; + const size_t bzin = SPEED_SIZE_BZ - 64 + 32 + 10; const size_t bzout = SPEED_WORD_COUNT * sizeof(int16_t); fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, &pout, bzout); memcpy(out_etalon, out, bzout); diff --git a/src/lib/xdsp/utests/conv_i16_i12_utest.c b/src/lib/xdsp/utests/conv_i16_i12_utest.c index 0c040460..237bb5e2 100644 --- a/src/lib/xdsp/utests/conv_i16_i12_utest.c +++ b/src/lib/xdsp/utests/conv_i16_i12_utest.c @@ -77,12 +77,13 @@ START_TEST(conv_i16_i12_check_simd) void* pout = (void*)out; last_fn_name = NULL; - const size_t bzin = PACKET_SIZE * sizeof(int16_t); + const size_t bzin = PACKET_SIZE * sizeof(int16_t) - 64 + 32 + 10; //we should test all branches const size_t bzout = OUT_BZ; fprintf(stderr,"\n**** Check SIMD implementations ***\n"); //get etalon output data (generic foo) + memset(out, 0, bzout); (*get_fn(OPT_GENERIC, 0))(&pin, bzin, &pout, bzout); memcpy(out_etalon, out, bzout); diff --git a/src/lib/xdsp/vbase.h b/src/lib/xdsp/vbase.h index 0c456124..0e7a28ea 100644 --- a/src/lib/xdsp/vbase.h +++ b/src/lib/xdsp/vbase.h @@ -40,6 +40,7 @@ typedef enum generic_opts generic_opts_t; #include #ifndef __EMSCRIPTEN__ +#define WVLT_AVX512BW #define WVLT_AVX2 #define WVLT_AVX #define WVLT_SSE4_2 @@ -59,6 +60,12 @@ typedef enum generic_opts generic_opts_t; #endif //WVLT_SIMD_INTEL +#ifdef WVLT_AVX512BW +#define SELECT_AVX512BW_FN(a, b, fn, cap) do { \ + if (cap >= OPT_AVX512BW) {a = &fn; b = VB_STRINGIFY(fn);} } while(0) +#else +#define SELECT_AVX512BW_FN(a, b, fn, cap) +#endif #ifdef WVLT_AVX2 #define SELECT_AVX2_FN(a, b, fn, cap) do { \ From 65969154095dbc17ffcf83957197eac7765e1fcf Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 28 Oct 2025 20:38:10 +0300 Subject: [PATCH 206/397] Add ci16_6ci16 & ci16_cf32, generics & AVX2 + tests --- src/lib/xdsp/CMakeLists.txt | 2 + src/lib/xdsp/conv.c | 19 ++ src/lib/xdsp/conv.h | 7 + src/lib/xdsp/conv_ci16_6cf32_2.c | 46 ++++ src/lib/xdsp/conv_ci16_6cf32_2.h | 12 + src/lib/xdsp/conv_ci16_6ci16_2.c | 44 ++++ src/lib/xdsp/conv_ci16_6ci16_2.h | 12 + src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t | 108 ++++++++ .../xdsp/templates/conv_ci16_6cf32_generic.t | 57 +++++ src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t | 80 ++++++ .../xdsp/templates/conv_ci16_6ci16_generic.t | 38 +++ src/lib/xdsp/utests/CMakeLists.txt | 4 + src/lib/xdsp/utests/conv_ci16_6cf32_utest.c | 238 ++++++++++++++++++ src/lib/xdsp/utests/conv_ci16_6ci16_utest.c | 227 +++++++++++++++++ src/lib/xdsp/utests/xdsp_utest_suite.c | 11 +- 15 files changed, 900 insertions(+), 5 deletions(-) create mode 100644 src/lib/xdsp/conv_ci16_6cf32_2.c create mode 100644 src/lib/xdsp/conv_ci16_6cf32_2.h create mode 100644 src/lib/xdsp/conv_ci16_6ci16_2.c create mode 100644 src/lib/xdsp/conv_ci16_6ci16_2.h create mode 100644 src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t create mode 100644 src/lib/xdsp/templates/conv_ci16_6cf32_generic.t create mode 100644 src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t create mode 100644 src/lib/xdsp/templates/conv_ci16_6ci16_generic.t create mode 100644 src/lib/xdsp/utests/conv_ci16_6cf32_utest.c create mode 100644 src/lib/xdsp/utests/conv_ci16_6ci16_utest.c diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index 3c4608c1..62b6fe43 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -42,6 +42,8 @@ set(xdsplib_conv_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci12_4ci16_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_2ci16_ci12_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_4ci16_ci12_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_6ci16_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_6cf32_2.c ) if(WVLT_ARCH_X86 OR WVLT_ARCH_X86_64) diff --git a/src/lib/xdsp/conv.c b/src/lib/xdsp/conv.c index c92c915e..52c4189c 100644 --- a/src/lib/xdsp/conv.c +++ b/src/lib/xdsp/conv.c @@ -28,6 +28,9 @@ #include "conv_2ci16_ci12_2.h" #include "conv_4ci16_ci12_2.h" +#include "conv_ci16_6ci16_2.h" +#include "conv_ci16_6cf32_2.h" + #include #include @@ -125,6 +128,22 @@ transform_info_t get_transform_fn(const char* from, unsigned inveccnt, unsigned outveccnt) { + /* Interleave 1 -> 6 */ + if(inveccnt == 1 && outveccnt == 6) + { + if(isCI16(from) && isCI16(to)) + { + transform_info_t l_conv_ci16_6ci16 = { conv_get_ci16_6ci16(), tr_dummy_sz }; + return l_conv_ci16_6ci16; + } + + if(isCI16(from) && isCF32(to)) + { + transform_info_t l_conv_ci16_6cf32 = { conv_get_ci16_6cf32(), tr_conv_i16_f32_sz }; + return l_conv_ci16_6cf32; + } + } + /* Deinterleave 4 -> 1 */ if(inveccnt == 4 && outveccnt == 1) { diff --git a/src/lib/xdsp/conv.h b/src/lib/xdsp/conv.h index 4bfdcc06..37892305 100644 --- a/src/lib/xdsp/conv.h +++ b/src/lib/xdsp/conv.h @@ -74,6 +74,13 @@ typedef void (*filter_function_t)(const int16_t *__restrict data, unsigned outdatabsz) \ { conv_fn(indata[0], indata[1], indata[2], indata[3], indatabsz, outdata[0], outdatabsz); } +#define DECLARE_TR_FUNC_1_6(conv_fn) \ + void tr_##conv_fn (const void *__restrict *__restrict indata, \ + unsigned indatabsz, \ + void *__restrict *__restrict outdata, \ + unsigned outdatabsz) \ + { conv_fn(*indata, indatabsz, outdata[0], outdata[1], outdata[2], outdata[3], outdata[4], outdata[5], outdatabsz); } + typedef void (*sincos_i16_interleaved_ctrl_function_t)(int32_t *__restrict start_phase, int32_t delta_phase, int16_t gain, bool inv_sin, bool inv_cos, diff --git a/src/lib/xdsp/conv_ci16_6cf32_2.c b/src/lib/xdsp/conv_ci16_6cf32_2.c new file mode 100644 index 00000000..48c6b61a --- /dev/null +++ b/src/lib/xdsp/conv_ci16_6cf32_2.c @@ -0,0 +1,46 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_ci16_6cf32_2.h" +#include "attribute_switch.h" + +#define CONV_SCALE (1.0f/32767) + +#define TEMPLATE_FUNC_NAME conv_ci16_6cf32_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_6cf32_generic.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6cf32_generic) + +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_ci16_6cf32_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_ci16_6cf32_avx2.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6cf32_avx2) +#endif + +#if 0 +#ifdef WVLT_NEON +#define TEMPLATE_FUNC_NAME conv_ci16_6cf32_neon +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_6cf32_neon.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6cf32_neon) +#endif +#endif + +conv_function_t conv_get_ci16_6cf32_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_6cf32_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_ci16_6cf32_avx2, cpu_cap); + //SELECT_NEON_FN(fn, fname, tr_conv_ci16_4cf32_neon, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_ci16_6cf32() +{ + return conv_get_ci16_6cf32_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_ci16_6cf32_2.h b/src/lib/xdsp/conv_ci16_6cf32_2.h new file mode 100644 index 00000000..9eaa60be --- /dev/null +++ b/src/lib/xdsp/conv_ci16_6cf32_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_CI16_6CF32_2_H +#define CONV_CI16_6CF32_2_H + +#include "conv.h" + +conv_function_t conv_get_ci16_6cf32_c(generic_opts_t cpu_cap, const char** sfunc); +conv_function_t conv_get_ci16_6cf32(); + +#endif // CONV_CI16_6CF32_2_H diff --git a/src/lib/xdsp/conv_ci16_6ci16_2.c b/src/lib/xdsp/conv_ci16_6ci16_2.c new file mode 100644 index 00000000..d82156e2 --- /dev/null +++ b/src/lib/xdsp/conv_ci16_6ci16_2.c @@ -0,0 +1,44 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_ci16_6ci16_2.h" +#include "attribute_switch.h" + +#define TEMPLATE_FUNC_NAME conv_ci16_6ci16_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_6ci16_generic.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6ci16_generic) + +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_ci16_6ci16_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_ci16_6ci16_avx2.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6ci16_avx2) +#endif + +#if 0 +#ifdef WVLT_NEON +#define TEMPLATE_FUNC_NAME conv_ci16_6ci16_neon +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_6ci16_neon.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6ci16_neon) +#endif +#endif + +conv_function_t conv_get_ci16_6ci16_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_6ci16_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_ci16_6ci16_avx2, cpu_cap); + //SELECT_NEON_FN(fn, fname, tr_conv_ci16_4ci16_neon, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_ci16_6ci16() +{ + return conv_get_ci16_6ci16_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_ci16_6ci16_2.h b/src/lib/xdsp/conv_ci16_6ci16_2.h new file mode 100644 index 00000000..18ae9bbd --- /dev/null +++ b/src/lib/xdsp/conv_ci16_6ci16_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_CI16_6CI16_H +#define CONV_CI16_6CI16_H + +#include "conv.h" + +conv_function_t conv_get_ci16_6ci16(); +conv_function_t conv_get_ci16_6ci16_c(generic_opts_t cpu_cap, const char **sfunc); + +#endif diff --git a/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t b/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t new file mode 100644 index 00000000..0cad220c --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t @@ -0,0 +1,108 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + float* outdata_3 = (float*)outdata_3_p; + float* outdata_4 = (float*)outdata_4_p; + float* outdata_5 = (float*)outdata_5_p; + + const __m256i loadmask = _mm256_set_epi64x(0, -1, -1, -1); + const __m256 scale = _mm256_set1_ps(CONV_SCALE); + + const long long int* inptr64 = (long long int*)indata_p; + + while(i >= 12 * sizeof(uint64_t)) + { + __m256i in0 = _mm256_maskload_epi64(inptr64 + 0, loadmask); + __m256i in1 = _mm256_maskload_epi64(inptr64 + 3, loadmask); + __m256i in2 = _mm256_maskload_epi64(inptr64 + 6, loadmask); + __m256i in3 = _mm256_maskload_epi64(inptr64 + 9, loadmask); + + __m256i a0 = _mm256_unpacklo_epi32(in0, in1); + __m256i a1 = _mm256_unpackhi_epi32(in0, in1); + __m256i a2 = _mm256_unpacklo_epi32(in2, in3); + __m256i a3 = _mm256_unpackhi_epi32(in2, in3); + + __m256d b0 = _mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a1), 0b0000); + __m256d b1 = _mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a1), 0b1111); + __m256d b2 = _mm256_shuffle_pd(_mm256_castsi256_pd(a2), _mm256_castsi256_pd(a3), 0b0000); + __m256d b3 = _mm256_shuffle_pd(_mm256_castsi256_pd(a2), _mm256_castsi256_pd(a3), 0b1111); + + __m256i c0 = _mm256_castpd_si256(_mm256_shuffle_pd(b0, b2, 0b0000)); + __m256i c2 = _mm256_castpd_si256(_mm256_shuffle_pd(b0, b2, 0b1111)); + __m256i c1 = _mm256_castpd_si256(_mm256_shuffle_pd(b1, b3, 0b0000)); + __m256i c3 = _mm256_castpd_si256(_mm256_shuffle_pd(b1, b3, 0b1111)); + + __m256i d0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(c0)); + __m256i d1 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(c1)); + __m256i d2 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(c2)); + __m256i d3 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(c3)); + __m256i d4 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(c0, 1)); + __m256i d5 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(c1, 1)); + + _mm256_storeu_ps(outdata_0, _mm256_mul_ps(_mm256_cvtepi32_ps(d0), scale)); + _mm256_storeu_ps(outdata_1, _mm256_mul_ps(_mm256_cvtepi32_ps(d1), scale)); + _mm256_storeu_ps(outdata_2, _mm256_mul_ps(_mm256_cvtepi32_ps(d2), scale)); + _mm256_storeu_ps(outdata_3, _mm256_mul_ps(_mm256_cvtepi32_ps(d3), scale)); + _mm256_storeu_ps(outdata_4, _mm256_mul_ps(_mm256_cvtepi32_ps(d4), scale)); + _mm256_storeu_ps(outdata_5, _mm256_mul_ps(_mm256_cvtepi32_ps(d5), scale)); + + outdata_0 += 8; + outdata_1 += 8; + outdata_2 += 8; + outdata_3 += 8; + outdata_4 += 8; + outdata_5 += 8; + + i -= 12 * sizeof(uint64_t); + inptr64 += 12; + } + + const int16_t *in = (const int16_t *)inptr64; + for (; i >= 24; i -= 24) + { + const float i0 = *in++; + const float q0 = *in++; + const float i1 = *in++; + const float q1 = *in++; + const float i2 = *in++; + const float q2 = *in++; + const float i3 = *in++; + const float q3 = *in++; + const float i4 = *in++; + const float q4 = *in++; + const float i5 = *in++; + const float q5 = *in++; + + *(outdata_0++) = i0 * CONV_SCALE; + *(outdata_0++) = q0 * CONV_SCALE; + *(outdata_1++) = i1 * CONV_SCALE; + *(outdata_1++) = q1 * CONV_SCALE; + *(outdata_2++) = i2 * CONV_SCALE; + *(outdata_2++) = q2 * CONV_SCALE; + *(outdata_3++) = i3 * CONV_SCALE; + *(outdata_3++) = q3 * CONV_SCALE; + *(outdata_4++) = i4 * CONV_SCALE; + *(outdata_4++) = q4 * CONV_SCALE; + *(outdata_5++) = i5 * CONV_SCALE; + *(outdata_5++) = q5 * CONV_SCALE; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_6cf32_generic.t b/src/lib/xdsp/templates/conv_ci16_6cf32_generic.t new file mode 100644 index 00000000..a8324d62 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6cf32_generic.t @@ -0,0 +1,57 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + const int16_t *in = (const int16_t *)indata; + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + float* outdata_3 = (float*)outdata_3_p; + float* outdata_4 = (float*)outdata_4_p; + float* outdata_5 = (float*)outdata_5_p; + + for (; i >= 24; i -= 24) + { + const float i0 = *in++; + const float q0 = *in++; + const float i1 = *in++; + const float q1 = *in++; + const float i2 = *in++; + const float q2 = *in++; + const float i3 = *in++; + const float q3 = *in++; + const float i4 = *in++; + const float q4 = *in++; + const float i5 = *in++; + const float q5 = *in++; + + *(outdata_0++) = i0 * CONV_SCALE; + *(outdata_0++) = q0 * CONV_SCALE; + *(outdata_1++) = i1 * CONV_SCALE; + *(outdata_1++) = q1 * CONV_SCALE; + *(outdata_2++) = i2 * CONV_SCALE; + *(outdata_2++) = q2 * CONV_SCALE; + *(outdata_3++) = i3 * CONV_SCALE; + *(outdata_3++) = q3 * CONV_SCALE; + *(outdata_4++) = i4 * CONV_SCALE; + *(outdata_4++) = q4 * CONV_SCALE; + *(outdata_5++) = i5 * CONV_SCALE; + *(outdata_5++) = q5 * CONV_SCALE; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t b/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t new file mode 100644 index 00000000..02f2ca6f --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t @@ -0,0 +1,80 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + uint32_t* outdata_0 = (uint32_t*)outdata_0_p; + uint32_t* outdata_1 = (uint32_t*)outdata_1_p; + uint32_t* outdata_2 = (uint32_t*)outdata_2_p; + uint32_t* outdata_3 = (uint32_t*)outdata_3_p; + uint32_t* outdata_4 = (uint32_t*)outdata_4_p; + uint32_t* outdata_5 = (uint32_t*)outdata_5_p; + + const __m256i loadmask = _mm256_set_epi64x(0, -1, -1, -1); + const long long int* inptr64 = (long long int*)indata_p; + + while(i >= 12 * sizeof(uint64_t)) + { + __m256i in0 = _mm256_maskload_epi64(inptr64 + 0, loadmask); + __m256i in1 = _mm256_maskload_epi64(inptr64 + 3, loadmask); + __m256i in2 = _mm256_maskload_epi64(inptr64 + 6, loadmask); + __m256i in3 = _mm256_maskload_epi64(inptr64 + 9, loadmask); + + __m256i a0 = _mm256_unpacklo_epi32(in0, in1); + __m256i a1 = _mm256_unpackhi_epi32(in0, in1); + __m256i a2 = _mm256_unpacklo_epi32(in2, in3); + __m256i a3 = _mm256_unpackhi_epi32(in2, in3); + + __m256d b0 = _mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a1), 0b0000); + __m256d b1 = _mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a1), 0b1111); + __m256d b2 = _mm256_shuffle_pd(_mm256_castsi256_pd(a2), _mm256_castsi256_pd(a3), 0b0000); + __m256d b3 = _mm256_shuffle_pd(_mm256_castsi256_pd(a2), _mm256_castsi256_pd(a3), 0b1111); + + __m256i c0 = _mm256_castpd_si256(_mm256_shuffle_pd(b0, b2, 0b0000)); + __m256i c2 = _mm256_castpd_si256(_mm256_shuffle_pd(b0, b2, 0b1111)); + __m256i c1 = _mm256_castpd_si256(_mm256_shuffle_pd(b1, b3, 0b0000)); + __m256i c3 = _mm256_castpd_si256(_mm256_shuffle_pd(b1, b3, 0b1111)); + + _mm_storeu_si128((__m128i*)outdata_0, _mm256_castsi256_si128(c0)); + _mm_storeu_si128((__m128i*)outdata_1, _mm256_castsi256_si128(c1)); + _mm_storeu_si128((__m128i*)outdata_2, _mm256_castsi256_si128(c2)); + _mm_storeu_si128((__m128i*)outdata_3, _mm256_castsi256_si128(c3)); + _mm_storeu_si128((__m128i*)outdata_4, _mm256_extracti128_si256(c0, 1)); + _mm_storeu_si128((__m128i*)outdata_5, _mm256_extracti128_si256(c1, 1)); + + outdata_0 += 4; + outdata_1 += 4; + outdata_2 += 4; + outdata_3 += 4; + outdata_4 += 4; + outdata_5 += 4; + + i -= 12 * sizeof(uint64_t); + inptr64 += 12; + } + + const uint32_t* indata = (uint32_t*)inptr64; + for (; i >= 24; i -= 24) + { + *outdata_0++ = *indata++; + *outdata_1++ = *indata++; + *outdata_2++ = *indata++; + *outdata_3++ = *indata++; + *outdata_4++ = *indata++; + *outdata_5++ = *indata++; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_generic.t b/src/lib/xdsp/templates/conv_ci16_6ci16_generic.t new file mode 100644 index 00000000..402df5c1 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_generic.t @@ -0,0 +1,38 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + const uint32_t* indata = (uint32_t*)indata_p; + + uint32_t* outdata_0 = (uint32_t*)outdata_0_p; + uint32_t* outdata_1 = (uint32_t*)outdata_1_p; + uint32_t* outdata_2 = (uint32_t*)outdata_2_p; + uint32_t* outdata_3 = (uint32_t*)outdata_3_p; + uint32_t* outdata_4 = (uint32_t*)outdata_4_p; + uint32_t* outdata_5 = (uint32_t*)outdata_5_p; + + for (; i >= 24; i -= 24) + { + *outdata_0++ = *indata++; + *outdata_1++ = *indata++; + *outdata_2++ = *indata++; + *outdata_3++ = *indata++; + *outdata_4++ = *indata++; + *outdata_5++ = *indata++; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/CMakeLists.txt b/src/lib/xdsp/utests/CMakeLists.txt index 469a0119..b21d10be 100644 --- a/src/lib/xdsp/utests/CMakeLists.txt +++ b/src/lib/xdsp/utests/CMakeLists.txt @@ -29,6 +29,8 @@ set(TEST_SUIT_SRCS conv_ci12_4ci16_utest.c conv_2ci16_ci12_utest.c conv_4ci16_ci12_utest.c + conv_ci16_6ci16_utest.c + conv_ci16_6cf32_utest.c ../fft_window_functions.c ../fftad_functions.c @@ -56,6 +58,8 @@ set(TEST_SUIT_SRCS ../conv_ci12_4ci16_2.c ../conv_2ci16_ci12_2.c ../conv_4ci16_ci12_2.c + ../conv_ci16_6ci16_2.c + ../conv_ci16_6cf32_2.c ../vbase.c ) diff --git a/src/lib/xdsp/utests/conv_ci16_6cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_6cf32_utest.c new file mode 100644 index 00000000..e76f90a1 --- /dev/null +++ b/src/lib/xdsp/utests/conv_ci16_6cf32_utest.c @@ -0,0 +1,238 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_ci16_6cf32_2.h" + +#undef DEBUG_PRINT + +#define WORD_COUNT (4098u) +#define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) + +#define SPEED_WORD_COUNT (32768u) +#define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) + +static const unsigned packet_lens[3] = { 1024, 16384, SPEED_SIZE_BZ }; + +#define SPEED_MEASURE_ITERS 1000000 + +static int16_t* in = NULL; +static float* out1 = NULL; +static float* out1_etalon = NULL; +static float* out2 = NULL; +static float* out2_etalon = NULL; +static float* out3 = NULL; +static float* out3_etalon = NULL; +static float* out4 = NULL; +static float* out4_etalon = NULL; +static float* out5 = NULL; +static float* out5_etalon = NULL; +static float* out6 = NULL; +static float* out6_etalon = NULL; +static float* out[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out5, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out5_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out6, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + res = res ? res : posix_memalign((void**)&out6_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/6); + ck_assert_int_eq(res, 0); + + out[0] = out1; + out[1] = out2; + out[2] = out3; + out[3] = out4; + out[4] = out5; + out[5] = out6; + + srand( time(0) ); + + //fill + int16_t n = 0; + for(unsigned i = 0; i < SPEED_WORD_COUNT; ++i) + { + int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; + in[i] = sign * 32767 * (float)(rand()) / (float)RAND_MAX; + } +#if 0 + for(unsigned i = 0; i < WORD_COUNT; ++i) + { + fprintf(stderr, "%x\n", pin[i]); + } +#endif +} + +static void teardown() +{ + free(in); + free(out1); + free(out1_etalon); + free(out2); + free(out2_etalon); + free(out3); + free(out3_etalon); + free(out4); + free(out4_etalon); + free(out5); + free(out5_etalon); + free(out6); + free(out6_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_ci16_6cf32_c, &last_fn_name); +} + +static void print_data(const char* header) +{ + if(header) + fprintf(stderr, "%s:", header); + + fprintf(stderr, "\n in: "); + for(unsigned i = 0; i < 32; ++i) + { + fprintf(stderr, "%d ", in[i]); + } + + for(unsigned n = 0; n < 6; ++n) + { + fprintf(stderr, "\n out%d: ", n); + for(unsigned i = 0; i < 8; ++i) + { + fprintf(stderr, "%.4f ", out[n][i]); + } + } + fprintf(stderr, "\n"); +} + +#define CONV_SCALE (1.0f/32767) + +START_TEST(conv_ci16_6cf32_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = IN_STREAM_SIZE_BZ; + const size_t bzout = WORD_COUNT * sizeof(float); + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(out[0], 0, bzout / 6); + memset(out[1], 0, bzout / 6); + memset(out[2], 0, bzout / 6); + memset(out[3], 0, bzout / 6); + memset(out[4], 0, bzout / 6); + memset(out[5], 0, bzout / 6); + (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); + memcpy(out1_etalon, out[0], bzout / 6); + memcpy(out2_etalon, out[1], bzout / 6); + memcpy(out3_etalon, out[2], bzout / 6); + memcpy(out4_etalon, out[3], bzout / 6); + memcpy(out5_etalon, out[4], bzout / 6); + memcpy(out6_etalon, out[5], bzout / 6); + +#ifdef DEBUG_PRINT + print_data("ETALON"); +#endif + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out[0], 0, bzout / 6); + memset(out[1], 0, bzout / 6); + memset(out[2], 0, bzout / 6); + memset(out[3], 0, bzout / 6); + memset(out[4], 0, bzout / 6); + memset(out[5], 0, bzout / 6); + (*fn)(&pin, bzin, pout, bzout); + + int res = memcmp(out[0], out1_etalon, bzout / 6) || + memcmp(out[1], out2_etalon, bzout / 6) || + memcmp(out[2], out3_etalon, bzout / 6) || + memcmp(out[3], out4_etalon, bzout / 6) || + memcmp(out[4], out5_etalon, bzout / 6) || + memcmp(out[5], out6_etalon, bzout / 6); + + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); + +#ifdef DEBUG_PRINT + print_data("TEST"); +#endif + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_ci16_6cf32_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i]; + const size_t bzout = SPEED_WORD_COUNT * sizeof(float); + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(&pin, bzin, pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_ci16_6cf32_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_ci16_6cf32"); + + ADD_REGRESS_TEST(s, conv_ci16_6cf32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_6cf32_speed, 60, 0, 3); + + return s; +} diff --git a/src/lib/xdsp/utests/conv_ci16_6ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_6ci16_utest.c new file mode 100644 index 00000000..c85b53d8 --- /dev/null +++ b/src/lib/xdsp/utests/conv_ci16_6ci16_utest.c @@ -0,0 +1,227 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_ci16_6ci16_2.h" + +#undef DEBUG_PRINT + +#define CHECK_WORD_COUNT (4098u) //must be a multiple of 6 +#define CHECK_SIZE_BZ (CHECK_WORD_COUNT * sizeof(int16_t)) + +#define SPEED_WORD_COUNT (65536u) +#define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) + +static const unsigned packet_lens[4] = { 8192u, 16384u, 32768u, SPEED_WORD_COUNT }; + +#define SPEED_MEASURE_ITERS 1000000 + +static int16_t* in = NULL; +static int16_t* out1 = NULL; +static int16_t* out1_etalon = NULL; +static int16_t* out2 = NULL; +static int16_t* out2_etalon = NULL; +static int16_t* out3 = NULL; +static int16_t* out3_etalon = NULL; +static int16_t* out4 = NULL; +static int16_t* out4_etalon = NULL; +static int16_t* out5 = NULL; +static int16_t* out5_etalon = NULL; +static int16_t* out6 = NULL; +static int16_t* out6_etalon = NULL; +static int16_t* out[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, SPEED_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, SPEED_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, SPEED_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, SPEED_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out5, ALIGN_BYTES, SPEED_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out6, ALIGN_BYTES, SPEED_SIZE_BZ/6); + + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out5_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/6); + res = res ? res : posix_memalign((void**)&out6_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/6); + + ck_assert_int_eq(res, 0); + + out[0] = out1; + out[1] = out2; + out[2] = out3; + out[3] = out4; + out[4] = out5; + out[5] = out6; + + srand( time(0) ); + + //fill + for(unsigned i = 0; i < SPEED_WORD_COUNT; ++i) + { + int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; + in[i] = sign * i; + } +} + +static void teardown() +{ + free(in); + free(out1); + free(out2); + free(out3); + free(out4); + free(out5); + free(out6); + free(out1_etalon); + free(out2_etalon); + free(out3_etalon); + free(out4_etalon); + free(out5_etalon); + free(out6_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_ci16_6ci16_c, &last_fn_name); +} + + +static void print_data(const char* header) +{ + if(header) + fprintf(stderr, "%s:", header); + + fprintf(stderr, "\n in: "); + for(unsigned i = 0; i < 32; ++i) + { + fprintf(stderr, "%d ", in[i]); + } + + for(unsigned n = 0; n < 6; ++n) + { + fprintf(stderr, "\n out%d: ", n); + for(unsigned i = 0; i < 8; ++i) + { + fprintf(stderr, "%4d ", out[n][i]); + } + } + fprintf(stderr, "\n"); +} + +START_TEST(conv_ci16_6ci16_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = CHECK_SIZE_BZ; + const size_t bzout = CHECK_SIZE_BZ; + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(out[0], 0, bzout / 6); + memset(out[1], 0, bzout / 6); + memset(out[2], 0, bzout / 6); + memset(out[3], 0, bzout / 6); + memset(out[4], 0, bzout / 6); + memset(out[5], 0, bzout / 6); + (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT + print_data("ETALON"); +#endif + memcpy(out1_etalon, out[0], bzout / 6); + memcpy(out2_etalon, out[1], bzout / 6); + memcpy(out3_etalon, out[2], bzout / 6); + memcpy(out4_etalon, out[3], bzout / 6); + memcpy(out5_etalon, out[4], bzout / 6); + memcpy(out6_etalon, out[5], bzout / 6); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out[0], 0, bzout / 6); + memset(out[1], 0, bzout / 6); + memset(out[2], 0, bzout / 6); + memset(out[3], 0, bzout / 6); + memset(out[4], 0, bzout / 6); + memset(out[5], 0, bzout / 6); + (*fn)(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT + print_data(0); +#endif + int res = memcmp(out[0], out1_etalon, bzout / 6) || memcmp(out[1], out2_etalon, bzout / 6) || + memcmp(out[2], out3_etalon, bzout / 6) || memcmp(out[3], out4_etalon, bzout / 6) || + memcmp(out[4], out5_etalon, bzout / 6) || memcmp(out[5], out6_etalon, bzout / 6); + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_ci16_6ci16_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i] * sizeof(int16_t); + const size_t bzout = bzin; + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(&pin, bzin, pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_ci16_6ci16_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_ci16_6ci16"); + + ADD_REGRESS_TEST(s, conv_ci16_6ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_6ci16_speed, 60, 0, 4); + + return s; +} diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index 163bb5e9..4f18e6e4 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -32,6 +32,8 @@ Suite * conv_ci12_2ci16_suite(void); Suite * conv_ci12_4ci16_suite(void); Suite * conv_2ci16_ci12_suite(void); Suite * conv_4ci16_ci12_suite(void); +Suite * conv_ci16_6ci16_suite(void); +Suite * conv_ci16_6cf32_suite(void); int main(int argc, char** argv) { @@ -41,7 +43,7 @@ int main(int argc, char** argv) int number_failed; SRunner *sr; -#if 1 +#if 0 sr = srunner_create( fftad_suite()); srunner_add_suite(sr, rtsa_suite()); srunner_add_suite(sr, fft_window_cf32_suite()); @@ -77,10 +79,9 @@ int main(int argc, char** argv) srunner_add_suite(sr, conv_ci12_4cf32_suite()); // #else - sr = srunner_create(wvlt_sincos_i16_suite()); - //srunner_add_suite(sr, conv_2ci16_ci16_suite()); - //srunner_add_suite(sr, conv_f32_i12_suite()); - //srunner_add_suite(sr, conv_2cf32_ci12_suite()); +// sr = srunner_create(conv_ci16_6cf32_suite()); + sr = srunner_create(conv_ci16_6ci16_suite()); + srunner_add_suite(sr, conv_ci16_6cf32_suite()); #endif srunner_set_fork_status (sr, CK_NOFORK); srunner_run_all(sr, (argc > 1) ? CK_VERBOSE : CK_NORMAL); From 8292f9074129e557cb3485703b49273236339b1c Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 28 Oct 2025 20:51:46 +0300 Subject: [PATCH 207/397] Refactoring for 6-way generics --- src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t | 32 ++----------------- .../templates/conv_ci16_6cf32_generic.inc | 29 +++++++++++++++++ .../xdsp/templates/conv_ci16_6cf32_generic.t | 31 +----------------- src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t | 13 ++------ .../templates/conv_ci16_6ci16_generic.inc | 10 ++++++ .../xdsp/templates/conv_ci16_6ci16_generic.t | 12 +------ 6 files changed, 47 insertions(+), 80 deletions(-) create mode 100644 src/lib/xdsp/templates/conv_ci16_6cf32_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci16_6ci16_generic.inc diff --git a/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t b/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t index 0cad220c..8018af31 100644 --- a/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t @@ -72,37 +72,11 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, inptr64 += 12; } - const int16_t *in = (const int16_t *)inptr64; - for (; i >= 24; i -= 24) + //Generic block { - const float i0 = *in++; - const float q0 = *in++; - const float i1 = *in++; - const float q1 = *in++; - const float i2 = *in++; - const float q2 = *in++; - const float i3 = *in++; - const float q3 = *in++; - const float i4 = *in++; - const float q4 = *in++; - const float i5 = *in++; - const float q5 = *in++; - - *(outdata_0++) = i0 * CONV_SCALE; - *(outdata_0++) = q0 * CONV_SCALE; - *(outdata_1++) = i1 * CONV_SCALE; - *(outdata_1++) = q1 * CONV_SCALE; - *(outdata_2++) = i2 * CONV_SCALE; - *(outdata_2++) = q2 * CONV_SCALE; - *(outdata_3++) = i3 * CONV_SCALE; - *(outdata_3++) = q3 * CONV_SCALE; - *(outdata_4++) = i4 * CONV_SCALE; - *(outdata_4++) = q4 * CONV_SCALE; - *(outdata_5++) = i5 * CONV_SCALE; - *(outdata_5++) = q5 * CONV_SCALE; + const int16_t *in = (const int16_t *)inptr64; + #include "conv_ci16_6cf32_generic.inc" } - - // do nothing with leftover } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_6cf32_generic.inc b/src/lib/xdsp/templates/conv_ci16_6cf32_generic.inc new file mode 100644 index 00000000..363c3e91 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6cf32_generic.inc @@ -0,0 +1,29 @@ +for (; i >= 24; i -= 24) +{ + const float i0 = *in++; + const float q0 = *in++; + const float i1 = *in++; + const float q1 = *in++; + const float i2 = *in++; + const float q2 = *in++; + const float i3 = *in++; + const float q3 = *in++; + const float i4 = *in++; + const float q4 = *in++; + const float i5 = *in++; + const float q5 = *in++; + + *(outdata_0++) = i0 * CONV_SCALE; + *(outdata_0++) = q0 * CONV_SCALE; + *(outdata_1++) = i1 * CONV_SCALE; + *(outdata_1++) = q1 * CONV_SCALE; + *(outdata_2++) = i2 * CONV_SCALE; + *(outdata_2++) = q2 * CONV_SCALE; + *(outdata_3++) = i3 * CONV_SCALE; + *(outdata_3++) = q3 * CONV_SCALE; + *(outdata_4++) = i4 * CONV_SCALE; + *(outdata_4++) = q4 * CONV_SCALE; + *(outdata_5++) = i5 * CONV_SCALE; + *(outdata_5++) = q5 * CONV_SCALE; +} +// do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_ci16_6cf32_generic.t b/src/lib/xdsp/templates/conv_ci16_6cf32_generic.t index a8324d62..59f6f968 100644 --- a/src/lib/xdsp/templates/conv_ci16_6cf32_generic.t +++ b/src/lib/xdsp/templates/conv_ci16_6cf32_generic.t @@ -22,36 +22,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, float* outdata_4 = (float*)outdata_4_p; float* outdata_5 = (float*)outdata_5_p; - for (; i >= 24; i -= 24) - { - const float i0 = *in++; - const float q0 = *in++; - const float i1 = *in++; - const float q1 = *in++; - const float i2 = *in++; - const float q2 = *in++; - const float i3 = *in++; - const float q3 = *in++; - const float i4 = *in++; - const float q4 = *in++; - const float i5 = *in++; - const float q5 = *in++; - - *(outdata_0++) = i0 * CONV_SCALE; - *(outdata_0++) = q0 * CONV_SCALE; - *(outdata_1++) = i1 * CONV_SCALE; - *(outdata_1++) = q1 * CONV_SCALE; - *(outdata_2++) = i2 * CONV_SCALE; - *(outdata_2++) = q2 * CONV_SCALE; - *(outdata_3++) = i3 * CONV_SCALE; - *(outdata_3++) = q3 * CONV_SCALE; - *(outdata_4++) = i4 * CONV_SCALE; - *(outdata_4++) = q4 * CONV_SCALE; - *(outdata_5++) = i5 * CONV_SCALE; - *(outdata_5++) = q5 * CONV_SCALE; - } - - // do nothing with leftover + #include "conv_ci16_6cf32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t b/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t index 02f2ca6f..1cdbcd98 100644 --- a/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t @@ -63,18 +63,11 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, inptr64 += 12; } - const uint32_t* indata = (uint32_t*)inptr64; - for (; i >= 24; i -= 24) + //Generic block { - *outdata_0++ = *indata++; - *outdata_1++ = *indata++; - *outdata_2++ = *indata++; - *outdata_3++ = *indata++; - *outdata_4++ = *indata++; - *outdata_5++ = *indata++; + const uint32_t* indata = (uint32_t*)inptr64; + #include "conv_ci16_6ci16_generic.inc" } - - // do nothing with leftover } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_generic.inc b/src/lib/xdsp/templates/conv_ci16_6ci16_generic.inc new file mode 100644 index 00000000..559b733d --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_generic.inc @@ -0,0 +1,10 @@ +for (; i >= 24; i -= 24) +{ + *outdata_0++ = *indata++; + *outdata_1++ = *indata++; + *outdata_2++ = *indata++; + *outdata_3++ = *indata++; + *outdata_4++ = *indata++; + *outdata_5++ = *indata++; +} +// do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_generic.t b/src/lib/xdsp/templates/conv_ci16_6ci16_generic.t index 402df5c1..26bb1869 100644 --- a/src/lib/xdsp/templates/conv_ci16_6ci16_generic.t +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_generic.t @@ -22,17 +22,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, uint32_t* outdata_4 = (uint32_t*)outdata_4_p; uint32_t* outdata_5 = (uint32_t*)outdata_5_p; - for (; i >= 24; i -= 24) - { - *outdata_0++ = *indata++; - *outdata_1++ = *indata++; - *outdata_2++ = *indata++; - *outdata_3++ = *indata++; - *outdata_4++ = *indata++; - *outdata_5++ = *indata++; - } - - // do nothing with leftover + #include "conv_ci16_6ci16_generic.inc" } #undef TEMPLATE_FUNC_NAME From c1d48572257d20f5fad73f359195c37ce6610cd9 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 29 Oct 2025 13:42:11 +0400 Subject: [PATCH 208/397] dsdr: fix crash when liblibafe79xx wasn't provided --- src/lib/device/m2_dsdr/m2_dsdr.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 7f8bfe0f..7964b5fb 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -542,6 +542,11 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { static const uint8_t s_chanmap_hw_to_fe[4] = { 2, 3, 1, 0 }; static const uint8_t s_chanmap_fe_to_hw[4] = { 3, 2, 0, 1 }; +enum DSDR_STATE { + STATE_IDLE = 0, + STATE_AFE_INIT = 1, +}; + struct dev_m2_dsdr { device_t base; @@ -558,6 +563,7 @@ struct dev_m2_dsdr { afe79xx_state_t st; dsdr_hiper_fe_t hiper; + uint32_t dsdr_state; uint32_t cfg_afe_type; uint32_t cfg_rx_lanemap; uint32_t cfg_tx_lanemap; @@ -1187,7 +1193,7 @@ int dev_m2_dsdr_debug_clk_info_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t * { struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; int res = 0; - uint32_t clk; + uint32_t clk = 0; res = res ? res : dev_gpi_get32(d->base.dev, 20, &clk); *value = clk & 0xfffffff; @@ -1359,6 +1365,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** unsigned lms8_step = LMS8_MPW2015; d->subdev = 0; + d->dsdr_state = STATE_IDLE; d->hw_mask_fb = 0; d->hw_mask_rx = 0xf; // RX_3 RX_2 RX_1 RX_0 d->hw_mask_tx = 0xf; // TX_3 TX_2 TX_1 TX_0 @@ -1734,13 +1741,12 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // check state res = res ? res : dev_m2_dsdr_afe_health_get(udev, NULL, NULL); - USDR_LOG("DSDR", USDR_LOG_ERROR, "Initializing AFE done\n"); - - - // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 1); - // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 0); + if (res) + return res; - return res; + USDR_LOG("DSDR", USDR_LOG_WARNING, "Initializing AFE done!\n"); + d->dsdr_state = STATE_AFE_INIT; + return 0; } @@ -1906,6 +1912,10 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char unsigned hwchs; channel_info_t lchans; + if (d->dsdr_state != STATE_AFE_INIT) { + return -EFAULT; + } + res = dsdr_map_channels(channels, &lchans); if (res) { return res; From ffbe1b69ad89837cb05c4659e9f123308c23f8b9 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 29 Oct 2025 20:51:43 +0400 Subject: [PATCH 209/397] hiper add LMS8A_MPW2024 and LMS8B_MPW2024 enviroment to alter LMS8 stepping --- src/lib/device/m2_dsdr/dsdr_hiper.c | 4 ++-- src/lib/device/m2_dsdr/dsdr_hiper.h | 2 +- src/lib/device/m2_dsdr/m2_dsdr.c | 13 +++++++++---- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 789e12dd..fa683b13 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -746,7 +746,7 @@ static int dsdr_hiper_initialize_lms8(dsdr_hiper_fe_t* dfe, unsigned addr, unsig return res; } #include -int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, dsdr_hiper_fe_t* dfe) +int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8a_chip, unsigned lms8b_chip, dsdr_hiper_fe_t* dfe) { int res = 0; device_t* base = lowlevel_get_device(dev); @@ -843,7 +843,7 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8_chip, // LMS8 for (unsigned k = 0; k < 6; k++) { uint32_t cfg = MAKE_SPIEXT_LSOPADR(MAKE_SPIEXT_CFG(LMS8_BCNTZ, k, LMS8_DIV), 0, spix_num); - res = res ? res : dsdr_hiper_initialize_lms8(dfe, cfg, lms8_chip, &dfe->lms8[k]); + res = res ? res : dsdr_hiper_initialize_lms8(dfe, cfg, (k == 2 || k == 3) ? lms8a_chip : lms8b_chip, &dfe->lms8[k]); } // ADF4002 (MUX -> GND -> DVDD readback as a sanity check) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.h b/src/lib/device/m2_dsdr/dsdr_hiper.h index f7886a43..fee4cbe5 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.h +++ b/src/lib/device/m2_dsdr/dsdr_hiper.h @@ -113,7 +113,7 @@ struct dsdr_hiper_fe { typedef struct dsdr_hiper_fe dsdr_hiper_fe_t; -int dsdr_hiper_fe_create(lldev_t dev, unsigned spix_num, unsigned lms8_chip, dsdr_hiper_fe_t* dfe); +int dsdr_hiper_fe_create(lldev_t dev, unsigned spix_num, unsigned lms8a_chip, unsigned int lms8b_chip, dsdr_hiper_fe_t* dfe); int dsdr_hiper_fe_destroy(dsdr_hiper_fe_t* dfe); int dsdr_hiper_fe_rx_freq_set(dsdr_hiper_fe_t* def, unsigned chno, uint64_t freq, uint64_t* ncotune, bool *p_swap_rxiq); diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 7964b5fb..e9c7002a 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1362,7 +1362,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** int res = 0; uint32_t hwid, usr2, pg, los, devid, jesdv; unsigned afeType = 0; - unsigned lms8_step = LMS8_MPW2015; + unsigned lms8a_step = LMS8_MPW2015; + unsigned lms8b_step = LMS8_MPW2015; d->subdev = 0; d->dsdr_state = STATE_IDLE; @@ -1731,10 +1732,14 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } if (d->type == DSDR_PCIE_HIPER_R0) { - if (getenv("LMS8_MPW2024")) { - lms8_step = LMS8_MPW2024; + if (getenv("LMS8A_MPW2024")) { + lms8a_step = LMS8_MPW2024; } - res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, lms8_step, &d->hiper); + if (getenv("LMS8B_MPW2024")) { + lms8b_step = LMS8_MPW2024; + } + + res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, lms8a_step, lms8b_step, &d->hiper); } usleep(100000); From 3421bc513009bf005a6626e3428df882cad8c28a Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Wed, 29 Oct 2025 19:57:10 +0300 Subject: [PATCH 210/397] Add ci16_6 avx512 convs --- src/lib/xdsp/conv_ci16_6cf32_2.c | 8 ++ src/lib/xdsp/conv_ci16_6ci16_2.c | 8 ++ src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t | 12 +- .../xdsp/templates/conv_ci16_6cf32_avx512bw.t | 112 ++++++++++++++++++ src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t | 12 +- .../templates/conv_ci16_6ci16_avx512bw.inc | 13 ++ .../xdsp/templates/conv_ci16_6ci16_avx512bw.t | 96 +++++++++++++++ 7 files changed, 249 insertions(+), 12 deletions(-) create mode 100644 src/lib/xdsp/templates/conv_ci16_6cf32_avx512bw.t create mode 100644 src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.inc create mode 100644 src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.t diff --git a/src/lib/xdsp/conv_ci16_6cf32_2.c b/src/lib/xdsp/conv_ci16_6cf32_2.c index 48c6b61a..ab3b6745 100644 --- a/src/lib/xdsp/conv_ci16_6cf32_2.c +++ b/src/lib/xdsp/conv_ci16_6cf32_2.c @@ -11,6 +11,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci16_6cf32_generic.t" DECLARE_TR_FUNC_1_6(conv_ci16_6cf32_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_ci16_6cf32_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_ci16_6cf32_avx512bw.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6cf32_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_ci16_6cf32_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -34,6 +41,7 @@ conv_function_t conv_get_ci16_6cf32_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_6cf32_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_ci16_6cf32_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_ci16_6cf32_avx512bw, cpu_cap); //SELECT_NEON_FN(fn, fname, tr_conv_ci16_4cf32_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/conv_ci16_6ci16_2.c b/src/lib/xdsp/conv_ci16_6ci16_2.c index d82156e2..94a58010 100644 --- a/src/lib/xdsp/conv_ci16_6ci16_2.c +++ b/src/lib/xdsp/conv_ci16_6ci16_2.c @@ -9,6 +9,13 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci16_6ci16_generic.t" DECLARE_TR_FUNC_1_6(conv_ci16_6ci16_generic) +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_ci16_6ci16_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_ci16_6ci16_avx512bw.t" +DECLARE_TR_FUNC_1_6(conv_ci16_6ci16_avx512bw) +#endif + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME conv_ci16_6ci16_avx2 VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) @@ -32,6 +39,7 @@ conv_function_t conv_get_ci16_6ci16_c(generic_opts_t cpu_cap, const char** sfunc SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_6ci16_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_ci16_6ci16_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_ci16_6ci16_avx512bw, cpu_cap); //SELECT_NEON_FN(fn, fname, tr_conv_ci16_4ci16_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t b/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t index 8018af31..4c03627a 100644 --- a/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci16_6cf32_avx2.t @@ -54,12 +54,12 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, __m256i d4 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(c0, 1)); __m256i d5 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(c1, 1)); - _mm256_storeu_ps(outdata_0, _mm256_mul_ps(_mm256_cvtepi32_ps(d0), scale)); - _mm256_storeu_ps(outdata_1, _mm256_mul_ps(_mm256_cvtepi32_ps(d1), scale)); - _mm256_storeu_ps(outdata_2, _mm256_mul_ps(_mm256_cvtepi32_ps(d2), scale)); - _mm256_storeu_ps(outdata_3, _mm256_mul_ps(_mm256_cvtepi32_ps(d3), scale)); - _mm256_storeu_ps(outdata_4, _mm256_mul_ps(_mm256_cvtepi32_ps(d4), scale)); - _mm256_storeu_ps(outdata_5, _mm256_mul_ps(_mm256_cvtepi32_ps(d5), scale)); + _mm256_store_ps(outdata_0, _mm256_mul_ps(_mm256_cvtepi32_ps(d0), scale)); + _mm256_store_ps(outdata_1, _mm256_mul_ps(_mm256_cvtepi32_ps(d1), scale)); + _mm256_store_ps(outdata_2, _mm256_mul_ps(_mm256_cvtepi32_ps(d2), scale)); + _mm256_store_ps(outdata_3, _mm256_mul_ps(_mm256_cvtepi32_ps(d3), scale)); + _mm256_store_ps(outdata_4, _mm256_mul_ps(_mm256_cvtepi32_ps(d4), scale)); + _mm256_store_ps(outdata_5, _mm256_mul_ps(_mm256_cvtepi32_ps(d5), scale)); outdata_0 += 8; outdata_1 += 8; diff --git a/src/lib/xdsp/templates/conv_ci16_6cf32_avx512bw.t b/src/lib/xdsp/templates/conv_ci16_6cf32_avx512bw.t new file mode 100644 index 00000000..63bcff9a --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6cf32_avx512bw.t @@ -0,0 +1,112 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + float* outdata_3 = (float*)outdata_3_p; + float* outdata_4 = (float*)outdata_4_p; + float* outdata_5 = (float*)outdata_5_p; + + const long long int* inptr64 = (long long int*)indata_p; + const __m512 scale = _mm512_set1_ps(CONV_SCALE); + const __m256 scale_avx2 = _mm256_set1_ps(CONV_SCALE); + + #include "conv_ci16_6ci16_avx512bw.inc" + + while(i >= 24 * sizeof(uint64_t)) + { + __m512i in0 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 0); + __m512i in1 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 6); + __m512i in2 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 12); + __m512i in3 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 18); + + __m512i c0, c1, c2, c3; + AVX512_INTERLEAVE6(in0, in1, c0, c1); + AVX512_INTERLEAVE6(in2, in3, c2, c3); + + __m512i d0 = _mm512_permutex2var_epi64(c0, permmask1, c2); + __m512i d1 = _mm512_permutex2var_epi64(c1, permmask1, c3); + __m512i d2 = _mm512_permutex2var_epi64(c0, permmask2, c2); + __m512i d3 = _mm512_permutex2var_epi64(c1, permmask2, c3); + + __m512 r0 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_castsi512_si256(d0))); + __m512 r1 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_castsi512_si256(d1))); + __m512 r2 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_castsi512_si256(d2))); + __m512 r3 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_castsi512_si256(d3))); + __m512 r4 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(d0, 1))); + __m512 r5 = _mm512_cvtepi32_ps(_mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(d1, 1))); + + _mm512_store_ps(outdata_0, _mm512_mul_ps(r0, scale)); + _mm512_store_ps(outdata_1, _mm512_mul_ps(r1, scale)); + _mm512_store_ps(outdata_2, _mm512_mul_ps(r2, scale)); + _mm512_store_ps(outdata_3, _mm512_mul_ps(r3, scale)); + _mm512_store_ps(outdata_4, _mm512_mul_ps(r4, scale)); + _mm512_store_ps(outdata_5, _mm512_mul_ps(r5, scale)); + + outdata_0 += 16; + outdata_1 += 16; + outdata_2 += 16; + outdata_3 += 16; + outdata_4 += 16; + outdata_5 += 16; + + i -= 24 * sizeof(uint64_t); + inptr64 += 24; + } + + while(i >= 12 * sizeof(uint64_t)) + { + __m512i in0 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 0); + __m512i in1 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 6); + + __m512i c0, c1; + AVX512_INTERLEAVE6(in0, in1, c0, c1); + + __m256 r0 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm512_castsi512_si128(c0))); + __m256 r1 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm512_castsi512_si128(c1))); + __m256 r2 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm512_extracti32x4_epi32(c0, 1))); + __m256 r3 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm512_extracti32x4_epi32(c1, 1))); + __m256 r4 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm512_extracti32x4_epi32(c0, 2))); + __m256 r5 = _mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm512_extracti32x4_epi32(c1, 2))); + + _mm256_store_ps(outdata_0, _mm256_mul_ps(r0, scale_avx2)); + _mm256_store_ps(outdata_1, _mm256_mul_ps(r1, scale_avx2)); + _mm256_store_ps(outdata_2, _mm256_mul_ps(r2, scale_avx2)); + _mm256_store_ps(outdata_3, _mm256_mul_ps(r3, scale_avx2)); + _mm256_store_ps(outdata_4, _mm256_mul_ps(r4, scale_avx2)); + _mm256_store_ps(outdata_5, _mm256_mul_ps(r5, scale_avx2)); + + outdata_0 += 8; + outdata_1 += 8; + outdata_2 += 8; + outdata_3 += 8; + outdata_4 += 8; + outdata_5 += 8; + + i -= 12 * sizeof(uint64_t); + inptr64 += 12; + } + +#undef AVX512_INTERLEAVE6 + + //Generic block + { + const int16_t *in = (const int16_t *)inptr64; + #include "conv_ci16_6cf32_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t b/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t index 1cdbcd98..1566da03 100644 --- a/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_avx2.t @@ -45,12 +45,12 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, __m256i c1 = _mm256_castpd_si256(_mm256_shuffle_pd(b1, b3, 0b0000)); __m256i c3 = _mm256_castpd_si256(_mm256_shuffle_pd(b1, b3, 0b1111)); - _mm_storeu_si128((__m128i*)outdata_0, _mm256_castsi256_si128(c0)); - _mm_storeu_si128((__m128i*)outdata_1, _mm256_castsi256_si128(c1)); - _mm_storeu_si128((__m128i*)outdata_2, _mm256_castsi256_si128(c2)); - _mm_storeu_si128((__m128i*)outdata_3, _mm256_castsi256_si128(c3)); - _mm_storeu_si128((__m128i*)outdata_4, _mm256_extracti128_si256(c0, 1)); - _mm_storeu_si128((__m128i*)outdata_5, _mm256_extracti128_si256(c1, 1)); + _mm_store_si128((__m128i*)outdata_0, _mm256_castsi256_si128(c0)); + _mm_store_si128((__m128i*)outdata_1, _mm256_castsi256_si128(c1)); + _mm_store_si128((__m128i*)outdata_2, _mm256_castsi256_si128(c2)); + _mm_store_si128((__m128i*)outdata_3, _mm256_castsi256_si128(c3)); + _mm_store_si128((__m128i*)outdata_4, _mm256_extracti128_si256(c0, 1)); + _mm_store_si128((__m128i*)outdata_5, _mm256_extracti128_si256(c1, 1)); outdata_0 += 4; outdata_1 += 4; diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.inc b/src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.inc new file mode 100644 index 00000000..6b9a364b --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.inc @@ -0,0 +1,13 @@ +const __m512i permmask0 = _mm512_set_epi32(15,14,13,12, 11,5,10,4, 9,3,8,2, 7,1,6,0); +const __m512i permmask1 = _mm512_set_epi64(13,12,5,4,9,8,1,0); +const __m512i permmask2 = _mm512_set_epi64(15,14,7,6,11,10,3,2); + +#define AVX512_INTERLEAVE6(in0, in1, out0, out1) \ +{ \ + __m512i a0 = _mm512_unpacklo_epi32(in0, in1); \ + __m512i a1 = _mm512_unpackhi_epi32(in0, in1); \ + __m512i b0 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a0), _mm512_castsi512_pd(a1), 0b00000000)); \ + __m512i b1 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(a0), _mm512_castsi512_pd(a1), 0b11111111)); \ + out0 = _mm512_permutexvar_epi32(permmask0, b0); \ + out1 = _mm512_permutexvar_epi32(permmask0, b1); \ +} diff --git a/src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.t b/src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.t new file mode 100644 index 00000000..198bf6a7 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_6ci16_avx512bw.t @@ -0,0 +1,96 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + uint32_t* outdata_0 = (uint32_t*)outdata_0_p; + uint32_t* outdata_1 = (uint32_t*)outdata_1_p; + uint32_t* outdata_2 = (uint32_t*)outdata_2_p; + uint32_t* outdata_3 = (uint32_t*)outdata_3_p; + uint32_t* outdata_4 = (uint32_t*)outdata_4_p; + uint32_t* outdata_5 = (uint32_t*)outdata_5_p; + + const long long int* inptr64 = (long long int*)indata_p; + + #include "conv_ci16_6ci16_avx512bw.inc" + + while(i >= 24 * sizeof(uint64_t)) + { + __m512i in0 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 0); + __m512i in1 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 6); + __m512i in2 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 12); + __m512i in3 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 18); + + __m512i c0, c1, c2, c3; + AVX512_INTERLEAVE6(in0, in1, c0, c1); + AVX512_INTERLEAVE6(in2, in3, c2, c3); + + __m512i d0 = _mm512_permutex2var_epi64(c0, permmask1, c2); + __m512i d1 = _mm512_permutex2var_epi64(c1, permmask1, c3); + __m512i d2 = _mm512_permutex2var_epi64(c0, permmask2, c2); + __m512i d3 = _mm512_permutex2var_epi64(c1, permmask2, c3); + + _mm256_store_si256((__m256i*)outdata_0, _mm512_castsi512_si256(d0)); + _mm256_store_si256((__m256i*)outdata_1, _mm512_castsi512_si256(d1)); + _mm256_store_si256((__m256i*)outdata_2, _mm512_castsi512_si256(d2)); + _mm256_store_si256((__m256i*)outdata_3, _mm512_castsi512_si256(d3)); + _mm256_store_si256((__m256i*)outdata_4, _mm512_extracti64x4_epi64(d0, 1)); + _mm256_store_si256((__m256i*)outdata_5, _mm512_extracti64x4_epi64(d1, 1)); + + outdata_0 += 8; + outdata_1 += 8; + outdata_2 += 8; + outdata_3 += 8; + outdata_4 += 8; + outdata_5 += 8; + + i -= 24 * sizeof(uint64_t); + inptr64 += 24; + } + + while(i >= 12 * sizeof(uint64_t)) + { + __m512i in0 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 0); + __m512i in1 = _mm512_maskz_loadu_epi64(0b00111111, inptr64 + 6); + + __m512i c0, c1; + AVX512_INTERLEAVE6(in0, in1, c0, c1); + + _mm_store_si128((__m128i*)outdata_0, _mm512_castsi512_si128(c0)); + _mm_store_si128((__m128i*)outdata_1, _mm512_castsi512_si128(c1)); + _mm_store_si128((__m128i*)outdata_2, _mm512_extracti32x4_epi32(c0, 1)); + _mm_store_si128((__m128i*)outdata_3, _mm512_extracti32x4_epi32(c1, 1)); + _mm_store_si128((__m128i*)outdata_4, _mm512_extracti32x4_epi32(c0, 2)); + _mm_store_si128((__m128i*)outdata_5, _mm512_extracti32x4_epi32(c1, 2)); + + outdata_0 += 4; + outdata_1 += 4; + outdata_2 += 4; + outdata_3 += 4; + outdata_4 += 4; + outdata_5 += 4; + + i -= 12 * sizeof(uint64_t); + inptr64 += 12; + } + +#undef AVX512_INTERLEAVE6 + + //Generic block + { + const uint32_t* indata = (uint32_t*)inptr64; + #include "conv_ci16_6ci16_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME From d8104f083d24f0ccca7556052fb14d985d694d11 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 30 Oct 2025 14:59:25 +0400 Subject: [PATCH 211/397] dsdr_hiper: fix readback of expanders in HiperR2 --- src/lib/device/m2_dsdr/dsdr_hiper.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index fa683b13..a2460682 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -688,6 +688,16 @@ int dsdr_hiper_dsdr_hiper_exp_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ case 0x26: res = tca6424a_reg8_get(hiper->dev, hiper->subdev, I2C_TCA6424AR_U115, TCA6424_OUT0 + (addr - 0x24), &di8); break; + + case 0x27: + case 0x28: + case 0x29: + if (hiper->rev == HIPER_REV2) { + res = tca6424a_reg8_get(hiper->dev, hiper->subdev, I2C_TCA6424AR_U110, TCA6424_OUT0 + (addr - 0x27), &di8); + } else { + di8 = 0xff; + } + break; default: return -EINVAL; } From 84ad4db5929dea4af25369a2e43ab1bed587d134 Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:04:40 +0400 Subject: [PATCH 212/397] Fixed yamls installation. --- src/lib/device/m2_dsdr/CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/lib/device/m2_dsdr/CMakeLists.txt b/src/lib/device/m2_dsdr/CMakeLists.txt index 3f18ff4a..af1170b1 100644 --- a/src/lib/device/m2_dsdr/CMakeLists.txt +++ b/src/lib/device/m2_dsdr/CMakeLists.txt @@ -10,6 +10,7 @@ set(HW_FILES m2_dsdr_e m2_dsdr_p m2_dsdr_usr) foreach(I ${HW_FILES}) message(STATUS "Generating header for ${I}") GENERATE_YAML_H(${CMAKE_CURRENT_SOURCE_DIR}/${I}.yaml ${CMAKE_CURRENT_BINARY_DIR}/def_${I}.h) + install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${I}.yaml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/usdr/schema/) list(APPEND USDR_DEPEND_TARGETS generate_${I}) endforeach() @@ -20,8 +21,3 @@ list(APPEND USDR_LIBRARY_FILES ${USDR_DSDR_LIB_FILES}) set(USDR_LIBRARY_FILES ${USDR_LIBRARY_FILES} PARENT_SCOPE) set(USDR_DEPEND_TARGETS ${USDR_DEPEND_TARGETS} PARENT_SCOPE) set(USDR_INCLUDE_DIRS ${USDR_INCLUDE_DIRS} PARENT_SCOPE) - -# Extra yaml files -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/m2_dsdr.yaml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/usdr/schema/) -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/m2_dsdr_e.yaml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/usdr/schema/) -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/m2_dsdr_p.yaml DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/usdr/schema/) From 6ec27f2b9600b86a59104581c5cc0bc6ef1658d2 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Thu, 30 Oct 2025 16:07:36 +0300 Subject: [PATCH 213/397] try to optimize redundant transforms on i12-f32 convs --- src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t | 42 +++++++++++++++++++ src/lib/xdsp/templates/conv_i12_f32_avx2.inc | 28 ++++++++++++- src/lib/xdsp/templates/conv_i12_i16_avx2.inc | 14 +++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t index 2014ea29..ab39419f 100644 --- a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t @@ -14,6 +14,47 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, float* outdata_0 = (float*)outdata_0_p; float* outdata_1 = (float*)outdata_1_p; +#if 1 + + #include "conv_i12_i16_avx2.inc" + #include "conv_i12_f32_avx2.inc" + + while(i >= 96) + { + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + __m256i y2 = _mm256_maskload_epi64((const long long*)(in + 6), load_mask); + __m256i y3 = _mm256_maskload_epi64((const long long*)(in + 9), load_mask); + + __m256 r0, r1; + + CONVERT_CI12_2CF32_BLOCK_OPT(y0, r0, r1); + _mm256_store_ps(outdata_0 + 0, r0); + _mm256_store_ps(outdata_1 + 0, r1); + + CONVERT_CI12_2CF32_BLOCK_OPT(y1, r0, r1); + _mm256_store_ps(outdata_0 + 8, r0); + _mm256_store_ps(outdata_1 + 8, r1); + + CONVERT_CI12_2CF32_BLOCK_OPT(y2, r0, r1); + _mm256_store_ps(outdata_0 + 16, r0); + _mm256_store_ps(outdata_1 + 16, r1); + + CONVERT_CI12_2CF32_BLOCK_OPT(y3, r0, r1); + _mm256_store_ps(outdata_0 + 24, r0); + _mm256_store_ps(outdata_1 + 24, r1); + + i -= 96; + in += 12; + outdata_0 += 32; + outdata_1 += 32; + } + + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_2CI16_BLOCK_OPT + +#else + const __m256 scale = _mm256_set1_ps(CONV_SCALE); const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); @@ -110,6 +151,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef CONVERT_I12_F32_BLOCK +#endif const uint8_t *indata = (const uint8_t*)in; #include "conv_ci12_2cf32_generic.inc" diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx2.inc b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc index 85c11a42..c9aac901 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx2.inc +++ b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc @@ -1,4 +1,5 @@ -const __m256 scale = _mm256_set1_ps(CONV_SCALE); +const __m256 scale = _mm256_set1_ps(CONV_SCALE); +const __m256 scale2 = _mm256_set1_ps(SCALE2); /* * reg: @@ -25,6 +26,19 @@ const __m256 scale = _mm256_set1_ps(CONV_SCALE); * | f15 |0| f14 |0| f13 |0| f12 |0| f11 |0| f10 |0| f9 |0| f8 |0| f7 |0| f6 |0| f5 |0| f4 |0| f3 |0| f2 |0| f1 |0| f0 |0| */ +/* +* | f14 |0| 00 00 | f12 |0| 00 00 | f10 |0| 00 00 | f8 |0| 00 00 | f6 |0| 00 00 | f4 |0| 00 00 | f2 |0| 00 00 | f0 |0| 00 00 | +* | f15 |0| 00 00 | f13 |0| 00 00 | f11 |0| 00 00 | f9 |0| 00 00 | f7 |0| 00 00 | f5 |0| 00 00 | f3 |0| 00 00 | f1 |0| 00 00 | + + +f11 f10 f9 f8 | f3 f2 f1 f0 unpack +f15 f14 f13 f12 | f7 f6 f5 f4 + +f13 f12 f9 f8 | f5 f4 f1 f0 _mm256_shuffle_pd +f15 f14 f11 f10 | f7 f6 f3 f2 + +*/ + #define CONVERT_I12_F32_BLOCK(reg, res0, res1) \ { \ __m256i result; \ @@ -48,3 +62,15 @@ const __m256 scale = _mm256_set1_ps(CONV_SCALE); _MM256_STOREX_PS(outdata + 8, res1); \ outdata += 16; \ } + +#define CONVERT_CI12_2CF32_BLOCK_OPT(reg, res0, res1) \ +{ \ + __m256i result0, result1; \ + CONVERT_CI12_2CI16_BLOCK_OPT(reg, result0, result1); \ + \ + res0 = _mm256_cvtepi32_ps(result0); \ + res1 = _mm256_cvtepi32_ps(result1); \ + \ + res0 = _mm256_mul_ps(res0, scale2); \ + res1 = _mm256_mul_ps(res1, scale2); \ +} diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx2.inc b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc index dfddab87..fc77ff07 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx2.inc +++ b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc @@ -19,3 +19,17 @@ const __m256i shfl = _mm256_set_epi8( __m256i r1 = _mm256_and_si256(_mm256_srli_epi64(r, 4), mask1); \ result = _mm256_or_si256(r0, r1); \ } + +#define CONVERT_CI12_2CI16_BLOCK_OPT(reg, res0, res1) \ +{ \ + __m256i v0 = _mm256_permutevar8x32_epi32(reg, permmask); \ + __m256i r = _mm256_shuffle_epi8(v0, shfl); \ + \ + __m256i a1 = _mm256_and_si256(r, mask0); \ + __m256i a0 = _mm256_and_si256(_mm256_slli_epi64(r, 12), mask0); \ + \ + __m256i b0 = _mm256_unpacklo_epi32(a0, a1); \ + __m256i b1 = _mm256_unpackhi_epi32(a0, a1); \ + res0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b0), _mm256_castsi256_pd(b1), 0b0000)); \ + res1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b0), _mm256_castsi256_pd(b1), 0b1111)); \ +} From 4d88a8a148b08add8e721f6fdd401b2784655c48 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 31 Oct 2025 01:20:12 +0400 Subject: [PATCH 214/397] conv_ci12_4cf32_generic: fix sigfault when the last byte of packet is page boundary --- src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc b/src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc index 266ce24d..30f3404a 100644 --- a/src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_generic.inc @@ -2,7 +2,7 @@ for (; i >= 12; i -= 12) { /* read 12 bytes -> 2*48 bits -> 4*2 floats -> 4cf32 */ uint64_t v0 = *(const uint64_t *)(indata + 0); - uint64_t v1 = *(const uint64_t *)(indata + 6); + uint64_t v1 = ((uint64_t)((*(const uint32_t *)(indata + 8))) << 16) | (v0 >> 48); indata += 12; float i0 = (int16_t)(v0 << 4); From be62e25dd534cb8e1b824de72149330a1e96803f Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 31 Oct 2025 01:21:45 +0400 Subject: [PATCH 215/397] conv_ci12_4cf32_avx512bw: unwrap operation by default (4x) --- .../xdsp/templates/conv_ci12_4cf32_avx512bw.t | 103 +++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t index de7430fd..077856c4 100644 --- a/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t @@ -1,3 +1,12 @@ +#ifndef UNWRAP_CNT +#define UNWRAP_CNT 4 +#endif + +#if UNWRAP_CNT > 4 +#error Maximum spported UNWRAP_CNT is 4! +#endif + + static void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, unsigned indatabsz, @@ -26,23 +35,78 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, __m512i y0, y1; __m512 res0, res1, res2, res3; +#if UNWRAP_CNT > 1 + __m512i y2, y3; + __m512 res4, res5, res6, res7; +#if UNWRAP_CNT > 2 + __m512i y4, y5; + __m512 res8, res9, resA, resB; +#if UNWRAP_CNT > 3 + __m512i y6, y7; + __m512 resC, resD, resE, resF; +#endif +#endif +#endif const __m512i idx0 = _mm512_set_epi64(13, 9,12, 8,5,1,4,0); const __m512i idx1 = _mm512_set_epi64(15,11,14,10,7,3,6,2); - for(; i >= 96; i -= 96) + for(; i >= 96 * UNWRAP_CNT; i -= 96 * UNWRAP_CNT) { y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); - in += 12; +#if UNWRAP_CNT > 1 + y2 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 12)); + y3 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 18)); +#if UNWRAP_CNT > 2 + y4 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 24)); + y5 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 30)); +#if UNWRAP_CNT > 3 + y6 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 36)); + y7 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 42)); +#endif +#endif +#endif + + in += UNWRAP_CNT * 12; CONVERT_I12_F32_BLOCK(y0, res0, res1); CONVERT_I12_F32_BLOCK(y1, res2, res3); +#if UNWRAP_CNT > 1 + CONVERT_I12_F32_BLOCK(y2, res4, res5); + CONVERT_I12_F32_BLOCK(y3, res6, res7); +#if UNWRAP_CNT > 2 + CONVERT_I12_F32_BLOCK(y4, res8, res9); + CONVERT_I12_F32_BLOCK(y5, resA, resB); +#if UNWRAP_CNT > 3 + CONVERT_I12_F32_BLOCK(y6, resC, resD); + CONVERT_I12_F32_BLOCK(y7, resE, resF); +#endif +#endif +#endif __m512d d0 = _mm512_shuffle_pd(_mm512_castps_pd(res0), _mm512_castps_pd(res1), 0b00000000); __m512d d1 = _mm512_shuffle_pd(_mm512_castps_pd(res0), _mm512_castps_pd(res1), 0b11111111); __m512d d2 = _mm512_shuffle_pd(_mm512_castps_pd(res2), _mm512_castps_pd(res3), 0b00000000); __m512d d3 = _mm512_shuffle_pd(_mm512_castps_pd(res2), _mm512_castps_pd(res3), 0b11111111); +#if UNWRAP_CNT > 1 + __m512d d4 = _mm512_shuffle_pd(_mm512_castps_pd(res4), _mm512_castps_pd(res5), 0b00000000); + __m512d d5 = _mm512_shuffle_pd(_mm512_castps_pd(res4), _mm512_castps_pd(res5), 0b11111111); + __m512d d6 = _mm512_shuffle_pd(_mm512_castps_pd(res6), _mm512_castps_pd(res7), 0b00000000); + __m512d d7 = _mm512_shuffle_pd(_mm512_castps_pd(res6), _mm512_castps_pd(res7), 0b11111111); +#if UNWRAP_CNT > 2 + __m512d d8 = _mm512_shuffle_pd(_mm512_castps_pd(res8), _mm512_castps_pd(res9), 0b00000000); + __m512d d9 = _mm512_shuffle_pd(_mm512_castps_pd(res8), _mm512_castps_pd(res9), 0b11111111); + __m512d dA = _mm512_shuffle_pd(_mm512_castps_pd(resA), _mm512_castps_pd(resB), 0b00000000); + __m512d dB = _mm512_shuffle_pd(_mm512_castps_pd(resA), _mm512_castps_pd(resB), 0b11111111); +#if UNWRAP_CNT > 3 + __m512d dC = _mm512_shuffle_pd(_mm512_castps_pd(resC), _mm512_castps_pd(resD), 0b00000000); + __m512d dD = _mm512_shuffle_pd(_mm512_castps_pd(resC), _mm512_castps_pd(resD), 0b11111111); + __m512d dE = _mm512_shuffle_pd(_mm512_castps_pd(resE), _mm512_castps_pd(resF), 0b00000000); + __m512d dF = _mm512_shuffle_pd(_mm512_castps_pd(resE), _mm512_castps_pd(resF), 0b11111111); +#endif +#endif +#endif _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(d0, idx0, d2)); _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(d1, idx0, d3)); @@ -53,6 +117,41 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, outdata_1 += 16; outdata_2 += 16; outdata_3 += 16; + +#if UNWRAP_CNT > 1 + _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(d4, idx0, d6)); + _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(d5, idx0, d7)); + _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(d4, idx1, d6)); + _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(d5, idx1, d7)); + + outdata_0 += 16; + outdata_1 += 16; + outdata_2 += 16; + outdata_3 += 16; + +#if UNWRAP_CNT > 2 + _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(d8, idx0, dA)); + _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(d9, idx0, dB)); + _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(d8, idx1, dA)); + _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(d9, idx1, dB)); + + outdata_0 += 16; + outdata_1 += 16; + outdata_2 += 16; + outdata_3 += 16; +#if UNWRAP_CNT > 3 + _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(dC, idx0, dE)); + _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(dD, idx0, dF)); + _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(dC, idx1, dE)); + _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(dD, idx1, dF)); + + outdata_0 += 16; + outdata_1 += 16; + outdata_2 += 16; + outdata_3 += 16; +#endif +#endif +#endif } #undef CONVERT_I12_F32_BLOCK From faf23065325f2293855fbddcdaee05e990b9e4d5 Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Fri, 31 Oct 2025 16:42:08 +0400 Subject: [PATCH 216/397] Hyper v2 support. --- src/lib/device/m2_dsdr/CMakeLists.txt | 2 +- src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml | 396 +++++++++++++++++++++++ 2 files changed, 397 insertions(+), 1 deletion(-) create mode 100644 src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml diff --git a/src/lib/device/m2_dsdr/CMakeLists.txt b/src/lib/device/m2_dsdr/CMakeLists.txt index af1170b1..5a1d8fe1 100644 --- a/src/lib/device/m2_dsdr/CMakeLists.txt +++ b/src/lib/device/m2_dsdr/CMakeLists.txt @@ -6,7 +6,7 @@ set(USDR_DSDR_LIB_FILES ${CMAKE_CURRENT_SOURCE_DIR}/dsdr_hiper.c ) -set(HW_FILES m2_dsdr_e m2_dsdr_p m2_dsdr_usr) +set(HW_FILES m2_dsdr_e m2_dsdr_e_v2 m2_dsdr_p m2_dsdr_usr) foreach(I ${HW_FILES}) message(STATUS "Generating header for ${I}") GENERATE_YAML_H(${CMAKE_CURRENT_SOURCE_DIR}/${I}.yaml ${CMAKE_CURRENT_BINARY_DIR}/def_${I}.h) diff --git a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml new file mode 100644 index 00000000..68e576c4 --- /dev/null +++ b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml @@ -0,0 +1,396 @@ +# Copyright (c) 2023-2024 Wavelet Lab +# SPDX-License-Identifier: MIT + +# Register desc and visual map +name: M2_DSDR_V2 +desc: Hiper board control +revision: "0.0.1" +processors: [ c ] +bus: + type: VIRTUAL + usdr_path: /debug/hw/dsdr_hiper_exp/0/reg + wr_mask: 0x80000000 +addr_width: 8 +data_width: 24 +# page_prefix: True +field_prefix: [ RegName ] +field_macros: True + +x-rx-filt-in-opts: &rx-filt-in-opts + 0b000: MUTE0 + 0b011: 400_1000M + 0b010: 1000_2000M + 0b001: 2000_3500M + 0b101: 2500_5000M + 0b100: 3500_7100M + 0b110: MUTE1 + 0b111: MUTE2 + + +x-rx-filt-out-opts: &rx-filt-out-opts + 0b000: MUTE0 + 0b011: 400_1000M + 0b100: 1000_2000M + 0b101: 2000_3500M + 0b001: 2500_5000M + 0b010: 3500_7100M + 0b110: MUTE1 + 0b111: MUTE2 + + +x-if-lna-opts: &if-lna-opts + 0b00: LNA + 0b01: Disable + 0b10: BYPASS + 0b11: BYPASS2 + + +x-r2rx-in-opts: &r2rx-in-opts + 0b00: DISABLE + 0b01: RX_HI + 0b10: RX_LOW + 0b11: RX_BYPASS + + +x-r2rx-out-opts: &r2rx-out-opts + 0b00: DISABLE + 0b01: RX_LOW + 0b10: RX_HI + 0b11: RX_BYPASS + + +pages: + - name: V0 + regs: +# + - addr: 0x20 + name: SW_RX_FILTER + fields: +# +# RX filters switching +# ---IN--- ---OUT-- +# V3 V2 V1 V3 V2 V1 +# --+--+-- --+--+-- +# 0 1 1 0 1 1 = 0.4 - 1.0 GHz +# 0 1 0 1 0 0 = 1.0 - 2.0 GHz +# 0 0 1 1 0 1 = 2.0 - 3.5 GHz +# 1 0 1 0 0 1 = 2.5 - 5.0 GHz +# 1 0 0 0 1 0 = 3.5 - 7.0 GHz +# + - bits: "8,23,22" + name: IN_CHA + desc: RX IN filters switch for Channel A + opts: *rx-filt-in-opts +# + - bits: "15,6,7" + name: OUT_CHA + desc: RX OUT filters switch for Channel A + opts: *rx-filt-out-opts +# + - bits: "9,21,20" + name: IN_CHB + desc: RX IN filters switch for Channel B + opts: *rx-filt-in-opts +# + - bits: "14,4,5" + name: OUT_CHB + desc: RX OUT filters switch for Channel B + opts: *rx-filt-out-opts +# + - bits: "10,19,18" + name: IN_CHC + desc: RX IN filters switch for Channel C + opts: *rx-filt-in-opts +# + - bits: "13,3,2" + name: OUT_CHC + desc: RX OUT filters switch for Channel C + opts: *rx-filt-out-opts +# + - bits: "11,17,16" + name: IN_CHD + desc: RX IN filters switch for Channel D + opts: *rx-filt-in-opts +# + - bits: "12,0,1" + name: OUT_CHD + desc: RX OUT filters switch for Channel D + opts: *rx-filt-out-opts +# + - addr: 0x21 + name: IF_LNA + fields: + - bits: "7:6" + name: CTRL_CHD + desc: IF LNA control mask for Channel D + opts: *if-lna-opts +# + - bits: "5:4" + name: CTRL_CHC + desc: IF LNA control mask for Channel C + opts: *if-lna-opts +# + - bits: "3:2" + name: CTRL_CHB + desc: IF LNA control mask for Channel B + opts: *if-lna-opts +# + - bits: "1:0" + name: CTRL_CHA + desc: IF LNA control mask for Channel A + opts: *if-lna-opts +# +# 0x22 and 0x23 for HB rev 1 +# - addr: 0x22 +# name: SW_OUT +# fields: +## +# - bits: "6" +# name: RX_H_CHA_R2D_V1 +# desc: Channel A RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) +# - bits: "7" +# name: RX_H_CHB_R2D_V2 +# desc: Channel B RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) +# - bits: "4" +# name: RX_H_CHC_R2C_V1 +# desc: Channel C RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) +# - bits: "5" +# name: RX_H_CHD_R2C_V2 +# desc: Channel D RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) +# - bits: "3" +# name: TX_L_CHA +# desc: Channel A TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# - bits: "2" +# name: TX_L_CHB +# desc: Channel B TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# - bits: "1" +# name: TX_L_CHC +# desc: Channel C TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# - bits: "0" +# name: TX_L_CHD +# desc: Channel D TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# +# - addr: 0x23 +# name: SW_IN +# fields: +## +# - bits: "0" +# name: RX_L_CHA_R2B_V1 +# desc: Channel A RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# - bits: "1" +# name: RX_L_CHB_R2B_V2 +# desc: Channel B RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# - bits: "2" +# name: RX_L_CHC_R2A_V1 +# desc: Channel C RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# - bits: "3" +# name: RX_L_CHD_R2A_V2 +# desc: Channel D RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) +# - bits: "4" +# name: TX_H_CHA +# desc: Channel A TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) +# - bits: "5" +# name: TX_H_CHB +# desc: Channel B TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) +# - bits: "6" +# name: TX_H_CHC +# desc: Channel C TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) +# - bits: "7" +# name: TX_H_CHD +# desc: Channel D TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) + +# +# 0x22 and 0x23 for HB rev 2 + - addr: 0x22 + name: SW_OUT_RX_CD + fields: + - bits: "0" + name: OUT_TX_CHD + desc: OUT_TX_CHD + - bits: "1" + name: OUT_TX_CHC + desc: OUT_TX_CHC + - bits: "2" + name: OUT_TX_CHB + desc: OUT_TX_CHB + - bits: "3" + name: OUT_TX_CHA + desc: OUT_TX_CHA + - bits: "5:4" + name: OUT_RX_CHC + desc: CHC + opts: *r2rx-out-opts + - bits: "7:6" + name: OUT_RX_CHD + desc: CHD + opts: *r2rx-out-opts +# + - addr: 0x23 + name: SW_OUT_RX_AB + fields: + - bits: "1:0" + name: OUT_RX_CHB + desc: CHA + opts: *r2rx-out-opts + - bits: "3:2" + name: OUT_RX_CHA + desc: CHB + opts: *r2rx-out-opts + - bits: "4" + name: IN_TX_CHA + desc: IN_TX_CHA + - bits: "5" + name: IN_TX_CHB + desc: IN_TX_CHB + - bits: "6" + name: IN_TX_CHC + desc: IN_TX_CHC + - bits: "7" + name: IN_TX_CHD + desc: IN_TX_CHC + + - addr: 0x24 + name: ENABLE + fields: + - bits: "7" + name: REV2_P5V + desc: Rev2 Enable +5v power for (IF Amplifier) + - bits: "6" + name: REV2_P5V_EXTLO + desc: Rev2 Eanble +5v power for EXT_LO clock distributor + - bits: "5" + name: REV2_PG_6P0 + desc: PG signal for 6P0 line + - bits: "4" + name: REV2_PG_8P0 + desc: PG signal for 8P0 line + - bits: "3" + name: REF_OSC + desc: Enable 25MHz reference clock oscillator + - bits: "2" + name: REF_GPS + desc: Enable GPS module + - bits: "1" + name: P8V_TX + desc: Enable +8v power supply for TX amps + - bits: "0" + name: P5V_RX + desc: Enable +5v power supply for RX amps, Rev2 Enable 6V rail +# + - addr: 0x25 + name: LMS8001_RESET + fields: + - bits: "6" + name: RX_CHCD_HIGH + desc: RX circuit LMS8001B reset (channels C and D, 2.5-7.1 GHz (HIGH) mode) + - bits: "5" + name: RX_CHCD_LOW + desc: RX circuit LMS8001A reset (channels C and D, 0.4-3.5 GHz (LOW) mode) + - bits: "4" + name: RX_CHAB_HIGH + desc: RX circuit LMS8001B reset (channels A and B, 2.5-7.1 GHz (HIGH) mode) + - bits: "3" + name: RX_CHAB_LOW + desc: RX circuit LMS8001A reset (channels A and B, 0.4-3.5 GHz (LOW) mode) + - bits: "2" + name: TX_CHAB + desc: TX circuit LMS8001B reset (channels A and B, 2.5-7.1 GHz (HIGH) mode) + - bits: "1" + name: TX_CHCD + desc: TX circuit LMS8001B reset (channels C and D, 2.5-7.1 GHz (HIGH) mode) + - bits: "0" + name: REV2_DCDC + desc: Reset pin for DCDC module + +# + - addr: 0x26 + name: AUX_CTRL + fields: + - bits: "7" + name: ABSLNA_PA_CHD + desc: 50 ohm absorptive LNA to PA switch selection, channel D + - bits: "6" + name: ABSLNA_PA_CHC + desc: 50 ohm absorptive LNA to PA switch selection, channel C + - bits: "5" + name: ABSLNA_PA_CHB + desc: 50 ohm absorptive LNA to PA switch selection, channel B + - bits: "4" + name: ABSLNA_PA_CHA + desc: 50 ohm absorptive LNA to PA switch selection, channel A + - bits: "3" + name: PA_BYPASS_D + desc: Rev0 FAN0 PWM input + - bits: "2" + name: PA_BYPASS_C + desc: Rev0 FAN0 tachometer output + - bits: "1" + name: PA_BYPASS_B + desc: Rev0 FAN1 PWM input + - bits: "0" + name: PA_BYPASS_A + desc: Rev0 FAN1 tachometer output +# + - addr: 0x27 + name: SW_IN_RX + fields: + - bits: "1:0" + name: CHA + desc: CHA + opts: *r2rx-in-opts + - bits: "3:2" + name: CHB + desc: CHB + opts: *r2rx-in-opts + - bits: "5:4" + name: CHC + desc: CHC + opts: *r2rx-in-opts + - bits: "7:6" + name: CHD + desc: CHD + opts: *r2rx-in-opts +# + - addr: 0x28 + name: LED_TRX_CTRL + fields: + - bits: "1:0" + name: LED_CHA + desc: LED CHA + - bits: "3:2" + name: LED_CHB + desc: LED CHB + - bits: "5:4" + name: LED_CHC + desc: LED CHC + - bits: "7:6" + name: LED_CHD + desc: LED CHD +# + - addr: 0x29 + name: LEDRX_CH_CTRL + fields: + - bits: "0" + name: EN_CHA + desc: Enable CHA + - bits: "1" + name: EN_CHB + desc: Enable CHB + - bits: "2" + name: EN_CHC + desc: Enable CHC + - bits: "3" + name: EN_CHD + desc: Enable CHD + - bits: "4" + name: LED_CHA + desc: LED CHA + - bits: "5" + name: LED_CHB + desc: LED CHB + - bits: "6" + name: LED_CHC + desc: LED CHC + - bits: "7" + name: LED_CHD + desc: LED CHD From 066cd1418fe5851ae2501315dee6369469cdd114 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 31 Oct 2025 16:50:12 +0400 Subject: [PATCH 217/397] hiper_v2: add exp_v2 commands --- src/lib/device/m2_dsdr/dsdr_hiper.c | 11 +++++++++++ src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index a2460682..e31c81e0 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -227,6 +227,9 @@ static int dsdr_hiper_senslms4temp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 static int dsdr_hiper_senslms5temp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static const usdr_dev_param_func_t s_fe_parameters_v2[] = { + { "/debug/hw/dsdr_hiper_exp_v2/0/reg" , { dsdr_hiper_dsdr_hiper_exp_reg_set, dsdr_hiper_dsdr_hiper_exp_reg_get } }, +}; static const usdr_dev_param_func_t s_fe_parameters[] = { { "/debug/hw/lms8001/0/reg" , { dsdr_hiper_debug_lms8001_u1_reg_set, dsdr_hiper_debug_lms8001_u1_reg_get }}, @@ -910,6 +913,14 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8a_chip (void*)dfe, s_fe_parameters, SIZEOF_ARRAY(s_fe_parameters)); + + if (dfe->rev == HIPER_REV2) { + res = res ? res : usdr_vfs_obj_param_init_array_param(base, + (void*)dfe, + s_fe_parameters_v2, + SIZEOF_ARRAY(s_fe_parameters_v2)); + } + if (res) return res; diff --git a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml index 68e576c4..c89abc11 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml @@ -8,7 +8,7 @@ revision: "0.0.1" processors: [ c ] bus: type: VIRTUAL - usdr_path: /debug/hw/dsdr_hiper_exp/0/reg + usdr_path: /debug/hw/dsdr_hiper_exp_v2/0/reg wr_mask: 0x80000000 addr_width: 8 data_width: 24 From f0182d71cc1c9a378962a050d875947197cc6f2e Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 31 Oct 2025 17:08:12 +0300 Subject: [PATCH 218/397] ci12_4cf32 optimized (AVX2) --- src/lib/xdsp/conv_ci12_4cf32_2.c | 1 + src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t | 102 ------------------ src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t | 55 ++++++++-- src/lib/xdsp/templates/conv_i12_f32_avx2.inc | 21 +++- src/lib/xdsp/templates/conv_i12_i16_avx2.inc | 56 +++++++++- 5 files changed, 117 insertions(+), 118 deletions(-) diff --git a/src/lib/xdsp/conv_ci12_4cf32_2.c b/src/lib/xdsp/conv_ci12_4cf32_2.c index b51688e8..bc85ee10 100644 --- a/src/lib/xdsp/conv_ci12_4cf32_2.c +++ b/src/lib/xdsp/conv_ci12_4cf32_2.c @@ -5,6 +5,7 @@ #include "attribute_switch.h" #define CONV_SCALE (1.0f/32767) +#define SCALE2 (CONV_SCALE / 65536) #define TEMPLATE_FUNC_NAME conv_ci12_4cf32_generic VWLT_ATTRIBUTE(optimize("-O3")) diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t index ab39419f..46f7bf44 100644 --- a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t @@ -14,8 +14,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, float* outdata_0 = (float*)outdata_0_p; float* outdata_1 = (float*)outdata_1_p; -#if 1 - #include "conv_i12_i16_avx2.inc" #include "conv_i12_f32_avx2.inc" @@ -53,106 +51,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, #undef CONVERT_CI12_2CF32_BLOCK_OPT #undef CONVERT_CI12_2CI16_BLOCK_OPT -#else - - const __m256 scale = _mm256_set1_ps(CONV_SCALE); - const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); - - const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); - const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); - - const __m256i permmask = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); - const __m256i shfl = _mm256_set_epi8( - 0x0f, 0x0e, 0x0d, 0x80, 0x09, 0x08, 0x07, 0x80, - 0x0c, 0x0b, 0x0a, 0x80, 0x06, 0x05, 0x04, 0x80, - 0x0b, 0x0a, 0x09, 0x80, 0x05, 0x04, 0x03, 0x80, - 0x08, 0x07, 0x06, 0x80, 0x02, 0x01, 0x00, 0x80); - -/* -* reg: -* | (3) | (2) | (1) | (0) | -* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -* | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | -* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ -* | 0 0 0 0 0 0 0 0 | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | -* -* v0: -* | | | | | -* | f15 | f14 | f13 | f12 | f11 | f10 | f9 | f8 | 0 0 0 0 0 0 0 0 | f7 | f6 | f5 | f4 | f3 | f2 | f1 | f0 | -* r: -* | | | | | -* | f15 | f14 | 0 | f11 | f10 | 0 | f13 | f12 | 0 | f9 | f8 | 0 | f7 | f6 | 0 | f3 | f2 | 0 | f5 | f4 | 0 | f1 | f0 | 0 | -* | f15 | f14 | 0 | f11 | f10 | 0 | f7 | f6 | 0 | f3 | f2 | 0 | f13 | f12 | 0 | f9 | f8 | 0 | f5 | f4 | 0 | f1 | f0 | 0 | -* r0: -* | | | | | -* | f15 |0| 00 00 | f11 |0| 00 00 | f7 |0| 00 00 | f3 |0| 00 00 | f13 |0| 00 00 | f9 |0| 00 00 | f5 |0| 00 00 | f1 |0| 00 00 | - r1: -* | | | | | -* | 00 00 | f14 |0| 00 00 | f10 |0| 00 00 | f6 |0| 00 00 | f2 |0| 00 00 | f12 |0| 00 00 | f8 |0| 00 00 | f4 |0| 00 00 | f0 |0| -* result: -* | | | | | -* | f15 |0| f14 |0| f11 |0| f10 |0| f7 |0| f6 |0| f3 |0| f2 |0| f13 |0| f12 |0| f9 |0| f8 |0| f5 |0| f4 |0| f1 |0| f0 |0| -*/ - -#define CONVERT_I12_F32_BLOCK(reg) \ - { \ - __m256i v0 = _mm256_permutevar8x32_epi32(reg, permmask); \ - __m256i r = _mm256_shuffle_epi8(v0, shfl); \ - r = _mm256_permute4x64_epi64(r, _MM_SHUFFLE(3, 1, 2, 0)); \ - \ - __m256i r0 = _mm256_and_si256(r, mask0); \ - __m256i r1 = _mm256_and_si256(_mm256_srli_epi64(r, 4), mask1); \ - __m256i result = _mm256_or_si256(r0, r1); \ - \ - __m256i d0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(result)); \ - __m256i d1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(result, 1)); \ - \ - __m256 f0 = _mm256_cvtepi32_ps(d0); /* 4 1|2 */ \ - __m256 f1 = _mm256_cvtepi32_ps(d1); /* 4 1|2 */ \ - \ - f0 = _mm256_mul_ps(f0, scale); /* 4 1|2 */ \ - f1 = _mm256_mul_ps(f1, scale); /* 4 1|2 */ \ - \ - _MM256_STOREX_PS(outdata_0, f0); outdata_0 += 8; /* 1 1|2 */ \ - _MM256_STOREX_PS(outdata_1, f1); outdata_1 += 8; /* 1 1|2 */ \ - } -// CONVERT_I12_F32_BLOCK end lat 40 - - __m256i y0, y1, y2, y3; - - if(i >= 96) - { - y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); // 8 1/3 - y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); // 8 1/3 - y2 = _mm256_maskload_epi64((const long long*)(in + 6), load_mask); // 8 1/3 - y3 = _mm256_maskload_epi64((const long long*)(in + 9), load_mask); // 8 1/3 - in += 12; - - for (; i >= 2*96; i -= 96) - { - CONVERT_I12_F32_BLOCK(y0); - CONVERT_I12_F32_BLOCK(y1); - CONVERT_I12_F32_BLOCK(y2); - CONVERT_I12_F32_BLOCK(y3); - - y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); // 8 1/3 - y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); // 8 1/3 - y2 = _mm256_maskload_epi64((const long long*)(in + 6), load_mask); // 8 1/3 - y3 = _mm256_maskload_epi64((const long long*)(in + 9), load_mask); // 8 1/3 - in += 12; - } - - i -= 96; - - CONVERT_I12_F32_BLOCK(y0); - CONVERT_I12_F32_BLOCK(y1); - CONVERT_I12_F32_BLOCK(y2); - CONVERT_I12_F32_BLOCK(y3); - } - -#undef CONVERT_I12_F32_BLOCK -#endif - const uint8_t *indata = (const uint8_t*)in; #include "conv_ci12_2cf32_generic.inc" } diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t index f59b60d8..8ecfc464 100644 --- a/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t @@ -19,23 +19,62 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, const uint64_t *in = (const uint64_t*)indata_p; - #include "conv_ci12_4cf32_avx2.inc" + #include "conv_i12_i16_avx2.inc" + #include "conv_i12_f32_avx2.inc" - __m256i r0, r1; + while(i >= 96) + { + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + __m256i y2 = _mm256_maskload_epi64((const long long*)(in + 6), load_mask); + __m256i y3 = _mm256_maskload_epi64((const long long*)(in + 9), load_mask); + + __m256 f0, f1, f2, f3, f4, f5, f6, f7; + + CONVERT_CI12_4CF32_BLOCK_OPT(y0, y1, f0, f1, f2, f3); + _mm256_store_ps(outdata_0 + 0, f0); + _mm256_store_ps(outdata_1 + 0, f1); + _mm256_store_ps(outdata_2 + 0, f2); + _mm256_store_ps(outdata_3 + 0, f3); + + CONVERT_CI12_4CF32_BLOCK_OPT(y2, y3, f4, f5, f6, f7); + _mm256_store_ps(outdata_0 + 8, f4); + _mm256_store_ps(outdata_1 + 8, f5); + _mm256_store_ps(outdata_2 + 8, f6); + _mm256_store_ps(outdata_3 + 8, f7); + + outdata_0 += 16; + outdata_1 += 16; + outdata_2 += 16; + outdata_3 += 16; + + in += 12; + i -= 96; + } while(i >= 48) { - r0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); - r1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); - in += 6; + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + + __m256 f0, f1, f2, f3; + + CONVERT_CI12_4CF32_BLOCK_OPT(y0, y1, f0, f1, f2, f3); - CONVERT_CI12_4F32_BLOCK(r0, r1); + _mm256_store_ps(outdata_0 + 0, f0); + _mm256_store_ps(outdata_1 + 0, f1); + _mm256_store_ps(outdata_2 + 0, f2); + _mm256_store_ps(outdata_3 + 0, f3); + outdata_0 += 8; + outdata_1 += 8; + outdata_2 += 8; + outdata_3 += 8; + + in += 6; i -= 48; } - #undef CONVERT_CI12_4F32_BLOCK - const uint8_t *indata = (const uint8_t*)in; #include "conv_ci12_4cf32_generic.inc" } diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx2.inc b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc index c9aac901..bc1dd99e 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx2.inc +++ b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc @@ -31,6 +31,9 @@ const __m256 scale2 = _mm256_set1_ps(SCALE2); * | f15 |0| 00 00 | f13 |0| 00 00 | f11 |0| 00 00 | f9 |0| 00 00 | f7 |0| 00 00 | f5 |0| 00 00 | f3 |0| 00 00 | f1 |0| 00 00 | +f14 f12 f10 f8 | f6 f4 f2 f0 after 12-16 conv +f15 f13 f11 f9 | f7 f5 f3 f1 + f11 f10 f9 f8 | f3 f2 f1 f0 unpack f15 f14 f13 f12 | f7 f6 f5 f4 @@ -66,11 +69,19 @@ f15 f14 f11 f10 | f7 f6 f3 f2 #define CONVERT_CI12_2CF32_BLOCK_OPT(reg, res0, res1) \ { \ __m256i result0, result1; \ - CONVERT_CI12_2CI16_BLOCK_OPT(reg, result0, result1); \ + CONVERT_CI12_2CI32_BLOCK_OPT(reg, result0, result1); \ \ - res0 = _mm256_cvtepi32_ps(result0); \ - res1 = _mm256_cvtepi32_ps(result1); \ + res0 = _mm256_mul_ps(_mm256_cvtepi32_ps(result0), scale2); \ + res1 = _mm256_mul_ps(_mm256_cvtepi32_ps(result1), scale2); \ +} + +#define CONVERT_CI12_4CF32_BLOCK_OPT(reg0, reg1, res0, res1, res2, res3) \ +{ \ + __m256i r0, r1, r2, r3; \ + CONVERT_CI12_4CI32_BLOCK_OPT(reg0, reg1, r0, r1, r2, r3); \ \ - res0 = _mm256_mul_ps(res0, scale2); \ - res1 = _mm256_mul_ps(res1, scale2); \ + res0 = _mm256_mul_ps(_mm256_cvtepi32_ps(r0), scale2); \ + res1 = _mm256_mul_ps(_mm256_cvtepi32_ps(r1), scale2); \ + res2 = _mm256_mul_ps(_mm256_cvtepi32_ps(r2), scale2); \ + res3 = _mm256_mul_ps(_mm256_cvtepi32_ps(r3), scale2); \ } diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx2.inc b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc index fc77ff07..5828ae1a 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx2.inc +++ b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc @@ -20,16 +20,66 @@ const __m256i shfl = _mm256_set_epi8( result = _mm256_or_si256(r0, r1); \ } -#define CONVERT_CI12_2CI16_BLOCK_OPT(reg, res0, res1) \ +/* +* input (i12): |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +* +* output(i32): |14 xx|12 xx|10 xx| 8 xx| 6 xx| 4 xx| 2 xx| 0 xx| + (hi word) |15 xx|13 xx|11 xx| 9 xx| 7 xx| 5 xx| 3 xx| 1 xx| - 2CH i32 interleave +*/ +#define CONVERT_I12_2I32_SEPARATED(reg, res0, res1) \ { \ __m256i v0 = _mm256_permutevar8x32_epi32(reg, permmask); \ __m256i r = _mm256_shuffle_epi8(v0, shfl); \ \ - __m256i a1 = _mm256_and_si256(r, mask0); \ - __m256i a0 = _mm256_and_si256(_mm256_slli_epi64(r, 12), mask0); \ + res1 = _mm256_and_si256(r, mask0); \ + res0 = _mm256_and_si256(_mm256_slli_epi64(r, 12), mask0); \ +} + +/* +* input (ci12): |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +* +* output(ci32): |13 xx|12 xx| 9 xx| 8 xx| 5 xx| 4 xx| 1 xx| 0 xx| + (hi word) |15 xx|14 xx|11 xx|10 xx| 7 xx| 6 xx| 3 xx| 2 xx| - 2CH ci32 interleave +*/ +#define CONVERT_CI12_2CI32_BLOCK_OPT(reg, res0, res1) \ +{ \ + __m256i a0, a1; \ + CONVERT_I12_2I32_SEPARATED(reg, a0, a1); \ \ __m256i b0 = _mm256_unpacklo_epi32(a0, a1); \ __m256i b1 = _mm256_unpackhi_epi32(a0, a1); \ res0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b0), _mm256_castsi256_pd(b1), 0b0000)); \ res1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b0), _mm256_castsi256_pd(b1), 0b1111)); \ } + +/* +* input (ci12): |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +* |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16| +* +* output(ci32): |25 xx|24 xx|17 xx|16 xx| 9 xx| 8 xx| 1 xx| 0 xx| + (hi word) |27 xx|26 xx|19 xx|18 xx|11 xx|10 xx| 3 xx| 2 xx| + (hi word) |29 xx|28 xx|21 xx|20 xx|13 xx|12 xx| 5 xx| 4 xx| + (hi word) |31 xx|30 xx|23 xx|22 xx|15 xx|14 xx| 7 xx| 6 xx| - 4CH ci32 interleave +*/ +#define CONVERT_CI12_4CI32_BLOCK_OPT(reg0, reg1, res0, res1, res2, res3) \ +{ \ + __m256i a0, a1, a2, a3; \ + CONVERT_I12_2I32_SEPARATED(reg0, a0, a1); \ + CONVERT_I12_2I32_SEPARATED(reg1, a2, a3); \ + \ + __m256i b0 = _mm256_unpacklo_epi32(a0, a1); \ + __m256i b1 = _mm256_unpackhi_epi32(a0, a1); \ + __m256i b2 = _mm256_unpacklo_epi32(a2, a3); \ + __m256i b3 = _mm256_unpackhi_epi32(a2, a3); \ + \ + __m256i c0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b0), _mm256_castsi256_pd(b2), 0b0000)); \ + __m256i c1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b0), _mm256_castsi256_pd(b2), 0b1111)); \ + __m256i c2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b1), _mm256_castsi256_pd(b3), 0b0000)); \ + __m256i c3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(b1), _mm256_castsi256_pd(b3), 0b1111)); \ + \ + res0 = _mm256_permute4x64_epi64(c0, _MM_SHUFFLE(3,1,2,0)); \ + res1 = _mm256_permute4x64_epi64(c1, _MM_SHUFFLE(3,1,2,0)); \ + res2 = _mm256_permute4x64_epi64(c2, _MM_SHUFFLE(3,1,2,0)); \ + res3 = _mm256_permute4x64_epi64(c3, _MM_SHUFFLE(3,1,2,0)); \ +} + From c68036ffadd34a31fc0cf2766923746af61acea5 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 31 Oct 2025 19:40:16 +0300 Subject: [PATCH 219/397] ci12_2f32 & 4f32 optims for AVX512 --- src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t | 11 +- .../xdsp/templates/conv_ci12_2cf32_avx512bw.t | 50 ++++--- .../xdsp/templates/conv_ci12_2ci16_avx512bw.t | 6 + src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t | 12 +- .../xdsp/templates/conv_ci12_4cf32_avx512bw.t | 124 +++++++++--------- .../xdsp/templates/conv_ci12_4ci16_avx512bw.t | 7 +- src/lib/xdsp/templates/conv_i12_f32_avx2.t | 8 +- .../xdsp/templates/conv_i12_f32_avx512bw.inc | 21 +++ .../xdsp/templates/conv_i12_f32_avx512bw.t | 17 ++- src/lib/xdsp/templates/conv_i12_i16_avx2.t | 3 + .../xdsp/templates/conv_i12_i16_avx512bw.inc | 44 +++++++ .../xdsp/templates/conv_i12_i16_avx512bw.t | 6 + 12 files changed, 221 insertions(+), 88 deletions(-) diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t index 46f7bf44..66881792 100644 --- a/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_avx2.t @@ -48,8 +48,15 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, outdata_1 += 32; } - #undef CONVERT_CI12_2CF32_BLOCK_OPT - #undef CONVERT_CI12_2CI16_BLOCK_OPT + #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT const uint8_t *indata = (const uint8_t*)in; #include "conv_ci12_2cf32_generic.inc" diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t index cf0209ab..3a7ca0b8 100644 --- a/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t @@ -30,20 +30,28 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); y1 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 6)); in += 12; - - CONVERT_I12_F32_BLOCK(y0, res0, res1); - CONVERT_I12_F32_BLOCK(y1, res2, res3); - - _mm512_storeu_pd(outdata_0 + 0, _mm512_permutex2var_pd(_mm512_castps_pd(res0), idx0, _mm512_castps_pd(res1))); - _mm512_storeu_pd(outdata_1 + 0, _mm512_permutex2var_pd(_mm512_castps_pd(res0), idx1, _mm512_castps_pd(res1))); - _mm512_storeu_pd(outdata_0 + 16, _mm512_permutex2var_pd(_mm512_castps_pd(res2), idx0, _mm512_castps_pd(res3))); - _mm512_storeu_pd(outdata_1 + 16, _mm512_permutex2var_pd(_mm512_castps_pd(res2), idx1, _mm512_castps_pd(res3))); + + CONVERT_CI12_2CF32_BLOCK_OPT(y0, res0, res1); + _mm512_store_ps(outdata_0 + 0, res0); + _mm512_store_ps(outdata_1 + 0, res1); + + CONVERT_CI12_2CF32_BLOCK_OPT(y1, res2, res3); + _mm512_store_ps(outdata_0 + 16, res2); + _mm512_store_ps(outdata_1 + 16, res3); + outdata_0 += 32; outdata_1 += 32; } - #undef CONVERT_I12_F32_BLOCK #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT } //AVX2 block @@ -60,23 +68,27 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, __m256 res0, res1, res2, res3; - CONVERT_I12_F32_BLOCK(y0, res0, res1); - CONVERT_I12_F32_BLOCK(y1, res2, res3); - - const __m256i idx0 = _mm256_set_epi64x(6,4,2,0); - const __m256i idx1 = _mm256_set_epi64x(7,5,3,1); + CONVERT_CI12_2CF32_BLOCK_OPT(y0, res0, res1); + _mm256_store_ps(outdata_0 + 0, res0); + _mm256_store_ps(outdata_1 + 0, res1); + + CONVERT_CI12_2CF32_BLOCK_OPT(y1, res2, res3); + _mm256_store_ps(outdata_0 + 8, res2); + _mm256_store_ps(outdata_1 + 8, res3); - _mm256_storeu_pd((double*)(outdata_0 + 0), _mm256_permutex2var_pd(_mm256_castps_pd(res0), idx0, _mm256_castps_pd(res1))); - _mm256_storeu_pd((double*)(outdata_1 + 0), _mm256_permutex2var_pd(_mm256_castps_pd(res0), idx1, _mm256_castps_pd(res1))); - _mm256_storeu_pd((double*)(outdata_0 + 8), _mm256_permutex2var_pd(_mm256_castps_pd(res2), idx0, _mm256_castps_pd(res3))); - _mm256_storeu_pd((double*)(outdata_1 + 8), _mm256_permutex2var_pd(_mm256_castps_pd(res2), idx1, _mm256_castps_pd(res3))); outdata_0 += 16; outdata_1 += 16; } + #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT + #undef CONVERT_I12_F32_BLOCK #undef CONVERT_I12_F32_BLOCK_STORE1 - #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT } //Generic block diff --git a/src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t index 96681f8c..d4e152c6 100644 --- a/src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t +++ b/src/lib/xdsp/templates/conv_ci12_2ci16_avx512bw.t @@ -40,6 +40,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT } //AVX2 block @@ -68,6 +71,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT } //Generic block diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t index 8ecfc464..fd3323de 100644 --- a/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_avx2.t @@ -52,7 +52,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, i -= 96; } - while(i >= 48) + if(i >= 48) { __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); @@ -74,6 +74,16 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, in += 6; i -= 48; } + + #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT const uint8_t *indata = (const uint8_t*)in; #include "conv_ci12_4cf32_generic.inc" diff --git a/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t index 077856c4..8a84d58a 100644 --- a/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t +++ b/src/lib/xdsp/templates/conv_ci12_4cf32_avx512bw.t @@ -34,23 +34,20 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, #include "conv_i12_f32_avx512bw.inc" __m512i y0, y1; - __m512 res0, res1, res2, res3; + __m512 f0, f1, f2, f3; #if UNWRAP_CNT > 1 __m512i y2, y3; - __m512 res4, res5, res6, res7; + __m512 f4, f5, f6, f7; #if UNWRAP_CNT > 2 __m512i y4, y5; - __m512 res8, res9, resA, resB; + __m512 f8, f9, fA, fB; #if UNWRAP_CNT > 3 __m512i y6, y7; - __m512 resC, resD, resE, resF; + __m512 fC, fD, fE, fF; #endif #endif #endif - const __m512i idx0 = _mm512_set_epi64(13, 9,12, 8,5,1,4,0); - const __m512i idx1 = _mm512_set_epi64(15,11,14,10,7,3,6,2); - for(; i >= 96 * UNWRAP_CNT; i -= 96 * UNWRAP_CNT) { y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); @@ -70,48 +67,21 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, in += UNWRAP_CNT * 12; - CONVERT_I12_F32_BLOCK(y0, res0, res1); - CONVERT_I12_F32_BLOCK(y1, res2, res3); -#if UNWRAP_CNT > 1 - CONVERT_I12_F32_BLOCK(y2, res4, res5); - CONVERT_I12_F32_BLOCK(y3, res6, res7); -#if UNWRAP_CNT > 2 - CONVERT_I12_F32_BLOCK(y4, res8, res9); - CONVERT_I12_F32_BLOCK(y5, resA, resB); -#if UNWRAP_CNT > 3 - CONVERT_I12_F32_BLOCK(y6, resC, resD); - CONVERT_I12_F32_BLOCK(y7, resE, resF); -#endif -#endif -#endif - - __m512d d0 = _mm512_shuffle_pd(_mm512_castps_pd(res0), _mm512_castps_pd(res1), 0b00000000); - __m512d d1 = _mm512_shuffle_pd(_mm512_castps_pd(res0), _mm512_castps_pd(res1), 0b11111111); - __m512d d2 = _mm512_shuffle_pd(_mm512_castps_pd(res2), _mm512_castps_pd(res3), 0b00000000); - __m512d d3 = _mm512_shuffle_pd(_mm512_castps_pd(res2), _mm512_castps_pd(res3), 0b11111111); + CONVERT_CI12_4CF32_BLOCK_OPT(y0, y1, f0, f1, f2, f3); #if UNWRAP_CNT > 1 - __m512d d4 = _mm512_shuffle_pd(_mm512_castps_pd(res4), _mm512_castps_pd(res5), 0b00000000); - __m512d d5 = _mm512_shuffle_pd(_mm512_castps_pd(res4), _mm512_castps_pd(res5), 0b11111111); - __m512d d6 = _mm512_shuffle_pd(_mm512_castps_pd(res6), _mm512_castps_pd(res7), 0b00000000); - __m512d d7 = _mm512_shuffle_pd(_mm512_castps_pd(res6), _mm512_castps_pd(res7), 0b11111111); + CONVERT_CI12_4CF32_BLOCK_OPT(y2, y3, f4, f5, f6, f7); #if UNWRAP_CNT > 2 - __m512d d8 = _mm512_shuffle_pd(_mm512_castps_pd(res8), _mm512_castps_pd(res9), 0b00000000); - __m512d d9 = _mm512_shuffle_pd(_mm512_castps_pd(res8), _mm512_castps_pd(res9), 0b11111111); - __m512d dA = _mm512_shuffle_pd(_mm512_castps_pd(resA), _mm512_castps_pd(resB), 0b00000000); - __m512d dB = _mm512_shuffle_pd(_mm512_castps_pd(resA), _mm512_castps_pd(resB), 0b11111111); + CONVERT_CI12_4CF32_BLOCK_OPT(y4, y5, f8, f9, fA, fB); #if UNWRAP_CNT > 3 - __m512d dC = _mm512_shuffle_pd(_mm512_castps_pd(resC), _mm512_castps_pd(resD), 0b00000000); - __m512d dD = _mm512_shuffle_pd(_mm512_castps_pd(resC), _mm512_castps_pd(resD), 0b11111111); - __m512d dE = _mm512_shuffle_pd(_mm512_castps_pd(resE), _mm512_castps_pd(resF), 0b00000000); - __m512d dF = _mm512_shuffle_pd(_mm512_castps_pd(resE), _mm512_castps_pd(resF), 0b11111111); + CONVERT_CI12_4CF32_BLOCK_OPT(y6, y7, fC, fD, fE, fF); #endif #endif #endif - _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(d0, idx0, d2)); - _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(d1, idx0, d3)); - _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(d0, idx1, d2)); - _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(d1, idx1, d3)); + _mm512_store_ps(outdata_0, f0); + _mm512_store_ps(outdata_1, f1); + _mm512_store_ps(outdata_2, f2); + _mm512_store_ps(outdata_3, f3); outdata_0 += 16; outdata_1 += 16; @@ -119,10 +89,10 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, outdata_3 += 16; #if UNWRAP_CNT > 1 - _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(d4, idx0, d6)); - _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(d5, idx0, d7)); - _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(d4, idx1, d6)); - _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(d5, idx1, d7)); + _mm512_store_ps(outdata_0, f4); + _mm512_store_ps(outdata_1, f5); + _mm512_store_ps(outdata_2, f6); + _mm512_store_ps(outdata_3, f7); outdata_0 += 16; outdata_1 += 16; @@ -130,20 +100,20 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, outdata_3 += 16; #if UNWRAP_CNT > 2 - _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(d8, idx0, dA)); - _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(d9, idx0, dB)); - _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(d8, idx1, dA)); - _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(d9, idx1, dB)); + _mm512_store_ps(outdata_0, f8); + _mm512_store_ps(outdata_1, f9); + _mm512_store_ps(outdata_2, fA); + _mm512_store_ps(outdata_3, fB); outdata_0 += 16; outdata_1 += 16; outdata_2 += 16; outdata_3 += 16; #if UNWRAP_CNT > 3 - _mm512_storeu_pd(outdata_0, _mm512_permutex2var_pd(dC, idx0, dE)); - _mm512_storeu_pd(outdata_1, _mm512_permutex2var_pd(dD, idx0, dF)); - _mm512_storeu_pd(outdata_2, _mm512_permutex2var_pd(dC, idx1, dE)); - _mm512_storeu_pd(outdata_3, _mm512_permutex2var_pd(dD, idx1, dF)); + _mm512_store_ps(outdata_0, fC); + _mm512_store_ps(outdata_1, fD); + _mm512_store_ps(outdata_2, fE); + _mm512_store_ps(outdata_3, fF); outdata_0 += 16; outdata_1 += 16; @@ -154,25 +124,55 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, #endif } - #undef CONVERT_I12_F32_BLOCK #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT } + //AVX2 block { - #include "conv_ci12_4cf32_avx2.inc" + #include "conv_i12_i16_avx2.inc" + #include "conv_i12_f32_avx2.inc" if(i >= 48) { - __m256i r0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); - __m256i r1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + __m256i y0 = _mm256_maskload_epi64((const long long*)(in + 0), load_mask); + __m256i y1 = _mm256_maskload_epi64((const long long*)(in + 3), load_mask); + + __m256 f0, f1, f2, f3; + + CONVERT_CI12_4CF32_BLOCK_OPT(y0, y1, f0, f1, f2, f3); + + _mm256_store_ps(outdata_0 + 0, f0); + _mm256_store_ps(outdata_1 + 0, f1); + _mm256_store_ps(outdata_2 + 0, f2); + _mm256_store_ps(outdata_3 + 0, f3); + + outdata_0 += 8; + outdata_1 += 8; + outdata_2 += 8; + outdata_3 += 8; + in += 6; i -= 48; - - CONVERT_CI12_4F32_BLOCK(r0, r1); } - - #undef CONVERT_CI12_4F32_BLOCK + + #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT + + #undef CONVERT_I12_F32_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT } //Generic block diff --git a/src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t index 1122a623..7f5e94ce 100644 --- a/src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t +++ b/src/lib/xdsp/templates/conv_ci12_4ci16_avx512bw.t @@ -66,6 +66,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT } //AVX2 block @@ -85,8 +88,10 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, STORE_CI12_4CI16_BLOCK(y0, y1, y2, y3); } - #undef STORE_CI12_4CI16_BLOCK #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT } //Generic block diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx2.t b/src/lib/xdsp/templates/conv_i12_f32_avx2.t index 2f2062cd..65a0a9e3 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx2.t +++ b/src/lib/xdsp/templates/conv_i12_f32_avx2.t @@ -47,9 +47,15 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, CONVERT_I12_F32_BLOCK_STORE1(y3); } +#undef CONVERT_I12_I16_BLOCK +#undef CONVERT_I12_2I32_SEPARATED +#undef CONVERT_CI12_2CI32_BLOCK_OPT +#undef CONVERT_CI12_4CI32_BLOCK_OPT + #undef CONVERT_I12_F32_BLOCK #undef CONVERT_I12_F32_BLOCK_STORE1 -#undef CONVERT_I12_I16_BLOCK +#undef CONVERT_CI12_2CF32_BLOCK_OPT +#undef CONVERT_CI12_4CF32_BLOCK_OPT const uint8_t *indata = (const uint8_t*)in; #include "conv_i12_f32_generic.inc" diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc index 47110ff0..f8178ac5 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc +++ b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc @@ -1,4 +1,5 @@ const __m512 scale = _mm512_set1_ps(CONV_SCALE); +const __m512 scale2 = _mm512_set1_ps(SCALE2); #define CONVERT_I12_F32_BLOCK(reg, res0, res1) \ { \ @@ -14,3 +15,23 @@ const __m512 scale = _mm512_set1_ps(CONV_SCALE); res0 = _mm512_mul_ps(res0, scale); \ res1 = _mm512_mul_ps(res1, scale); \ } + +#define CONVERT_CI12_2CF32_BLOCK_OPT(reg, res0, res1) \ +{ \ + __m512i result0, result1; \ + CONVERT_CI12_2CI32_BLOCK_OPT(reg, result0, result1); \ + \ + res0 = _mm512_mul_ps(_mm512_cvtepi32_ps(result0), scale2); \ + res1 = _mm512_mul_ps(_mm512_cvtepi32_ps(result1), scale2); \ +} + +#define CONVERT_CI12_4CF32_BLOCK_OPT(reg0, reg1, res0, res1, res2, res3) \ +{ \ + __m512i r0, r1, r2, r3; \ + CONVERT_CI12_4CI32_BLOCK_OPT(reg0, reg1, r0, r1, r2, r3); \ + \ + res0 = _mm512_mul_ps(_mm512_cvtepi32_ps(r0), scale2); \ + res1 = _mm512_mul_ps(_mm512_cvtepi32_ps(r1), scale2); \ + res2 = _mm512_mul_ps(_mm512_cvtepi32_ps(r2), scale2); \ + res3 = _mm512_mul_ps(_mm512_cvtepi32_ps(r3), scale2); \ +} diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.t b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.t index fb42d4bf..f47bd533 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.t +++ b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.t @@ -35,9 +35,16 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, _mm512_storeu_ps(outdata + 48, res3); outdata += 64; } + + #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT #undef CONVERT_I12_F32_BLOCK - #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_F32_BLOCK_STORE1 + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT } //AVX2 block @@ -56,9 +63,15 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, CONVERT_I12_F32_BLOCK_STORE1(y1); } + #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT + #undef CONVERT_I12_F32_BLOCK #undef CONVERT_I12_F32_BLOCK_STORE1 - #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_CI12_2CF32_BLOCK_OPT + #undef CONVERT_CI12_4CF32_BLOCK_OPT } //Generic block diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx2.t b/src/lib/xdsp/templates/conv_i12_i16_avx2.t index eb29e34f..36ee8ee3 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx2.t +++ b/src/lib/xdsp/templates/conv_i12_i16_avx2.t @@ -60,6 +60,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef CONVERT_I12_I16_BLOCK +#undef CONVERT_I12_2I32_SEPARATED +#undef CONVERT_CI12_2CI32_BLOCK_OPT +#undef CONVERT_CI12_4CI32_BLOCK_OPT const uint8_t* indata = (const uint8_t*)in; #include "conv_i12_i16_generic.inc" diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc index 66f2aad4..ebedb270 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc +++ b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc @@ -12,6 +12,8 @@ const __m512i shfl = _mm512_set_epi8( 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); +const __m512i pidx = _mm512_set_epi64(7,5,3,1,6,4,2,0); + #define CONVERT_I12_I16_BLOCK(reg, result) \ { \ __m512i v0 = _mm512_permutexvar_epi32(permmask, reg); \ @@ -21,3 +23,45 @@ const __m512i shfl = _mm512_set_epi8( __m512i r1 = _mm512_and_si512(_mm512_srli_epi64(r, 4), mask1); \ result = _mm512_or_si512(r0, r1); \ } + +#define CONVERT_I12_2I32_SEPARATED(reg, res0, res1) \ +{ \ + __m512i v0 = _mm512_permutexvar_epi32(permmask, reg); \ + __m512i r = _mm512_shuffle_epi8(v0, shfl); \ + \ + res1 = _mm512_and_si512(r, mask0); \ + res0 = _mm512_and_si512(_mm512_slli_epi64(r, 12), mask0); \ +} + +#define CONVERT_CI12_2CI32_BLOCK_OPT(reg, res0, res1) \ +{ \ + __m512i a0, a1; \ + CONVERT_I12_2I32_SEPARATED(reg, a0, a1); \ + \ + __m512i b0 = _mm512_unpacklo_epi32(a0, a1); \ + __m512i b1 = _mm512_unpackhi_epi32(a0, a1); \ + res0 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(b0), _mm512_castsi512_pd(b1), 0b00000000)); \ + res1 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(b0), _mm512_castsi512_pd(b1), 0b11111111)); \ +} + +#define CONVERT_CI12_4CI32_BLOCK_OPT(reg0, reg1, res0, res1, res2, res3) \ +{ \ + __m512i a0, a1, a2, a3; \ + CONVERT_I12_2I32_SEPARATED(reg0, a0, a1); \ + CONVERT_I12_2I32_SEPARATED(reg1, a2, a3); \ + \ + __m512i b0 = _mm512_unpacklo_epi32(a0, a1); \ + __m512i b1 = _mm512_unpackhi_epi32(a0, a1); \ + __m512i b2 = _mm512_unpacklo_epi32(a2, a3); \ + __m512i b3 = _mm512_unpackhi_epi32(a2, a3); \ + \ + __m512i c0 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(b0), _mm512_castsi512_pd(b2), 0b00000000)); \ + __m512i c1 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(b0), _mm512_castsi512_pd(b2), 0b11111111)); \ + __m512i c2 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(b1), _mm512_castsi512_pd(b3), 0b00000000)); \ + __m512i c3 = _mm512_castpd_si512(_mm512_shuffle_pd(_mm512_castsi512_pd(b1), _mm512_castsi512_pd(b3), 0b11111111)); \ + \ + res0 = _mm512_permutexvar_epi64(pidx, c0); \ + res1 = _mm512_permutexvar_epi64(pidx, c1); \ + res2 = _mm512_permutexvar_epi64(pidx, c2); \ + res3 = _mm512_permutexvar_epi64(pidx, c3); \ +} diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.t b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.t index 53be77fd..6495688d 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.t +++ b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.t @@ -34,6 +34,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT } //AVX2 block @@ -58,6 +61,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, } #undef CONVERT_I12_I16_BLOCK + #undef CONVERT_I12_2I32_SEPARATED + #undef CONVERT_CI12_2CI32_BLOCK_OPT + #undef CONVERT_CI12_4CI32_BLOCK_OPT } //Generic block From 47ad192e6fb579abd1702bc052084b2c353fe737 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 31 Oct 2025 23:56:31 +0300 Subject: [PATCH 220/397] SA AVX512 code written (not tested) --- src/lib/xdsp/fast_math.h | 46 ++++++++++++++ src/lib/xdsp/fftad_functions.c | 24 +++++++ src/lib/xdsp/templates/fftad_add_avx512bw.t | 67 ++++++++++++++++++++ src/lib/xdsp/templates/fftad_init_avx512bw.t | 13 ++++ src/lib/xdsp/templates/fftad_norm_avx512bw.t | 61 ++++++++++++++++++ src/lib/xdsp/utests/xdsp_utest_suite.c | 4 +- src/lib/xdsp/utests/xfft_fftad_utest.c | 12 ++-- 7 files changed, 221 insertions(+), 6 deletions(-) create mode 100644 src/lib/xdsp/templates/fftad_add_avx512bw.t create mode 100644 src/lib/xdsp/templates/fftad_init_avx512bw.t create mode 100644 src/lib/xdsp/templates/fftad_norm_avx512bw.t diff --git a/src/lib/xdsp/fast_math.h b/src/lib/xdsp/fast_math.h index 46f92f76..e74678c7 100644 --- a/src/lib/xdsp/fast_math.h +++ b/src/lib/xdsp/fast_math.h @@ -103,6 +103,52 @@ static inline #endif + + +#ifdef WVLT_AVX512BW + +#define WVLT_AVX512_LOG2_POLY0(x, c0) _mm512_set1_ps(c0) +#define WVLT_AVX512_LOG2_POLY1(x, c0, c1) _mm512_add_ps(_mm512_mul_ps(WVLT_AVX512_LOG2_POLY0(x, c1), x), _mm512_set1_ps(c0)) +#define WVLT_AVX512_LOG2_POLY2(x, c0, c1, c2) _mm512_add_ps(_mm512_mul_ps(WVLT_AVX512_LOG2_POLY1(x, c1, c2), x), _mm512_set1_ps(c0)) +#define WVLT_AVX512_LOG2_POLY3(x, c0, c1, c2, c3) _mm512_add_ps(_mm512_mul_ps(WVLT_AVX512_LOG2_POLY2(x, c1, c2, c3), x), _mm512_set1_ps(c0)) +#define WVLT_AVX512_LOG2_POLY4(x, c0, c1, c2, c3, c4) _mm512_add_ps(_mm512_mul_ps(WVLT_AVX512_LOG2_POLY3(x, c1, c2, c3, c4), x), _mm512_set1_ps(c0)) +#define WVLT_AVX512_LOG2_POLY5(x, c0, c1, c2, c3, c4, c5) _mm512_add_ps(_mm512_mul_ps(WVLT_AVX512_LOG2_POLY4(x, c1, c2, c3, c4, c5), x), _mm512_set1_ps(c0)) + +#define WVLT_AVX512_POLYLOG2_DECL_CONSTS \ +const __m512i wvlt_AVX512_log2_exp = _mm512_set1_epi32(0x7F800000); \ + const __m512i wvlt_AVX512_log2_mant = _mm512_set1_epi32(0x007FFFFF); \ + const __m512 wvlt_AVX512_log2_one = _mm512_set1_ps(1.0f); \ + const __m512i wvlt_AVX512_log2_v127 = _mm512_set1_epi32(127); + +#if LOG_POLY_DEGREE == 3 +#define WVLT_AVX512_LOG2_POLY_APPROX(x) WVLT_AVX512_LOG2_POLY2(x, 2.28330284476918490682f, -1.04913055217340124191f, 0.204446009836232697516f) +#elif LOG_POLY_DEGREE == 4 +#define WVLT_AVX512_LOG2_POLY_APPROX(x) WVLT_AVX512_LOG2_POLY3(x, 2.61761038894603480148f, -1.75647175389045657003f, 0.688243882994381274313f, -0.107254423828329604454f) +#elif LOG_POLY_DEGREE == 5 +#define WVLT_AVX512_LOG2_POLY_APPROX(x) WVLT_AVX512_LOG2_POLY4(x, 2.8882704548164776201f, -2.52074962577807006663f, 1.48116647521213171641f, -0.465725644288844778798f, 0.0596515482674574969533f) +#elif LOG_POLY_DEGREE == 6 +#define WVLT_AVX512_LOG2_POLY_APPROX(x) WVLT_AVX512_LOG2_POLY5(x, 3.1157899f, -3.3241990f, 2.5988452f, -1.2315303f, 3.1821337e-1f, -3.4436006e-2f) +#else +#error +#endif + +#define WVLT_POLYLOG2F16(in, out) \ +{ \ + __m512i i = _mm512_castps_si512(in); \ + __m512 e = _mm512_cvtepi32_ps(_mm512_sub_epi32(_mm512_srli_epi32(_mm512_and_si512(i, wvlt_AVX512_log2_exp), 23), wvlt_AVX512_log2_v127)); \ + __m512 m = _mm512_or_ps(_mm512_castsi512_ps(_mm512_and_si512(i, wvlt_AVX512_log2_mant)), wvlt_AVX512_log2_one); \ + \ + /* Minimax polynomial fit of log2(x)/(x - 1), for x in range [1, 2[ */ \ + __m512 p = WVLT_AVX512_LOG2_POLY_APPROX(m); \ + \ + /* This effectively increases the polynomial degree by one, but ensures that log2(1) == 0*/ \ + p = _mm512_mul_ps(p, _mm512_sub_ps(m, wvlt_AVX512_log2_one)); \ + \ + out = _mm512_add_ps(p, e); \ +} + +#endif + #ifdef WVLT_NEON #define WVLT_LOG2_POLY0(x, c0) vdupq_n_f32(c0) diff --git a/src/lib/xdsp/fftad_functions.c b/src/lib/xdsp/fftad_functions.c index 9139b663..617fdc36 100644 --- a/src/lib/xdsp/fftad_functions.c +++ b/src/lib/xdsp/fftad_functions.c @@ -38,6 +38,27 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/fftad_norm_hwi16_generic.t" DECLARE_TR_FUNC_FFTAD_NORM_HWI16(fftad_norm_hwi16_generic) + +#ifdef WVLT_AVX512BW + +#define TEMPLATE_FUNC_NAME fftad_init_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/fftad_init_avx512bw.t" +DECLARE_TR_FUNC_FFTAD_INIT(fftad_init_avx512bw) + +#define TEMPLATE_FUNC_NAME fftad_add_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw,avx512dq")) +#include "templates/fftad_add_avx512bw.t" +DECLARE_TR_FUNC_FFTAD_ADD(fftad_add_avx512bw) + +#define TEMPLATE_FUNC_NAME fftad_norm_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw,avx512dq,fma")) +#include "templates/fftad_norm_avx512bw.t" +DECLARE_TR_FUNC_FFTAD_NORM(fftad_norm_avx512bw) + +#endif //WVLT_AVX512BW + + #ifdef WVLT_AVX2 #define TEMPLATE_FUNC_NAME fftad_init_avx2 @@ -116,6 +137,7 @@ fftad_init_function_t fftad_init_c(generic_opts_t cpu_cap, const char** sfunc) SELECT_GENERIC_FN(fn, fname, tr_fftad_init_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_fftad_init_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_fftad_init_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_fftad_init_neon, cpu_cap); if (sfunc) *sfunc = fname; @@ -129,6 +151,7 @@ fftad_add_function_t fftad_add_c(generic_opts_t cpu_cap, const char** sfunc) SELECT_GENERIC_FN(fn, fname, tr_fftad_add_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_fftad_add_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_fftad_add_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_fftad_add_neon, cpu_cap); if (sfunc) *sfunc = fname; @@ -142,6 +165,7 @@ fftad_norm_function_t fftad_norm_c(generic_opts_t cpu_cap, const char** sfunc) SELECT_GENERIC_FN(fn, fname, tr_fftad_norm_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_fftad_norm_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_fftad_norm_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_fftad_norm_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/templates/fftad_add_avx512bw.t b/src/lib/xdsp/templates/fftad_add_avx512bw.t new file mode 100644 index 00000000..f4441ab6 --- /dev/null +++ b/src/lib/xdsp/templates/fftad_add_avx512bw.t @@ -0,0 +1,67 @@ +static +void TEMPLATE_FUNC_NAME(fft_acc_t* __restrict p, wvlt_fftwf_complex* __restrict d, unsigned fftsz) +{ + const __m512 fnoexp = _mm512_castsi512_ps(_mm512_set1_epi32(~(0xffu << 23))); + const __m512 fexp0 = _mm512_castsi512_ps(_mm512_set1_epi32(127u << 23)); + const __m512i expcorr = _mm512_set1_epi32(127); + const __m512 mine = _mm512_set1_ps(p->mine); + + const __m512i pidx0 = _mm512_set_epi32(30,28,26,24,22,20,18,16, 14,12,10,8,6,4,2,0); + const __m512i pidx1 = _mm512_set_epi32(31,29,27,25,23,21,19,17, 15,13,11,9,7,5,3,1); + + for (unsigned i = 0; i < fftsz; i += 32) + { + __m512 e0 = _mm512_load_ps(&d[i + 0][0]); + __m512 e1 = _mm512_load_ps(&d[i + 8][0]); + __m512 e2 = _mm512_load_ps(&d[i + 16][0]); + __m512 e3 = _mm512_load_ps(&d[i + 24][0]); + + __m512 acc_m0 = _mm512_load_ps(&p->f_mant[i + 0]); + __m512 acc_m1 = _mm512_load_ps(&p->f_mant[i + 16]); + + __m512i acc_p0 = _mm512_load_si512((__m512i*)&p->f_pwr[i + 0]); + __m512i acc_p1 = _mm512_load_si512((__m512i*)&p->f_pwr[i + 16]); + + __m512 p0 = _mm512_mul_ps(e0, e0); // i0 q0 ... i3 q3 + __m512 p1 = _mm512_mul_ps(e1, e1); // i4 q4 ... i7 q7 + __m512 p2 = _mm512_mul_ps(e2, e2); // i8 q8 ... iB qB + __m512 p3 = _mm512_mul_ps(e3, e3); // iC qC ... iF qF + + __m512 pm0 = _mm512_permutex2var_ps(p0, pidx0, p1); + __m512 pm1 = _mm512_permutex2var_ps(p0, pidx1, p1); + __m512 pm2 = _mm512_permutex2var_ps(p2, pidx0, p3); + __m512 pm3 = _mm512_permutex2var_ps(p2, pidx1, p3); + + __m512 en0 = _mm512_add_ps(pm0, pm1); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + __m512 en1 = _mm512_add_ps(pm2, pm3); // 16.....31 + + __m512 enz0 = _mm512_add_ps(en0, mine); + __m512 enz1 = _mm512_add_ps(en1, mine); + + __m512 zmpy0 = _mm512_mul_ps(enz0, acc_m0); + __m512 zmpy1 = _mm512_mul_ps(enz1, acc_m1); + + __m512 zClearExp0 = _mm512_and_ps(fnoexp, zmpy0); + __m512 zClearExp1 = _mm512_and_ps(fnoexp, zmpy1); + + __m512 z0 = _mm512_or_ps(zClearExp0, fexp0); + __m512 z1 = _mm512_or_ps(zClearExp1, fexp0); + + __m512i az0 = _mm512_srli_epi32(_mm512_castps_si512(zmpy0), 23); + __m512i az1 = _mm512_srli_epi32(_mm512_castps_si512(zmpy1), 23); + + __m512i azsum0 = _mm512_add_epi32(az0, acc_p0); + __m512i azsum1 = _mm512_add_epi32(az1, acc_p1); + + __m512i azc0 = _mm512_sub_epi32(azsum0, expcorr); + __m512i azc1 = _mm512_sub_epi32(azsum1, expcorr); + + _mm512_store_ps(&p->f_mant[i + 0], z0); + _mm512_store_ps(&p->f_mant[i + 16], z1); + + _mm512_store_si512((__m512i*)&p->f_pwr[i + 0], azc0); + _mm512_store_si512((__m512i*)&p->f_pwr[i + 16], azc1); + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/fftad_init_avx512bw.t b/src/lib/xdsp/templates/fftad_init_avx512bw.t new file mode 100644 index 00000000..b12ddfda --- /dev/null +++ b/src/lib/xdsp/templates/fftad_init_avx512bw.t @@ -0,0 +1,13 @@ +static +void TEMPLATE_FUNC_NAME(fft_acc_t* __restrict p, unsigned fftsz) +{ + __m512 e1 = _mm512_set1_ps(1.0); + __m512i d1 = _mm512_set1_epi32(0); + + for (unsigned i = 0; i < fftsz; i += 16) { + _mm512_store_ps(p->f_mant + i, e1); + _mm512_store_si512((__m512i*)(p->f_pwr + i), d1); + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/fftad_norm_avx512bw.t b/src/lib/xdsp/templates/fftad_norm_avx512bw.t new file mode 100644 index 00000000..46e983d7 --- /dev/null +++ b/src/lib/xdsp/templates/fftad_norm_avx512bw.t @@ -0,0 +1,61 @@ +static +void TEMPLATE_FUNC_NAME(fft_acc_t* __restrict p, unsigned fftsz, float scale, float corr, float* __restrict outa) +{ +#ifdef USE_POLYLOG2 + WVLT_AVX512_POLYLOG2_DECL_CONSTS; +#else + const __m512 log2_mul = _mm512_set1_ps(WVLT_FASTLOG2_MUL); + const __m512 log2_sub = _mm512_set1_ps(WVLT_FASTLOG2_SUB); +#endif + const __m512 vcorr = _mm512_set1_ps(corr); + const __m512 vscale = _mm512_set1_ps(scale); + + const unsigned half = fftsz >> 1; + + for(unsigned i = 0; i < fftsz; i += 32) + { + __m512 m0 = _mm512_load_ps(p->f_mant + i + 0); + __m512 m1 = _mm512_load_ps(p->f_mant + i + 16); + + __m512i p0 = _mm512_load_si512((__m512i*)(p->f_pwr + i + 0)); + __m512i p1 = _mm512_load_si512((__m512i*)(p->f_pwr + i + 16)); + +#ifdef USE_POLYLOG2 + __m512 apwr0, apwr1; + WVLT_POLYLOG2F16(m0, apwr0); + WVLT_POLYLOG2F16(m1, apwr1); +#else + //wvlt_fastlog2 + __m512 l20 = _mm512_cvtepi32_ps(_mm512_castps_si512(m0)); + __m512 l21 = _mm512_cvtepi32_ps(_mm512_castps_si512(m1)); + __m512 apwr0 = _mm512_fmsub_ps(l20, log2_mul, log2_sub); + __m512 apwr1 = _mm512_fmsub_ps(l21, log2_mul, log2_sub); + // +#endif + __m512 s0 = _mm512_add_ps(apwr0, _mm512_cvtepi32_ps(p0)); + __m512 s1 = _mm512_add_ps(apwr1, _mm512_cvtepi32_ps(p1)); + + __m512 f0 = _mm512_fmadd_ps(vscale, s0, vcorr); + __m512 f1 = _mm512_fmadd_ps(vscale, s1, vcorr); + + int32_t offset; + + if(i + 32 <= half) + { + offset = half; + } + else if(i >= half) + { + offset = - half; + } + else + { + offset = 0; + } + + _mm512_store_ps(outa + i + offset + 0, f0); + _mm512_store_ps(outa + i + offset + 16, f1); + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index 163bb5e9..2aacdc2e 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -41,7 +41,7 @@ int main(int argc, char** argv) int number_failed; SRunner *sr; -#if 1 +#if 0 sr = srunner_create( fftad_suite()); srunner_add_suite(sr, rtsa_suite()); srunner_add_suite(sr, fft_window_cf32_suite()); @@ -77,7 +77,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, conv_ci12_4cf32_suite()); // #else - sr = srunner_create(wvlt_sincos_i16_suite()); + sr = srunner_create(fftad_suite()); //srunner_add_suite(sr, conv_2ci16_ci16_suite()); //srunner_add_suite(sr, conv_f32_i12_suite()); //srunner_add_suite(sr, conv_2cf32_ci12_suite()); diff --git a/src/lib/xdsp/utests/xfft_fftad_utest.c b/src/lib/xdsp/utests/xfft_fftad_utest.c index c675e4bc..ce89f421 100644 --- a/src/lib/xdsp/utests/xfft_fftad_utest.c +++ b/src/lib/xdsp/utests/xfft_fftad_utest.c @@ -17,7 +17,8 @@ static_assert( STREAM_SIZE >= 4096, "STREAM_SIZE should be >= 4096!" ); static const unsigned packet_lens[3] = { 256, 4096, STREAM_SIZE }; -#define SPEED_MEASURE_ITERS 1000000 +#define SPEED_MEASURE_ITERS 10000 +#define AVGS 256 #define EPSILON 1E-4 @@ -151,7 +152,7 @@ END_TEST START_TEST(fftad_speed) { - fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "\n**** Compare SIMD implementations speed (%d adds + 1 norm within 1 iteration) ***\n", AVGS); const char* fn_name = NULL; fftad_init_function_t fn_init = NULL; @@ -187,8 +188,11 @@ START_TEST(fftad_speed) //measuring uint64_t tk = clock_get_time(); (*fn_init)(&acc, size); - for(unsigned i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn_add)(&acc, in, size); - (*fn_norm)(&acc, size, 1.0, 0.0, out); + for(unsigned i = 0; i < SPEED_MEASURE_ITERS; ++i) + { + for(unsigned j = 0; j < AVGS; ++j) (*fn_add)(&acc, in, size); + (*fn_norm)(&acc, size, 1.0, 0.0, out); + } uint64_t tk1 = clock_get_time() - tk; fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 cycle, ave speed = %" PRIu64 " cycles/s \n", From bd568749cf861f0355c3ef59fb4ac431d94f54d2 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 1 Nov 2025 01:17:32 +0400 Subject: [PATCH 221/397] xdsp: add AVX512VBMI check --- src/lib/xdsp/vbase.c | 9 +++++++-- src/lib/xdsp/vbase.h | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/lib/xdsp/vbase.c b/src/lib/xdsp/vbase.c index 86957a62..361b80f6 100644 --- a/src/lib/xdsp/vbase.c +++ b/src/lib/xdsp/vbase.c @@ -19,14 +19,16 @@ generic_opts_t cpu_vcap_obtain(unsigned flags) cap = OPT_SSE41; #else - unsigned max_cpu = OPT_AVX512BW; + unsigned max_cpu = OPT_AVX512VBMI; if (flags & CVF_LIMIT_VCPU) { max_cpu = (flags & 0xffff); } __builtin_cpu_init(); - if (__builtin_cpu_supports("avx512bw") && max_cpu >= OPT_AVX512BW) + if (__builtin_cpu_supports("avx512vbmi") && max_cpu >= OPT_AVX512VBMI) + cap = OPT_AVX512VBMI; + else if (__builtin_cpu_supports("avx512bw") && max_cpu >= OPT_AVX512BW) cap = OPT_AVX512BW; else if (__builtin_cpu_supports("avx2") && max_cpu >= OPT_AVX2) cap = OPT_AVX2; @@ -67,6 +69,8 @@ void cpu_vcap_str(char* buffer, unsigned buflen, generic_opts_t caps) case OPT_AVX: type = "AVX"; break; case OPT_AVX2: type = "AVX2"; break; case OPT_AVX512BW: type = "AVX512BW"; break; + case OPT_AVX512VBMI: type = "AVX512VBMI"; break; + case OPT_NEON: type = "ARM_NEON"; break; } @@ -84,6 +88,7 @@ unsigned cpu_vcap_align(generic_opts_t caps) case OPT_SSE42: return 16; case OPT_AVX: case OPT_AVX2: return 32; + case OPT_AVX512VBMI: case OPT_AVX512BW: return 64; case OPT_NEON: return 16; default: diff --git a/src/lib/xdsp/vbase.h b/src/lib/xdsp/vbase.h index 0e7a28ea..072c7909 100644 --- a/src/lib/xdsp/vbase.h +++ b/src/lib/xdsp/vbase.h @@ -19,6 +19,7 @@ enum generic_opts { OPT_AVX, OPT_AVX2, OPT_AVX512BW, + OPT_AVX512VBMI, //ARM-specific OPT_NEON = 2000, @@ -40,6 +41,7 @@ typedef enum generic_opts generic_opts_t; #include #ifndef __EMSCRIPTEN__ +#define WVLT_AVX512VBMI #define WVLT_AVX512BW #define WVLT_AVX2 #define WVLT_AVX @@ -60,6 +62,13 @@ typedef enum generic_opts generic_opts_t; #endif //WVLT_SIMD_INTEL +#ifdef WVLT_AVX512VBMI +#define SELECT_AVX512VBMI_FN(a, b, fn, cap) do { \ +if (cap >= OPT_AVX512VBMI) {a = &fn; b = VB_STRINGIFY(fn);} } while(0) +#else +#define SELECT_AVX512VBMI_FN(a, b, fn, cap) +#endif + #ifdef WVLT_AVX512BW #define SELECT_AVX512BW_FN(a, b, fn, cap) do { \ if (cap >= OPT_AVX512BW) {a = &fn; b = VB_STRINGIFY(fn);} } while(0) From eef5f603b857b10c816195534b3caa6d07ae1a03 Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Mon, 3 Nov 2025 15:13:57 +0400 Subject: [PATCH 222/397] Hyper v2 support. --- src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml | 78 +++--------------------- 1 file changed, 9 insertions(+), 69 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml index c89abc11..a400a07d 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml @@ -3,7 +3,7 @@ # Register desc and visual map name: M2_DSDR_V2 -desc: Hiper board control +desc: Hiper v2 board control revision: "0.0.1" processors: [ c ] bus: @@ -139,71 +139,19 @@ pages: name: CTRL_CHA desc: IF LNA control mask for Channel A opts: *if-lna-opts -# -# 0x22 and 0x23 for HB rev 1 -# - addr: 0x22 -# name: SW_OUT -# fields: -## -# - bits: "6" -# name: RX_H_CHA_R2D_V1 -# desc: Channel A RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) -# - bits: "7" -# name: RX_H_CHB_R2D_V2 -# desc: Channel B RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) -# - bits: "4" -# name: RX_H_CHC_R2C_V1 -# desc: Channel C RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) -# - bits: "5" -# name: RX_H_CHD_R2C_V2 -# desc: Channel D RX OUT selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) -# - bits: "3" -# name: TX_L_CHA -# desc: Channel A TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# - bits: "2" -# name: TX_L_CHB -# desc: Channel B TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# - bits: "1" -# name: TX_L_CHC -# desc: Channel C TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# - bits: "0" -# name: TX_L_CHD -# desc: Channel D TX OUT selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# -# - addr: 0x23 -# name: SW_IN -# fields: -## -# - bits: "0" -# name: RX_L_CHA_R2B_V1 -# desc: Channel A RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# - bits: "1" -# name: RX_L_CHB_R2B_V2 -# desc: Channel B RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# - bits: "2" -# name: RX_L_CHC_R2A_V1 -# desc: Channel C RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# - bits: "3" -# name: RX_L_CHD_R2A_V2 -# desc: Channel D RX IN selection, 2.5-7.1 GHz (0) or 0.4-3.5 GHz (1) -# - bits: "4" -# name: TX_H_CHA -# desc: Channel A TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) -# - bits: "5" -# name: TX_H_CHB -# desc: Channel B TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) -# - bits: "6" -# name: TX_H_CHC -# desc: Channel C TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) -# - bits: "7" -# name: TX_H_CHD -# desc: Channel D TX IN selection, 2.5-7.1 GHz (1) or 0.4-3.5 GHz (0) - # # 0x22 and 0x23 for HB rev 2 - addr: 0x22 name: SW_OUT_RX_CD fields: + - bits: "5:4" + name: OUT_RX_CHC + desc: CHC + opts: *r2rx-out-opts + - bits: "7:6" + name: OUT_RX_CHD + desc: CHD + opts: *r2rx-out-opts - bits: "0" name: OUT_TX_CHD desc: OUT_TX_CHD @@ -216,14 +164,6 @@ pages: - bits: "3" name: OUT_TX_CHA desc: OUT_TX_CHA - - bits: "5:4" - name: OUT_RX_CHC - desc: CHC - opts: *r2rx-out-opts - - bits: "7:6" - name: OUT_RX_CHD - desc: CHD - opts: *r2rx-out-opts # - addr: 0x23 name: SW_OUT_RX_AB From 40f0c07b4e7408f30c5058eef31099790633445a Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Mon, 3 Nov 2025 19:38:15 +0400 Subject: [PATCH 223/397] Hyper v2 support: fixed swapped gpios. --- src/lib/device/m2_dsdr/m2_dsdr_p.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr_p.yaml b/src/lib/device/m2_dsdr/m2_dsdr_p.yaml index 940bceed..44e527d1 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_p.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_p.yaml @@ -18,8 +18,8 @@ field_macros: True x-tdd-fdd-opts: &tdd-fdd-opts 0b00: REV0_LNA_TO_RX_____REV2_SHUTDOWN - 0b01: REV0_LNA_TO_TDDSW__REV2_LNA_TO_LB - 0b10: REV0_LNA_TO_RX_____REV2_LNA_TO_TDDSW + 0b01: REV0_LNA_TO_TDDSW__REV2_LNA_TO_TDDSW + 0b10: REV0_LNA_TO_RX_____REV2_LNA_TO_LB 0b11: REV0_LNA_TO_TDDSW__REV2_LNA_TO_RX From 006c4ac88e2f456ad0181436334b99e9cbd1dc2f Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 6 Nov 2025 00:22:04 +0400 Subject: [PATCH 224/397] usdr_pcie_uram: fix metadata overrun issue for >15 delayed events --- .../pcie_uram/driver/usdr_pcie_uram.c | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index 22639668..ab7af9e4 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -140,9 +140,12 @@ struct usdr_dev; typedef void (*bucket_func_t)(struct usdr_dev* dev, unsigned event, void* slot); +enum { + STAT_MAX_SZ = 64, +}; struct event_data_log { - uint32_t stat_data[4 * 64]; + uint32_t stat_data[4 * STAT_MAX_SZ]; uint64_t stat_wptr; uint64_t stat_rptr; }; @@ -465,18 +468,18 @@ static irqreturn_t usdr_pcie_irq_bucket_128(int irq, void *data) if (i % 32 == 31) { do_cnf = (i << 1) & 0x3ff; } - + DEBUG_DEV_OUT(&d->pdev->dev, "BUCKET %d IRQ %d: Event %d Flag: %d; RPTR %d; Data: %08x_%08x_%08x_%08x\n", i, irq, event_no, flags, b->rptr, data[3], data[2], data[1], data[0]); // TODO: based on event handler process data if (event_no == 0 || event_no == 1) { - unsigned k = (d->streaming[event_no].stat_wptr * 4) & 0x3f; - d->streaming[event_no].stat_data[k + 0] = data[1]; // 0 - d->streaming[event_no].stat_data[k + 1] = data[2]; // 1 - d->streaming[event_no].stat_data[k + 2] = data[3]; // 2 - d->streaming[event_no].stat_data[k + 3] = + unsigned k = (d->streaming[event_no].stat_wptr) & (STAT_MAX_SZ - 1); + d->streaming[event_no].stat_data[4 * k + 0] = data[1]; // 0 + d->streaming[event_no].stat_data[4 * k + 1] = data[2]; // 1 + d->streaming[event_no].stat_data[4 * k + 2] = data[3]; // 2 + d->streaming[event_no].stat_data[4 * k + 3] = #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) ets.tv64; // Timestamp #else @@ -484,7 +487,7 @@ static irqreturn_t usdr_pcie_irq_bucket_128(int irq, void *data) #endif d->streaming[event_no].stat_wptr++; - + //dev_notice(&d->pdev->dev, "BUCKET %d IRQ %d: Event %d Flag: %d; RPTR %d; Data: %08x_%08x_%08x_%08x %016llx\n", // i, irq, event_no, flags, b->rptr, data[3], data[2], data[1], data[0], ets); } else { @@ -928,14 +931,14 @@ static int usdr_stream_initialize(struct usdr_dev *usdrdev, usdrdev->dl.stream_core[sno]); goto failed_alloc; } - + usdrdev->streams[sno] = s; exit_success: //s->cntr_last = 0; sdma->out_vma_length = s->dma_buff_size * s->dma_buffs; sdma->out_vma_off = ((off_t)(sdma->sno + 1)) << VMA_STREAM_IDX_SHIFT; - + // Flush non-read events usdrdev->streaming[sno].stat_rptr = usdrdev->streaming[sno].stat_wptr; usdrdev->streams[sno]->abuffer_no = 0; @@ -1031,23 +1034,23 @@ static int usdr_stream_wait_or_alloc(struct usdr_dev *usdrdev, unsigned long sno BUG_ON(cnt == 0); } } - + max = usdrdev->streaming[sno].stat_wptr; if (max > usdrdev->streaming[sno].stat_rptr + cnt) { - max = usdrdev->streaming[sno].stat_rptr + cnt; + max = usdrdev->streaming[sno].stat_rptr + cnt; } - + for (i = usdrdev->streaming[sno].stat_rptr; i < max; i++, ooidx++) { unsigned k, nreg[3], ktm; - k = (usdrdev->streaming[sno].stat_rptr * 4) & 0x3f; - nreg[0] = usdrdev->streaming[sno].stat_data[k + 0]; - nreg[1] = usdrdev->streaming[sno].stat_data[k + 1]; - nreg[2] = usdrdev->streaming[sno].stat_data[k + 2]; - ktm = usdrdev->streaming[sno].stat_data[k + 3]; - + k = (usdrdev->streaming[sno].stat_rptr) & (STAT_MAX_SZ - 1); + nreg[0] = usdrdev->streaming[sno].stat_data[4 * k + 0]; + nreg[1] = usdrdev->streaming[sno].stat_data[4 * k + 1]; + nreg[2] = usdrdev->streaming[sno].stat_data[4 * k + 2]; + ktm = usdrdev->streaming[sno].stat_data[4 * k + 3]; + //sr = ((uint64_t)nreg[1] << 32) | nreg[0]; usdrdev->streaming[sno].stat_rptr++; - + //cntr_last = (stat >> 8) & 0x3f; //dcnt = (cntr_last - usdrdev->streams[sno]->cntr_last) & 0x3f; //BUG_ON(dcnt == 0); @@ -1061,14 +1064,14 @@ static int usdr_stream_wait_or_alloc(struct usdr_dev *usdrdev, unsigned long sno oob_out_u64[2 * ooidx + 0] = (((uint64_t)nreg[1]) << 32) | nreg[0]; oob_out_u64[2 * ooidx + 1] = (((uint64_t)ktm) << 32) | nreg[2]; oobcnt++; - + // dw0 - evnt[1] - reg[0] // dw1 - evnt[2] - reg[1] // dw2 - evnt[0] - reg[2] // dw3 - timestamp } } - + if (oob_length) { *oob_length = oobcnt * 16; } From 7032dd95920c2e9726e19cffe12035a32f916f9d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 6 Nov 2025 00:23:20 +0400 Subject: [PATCH 225/397] usdr_pcie_uram: set RX DMA boundaries for the newest FPGA images --- .../lowlevel/pcie_uram/driver/usdr_pcie_uram.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index ab7af9e4..73264011 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -612,8 +612,13 @@ static int usdr_stream_free(struct usdr_dev *usdrdev, unsigned sno) return 0; // Release DMA buffers - // Check that mapping is invalid + if (usdrdev->dl.stream_core[sno] == USDR_MAKE_COREID(USDR_CS_STREAM, USDR_SC_TXDMA_OLD)) { + usdr_reg_wr32(usdrdev, usdrdev->dl.stream_cfg_base[sno] + s->dma_buffs, 0); + } else { + usdr_reg_wr32(usdrdev, usdrdev->dl.stream_cfg_base[sno] + 7 * s->dma_buffs, 0); + } + // Destroy buffers for (i = s->dma_buffs; i > 0; i--) { dma_free_attrs(&usdrdev->pdev->dev, s->dma_buff_size, @@ -913,8 +918,8 @@ static int usdr_stream_initialize(struct usdr_dev *usdrdev, goto failed_alloc; } s->dmab[i].uvirt = NULL; - //dev_notice(&usdrdev->pdev->dev, "buf[%d]=%lx [virt %p]\n", i, - // (unsigned long)s->dmab[i].phys, s->dmab[i].kvirt); + //dev_notice(&usdrdev->pdev->dev, "buf[%d]=%lx len=%d [virt %px]\n", i, + // (unsigned long)s->dmab[i].phys, s->dma_buff_size, s->dmab[i].kvirt); } // Initialize dma buffer pointer in the dev @@ -956,6 +961,11 @@ static int usdr_stream_initialize(struct usdr_dev *usdrdev, } else { // Clear spurious interrupts atomic_xchg(&usdrdev->irq_ev_cnt[usdrdev->dl.stream_int_number[sno]], 0); + + usdr_reg_wr32(usdrdev, + usdrdev->dl.stream_cfg_base[sno] + 7 * sdma->dma_bufs, + sdma->dma_buf_sz - 1); + dev_notice(&usdrdev->pdev->dev, "RX stream is limited to %d bytes\n", sdma->dma_buf_sz); } return 0; From bdb4f2abf277f8616246d8b2acc321d062440bf3 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 6 Nov 2025 00:36:10 +0400 Subject: [PATCH 226/397] pcie_uram_main: verbose dma buffer information --- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 51 ++++++++++++++++--- src/lib/lowlevel/pcie_uram/pcie_uram_main.c | 5 ++ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 8508d9fc..3c1c21e2 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -161,23 +161,60 @@ int _sfetrx4_stream_recv(stream_handle_t* str, res = ops->recv_dma_wait(dev, 0, stream->ll_streamo, (void**)&dma_buf, &oob_data, &oob_size, timeout); - if (res < 0) + if (res == -ETIMEDOUT) { + } else if (res < 0) return res; + uint32_t dma_stat = oob_data[1]; + unsigned dbno_inram; // BUF# filled in FIFO RAM + unsigned dbno_xfred; // BUF# transferred to host + unsigned dbno_ntfysent; // BUF# notification sent + unsigned dbno_confirmed; // BUF# confirmed by user (can reuse again) + unsigned fe_stat; // BUF# in FE + bool srdy = dma_stat >> 31; + fe_stat = (((dma_stat >> 22) & 3) << 4) | + (((dma_stat >> 14) & 3) << 2) | + (((dma_stat >> 6) & 3) << 0); + dbno_confirmed = (dma_stat >> 0) & 0x3f; + dbno_xfred = (dma_stat >> 8) & 0x3f; + dbno_inram = (dma_stat >> 16) & 0x3f; + dbno_ntfysent = (dma_stat >> 24) & 0x3f; + +#if DEBUG_DMA_BUFFERS + bool santify_fail = false; + { + unsigned a = dbno_inram, b = dbno_xfred, c = dbno_ntfysent; + unsigned d1 = (a - b) & 0x3f; + unsigned d2 = (b - c) & 0x3f; + if ((d1 >= 32) || (d2 >= 32)) { + santify_fail = true; + } + } +#else +#define santify_fail false +#endif + + if (res == -ETIMEDOUT) { + USDR_LOG("UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " TIMEDOUT:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], res, dma_buf, + stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); + return res; + } + if (oob_data[0] & 0xffffff) { unsigned pkt_lost = oob_data[0] & 0xffffff; - USDR_LOG("UDMS", USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " EXTRA:%d buf=%p seq=%16" PRIu64 "\n", oob_data[0], oob_data[1], res, dma_buf, - stream->rcnt); + USDR_LOG("UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " EXTRA:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], res, dma_buf, + stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); stream->stats.fe_drop += pkt_lost; stream->r_ts += stream->pkt_symbs * pkt_lost; } else if ((oob_data[0] >> 32) != stream->burst_mask) { - USDR_LOG("UDMS", USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " [%08x] EXTRA:%d buf=%p seq=%16" PRIu64 "\n", oob_data[0], oob_data[1], stream->burst_mask, res, dma_buf, - stream->rcnt); + USDR_LOG("UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " [%08x] EXTRA:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], stream->burst_mask, res, dma_buf, + stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); } else { - USDR_LOG("UDMS", USDR_LOG_DEBUG, "Recv %016" PRIx64 ".%016" PRIx64 " EXTRA:- buf=%p seq=%16" PRIu64 "\n", oob_data[0], oob_data[1], dma_buf, - stream->rcnt); + USDR_LOG("UDMS", + santify_fail ? USDR_LOG_ERROR : USDR_LOG_DEBUG, "Recv %016" PRIx64 ".%016" PRIx64 " EXTRA:- buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], dma_buf, + stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); } stream->stats.pktok ++; diff --git a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c index 3143a099..ab9abe80 100644 --- a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c +++ b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c @@ -577,6 +577,11 @@ int pcie_uram_dma_wait_or_alloc(struct pcie_uram_dev* d, bool rx, stream_t chann pcie_reg_op_iommap(d, 4, &stat[0], 12, NULL, 0); USDR_LOG("PCIE", USDR_LOG_NOTE, "STR[%d]: PCIe recv dma buffer alloc timed out stat=%08x:%08x:%08x %08x!\n", channel, stat[0], stat[1], stat[2], stat[3]); + + uint32_t* oob32 = (uint32_t*)oob_ptr; + oob32[0] = stat[0]; + oob32[1] = stat[1]; + oob32[2] = stat[2]; } else { unsigned stat[4]; // TODO: Remove hardcoded address to upper layer From 95b6f53561dd2fbe2ed2bc3c4a720da3a0018148 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 6 Nov 2025 14:04:08 +0400 Subject: [PATCH 227/397] ssdr: add dynamic layout for r1/r2 --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 9f50f649..9f1681a2 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -124,7 +124,7 @@ const usdr_dev_param_constant_t s_params_m2_lm7_1_rev000[] = { { "/ll/qspi_flash/core", USDR_MAKE_COREID(USDR_CS_BUS, USDR_QSPI_FLASH_24_RW) }, { "/ll/qspi_flash/base", M2PCI_REG_QSPI_FLASH }, - { "/ll/qspi_flash/master_off", 0x1C0000 }, +// { "/ll/qspi_flash/master_off", 0x1C0000 }, { "/ll/gpi/0/core", USDR_MAKE_COREID(USDR_CS_GPI, USDR_GPI_32BIT_12) }, { "/ll/gpi/0/base", M2PCI_REG_RD_GPI0_12 }, @@ -249,6 +249,7 @@ static int dev_m2_lm7_1_lms7002rxlml_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint static int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_revision_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm7_1_qspi_flash_master_off_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); static int dev_m2_lm7_1_sdr_tx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_rx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -355,6 +356,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/debug/clk_info", { dev_m2_lm7_1_debug_clkinfo_set, NULL }}, { "/dm/revision", { NULL, dev_m2_lm7_1_revision_get }}, + + { "/ll/qspi_flash/master_off", { NULL, dev_m2_lm7_1_qspi_flash_master_off_get }}, }; struct dev_m2_lm7_1_gps { @@ -1233,6 +1236,17 @@ int dev_m2_lm7_1_usb_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) return 0; } +int dev_m2_lm7_1_qspi_flash_master_off_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + if (d->xdev.ssdr_pro) { + *ovalue = 0x07b0000; + } else { + *ovalue = MASTER_IMAGE_OFF; + } + return 0; +} + int dev_m2_lm7_1_revision_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue) { unsigned rev_lo, rev_hi; From c5d8fd79a8197a9ff01980e20eb6ab9e14886570 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 6 Nov 2025 14:04:49 +0400 Subject: [PATCH 228/397] usb: add initialization of DMA limiter in RX chain for newest FPGA images --- src/lib/lowlevel/usb_uram/usb_uram_generic.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/lowlevel/usb_uram/usb_uram_generic.c b/src/lib/lowlevel/usb_uram/usb_uram_generic.c index 493d1ede..0d1587c2 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_generic.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_generic.c @@ -376,7 +376,8 @@ int usb_uram_generic_create_and_init(lldev_t dev, unsigned pcount, const char** interrupt_base = tmp; //Do these in case of pure USB only - + const unsigned REG_WR_MBUS2_ADDR= 6; + const unsigned REG_WR_MBUS2_DATA= 7; const unsigned REG_WR_PNTFY_CFG = 8; const unsigned REG_WR_PNTFY_ACK = 9; @@ -402,6 +403,9 @@ int usb_uram_generic_create_and_init(lldev_t dev, unsigned pcount, const char** return res; } + // Set no limit for RX USB transfers + res = res ? res : usb_uram_reg_out(dev, REG_WR_MBUS2_ADDR, 0x000000e0); + res = res ? res : usb_uram_reg_out(dev, REG_WR_MBUS2_DATA, 0xffffffff); } else { USDR_LOG(USBG_LOG_TAG, USDR_LOG_WARNING, "Omit interrupt initialization on USB+PCIE mode\n"); } From 1e96550c59263f34b4de78c8a277425a141a1336 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 6 Nov 2025 14:05:55 +0400 Subject: [PATCH 229/397] usdr_flash add internal verbosity flag for debugging --- src/tools/usdr_flash.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/tools/usdr_flash.c b/src/tools/usdr_flash.c index 230b6635..eb9f694e 100644 --- a/src/tools/usdr_flash.c +++ b/src/tools/usdr_flash.c @@ -48,6 +48,7 @@ int main(int argc, char** argv) bool force = false; bool golden = false; bool corrupt = false; + bool verbose = false; uint32_t curfwid; bool no_device = false; uint64_t master_offset = MASTER_IMAGE_OFF; @@ -59,7 +60,7 @@ int main(int argc, char** argv) usdrlog_setlevel(NULL, USDR_LOG_WARNING); usdrlog_enablecolorize(NULL); - while ((opt = getopt(argc, argv, "U:l:i:w:r:FGC")) != -1) { + while ((opt = getopt(argc, argv, "U:l:i:w:r:FGCv")) != -1) { switch (opt) { case 'U': busname = optarg; @@ -88,6 +89,9 @@ int main(int argc, char** argv) case 'C': corrupt = true; break; + case 'v': + verbose = true; + break; default: fprintf(stderr, "Usage: %s [-U device_bus] [-l loglevel] [-r filename | -w filename | -i filename] [-G]\n", argv[0]); @@ -216,6 +220,13 @@ int main(int argc, char** argv) fprintf(stderr, "It looks like the file is corrupted! res=%d\n", res); return 4; } + if (verbose) { + fprintf(stderr, "- GOLDEN: WBSTART=%08x IPROG=%d\n", image.wbstar, image.iprog); + fprintf(stderr, "- MASTER: WBSTART=%08x IPROG=%d\n", image_master.wbstar, image_master.iprog); + fprintf(stderr, "- FILE: WBSTART=%08x IPROG=%d\n", file.wbstar, file.iprog); + fprintf(stderr, "- DEVICE: OFFSET= %08x\n", (unsigned)master_offset); + } + res = (no_device) ? 0 : xlnx_btstrm_iprgcheck(&image, &file, master_offset, golden); if (res) { fprintf(stderr, "Image check failed! res=%d, file revision=%12ld\n", res, get_xilinx_rev_h(file.usr_access2)); From b48ef76d38d16c69c427eb7c9b13e5c7382250cb Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 7 Nov 2025 00:54:27 +0400 Subject: [PATCH 230/397] dsdr_hiper: fix bugs in control --- src/lib/device/m2_dsdr/dsdr_hiper.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index e31c81e0..2fe6d1d3 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -964,10 +964,13 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8a_chip cfg->rx_dsa = 0; cfg->tx_band = IFBAND_AUTO; cfg->ant_sel = ANT_RX_TRX; + cfg->rx_en = 0; + cfg->tx_en = 0; cfg->rx_freq = 0; cfg->rx_nco = 0; cfg->tx_freq = 0; cfg->tx_nco = 0; + cfg->pa_2stage_bypass = 0; cfg->lms8_lna_gain = 0; cfg->lms8_pa_gain = 0; cfg->lms8_rx_hlmix_gain = 15; @@ -1340,10 +1343,10 @@ enum led_rx_cals { // Switch on RX path => ANT_RX external port / rfsw_rxtx / LB enum rfsw_tddfdd_bits { - EXP_TDDFDD_SD = 0b00, // LB SW is on - EXP_TDDFDD_P1_LB_SW = 0b01, // LB SW is on - EXP_TDDFDD_P2_TRX_SW = 0b10, - EXP_TDDFDD_P3_ANT_RX = 0b11, + EXP_TDDFDD_SD = TDD_FDD_OPTS_REV0_LNA_TO_RX_____REV2_SHUTDOWN, // LB SW is on + EXP_TDDFDD_P1_LB_SW = TDD_FDD_OPTS_REV0_LNA_TO_RX_____REV2_LNA_TO_LB, // LB SW is on + EXP_TDDFDD_P2_TRX_SW = TDD_FDD_OPTS_REV0_LNA_TO_TDDSW__REV2_LNA_TO_TDDSW, + EXP_TDDFDD_P3_ANT_RX = TDD_FDD_OPTS_REV0_LNA_TO_TDDSW__REV2_LNA_TO_RX, }; static void _hiper_antenna_sw_map(bool rev2, unsigned antenna, bool rxen, bool txen, uint8_t* gpo_ctrl, unsigned* inswlb, unsigned *arx, unsigned *atx, @@ -1367,8 +1370,8 @@ static void _hiper_antenna_sw_map(bool rev2, unsigned antenna, bool rxen, bool t *inswlb = 0; *arx = rxen; *atx = txen; - *exp_led_trx = LED_TRX_TXO; - *exp_led_rx = LED_RX_ON; + *exp_led_trx = txen ? LED_TRX_TXO : LED_TRX_OFF; + *exp_led_rx = rxen ? LED_RX_ON : LED_RX_OFF; break; case ANT_TRX_TERM: @@ -1382,7 +1385,7 @@ static void _hiper_antenna_sw_map(bool rev2, unsigned antenna, bool rxen, bool t *inswlb = 0; *arx = rxen; *atx = 0; - *exp_led_trx = LED_TRX_RXO; + *exp_led_trx = rxen ? LED_TRX_RXO : LED_TRX_OFF; *exp_led_rx = LED_RX_OFF; break; @@ -1398,7 +1401,7 @@ static void _hiper_antenna_sw_map(bool rev2, unsigned antenna, bool rxen, bool t *arx = rxen; *atx = 0; *exp_led_trx = LED_TRX_OFF; - *exp_led_rx = LED_RX_ON; + *exp_led_rx = rxen ? LED_RX_ON : LED_RX_OFF; break; case ANT_LOOPBACK: @@ -1424,7 +1427,7 @@ static void _hiper_antenna_sw_map(bool rev2, unsigned antenna, bool rxen, bool t *inswlb = 0; *arx = rxen; *atx = txen; - *exp_led_trx = LED_TRX_TRX; + *exp_led_trx = (rxen && txen) ? LED_TRX_TRX : txen ? LED_TRX_TXO : rxen ? LED_TRX_RXO : LED_TRX_OFF; *exp_led_rx = LED_RX_OFF; break; @@ -1625,7 +1628,7 @@ static void dsdr_hiper_fe_rx_band_upd(dsdr_hiper_fe_t* def, unsigned chno, unsig if (def->ucfg[chno].rx_band < RXBAND_OPTS_BAND_AUTO_L) return; - def->ucfg[chno].rx_band = (band == 0) ? RXBAND_OPTS_BAND_AUTO_L : (band == 1) ? RXBAND_OPTS_BAND_AUTO_H : RXBAND_OPTS_BAND_AUTO_BP; + def->ucfg[chno].rx_band = (band & 3); USDR_LOG("HIPR", USDR_LOG_WARNING, "RXBand[%d] switched to %c (%d)\n", chno, def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_H ? 'H' : def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_L ? 'L' : From 824c4b42865ba8cbee773b8e8e74f868a4ade7d7 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 7 Nov 2025 00:32:02 +0300 Subject: [PATCH 231/397] lite refactoring & optimization --- src/lib/xdsp/templates/conv_i16_f32_avx2.t | 18 +++++++++--------- src/lib/xdsp/templates/fft_window_cf32_avx2.t | 4 ++-- src/lib/xdsp/utests/fft_window_cf32_utest.c | 11 +++++------ src/lib/xdsp/utests/xdsp_utest_suite.c | 2 +- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/lib/xdsp/templates/conv_i16_f32_avx2.t b/src/lib/xdsp/templates/conv_i16_f32_avx2.t index 11117297..b666e3d6 100644 --- a/src/lib/xdsp/templates/conv_i16_f32_avx2.t +++ b/src/lib/xdsp/templates/conv_i16_f32_avx2.t @@ -23,16 +23,16 @@ void TEMPLATE_FUNC_NAME(const int16_t *__restrict indata, f0 = _mm256_mul_ps(f0, scale); \ f1 = _mm256_mul_ps(f1, scale); \ \ - _mm256_storeu_ps(outdata, f0); outdata += 8; \ - _mm256_storeu_ps(outdata, f1); outdata += 8; \ + _mm256_store_ps(outdata, f0); outdata += 8; \ + _mm256_store_ps(outdata, f1); outdata += 8; \ } // CONVERT_I16_F32_BLOCK end for(; i >= 96; i -= 96) { - t0 = _mm256_loadu_si256(vp++); - t1 = _mm256_loadu_si256(vp++); - t2 = _mm256_loadu_si256(vp++); + t0 = _mm256_load_si256(vp++); + t1 = _mm256_load_si256(vp++); + t2 = _mm256_load_si256(vp++); CONVERT_I16_F32_BLOCK(t0); CONVERT_I16_F32_BLOCK(t1); @@ -41,8 +41,8 @@ void TEMPLATE_FUNC_NAME(const int16_t *__restrict indata, for(; i >= 64; i -= 64) { - t0 = _mm256_loadu_si256(vp++); - t1 = _mm256_loadu_si256(vp++); + t0 = _mm256_load_si256(vp++); + t1 = _mm256_load_si256(vp++); CONVERT_I16_F32_BLOCK(t0); CONVERT_I16_F32_BLOCK(t1); @@ -50,7 +50,7 @@ void TEMPLATE_FUNC_NAME(const int16_t *__restrict indata, for(; i >= 32; i -= 32) { - t0 = _mm256_loadu_si256(vp++); + t0 = _mm256_load_si256(vp++); CONVERT_I16_F32_BLOCK(t0); } @@ -59,7 +59,7 @@ void TEMPLATE_FUNC_NAME(const int16_t *__restrict indata, if (i > 0) { const int16_t *ldw = (const int16_t *)vp; for (; i >= 2; i -= 2) { - *(outdata++) = *(ldw++) * inscale; + *(outdata++) = *(ldw++) * CONV_SCALE; } } } diff --git a/src/lib/xdsp/templates/fft_window_cf32_avx2.t b/src/lib/xdsp/templates/fft_window_cf32_avx2.t index 07d0d0c4..ad811d71 100644 --- a/src/lib/xdsp/templates/fft_window_cf32_avx2.t +++ b/src/lib/xdsp/templates/fft_window_cf32_avx2.t @@ -12,8 +12,8 @@ void TEMPLATE_FUNC_NAME(wvlt_fftwf_complex* __restrict in, unsigned fftsz, float __m256 e2 = _mm256_load_ps(&in[i + 8][0]); __m256 e3 = _mm256_load_ps(&in[i + 12][0]); - __m256 w0 = _mm256_load_ps(&wnd[i + 0]); - __m256 w1 = _mm256_load_ps(&wnd[i + 8]); + __m256 w0 = _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)&wnd[i + 0])); + __m256 w1 = _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)&wnd[i + 8])); __m256 dw0 = _mm256_permutevar8x32_ps(w0, sh0); __m256 dw1 = _mm256_permutevar8x32_ps(w0, sh1); diff --git a/src/lib/xdsp/utests/fft_window_cf32_utest.c b/src/lib/xdsp/utests/fft_window_cf32_utest.c index 2125c9ad..1b6a90e2 100644 --- a/src/lib/xdsp/utests/fft_window_cf32_utest.c +++ b/src/lib/xdsp/utests/fft_window_cf32_utest.c @@ -9,7 +9,7 @@ #include "fft_window_functions.h" #define FFT_SIZE (65536) -static const unsigned packet_lens[3] = { 256, 4096, FFT_SIZE }; +static const unsigned packet_lens[3] = { 4096, 16384, FFT_SIZE }; #define SPEED_MEASURE_ITERS 1000000 #define EPSILON 1E-4 @@ -24,10 +24,9 @@ static generic_opts_t max_opt = OPT_GENERIC; static void recalcWnd(unsigned fft_size) { - for(unsigned i = 0; i < fft_size * 2; i += 2) + for(unsigned i = 0; i < fft_size; i++) { wnd[i] = (1 - cos(2 * M_PI * i / fft_size)) / 2; - wnd[i+1] = (1 - cos(2 * M_PI * (i + 1) / fft_size)) / 2; } } @@ -37,13 +36,13 @@ static void setup() res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); - res = res ? res : posix_memalign((void**)&wnd, ALIGN_BYTES, sizeof(float) * 2 * FFT_SIZE); + res = res ? res : posix_memalign((void**)&wnd, ALIGN_BYTES, sizeof(float) * FFT_SIZE); ck_assert_int_eq(res, 0); for(unsigned i = 0; i < FFT_SIZE; ++i) { - in[i][0] = 100.0f * (float)(rand()) / (float)RAND_MAX; - in[i][1] = -100.0f * (float)(rand()) / (float)RAND_MAX; + in[i][0] = 1.0f * (float)(rand()) / (float)RAND_MAX; + in[i][1] = -1.0f * (float)(rand()) / (float)RAND_MAX; } recalcWnd(FFT_SIZE); diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index 2aacdc2e..cf9b20bc 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -77,7 +77,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, conv_ci12_4cf32_suite()); // #else - sr = srunner_create(fftad_suite()); + sr = srunner_create(conv_i16_f32_suite()); //srunner_add_suite(sr, conv_2ci16_ci16_suite()); //srunner_add_suite(sr, conv_f32_i12_suite()); //srunner_add_suite(sr, conv_2cf32_ci12_suite()); From ab5e474f9ad3ca26ca178e5ef80b3c81ba9d7407 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 7 Nov 2025 11:37:54 +0400 Subject: [PATCH 232/397] dsdr: fix configuration message --- src/lib/device/m2_dsdr/m2_dsdr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index e9c7002a..4d7603e0 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1483,13 +1483,12 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->cfg_afe_type = afeType; d->jesdv = jesdv; - USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s\n", d->afecongiguration); - USDR_LOG("XDEV", USDR_LOG_WARNING, "AFE type JESD204%c CH_TX=%02x CH_RX=%02x\n", (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx); + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s, Type: %d, AFE: %d, JESD204%c, CH_TX=%02x, CH_RX=%02x", + d->afecongiguration, d->type, d->cfg_afe_type, (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx); if (getenv("SKIPAFE")) { d->type = DSDR_KCU116_EVM; } - if (d->type == DSDR_KCU116_EVM) { USDR_LOG("XDEV", USDR_LOG_ERROR, "Skipping AFE initialization! SR=%.2f\n", d->adc_rate / 1e6); res = res ? res : afe79xx_create_dummy(&d->st); From 3313e212bc6af7ed024ba1ce5385349f101b0519 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 7 Nov 2025 11:58:08 +0400 Subject: [PATCH 233/397] hiper: turnoff IF LNA by default --- src/lib/device/m2_dsdr/dsdr_hiper.c | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 2fe6d1d3..5d579b6c 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -142,6 +142,17 @@ static const uint64_t s_filerbank_ranges[] = { }; +enum led_rtx_vals { + LED_TRX_RXO = 0, + LED_TRX_OFF = 1, + LED_TRX_TRX = 2, + LED_TRX_TXO = 3, +}; + +enum led_rx_cals { + LED_RX_ON = 0, + LED_RX_OFF = 1, +}; static int dsdr_hiper_debug_lms8001_u1_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -810,15 +821,13 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8a_chip // TODO: sanity check - // Reset all LMS8001 - // res = res ? res : tca6424a_reg16_set(dev, dfe->subdev, I2C_TCA6424AR_U115, TCA6424_OUT0, 0xffff); - // res = res ? res : tca6424a_reg8_set(dev, dfe->subdev, I2C_TCA6424AR_U115, TCA6424_OUT0 + 2, 0xff); - // if (res) - // return res; - + dfe->fe_ctrl_regs[IF_LNA- SW_RX_FILTER] = MAKE_M2_DSDR_E_IF_LNA(IF_LNA_CTRL_CHD_DISABLE, IF_LNA_CTRL_CHC_DISABLE, IF_LNA_CTRL_CHB_DISABLE, IF_LNA_CTRL_CHA_DISABLE); dfe->fe_ctrl_regs[ENABLE - SW_RX_FILTER] = MAKE_M2_DSDR_E_ENABLE(1, 0, 1, 1, 1, 1, 1, 1); dfe->fe_ctrl_regs[LMS8001_RESET - SW_RX_FILTER] = MAKE_M2_DSDR_E_LMS8001_RESET(1, 1, 1, 1, 1, 1, 1); dfe->fe_ctrl_regs[AUX_CTRL - SW_RX_FILTER] = MAKE_M2_DSDR_E_AUX_CTRL(0, 0, 0, 0, 1, 1, 1, 1); + + dfe->fe_ctrl_regs[LED_TRX_CTRL - SW_RX_FILTER] = MAKE_M2_DSDR_E_LED_TRX_CTRL(LED_TRX_OFF, LED_TRX_OFF, LED_TRX_OFF, LED_TRX_OFF); + dfe->fe_ctrl_regs[LEDRX_CH_CTRL - SW_RX_FILTER] = MAKE_M2_DSDR_E_LEDRX_CH_CTRL(LED_RX_OFF, LED_RX_OFF, LED_RX_OFF, LED_RX_OFF, 0, 0, 0, 0); for (unsigned k = 0; k < SIZEOF_ARRAY(dfe->fe_ctrl_regs); k++) { res = res ? res : _hiper_update_expander_vreg(dfe, k, dfe->fe_ctrl_regs[k]); } @@ -1329,18 +1338,6 @@ static void _hiper_fbank_map(unsigned filsel, unsigned *bout, unsigned *bin) } } -enum led_rtx_vals { - LED_TRX_RXO = 0, - LED_TRX_OFF = 1, - LED_TRX_TRX = 2, - LED_TRX_TXO = 3, -}; - -enum led_rx_cals { - LED_RX_ON = 0, - LED_RX_OFF = 1, -}; - // Switch on RX path => ANT_RX external port / rfsw_rxtx / LB enum rfsw_tddfdd_bits { EXP_TDDFDD_SD = TDD_FDD_OPTS_REV0_LNA_TO_RX_____REV2_SHUTDOWN, // LB SW is on From 10ba32817ae026dc90dcd38e356d41f3d5a48f8c Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Fri, 7 Nov 2025 18:21:03 +0400 Subject: [PATCH 234/397] Hyper v2 support: fixed swapped gpios(2). --- src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml index a400a07d..464006fe 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml @@ -54,8 +54,8 @@ x-r2rx-in-opts: &r2rx-in-opts x-r2rx-out-opts: &r2rx-out-opts 0b00: DISABLE - 0b01: RX_LOW - 0b10: RX_HI + 0b01: RX_HI + 0b10: RX_LOW 0b11: RX_BYPASS From 5db6c6f1e3e3357c94e6f97651d93bab30c09d9a Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 7 Nov 2025 23:07:51 +0300 Subject: [PATCH 235/397] fft_window_ci16_cf32_function added (g&avx2) + utest + minors --- src/lib/xdsp/conv.h | 10 ++ src/lib/xdsp/fft_window_functions.c | 24 +++ src/lib/xdsp/fft_window_functions.h | 6 + .../xdsp/templates/conv_ci12_2cf32_avx512bw.t | 3 - src/lib/xdsp/templates/conv_i12_f32_avx2.inc | 4 +- .../xdsp/templates/conv_i12_f32_avx512bw.inc | 4 +- src/lib/xdsp/templates/conv_i12_i16_avx2.inc | 2 +- .../xdsp/templates/conv_i12_i16_avx512bw.inc | 4 +- src/lib/xdsp/templates/conv_i16_f32_avx2.t | 8 +- src/lib/xdsp/templates/conv_i16_f32_neon.t | 2 +- .../templates/fft_window_ci16_cf32_avx2.t | 43 +++++ .../templates/fft_window_ci16_cf32_generic.t | 12 ++ src/lib/xdsp/utests/CMakeLists.txt | 1 + .../xdsp/utests/fft_window_ci16_cf32_utest.c | 160 ++++++++++++++++++ src/lib/xdsp/utests/xdsp_utest_suite.c | 6 +- 15 files changed, 271 insertions(+), 18 deletions(-) create mode 100644 src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t create mode 100644 src/lib/xdsp/templates/fft_window_ci16_cf32_generic.t create mode 100644 src/lib/xdsp/utests/fft_window_ci16_cf32_utest.c diff --git a/src/lib/xdsp/conv.h b/src/lib/xdsp/conv.h index 4bfdcc06..b7d25f33 100644 --- a/src/lib/xdsp/conv.h +++ b/src/lib/xdsp/conv.h @@ -6,6 +6,7 @@ #include #include +#include "usdr_port.h" #include "vbase.h" #define I16RND(x) (int16_t)(x) @@ -122,6 +123,7 @@ struct fft_accumulate_data { typedef struct fft_accumulate_data fft_acc_t; typedef float wvlt_fftwf_complex[2]; +typedef int16_t wvlt_fftwi16_complex[2]; typedef void (*fftad_init_function_t) (fft_acc_t* __restrict p, unsigned fftsz); @@ -237,4 +239,12 @@ void tr_##conv_fn (wvlt_fftwf_complex* __restrict in, unsigned fftsz, float* __r wvlt_fftwf_complex* __restrict out) \ { conv_fn(in, fftsz, wnd, out); } +typedef void (*fft_window_ci16_cf32_function_t) + (wvlt_fftwi16_complex* __restrict in, unsigned fftsz, float* __restrict wnd, wvlt_fftwf_complex* __restrict out); + +#define DECLARE_TR_FUNC_FFT_WINDOW_CI16_CF32(conv_fn) \ +void tr_##conv_fn (wvlt_fftwi16_complex* __restrict in, unsigned fftsz, float* __restrict wnd, \ + wvlt_fftwf_complex* __restrict out) \ +{ conv_fn(in, fftsz, wnd, out); } + #endif diff --git a/src/lib/xdsp/fft_window_functions.c b/src/lib/xdsp/fft_window_functions.c index 7b9d7301..c6e17cde 100644 --- a/src/lib/xdsp/fft_window_functions.c +++ b/src/lib/xdsp/fft_window_functions.c @@ -13,6 +13,18 @@ VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) DECLARE_TR_FUNC_FFT_WINDOW_CF32(fft_window_cf32_avx2) #endif +#define TEMPLATE_FUNC_NAME fft_window_ci16_cf32_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/fft_window_ci16_cf32_generic.t" +DECLARE_TR_FUNC_FFT_WINDOW_CI16_CF32(fft_window_ci16_cf32_generic) + +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME fft_window_ci16_cf32_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/fft_window_ci16_cf32_avx2.t" +DECLARE_TR_FUNC_FFT_WINDOW_CI16_CF32(fft_window_ci16_cf32_avx2) +#endif + fft_window_cf32_function_t fft_window_cf32_c(generic_opts_t cpu_cap, const char** sfunc) { const char* fname; @@ -24,3 +36,15 @@ fft_window_cf32_function_t fft_window_cf32_c(generic_opts_t cpu_cap, const char* if (sfunc) *sfunc = fname; return fn; } + +fft_window_ci16_cf32_function_t fft_window_ci16_cf32_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + fft_window_ci16_cf32_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_fft_window_ci16_cf32_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_fft_window_ci16_cf32_avx2, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} diff --git a/src/lib/xdsp/fft_window_functions.h b/src/lib/xdsp/fft_window_functions.h index c4e90a35..a08a5572 100644 --- a/src/lib/xdsp/fft_window_functions.h +++ b/src/lib/xdsp/fft_window_functions.h @@ -9,12 +9,18 @@ extern "C" { #endif fft_window_cf32_function_t fft_window_cf32_c(generic_opts_t cpu_cap, const char** sfunc); +fft_window_ci16_cf32_function_t fft_window_ci16_cf32_c(generic_opts_t cpu_cap, const char** sfunc); static inline void fft_window_cf32(wvlt_fftwf_complex* in, unsigned fftsz, float* wnd, wvlt_fftwf_complex* out) { return (*fft_window_cf32_c(cpu_vcap_get(), NULL))(in, fftsz, wnd, out); } +static inline void fft_window_ci16_cf32(wvlt_fftwi16_complex* in, unsigned fftsz, float* wnd, wvlt_fftwf_complex* out) +{ + return (*fft_window_ci16_cf32_c(cpu_vcap_get(), NULL))(in, fftsz, wnd, out); +} + #ifdef __cplusplus } #endif diff --git a/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t b/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t index 3a7ca0b8..ccaa216b 100644 --- a/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t +++ b/src/lib/xdsp/templates/conv_ci12_2cf32_avx512bw.t @@ -22,9 +22,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, __m512i y0, y1; __m512 res0, res1, res2, res3; - const __m512i idx0 = _mm512_set_epi64(14,12,10,8,6,4,2,0); - const __m512i idx1 = _mm512_set_epi64(15,13,11,9,7,5,3,1); - for(; i >= 96; i -= 96) { y0 = _mm512_maskz_loadu_epi64(0b00111111, (const long long*)(in + 0)); diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx2.inc b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc index bc1dd99e..8125e1b4 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx2.inc +++ b/src/lib/xdsp/templates/conv_i12_f32_avx2.inc @@ -1,5 +1,5 @@ -const __m256 scale = _mm256_set1_ps(CONV_SCALE); -const __m256 scale2 = _mm256_set1_ps(SCALE2); +UNUSED const __m256 scale = _mm256_set1_ps(CONV_SCALE); +UNUSED const __m256 scale2 = _mm256_set1_ps(SCALE2); /* * reg: diff --git a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc index f8178ac5..bee9eb28 100644 --- a/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc +++ b/src/lib/xdsp/templates/conv_i12_f32_avx512bw.inc @@ -1,5 +1,5 @@ -const __m512 scale = _mm512_set1_ps(CONV_SCALE); -const __m512 scale2 = _mm512_set1_ps(SCALE2); +UNUSED const __m512 scale = _mm512_set1_ps(CONV_SCALE); +UNUSED const __m512 scale2 = _mm512_set1_ps(SCALE2); #define CONVERT_I12_F32_BLOCK(reg, res0, res1) \ { \ diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx2.inc b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc index 5828ae1a..9c3493fb 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx2.inc +++ b/src/lib/xdsp/templates/conv_i12_i16_avx2.inc @@ -1,7 +1,7 @@ const __m256i load_mask = _mm256_set_epi64x(0, -1, -1, -1); const __m256i mask0 = _mm256_set1_epi64x(0xfff00000fff00000); -const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); +UNUSED const __m256i mask1 = _mm256_set1_epi64x(0x0000fff00000fff0); const __m256i permmask = _mm256_set_epi32(5, 4, 3, 7, 6, 2, 1, 0); const __m256i shfl = _mm256_set_epi8( diff --git a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc index ebedb270..63931311 100644 --- a/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc +++ b/src/lib/xdsp/templates/conv_i12_i16_avx512bw.inc @@ -1,5 +1,5 @@ const __m512i mask0 = _mm512_set1_epi64(0xfff00000fff00000); -const __m512i mask1 = _mm512_set1_epi64(0x0000fff00000fff0); +UNUSED const __m512i mask1 = _mm512_set1_epi64(0x0000fff00000fff0); const __m512i permmask = _mm512_set_epi32(11,10,9, 15,14, 8,7,6, 5,4,3, 13,12, 2,1,0); const __m512i shfl = _mm512_set_epi8( @@ -12,7 +12,7 @@ const __m512i shfl = _mm512_set_epi8( 0x0b, 0x0a, 0x09, 0x80, 0x08, 0x07, 0x06, 0x80, 0x05, 0x04, 0x03, 0x80, 0x02, 0x01, 0x00, 0x80); -const __m512i pidx = _mm512_set_epi64(7,5,3,1,6,4,2,0); +UNUSED const __m512i pidx = _mm512_set_epi64(7,5,3,1,6,4,2,0); #define CONVERT_I12_I16_BLOCK(reg, result) \ { \ diff --git a/src/lib/xdsp/templates/conv_i16_f32_avx2.t b/src/lib/xdsp/templates/conv_i16_f32_avx2.t index b666e3d6..0246d53e 100644 --- a/src/lib/xdsp/templates/conv_i16_f32_avx2.t +++ b/src/lib/xdsp/templates/conv_i16_f32_avx2.t @@ -56,11 +56,9 @@ void TEMPLATE_FUNC_NAME(const int16_t *__restrict indata, #undef CONVERT_I16_F32_BLOCK - if (i > 0) { - const int16_t *ldw = (const int16_t *)vp; - for (; i >= 2; i -= 2) { - *(outdata++) = *(ldw++) * CONV_SCALE; - } + const int16_t *ldw = (const int16_t *)vp; + for (; i >= 2; i -= 2) { + *(outdata++) = *(ldw++) * CONV_SCALE; } } diff --git a/src/lib/xdsp/templates/conv_i16_f32_neon.t b/src/lib/xdsp/templates/conv_i16_f32_neon.t index e8118fa2..b04feeba 100644 --- a/src/lib/xdsp/templates/conv_i16_f32_neon.t +++ b/src/lib/xdsp/templates/conv_i16_f32_neon.t @@ -45,7 +45,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, i -= 8; } - while(i) + while(i >= 2) { *(out++) = *(in++) * CONV_SCALE; i -= 2; diff --git a/src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t b/src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t new file mode 100644 index 00000000..d9b529b4 --- /dev/null +++ b/src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t @@ -0,0 +1,43 @@ +static +void TEMPLATE_FUNC_NAME(wvlt_fftwi16_complex* __restrict in, unsigned fftsz, float* __restrict wnd, + wvlt_fftwf_complex* __restrict out) +{ + const __m256i sh0 = _mm256_setr_epi32(0, 0, 1, 1, 2, 2, 3, 3); + const __m256i sh1 = _mm256_setr_epi32(4, 4, 5, 5, 6, 6, 7, 7); + + for(unsigned i = 0; i < fftsz; i += 16) + { + __m256i i0 = _mm256_load_si256((__m256i*)&in[i + 0][0]); + __m256i i1 = _mm256_load_si256((__m256i*)&in[i + 8][0]); + + __m256 w0 = _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)&wnd[i + 0])); + __m256 w1 = _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)&wnd[i + 8])); + + __m256 dw0 = _mm256_permutevar8x32_ps(w0, sh0); + __m256 dw1 = _mm256_permutevar8x32_ps(w0, sh1); + __m256 dw2 = _mm256_permutevar8x32_ps(w1, sh0); + __m256 dw3 = _mm256_permutevar8x32_ps(w1, sh1); + + __m256i d0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(i0)); + __m256i d1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(i0, 1)); + __m256i d2 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(i1)); + __m256i d3 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(i1, 1)); + + __m256 e0 = _mm256_cvtepi32_ps(d0); + __m256 e1 = _mm256_cvtepi32_ps(d1); + __m256 e2 = _mm256_cvtepi32_ps(d2); + __m256 e3 = _mm256_cvtepi32_ps(d3); + + __m256 r0 = _mm256_mul_ps(e0, dw0); + __m256 r1 = _mm256_mul_ps(e1, dw1); + __m256 r2 = _mm256_mul_ps(e2, dw2); + __m256 r3 = _mm256_mul_ps(e3, dw3); + + _mm256_store_ps(&out[i + 0][0], r0); + _mm256_store_ps(&out[i + 4][0], r1); + _mm256_store_ps(&out[i + 8][0], r2); + _mm256_store_ps(&out[i + 12][0], r3); + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/fft_window_ci16_cf32_generic.t b/src/lib/xdsp/templates/fft_window_ci16_cf32_generic.t new file mode 100644 index 00000000..c7de2896 --- /dev/null +++ b/src/lib/xdsp/templates/fft_window_ci16_cf32_generic.t @@ -0,0 +1,12 @@ +static +void TEMPLATE_FUNC_NAME(wvlt_fftwi16_complex* __restrict in, unsigned fftsz, float* __restrict wnd, + wvlt_fftwf_complex* __restrict out) +{ + for(unsigned i = 0; i < fftsz; ++i) + { + out[i][0] = wnd[i] * in[i][0]; //wnd[i] must be normalized! + out[i][1] = wnd[i] * in[i][1]; + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/CMakeLists.txt b/src/lib/xdsp/utests/CMakeLists.txt index 469a0119..31e657ce 100644 --- a/src/lib/xdsp/utests/CMakeLists.txt +++ b/src/lib/xdsp/utests/CMakeLists.txt @@ -16,6 +16,7 @@ set(TEST_SUIT_SRCS xfft_fftad_utest.c xfft_rtsa_utest.c fft_window_cf32_utest.c + fft_window_ci16_cf32_utest.c wvlt_sincos_i16_utest.c conv_4ci16_ci16_utest.c conv_ci16_4ci16_utest.c diff --git a/src/lib/xdsp/utests/fft_window_ci16_cf32_utest.c b/src/lib/xdsp/utests/fft_window_ci16_cf32_utest.c new file mode 100644 index 00000000..aae826c8 --- /dev/null +++ b/src/lib/xdsp/utests/fft_window_ci16_cf32_utest.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "fft_window_functions.h" + +#define FFT_SIZE (65536) +static const unsigned packet_lens[3] = { 4096, 16384, FFT_SIZE }; + +#define SPEED_MEASURE_ITERS 1000000 +#define EPSILON 1E-4 +#define CONV_SCALE (1.0f/32767) + +static wvlt_fftwi16_complex* in = NULL; +static wvlt_fftwf_complex* out = NULL; +static wvlt_fftwf_complex* out_etalon = NULL; +static float* wnd = NULL; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void recalcWnd(unsigned fft_size) +{ + for(unsigned i = 0; i < fft_size; i++) + { + wnd[i] = CONV_SCALE * (1 - cos(2 * M_PI * i / fft_size)) / 2; + } +} + +static void setup() +{ + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, sizeof(wvlt_fftwi16_complex) * FFT_SIZE); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, sizeof(wvlt_fftwf_complex) * FFT_SIZE); + res = res ? res : posix_memalign((void**)&wnd, ALIGN_BYTES, sizeof(float) * FFT_SIZE); + ck_assert_int_eq(res, 0); + + for(unsigned i = 0; i < FFT_SIZE; ++i) + { + in[i][0] = 32767 * (float)(rand()) / (float)RAND_MAX; + in[i][1] = -32768 * (float)(rand()) / (float)RAND_MAX; + } + + recalcWnd(FFT_SIZE); +} + +static void teardown(void) +{ + free(in); + free(out); + free(out_etalon); + free(wnd); +} + +static int32_t is_equal() +{ + for(unsigned i = 0; i < FFT_SIZE; i++) + { + if(fabs(out[i][0] - out_etalon[i][0]) > EPSILON) return i; + if(fabs(out[i][1] - out_etalon[i][1]) > EPSILON) return i; + } + return -1; +} + +START_TEST(wnd_check) +{ + generic_opts_t opt = max_opt; + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + fft_window_ci16_cf32_c(OPT_GENERIC, NULL)(in, FFT_SIZE, wnd, out_etalon); + last_fn_name = NULL; + const char* fn_name = NULL; + fft_window_ci16_cf32_function_t fn = NULL; + + while(opt != OPT_GENERIC) + { + fn = fft_window_ci16_cf32_c(opt, &fn_name); + + if(last_fn_name && !strcmp(last_fn_name, fn_name)) + { + --opt; + continue; + } + + last_fn_name = fn_name; + fn(in, FFT_SIZE, wnd, out); + + int res = is_equal(); + fprintf(stderr, "%-30s\t", fn_name); + (res >= 0) ? fprintf(stderr, "\tFAILED!\n") : fprintf(stderr, "\tOK!\n"); +#if 1 + if(res >= 0) + { + unsigned i = res; + fprintf(stderr, "TEST > i:%u in=(%d,%d) out=(%.6f,%.6f) <---> out_etalon=(%.6f,%.6f)\n", + i, in[i][0], in[i][1], out[i][0], out[i][1], out_etalon[i][0], out_etalon[i][1]); + } +#endif + ck_assert_int_eq( res, -1 ); + --opt; + } +} +END_TEST + +START_TEST(wnd_speed) +{ + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + const char* fn_name = NULL; + fft_window_ci16_cf32_function_t fn = NULL; + + unsigned size = packet_lens[_i]; + + last_fn_name = NULL; + generic_opts_t opt = max_opt; + + fprintf(stderr, "**** packet: %u elems, iters: %u ***\n", size, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + fn = fft_window_ci16_cf32_c(opt, &fn_name); + if(last_fn_name && !strcmp(last_fn_name, fn_name)) + { + --opt; + continue; + } + last_fn_name = fn_name; + fprintf(stderr, "%-30s\t", fn_name); + + //warming + for(unsigned i = 0; i < 100; ++i) (*fn)(in, size, wnd, out); + + //measuring + uint64_t tk = clock_get_time(); + for(unsigned i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(in, size, wnd, out); + uint64_t tk1 = clock_get_time() - tk; + + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 cycle, ave speed = %" PRIu64 " cycles/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + + --opt; + } +} +END_TEST + +Suite * fft_window_ci16_cf32_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("fft_window_ci16_cf32_functions"); + + ADD_REGRESS_TEST(s, wnd_check); + ADD_PERF_LOOP_TEST(s, wnd_speed, 300, 0, 3); + + return s; +} diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index cf9b20bc..ebad42e7 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -15,6 +15,7 @@ Suite * conv_2ci16_ci16_suite(void); Suite * fftad_suite(void); Suite * rtsa_suite(void); Suite * fft_window_cf32_suite(void); +Suite * fft_window_ci16_cf32_suite(void); Suite * conv_i12_f32_suite(void); Suite * conv_ci12_2cf32_suite(void); Suite * conv_f32_i12_suite(void); @@ -77,8 +78,9 @@ int main(int argc, char** argv) srunner_add_suite(sr, conv_ci12_4cf32_suite()); // #else - sr = srunner_create(conv_i16_f32_suite()); - //srunner_add_suite(sr, conv_2ci16_ci16_suite()); + //sr = srunner_create(conv_i16_f32_suite()); + sr = srunner_create(fft_window_ci16_cf32_suite()); + //srunner_add_suite(sr, fft_window_cf32_suite()); //srunner_add_suite(sr, conv_f32_i12_suite()); //srunner_add_suite(sr, conv_2cf32_ci12_suite()); #endif From fd51884a3edde357b46233a28bec1129d2f9eae2 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sat, 8 Nov 2025 21:53:39 +0300 Subject: [PATCH 236/397] add AVX512 funcs for fft windows & i16-f32 --- src/lib/xdsp/conv_i16_f32_2.c | 8 + src/lib/xdsp/fft_window_functions.c | 16 ++ .../xdsp/templates/conv_i16_f32_avx512bw.t | 138 ++++++++++++++++++ .../xdsp/templates/fft_window_cf32_avx512bw.t | 37 +++++ .../templates/fft_window_ci16_cf32_avx2.t | 2 + .../templates/fft_window_ci16_cf32_avx512bw.t | 93 ++++++++++++ 6 files changed, 294 insertions(+) create mode 100644 src/lib/xdsp/templates/conv_i16_f32_avx512bw.t create mode 100644 src/lib/xdsp/templates/fft_window_cf32_avx512bw.t create mode 100644 src/lib/xdsp/templates/fft_window_ci16_cf32_avx512bw.t diff --git a/src/lib/xdsp/conv_i16_f32_2.c b/src/lib/xdsp/conv_i16_f32_2.c index 79b35d9e..98f04e84 100644 --- a/src/lib/xdsp/conv_i16_f32_2.c +++ b/src/lib/xdsp/conv_i16_f32_2.c @@ -33,6 +33,13 @@ VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) DECLARE_TR_FUNC_1_1(conv_i16_f32_avx2) #endif +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME conv_i16_f32_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/conv_i16_f32_avx512bw.t" +DECLARE_TR_FUNC_1_1(conv_i16_f32_avx512bw) +#endif + #ifdef WVLT_NEON #define TEMPLATE_FUNC_NAME conv_i16_f32_neon VWLT_ATTRIBUTE(optimize("-O3")) @@ -49,6 +56,7 @@ conv_function_t conv_get_i16_f32_c(generic_opts_t cpu_cap, const char** sfunc) SELECT_SSE2_FN(fn, fname, tr_conv_i16_f32_sse2, cpu_cap); SELECT_AVX_FN(fn, fname, tr_conv_i16_f32_avx, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_conv_i16_f32_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_conv_i16_f32_avx512bw, cpu_cap); SELECT_NEON_FN(fn, fname, tr_conv_i16_f32_neon, cpu_cap); if (sfunc) *sfunc = fname; diff --git a/src/lib/xdsp/fft_window_functions.c b/src/lib/xdsp/fft_window_functions.c index c6e17cde..44302804 100644 --- a/src/lib/xdsp/fft_window_functions.c +++ b/src/lib/xdsp/fft_window_functions.c @@ -13,6 +13,13 @@ VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) DECLARE_TR_FUNC_FFT_WINDOW_CF32(fft_window_cf32_avx2) #endif +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME fft_window_cf32_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/fft_window_cf32_avx512bw.t" +DECLARE_TR_FUNC_FFT_WINDOW_CF32(fft_window_cf32_avx512bw) +#endif + #define TEMPLATE_FUNC_NAME fft_window_ci16_cf32_generic VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/fft_window_ci16_cf32_generic.t" @@ -25,6 +32,13 @@ VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) DECLARE_TR_FUNC_FFT_WINDOW_CI16_CF32(fft_window_ci16_cf32_avx2) #endif +#ifdef WVLT_AVX512BW +#define TEMPLATE_FUNC_NAME fft_window_ci16_cf32_avx512bw +VWLT_ATTRIBUTE(optimize("-O3"), target("avx512bw")) +#include "templates/fft_window_ci16_cf32_avx512bw.t" +DECLARE_TR_FUNC_FFT_WINDOW_CI16_CF32(fft_window_ci16_cf32_avx512bw) +#endif + fft_window_cf32_function_t fft_window_cf32_c(generic_opts_t cpu_cap, const char** sfunc) { const char* fname; @@ -32,6 +46,7 @@ fft_window_cf32_function_t fft_window_cf32_c(generic_opts_t cpu_cap, const char* SELECT_GENERIC_FN(fn, fname, tr_fft_window_cf32_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_fft_window_cf32_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_fft_window_cf32_avx512bw, cpu_cap); if (sfunc) *sfunc = fname; return fn; @@ -44,6 +59,7 @@ fft_window_ci16_cf32_function_t fft_window_ci16_cf32_c(generic_opts_t cpu_cap, c SELECT_GENERIC_FN(fn, fname, tr_fft_window_ci16_cf32_generic, cpu_cap); SELECT_AVX2_FN(fn, fname, tr_fft_window_ci16_cf32_avx2, cpu_cap); + SELECT_AVX512BW_FN(fn, fname, tr_fft_window_ci16_cf32_avx512bw, cpu_cap); if (sfunc) *sfunc = fname; return fn; diff --git a/src/lib/xdsp/templates/conv_i16_f32_avx512bw.t b/src/lib/xdsp/templates/conv_i16_f32_avx512bw.t new file mode 100644 index 00000000..fe59712d --- /dev/null +++ b/src/lib/xdsp/templates/conv_i16_f32_avx512bw.t @@ -0,0 +1,138 @@ +#ifndef UNWRAP_CNT +#define UNWRAP_CNT 4 +#endif + +#if UNWRAP_CNT > 4 +#error Maximum spported UNWRAP_CNT is 4! +#endif + +static +void TEMPLATE_FUNC_NAME(const int16_t *__restrict indata, + unsigned indatabsz, + float *__restrict outdata, + unsigned outdatabsz) +{ + size_t i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + const __m512i* vp = (const __m512i* )indata; + __m512 scale = _mm512_set1_ps(CONV_SCALE); + __m512i t0, t1; + __m512 f0, f1, f2, f3; +#if UNWRAP_CNT > 1 + __m512i t2, t3; + __m512 f4, f5, f6, f7; +#if UNWRAP_CNT > 2 + __m512i t4, t5; + __m512 f8, f9, fA, fB; +#if UNWRAP_CNT > 3 + __m512i t6, t7; + __m512 fC, fD, fE, fF; +#endif +#endif +#endif + +#define CONVERT_I16_F32_BLOCK(reg0, reg1, f0, f1, f2, f3) \ + { \ + __m512i d0 = _mm512_cvtepi16_epi32(_mm512_castsi512_si256(reg0)); \ + __m512i d1 = _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(reg0, 1)); \ + __m512i d2 = _mm512_cvtepi16_epi32(_mm512_castsi512_si256(reg1)); \ + __m512i d3 = _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(reg1, 1)); \ + \ + f0 = _mm512_cvtepi32_ps(d0); \ + f1 = _mm512_cvtepi32_ps(d1); \ + f2 = _mm512_cvtepi32_ps(d2); \ + f3 = _mm512_cvtepi32_ps(d3); \ + \ + f0 = _mm512_mul_ps(f0, scale); \ + f1 = _mm512_mul_ps(f1, scale); \ + f2 = _mm512_mul_ps(f2, scale); \ + f3 = _mm512_mul_ps(f3, scale); \ + \ + _mm512_store_ps(outdata, f0); \ + _mm512_store_ps(outdata, f1); \ + } +// CONVERT_I16_F32_BLOCK end + + + while(i >= UNWRAP_CNT * 128) + { + t0 = _mm512_load_si512(vp++); + t1 = _mm512_load_si512(vp++); +#if UNWRAP_CNT > 1 + t2 = _mm512_load_si512(vp++); + t3 = _mm512_load_si512(vp++); +#if UNWRAP_CNT > 2 + t4 = _mm512_load_si512(vp++); + t5 = _mm512_load_si512(vp++); +#if UNWRAP_CNT > 3 + t6 = _mm512_load_si512(vp++); + t7 = _mm512_load_si512(vp++); +#endif +#endif +#endif + + CONVERT_I16_F32_BLOCK(t0, t1, f0, f1, f2, f3); +#if UNWRAP_CNT > 1 + CONVERT_I16_F32_BLOCK(t2, t3, f4, f5, f6, f7); +#if UNWRAP_CNT > 2 + CONVERT_I16_F32_BLOCK(t4, t5, f8, f9, fA, fB); +#if UNWRAP_CNT > 3 + CONVERT_I16_F32_BLOCK(t6, t7, fC, fD, fE, fF); +#endif +#endif +#endif + + _mm512_store_ps(outdata + 0x00, f0); + _mm512_store_ps(outdata + 0x10, f1); + _mm512_store_ps(outdata + 0x20, f2); + _mm512_store_ps(outdata + 0x30, f3); +#if UNWRAP_CNT > 1 + _mm512_store_ps(outdata + 0x40, f4); + _mm512_store_ps(outdata + 0x50, f5); + _mm512_store_ps(outdata + 0x60, f6); + _mm512_store_ps(outdata + 0x70, f7); +#if UNWRAP_CNT > 2 + _mm512_store_ps(outdata + 0x80, f8); + _mm512_store_ps(outdata + 0x90, f9); + _mm512_store_ps(outdata + 0xa0, fA); + _mm512_store_ps(outdata + 0xb0, fB); +#if UNWRAP_CNT > 3 + _mm512_store_ps(outdata + 0xc0, fC); + _mm512_store_ps(outdata + 0xd0, fD); + _mm512_store_ps(outdata + 0xe0, fE); + _mm512_store_ps(outdata + 0xf0, fF); +#endif +#endif +#endif + + outdata += UNWRAP_CNT * 64; + i -= UNWRAP_CNT * 128; + } + + while(i >= 128) + { + t0 = _mm512_load_si512(vp++); + t1 = _mm512_load_si512(vp++); + + CONVERT_I16_F32_BLOCK(t0, t1, f0, f1, f2, f3); + + _mm512_store_ps(outdata + 0, f0); + _mm512_store_ps(outdata + 16, f1); + _mm512_store_ps(outdata + 32, f2); + _mm512_store_ps(outdata + 48, f3); + + outdata += 64; + i -= 128; + } + +#undef CONVERT_I16_F32_BLOCK + + const int16_t *ldw = (const int16_t *)vp; + for (; i >= 2; i -= 2) { + *(outdata++) = *(ldw++) * CONV_SCALE; + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/fft_window_cf32_avx512bw.t b/src/lib/xdsp/templates/fft_window_cf32_avx512bw.t new file mode 100644 index 00000000..a12e1f41 --- /dev/null +++ b/src/lib/xdsp/templates/fft_window_cf32_avx512bw.t @@ -0,0 +1,37 @@ +static +void TEMPLATE_FUNC_NAME(wvlt_fftwf_complex* __restrict in, unsigned fftsz, float* __restrict wnd, + wvlt_fftwf_complex* __restrict out) +{ + const __m512i idx0 = _mm512_set_epi32( 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1, 0,0); + const __m512i idx1 = _mm512_set_epi32(15,15, 14,14, 13,13, 12,12, 11,11, 10,10, 9,9, 8,8); + + for(unsigned i = 0; i < fftsz; i += 32) + { + __m512 e0 = _mm512_load_ps(&in[i + 0][0]); + __m512 e1 = _mm512_load_ps(&in[i + 8][0]); + __m512 e2 = _mm512_load_ps(&in[i + 16][0]); + __m512 e3 = _mm512_load_ps(&in[i + 24][0]); + + __m512 w0 = _mm512_castsi512_ps(_mm512_stream_load_si512(&wnd[i + 0])); + __m512 w1 = _mm512_castsi512_ps(_mm512_stream_load_si512(&wnd[i + 16])); + //__m512 w0 = _mm512_load_ps(&wnd[i + 0]); + //__m512 w1 = _mm512_load_ps(&wnd[i + 16]); + + __m512 dw0 = _mm512_permutexvar_ps(idx0, w0); + __m512 dw1 = _mm512_permutexvar_ps(idx1, w0); + __m512 dw2 = _mm512_permutexvar_ps(idx0, w1); + __m512 dw3 = _mm512_permutexvar_ps(idx1, w1); + + __m512 r0 = _mm512_mul_ps(e0, dw0); + __m512 r1 = _mm512_mul_ps(e1, dw1); + __m512 r2 = _mm512_mul_ps(e2, dw2); + __m512 r3 = _mm512_mul_ps(e3, dw3); + + _mm512_store_ps(&out[i + 0][0], r0); + _mm512_store_ps(&out[i + 8][0], r1); + _mm512_store_ps(&out[i + 16][0], r2); + _mm512_store_ps(&out[i + 24][0], r3); + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t b/src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t index d9b529b4..8af106d1 100644 --- a/src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t +++ b/src/lib/xdsp/templates/fft_window_ci16_cf32_avx2.t @@ -12,6 +12,8 @@ void TEMPLATE_FUNC_NAME(wvlt_fftwi16_complex* __restrict in, unsigned fftsz, flo __m256 w0 = _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)&wnd[i + 0])); __m256 w1 = _mm256_castsi256_ps(_mm256_stream_load_si256((__m256i*)&wnd[i + 8])); + //__m256 w0 = _mm256_load_ps(&wnd[i + 0]); + //__m256 w1 = _mm256_load_ps(&wnd[i + 8]); __m256 dw0 = _mm256_permutevar8x32_ps(w0, sh0); __m256 dw1 = _mm256_permutevar8x32_ps(w0, sh1); diff --git a/src/lib/xdsp/templates/fft_window_ci16_cf32_avx512bw.t b/src/lib/xdsp/templates/fft_window_ci16_cf32_avx512bw.t new file mode 100644 index 00000000..82d2023d --- /dev/null +++ b/src/lib/xdsp/templates/fft_window_ci16_cf32_avx512bw.t @@ -0,0 +1,93 @@ +#ifndef UNWRAP_CNT +#define UNWRAP_CNT 2 +#endif + +#if UNWRAP_CNT > 2 +#error Maximum spported UNWRAP_CNT is 2! +#endif + +static +void TEMPLATE_FUNC_NAME(wvlt_fftwi16_complex* __restrict in, unsigned fftsz, float* __restrict wnd, + wvlt_fftwf_complex* __restrict out) +{ + const __m512i idx0 = _mm512_set_epi32( 7,7, 6,6, 5,5, 4,4, 3,3, 2,2, 1,1, 0,0); + const __m512i idx1 = _mm512_set_epi32(15,15, 14,14, 13,13, 12,12, 11,11, 10,10, 9,9, 8,8); + + for(unsigned i = 0; i < fftsz; i += UNWRAP_CNT * 32) + { + __m512i i0 = _mm512_load_si512(&in[i + 0][0]); + __m512i i1 = _mm512_load_si512(&in[i + 16][0]); +#if UNWRAP_CNT > 1 + __m512i i2 = _mm512_load_si512(&in[i + 32][0]); + __m512i i3 = _mm512_load_si512(&in[i + 48][0]); +#endif + + __m512 w0 = _mm512_castsi512_ps(_mm512_stream_load_si512(&wnd[i + 0])); + __m512 w1 = _mm512_castsi512_ps(_mm512_stream_load_si512(&wnd[i + 16])); + //__m512 w0 = _mm512_load_ps(&wnd[i + 0]); + //__m512 w1 = _mm512_load_ps(&wnd[i + 16]); +#if UNWRAP_CNT > 1 + __m512 w2 = _mm512_castsi512_ps(_mm512_stream_load_si512(&wnd[i + 32])); + __m512 w3 = _mm512_castsi512_ps(_mm512_stream_load_si512(&wnd[i + 48])); + //__m512 w2 = _mm512_load_ps(&wnd[i + 32]); + //__m512 w3 = _mm512_load_ps(&wnd[i + 48]); +#endif + + __m512 dw0 = _mm512_permutexvar_ps(idx0, w0); + __m512 dw1 = _mm512_permutexvar_ps(idx1, w0); + __m512 dw2 = _mm512_permutexvar_ps(idx0, w1); + __m512 dw3 = _mm512_permutexvar_ps(idx1, w1); +#if UNWRAP_CNT > 1 + __m512 dw4 = _mm512_permutexvar_ps(idx0, w2); + __m512 dw5 = _mm512_permutexvar_ps(idx1, w2); + __m512 dw6 = _mm512_permutexvar_ps(idx0, w3); + __m512 dw7 = _mm512_permutexvar_ps(idx1, w3); +#endif + + __m512i d0 = _mm512_cvtepi16_epi32(_mm512_castsi512_si256(i0)); + __m512i d1 = _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(i0, 1)); + __m512i d2 = _mm512_cvtepi16_epi32(_mm512_castsi512_si256(i1)); + __m512i d3 = _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(i1, 1)); +#if UNWRAP_CNT > 1 + __m512i d4 = _mm512_cvtepi16_epi32(_mm512_castsi512_si256(i2)); + __m512i d5 = _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(i2, 1)); + __m512i d6 = _mm512_cvtepi16_epi32(_mm512_castsi512_si256(i3)); + __m512i d7 = _mm512_cvtepi16_epi32(_mm512_extracti64x4_epi64(i3, 1)); +#endif + + __m512 e0 = _mm512_cvtepi32_ps(d0); + __m512 e1 = _mm512_cvtepi32_ps(d1); + __m512 e2 = _mm512_cvtepi32_ps(d2); + __m512 e3 = _mm512_cvtepi32_ps(d3); +#if UNWRAP_CNT > 1 + __m512 e4 = _mm512_cvtepi32_ps(d4); + __m512 e5 = _mm512_cvtepi32_ps(d5); + __m512 e6 = _mm512_cvtepi32_ps(d6); + __m512 e7 = _mm512_cvtepi32_ps(d7); +#endif + + __m512 r0 = _mm512_mul_ps(e0, dw0); + __m512 r1 = _mm512_mul_ps(e1, dw1); + __m512 r2 = _mm512_mul_ps(e2, dw2); + __m512 r3 = _mm512_mul_ps(e3, dw3); +#if UNWRAP_CNT > 1 + __m512 r4 = _mm512_mul_ps(e4, dw4); + __m512 r5 = _mm512_mul_ps(e5, dw5); + __m512 r6 = _mm512_mul_ps(e6, dw6); + __m512 r7 = _mm512_mul_ps(e7, dw7); +#endif + + _mm512_store_ps(&out[i + 0][0], r0); + _mm512_store_ps(&out[i + 8][0], r1); + _mm512_store_ps(&out[i + 16][0], r2); + _mm512_store_ps(&out[i + 24][0], r3); +#if UNWRAP_CNT > 1 + _mm512_store_ps(&out[i + 32][0], r4); + _mm512_store_ps(&out[i + 40][0], r5); + _mm512_store_ps(&out[i + 48][0], r6); + _mm512_store_ps(&out[i + 56][0], r7); +#endif + } +} + +#undef TEMPLATE_FUNC_NAME From db39caff308b8bff7712fdd0ba80545d72b91b5f Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 18 Nov 2025 22:29:17 +0400 Subject: [PATCH 237/397] hiper: fix RX band selection --- src/lib/device/m2_dsdr/dsdr_hiper.c | 16 +++++++++------- src/lib/device/m2_dsdr/dsdr_hiper.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 5d579b6c..34f11ba0 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -770,7 +770,7 @@ static int dsdr_hiper_initialize_lms8(dsdr_hiper_fe_t* dfe, unsigned addr, unsig return res; } #include -int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8a_chip, unsigned lms8b_chip, dsdr_hiper_fe_t* dfe) +int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned* plms8_mpw_mask, dsdr_hiper_fe_t* dfe) { int res = 0; device_t* base = lowlevel_get_device(dev); @@ -863,9 +863,10 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned lms8a_chip } // LMS8 + unsigned lms8_mask = (plms8_mpw_mask) ? *plms8_mpw_mask : (dfe->rev == HIPER_REV2) ? 0b001100 : 0; for (unsigned k = 0; k < 6; k++) { uint32_t cfg = MAKE_SPIEXT_LSOPADR(MAKE_SPIEXT_CFG(LMS8_BCNTZ, k, LMS8_DIV), 0, spix_num); - res = res ? res : dsdr_hiper_initialize_lms8(dfe, cfg, (k == 2 || k == 3) ? lms8a_chip : lms8b_chip, &dfe->lms8[k]); + res = res ? res : dsdr_hiper_initialize_lms8(dfe, cfg, (lms8_mask >> k) & 1, &dfe->lms8[k]); } // ADF4002 (MUX -> GND -> DVDD readback as a sanity check) @@ -1625,12 +1626,13 @@ static void dsdr_hiper_fe_rx_band_upd(dsdr_hiper_fe_t* def, unsigned chno, unsig if (def->ucfg[chno].rx_band < RXBAND_OPTS_BAND_AUTO_L) return; - def->ucfg[chno].rx_band = (band & 3); + //def->ucfg[chno].rx_band = (band & 3); + unsigned rx_band = (band & 3); USDR_LOG("HIPR", USDR_LOG_WARNING, "RXBand[%d] switched to %c (%d)\n", chno, - def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_H ? 'H' : - def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_L ? 'L' : - def->ucfg[chno].rx_band == RXBAND_OPTS_BAND_AUTO_BP ? 'B' : 'D', - def->ucfg[chno].rx_band); + rx_band == RXBAND_OPTS_BAND_AUTO_H ? 'H' : + rx_band == RXBAND_OPTS_BAND_AUTO_L ? 'L' : + rx_band == RXBAND_OPTS_BAND_AUTO_BP ? 'B' : 'D', + rx_band); } static void dsdr_hiper_fe_tx_band_upd(dsdr_hiper_fe_t* def, unsigned chno, bool band_high) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.h b/src/lib/device/m2_dsdr/dsdr_hiper.h index fee4cbe5..07e6f297 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.h +++ b/src/lib/device/m2_dsdr/dsdr_hiper.h @@ -113,7 +113,7 @@ struct dsdr_hiper_fe { typedef struct dsdr_hiper_fe dsdr_hiper_fe_t; -int dsdr_hiper_fe_create(lldev_t dev, unsigned spix_num, unsigned lms8a_chip, unsigned int lms8b_chip, dsdr_hiper_fe_t* dfe); +int dsdr_hiper_fe_create(lldev_t dev, unsigned spix_num, unsigned int *lms8_mpw_mask, dsdr_hiper_fe_t* dfe); int dsdr_hiper_fe_destroy(dsdr_hiper_fe_t* dfe); int dsdr_hiper_fe_rx_freq_set(dsdr_hiper_fe_t* def, unsigned chno, uint64_t freq, uint64_t* ncotune, bool *p_swap_rxiq); From 906eb924830707fa64e8ad4ee731031a1641ef97 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 18 Nov 2025 22:31:04 +0400 Subject: [PATCH 238/397] dsdr: fix AFETDD control through GPIO --- src/lib/device/m2_dsdr/m2_dsdr.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 4d7603e0..a25d3711 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -159,6 +159,10 @@ enum { IGPO_TX_CHEN = 39, IGPO_RX_CHEN = 40, + + IGPO_TX_AFETDD = 41, + IGPO_RX_AFETDD = 42, + }; enum { @@ -1384,6 +1388,9 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : dev_gpo_set(dev, IGPO_PWR_LMK, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_RX_CHEN, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_TX_CHEN, 0x0); + res = res ? res : dev_gpo_set(dev, IGPO_TX_AFETDD, 0x0); + res = res ? res : dev_gpo_set(dev, IGPO_RX_AFETDD, 0x0); + // TODO check for AFE7903 if (getenv("DSDR_AFE7903")) { @@ -1710,7 +1717,10 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x1); - usleep(100000); + res = res ? res : usleep(100000); + + res = res ? res : dev_gpo_set(dev, IGPO_TX_AFETDD, 0x0f); + res = res ? res : dev_gpo_set(dev, IGPO_RX_AFETDD, 0x0f); res = res ? res : afe79xx_create(dev, d->subdev, 0, afeType, &d->st); From 449a28d14239d80515def8c56395ff9a223f1892 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 18 Nov 2025 22:31:47 +0400 Subject: [PATCH 239/397] hiper: introduce LMS8_MPW2024_MASK to override default MPW configuration in hiper --- src/lib/device/m2_dsdr/m2_dsdr.c | 35 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index a25d3711..d72afa29 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1366,8 +1366,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** int res = 0; uint32_t hwid, usr2, pg, los, devid, jesdv; unsigned afeType = 0; - unsigned lms8a_step = LMS8_MPW2015; - unsigned lms8b_step = LMS8_MPW2015; d->subdev = 0; d->dsdr_state = STATE_IDLE; @@ -1741,17 +1739,36 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } if (d->type == DSDR_PCIE_HIPER_R0) { - if (getenv("LMS8A_MPW2024")) { - lms8a_step = LMS8_MPW2024; - } - if (getenv("LMS8B_MPW2024")) { - lms8b_step = LMS8_MPW2024; + unsigned override = 0; + unsigned* poverride = NULL; + const char* env_over; + if ((env_over = getenv("LMS8_MPW2024_MASK"))) { + bool ok = (strlen(env_over) == 6); + if (ok) { + for (unsigned i = 0; i < 6; i++) { + if (env_over[i] == '0') { + } else if (env_over[i] == '1') { + override |= 1 << (5 - i); + } else { + ok = false; + } + } + } + + if (ok) { + poverride = &override; + USDR_LOG("DSDR", USDR_LOG_ERROR, "Applying external MPW mask for LMS8 chips: %d%d%d%d%d%d", + (override >> 5) & 1, (override >> 4) & 1, (override >> 3) & 1, + (override >> 2) & 1, (override >> 1) & 1, (override >> 0) & 1); + } else { + USDR_LOG("DSDR", USDR_LOG_ERROR, "Incorrect LMS8_MPW2024_MASK format!!! Should be like `LMS8_MPW_MASK=010101`\n"); + } } - res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, lms8a_step, lms8b_step, &d->hiper); + res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, poverride, &d->hiper); } - usleep(100000); + res = res ? res : usleep(100000); // check state res = res ? res : dev_m2_dsdr_afe_health_get(udev, NULL, NULL); From c3184ad8162fdb0943bb0c3179246787cee83bbf Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 18 Nov 2025 22:33:19 +0400 Subject: [PATCH 240/397] dsdr: do not delay in case of error --- src/lib/device/m2_dsdr/m2_dsdr.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index d72afa29..84cf089c 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1634,10 +1634,10 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : dev_gpi_get32(d->base.dev, 20, &clk); USDR_LOG("DSDR", USDR_LOG_ERROR, "Clk %d: %d\n", clk >> 28, clk & 0xfffffff); - usleep(0.5 * 1e6); + res = res ? res : usleep(0.5 * 1e6); } - usleep(1000); + res = res ? res : usleep(1000); res = res ? res : dev_gpi_get32(dev, IGPI_PGOOD, &pg); USDR_LOG("DSDR", USDR_LOG_ERROR, "Configuration: OK [%08x, %08x] res=%d PG=%08x\n", usr2, hwid, res, pg); @@ -1652,7 +1652,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // Initialize AFEPWR res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x1); // Enable VIOSYS, hold RESET - usleep(10000); + res = res ? res : usleep(10000); //res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x3); // Enable VIOSYS, hold RESET res = res ? res : lp875484_init(dev, d->subdev, I2C_AFE_PMIC); res = res ? res : lp875484_set_vout(dev, d->subdev, I2C_AFE_PMIC, 930); // Recomended 925mV @@ -1676,7 +1676,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return -EIO; } - usleep(100000); + res = res ? res : usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x7); // Enable DCDC 1.2V; // We don't have PG_1v2 routed in this rev @@ -1693,14 +1693,14 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** if (pgdat & (1 << 6)) break; - usleep(1000); + res = res ? res : usleep(1000); } if (!(pgdat & (1 << 6))) { USDR_LOG("DSDR", USDR_LOG_ERROR, "DCDC 1.8V isn't good, giving up!\n"); return -EIO; } - usleep(100000); + res = res ? res : usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x1f); if (res) @@ -1709,10 +1709,10 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // Test AFE chip USDR_LOG("DSDR", USDR_LOG_ERROR, "AFE is powered up!\n"); - usleep(100000); + res = res ? res : usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x0); - usleep(100000); + res = res ? res : usleep(100000); res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x1); res = res ? res : usleep(100000); @@ -1726,7 +1726,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : usdr_jesd204b_bringup_pre(d); // sleep(1); - usleep(10000); + res = res ? res : usleep(10000); char afeconfig_path[1024]; char *afecfgpath = getenv("AFECFG_PATH"); From a5ad155357a6ad4c77d2dc3cf8ea0cfb9e43db10 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 18 Nov 2025 22:33:54 +0400 Subject: [PATCH 241/397] dsdr: refacotr AFE7950 default configuration name --- src/lib/device/m2_dsdr/m2_dsdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 84cf089c..34ca63c8 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1476,7 +1476,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** if (getenv("DSDR_M2_7950")) { // AFE7950 - d->afecongiguration = "Afe79xxPg1_600_1.txt"; + d->afecongiguration = "Afe79xxPg1_6664_491_7950.txt"; afeType = 7950; } break; From 7e5bb5dad7e655f2557624f62a6eb1a7e863e22d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 18 Nov 2025 22:34:39 +0400 Subject: [PATCH 242/397] lms8001: add more tweaks for MPW2024 --- src/lib/hw/lms8001/lms8001.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index 4ac8e5c1..bf8d425b 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -811,25 +811,30 @@ static int _lms8001_optim_pll_loopbw(lms8001_state_t* m, double PM_deg, double f return -EINVAL; } - double KVCO_avg; + double KVCO_avg = 0; + const static double s_kvco_s_mpw2015[4] = {0, 44.404e6, 33.924e6, 41.455e6}; + const static double s_kvco_s_mpw2024[4] = {0, 6.2842e7, 6.4853e7, 9.1550e7}; if (!fitKVCO) { + KVCO_avg = (m->stepping == LMS8_MPW2015) ? s_kvco_s_mpw2015[vco_sel] : s_kvco_s_mpw2024[vco_sel]; + } else if (m->stepping == LMS8_MPW2015) { + // Use Fitted Values for KVCO in Calculations for mpw 2015 + int CBANK = vco_freq; if (vco_sel == 1) - KVCO_avg = 44.404e6; + KVCO_avg = 24.71e6 * (2.09e-10 * pow(CBANK, 4) + 2.77e-09 * pow(CBANK, 3) + 1.13e-05 * pow(CBANK, 2) + 3.73e-03 * CBANK + 1.01e+00); else if (vco_sel == 2) - KVCO_avg = 33.924e6; + KVCO_avg = 21.05e6 * (-9.88e-11 * pow(CBANK, 4) + 1.46e-07 * pow(CBANK, 3) + (-2.14e-05) * pow(CBANK, 2) + 5.08e-03 * CBANK + 9.99e-01); else if (vco_sel == 3) - KVCO_avg = 41.455e6; - } - else { - // Use Fitted Values for KVCO in Calculations + KVCO_avg = 32.00e6 * (-1.04e-10 * pow(CBANK, 4) + 8.72e-08 * pow(CBANK, 3) + (-4.68e-06) * pow(CBANK, 2) + 3.68e-03 * CBANK + 1.00e+00); + } else { + // Use Fitted Values for KVCO in Calculations for mpw 2024 int CBANK = vco_freq; if (vco_sel == 1) - KVCO_avg = 24.71e6 * (2.09e-10*pow(CBANK, 4) + 2.77e-09*pow(CBANK, 3) + 1.13e-05*pow(CBANK, 2) + 3.73e-03*CBANK + 1.01e+00); + KVCO_avg = 3.8492e7 * (2.1005e-10 * pow(CBANK, 4) - 3.6267e-08 * pow(CBANK, 3) + 1.3634e-05 *pow(CBANK, 2) + 3.0541e-03 * CBANK + 1.0011e+00); else if (vco_sel == 2) - KVCO_avg = 21.05e6 * (-9.88e-11*pow(CBANK, 4) + 1.46e-07*pow(CBANK, 3) + (-2.14e-05)*pow(CBANK, 2) + 5.08e-03*CBANK + 9.99e-01); + KVCO_avg = 4.4058e7 * (6.4250e-11 * pow(CBANK, 4) + 2.1831e-10 * pow(CBANK, 3) + 5.7102e-06 *pow(CBANK, 2) + 2.6286e-03 * CBANK + 1.0011e+00); else if (vco_sel == 3) - KVCO_avg = 32.00e6 * (-1.04e-10*pow(CBANK, 4) + 8.72e-08*pow(CBANK, 3) + (-4.68e-06)*pow(CBANK, 2) + 3.68e-03*CBANK + 1.00e+00); + KVCO_avg = 6.2508e7 * (3.7053e-11 * pow(CBANK, 4) + 6.3153e-09 * pow(CBANK, 3) + 5.6397e-06 *pow(CBANK, 2) + 2.5792e-03 * CBANK + 9.9837e-01); } double Kvco = 2 * M_PI * KVCO_avg; @@ -1053,8 +1058,8 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, return res; } - // Step 2 - Center VCO Tuning Voltage if needed - res = _lms8001_center_vtune(m, fvco, fref, tune_flags); + // Step 2 - Center VCO Tuning Voltage if needed only for MPW2015 + res = (m->stepping == LMS8_MPW2024) ? res : _lms8001_center_vtune(m, fvco, fref, tune_flags); if (res) { return res; } From bd7df6f3ef6dc99b184ec1502ef12e46a77f9f2f Mon Sep 17 00:00:00 2001 From: Timur <62694921+dtv-comp@users.noreply.github.com> Date: Wed, 19 Nov 2025 02:59:53 +0300 Subject: [PATCH 243/397] Fixed soapy driver (#96) * Device configuration has been corrected. Added support for an external oscilator. Returned actual ranges for various devices. * Fixed min bandwidth for usdr * Fixed frequency range for ssdr Added channel number endpoint for lime * Fixed pointer to ssdr * Reworked the device name setup. Fixed samperate setting in the Soapy. --- src/lib/device/m2_dsdr/m2_dsdr.c | 2 + src/lib/device/m2_lm6_1/m2_lm6_1.c | 1 + src/lib/device/m2_lm7_1/m2_lm7_1.c | 22 ++ src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c | 2 + src/lib/device/pe_sync/pe_sync.c | 2 + src/lib/device/u3_limesdr/u3_limesdr.c | 6 + src/lib/hw/si5332/si5332.c | 6 +- src/lib/lowlevel/libusb_generic.c | 2 +- .../pcie_uram/driver/usdr_pcie_uram.c | 2 +- src/soapysdr/usdr_soapy.cpp | 228 ++++++++++++++---- src/soapysdr/usdr_soapy.h | 16 ++ 11 files changed, 239 insertions(+), 50 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 34ca63c8..f4a9495b 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -264,6 +264,8 @@ const usdr_dev_param_constant_t s_params_m2_dsdr_rev000[] = { { "/ll/sync/0/base", M2PCI_REG_WR_SYNC_CTRL}, { "/ll/sdr/0/rfic/0", (uintptr_t)"afe79xx" }, + { "/ll/device/name", (uintptr_t)"dsdr"}, + // { "/ll/sdr/max_hw_rx_chans", 4 }, // { "/ll/sdr/max_hw_tx_chans", 4 }, diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index c4bcc267..763c7350 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -111,6 +111,7 @@ const usdr_dev_param_constant_t s_params_m2_lm6_1_rev000[] = { { "/ll/dsp/atcrbs/0/base", M2PCI_REG_WR_LBDSP }, { "/ll/sdr/0/rfic/0", (uintptr_t)"lms6002d" }, + { "/ll/device/name", (uintptr_t)"usdr"}, { "/ll/sdr/max_hw_rx_chans", 1 }, { "/ll/sdr/max_hw_tx_chans", 1 }, diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 9f1681a2..30ac7c07 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -141,6 +141,7 @@ const usdr_dev_param_constant_t s_params_m2_lm7_1_rev000[] = { { "/ll/dsp/atcrbs/0/base", M2PCI_REG_WR_LBDSP }, { "/ll/sdr/0/rfic/0", (uintptr_t)"lms7002m" }, + { "/ll/sdr/max_hw_rx_chans", 2 }, { "/ll/sdr/max_hw_tx_chans", 2 }, @@ -158,6 +159,14 @@ const usdr_dev_param_constant_t s_params_m2_lm7_1_rev000[] = { { "/ll/fe/0/i2c_busno/0", -1}, }; +static const usdr_dev_param_constant_t xsdr_params_m2_lm7_1_rev000[] = { + { "/ll/device/name", (uintptr_t)"xsdr"}, +}; + +static const usdr_dev_param_constant_t ssdr_params_m2_lm7_1_rev000[] = { + { "/ll/device/name", (uintptr_t)"ssdr"}, +}; + static int dev_m2_lm7_1_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_debug_all_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); @@ -1200,6 +1209,19 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* if (res) return res; + if (d->xdev.ssdr) + { + res = vfs_add_const_i64_vec(&udev->rootfs, ssdr_params_m2_lm7_1_rev000, SIZEOF_ARRAY(ssdr_params_m2_lm7_1_rev000)); + if (res) + USDR_LOG("UDEV", USDR_LOG_WARNING, "Unable to set device name \"ssdr\"!\n"); + } + else + { + res = vfs_add_const_i64_vec(&udev->rootfs, xsdr_params_m2_lm7_1_rev000, SIZEOF_ARRAY(xsdr_params_m2_lm7_1_rev000)); + if (res) + USDR_LOG("UDEV", USDR_LOG_WARNING, "Unable to set device name \"xsdr\"!\n"); + } + d->xdev.dpump = d->double_pump; // Proxy operations diff --git a/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c b/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c index 9efbfeb9..40c8a83f 100644 --- a/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c +++ b/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c @@ -125,6 +125,8 @@ const usdr_dev_param_constant_t s_params_m2_da09_4_ad45_2_rev000[] = { { "/ll/rfe/0/base", CSR_RFE4_BASE }, { "/ll/sdr/0/rfic/0", (uintptr_t)"ad45lb49" }, + { "/ll/device/name", (uintptr_t)"lsdr"}, + { "/ll/sdr/max_hw_rx_chans", 1 }, { "/ll/sdr/max_hw_tx_chans", 0 }, diff --git a/src/lib/device/pe_sync/pe_sync.c b/src/lib/device/pe_sync/pe_sync.c index 3865fa71..63c10fab 100644 --- a/src/lib/device/pe_sync/pe_sync.c +++ b/src/lib/device/pe_sync/pe_sync.c @@ -108,6 +108,8 @@ const usdr_dev_param_constant_t s_params_pe_sync_rev000[] = { { "/ll/qspi_flash/base", REG_WR_FLASHSPI_CMD }, { "/ll/sdr/0/rfic/0", (uintptr_t)"none" }, + { "/ll/device/name", (uintptr_t)"none"}, + { "/ll/sdr/max_hw_rx_chans", 0 }, { "/ll/sdr/max_hw_tx_chans", 0 }, { "/ll/sdr/max_sw_rx_chans", 0 }, diff --git a/src/lib/device/u3_limesdr/u3_limesdr.c b/src/lib/device/u3_limesdr/u3_limesdr.c index e43c5733..127722b5 100644 --- a/src/lib/device/u3_limesdr/u3_limesdr.c +++ b/src/lib/device/u3_limesdr/u3_limesdr.c @@ -42,7 +42,13 @@ const usdr_dev_param_constant_t s_params_u3_limesdr_0[] = { { "/ll/sdr/0/rfic/0", (uintptr_t)"lms7002m" }, + { "/ll/device/name", (uintptr_t)"limemini"}, + { "/ll/sdr/max_hw_rx_chans", 1 }, + { "/ll/sdr/max_hw_tx_chans", 1 }, + + { "/ll/sdr/max_sw_rx_chans", 1 }, + { "/ll/sdr/max_sw_tx_chans", 1 }, }; diff --git a/src/lib/hw/si5332/si5332.c b/src/lib/hw/si5332/si5332.c index fc4dbf6c..0c55a760 100644 --- a/src/lib/hw/si5332/si5332.c +++ b/src/lib/hw/si5332/si5332.c @@ -388,7 +388,7 @@ int si5332_init(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, unsigned div, // CLKIN_2_CLK_SEL, 1, IMUX_SEL, ext_in2 ? IMUX_IN_2 : IMUX_XOSC, - CLKIN_2_CLK_SEL, ext_in2 ? IMUX_INX_CMOS_AC : IMUX_INX_DISABLED, + CLKIN_2_CLK_SEL, ext_in2 ? IMUX_INX_DIFF /*IMUX_INX_CMOS_AC*/ : IMUX_INX_DISABLED, CLKIN_3_CLK_SEL, 0, 0x3C, 0, @@ -497,11 +497,13 @@ int si5532_set_ext_clock_sw(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, b { USYS_CTRL, 0x01, //READY IMUX_SEL, set_flag ? IMUX_IN_2 : IMUX_XOSC, - CLKIN_2_CLK_SEL, set_flag ? IMUX_INX_CMOS_AC : IMUX_INX_DISABLED, + CLKIN_2_CLK_SEL, set_flag ? IMUX_INX_DIFF /* IMUX_INX_CMOS_AC */ : IMUX_INX_DISABLED, 0xB9, set_flag ? (B9_XOSC_DIS /*| B9_PLL_DIS | B9_PDIV_DIS*/) : (B9_IBUF0_DIS /*| B9_PLL_DIS | B9_PDIV_DIS*/), USYS_CTRL, 0x02, //ACTIVE }; + USDR_LOG("5332", USDR_LOG_INFO, "Si5332 ExtClock=%d\n", set_flag); + int res = 0; res = si5532_get_state(dev, subdev, lsopaddr, "BEFORE SET_EX_CLK"); diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index cb019d37..b78be016 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -154,7 +154,7 @@ int libusb_generic_plugin_discovery(unsigned pcount, const char** filterparams, for (i = 0, off = 0; i < fcnt; i++) { int cap = maxbuf - off; - int l = snprintf(outarray + off, cap, "bus\t%s@%s\n", busname, md[i].devid_s); + int l = snprintf(outarray + off, cap, "bus=%s@%s\n", busname, md[i].devid_s); if (l < 0 || l > cap) { outarray[off] = 0; res = i; diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index 73264011..cb4b83b6 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -1601,7 +1601,7 @@ static int usdr_probe(struct pci_dev *pdev, /* Reconfigure MaxReadReq to 4KB */ pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_2048B); + PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_1024B); //dma_set_mask_and_coherent if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) { diff --git a/src/soapysdr/usdr_soapy.cpp b/src/soapysdr/usdr_soapy.cpp index ca1061d6..fe4f297a 100644 --- a/src/soapysdr/usdr_soapy.cpp +++ b/src/soapysdr/usdr_soapy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Wavelet Lab +// Copyright (c) 2023-2025 Wavelet Lab // SPDX-License-Identifier: MIT #include "usdr_soapy.h" @@ -55,7 +55,7 @@ struct rfic_gain_descriptor const char* property_name; }; -const rfic_gain_descriptor lms7_gains[] { +static const rfic_gain_descriptor lms7_gains[] { { SOAPY_SDR_RX, SoapySDR::Range(0.0, 30.0), "LNA", nullptr, nullptr, "/dm/sdr/0/rx/gain/lna" }, { SOAPY_SDR_RX, SoapySDR::Range(0.0, 12.0), "TIA", "VGA", "VGA1", "/dm/sdr/0/rx/gain/vga" }, { SOAPY_SDR_RX, SoapySDR::Range(-12.0, 19.0), "PGA", "VGA2", nullptr, "/dm/sdr/0/rx/gain/pga" }, @@ -63,7 +63,7 @@ const rfic_gain_descriptor lms7_gains[] { { 0, SoapySDR::Range(), nullptr, nullptr, nullptr, nullptr } }; -const rfic_gain_descriptor lms6_gains[] { +static const rfic_gain_descriptor lms6_gains[] { { SOAPY_SDR_RX, SoapySDR::Range(0.0, 6.0), "LNA", nullptr, nullptr, "/dm/sdr/0/rx/gain/lna" }, { SOAPY_SDR_RX, SoapySDR::Range(5, 31), "VGA1", "TIA", nullptr, "/dm/sdr/0/rx/gain/vga" }, { SOAPY_SDR_RX, SoapySDR::Range(0, 60.0), "VGA2", "PGA", nullptr, "/dm/sdr/0/rx/gain/pga" }, @@ -72,14 +72,14 @@ const rfic_gain_descriptor lms6_gains[] { { 0, SoapySDR::Range(), nullptr, nullptr, nullptr, nullptr } }; -const rfic_gain_descriptor ad45lb49_gains[] { +static const rfic_gain_descriptor ad45lb49_gains[] { { SOAPY_SDR_RX, SoapySDR::Range(0, 4), "LNA", "SEL", nullptr, "/dm/sdr/0/rx/gain/lna" }, { SOAPY_SDR_RX, SoapySDR::Range(0, 31), "VGA", "ATTN", nullptr, "/dm/sdr/0/rx/gain/vga" }, { SOAPY_SDR_RX, SoapySDR::Range(0, 31), "PGA", nullptr, nullptr, "/dm/sdr/0/rx/gain/pga" }, { 0, SoapySDR::Range(), nullptr, nullptr, nullptr, nullptr } }; -const rfic_gain_descriptor unk_gains[] { +static const rfic_gain_descriptor unk_gains[] { { SOAPY_SDR_RX, SoapySDR::Range(-99, 99), "GRX", nullptr, nullptr, "/dm/sdr/0/rx/gain" }, { SOAPY_SDR_TX, SoapySDR::Range(-99, 99), "GTX", nullptr, nullptr, "/dm/sdr/0/tx/gain" }, { 0, SoapySDR::Range(), nullptr, nullptr, nullptr, nullptr } @@ -94,6 +94,67 @@ static inline const rfic_gain_descriptor* get_gains(rfic_type_t t) { } } +struct device_ranges +{ + SoapySDR::Range frequency_range; + SoapySDR::Range samplerate_range; + SoapySDR::Range bandwidth_range; +}; + +static const device_ranges usdr_ranges { + .frequency_range = SoapySDR::Range(0.1e6, 3800e6), + .samplerate_range = SoapySDR::Range(1e6, 85e6), + .bandwidth_range = SoapySDR::Range(0.5e6, 40e6), +}; + +static const device_ranges xsdr_ranges { + .frequency_range = SoapySDR::Range(0.1e6, 3800e6), + .samplerate_range = SoapySDR::Range(1e6, 125e6), + .bandwidth_range = SoapySDR::Range(0.5e6, 125e6), +}; + +static const device_ranges ssdr_ranges { + .frequency_range = SoapySDR::Range(0.1e6, 12500e6), + .samplerate_range = SoapySDR::Range(4e6, 125e6), + .bandwidth_range = SoapySDR::Range(0.5e6, 125e6), +}; + +static const device_ranges dsdr_ranges { + .frequency_range = SoapySDR::Range(5e6, 12500e6), + .samplerate_range = SoapySDR::Range(4e6, 500e6), + .bandwidth_range = SoapySDR::Range(0.5e6, 500e6), +}; + +static const device_ranges lsdr_ranges { + .frequency_range = SoapySDR::Range(0.1e6, 3800e6), + .samplerate_range = SoapySDR::Range(2e6, 125e6), + .bandwidth_range = SoapySDR::Range(0.5e6, 125e6), +}; + +static const device_ranges limesdr_mini_ranges { + .frequency_range = SoapySDR::Range(30e6, 3800e6), + .samplerate_range = SoapySDR::Range(0.1e6, 40e6), + .bandwidth_range = SoapySDR::Range(0.5e6, 40e6), +}; + +static const device_ranges unk_ranges { + .frequency_range = SoapySDR::Range(30e6, 3800e6), + .samplerate_range = SoapySDR::Range(1e6, 40e6), + .bandwidth_range = SoapySDR::Range(0.5e6, 40e6), +}; + +static inline const device_ranges* get_ranges(device_type_t t) { + switch (t) { + case DEVICE_USDR: return &usdr_ranges; + case DEVICE_XSDR: return &xsdr_ranges; + case DEVICE_SSDR: return &ssdr_ranges; + case DEVICE_DSDR: return &dsdr_ranges; + case DEVICE_LSDR: return &lsdr_ranges; + case DEVICE_LIMESDR_MINI: return &limesdr_mini_ranges; + default: return &unk_ranges; + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const char* SoapyUSDR::get_sdr_param(int sdridx, const char* dir, const char* par, const char* subpar) @@ -136,25 +197,43 @@ SoapyUSDR::SoapyUSDR(const SoapySDR::Kwargs &args_orig) const SoapySDR::Kwargs &args = (env_str.length() > 0) ? env_args : args_orig; - std::string dev = (args.count("dev")) ? args.at("dev") : ""; - if (args.count("loglevel")) { loglevel = std::stoi(args.at("loglevel")); } + + SoapySDR::Kwargs dev_args = SoapySDR:: + KwargsFromString((args.count("dev")) ? args.at("dev") : ""); + + if (args.count("bus")) { + dev_args["bus"] = args.at("bus"); + } + + if (args.count("device")) { + dev_args["device"] = args.at("device"); + } + if (args.count("fe")) { - if (dev.length() != 0) { - dev += ","; - } - dev += "fe="; - dev += args.at("fe").c_str(); + dev_args["fe"] = args.at("fe"); } - if (args.count("bus")) { - if (dev.length() > 0) { + + if (args.count("extclk")) { + dev_args["extclk"] = args.at("extclk"); + } + + if (args.count("extref")) { + dev_args["extref"] = args.at("extref"); + } + + bool first = true; + std::string dev = ""; + for (const auto &dev_arg : dev_args) { + if (first) + first = false; + else dev += ","; - } - dev += "bus="; - dev += args.at("bus").c_str(); + dev += dev_arg.first + "=" + dev_arg.second; } + if (args.count("txcorr")) { _txcorr = atoi(args.at("txcorr").c_str()); } @@ -164,11 +243,11 @@ SoapyUSDR::SoapyUSDR(const SoapySDR::Kwargs &args_orig) usdrlog_setlevel(NULL, loglevel); - - SoapySDR::logf(callLogLvl(), "Make connection: '%s'", args.count("dev") ? args.at("dev").c_str() : "*"); + SoapySDR::logf(SOAPY_SDR_DEBUG, "Make connection: '%s'", args.count("dev") ? args.at("dev").c_str() : "*"); for (auto& i: args) { - SoapySDR::logf(callLogLvl(), "Param %s => %s", i.first.c_str(), i.second.c_str()); + SoapySDR::logf(SOAPY_SDR_DEBUG, "Param %s => %s", i.first.c_str(), i.second.c_str()); } + _dev = usdr_handle::get(dev); if (args.count("refclk")) { @@ -198,7 +277,9 @@ SoapyUSDR::SoapyUSDR(const SoapySDR::Kwargs &args_orig) } uint64_t val; - int res = usdr_dme_get_uint(_dev->dev(), "/ll/sdr/0/rfic/0", &val); + int res; + + res = usdr_dme_get_uint(_dev->dev(), "/ll/sdr/0/rfic/0", &val); if (res == 0) { const char* rfic = reinterpret_cast(val); if (strcmp(rfic, "lms6002d") == 0) @@ -211,6 +292,24 @@ SoapyUSDR::SoapyUSDR(const SoapySDR::Kwargs &args_orig) type = RFIC_AFE79XX; } + res = usdr_dme_get_uint(_dev->dev(), "/ll/device/name", &val); + if (res == 0) { + const char* device = reinterpret_cast(val); + SoapySDR::logf(callLogLvl(), "SoapyUSDR::SoapyUSDR() Device name is \"%s\"", device); + if (strcmp(device, "usdr") == 0) + device_type = DEVICE_USDR; + else if (strcmp(device, "xsdr") == 0) + device_type = DEVICE_XSDR; + else if (strcmp(device, "ssdr") == 0) + device_type = DEVICE_SSDR; + else if (strcmp(device, "dsdr") == 0) + device_type = DEVICE_DSDR; + else if (strcmp(device, "lsdr") == 0) + device_type = DEVICE_LSDR; + else if (strcmp(device, "limemini") == 0) + device_type = DEVICE_LIMESDR_MINI; + } + if (args.count("rx_bw")) { unsigned bw = atoi(args.at("rx_bw").c_str()); SoapySDR::logf(callLogLvl(), "SoapyUSDR::SoapyUSDR() RX_BW set to %d", bw); @@ -528,11 +627,10 @@ SoapySDR::RangeList SoapyUSDR::getFrequencyRange(const int /*direction*/, const SoapySDR::RangeList ranges; if (name == "RF") { - if (type == RFIC_AFE79XX) { - ranges.push_back(SoapySDR::Range(5e6, 12.5e9)); - } else { - ranges.push_back(SoapySDR::Range(1e5, 3.8e9)); - } + const device_ranges *dev_ranges = get_ranges(device_type); + if (!dev_ranges) + return ranges; + ranges.push_back(dev_ranges->frequency_range); } else if (name == "BB") { @@ -613,17 +711,24 @@ double SoapyUSDR::getSampleRate(const int direction, const size_t /*channel*/) c SoapySDR::RangeList SoapyUSDR::getSampleRateRange(const int /*direction*/, const size_t /*channel*/) const { SoapySDR::RangeList ranges; - ranges.push_back(SoapySDR::Range((type == RFIC_AFE79XX) ? 1.92e6 : 0.1e6, - (type == RFIC_AFE79XX) ? 500e6 : (type == RFIC_AD45LB49) ? 130e6 : 80e6)); + const device_ranges *dev_ranges = get_ranges(device_type); + if (!dev_ranges) + return ranges; + ranges.push_back(dev_ranges->samplerate_range); return ranges; } std::vector SoapyUSDR::listSampleRates(const int /*direction*/, const size_t /*channel*/) const { std::vector rates; - for (int i = 2; i < 57; i++) + const device_ranges *dev_ranges = get_ranges(device_type); + if (!dev_ranges) + return rates; + const int min_sr = (int) (dev_ranges->bandwidth_range.minimum() / 1e6); + const int max_sr = (int) (dev_ranges->bandwidth_range.maximum() / 1e6); + for (int i = min_sr; i < max_sr; ++i) { - rates.push_back(i*1e6); + rates.push_back(i * 1e6); } return rates; } @@ -669,7 +774,10 @@ double SoapyUSDR::getBandwidth(const int direction, const size_t /*channel*/) co SoapySDR::RangeList SoapyUSDR::getBandwidthRange(const int /*direction*/, const size_t /*channel*/) const { SoapySDR::RangeList bws; - bws.push_back(SoapySDR::Range(0.5e6, 80e6)); + const device_ranges *dev_ranges = get_ranges(device_type); + if (!dev_ranges) + return bws; + bws.push_back(dev_ranges->bandwidth_range); return bws; } @@ -757,6 +865,11 @@ void SoapyUSDR::setHardwareTime(const long long timeNs, const std::string &what) SoapySDR::logf(callLogLvl(), "SoapyUSDR::setHardwareTime(%lld)", timeNs); } +std::vector SoapyUSDR::listTimeSources(void) const +{ + return { "internal", "external" }; +} + /******************************************************************* * Sensor API ******************************************************************/ @@ -765,6 +878,7 @@ std::vector SoapyUSDR::listSensors(void) const { std::vector sensors; sensors.push_back("clock_locked"); + sensors.push_back("ref_locked"); sensors.push_back("board_temp"); return sensors; } @@ -780,6 +894,14 @@ SoapySDR::ArgInfo SoapyUSDR::getSensorInfo(const std::string &name) const info.value = "false"; info.description = "CGEN clock is locked, good VCO selection."; } + else if (name == "ref_locked") + { + info.key = "ref_locked"; + info.name = "Reference Locked"; + info.type = SoapySDR::ArgInfo::BOOL; + info.value = "false"; + info.description = "Reference clock is locked."; + } else if (name == "board_temp") { info.key = "board_temp"; @@ -799,6 +921,10 @@ std::string SoapyUSDR::readSensor(const std::string &name) const { return "true"; } + else if (name == "ref_locked") + { + return "true"; + } else if (name == "board_temp") { uint64_t val; @@ -832,6 +958,7 @@ SoapySDR::ArgInfo SoapyUSDR::getSensorInfo(const int /*direction*/, const size_t info.value = "false"; info.description = "LO synthesizer is locked, good VCO selection."; } + return info; } @@ -1080,6 +1207,14 @@ SoapySDR::Stream *SoapyUSDR::setupStream( _streams[direction].chmsk = chmsk; _streams[direction].stream = direction == SOAPY_SDR_RX ? "/ll/srx/0" : "/ll/stx/0"; + if (_actual_rx_rate == 0) { + const device_ranges *dev_ranges = get_ranges(device_type); + if (dev_ranges) + setSampleRate(SOAPY_SDR_RX, 0, dev_ranges->samplerate_range.minimum()); + else + setSampleRate(SOAPY_SDR_RX, 0, 5e6); + } + if (direction == SOAPY_SDR_RX) { // We need a better way to calculate packet size unsigned defbufsz = @@ -1112,10 +1247,6 @@ SoapySDR::Stream *SoapyUSDR::setupStream( SoapySDR::logf(callLogLvl(), "SoapyUSDR::setupStream(%s) %d Samples per packet, burst size %d * %d chs; res = %d", ustr->stream, numElems, ustr->nfo.pktsyms, ustr->nfo.channels, res); - if (_actual_rx_rate == 0) { - setSampleRate(SOAPY_SDR_RX, 0, 1.92e6); - } - res = usdr_dms_sync(_dev->dev(), "off", 1, &ustr->strm); if (res) { throw std::runtime_error("SoapyUSDR::setupStream failed!"); @@ -1296,17 +1427,21 @@ int SoapyUSDR::readStream( } } -int SoapyUSDR::writeStream( - SoapySDR::Stream *stream, - const void * const *buffs, - const size_t numElems, - int &flags, - const long long timeNs, - const long timeoutUs) +int SoapyUSDR::writeStream(SoapySDR::Stream *stream, + const void *const *buffs, + const size_t numElems, + int &flags, + const long long timeNs, + const long timeoutUs) { - USDRStream* ustr = (USDRStream*)(stream); - long long ts = (flags & SOAPY_SDR_HAS_TIME) ? - SoapySDR::timeNsToTicks(timeNs, _actual_tx_rate) + _txcorr : -1; + USDRStream *ustr = (USDRStream *) (stream); + long long ts; + if (flags & SOAPY_SDR_HAS_TIME) { + ts = SoapySDR::timeNsToTicks(timeNs, _actual_tx_rate) + _txcorr; + this->calc_ts = ts; + } else { + ts = this->calc_ts; + } int64_t lag = ts - last_recv_pkt_time; if (tx_pkts == 0) { @@ -1319,7 +1454,8 @@ int SoapyUSDR::writeStream( SoapySDR::logf(SOAPY_SDR_DEBUG, "writeStream::writeStream(%s) @ %lld num %d should be %d\n", ustr->stream, ts, numElems, ustr->nfo.pktsyms); unsigned toSend = numElems; - int res = usdr_dms_send(ustr->strm, (const void **)buffs, numElems, ts, timeoutUs / 1000); + int res = usdr_dms_send(ustr->strm, (const void **) buffs, numElems, ts, timeoutUs / 1000); + this->calc_ts += numElems; if (tx_pkts % 1000 == 0) { SoapySDR::logf(_dump_calls ? SOAPY_SDR_ERROR : SOAPY_SDR_TRACE, diff --git a/src/soapysdr/usdr_soapy.h b/src/soapysdr/usdr_soapy.h index 890ceeab..c5cb1261 100644 --- a/src/soapysdr/usdr_soapy.h +++ b/src/soapysdr/usdr_soapy.h @@ -26,6 +26,16 @@ enum rfic_type_t { RFIC_UNKNOWN }; +enum device_type_t { + DEVICE_USDR, + DEVICE_XSDR, + DEVICE_SSDR, + DEVICE_DSDR, + DEVICE_LSDR, + DEVICE_LIMESDR_MINI, + DEVICE_UNKNOWN, +}; + class usdr_handle { public: @@ -241,6 +251,8 @@ class SoapyUSDR : public SoapySDR::Device void setHardwareTime(const long long timeNs, const std::string &what = ""); + std::vector listTimeSources(void) const; + /******************************************************************* * Sensor API ******************************************************************/ @@ -345,6 +357,8 @@ class SoapyUSDR : public SoapySDR::Device FILE* rd; rfic_type_t type = RFIC_UNKNOWN; + device_type_t device_type = DEVICE_UNKNOWN; + double _actual_bandwidth[2] = { 0, 0 }; double _actual_frequency[2] = { 0, 0 }; @@ -352,6 +366,8 @@ class SoapyUSDR : public SoapySDR::Device int _txcorr = 0; + int64_t calc_ts = 0LL; + std::string _clk_source = "internal"; }; From d08447d8ec608925f195d323675c226e9f5a96c6 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 26 Nov 2025 00:31:38 +0400 Subject: [PATCH 244/397] driver: add automatic features detect for entreprise-like kernels --- src/lib/lowlevel/pcie_uram/driver/Makefile | 3 +++ .../pcie_uram/driver/usdr_pcie_uram.c | 22 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/lib/lowlevel/pcie_uram/driver/Makefile b/src/lib/lowlevel/pcie_uram/driver/Makefile index 68f77e99..da853afd 100644 --- a/src/lib/lowlevel/pcie_uram/driver/Makefile +++ b/src/lib/lowlevel/pcie_uram/driver/Makefile @@ -1,11 +1,14 @@ + ifneq ($(KERNELRELEASE),) +ccflags-y += $(shell grep -E 'class_create\s*.*\s*const char' $(srctree)/include/linux/device/class.h >/dev/null && echo -DHAVE_CLASS_CREATE_ONE_ARG) obj-m += usdr_pcie_uram.o else KERNELDIR ?= /lib/modules/$(shell uname -r)/build + modules modules_install clean:: make -C $(KERNELDIR) M=$(PWD) $@ diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index cb4b83b6..f03dec76 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -65,6 +65,24 @@ static int pci_irq_vector(struct pci_dev *dev, unsigned int nr) } #endif + +// vm_flags_set introduced in 6.3.0, however enterprise-like kernels heavily backport new API to +// old base kernel version, notably RHEL, resulting in newer API in 5.x.x. So version like checks +// will fail here +#ifndef HAVE_VM_FLAGS_SET +#if defined(vm_flags_set) +#define HAVE_VM_FLAGS_SET 1 +#endif +#endif + +#ifndef HAVE_CLASS_CREATE_ONE_ARG +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) +#define HAVE_CLASS_CREATE_ONE_ARG 1 +#endif +#endif + + + // Change anytime when extra parameter or meaning is changed in pcie_uram_driver_if.h #define USDR_DRIVER_ABI_VERSION 3 @@ -1474,7 +1492,7 @@ static int usdrfd_mmap_io(struct usdr_dev *usdrdev, struct vm_area_struct *vma) return -EINVAL; vma->vm_page_prot = pgprot_device(vma->vm_page_prot); -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) +#ifdef HAVE_VM_FLAGS_SET vma->vm_flags |= VM_IO; #else vm_flags_set(vma, VM_IO); @@ -1799,7 +1817,7 @@ static int __init usdr_init(void) printk(KERN_NOTICE PFX "Unable to allocate chrdev region: %d\n", err); goto failed_chrdev; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) +#ifndef HAVE_CLASS_CREATE_ONE_ARG usdr_class = class_create(THIS_MODULE, CLASS_NAME); #else usdr_class = class_create(CLASS_NAME); From 85cba238639a590a17ddbeba1b86c64c3680957e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 27 Nov 2025 12:44:15 +0400 Subject: [PATCH 245/397] usdr_pcie_uram: properly detect backport kernel features in REHL-like distros --- src/lib/lowlevel/pcie_uram/driver/Makefile | 3 +-- src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/lib/lowlevel/pcie_uram/driver/Makefile b/src/lib/lowlevel/pcie_uram/driver/Makefile index da853afd..8204e9d3 100644 --- a/src/lib/lowlevel/pcie_uram/driver/Makefile +++ b/src/lib/lowlevel/pcie_uram/driver/Makefile @@ -1,6 +1,6 @@ - ifneq ($(KERNELRELEASE),) +ccflags-y += $(shell grep -E 'vm_flags_set\s*.*\s*struct vm_area_struct' $(srctree)/include/linux/mm.h >/dev/null && echo -DHAVE_VM_FLAGS_SET) ccflags-y += $(shell grep -E 'class_create\s*.*\s*const char' $(srctree)/include/linux/device/class.h >/dev/null && echo -DHAVE_CLASS_CREATE_ONE_ARG) obj-m += usdr_pcie_uram.o @@ -16,4 +16,3 @@ clean:: rm -f *.o Module.markers modules.order endif - diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index f03dec76..97f17b4b 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -70,11 +70,12 @@ static int pci_irq_vector(struct pci_dev *dev, unsigned int nr) // old base kernel version, notably RHEL, resulting in newer API in 5.x.x. So version like checks // will fail here #ifndef HAVE_VM_FLAGS_SET -#if defined(vm_flags_set) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) #define HAVE_VM_FLAGS_SET 1 #endif #endif + #ifndef HAVE_CLASS_CREATE_ONE_ARG #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) #define HAVE_CLASS_CREATE_ONE_ARG 1 @@ -82,7 +83,6 @@ static int pci_irq_vector(struct pci_dev *dev, unsigned int nr) #endif - // Change anytime when extra parameter or meaning is changed in pcie_uram_driver_if.h #define USDR_DRIVER_ABI_VERSION 3 @@ -1492,7 +1492,7 @@ static int usdrfd_mmap_io(struct usdr_dev *usdrdev, struct vm_area_struct *vma) return -EINVAL; vma->vm_page_prot = pgprot_device(vma->vm_page_prot); -#ifdef HAVE_VM_FLAGS_SET +#ifndef HAVE_VM_FLAGS_SET vma->vm_flags |= VM_IO; #else vm_flags_set(vma, VM_IO); From 694823fb1f2aad621fbe202a6f37c0382ded25ef Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 2 Dec 2025 01:19:00 +0400 Subject: [PATCH 246/397] xsdp: add generic ci16->8cf32 transformation --- src/lib/xdsp/conv.c | 11 +++ src/lib/xdsp/conv.h | 7 ++ src/lib/xdsp/conv_ci16_8cf32_2.c | 29 +++++++ src/lib/xdsp/conv_ci16_8cf32_2.h | 12 +++ .../xdsp/templates/conv_ci16_8cf32_generic.t | 75 +++++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 src/lib/xdsp/conv_ci16_8cf32_2.c create mode 100644 src/lib/xdsp/conv_ci16_8cf32_2.h create mode 100644 src/lib/xdsp/templates/conv_ci16_8cf32_generic.t diff --git a/src/lib/xdsp/conv.c b/src/lib/xdsp/conv.c index c92c915e..af6577ea 100644 --- a/src/lib/xdsp/conv.c +++ b/src/lib/xdsp/conv.c @@ -28,6 +28,8 @@ #include "conv_2ci16_ci12_2.h" #include "conv_4ci16_ci12_2.h" +#include "conv_ci16_8cf32_2.h" + #include #include @@ -125,6 +127,15 @@ transform_info_t get_transform_fn(const char* from, unsigned inveccnt, unsigned outveccnt) { + if(inveccnt == 1 && outveccnt == 8) + { + if(isCI16(from) && isCF32(to)) + { + transform_info_t l_conv_ci16_8cf32 = { conv_get_ci16_8cf32(), tr_conv_i16_f32_sz }; + return l_conv_ci16_8cf32; + } + } + /* Deinterleave 4 -> 1 */ if(inveccnt == 4 && outveccnt == 1) { diff --git a/src/lib/xdsp/conv.h b/src/lib/xdsp/conv.h index b7d25f33..6742df87 100644 --- a/src/lib/xdsp/conv.h +++ b/src/lib/xdsp/conv.h @@ -61,6 +61,13 @@ typedef void (*filter_function_t)(const int16_t *__restrict data, unsigned outdatabsz) \ { conv_fn(*indata, indatabsz, outdata[0], outdata[1], outdata[2], outdata[3], outdatabsz); } +#define DECLARE_TR_FUNC_1_8(conv_fn) \ +void tr_##conv_fn (const void *__restrict *__restrict indata, \ + unsigned indatabsz, \ + void *__restrict *__restrict outdata, \ + unsigned outdatabsz) \ +{ conv_fn(*indata, indatabsz, outdata[0], outdata[1], outdata[2], outdata[3], outdata[4], outdata[5], outdata[6], outdata[7], outdatabsz); } + #define DECLARE_TR_FUNC_2_1(conv_fn) \ void tr_##conv_fn (const void *__restrict *__restrict indata, \ unsigned indatabsz, \ diff --git a/src/lib/xdsp/conv_ci16_8cf32_2.c b/src/lib/xdsp/conv_ci16_8cf32_2.c new file mode 100644 index 00000000..dd8e7d5a --- /dev/null +++ b/src/lib/xdsp/conv_ci16_8cf32_2.c @@ -0,0 +1,29 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_ci16_8cf32_2.h" +#include "attribute_switch.h" + +#define CONV_SCALE (1.0f/32767) + +#define TEMPLATE_FUNC_NAME conv_ci16_8cf32_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_8cf32_generic.t" +DECLARE_TR_FUNC_1_8(conv_ci16_8cf32_generic) + + +conv_function_t conv_get_ci16_8cf32_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_8cf32_generic, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_ci16_8cf32() +{ + return conv_get_ci16_8cf32_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_ci16_8cf32_2.h b/src/lib/xdsp/conv_ci16_8cf32_2.h new file mode 100644 index 00000000..b527eb01 --- /dev/null +++ b/src/lib/xdsp/conv_ci16_8cf32_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_CI16_8CF32_2_H +#define CONV_CI16_8CF32_2_H + +#include "conv.h" + +conv_function_t conv_get_ci16_8cf32_c(generic_opts_t cpu_cap, const char** sfunc); +conv_function_t conv_get_ci16_8cf32(); + +#endif // CONV_CI16_8CF32_2_H diff --git a/src/lib/xdsp/templates/conv_ci16_8cf32_generic.t b/src/lib/xdsp/templates/conv_ci16_8cf32_generic.t new file mode 100644 index 00000000..f4bfcf8a --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_8cf32_generic.t @@ -0,0 +1,75 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + void *__restrict outdata_6_p, + void *__restrict outdata_7_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + const uint64_t *ld = (const uint64_t *)indata; + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + float* outdata_3 = (float*)outdata_3_p; + float* outdata_4 = (float*)outdata_4_p; + float* outdata_5 = (float*)outdata_5_p; + float* outdata_6 = (float*)outdata_6_p; + float* outdata_7 = (float*)outdata_7_p; + + for (; i >= 32; i -= 32) + { + const uint64_t v0 = *(ld++); + const uint64_t v1 = *(ld++); + const uint64_t v2 = *(ld++); + const uint64_t v3 = *(ld++); + + const float i0 = (int16_t)(v0); + const float q0 = (int16_t)(v0>>16); + const float i1 = (int16_t)(v0>>32); + const float q1 = (int16_t)(v0>>48); + const float i2 = (int16_t)(v1); + const float q2 = (int16_t)(v1>>16); + const float i3 = (int16_t)(v1>>32); + const float q3 = (int16_t)(v1>>48); + const float i4 = (int16_t)(v2); + const float q4 = (int16_t)(v2>>16); + const float i5 = (int16_t)(v2>>32); + const float q5 = (int16_t)(v2>>48); + const float i6 = (int16_t)(v3); + const float q6 = (int16_t)(v3>>16); + const float i7 = (int16_t)(v3>>32); + const float q7 = (int16_t)(v3>>48); + + *(outdata_0++) = i0 * CONV_SCALE; + *(outdata_0++) = q0 * CONV_SCALE; + *(outdata_1++) = i1 * CONV_SCALE; + *(outdata_1++) = q1 * CONV_SCALE; + *(outdata_2++) = i2 * CONV_SCALE; + *(outdata_2++) = q2 * CONV_SCALE; + *(outdata_3++) = i3 * CONV_SCALE; + *(outdata_3++) = q3 * CONV_SCALE; + + *(outdata_4++) = i4 * CONV_SCALE; + *(outdata_4++) = q4 * CONV_SCALE; + *(outdata_5++) = i5 * CONV_SCALE; + *(outdata_5++) = q5 * CONV_SCALE; + *(outdata_6++) = i6 * CONV_SCALE; + *(outdata_6++) = q6 * CONV_SCALE; + *(outdata_7++) = i7 * CONV_SCALE; + *(outdata_7++) = q7 * CONV_SCALE; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME From f1c64d4f59f4c041d2e616538bb3cd76bc2e712c Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 2 Dec 2025 09:25:28 +0400 Subject: [PATCH 247/397] xsdp: update CMakeLists.txt --- src/lib/xdsp/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index 3c4608c1..21cea2a0 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -42,6 +42,7 @@ set(xdsplib_conv_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci12_4ci16_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_2ci16_ci12_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_4ci16_ci12_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8cf32_2.c ) if(WVLT_ARCH_X86 OR WVLT_ARCH_X86_64) From 250532a2b8d7f74f9cf76d4ee035520559ac3ac6 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 7 Dec 2025 23:11:55 +0300 Subject: [PATCH 248/397] Add ci16_8cf32 AVX2 --- src/lib/xdsp/conv_ci16_8cf32_2.c | 7 + src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t | 99 +++++++ .../templates/conv_ci16_8cf32_generic.inc | 43 +++ .../xdsp/templates/conv_ci16_8cf32_generic.t | 45 +--- src/lib/xdsp/utests/CMakeLists.txt | 2 + src/lib/xdsp/utests/conv_ci16_8cf32_utest.c | 246 ++++++++++++++++++ src/lib/xdsp/utests/xdsp_utest_suite.c | 5 +- 7 files changed, 402 insertions(+), 45 deletions(-) create mode 100644 src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t create mode 100644 src/lib/xdsp/templates/conv_ci16_8cf32_generic.inc create mode 100644 src/lib/xdsp/utests/conv_ci16_8cf32_utest.c diff --git a/src/lib/xdsp/conv_ci16_8cf32_2.c b/src/lib/xdsp/conv_ci16_8cf32_2.c index dd8e7d5a..e56bfe15 100644 --- a/src/lib/xdsp/conv_ci16_8cf32_2.c +++ b/src/lib/xdsp/conv_ci16_8cf32_2.c @@ -11,6 +11,12 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci16_8cf32_generic.t" DECLARE_TR_FUNC_1_8(conv_ci16_8cf32_generic) +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_ci16_8cf32_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_ci16_8cf32_avx2.t" +DECLARE_TR_FUNC_1_8(conv_ci16_8cf32_avx2) +#endif conv_function_t conv_get_ci16_8cf32_c(generic_opts_t cpu_cap, const char** sfunc) { @@ -18,6 +24,7 @@ conv_function_t conv_get_ci16_8cf32_c(generic_opts_t cpu_cap, const char** sfunc conv_function_t fn; SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_8cf32_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_ci16_8cf32_avx2, cpu_cap); if (sfunc) *sfunc = fname; return fn; diff --git a/src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t b/src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t new file mode 100644 index 00000000..664f51cb --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t @@ -0,0 +1,99 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + void *__restrict outdata_6_p, + void *__restrict outdata_7_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + const __m256i * indata_p = (__m256i*)indata; + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + float* outdata_3 = (float*)outdata_3_p; + float* outdata_4 = (float*)outdata_4_p; + float* outdata_5 = (float*)outdata_5_p; + float* outdata_6 = (float*)outdata_6_p; + float* outdata_7 = (float*)outdata_7_p; + + //AVX2 + { + const __m256 scale = _mm256_set1_ps(CONV_SCALE); + + __m256i in0, in1, in2, in3; + __m256d f0a, f0b, f1a, f1b, f2a, f2b, f3a, f3b; + __m256d x0a, x0b, x1a, x1b, x2a, x2b, x3a, x3b; + __m256d out0, out1, out2, out3, out4, out5, out6, out7; + + for (; i >= 32 * 4; i -= 32 * 4) + { + in0 = _mm256_load_si256(indata_p++); + in1 = _mm256_load_si256(indata_p++); + in2 = _mm256_load_si256(indata_p++); + in3 = _mm256_load_si256(indata_p++); + + f0a = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_castsi256_si128(in0))), scale)); + f0b = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_extracti128_si256(in0, 1))), scale)); + f1a = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_castsi256_si128(in1))), scale)); + f1b = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_extracti128_si256(in1, 1))), scale)); + f2a = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_castsi256_si128(in2))), scale)); + f2b = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_extracti128_si256(in2, 1))), scale)); + f3a = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_castsi256_si128(in3))), scale)); + f3b = _mm256_castps_pd(_mm256_mul_ps(_mm256_cvtepi32_ps(_mm256_cvtepi16_epi32(_mm256_extracti128_si256(in3, 1))), scale)); + + x0a = _mm256_shuffle_pd(f0a, f1a, 0b0000); + x1a = _mm256_shuffle_pd(f0a, f1a, 0b1111); + x0b = _mm256_shuffle_pd(f0b, f1b, 0b0000); + x1b = _mm256_shuffle_pd(f0b, f1b, 0b1111); + x2a = _mm256_shuffle_pd(f2a, f3a, 0b0000); + x3a = _mm256_shuffle_pd(f2a, f3a, 0b1111); + x2b = _mm256_shuffle_pd(f2b, f3b, 0b0000); + x3b = _mm256_shuffle_pd(f2b, f3b, 0b1111); + + out0 = _mm256_permute2f128_pd(x0a, x2a, 0b00100000); + out2 = _mm256_permute2f128_pd(x0a, x2a, 0b00110001); + out1 = _mm256_permute2f128_pd(x1a, x3a, 0b00100000); + out3 = _mm256_permute2f128_pd(x1a, x3a, 0b00110001); + out4 = _mm256_permute2f128_pd(x0b, x2b, 0b00100000); + out6 = _mm256_permute2f128_pd(x0b, x2b, 0b00110001); + out5 = _mm256_permute2f128_pd(x1b, x3b, 0b00100000); + out7 = _mm256_permute2f128_pd(x1b, x3b, 0b00110001); + + _mm256_store_pd((double*)outdata_0, out0); + _mm256_store_pd((double*)outdata_1, out1); + _mm256_store_pd((double*)outdata_2, out2); + _mm256_store_pd((double*)outdata_3, out3); + _mm256_store_pd((double*)outdata_4, out4); + _mm256_store_pd((double*)outdata_5, out5); + _mm256_store_pd((double*)outdata_6, out6); + _mm256_store_pd((double*)outdata_7, out7); + + outdata_0 += 8; + outdata_1 += 8; + outdata_2 += 8; + outdata_3 += 8; + outdata_4 += 8; + outdata_5 += 8; + outdata_6 += 8; + outdata_7 += 8; + } + } + + //Generic + { + const uint64_t *ld = (const uint64_t *)indata_p; + #include "conv_ci16_8cf32_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_8cf32_generic.inc b/src/lib/xdsp/templates/conv_ci16_8cf32_generic.inc new file mode 100644 index 00000000..1ea63465 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_8cf32_generic.inc @@ -0,0 +1,43 @@ +for (; i >= 32; i -= 32) +{ + const uint64_t v0 = *(ld++); + const uint64_t v1 = *(ld++); + const uint64_t v2 = *(ld++); + const uint64_t v3 = *(ld++); + + const float i0 = (int16_t)(v0); + const float q0 = (int16_t)(v0>>16); + const float i1 = (int16_t)(v0>>32); + const float q1 = (int16_t)(v0>>48); + const float i2 = (int16_t)(v1); + const float q2 = (int16_t)(v1>>16); + const float i3 = (int16_t)(v1>>32); + const float q3 = (int16_t)(v1>>48); + const float i4 = (int16_t)(v2); + const float q4 = (int16_t)(v2>>16); + const float i5 = (int16_t)(v2>>32); + const float q5 = (int16_t)(v2>>48); + const float i6 = (int16_t)(v3); + const float q6 = (int16_t)(v3>>16); + const float i7 = (int16_t)(v3>>32); + const float q7 = (int16_t)(v3>>48); + + *(outdata_0++) = i0 * CONV_SCALE; + *(outdata_0++) = q0 * CONV_SCALE; + *(outdata_1++) = i1 * CONV_SCALE; + *(outdata_1++) = q1 * CONV_SCALE; + *(outdata_2++) = i2 * CONV_SCALE; + *(outdata_2++) = q2 * CONV_SCALE; + *(outdata_3++) = i3 * CONV_SCALE; + *(outdata_3++) = q3 * CONV_SCALE; + + *(outdata_4++) = i4 * CONV_SCALE; + *(outdata_4++) = q4 * CONV_SCALE; + *(outdata_5++) = i5 * CONV_SCALE; + *(outdata_5++) = q5 * CONV_SCALE; + *(outdata_6++) = i6 * CONV_SCALE; + *(outdata_6++) = q6 * CONV_SCALE; + *(outdata_7++) = i7 * CONV_SCALE; + *(outdata_7++) = q7 * CONV_SCALE; +} +// do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_ci16_8cf32_generic.t b/src/lib/xdsp/templates/conv_ci16_8cf32_generic.t index f4bfcf8a..101bcf60 100644 --- a/src/lib/xdsp/templates/conv_ci16_8cf32_generic.t +++ b/src/lib/xdsp/templates/conv_ci16_8cf32_generic.t @@ -26,50 +26,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, float* outdata_6 = (float*)outdata_6_p; float* outdata_7 = (float*)outdata_7_p; - for (; i >= 32; i -= 32) - { - const uint64_t v0 = *(ld++); - const uint64_t v1 = *(ld++); - const uint64_t v2 = *(ld++); - const uint64_t v3 = *(ld++); - - const float i0 = (int16_t)(v0); - const float q0 = (int16_t)(v0>>16); - const float i1 = (int16_t)(v0>>32); - const float q1 = (int16_t)(v0>>48); - const float i2 = (int16_t)(v1); - const float q2 = (int16_t)(v1>>16); - const float i3 = (int16_t)(v1>>32); - const float q3 = (int16_t)(v1>>48); - const float i4 = (int16_t)(v2); - const float q4 = (int16_t)(v2>>16); - const float i5 = (int16_t)(v2>>32); - const float q5 = (int16_t)(v2>>48); - const float i6 = (int16_t)(v3); - const float q6 = (int16_t)(v3>>16); - const float i7 = (int16_t)(v3>>32); - const float q7 = (int16_t)(v3>>48); - - *(outdata_0++) = i0 * CONV_SCALE; - *(outdata_0++) = q0 * CONV_SCALE; - *(outdata_1++) = i1 * CONV_SCALE; - *(outdata_1++) = q1 * CONV_SCALE; - *(outdata_2++) = i2 * CONV_SCALE; - *(outdata_2++) = q2 * CONV_SCALE; - *(outdata_3++) = i3 * CONV_SCALE; - *(outdata_3++) = q3 * CONV_SCALE; - - *(outdata_4++) = i4 * CONV_SCALE; - *(outdata_4++) = q4 * CONV_SCALE; - *(outdata_5++) = i5 * CONV_SCALE; - *(outdata_5++) = q5 * CONV_SCALE; - *(outdata_6++) = i6 * CONV_SCALE; - *(outdata_6++) = q6 * CONV_SCALE; - *(outdata_7++) = i7 * CONV_SCALE; - *(outdata_7++) = q7 * CONV_SCALE; - } - - // do nothing with leftover + #include "conv_ci16_8cf32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/CMakeLists.txt b/src/lib/xdsp/utests/CMakeLists.txt index 31e657ce..2269f358 100644 --- a/src/lib/xdsp/utests/CMakeLists.txt +++ b/src/lib/xdsp/utests/CMakeLists.txt @@ -21,6 +21,7 @@ set(TEST_SUIT_SRCS conv_4ci16_ci16_utest.c conv_ci16_4ci16_utest.c conv_ci16_4cf32_utest.c + conv_ci16_8cf32_utest.c conv_4cf32_ci16_utest.c conv_ci12_4cf32_utest.c conv_4cf32_ci12_utest.c @@ -48,6 +49,7 @@ set(TEST_SUIT_SRCS ../conv_4ci16_ci16_2.c ../conv_ci16_4ci16_2.c ../conv_ci16_4cf32_2.c + ../conv_ci16_8cf32_2.c ../conv_4cf32_ci16_2.c ../conv_ci12_4cf32_2.c ../conv_4cf32_ci12_2.c diff --git a/src/lib/xdsp/utests/conv_ci16_8cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_8cf32_utest.c new file mode 100644 index 00000000..acfcf35f --- /dev/null +++ b/src/lib/xdsp/utests/conv_ci16_8cf32_utest.c @@ -0,0 +1,246 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_ci16_8cf32_2.h" + +#undef DEBUG_PRINT + +#define WORD_COUNT (4096u + 80u) +#define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) + +#define SPEED_WORD_COUNT (32768u) +#define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) + +static const unsigned packet_lens[3] = { 1024, 16384, SPEED_SIZE_BZ }; + +#define SPEED_MEASURE_ITERS 1000000 + +static int16_t* in = NULL; +static float* out1 = NULL; +static float* out1_etalon = NULL; +static float* out2 = NULL; +static float* out2_etalon = NULL; +static float* out3 = NULL; +static float* out3_etalon = NULL; +static float* out4 = NULL; +static float* out4_etalon = NULL; +static float* out5 = NULL; +static float* out5_etalon = NULL; +static float* out6 = NULL; +static float* out6_etalon = NULL; +static float* out7 = NULL; +static float* out7_etalon = NULL; +static float* out8 = NULL; +static float* out8_etalon = NULL; + +static float* out[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out5, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out5_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out6, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out6_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out7, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out7_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out8, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + res = res ? res : posix_memalign((void**)&out8_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/8); + ck_assert_int_eq(res, 0); + + out[0] = out1; + out[1] = out2; + out[2] = out3; + out[3] = out4; + out[4] = out5; + out[5] = out6; + out[6] = out7; + out[7] = out8; + + srand( time(0) ); + + //fill + int16_t n = 0; + for(unsigned i = 0; i < SPEED_WORD_COUNT; ++i) + { + int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; + in[i] = sign * 32767 * (float)(rand()) / (float)RAND_MAX; + } +#if 0 + for(unsigned i = 0; i < WORD_COUNT; ++i) + { + fprintf(stderr, "%x\n", pin[i]); + } +#endif +} + +static void teardown() +{ + free(in); + free(out1); + free(out1_etalon); + free(out2); + free(out2_etalon); + free(out3); + free(out3_etalon); + free(out4); + free(out4_etalon); + free(out5); + free(out5_etalon); + free(out6); + free(out6_etalon); + free(out7); + free(out7_etalon); + free(out8); + free(out8_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_ci16_8cf32_c, &last_fn_name); +} + +#define CONV_SCALE (1.0f/32767) + +START_TEST(conv_ci16_8cf32_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = IN_STREAM_SIZE_BZ; + const size_t bzout = WORD_COUNT * sizeof(float); + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(out1_etalon, 0, bzout / 8); + memset(out2_etalon, 0, bzout / 8); + memset(out3_etalon, 0, bzout / 8); + memset(out4_etalon, 0, bzout / 8); + memset(out5_etalon, 0, bzout / 8); + memset(out6_etalon, 0, bzout / 8); + memset(out7_etalon, 0, bzout / 8); + memset(out8_etalon, 0, bzout / 8); + (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); + memcpy(out1_etalon, out[0], bzout / 8); + memcpy(out2_etalon, out[1], bzout / 8); + memcpy(out3_etalon, out[2], bzout / 8); + memcpy(out4_etalon, out[3], bzout / 8); + memcpy(out5_etalon, out[4], bzout / 8); + memcpy(out6_etalon, out[5], bzout / 8); + memcpy(out7_etalon, out[6], bzout / 8); + memcpy(out8_etalon, out[7], bzout / 8); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out[0], 0, bzout / 8); + memset(out[1], 0, bzout / 8); + memset(out[2], 0, bzout / 8); + memset(out[3], 0, bzout / 8); + memset(out[4], 0, bzout / 8); + memset(out[5], 0, bzout / 8); + memset(out[6], 0, bzout / 8); + memset(out[7], 0, bzout / 8); + (*fn)(&pin, bzin, pout, bzout); + + int res = memcmp(out[0], out1_etalon, bzout / 8) || + memcmp(out[1], out2_etalon, bzout / 8) || + memcmp(out[2], out3_etalon, bzout / 8) || + memcmp(out[3], out4_etalon, bzout / 8) || + memcmp(out[4], out5_etalon, bzout / 8) || + memcmp(out[5], out6_etalon, bzout / 8) || + memcmp(out[6], out7_etalon, bzout / 8) || + memcmp(out[7], out8_etalon, bzout / 8); + + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); +#ifdef DEBUG_PRINT + for(unsigned i = 0; res && i < WORD_COUNT; i += 8) + { + if(i > 32) break; + + fprintf(stderr,"#%d in: {", i); + for(unsigned j = 0; j < 8; ++j) fprintf(stderr,"%d, ", in[i+j]); + fprintf(stderr,"}\n"); + + for(unsigned k = 0; k < 8; ++k) + { + fprintf(stderr,"\tout[%d]: {%.2f, %.2f}\n", k, out[k][i / 8] / CONV_SCALE, out[k][i / 8 + 1] / CONV_SCALE); + } + } +#endif + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_ci16_8cf32_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i]; + const size_t bzout = SPEED_WORD_COUNT * sizeof(float); + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(&pin, bzin, pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_ci16_8cf32_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_ci16_8cf32"); + + ADD_REGRESS_TEST(s, conv_ci16_8cf32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_8cf32_speed, 60, 0, 3); + + return s; +} diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index ebad42e7..32138b5b 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -33,6 +33,7 @@ Suite * conv_ci12_2ci16_suite(void); Suite * conv_ci12_4ci16_suite(void); Suite * conv_2ci16_ci12_suite(void); Suite * conv_4ci16_ci12_suite(void); +Suite * conv_ci16_8cf32_suite(void); int main(int argc, char** argv) { @@ -79,7 +80,9 @@ int main(int argc, char** argv) // #else //sr = srunner_create(conv_i16_f32_suite()); - sr = srunner_create(fft_window_ci16_cf32_suite()); + //sr = srunner_create(fft_window_ci16_cf32_suite()); + sr = srunner_create(conv_ci16_8cf32_suite()); + //srunner_add_suite(sr, fft_window_cf32_suite()); //srunner_add_suite(sr, conv_f32_i12_suite()); //srunner_add_suite(sr, conv_2cf32_ci12_suite()); From cdc25e1ab9b0da1825a21f02b8dd7df1bf1910e2 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Mon, 8 Dec 2025 22:37:33 +0300 Subject: [PATCH 249/397] Add ci16_8ci16 AVX2 --- src/lib/xdsp/CMakeLists.txt | 1 + src/lib/xdsp/conv_ci16_8ci16_2.c | 34 +++ src/lib/xdsp/conv_ci16_8ci16_2.h | 12 + src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t | 119 +++++++++ .../templates/conv_ci16_8ci16_generic.inc | 13 + .../xdsp/templates/conv_ci16_8ci16_generic.t | 31 +++ src/lib/xdsp/utests/CMakeLists.txt | 2 + src/lib/xdsp/utests/conv_ci16_8ci16_utest.c | 248 ++++++++++++++++++ src/lib/xdsp/utests/xdsp_utest_suite.c | 4 +- 9 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 src/lib/xdsp/conv_ci16_8ci16_2.c create mode 100644 src/lib/xdsp/conv_ci16_8ci16_2.h create mode 100644 src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t create mode 100644 src/lib/xdsp/templates/conv_ci16_8ci16_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci16_8ci16_generic.t create mode 100644 src/lib/xdsp/utests/conv_ci16_8ci16_utest.c diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index 21cea2a0..0e067b71 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -43,6 +43,7 @@ set(xdsplib_conv_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/conv_2ci16_ci12_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_4ci16_ci12_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8cf32_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8ci16_2.c ) if(WVLT_ARCH_X86 OR WVLT_ARCH_X86_64) diff --git a/src/lib/xdsp/conv_ci16_8ci16_2.c b/src/lib/xdsp/conv_ci16_8ci16_2.c new file mode 100644 index 00000000..5e8a191b --- /dev/null +++ b/src/lib/xdsp/conv_ci16_8ci16_2.c @@ -0,0 +1,34 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_ci16_8ci16_2.h" +#include "attribute_switch.h" + +#define TEMPLATE_FUNC_NAME conv_ci16_8ci16_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_8ci16_generic.t" +DECLARE_TR_FUNC_1_8(conv_ci16_8ci16_generic) + +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_ci16_8ci16_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_ci16_8ci16_avx2.t" +DECLARE_TR_FUNC_1_8(conv_ci16_8ci16_avx2) +#endif + +conv_function_t conv_get_ci16_8ci16_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_8ci16_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_ci16_8ci16_avx2, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_ci16_8ci16() +{ + return conv_get_ci16_8ci16_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_ci16_8ci16_2.h b/src/lib/xdsp/conv_ci16_8ci16_2.h new file mode 100644 index 00000000..21d8f3f1 --- /dev/null +++ b/src/lib/xdsp/conv_ci16_8ci16_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_CI16_8CI16_2_H +#define CONV_CI16_8CI16_2_H + +#include "conv.h" + +conv_function_t conv_get_ci16_8ci16_c(generic_opts_t cpu_cap, const char** sfunc); +conv_function_t conv_get_ci16_8ci16(); + +#endif // CONV_CI16_8CI16_2_H diff --git a/src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t b/src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t new file mode 100644 index 00000000..200c3294 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t @@ -0,0 +1,119 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + void *__restrict outdata_6_p, + void *__restrict outdata_7_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + const __m256i * indata = (__m256i*)indata_p; + + uint32_t* outdata_0 = (uint32_t*)outdata_0_p; + uint32_t* outdata_1 = (uint32_t*)outdata_1_p; + uint32_t* outdata_2 = (uint32_t*)outdata_2_p; + uint32_t* outdata_3 = (uint32_t*)outdata_3_p; + uint32_t* outdata_4 = (uint32_t*)outdata_4_p; + uint32_t* outdata_5 = (uint32_t*)outdata_5_p; + uint32_t* outdata_6 = (uint32_t*)outdata_6_p; + uint32_t* outdata_7 = (uint32_t*)outdata_7_p; + + //AVX2 + { + __m256i in0, in1, in2, in3, in4, in5, in6, in7; + __m256i a0, a1, a2, a3, a4, a5, a6, a7; + __m256i b0, b1, b2, b3, b4, b5, b6, b7; + __m256i out0, out1, out2, out3, out4, out5, out6, out7; + + for(; i >= 32 * 8; i -= 32 * 8) + { + in0 = _mm256_load_si256(indata++); + in1 = _mm256_load_si256(indata++); + in2 = _mm256_load_si256(indata++); + in3 = _mm256_load_si256(indata++); + in4 = _mm256_load_si256(indata++); + in5 = _mm256_load_si256(indata++); + in6 = _mm256_load_si256(indata++); + in7 = _mm256_load_si256(indata++); + + in0 = _mm256_shuffle_epi32(in0, _MM_SHUFFLE(3, 1, 2, 0)); + in1 = _mm256_shuffle_epi32(in1, _MM_SHUFFLE(3, 1, 2, 0)); + in2 = _mm256_shuffle_epi32(in2, _MM_SHUFFLE(3, 1, 2, 0)); + in3 = _mm256_shuffle_epi32(in3, _MM_SHUFFLE(3, 1, 2, 0)); + in4 = _mm256_shuffle_epi32(in4, _MM_SHUFFLE(3, 1, 2, 0)); + in5 = _mm256_shuffle_epi32(in5, _MM_SHUFFLE(3, 1, 2, 0)); + in6 = _mm256_shuffle_epi32(in6, _MM_SHUFFLE(3, 1, 2, 0)); + in7 = _mm256_shuffle_epi32(in7, _MM_SHUFFLE(3, 1, 2, 0)); + + a0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in0), _mm256_castsi256_pd(in1), 0b0000)); + a1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in0), _mm256_castsi256_pd(in1), 0b1111)); + a2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in2), _mm256_castsi256_pd(in3), 0b0000)); + a3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in2), _mm256_castsi256_pd(in3), 0b1111)); + a4 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in4), _mm256_castsi256_pd(in5), 0b0000)); + a5 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in4), _mm256_castsi256_pd(in5), 0b1111)); + a6 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in6), _mm256_castsi256_pd(in7), 0b0000)); + a7 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in6), _mm256_castsi256_pd(in7), 0b1111)); + + a0 = _mm256_shuffle_epi32(a0, _MM_SHUFFLE(3, 1, 2, 0)); + a1 = _mm256_shuffle_epi32(a1, _MM_SHUFFLE(3, 1, 2, 0)); + a2 = _mm256_shuffle_epi32(a2, _MM_SHUFFLE(3, 1, 2, 0)); + a3 = _mm256_shuffle_epi32(a3, _MM_SHUFFLE(3, 1, 2, 0)); + a4 = _mm256_shuffle_epi32(a4, _MM_SHUFFLE(3, 1, 2, 0)); + a5 = _mm256_shuffle_epi32(a5, _MM_SHUFFLE(3, 1, 2, 0)); + a6 = _mm256_shuffle_epi32(a6, _MM_SHUFFLE(3, 1, 2, 0)); + a7 = _mm256_shuffle_epi32(a7, _MM_SHUFFLE(3, 1, 2, 0)); + + b0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a2), 0b0000)); + b1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a1), _mm256_castsi256_pd(a3), 0b0000)); + b2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a2), 0b1111)); + b3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a1), _mm256_castsi256_pd(a3), 0b1111)); + b4 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a4), _mm256_castsi256_pd(a6), 0b0000)); + b5 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a5), _mm256_castsi256_pd(a7), 0b0000)); + b6 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a4), _mm256_castsi256_pd(a6), 0b1111)); + b7 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a5), _mm256_castsi256_pd(a7), 0b1111)); + + out0 = _mm256_permute2x128_si256(b0, b4, 0b00100000); + out1 = _mm256_permute2x128_si256(b1, b5, 0b00100000); + out2 = _mm256_permute2x128_si256(b2, b6, 0b00100000); + out3 = _mm256_permute2x128_si256(b3, b7, 0b00100000); + out4 = _mm256_permute2x128_si256(b0, b4, 0b00110001); + out5 = _mm256_permute2x128_si256(b1, b5, 0b00110001); + out6 = _mm256_permute2x128_si256(b2, b6, 0b00110001); + out7 = _mm256_permute2x128_si256(b3, b7, 0b00110001); + + _mm256_store_si256((__m256i*)outdata_0, out0); + _mm256_store_si256((__m256i*)outdata_1, out1); + _mm256_store_si256((__m256i*)outdata_2, out2); + _mm256_store_si256((__m256i*)outdata_3, out3); + _mm256_store_si256((__m256i*)outdata_4, out4); + _mm256_store_si256((__m256i*)outdata_5, out5); + _mm256_store_si256((__m256i*)outdata_6, out6); + _mm256_store_si256((__m256i*)outdata_7, out7); + + outdata_0 += 8; + outdata_1 += 8; + outdata_2 += 8; + outdata_3 += 8; + outdata_4 += 8; + outdata_5 += 8; + outdata_6 += 8; + outdata_7 += 8; + } + } + + //Generic + { + const uint32_t* in = (uint32_t*)indata; + #include "conv_ci16_8ci16_generic.inc" + } +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_8ci16_generic.inc b/src/lib/xdsp/templates/conv_ci16_8ci16_generic.inc new file mode 100644 index 00000000..f1de8b40 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_8ci16_generic.inc @@ -0,0 +1,13 @@ +for (; i >= 32; i -= 32) +{ + *outdata_0++ = *in++; + *outdata_1++ = *in++; + *outdata_2++ = *in++; + *outdata_3++ = *in++; + *outdata_4++ = *in++; + *outdata_5++ = *in++; + *outdata_6++ = *in++; + *outdata_7++ = *in++; +} + +// do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_ci16_8ci16_generic.t b/src/lib/xdsp/templates/conv_ci16_8ci16_generic.t new file mode 100644 index 00000000..d27d1e22 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_8ci16_generic.t @@ -0,0 +1,31 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + void *__restrict outdata_3_p, + void *__restrict outdata_4_p, + void *__restrict outdata_5_p, + void *__restrict outdata_6_p, + void *__restrict outdata_7_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + uint32_t* outdata_0 = (uint32_t*)outdata_0_p; + uint32_t* outdata_1 = (uint32_t*)outdata_1_p; + uint32_t* outdata_2 = (uint32_t*)outdata_2_p; + uint32_t* outdata_3 = (uint32_t*)outdata_3_p; + uint32_t* outdata_4 = (uint32_t*)outdata_4_p; + uint32_t* outdata_5 = (uint32_t*)outdata_5_p; + uint32_t* outdata_6 = (uint32_t*)outdata_6_p; + uint32_t* outdata_7 = (uint32_t*)outdata_7_p; + + const uint32_t* in = (uint32_t*)indata_p; + #include "conv_ci16_8ci16_generic.inc" +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/CMakeLists.txt b/src/lib/xdsp/utests/CMakeLists.txt index 2269f358..bf1aea30 100644 --- a/src/lib/xdsp/utests/CMakeLists.txt +++ b/src/lib/xdsp/utests/CMakeLists.txt @@ -22,6 +22,7 @@ set(TEST_SUIT_SRCS conv_ci16_4ci16_utest.c conv_ci16_4cf32_utest.c conv_ci16_8cf32_utest.c + conv_ci16_8ci16_utest.c conv_4cf32_ci16_utest.c conv_ci12_4cf32_utest.c conv_4cf32_ci12_utest.c @@ -50,6 +51,7 @@ set(TEST_SUIT_SRCS ../conv_ci16_4ci16_2.c ../conv_ci16_4cf32_2.c ../conv_ci16_8cf32_2.c + ../conv_ci16_8ci16_2.c ../conv_4cf32_ci16_2.c ../conv_ci12_4cf32_2.c ../conv_4cf32_ci12_2.c diff --git a/src/lib/xdsp/utests/conv_ci16_8ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_8ci16_utest.c new file mode 100644 index 00000000..53996d61 --- /dev/null +++ b/src/lib/xdsp/utests/conv_ci16_8ci16_utest.c @@ -0,0 +1,248 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_ci16_8ci16_2.h" + +#define DEBUG_PRINT + +#define CHECK_WORD_COUNT (4096u + 80u) //must be a multiple of 4 +#define CHECK_SIZE_BZ (CHECK_WORD_COUNT * sizeof(int16_t)) + +#define SPEED_WORD_COUNT (65536u) +#define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) + +static const unsigned packet_lens[4] = { 8192u, 16384u, 32768u, SPEED_WORD_COUNT }; + +#define SPEED_MEASURE_ITERS 1000000 + +static int16_t* in = NULL; +static int16_t* out1 = NULL; +static int16_t* out1_etalon = NULL; +static int16_t* out2 = NULL; +static int16_t* out2_etalon = NULL; +static int16_t* out3 = NULL; +static int16_t* out3_etalon = NULL; +static int16_t* out4 = NULL; +static int16_t* out4_etalon = NULL; +static int16_t* out5 = NULL; +static int16_t* out5_etalon = NULL; +static int16_t* out6 = NULL; +static int16_t* out6_etalon = NULL; +static int16_t* out7 = NULL; +static int16_t* out7_etalon = NULL; +static int16_t* out8 = NULL; +static int16_t* out8_etalon = NULL; +static int16_t* out[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, SPEED_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, SPEED_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, SPEED_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out4, ALIGN_BYTES, SPEED_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out5, ALIGN_BYTES, SPEED_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out6, ALIGN_BYTES, SPEED_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out7, ALIGN_BYTES, SPEED_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out8, ALIGN_BYTES, SPEED_SIZE_BZ/8); + + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out4_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out5_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out6_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out7_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + res = res ? res : posix_memalign((void**)&out8_etalon, ALIGN_BYTES, CHECK_SIZE_BZ/8); + + ck_assert_int_eq(res, 0); + + out[0] = out1; + out[1] = out2; + out[2] = out3; + out[3] = out4; + out[4] = out5; + out[5] = out6; + out[6] = out7; + out[7] = out8; + + srand( time(0) ); + + //fill + for(unsigned i = 0; i < SPEED_WORD_COUNT; ++i) + { + int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; + in[i] = sign * i; + } +} + +static void teardown() +{ + free(in); + free(out1); + free(out2); + free(out3); + free(out4); + free(out5); + free(out6); + free(out7); + free(out8); + free(out1_etalon); + free(out2_etalon); + free(out3_etalon); + free(out4_etalon); + free(out5_etalon); + free(out6_etalon); + free(out7_etalon); + free(out8_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_ci16_8ci16_c, &last_fn_name); +} + + +static void print_data(const char* header) +{ + if(header) + fprintf(stderr, "%s:", header); + + fprintf(stderr, "\n in: "); + for(unsigned i = 0; i < 32; ++i) + { + fprintf(stderr, "%d ", in[i]); + } + + for(unsigned n = 0; n < 8; ++n) + { + fprintf(stderr, "\n out%d: ", n); + for(unsigned i = 0; i < 8; ++i) + { + fprintf(stderr, "%4d ", out[n][i]); + } + } + fprintf(stderr, "\n"); +} + +START_TEST(conv_ci16_8ci16_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = CHECK_SIZE_BZ; + const size_t bzout = CHECK_SIZE_BZ; + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(out[0], 0, bzout / 8); + memset(out[1], 0, bzout / 8); + memset(out[2], 0, bzout / 8); + memset(out[3], 0, bzout / 8); + memset(out[4], 0, bzout / 8); + memset(out[5], 0, bzout / 8); + memset(out[6], 0, bzout / 8); + memset(out[7], 0, bzout / 8); + (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT + print_data("ETALON"); +#endif + memcpy(out1_etalon, out[0], bzout / 8); + memcpy(out2_etalon, out[1], bzout / 8); + memcpy(out3_etalon, out[2], bzout / 8); + memcpy(out4_etalon, out[3], bzout / 8); + memcpy(out5_etalon, out[4], bzout / 8); + memcpy(out6_etalon, out[5], bzout / 8); + memcpy(out7_etalon, out[6], bzout / 8); + memcpy(out8_etalon, out[7], bzout / 8); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out[0], 0, bzout / 8); + memset(out[1], 0, bzout / 8); + memset(out[2], 0, bzout / 8); + memset(out[3], 0, bzout / 8); + memset(out[4], 0, bzout / 8); + memset(out[5], 0, bzout / 8); + memset(out[6], 0, bzout / 8); + memset(out[7], 0, bzout / 8); + (*fn)(&pin, bzin, pout, bzout); +#ifdef DEBUG_PRINT + print_data(0); +#endif + int res = memcmp(out[0], out1_etalon, bzout / 8) || memcmp(out[1], out2_etalon, bzout / 8) || + memcmp(out[2], out3_etalon, bzout / 8) || memcmp(out[3], out4_etalon, bzout / 8) || + memcmp(out[4], out5_etalon, bzout / 8) || memcmp(out[5], out6_etalon, bzout / 8) || + memcmp(out[6], out7_etalon, bzout / 8) || memcmp(out[7], out8_etalon, bzout / 8); + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_ci16_8ci16_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i] * sizeof(int16_t); + const size_t bzout = bzin; + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(&pin, bzin, pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_ci16_8ci16_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_ci16_8ci16"); + + ADD_REGRESS_TEST(s, conv_ci16_8ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_8ci16_speed, 60, 0, 4); + + return s; +} diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index 32138b5b..17c3fe8d 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -34,6 +34,7 @@ Suite * conv_ci12_4ci16_suite(void); Suite * conv_2ci16_ci12_suite(void); Suite * conv_4ci16_ci12_suite(void); Suite * conv_ci16_8cf32_suite(void); +Suite * conv_ci16_8ci16_suite(void); int main(int argc, char** argv) { @@ -81,7 +82,8 @@ int main(int argc, char** argv) #else //sr = srunner_create(conv_i16_f32_suite()); //sr = srunner_create(fft_window_ci16_cf32_suite()); - sr = srunner_create(conv_ci16_8cf32_suite()); + //sr = srunner_create(conv_ci16_8cf32_suite()); + sr = srunner_create(conv_ci16_8ci16_suite()); //srunner_add_suite(sr, fft_window_cf32_suite()); //srunner_add_suite(sr, conv_f32_i12_suite()); From b35ce92ddf31025b86c736f48a8a331ab97afc2f Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 9 Dec 2025 00:22:44 +0300 Subject: [PATCH 250/397] refactoring --- src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t | 51 ++++++++-- src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t | 92 ++++++++++++++----- src/lib/xdsp/utests/conv_ci16_8cf32_utest.c | 6 +- src/lib/xdsp/utests/conv_ci16_8ci16_utest.c | 2 +- src/lib/xdsp/utests/xdsp_utest_suite.c | 4 +- 5 files changed, 115 insertions(+), 40 deletions(-) diff --git a/src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t b/src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t index 664f51cb..00b3d904 100644 --- a/src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t +++ b/src/lib/xdsp/templates/conv_ci16_8cf32_avx2.t @@ -26,6 +26,8 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, float* outdata_6 = (float*)outdata_6_p; float* outdata_7 = (float*)outdata_7_p; +#define USE_SSE_STORES + //AVX2 { const __m256 scale = _mm256_set1_ps(CONV_SCALE); @@ -33,7 +35,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, __m256i in0, in1, in2, in3; __m256d f0a, f0b, f1a, f1b, f2a, f2b, f3a, f3b; __m256d x0a, x0b, x1a, x1b, x2a, x2b, x3a, x3b; +#ifndef USE_SSE_STORES __m256d out0, out1, out2, out3, out4, out5, out6, out7; +#endif for (; i >= 32 * 4; i -= 32 * 4) { @@ -60,24 +64,53 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, x2b = _mm256_shuffle_pd(f2b, f3b, 0b0000); x3b = _mm256_shuffle_pd(f2b, f3b, 0b1111); +#ifdef USE_SSE_STORES + +//#define _MM_STORE_FN _mm_store_pd +#define _MM_STORE_FN _mm_storeu_pd + + _MM_STORE_FN((double*)outdata_0, _mm256_castpd256_pd128(x0a)); + _MM_STORE_FN((double*)outdata_1, _mm256_castpd256_pd128(x1a)); + _MM_STORE_FN((double*)outdata_2, _mm256_extractf128_pd(x0a, 1)); + _MM_STORE_FN((double*)outdata_3, _mm256_extractf128_pd(x1a, 1)); + _MM_STORE_FN((double*)outdata_4, _mm256_castpd256_pd128(x0b)); + _MM_STORE_FN((double*)outdata_5, _mm256_castpd256_pd128(x1b)); + _MM_STORE_FN((double*)outdata_6, _mm256_extractf128_pd(x0b, 1)); + _MM_STORE_FN((double*)outdata_7, _mm256_extractf128_pd(x1b, 1)); + + _MM_STORE_FN((double*)(outdata_0 + 4), _mm256_castpd256_pd128(x2a)); + _MM_STORE_FN((double*)(outdata_1 + 4), _mm256_castpd256_pd128(x3a)); + _MM_STORE_FN((double*)(outdata_2 + 4), _mm256_extractf128_pd(x2a, 1)); + _MM_STORE_FN((double*)(outdata_3 + 4), _mm256_extractf128_pd(x3a, 1)); + _MM_STORE_FN((double*)(outdata_4 + 4), _mm256_castpd256_pd128(x2b)); + _MM_STORE_FN((double*)(outdata_5 + 4), _mm256_castpd256_pd128(x3b)); + _MM_STORE_FN((double*)(outdata_6 + 4), _mm256_extractf128_pd(x2b, 1)); + _MM_STORE_FN((double*)(outdata_7 + 4), _mm256_extractf128_pd(x3b, 1)); +#else + +//#define _MM256_STORE_FN _mm256_store_pd +#define _MM256_STORE_FN _mm256_storeu_pd + out0 = _mm256_permute2f128_pd(x0a, x2a, 0b00100000); out2 = _mm256_permute2f128_pd(x0a, x2a, 0b00110001); out1 = _mm256_permute2f128_pd(x1a, x3a, 0b00100000); out3 = _mm256_permute2f128_pd(x1a, x3a, 0b00110001); + + _MM256_STORE_FN((double*)outdata_0, out0); + _MM256_STORE_FN((double*)outdata_1, out1); + _MM256_STORE_FN((double*)outdata_2, out2); + _MM256_STORE_FN((double*)outdata_3, out3); + out4 = _mm256_permute2f128_pd(x0b, x2b, 0b00100000); out6 = _mm256_permute2f128_pd(x0b, x2b, 0b00110001); out5 = _mm256_permute2f128_pd(x1b, x3b, 0b00100000); out7 = _mm256_permute2f128_pd(x1b, x3b, 0b00110001); - _mm256_store_pd((double*)outdata_0, out0); - _mm256_store_pd((double*)outdata_1, out1); - _mm256_store_pd((double*)outdata_2, out2); - _mm256_store_pd((double*)outdata_3, out3); - _mm256_store_pd((double*)outdata_4, out4); - _mm256_store_pd((double*)outdata_5, out5); - _mm256_store_pd((double*)outdata_6, out6); - _mm256_store_pd((double*)outdata_7, out7); - + _MM256_STORE_FN((double*)outdata_4, out4); + _MM256_STORE_FN((double*)outdata_5, out5); + _MM256_STORE_FN((double*)outdata_6, out6); + _MM256_STORE_FN((double*)outdata_7, out7); +#endif outdata_0 += 8; outdata_1 += 8; outdata_2 += 8; diff --git a/src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t b/src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t index 200c3294..77573b57 100644 --- a/src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t +++ b/src/lib/xdsp/templates/conv_ci16_8ci16_avx2.t @@ -26,12 +26,16 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, uint32_t* outdata_6 = (uint32_t*)outdata_6_p; uint32_t* outdata_7 = (uint32_t*)outdata_7_p; +#undef USE_SSE_STORES + //AVX2 { __m256i in0, in1, in2, in3, in4, in5, in6, in7; __m256i a0, a1, a2, a3, a4, a5, a6, a7; __m256i b0, b1, b2, b3, b4, b5, b6, b7; +#ifndef USE_SSE_STORES __m256i out0, out1, out2, out3, out4, out5, out6, out7; +#endif for(; i >= 32 * 8; i -= 32 * 8) { @@ -39,65 +43,103 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_p, in1 = _mm256_load_si256(indata++); in2 = _mm256_load_si256(indata++); in3 = _mm256_load_si256(indata++); - in4 = _mm256_load_si256(indata++); - in5 = _mm256_load_si256(indata++); - in6 = _mm256_load_si256(indata++); - in7 = _mm256_load_si256(indata++); in0 = _mm256_shuffle_epi32(in0, _MM_SHUFFLE(3, 1, 2, 0)); in1 = _mm256_shuffle_epi32(in1, _MM_SHUFFLE(3, 1, 2, 0)); in2 = _mm256_shuffle_epi32(in2, _MM_SHUFFLE(3, 1, 2, 0)); in3 = _mm256_shuffle_epi32(in3, _MM_SHUFFLE(3, 1, 2, 0)); - in4 = _mm256_shuffle_epi32(in4, _MM_SHUFFLE(3, 1, 2, 0)); - in5 = _mm256_shuffle_epi32(in5, _MM_SHUFFLE(3, 1, 2, 0)); - in6 = _mm256_shuffle_epi32(in6, _MM_SHUFFLE(3, 1, 2, 0)); - in7 = _mm256_shuffle_epi32(in7, _MM_SHUFFLE(3, 1, 2, 0)); a0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in0), _mm256_castsi256_pd(in1), 0b0000)); a1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in0), _mm256_castsi256_pd(in1), 0b1111)); a2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in2), _mm256_castsi256_pd(in3), 0b0000)); a3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in2), _mm256_castsi256_pd(in3), 0b1111)); - a4 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in4), _mm256_castsi256_pd(in5), 0b0000)); - a5 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in4), _mm256_castsi256_pd(in5), 0b1111)); - a6 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in6), _mm256_castsi256_pd(in7), 0b0000)); - a7 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in6), _mm256_castsi256_pd(in7), 0b1111)); a0 = _mm256_shuffle_epi32(a0, _MM_SHUFFLE(3, 1, 2, 0)); a1 = _mm256_shuffle_epi32(a1, _MM_SHUFFLE(3, 1, 2, 0)); a2 = _mm256_shuffle_epi32(a2, _MM_SHUFFLE(3, 1, 2, 0)); a3 = _mm256_shuffle_epi32(a3, _MM_SHUFFLE(3, 1, 2, 0)); - a4 = _mm256_shuffle_epi32(a4, _MM_SHUFFLE(3, 1, 2, 0)); - a5 = _mm256_shuffle_epi32(a5, _MM_SHUFFLE(3, 1, 2, 0)); - a6 = _mm256_shuffle_epi32(a6, _MM_SHUFFLE(3, 1, 2, 0)); - a7 = _mm256_shuffle_epi32(a7, _MM_SHUFFLE(3, 1, 2, 0)); b0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a2), 0b0000)); b1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a1), _mm256_castsi256_pd(a3), 0b0000)); b2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a0), _mm256_castsi256_pd(a2), 0b1111)); b3 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a1), _mm256_castsi256_pd(a3), 0b1111)); + + // + + in4 = _mm256_load_si256(indata++); + in5 = _mm256_load_si256(indata++); + in6 = _mm256_load_si256(indata++); + in7 = _mm256_load_si256(indata++); + + in4 = _mm256_shuffle_epi32(in4, _MM_SHUFFLE(3, 1, 2, 0)); + in5 = _mm256_shuffle_epi32(in5, _MM_SHUFFLE(3, 1, 2, 0)); + in6 = _mm256_shuffle_epi32(in6, _MM_SHUFFLE(3, 1, 2, 0)); + in7 = _mm256_shuffle_epi32(in7, _MM_SHUFFLE(3, 1, 2, 0)); + + a4 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in4), _mm256_castsi256_pd(in5), 0b0000)); + a5 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in4), _mm256_castsi256_pd(in5), 0b1111)); + a6 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in6), _mm256_castsi256_pd(in7), 0b0000)); + a7 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(in6), _mm256_castsi256_pd(in7), 0b1111)); + + a4 = _mm256_shuffle_epi32(a4, _MM_SHUFFLE(3, 1, 2, 0)); + a5 = _mm256_shuffle_epi32(a5, _MM_SHUFFLE(3, 1, 2, 0)); + a6 = _mm256_shuffle_epi32(a6, _MM_SHUFFLE(3, 1, 2, 0)); + a7 = _mm256_shuffle_epi32(a7, _MM_SHUFFLE(3, 1, 2, 0)); + b4 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a4), _mm256_castsi256_pd(a6), 0b0000)); b5 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a5), _mm256_castsi256_pd(a7), 0b0000)); b6 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a4), _mm256_castsi256_pd(a6), 0b1111)); b7 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(a5), _mm256_castsi256_pd(a7), 0b1111)); + // + +#ifdef USE_SSE_STORES + +//#define _MM_STORE_FN _mm_store_si128 +#define _MM_STORE_FN _mm_storeu_si128 + + _MM_STORE_FN((__m128i*)outdata_0, _mm256_castsi256_si128(b0)); + _MM_STORE_FN((__m128i*)outdata_1, _mm256_castsi256_si128(b1)); + _MM_STORE_FN((__m128i*)outdata_2, _mm256_castsi256_si128(b2)); + _MM_STORE_FN((__m128i*)outdata_3, _mm256_castsi256_si128(b3)); + _MM_STORE_FN((__m128i*)outdata_4, _mm256_extractf128_si256(b0, 1)); + _MM_STORE_FN((__m128i*)outdata_5, _mm256_extractf128_si256(b1, 1)); + _MM_STORE_FN((__m128i*)outdata_6, _mm256_extractf128_si256(b2, 1)); + _MM_STORE_FN((__m128i*)outdata_7, _mm256_extractf128_si256(b3, 1)); + + _MM_STORE_FN((__m128i*)(outdata_0 + 4), _mm256_castsi256_si128(b4)); + _MM_STORE_FN((__m128i*)(outdata_1 + 4), _mm256_castsi256_si128(b5)); + _MM_STORE_FN((__m128i*)(outdata_2 + 4), _mm256_castsi256_si128(b6)); + _MM_STORE_FN((__m128i*)(outdata_3 + 4), _mm256_castsi256_si128(b7)); + _MM_STORE_FN((__m128i*)(outdata_4 + 4), _mm256_extractf128_si256(b4, 1)); + _MM_STORE_FN((__m128i*)(outdata_5 + 4), _mm256_extractf128_si256(b5, 1)); + _MM_STORE_FN((__m128i*)(outdata_6 + 4), _mm256_extractf128_si256(b6, 1)); + _MM_STORE_FN((__m128i*)(outdata_7 + 4), _mm256_extractf128_si256(b7, 1)); +#else + +//#define _MM256_STORE_FN _mm256_store_si256 +#define _MM256_STORE_FN _mm256_storeu_si256 + out0 = _mm256_permute2x128_si256(b0, b4, 0b00100000); out1 = _mm256_permute2x128_si256(b1, b5, 0b00100000); out2 = _mm256_permute2x128_si256(b2, b6, 0b00100000); out3 = _mm256_permute2x128_si256(b3, b7, 0b00100000); + + _MM256_STORE_FN((__m256i*)outdata_0, out0); + _MM256_STORE_FN((__m256i*)outdata_1, out1); + _MM256_STORE_FN((__m256i*)outdata_2, out2); + _MM256_STORE_FN((__m256i*)outdata_3, out3); + out4 = _mm256_permute2x128_si256(b0, b4, 0b00110001); out5 = _mm256_permute2x128_si256(b1, b5, 0b00110001); out6 = _mm256_permute2x128_si256(b2, b6, 0b00110001); out7 = _mm256_permute2x128_si256(b3, b7, 0b00110001); - _mm256_store_si256((__m256i*)outdata_0, out0); - _mm256_store_si256((__m256i*)outdata_1, out1); - _mm256_store_si256((__m256i*)outdata_2, out2); - _mm256_store_si256((__m256i*)outdata_3, out3); - _mm256_store_si256((__m256i*)outdata_4, out4); - _mm256_store_si256((__m256i*)outdata_5, out5); - _mm256_store_si256((__m256i*)outdata_6, out6); - _mm256_store_si256((__m256i*)outdata_7, out7); - + _MM256_STORE_FN((__m256i*)outdata_4, out4); + _MM256_STORE_FN((__m256i*)outdata_5, out5); + _MM256_STORE_FN((__m256i*)outdata_6, out6); + _MM256_STORE_FN((__m256i*)outdata_7, out7); +#endif outdata_0 += 8; outdata_1 += 8; outdata_2 += 8; diff --git a/src/lib/xdsp/utests/conv_ci16_8cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_8cf32_utest.c index acfcf35f..955dce96 100644 --- a/src/lib/xdsp/utests/conv_ci16_8cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_8cf32_utest.c @@ -15,10 +15,10 @@ #define WORD_COUNT (4096u + 80u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) -#define SPEED_WORD_COUNT (32768u) +#define SPEED_WORD_COUNT (65536u) #define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) -static const unsigned packet_lens[3] = { 1024, 16384, SPEED_SIZE_BZ }; +static const unsigned packet_lens[4] = { 1024, 16384, 32768, SPEED_SIZE_BZ }; #define SPEED_MEASURE_ITERS 1000000 @@ -240,7 +240,7 @@ Suite * conv_ci16_8cf32_suite(void) Suite* s = suite_create("conv_ci16_8cf32"); ADD_REGRESS_TEST(s, conv_ci16_8cf32_check_simd); - ADD_PERF_LOOP_TEST(s, conv_ci16_8cf32_speed, 60, 0, 3); + ADD_PERF_LOOP_TEST(s, conv_ci16_8cf32_speed, 60, 0, 4); return s; } diff --git a/src/lib/xdsp/utests/conv_ci16_8ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_8ci16_utest.c index 53996d61..5c698f46 100644 --- a/src/lib/xdsp/utests/conv_ci16_8ci16_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_8ci16_utest.c @@ -10,7 +10,7 @@ #include "xdsp_utest_common.h" #include "conv_ci16_8ci16_2.h" -#define DEBUG_PRINT +#undef DEBUG_PRINT #define CHECK_WORD_COUNT (4096u + 80u) //must be a multiple of 4 #define CHECK_SIZE_BZ (CHECK_WORD_COUNT * sizeof(int16_t)) diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index 17c3fe8d..86beead2 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -82,8 +82,8 @@ int main(int argc, char** argv) #else //sr = srunner_create(conv_i16_f32_suite()); //sr = srunner_create(fft_window_ci16_cf32_suite()); - //sr = srunner_create(conv_ci16_8cf32_suite()); - sr = srunner_create(conv_ci16_8ci16_suite()); + sr = srunner_create(conv_ci16_8cf32_suite()); + srunner_add_suite(sr, conv_ci16_8ci16_suite()); //srunner_add_suite(sr, fft_window_cf32_suite()); //srunner_add_suite(sr, conv_f32_i12_suite()); From 30d50a780a4209f681b9edcad0cf8aa9ff5dc00a Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 9 Dec 2025 14:11:40 +0400 Subject: [PATCH 251/397] sfe_rx_4: fix typo in number of maximum channel check --- src/lib/ipblks/streams/sfe_rx_4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ipblks/streams/sfe_rx_4.c b/src/lib/ipblks/streams/sfe_rx_4.c index cdaf5265..68ba9e08 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.c +++ b/src/lib/ipblks/streams/sfe_rx_4.c @@ -526,7 +526,7 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str USDR_LOG("STRM", USDR_LOG_ERROR, "EXFERX: Unsupported channel count %d!\n", chns); return -EINVAL; } - if (fe->cfg_raw_chans >= MAX_EX_CHANS) { + if (fe->cfg_raw_chans > MAX_EX_CHANS) { USDR_LOG("STRM", USDR_LOG_ERROR, "EXFERX: Maximum channel count supported by the core is 16, requested %d!", fe->cfg_raw_chans); return -EINVAL; } From 8f598372a85e31dbc7f7629d34e3759841be619d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 9 Dec 2025 14:13:02 +0400 Subject: [PATCH 252/397] usdr_channel_info_map_default: initialize channel list to invalid mapping by default --- src/lib/ipblks/streams/streams_api.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/ipblks/streams/streams_api.c b/src/lib/ipblks/streams/streams_api.c index 3cbe2b1a..40c66f75 100644 --- a/src/lib/ipblks/streams/streams_api.c +++ b/src/lib/ipblks/streams/streams_api.c @@ -10,6 +10,8 @@ int usdr_channel_info_map_default(const usdr_channel_info_t* channels, const channel_map_info_t* map, unsigned max_chnum, channel_info_t* core_chans) { + memset(core_chans->ch_map, 0xff, sizeof(core_chans->ch_map)); + if (channels->phys_names == NULL && channels->phys_nums == NULL) { for (unsigned i = 0; i < channels->count; i++) { core_chans->ch_map[i] = i; From 0ab43ab676f50d7ee93855b858347bd6d7ca384d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 9 Dec 2025 14:14:34 +0400 Subject: [PATCH 253/397] sfetrx4: add 8-ch dsp chain support --- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 24 ++++++++++--------- src/lib/ipblks/streams/stream_sfetrx4_dma32.h | 3 +++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 3c1c21e2..8f4b20f7 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -361,7 +361,7 @@ int _sfetrx4_stream_send(stream_handle_t* str, if (stream->type != USDR_ZCPY_TX) return -ENOTSUP; - if (stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0) { + if (stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0 || stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { res = _extx_burstup(samples, brst_samples, &lgbursts); if (res) return res; @@ -575,10 +575,10 @@ int _sfetrx4_option_set(stream_handle_t* str, const char* name, int64_t in_val) const channel_info_t *new_map = (const channel_info_t *)in_val; if (stream->type == USDR_ZCPY_RX) { - if (stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0) + if (stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0_8) return -ENOTSUP; } else if (stream->type == USDR_ZCPY_TX) { - if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0) { + if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_8) { unsigned swap_ab_flag; int res = fe_tx4_swap_ab_get(stream->fe_chans, new_map, &swap_ab_flag); if (res) @@ -603,7 +603,7 @@ int _sfetrx4_option_set(stream_handle_t* str, const char* name, int64_t in_val) (stream->fe_complex ? 2 : 1) * stream->fe_chans, (const channel_info_t *)in_val); } else if (stream->type == USDR_ZCPY_TX && (strcmp(name, "mute") == 0)) { - if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0) { + if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_8) { stream->fe_old_tx_mute = in_val & 3; return sfe_tx4_upd(&stream->storage.srx4, stream->sync_base, @@ -792,7 +792,7 @@ static int initialize_stream_rx_32(device_t* device, } // TODO obtain exfe configuration constants - res = (fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0) ? + res = (fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0 || fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0_8) ? exfe_rx4_configure(fecfg, &sc, &fc) : sfe_rx4_configure(fecfg, &sc, &fc, &hw_chan_msk); if (res) @@ -1073,7 +1073,7 @@ static int initialize_stream_tx_32(device_t* device, sparams.out_max_bursts = 1; if (sparams.block_size > max_mtu) { - if (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0) { + if (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0 || fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { unsigned max_burst_sps = 8 * max_mtu / sparams.bits_per_sym; unsigned lgbrst; res = _extx_burstup(pktsyms, max_burst_sps, &lgbrst); @@ -1147,7 +1147,7 @@ static int initialize_stream_tx_32(device_t* device, strdev->burst_mask = 0; strdev->burst_count = sparams.out_max_bursts; - strdev->burst_align_bytes = (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0) ? 16 : 1; + strdev->burst_align_bytes = (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) ? 32 : (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0) ? 16 : 1; strdev->fe_old_tx_mute = fe_old_tx_mute; strdev->fe_old_tx_swap = fe_old_tx_swap; @@ -1205,9 +1205,10 @@ int create_sfetrx4_stream(device_t* device, switch (core_id) { case CORE_SFERX_DMA32_R0: case CORE_EXFERX_DMA32_R0: + case CORE_EXFERX_DMA32_R0_8: // TODO obtain dynamic config - fecfg.cfg_word_bytes = (core_id == CORE_SFERX_DMA32_R0) ? 8 : 16; - fecfg.cfg_raw_chans = (core_id == CORE_SFERX_DMA32_R0) ? 4 : 8; + fecfg.cfg_word_bytes = (core_id == CORE_SFERX_DMA32_R0) ? 8 : (core_id == CORE_EXFERX_DMA32_R0) ? 16 : 32; + fecfg.cfg_raw_chans = (core_id == CORE_SFERX_DMA32_R0) ? 4 : (core_id == CORE_EXFERX_DMA32_R0) ? 8 : 16; fecfg.cfg_dma_align_bytes = fecfg.cfg_word_bytes; res = initialize_stream_rx_32(device, chcount, channels, pktsyms, @@ -1217,9 +1218,10 @@ int create_sfetrx4_stream(device_t* device, break; case CORE_SFETX_DMA32_R0: case CORE_EXFETX_DMA32_R0: + case CORE_EXFETX_DMA32_R0_8: // TODO obtain dynamic config - fecfg.cfg_word_bytes = (core_id == CORE_SFETX_DMA32_R0) ? 8 : 16; - fecfg.cfg_raw_chans = (core_id == CORE_SFETX_DMA32_R0) ? 4 : 8; + fecfg.cfg_word_bytes = (core_id == CORE_SFETX_DMA32_R0) ? 8 : (core_id == CORE_EXFETX_DMA32_R0) ? 16 : 32; + fecfg.cfg_raw_chans = (core_id == CORE_SFETX_DMA32_R0) ? 4 : (core_id == CORE_EXFETX_DMA32_R0) ? 8 : 16; fecfg.cfg_dma_align_bytes = fecfg.cfg_word_bytes; res = initialize_stream_tx_32(device, chcount, channels, pktsyms, diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.h b/src/lib/ipblks/streams/stream_sfetrx4_dma32.h index e1881692..326bbd4a 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.h +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.h @@ -14,6 +14,9 @@ enum { CORE_EXFERX_DMA32_R0 = 256, CORE_EXFETX_DMA32_R0 = 257, + + CORE_EXFERX_DMA32_R0_8 = 258, + CORE_EXFETX_DMA32_R0_8 = 259, }; enum { From 86f932aceb3f3b50ba99864525edbb2d65b4620b Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 9 Dec 2025 14:15:59 +0400 Subject: [PATCH 254/397] dsdr_hiper: cache LMS8_LO PLL settings not to apply it twice succesfully --- src/lib/device/m2_dsdr/dsdr_hiper.c | 37 ++++++++++++++++++++++++----- src/lib/device/m2_dsdr/dsdr_hiper.h | 4 ++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 34f11ba0..b3e48a2c 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -865,6 +865,8 @@ int dsdr_hiper_fe_create(lldev_t dev, unsigned int spix_num, unsigned* plms8_mpw // LMS8 unsigned lms8_mask = (plms8_mpw_mask) ? *plms8_mpw_mask : (dfe->rev == HIPER_REV2) ? 0b001100 : 0; for (unsigned k = 0; k < 6; k++) { + opt_u64_set_null(&dfe->lms8_lo[k]); + uint32_t cfg = MAKE_SPIEXT_LSOPADR(MAKE_SPIEXT_CFG(LMS8_BCNTZ, k, LMS8_DIV), 0, spix_num); res = res ? res : dsdr_hiper_initialize_lms8(dfe, cfg, (lms8_mask >> k) & 1, &dfe->lms8[k]); } @@ -1686,6 +1688,7 @@ int dsdr_hiper_fe_rxlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_rxi if (high_path) { unsigned zeroes[4] = {0, 0, 0, 0}; + opt_u64_set_null(&def->lms8_lo[idx_off]); res = res ? res : lms8001a_ch_enable(&def->lms8[idx_off], 0x0, zeroes, zeroes); res = res ? res : lms8001_ch_enable(&def->lms8[idx], chmsk); } else if ((def->rev == HIPER_REV2) && ((rxpath & 0x3) == RXBAND_OPTS_BAND_1580_2760_BP)) { @@ -1695,7 +1698,10 @@ int dsdr_hiper_fe_rxlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_rxi res = res ? res : lms8001_ch_enable(&def->lms8[idx_off], 0x0); res = res ? res : lms8001a_ch_enable(&def->lms8[idx], 0, lnas, pas); - def->ucfg[chno].rx_nco = 0; + opt_u64_set_null(&def->lms8_lo[idx_off]); + opt_u64_set_null(&def->lms8_lo[idx]); + + def->ucfg[chno].rx_nco = def->ucfg[chno].rx_freq; *p_path = rxpath; *p_swap_rxiq = 0; @@ -1709,11 +1715,20 @@ int dsdr_hiper_fe_rxlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_rxi convert_lms8_gains_to_loss(def, (chno & 1) ? chno - 0 : chno + 1, pas + 3, lnas + 3); convert_lms8_gains_to_loss(def, (chno & 1) ? chno - 1 : chno + 0, pas + 2, lnas + 2); + opt_u64_set_null(&def->lms8_lo[idx_off]); res = res ? res : lms8001_ch_enable(&def->lms8[idx_off], 0x0); res = res ? res : lms8001a_ch_enable(&def->lms8[idx], chmsk, lnas, pas); } - res = res ? res : dsdr_hiper_fe_lms8_set_lo(def, idx, fLO); + if (def->lms8_lo[idx].set && def->lms8_lo[idx].value == fLO) { + USDR_LOG("HIPR", USDR_LOG_INFO, "HIPER_LMS8_%s: CH[%d] LMS[%d] LO Setup skipped\n", + s_lms8_names[idx], chno, idx); + } else { + res = res ? res : dsdr_hiper_fe_lms8_set_lo(def, idx, fLO); + if (res == 0) { + opt_u64_set_val(&def->lms8_lo[idx], fLO); + } + } def->ucfg[chno].rx_nco = fIF; *p_swap_rxiq = (fLOh) ? 1 : 0; @@ -1737,7 +1752,7 @@ int dsdr_hiper_fe_txlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_txi high_path = (def->ucfg[chno].tx_freq < 3500e6) ? false : true; } - uint64_t fIF = (high_path) ? 1875e6 : def->ucfg[chno].tx_freq; + uint64_t fIF = 1875e6; // (high_path) ? 1875e6 : def->ucfg[chno].tx_freq; uint64_t fLO = (high_path) ? def->ucfg[chno].tx_freq + fIF : 0; unsigned idx = get_lms8_tx_idx(chno); @@ -1745,14 +1760,24 @@ int dsdr_hiper_fe_txlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_txi (def->ucfg[chno].tx_en << 3) | (def->ucfg[chno - 1].tx_en << 2) : (def->ucfg[chno + 1].tx_en << 3) | (def->ucfg[chno].tx_en << 2); - res = res ? res : lms8001_core_enable(&def->lms8[idx], high_path); res = res ? res : lms8001_ch_enable(&def->lms8[idx], high_path ? chmsk : 0); if (fLO > 0) { - res = res ? res : dsdr_hiper_fe_lms8_set_lo(def, idx, fLO); + if (def->lms8_lo[idx].set && def->lms8_lo[idx].value == fLO) { + USDR_LOG("HIPR", USDR_LOG_INFO, "HIPER_LMS8_%s: CH[%d] LMS[%d] LO Setup skipped\n", + s_lms8_names[idx], chno, idx); + } else { + res = res ? res : dsdr_hiper_fe_lms8_set_lo(def, idx, fLO); + if (res == 0) { + opt_u64_set_val(&def->lms8_lo[idx], fLO); + } + } + def->ucfg[chno].tx_nco = fIF; + } else { + opt_u64_set_null(&def->lms8_lo[idx]); + def->ucfg[chno].tx_nco = def->ucfg[chno].tx_freq; } - def->ucfg[chno].tx_nco = fIF; *p_swap_txiq = high_path; *p_high_path = high_path; diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.h b/src/lib/device/m2_dsdr/dsdr_hiper.h index 07e6f297..799cd3d5 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.h +++ b/src/lib/device/m2_dsdr/dsdr_hiper.h @@ -3,6 +3,7 @@ #include "../device.h" #include "../hw/lms8001/lms8001.h" +#include "../dev_param.h" #define HIPER_MAX_HW_CHANS 4 @@ -107,6 +108,9 @@ struct dsdr_hiper_fe { uint32_t lms8st_int_mod; uint32_t lms8st_enabled; + // Cached LO values + opt_u64_t lms8_lo[6]; + // High level control fe_chan_config_t ucfg[HIPER_MAX_HW_CHANS]; }; From 422e196565139d66c69cf58d74d244334271fdf9 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 9 Dec 2025 14:17:01 +0400 Subject: [PATCH 255/397] m2_dsdr: unify 4-ch/8-ch DSP chain support alog with HIPER FE LO update --- src/lib/device/m2_dsdr/m2_dsdr.c | 1152 ++++++++++++++++++++---------- 1 file changed, 767 insertions(+), 385 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index f4a9495b..04102e26 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -17,7 +17,6 @@ #include "../device_ids.h" #include "../dev_param.h" -#include "../ipblks/streams/sfe_rx_4.h" #include "../ipblks/streams/stream_sfetrx4_dma32.h" #include "../ipblks/fgearbox.h" @@ -48,6 +47,12 @@ enum dsdr_jesdv { DSDR_JESD204C_6664_491 = 3, }; +enum dsdr_jesd_config { + JESD_MODE_4X_4X_491 = 0, + JESD_MODE_8X_8X_369 = 1, + JESD_MODE_8X_4X_491 = 8, +}; + // I2C buses // I2C3 () -- TCA6424AR ( 0 & 1), TMP114 // REF/I2C5 () -- TCA6424AR ( 0 ), DAC80501MD, LG77LIC, TMP114 @@ -265,12 +270,6 @@ const usdr_dev_param_constant_t s_params_m2_dsdr_rev000[] = { { "/ll/sdr/0/rfic/0", (uintptr_t)"afe79xx" }, { "/ll/device/name", (uintptr_t)"dsdr"}, - - // { "/ll/sdr/max_hw_rx_chans", 4 }, - // { "/ll/sdr/max_hw_tx_chans", 4 }, - - // { "/ll/sdr/max_sw_rx_chans", 4 }, - // { "/ll/sdr/max_sw_tx_chans", 4 }, }; static int dev_m2_dsdr_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -335,91 +334,20 @@ void chmsk_set_all(chmsk_t* msk) { *msk = ~((uint64_t)0); } -static int device_path_to_chmsk(const char* full_path, const char* basename, chmsk_t *hw_mask, chmsk_t *lg_mask); - - -#if 0 -static int device_path_to_chmsk(const char* full_path, const char* basename, chmsk_t *hw_mask, chmsk_t *lg_mask) -{ - const char* delim = ":_-"; - *hw_mask = 0; - *lg_mask = 0; - - size_t len = strlen(basename); - if (strncmp(full_path, basename, len)) { - return -ENOENT; - } - const char* lst = full_path + len; - if (*lst != '/') { - chmsk_set_all(lg_mask); - return -ENAVAIL; - } - - lst++; - - char chanlist[64*4]; - SAFE_STRCPY(chanlist, lst); - - char* saveptr; - char* str1; - unsigned t; - for (t = 0, str1 = chanlist; ; str1 = NULL, t++) { - const char* token = strtok_r(str1, delim, &saveptr); - if (token == NULL) { - break; - } - - if (isdigit(*token)) { - unsigned chn = atoi(token); - if (chn >= MAX_CHANNEL_NUMBER) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "Channel mask parsing for %s: incorrect channel number: %d, token# %d `%s`\n", full_path, chn, t, token); - return -EINVAL; - } - uint64_t chmsh = 1ull << chn; - if (chmsh & *lg_mask) { - USDR_LOG("UDEV", USDR_LOG_WARNING, "Channel mask parsing for %s: channel %d duplication, token# %d `%s`!\n", full_path, chn, t, token); - } - - *lg_mask |= chmsh; - } else if (isalpha(*token)) { - int chA = tolower(*token) - 'a'; - int chB = isalpha(*(token + 1)) ? tolower(*(token + 1)) - 'a' : -1; - - unsigned chn = (chB < 0) ? chA : ((chA + 1) * 26 + chB); - if (chn >= MAX_CHANNEL_NUMBER) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "Channel mask parsing for %s: incorrect channel number: %d, token# %d `%s`\n", full_path, chn, t, token); - return -EINVAL; - } - uint64_t chmsh = 1ull << chn; - if (chmsh & *hw_mask) { - USDR_LOG("UDEV", USDR_LOG_WARNING, "Channel mask parsing for %s: channel %d duplication, token# %d `%s`!\n", full_path, chn, t, token); - } - - *hw_mask |= chmsh; - } else { - USDR_LOG("UDEV", USDR_LOG_ERROR, "Channel mask parsing for %s: incorrect token# %d `%s`\n", full_path, t, token); - return -EINVAL; - } - } - - if (*hw_mask && *lg_mask) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "Hardware and logical channel types mixing for %s: HW_MSK=%" PRIu64 " LG_MSK=%" PRIu64 "\n", full_path, *hw_mask, *lg_mask); - return -EINVAL; - } - - return 0; -} -#endif +static int device_path_to_chmsk(const char* full_path, const char* basename, const channel_map_info_t* map, const unsigned max_lchan, chmsk_t *hw_mask, chmsk_t *lg_mask); -static int dev_m2_dsdr_numchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int dev_m2_dsdr_hrxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int dev_m2_dsdr_htxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int dev_m2_dsdr_lrxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int dev_m2_dsdr_ltxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); static const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { - { "/ll/sdr/max_hw_rx_chans", { NULL, dev_m2_dsdr_numchans_get } }, - { "/ll/sdr/max_hw_tx_chans", { NULL, dev_m2_dsdr_numchans_get } }, + { "/ll/sdr/max_hw_rx_chans", { NULL, dev_m2_dsdr_hrxnumchans_get } }, + { "/ll/sdr/max_hw_tx_chans", { NULL, dev_m2_dsdr_htxnumchans_get } }, - { "/ll/sdr/max_sw_rx_chans", { NULL, dev_m2_dsdr_numchans_get } }, - { "/ll/sdr/max_sw_tx_chans", { NULL, dev_m2_dsdr_numchans_get } }, + { "/ll/sdr/max_sw_rx_chans", { NULL, dev_m2_dsdr_lrxnumchans_get } }, + { "/ll/sdr/max_sw_tx_chans", { NULL, dev_m2_dsdr_ltxnumchans_get } }, { "/dm/rate/master", { dev_m2_dsdr_rate_set, NULL }}, { "/dm/rate/rxtxadcdac", { dev_m2_dsdr_rate_m_set, NULL }}, @@ -435,90 +363,90 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { { "/dm/sdr/0/rx/gain/1", { dev_m2_dsdr_gain_rx_set, NULL }}, { "/dm/sdr/0/rx/gain/2", { dev_m2_dsdr_gain_rx_set, NULL }}, { "/dm/sdr/0/rx/gain/3", { dev_m2_dsdr_gain_rx_set, NULL }}, - { "/dm/sdr/0/rx/gain/a", { dev_m2_dsdr_gain_rx_set, NULL }}, - { "/dm/sdr/0/rx/gain/b", { dev_m2_dsdr_gain_rx_set, NULL }}, - { "/dm/sdr/0/rx/gain/c", { dev_m2_dsdr_gain_rx_set, NULL }}, - { "/dm/sdr/0/rx/gain/d", { dev_m2_dsdr_gain_rx_set, NULL }}, + { "/dm/sdr/0/rx/gain/4", { dev_m2_dsdr_gain_rx_set, NULL }}, + { "/dm/sdr/0/rx/gain/5", { dev_m2_dsdr_gain_rx_set, NULL }}, + { "/dm/sdr/0/rx/gain/6", { dev_m2_dsdr_gain_rx_set, NULL }}, + { "/dm/sdr/0/rx/gain/7", { dev_m2_dsdr_gain_rx_set, NULL }}, { "/dm/sdr/0/rx/gain/auto", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, { "/dm/sdr/0/rx/gain/auto/0", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, { "/dm/sdr/0/rx/gain/auto/1", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, { "/dm/sdr/0/rx/gain/auto/2", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, { "/dm/sdr/0/rx/gain/auto/3", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, - { "/dm/sdr/0/rx/gain/auto/a", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, - { "/dm/sdr/0/rx/gain/auto/b", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, - { "/dm/sdr/0/rx/gain/auto/c", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, - { "/dm/sdr/0/rx/gain/auto/d", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, + { "/dm/sdr/0/rx/gain/auto/4", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, + { "/dm/sdr/0/rx/gain/auto/5", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, + { "/dm/sdr/0/rx/gain/auto/6", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, + { "/dm/sdr/0/rx/gain/auto/7", { dev_m2_dsdr_gain_rx_auto_set, NULL }}, { "/dm/sdr/0/rx/gain/lna", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, { "/dm/sdr/0/rx/gain/lna/0", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, { "/dm/sdr/0/rx/gain/lna/1", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, { "/dm/sdr/0/rx/gain/lna/2", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, { "/dm/sdr/0/rx/gain/lna/3", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, - { "/dm/sdr/0/rx/gain/lna/a", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, - { "/dm/sdr/0/rx/gain/lna/b", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, - { "/dm/sdr/0/rx/gain/lna/c", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, - { "/dm/sdr/0/rx/gain/lna/d", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, + { "/dm/sdr/0/rx/gain/lna/4", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, + { "/dm/sdr/0/rx/gain/lna/5", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, + { "/dm/sdr/0/rx/gain/lna/6", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, + { "/dm/sdr/0/rx/gain/lna/7", { dev_m2_dsdr_gain_rx_lna_set, NULL }}, { "/dm/sdr/0/rx/gain/pga", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, { "/dm/sdr/0/rx/gain/pga/0", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, { "/dm/sdr/0/rx/gain/pga/1", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, { "/dm/sdr/0/rx/gain/pga/2", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, { "/dm/sdr/0/rx/gain/pga/3", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, - { "/dm/sdr/0/rx/gain/pga/a", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, - { "/dm/sdr/0/rx/gain/pga/b", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, - { "/dm/sdr/0/rx/gain/pga/c", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, - { "/dm/sdr/0/rx/gain/pga/d", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, + { "/dm/sdr/0/rx/gain/pga/4", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, + { "/dm/sdr/0/rx/gain/pga/5", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, + { "/dm/sdr/0/rx/gain/pga/6", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, + { "/dm/sdr/0/rx/gain/pga/7", { dev_m2_dsdr_gain_rx_pga_set, NULL }}, { "/dm/sdr/0/tx/gain", { dev_m2_dsdr_gain_tx_set, NULL }}, { "/dm/sdr/0/tx/gain/0", { dev_m2_dsdr_gain_tx_set, NULL }}, { "/dm/sdr/0/tx/gain/1", { dev_m2_dsdr_gain_tx_set, NULL }}, { "/dm/sdr/0/tx/gain/2", { dev_m2_dsdr_gain_tx_set, NULL }}, { "/dm/sdr/0/tx/gain/3", { dev_m2_dsdr_gain_tx_set, NULL }}, - { "/dm/sdr/0/tx/gain/a", { dev_m2_dsdr_gain_tx_set, NULL }}, - { "/dm/sdr/0/tx/gain/b", { dev_m2_dsdr_gain_tx_set, NULL }}, - { "/dm/sdr/0/tx/gain/c", { dev_m2_dsdr_gain_tx_set, NULL }}, - { "/dm/sdr/0/tx/gain/d", { dev_m2_dsdr_gain_tx_set, NULL }}, + { "/dm/sdr/0/tx/gain/4", { dev_m2_dsdr_gain_tx_set, NULL }}, + { "/dm/sdr/0/tx/gain/5", { dev_m2_dsdr_gain_tx_set, NULL }}, + { "/dm/sdr/0/tx/gain/6", { dev_m2_dsdr_gain_tx_set, NULL }}, + { "/dm/sdr/0/tx/gain/7", { dev_m2_dsdr_gain_tx_set, NULL }}, { "/dm/sdr/0/rx/freqency", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/rx/freqency/0", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/rx/freqency/1", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/rx/freqency/2", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/rx/freqency/3", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, - { "/dm/sdr/0/rx/freqency/a", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, - { "/dm/sdr/0/rx/freqency/b", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, - { "/dm/sdr/0/rx/freqency/c", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, - { "/dm/sdr/0/rx/freqency/d", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/freqency/4", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/freqency/5", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/freqency/6", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/freqency/7", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/rx/dsa", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, { "/dm/sdr/0/rx/dsa/0", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, { "/dm/sdr/0/rx/dsa/1", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, { "/dm/sdr/0/rx/dsa/2", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, { "/dm/sdr/0/rx/dsa/3", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, - { "/dm/sdr/0/rx/dsa/a", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, - { "/dm/sdr/0/rx/dsa/b", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, - { "/dm/sdr/0/rx/dsa/c", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, - { "/dm/sdr/0/rx/dsa/d", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, + { "/dm/sdr/0/rx/dsa/4", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, + { "/dm/sdr/0/rx/dsa/5", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, + { "/dm/sdr/0/rx/dsa/6", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, + { "/dm/sdr/0/rx/dsa/7", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, { "/dm/sdr/0/tx/freqency", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency/0", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency/1", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency/2", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency/3", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, - { "/dm/sdr/0/tx/freqency/a", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, - { "/dm/sdr/0/tx/freqency/b", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, - { "/dm/sdr/0/tx/freqency/c", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, - { "/dm/sdr/0/tx/freqency/d", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/freqency/4", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/freqency/5", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/freqency/6", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/freqency/7", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, { "/dm/sdr/0/tx/dsa", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, { "/dm/sdr/0/tx/dsa/0", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, { "/dm/sdr/0/tx/dsa/1", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, { "/dm/sdr/0/tx/dsa/2", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, { "/dm/sdr/0/tx/dsa/3", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, - { "/dm/sdr/0/tx/dsa/a", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, - { "/dm/sdr/0/tx/dsa/b", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, - { "/dm/sdr/0/tx/dsa/c", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, - { "/dm/sdr/0/tx/dsa/d", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, + { "/dm/sdr/0/tx/dsa/4", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, + { "/dm/sdr/0/tx/dsa/5", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, + { "/dm/sdr/0/tx/dsa/6", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, + { "/dm/sdr/0/tx/dsa/7", { dev_m2_dsdr_sdr_tx_dsa_set, NULL }}, { "/dm/sdr/0/rx/bandwidth", { dev_m2_dsdr_dummy, NULL }}, @@ -543,16 +471,82 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { }; +// Maximum supported simultanious logical channels (inc. multiband configurations) +#define MAX_LOGIC_CHANS 8 +#define MAX_HIPER_FE_PORT 4 +#define MAX_PORT_BANDS 2 // HIPER FE channel map table -static const uint8_t s_chanmap_hw_to_fe[4] = { 2, 3, 1, 0 }; -static const uint8_t s_chanmap_fe_to_hw[4] = { 3, 2, 0, 1 }; +static const uint8_t s_chanmap_hw_to_fe[MAX_HIPER_FE_PORT] = { 2, 3, 1, 0 }; +static const uint8_t s_chanmap_fe_to_hw[MAX_HIPER_FE_PORT] = { 3, 2, 0, 1 }; enum DSDR_STATE { STATE_IDLE = 0, STATE_AFE_INIT = 1, }; +struct channel_logic_dsp_wire { + uint8_t dsp_type; + uint8_t hwport; + uint8_t band; +}; +typedef struct channel_logic_dsp_wire channel_logic_dsp_wire_t; + + +static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco[] = { + { NCO_RX, 0, 0 }, + { NCO_RX, 1, 0 }, + { NCO_RX, 2, 0 }, + { NCO_RX, 3, 0 }, +}; +static const channel_map_info_t s_dsdr_chmap_s_nco[] = { + { "a", 0 }, + { "b", 1 }, + { "c", 2 }, + { "d", 3 }, + { NULL, CH_NULL }, +}; + +static const channel_logic_dsp_wire_t s_dsdr_lmap_d_nco[] = { + { NCO_RX, 0, 0 }, + { NCO_RX, 1, 0 }, + { NCO_RX, 2, 0 }, + { NCO_RX, 3, 0 }, + { NCO_RX, 0, 1 }, + { NCO_RX, 1, 1 }, + { NCO_RX, 2, 1 }, + { NCO_RX, 3, 1 }, +}; +static const channel_map_info_t s_dsdr_chmap_d_nco[] = { + { "a0", 0 }, + { "b0", 1 }, + { "c0", 2 }, + { "d0", 3 }, + { "a1", 4 }, + { "b1", 5 }, + { "c1", 6 }, + { "d1", 7 }, + { NULL, CH_NULL }, +}; + +static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco_fb[] = { + { NCO_RX, 0, 0 }, + { NCO_RX, 1, 0 }, + { NCO_RX, 2, 0 }, + { NCO_RX, 3, 0 }, + { NCO_FB, 4, 0 }, + { NCO_FB, 5, 0 }, +}; +static const channel_map_info_t s_dsdr_chmap_s_nco_fb[] = { + { "a", 0 }, + { "b", 1 }, + { "c", 2 }, + { "d", 3 }, + { "f0", 4 }, + { "f1", 5 }, + { NULL, CH_NULL }, +}; + struct dev_m2_dsdr { device_t base; @@ -562,6 +556,7 @@ struct dev_m2_dsdr { unsigned type; unsigned jesdv; + unsigned jesd_x8; stream_handle_t* rx; stream_handle_t* tx; @@ -579,18 +574,29 @@ struct dev_m2_dsdr { const char* afecongiguration; uint32_t max_rate; // Maximum I/Q rate supported by HW + const channel_map_info_t *rx_chmap_info; + const channel_map_info_t *tx_chmap_info; + const channel_logic_dsp_wire_t *rx_lmap_info; + const channel_logic_dsp_wire_t *tx_lmap_info; + unsigned hw_enabled_tx; // HW Enabled channels unsigned hw_enabled_rx; // HW Enabled channels + unsigned logic_enabled_tx; // Logic Enabled channels + unsigned logic_enabled_rx; // Logic Enabled channels unsigned hw_mask_tx; // Physically wired TX channels unsigned hw_mask_rx; // Physically wired RX channels - unsigned hw_mask_fb; // Physically wired FB channels + + unsigned hw_chcnt_rx; + unsigned hw_chcnt_tx; + unsigned logic_chcnt_rx; + unsigned logic_chcnt_tx; unsigned hw_fpga_jesd_rx_en; // Physical lanes enabled bitmask 0: X0Y4, 1: X0Y5, ... 3: X0Y7 unsigned hw_fpga_jesd_tx_en; // Physical lanes enabled bitmask 0: X0Y4, 1: X0Y5, ... 3: X0Y7 - uint8_t hw_rxch_route[8]; - uint8_t hw_txch_route[8]; + uint8_t hw_rxch_route[MAX_LOGIC_CHANS]; // Physical channel reroute dueto absent physical channels (like in AFE7903) + uint8_t hw_txch_route[MAX_LOGIC_CHANS]; // Physical channel reroute dueto absent physical channels (like in AFE7903) uint32_t adc_rate; unsigned rxbb_rate; @@ -604,12 +610,19 @@ struct dev_m2_dsdr { uint8_t rx_activated; // 0xff means channel not wired - uint8_t rx_logic_to_hw[8]; // logic <- hw, index is logic chnum - uint8_t tx_hw_to_logic[8]; // hw -> logic, index is hw chnum + uint8_t rx_ordinal_to_logic[MAX_LOGIC_CHANS]; + uint8_t tx_ordinal_to_logic[MAX_LOGIC_CHANS]; + //uint8_t tx_hw_to_logic[MAX_LOGIC_CHANS]; // hw -> logic, index is hw chnum // Configuration parameters - opt_u64_t rx_freqs[8]; - opt_u64_t tx_freqs[8]; + opt_u64_t rx_ord_freqs[MAX_LOGIC_CHANS]; + opt_u64_t tx_ord_freqs[MAX_LOGIC_CHANS]; + + // For proper FE configuration in dual-band DSP configuration indexed by hwidx, band_no + opt_u64_t rx_bxfc[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; + opt_u64_t tx_bxfc[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; + opt_u64_t rx_raw_nco[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; + opt_u64_t tx_raw_nco[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; channel_info_t rx_chans; channel_info_t tx_chans; @@ -646,15 +659,28 @@ bool dev_m2_dsdr_has_hiper(dev_m2_dsdr_t* d) } -int dev_m2_dsdr_numchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +int dev_m2_dsdr_lrxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; - if (d->cfg_afe_type == 7903) - *ovalue = 2; - else - *ovalue = 4; + return d->logic_chcnt_rx; +} - return 0; +int dev_m2_dsdr_ltxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; + return d->logic_chcnt_tx; +} + +int dev_m2_dsdr_htxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; + return d->hw_chcnt_tx; +} + +int dev_m2_dsdr_hrxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; + return d->hw_chcnt_rx; } int dev_m2_dsdr_rx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -673,14 +699,17 @@ static int dsdr_update_rx_remap(dev_m2_dsdr_t* d) { // Mark corresponding RX chanel uint64_t hiper_cfg_msk = 0; - unsigned rx_remap = 0; + //unsigned rx_remap = 0; int res = 0; - for (unsigned i = 0; i < 4; i++) { - if (d->rx_logic_to_hw[i] != 0xff) { - rx_remap |= (d->rx_logic_to_hw[i] & 0x3) << (2 * i); + for (unsigned i = 0; i < MAX_LOGIC_CHANS; i++) { + if (d->rx_ordinal_to_logic[i] != 0xff) { + //rx_remap |= (d->rx_ordinal_to_logic[i] & 0x3) << (2 * i); - hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[d->rx_logic_to_hw[i]]); + unsigned hw_chan = d->rx_lmap_info[d->rx_ordinal_to_logic[i]].hwport; + if (hw_chan < MAX_HIPER_FE_PORT) { + hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[hw_chan]); + } } } @@ -697,14 +726,27 @@ static int dsdr_update_tx_remap(dev_m2_dsdr_t* d) { // Mark corresponding TX chanel uint64_t hiper_cfg_msk = 0; - unsigned tx_remap = 0; + //unsigned tx_remap = 0; int res = 0; for (unsigned i = 0; i < 4; i++) { - if (d->tx_hw_to_logic[i] != 0xff) { - tx_remap |= (d->tx_hw_to_logic[i] & 0x3) << (2 * i); - - hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[i]); + //if (d->tx_hw_to_logic[i] != 0xff) { + //tx_remap |= (d->tx_hw_to_logic[i] & 0x3) << (2 * i); + + //unsigned hw_chan = d->tx_lmap_info[d->rx_ordinal_to_logic[i]].hwport; + //if (hw_chan < MAX_ANT_PORT) { + // + //} + // hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[i]); + //} + + if (d->tx_ordinal_to_logic[i] != 0xff) { + //tx_remap |= (d->rx_ordinal_to_logic[i] & 0x3) << (2 * i); + + unsigned hw_chan = d->tx_lmap_info[d->tx_ordinal_to_logic[i]].hwport; + if (hw_chan < MAX_HIPER_FE_PORT) { + hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[hw_chan]); + } } } @@ -716,114 +758,302 @@ static int dsdr_update_tx_remap(dev_m2_dsdr_t* d) return res; } -static int dsdr_iterate_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val, const char* basename, bool rxchans) +// Function tries to parse and match names to logical channels and iterate with ordinal index +static int dsdr_iterate_ordinal_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val, const char* basename, bool rxchans) { dev_m2_dsdr_t *d = (dev_m2_dsdr_t *)ud; vfs_object_t ph; chmsk_t logic_msk; - chmsk_t hw_msk; - int res = device_path_to_chmsk(obj->full_path, basename, &hw_msk, &logic_msk); + chmsk_t logic_enabled; + chmsk_t ordinal_msk; + chmsk_t ordinal_enabled; + int res = device_path_to_chmsk(obj->full_path, basename, + rxchans ? d->rx_chmap_info : d->tx_chmap_info, + rxchans ? d->logic_chcnt_rx : d->logic_chcnt_tx, + &logic_msk, &ordinal_msk); if (res == -ENAVAIL) { // No channel information were specified, apply settings to all HW enabled channels or cache the value - if (rxchans) { - hw_msk = d->rx_activated ? d->hw_enabled_rx : 0xf; - } else { - hw_msk = d->tx_activated ? d->hw_enabled_tx : 0xf; - } + ordinal_msk = 0; logic_msk = 0; res = 0; } else if (res != 0) { return res; } + if (rxchans) { + logic_enabled = d->rx_activated ? d->logic_enabled_rx : 0xf; + } else { + logic_enabled = d->tx_activated ? d->logic_enabled_tx : 0xf; + } + + ordinal_enabled = 0; + if (logic_msk != 0) { + logic_enabled &= logic_msk; + } + + for (unsigned i = 0; i < (rxchans ? d->logic_chcnt_rx : d->logic_chcnt_tx); i++) { + if (chmsk_is_set(&logic_enabled, rxchans ? d->rx_ordinal_to_logic[i] : d->tx_ordinal_to_logic[i])) { + ordinal_enabled |= (1 << i); + } + } + if (ordinal_msk != 0) { + ordinal_enabled &= ordinal_msk; + } + + ph.type = obj->type; ph.object = obj->object; ph.data = obj->data; ph.ops = obj->ops; ph.full_path[0] = 0; - USDR_LOG("HIPR", USDR_LOG_WARNING, "Setting parameter `%s` to LOGIC: %08x HW: %08x chans\n", - obj->full_path, (unsigned)logic_msk, (unsigned)hw_msk); + USDR_LOG("HIPR", USDR_LOG_WARNING, "Setting parameter `%s` to LOGIC: %08x ORD: %08x chans\n", + obj->full_path, (unsigned)logic_msk, (unsigned)ordinal_enabled); + // We rely on ordinal numbers for API simplification + for (unsigned i = 0; i < (rxchans ? d->logic_chcnt_rx : d->logic_chcnt_tx); i++) { + if (chmsk_is_set(&ordinal_enabled, i)) { + ph.full_path[1] = i; + res = res ? res : obj->ops.si64(&ph, val); + } + } + +#if 0 for (unsigned i = 0; i < DSDR_CHANS_HW; i++) { if (chmsk_is_set(&hw_msk, i)) { - ph.full_path[1] = rxchans ? d->hw_rxch_route[i] :d->hw_txch_route[i]; // i; + ph.full_path[1] = rxchans ? d->hw_rxch_route[i] : d->hw_txch_route[i]; // i; res = res ? res : obj->ops.si64(&ph, val); } } + for (unsigned i = 0; i < DSDR_CHANS_LOGIC; i++) { if (chmsk_is_set(&logic_msk, i)) { - if (rxchans) { - uint8_t map = d->rx_logic_to_hw[i]; - if (map == 0xff) { - // Channel disabled - continue; - } - - ph.full_path[1] = rxchans ? d->hw_rxch_route[i] :d->hw_txch_route[i]; //i; - res = res ? res : obj->ops.si64(&ph, val); - } else { - // One logical TX channel can be mapped to many physical + uint8_t map = (rxchans) ? d->rx_ordinal_to_logic[i] : d->tx_ordinal_to_logic[i]; + if (map == 0xff) { + // Channel disabled + continue; + } - for (unsigned j = 0; j < DSDR_CHANS_HW; j++) { - if (d->tx_hw_to_logic[j] != i) - continue; + ph.full_path[1] = rxchans ? d->hw_rxch_route[i] : d->hw_txch_route[i]; //i; + res = res ? res : obj->ops.si64(&ph, val); - ph.full_path[1] = rxchans ? d->hw_rxch_route[i] :d->hw_txch_route[i]; //i; - res = res ? res : obj->ops.si64(&ph, val); - } - } } } - +#endif return res; } -static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned chno) +static const channel_logic_dsp_wire_t *get_chmapnfo_from_ordinal(dev_m2_dsdr_t* d, bool rx, unsigned ordinal) +{ + if (ordinal >= (rx ? d->logic_chcnt_rx : d->logic_chcnt_tx)) { + return NULL; + } + uint8_t logic_num = (rx ? d->rx_ordinal_to_logic[ordinal] : d->tx_ordinal_to_logic[ordinal]); + if (logic_num == 0xff) { + return NULL; + } + return rx ? &d->rx_lmap_info[logic_num] : &d->tx_lmap_info[logic_num]; +} + +static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned ord) { int res = 0; - opt_u64_set_val(& d->rx_freqs[chno], freq); + opt_u64_set_val(&d->rx_ord_freqs[ord], freq); if (!d->rx_activated) { return 0; } + // Ordinal to logic converter + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, ord); + if (!w) { + return -EINVAL; + } + unsigned hwidx = d->hw_rxch_route[w->hwport]; + uint64_t ncoval = freq; - if (dev_m2_dsdr_has_hiper(d)) { + if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { bool ch_rxiq; bool mod = false; - unsigned fe_chan = s_chanmap_hw_to_fe[chno]; - int res = dsdr_hiper_fe_rx_freq_set(&d->hiper, fe_chan, freq, &ncoval, &ch_rxiq); + const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; + const uint8_t iter_shared_selector[4] = { 0, 0, 1, 1 }; + uint64_t chan_mid = 0; + unsigned cnt = 0; + int res = 0; + const bool shared_lo_cfg_mode = true; + + opt_u64_set_val(&d->rx_bxfc[hwidx][w->band], freq); + + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { + if (d->rx_bxfc[iter_hwid][j].set) { + chan_mid += d->rx_bxfc[iter_hwid][j].value; + cnt++; + } + } + } + chan_mid /= cnt; + + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + res = res ? res : dsdr_hiper_fe_rx_freq_set(&d->hiper, s_chanmap_hw_to_fe[iter_hwid], chan_mid, &ncoval, &ch_rxiq); + } + if (res) return res; - for (unsigned k = 0; k < DSDR_CHANS_HW; k++) { - if ((d->rx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG) == chno) { - uint8_t nchan = (ch_rxiq) ? d->rx_chans.ch_map[k] | CH_SWAP_IQ_FLAG : d->rx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG; - if (nchan != d->rx_chans.ch_map[k]) { - d->rx_chans.ch_map[k] = nchan; - mod = true; + for (unsigned k = 0; k < d->logic_chcnt_rx; k++) { + uint8_t logic_ch = d->rx_ordinal_to_logic[k]; + if (logic_ch == 0xff) + continue; + + unsigned hw_iter = d->hw_rxch_route[d->rx_lmap_info[logic_ch].hwport]; + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + + if (iter_hwid == hw_iter) { + uint8_t nchan = (ch_rxiq) ? d->rx_chans.ch_map[k] | CH_SWAP_IQ_FLAG : d->rx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG; + if (nchan != d->rx_chans.ch_map[k]) { + d->rx_chans.ch_map[k] = nchan; + mod = true; + } } } } if (mod) { res = res ? res : d->rx->ops->option_set(d->rx, "chmap", (uintptr_t)&d->rx_chans); } + + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + + for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { + if (!d->rx_bxfc[iter_hwid][j].set) + continue; + + uint64_t freq_req = d->rx_bxfc[iter_hwid][j].value; + int64_t nco_offset = freq_req - chan_mid; + uint64_t freq_mod = ch_rxiq ? (ncoval - nco_offset) : (ncoval + nco_offset); + + if (d->rx_raw_nco[iter_hwid][j].set && d->rx_raw_nco[iter_hwid][j].value == freq_mod) + continue; + + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_RX, iter_hwid, freq_mod / 1000, 0, j); + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f RX_NCO=%.3f MID_F=%.3f\n", + ord, iter_hwid + 'A', j, freq_req / 1.0e6, freq_mod / 1.0e6, chan_mid / 1.0e6); + + opt_u64_set_val(&d->rx_raw_nco[iter_hwid][j], freq_mod); + } + } + + return res; } - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d] F=%.3f RX_NCO=%.3f\n", chno, freq / 1.0e6, ncoval / 1.0e6); - res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_RX, chno, ncoval / 1000, 0, 0); + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f RX_NCO=%.3f\n", ord, hwidx + 'A', w->band, freq / 1.0e6, ncoval / 1.0e6); + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_RX, hwidx, ncoval / 1000, 0, w->band); return res; } -static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned chno) +static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned ord) { - opt_u64_set_val(& d->tx_freqs[chno], freq); + int res = 0; + opt_u64_set_val(& d->tx_ord_freqs[ord], freq); if (!d->tx_activated) { return 0; } + // Ordinal to logic converter + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, ord); + if (!w) { + return -EINVAL; + } + unsigned hwidx = d->hw_txch_route[w->hwport]; + + uint64_t ncoval = freq; + if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { + bool ch_txiq; + bool mod = false; + const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; + const uint8_t iter_shared_selector[4] = { 0, 0, 1, 1 }; + uint64_t chan_mid = 0; + unsigned cnt = 0; + int res = 0; + const bool shared_lo_cfg_mode = true; + + opt_u64_set_val(&d->tx_bxfc[hwidx][w->band], freq); + + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { + if (d->tx_bxfc[iter_hwid][j].set) { + chan_mid += d->tx_bxfc[iter_hwid][j].value; + cnt++; + } + } + } + chan_mid /= cnt; + + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + res = res ? res : dsdr_hiper_fe_tx_freq_set(&d->hiper, s_chanmap_hw_to_fe[iter_hwid], chan_mid, &ncoval, &ch_txiq); + } + + if (res) + return res; + + for (unsigned k = 0; k < d->logic_chcnt_tx; k++) { + uint8_t logic_ch = d->tx_ordinal_to_logic[k]; + if (logic_ch == 0xff) + continue; + + unsigned hw_iter = d->hw_txch_route[d->tx_lmap_info[logic_ch].hwport]; + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + + if (iter_hwid == hw_iter) { + uint8_t nchan = (ch_txiq) ? d->tx_chans.ch_map[k] | CH_SWAP_IQ_FLAG : d->tx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG; + if (nchan != d->tx_chans.ch_map[k]) { + d->tx_chans.ch_map[k] = nchan; + mod = true; + } + } + } + } + if (mod) { + res = res ? res : d->tx->ops->option_set(d->tx, "chmap", (uintptr_t)&d->tx_chans); + } + + for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { + unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + + for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { + if (!d->tx_bxfc[iter_hwid][j].set) + continue; + + uint64_t freq_req = d->tx_bxfc[iter_hwid][j].value; + int64_t nco_offset = freq_req - chan_mid; + uint64_t freq_mod = ch_txiq ? (ncoval - nco_offset) : (ncoval + nco_offset); + + if (d->tx_raw_nco[iter_hwid][j].set && d->tx_raw_nco[iter_hwid][j].value == freq_mod) + continue; + + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_TX, iter_hwid, freq_mod / 1000, 0, j); + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f TX_NCO=%.3f MID_F=%.3f\n", + ord, iter_hwid + 'A', j, freq_req / 1.0e6, freq_mod / 1.0e6, chan_mid / 1.0e6); + + opt_u64_set_val(&d->tx_raw_nco[iter_hwid][j], freq_mod); + } + } + + return res; + } + + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f TX_NCO=%.3f\n", ord, hwidx + 'A', w->band, freq / 1.0e6, ncoval / 1.0e6); + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_TX, hwidx, ncoval / 1000, 0, w->band); + return res; +#if 0 uint64_t ncoval = freq; if (dev_m2_dsdr_has_hiper(d)) { bool ch_txiq; @@ -850,6 +1080,7 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d] F=%.3f TX_NCO=%.3f\n", chno, freq / 1.0e6, ncoval / 1.0e6); return d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_TX, chno, ncoval / 1000, 0, 0); +#endif } int dev_m2_dsdr_sdr_rx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -859,7 +1090,7 @@ int dev_m2_dsdr_sdr_rx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/rx/freqency", true); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/freqency", true); return dsdr_set_rx_frequency_chan(d, value, obj->full_path[1]); } @@ -871,11 +1102,15 @@ int dev_m2_dsdr_sdr_rx_dsa_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/rx/dsa", true); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/dsa", true); unsigned i = obj->full_path[1]; - int res = d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, value); - return res; + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, i); + if (!w) { + return -EINVAL; + } + + return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, d->hw_rxch_route[w->hwport], value); } int dev_m2_dsdr_sdr_tx_dsa_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -885,11 +1120,15 @@ int dev_m2_dsdr_sdr_tx_dsa_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/tx/dsa", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/tx/dsa", false); unsigned i = obj->full_path[1]; - int res = d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_TX, i, value); - return res; + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, false, i); + if (!w) { + return -EINVAL; + } + + return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, d->hw_txch_route[w->hwport], value); } @@ -900,7 +1139,7 @@ int dev_m2_dsdr_sdr_tx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/tx/freqency", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/tx/freqency", false); return dsdr_set_tx_frequency_chan(d, value, obj->full_path[1]); } @@ -912,17 +1151,23 @@ int dev_m2_dsdr_gain_rx_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t v return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/rx/gain", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/gain", true); int res = 0; unsigned i = obj->full_path[1]; unsigned dsa_attn = (value > 25) ? 0 : 50 - 2 * value; unsigned rem_gain = (value > 25) ? value - 25 : 0; + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, i); + if (!w) { + return -EINVAL; + } + unsigned hwidx = d->hw_rxch_route[w->hwport]; - if (dev_m2_dsdr_has_hiper(d)) { - res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[i], rem_gain, NULL); + if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { + res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[hwidx], rem_gain, NULL); } - res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, dsa_attn); + + res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); return res; } @@ -933,13 +1178,18 @@ int dev_m2_dsdr_gain_tx_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t v return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/tx/gain", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/tx/gain", false); - int res = 0; unsigned i = obj->full_path[1]; unsigned dsa_attn = (value > 29) ? 0 : 29 - value; - res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_TX, i, dsa_attn); - return res; + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, false, i); + if (!w) { + return -EINVAL; + } + unsigned hwidx = d->hw_txch_route[w->hwport]; + return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); + //res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_TX, i, dsa_attn); + //return res; } int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t value) @@ -949,17 +1199,23 @@ int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint6 return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/rx/gain/auto", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/gain/auto", true); int res = 0; unsigned i = obj->full_path[1]; unsigned dsa_attn = (value > 25) ? 0 : 50 - 2 * value; unsigned rem_gain = (value > 25) ? value - 25 : 0; + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, i); + if (!w) { + return -EINVAL; + } + unsigned hwidx = d->hw_rxch_route[w->hwport]; - if (dev_m2_dsdr_has_hiper(d)) { - res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[i], rem_gain, NULL); + if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { + res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[hwidx], rem_gain, NULL); } - res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, dsa_attn); + res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); + //res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, dsa_attn); return res; } @@ -970,11 +1226,22 @@ int dev_m2_dsdr_gain_rx_lna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu return -ENOTSUP; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/rx/gain/lna", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/gain/lna", true); unsigned i = obj->full_path[1]; - int res = dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[i], value, NULL); - return res; + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, i); + if (!w) { + return -EINVAL; + } + unsigned hwidx = d->hw_rxch_route[w->hwport]; + + if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { + return dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[hwidx], value, NULL); + } + + return -EINVAL; + //int res = dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[i], value, NULL); + //return res; } int dev_m2_dsdr_gain_rx_pga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -984,14 +1251,18 @@ int dev_m2_dsdr_gain_rx_pga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu return 0; if (obj->full_path[0]) - return dsdr_iterate_chans(ud, obj, value, "/dm/sdr/0/rx/gain/pga", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/gain/pga", true); unsigned i = obj->full_path[1]; - if (value > 25) - value = 25; - - int res = d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, 50 - 2 * value); - return res; + unsigned dsa_attn = (value > 25) ? 0 : 50 - 2 * value; + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, i); + if (!w) { + return -EINVAL; + } + unsigned hwidx = d->hw_rxch_route[w->hwport]; + return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); + //int res = d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, 50 - 2 * value); + //return res; } @@ -1029,7 +1300,6 @@ static int dsdr_set_rates(dev_m2_dsdr_t* d, uint32_t rx_rate, uint32_t tx_rate) res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x2); } - USDR_LOG("DSDR", USDR_LOG_ERROR, "Set rate: RX %.3f Mhz => %.3f (Decim: %d) -- TX %.3f Mhz => %.3f (Inter: %d)\n", rx_rate / 1.0e6, d->rxbb_rate / 1.0e6, d->rxbb_decim, tx_rate / 1.0e6, d->txbb_rate / 1.0e6, d->txbb_inter); @@ -1054,16 +1324,6 @@ static int dsdr_set_rates(dev_m2_dsdr_t* d, uint32_t rx_rate, uint32_t tx_rate) res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x0); } -#if 0 - for (int i = 0; i < 5; i++) { - uint32_t clk; - res = res ? res : dev_gpi_get32(d->base.dev, 20, &clk); - - USDR_LOG("DSDR", USDR_LOG_ERROR, "Clk %d: %d\n", clk >> 28, clk & 0xfffffff); - usleep(0.5 * 1e6); - } -#endif - return res; } @@ -1097,22 +1357,28 @@ static int dsdr_check_fpga_gtrx(dev_m2_dsdr_t* o) uint32_t fpga_jesd = ~0, fpga_err_0 = ~0, fpga_err_1 = ~0; unsigned delay; int res = 0; - res = res ? res : dev_gpi_get32(o->base.dev, IGPI_JESD_SYSREF_RAC, &fpga_jesd); - res = res ? res : dev_gpi_get32(o->base.dev, IGPI_JESD_FPGA_ERR_0, &fpga_err_0); - res = res ? res : dev_gpi_get32(o->base.dev, IGPI_JESD_FPGA_ERR_1, &fpga_err_1); - - delay = (fpga_jesd >> 16) & 0x3ff; - USDR_LOG("DSDR", (fpga_err_0 != 0 || fpga_err_1 != 0) ? USDR_LOG_ERROR : USDR_LOG_INFO, - "FPGA JESD: SYSREF realign TX/RX = %08x Delay = %d PLL Locked %d BUFFER_OVERFLOW: %04x ERRS %04x %04x %04x %04x \n", - fpga_jesd & 0xff, delay, (fpga_jesd >> 26) & 3, fpga_jesd >> 28, - fpga_err_0 >> 16, fpga_err_0 & 0xffff, fpga_err_1 >> 16, fpga_err_1 & 0xffff); - - USDR_LOG("DSDR", USDR_LOG_INFO, "FPGA JESD lanes: 3 2 1 0\n"); - USDR_LOG("DSDR", USDR_LOG_INFO, "Block Header errors: %2d %2d %2d %2d\n", (fpga_err_0 >> 12) & 0xf, (fpga_err_0 >> 8) & 0xf, (fpga_err_0 >> 4) & 0xf, (fpga_err_0 >> 0) & 0xf); - USDR_LOG("DSDR", USDR_LOG_INFO, "End of Multi-Block errors: %2d %2d %2d %2d\n", (fpga_err_0 >> 28) & 0xf, (fpga_err_0 >> 24) & 0xf, (fpga_err_0 >> 20) & 0xf, (fpga_err_0 >> 16) & 0xf); - USDR_LOG("DSDR", USDR_LOG_INFO, "End of Extended Multi-Block errors: %2d %2d %2d %2d\n", (fpga_err_1 >> 12) & 0xf, (fpga_err_1 >> 8) & 0xf, (fpga_err_1 >> 4) & 0xf, (fpga_err_1 >> 0) & 0xf); - USDR_LOG("DSDR", USDR_LOG_INFO, "CRC mismatch errors: %2d %2d %2d %2d\n", (fpga_err_1 >> 28) & 0xf, (fpga_err_1 >> 24) & 0xf, (fpga_err_1 >> 20) & 0xf, (fpga_err_1 >> 16) & 0xf); + for (unsigned q = 0; q < (o->jesd_x8 ? 2 : 1); q++) { + if (o->jesd_x8) { + res = res ? res : dev_gpo_set(o->base.dev, IGPO_TIAFE_MASTER_RESET_N, q == 0 ? 0x01 : 0x81); + } + + res = res ? res : dev_gpi_get32(o->base.dev, IGPI_JESD_SYSREF_RAC, &fpga_jesd); + res = res ? res : dev_gpi_get32(o->base.dev, IGPI_JESD_FPGA_ERR_0, &fpga_err_0); + res = res ? res : dev_gpi_get32(o->base.dev, IGPI_JESD_FPGA_ERR_1, &fpga_err_1); + + delay = (fpga_jesd >> 16) & 0x3ff; + USDR_LOG("DSDR", (fpga_err_0 != 0 || fpga_err_1 != 0) ? USDR_LOG_ERROR : USDR_LOG_INFO, + "FPGA JESD: SYSREF realign TX/RX = %08x Delay = %d PLL Locked %d BUFFER_OVERFLOW: %04x ERRS %04x %04x %04x %04x \n", + fpga_jesd & 0xff, delay, (fpga_jesd >> 26) & 3, fpga_jesd >> 28, + fpga_err_0 >> 16, fpga_err_0 & 0xffff, fpga_err_1 >> 16, fpga_err_1 & 0xffff); + + USDR_LOG("DSDR", USDR_LOG_INFO, "FPGA JESD lanes: 3 2 1 0\n"); + USDR_LOG("DSDR", USDR_LOG_INFO, "Block Header errors: %2d %2d %2d %2d\n", (fpga_err_0 >> 12) & 0xf, (fpga_err_0 >> 8) & 0xf, (fpga_err_0 >> 4) & 0xf, (fpga_err_0 >> 0) & 0xf); + USDR_LOG("DSDR", USDR_LOG_INFO, "End of Multi-Block errors: %2d %2d %2d %2d\n", (fpga_err_0 >> 28) & 0xf, (fpga_err_0 >> 24) & 0xf, (fpga_err_0 >> 20) & 0xf, (fpga_err_0 >> 16) & 0xf); + USDR_LOG("DSDR", USDR_LOG_INFO, "End of Extended Multi-Block errors: %2d %2d %2d %2d\n", (fpga_err_1 >> 12) & 0xf, (fpga_err_1 >> 8) & 0xf, (fpga_err_1 >> 4) & 0xf, (fpga_err_1 >> 0) & 0xf); + USDR_LOG("DSDR", USDR_LOG_INFO, "CRC mismatch errors: %2d %2d %2d %2d\n", (fpga_err_1 >> 28) & 0xf, (fpga_err_1 >> 24) & 0xf, (fpga_err_1 >> 20) & 0xf, (fpga_err_1 >> 16) & 0xf); + } return res; } @@ -1285,7 +1551,7 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) { lldev_t dev = dd->base.dev; int res = 0; - uint32_t d; + uint32_t d = 0; bool pll_ready = false; res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 1); @@ -1294,17 +1560,15 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_BUFFER_RELDLY_0, 0); // 0 means autodetect and adjust - // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_0, 0x10); - // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_1, 0x32); - - // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_0, 0x10); - // res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_1, 0x32); - res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_0, dd->cfg_rx_lanemap & 0xff); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_1, (dd->cfg_rx_lanemap >> 8) & 0xff); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_2, (dd->cfg_rx_lanemap >> 16) & 0xff); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_3, (dd->cfg_rx_lanemap >> 24) & 0xff); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_0, dd->cfg_tx_lanemap & 0xff); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_1, (dd->cfg_tx_lanemap >> 8) & 0xff); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_2, (dd->cfg_tx_lanemap >> 16) & 0xff); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_MAP_3, (dd->cfg_tx_lanemap >> 24) & 0xff); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_POLARITY, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_POLARITY, 0x0); @@ -1312,14 +1576,13 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_ENABLED, dd->hw_fpga_jesd_rx_en); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_ENABLED, dd->hw_fpga_jesd_tx_en); - usleep(1); + res = res ? res : usleep(1000); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_MASTER_RESET_N, 1); for (unsigned k = 0; k < 100; k++) { - usleep(10000); - - res = dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); + res = res ? res : usleep(10000); + res = res ? res : dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); if (d & 0x08000000) { pll_ready = true; @@ -1332,12 +1595,12 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) return -EIO; } - usleep(10000); + res = res ? res : usleep(100000); //TODO check // TODO wait for PLL to lock.. res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_SYNC_RESET, 0); - usleep(10000); + res = res ? res : usleep(10000); res = res ? res :dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); @@ -1351,9 +1614,7 @@ static int usdr_jesd204b_bringup_post(struct dev_m2_dsdr *dd) uint32_t d = 0; res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 0); - - usleep(10000); - + res = res ? res : usleep(10000); res = res ? res : dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); return res; @@ -1371,7 +1632,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->subdev = 0; d->dsdr_state = STATE_IDLE; - d->hw_mask_fb = 0; + d->hw_mask_rx = 0xf; // RX_3 RX_2 RX_1 RX_0 d->hw_mask_tx = 0xf; // TX_3 TX_2 TX_1 TX_0 d->hw_fpga_jesd_rx_en = 0xf; @@ -1396,13 +1657,76 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** if (getenv("DSDR_AFE7903")) { d->hw_mask_rx = 0x5; // RX_3 RX_1 d->hw_mask_tx = 0xA; // TX_4 TX_2 - - // d->hw_fpga_jesd_rx_en = 0xc; - // d->hw_fpga_jesd_tx_en = 0xc; } devid = (hwid >> 16) & 0xff; jesdv = (hwid >> 8) & 0xff; + bool dpump_afe_clk = false; + bool jesd_x8 = false; + if (jesdv & 0x08) { + dpump_afe_clk = true; + jesdv ^= 0x08; + } + + unsigned master_rate = 491520000; + unsigned maxusr_rate = 520000000; + unsigned jesd_cfg = (jesdv >> 4); + jesdv &= 0x0f; + + switch (jesd_cfg) { + case JESD_MODE_4X_4X_491: + d->rx_chmap_info = s_dsdr_chmap_s_nco; + d->tx_chmap_info = s_dsdr_chmap_s_nco; + d->rx_lmap_info = s_dsdr_lmap_s_nco; + d->tx_lmap_info = s_dsdr_lmap_s_nco; + + d->logic_chcnt_rx = 4; + d->logic_chcnt_tx = 4; + d->hw_chcnt_rx = 4; + d->hw_chcnt_tx = 4; + break; + + case JESD_MODE_8X_8X_369: + d->rx_chmap_info = s_dsdr_chmap_d_nco; + d->tx_chmap_info = s_dsdr_chmap_d_nco; + d->rx_lmap_info = s_dsdr_lmap_d_nco; + d->tx_lmap_info = s_dsdr_lmap_d_nco; + + d->logic_chcnt_rx = 8; + d->logic_chcnt_tx = 4; //TODO: recompile to 8!!! + d->hw_chcnt_rx = 4; + d->hw_chcnt_tx = 4; + + master_rate = 368640000; + maxusr_rate = 380000000; + + d->hw_fpga_jesd_rx_en = 0xff; + d->hw_fpga_jesd_tx_en = 0xff; + jesd_x8 = true; + break; + + case JESD_MODE_8X_4X_491: + d->rx_chmap_info = s_dsdr_chmap_s_nco_fb; + d->tx_chmap_info = s_dsdr_chmap_s_nco; + d->rx_lmap_info = s_dsdr_lmap_s_nco_fb; + d->tx_lmap_info = s_dsdr_lmap_s_nco; + + d->logic_chcnt_rx = 6; // a FB channels can occupy x2 lanes, but we support only x1 at the moment + d->logic_chcnt_tx = 4; + d->hw_chcnt_rx = 6; + d->hw_chcnt_tx = 4; + + d->hw_fpga_jesd_rx_en = 0x3f; + jesd_x8 = true; + break; + + default: + USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported JESD_CFG=%d!\n", jesd_cfg); + return -EIO; + } + + d->jesd_x8 = jesd_x8; + switch (devid) { case DSDR_KCU116_EVM: case DSDR_M2_R0: @@ -1411,10 +1735,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->type = devid; break; - //case 0xff: - // d->type = DSDR_PCIE_HIPER_R0; - // break; - default: USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported HWID = %08x, skipping initialization!\n", hwid); return -EIO; @@ -1428,7 +1748,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->cfg_rx_lanemap = 0x76543210; d->cfg_tx_lanemap = 0x76543210; - for (unsigned h = 0; h < 8; h++) { + for (unsigned h = 0; h < MAX_LOGIC_CHANS; h++) { d->hw_rxch_route[h] = h; d->hw_txch_route[h] = h; } @@ -1436,49 +1756,72 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** afeType = 7901; switch (jesdv) { case DSDR_JESD204B_810_245: - d->max_rate = 260e6; - d->dac_rate = d->adc_rate = 245760000; + d->max_rate = maxusr_rate / 2; + d->dac_rate = d->adc_rate = master_rate / 2; d->afecongiguration = "Afe79xxPg1_02.txt"; break; case DSDR_JESD204C_6664_245: - d->max_rate = 260e6; - d->dac_rate = d->adc_rate = 245760000; + d->max_rate = maxusr_rate / 2; + d->dac_rate = d->adc_rate = master_rate / 2; d->afecongiguration = "Afe79xxPg1_6664_245.txt"; break; case DSDR_JESD204C_6664_491: - d->cfg_rx_lanemap = 0x75643210; - d->cfg_tx_lanemap = 0x75643210; - - d->max_rate = 520e6; - d->dac_rate = d->adc_rate = 491520000; - d->afecongiguration = "Afe79xxPg1_6664_491.txt"; + d->max_rate = maxusr_rate; + d->dac_rate = d->adc_rate = master_rate; + + if (jesd_x8 == false && master_rate == 491520000) { + d->afecongiguration = "Afe79xxPg1_6664_491.txt"; + } else if (jesd_x8 == true && master_rate == 368640000) { + d->afecongiguration = "Afe79xxPg1_6664_369_D.txt"; + } else if (jesd_x8 == true && master_rate == 491520000) { + d->afecongiguration = "Afe79xxPg1_6664_491_fb3.txt"; + } if (d->hw_mask_rx == 0x5 && d->hw_mask_tx == 0xA) { // RX C/A // TX D/B // d->afecongiguration = "Afe79xxPg1_dsdr_491_7903.txt"; + afeType = 7903; - d->cfg_rx_lanemap = 0x75643120; - d->cfg_tx_lanemap = 0x75642031; - //d->hw_fpga_jesd_rx_en = 0x3; - //d->hw_fpga_jesd_tx_en = 0xc; + d->hw_chcnt_rx = 2; + d->hw_chcnt_tx = 2; + + d->cfg_rx_lanemap = 0x76543120; + d->cfg_tx_lanemap = 0x76542031; d->hw_rxch_route[0] = 0; d->hw_rxch_route[1] = 2; d->hw_rxch_route[2] = 1; d->hw_rxch_route[3] = 3; + d->hw_rxch_route[4] = 0; + d->hw_rxch_route[5] = 2; + d->hw_rxch_route[6] = 1; + d->hw_rxch_route[7] = 3; + d->hw_txch_route[0] = 1; d->hw_txch_route[1] = 3; d->hw_txch_route[2] = 0; d->hw_txch_route[3] = 2; + d->hw_txch_route[4] = 1; + d->hw_txch_route[5] = 3; + d->hw_txch_route[6] = 0; + d->hw_txch_route[7] = 2; } if (getenv("DSDR_M2_7950")) { + if (master_rate != 491520000) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "No configuration for 7950@369MSPS!\n"); + return -EIO; + } // AFE7950 - d->afecongiguration = "Afe79xxPg1_6664_491_7950.txt"; + if (jesd_x8 == true) { + d->afecongiguration = "Afe79xxPg1_6664_491_7950_fb3.txt"; + } else { + d->afecongiguration = "Afe79xxPg1_6664_491_7950.txt"; + } afeType = 7950; } break; @@ -1490,8 +1833,9 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->cfg_afe_type = afeType; d->jesdv = jesdv; - USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s, Type: %d, AFE: %d, JESD204%c, CH_TX=%02x, CH_RX=%02x", - d->afecongiguration, d->type, d->cfg_afe_type, (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx); + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s, Type: %d, AFE: %d, JESD204%c, CH_TX=%02x, CH_RX=%02x JESDx%d", + d->afecongiguration, d->type, d->cfg_afe_type, (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx, + jesd_x8 ? 8 : 4); if (getenv("SKIPAFE")) { d->type = DSDR_KCU116_EVM; @@ -1583,14 +1927,14 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** lmk05318_out_config_t lmk_out[8]; - lmk05318_port_request(&lmk_out[0], 0, 491520000, false, OUT_OFF); - lmk05318_port_request(&lmk_out[1], 1, 491520000, false, LVDS); + lmk05318_port_request(&lmk_out[0], 0, master_rate, false, OUT_OFF); + lmk05318_port_request(&lmk_out[1], 1, master_rate, false, LVDS); lmk05318_port_request(&lmk_out[2], 2, 3840000, false, LVDS); lmk05318_port_request(&lmk_out[3], 3, 3840000, false, OUT_OFF); lmk05318_port_request(&lmk_out[4], 4, 0, false, OUT_OFF); lmk05318_port_request(&lmk_out[5], 5, d->dac_rate / 2, false, LVDS); lmk05318_port_request(&lmk_out[6], 6, 3840000, false, LVDS); - lmk05318_port_request(&lmk_out[7], 7, d->dac_rate / 2, false, LVDS); + lmk05318_port_request(&lmk_out[7], 7, dpump_afe_clk ? d->dac_rate : d->dac_rate / 2, false, LVDS); res = lmk05318_create(dev, d->subdev, I2C_LMK, (d->type == DSDR_PCIE_HIPER_R0) ? 52000000 : 26000000, XO_CMOS, false, &dpll, lmk_out, SIZEOF_ARRAY(lmk_out), &d->lmk, false /*dry_run*/); @@ -1711,7 +2055,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** // Test AFE chip USDR_LOG("DSDR", USDR_LOG_ERROR, "AFE is powered up!\n"); - res = res ? res : usleep(100000); + res = res ? res : usleep(300000); res = res ? res : dev_gpo_set(dev, IGPO_AFE_RST, 0x0); res = res ? res : usleep(100000); @@ -1727,8 +2071,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** if (res == 0) { res = res ? res : usdr_jesd204b_bringup_pre(d); - // sleep(1); - res = res ? res : usleep(10000); + // TODO accurate check GTH/GTY TX is up and running + res = res ? res : usleep(100000); char afeconfig_path[1024]; char *afecfgpath = getenv("AFECFG_PATH"); @@ -1786,8 +2130,10 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** int dev_m2_dsdr_sdr_rx_remap_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; - for (unsigned i = 0; i < 4; i++) { - d->rx_logic_to_hw[i] = (value >> (2 * i)) & 0x3; + unsigned bits = (d->logic_chcnt_rx == 1) ? 0 : (d->logic_chcnt_rx == 2) ? 1 : (d->logic_chcnt_rx <= 4) ? 2 : 3; + unsigned mask = (1 << bits) - 1; + for (unsigned i = 0; i < d->logic_chcnt_rx; i++) { + d->rx_ordinal_to_logic[i] = (value >> (bits * i)) & mask; } return dsdr_update_rx_remap(d); @@ -1796,9 +2142,11 @@ int dev_m2_dsdr_sdr_rx_remap_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val int dev_m2_dsdr_sdr_rx_remap_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; + unsigned bits = (d->logic_chcnt_rx == 1) ? 0 : (d->logic_chcnt_rx == 2) ? 1 : (d->logic_chcnt_rx <= 4) ? 2 : 3; + unsigned mask = (1 << bits) - 1; uint64_t remap = 0; - for (unsigned i = 0; i < 4; i++) { - remap |= (d->rx_logic_to_hw[i] & 0x3) << (2 * i); + for (unsigned i = 0; i < d->logic_chcnt_rx; i++) { + remap |= (d->rx_ordinal_to_logic[i] & mask) << (bits * i); } *ovalue = remap; @@ -1808,60 +2156,43 @@ int dev_m2_dsdr_sdr_rx_remap_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ov int dev_m2_dsdr_sdr_tx_remap_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; - for (unsigned i = 0; i < 4; i++) { - d->tx_hw_to_logic[i] = (value >> (2 * i)) & 0x3; + unsigned bits = (d->logic_chcnt_tx == 1) ? 0 : (d->logic_chcnt_tx == 2) ? 1 : (d->logic_chcnt_tx <= 4) ? 2 : 3; + unsigned mask = (1 << bits) - 1; + for (unsigned i = 0; i < d->logic_chcnt_tx; i++) { + d->tx_ordinal_to_logic[i] = (value >> (bits * i)) & mask; } - return dsdr_update_tx_remap(d); } + int dev_m2_dsdr_sdr_tx_remap_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; + unsigned bits = (d->logic_chcnt_tx == 1) ? 0 : (d->logic_chcnt_tx == 2) ? 1 : (d->logic_chcnt_tx <= 4) ? 2 : 3; + unsigned mask = (1 << bits) - 1; uint64_t remap = 0; - for (unsigned i = 0; i < 4; i++) { - remap |= (d->tx_hw_to_logic[i] & 0x3) << (2 * i); + for (unsigned i = 0; i < d->logic_chcnt_tx; i++) { + remap |= (d->tx_ordinal_to_logic[i] & mask) << (bits * i); } *ovalue = remap; return 0; } -char static dsdr_chan_name(uint8_t n) +static const char* dsdr_chan_name(struct dev_m2_dsdr *d, bool rx, uint8_t logic_number) { - return n == 0xff ? '-' : 'a' + n; -} - -char static dsdr_chan_num(uint8_t n) -{ - return n == 0xff ? '-' : '0' + n; -} - -static const channel_map_info_t s_dsdr_chmap[] = { - // Single NCO mode - { "a", 0 }, - { "b", 1 }, - { "c", 2 }, - { "d", 3 }, - - // Dual NCO mode - { "a0", 0 }, - { "b0", 1 }, - { "c0", 2 }, - { "d0", 3 }, - { "a1", 4 }, - { "b1", 5 }, - { "c1", 6 }, - { "d1", 7 }, + const channel_map_info_t *nfo = rx ? d->rx_chmap_info : d->tx_chmap_info; + for (unsigned p = 0; p < 16; p++) { + if (nfo[p].name == NULL) + break; - { NULL, CH_NULL }, - }; + if (nfo[p].hwidx == logic_number) + return nfo[p].name; + } -int dsdr_map_channels(const usdr_channel_info_t* channels, channel_info_t* core_chans) -{ - return usdr_channel_info_map_default(channels, s_dsdr_chmap, 4, core_chans); + return "-"; } -int device_path_to_chmsk(const char* full_path, const char* basename, chmsk_t *hw_mask, chmsk_t *lg_mask) +int device_path_to_chmsk(const char* full_path, const char* basename, const channel_map_info_t* map, const unsigned max_lchan, chmsk_t *hw_mask, chmsk_t *lg_mask) { *hw_mask = 0; *lg_mask = 0; @@ -1899,7 +2230,7 @@ int device_path_to_chmsk(const char* full_path, const char* basename, chmsk_t *h } channel_info_t mmaped; - res = dsdr_map_channels(&nfo, &mmaped); + res = usdr_channel_info_map_default(&nfo, map, max_lchan, &mmaped); if (res) return res; @@ -1911,7 +2242,7 @@ int device_path_to_chmsk(const char* full_path, const char* basename, chmsk_t *h return 0; } -static int parse_overriden_cahnnel_info(const char* env_string, const usdr_channel_info_t* orig, channel_info_t* override) +static int parse_overriden_cahnnel_info(const char* env_string, const usdr_channel_info_t* orig, const channel_map_info_t* map, const unsigned max_lchan, channel_info_t* override) { char chanlist[64*4]; char* phys_names[DSDR_CHANS_LOGIC]; @@ -1931,7 +2262,7 @@ static int parse_overriden_cahnnel_info(const char* env_string, const usdr_chann return -EINVAL; } - res = dsdr_map_channels(&nfo, override); + res = usdr_channel_info_map_default(&nfo, map, max_lchan, override); return res; } @@ -1949,53 +2280,72 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char return -EFAULT; } - res = dsdr_map_channels(channels, &lchans); + bool rx_str = strstr(sid, "rx") != NULL; + bool tx_str = strstr(sid, "tx") != NULL; + if (!rx_str && !tx_str) { + USDR_LOG("UDEV", USDR_LOG_ERROR, "DSDR Unrecognised stream: %s\n", sid); + return -EINVAL; + } + + res = usdr_channel_info_map_default(channels, + rx_str ? d->rx_chmap_info : d->tx_chmap_info, + rx_str ? d->logic_chcnt_rx : d->logic_chcnt_tx, &lchans); if (res) { return res; } - if (channels->count > 4 || channels->count == 3) { + if (channels->count > 8 || channels->count == 3 || channels->count == 5 || channels->count == 7 || channels->count == 6) { USDR_LOG("UDEV", USDR_LOG_ERROR, "DSDR %s: Unsupported channel count: %d, valid are (1, 2, 4)\n", sid, channels->count); return -EINVAL; } - if (strstr(sid, "rx") != NULL) { + if (rx_str) { if (d->rx) { return -EBUSY; } - memset(d->rx_logic_to_hw, 0xff, sizeof(d->rx_logic_to_hw)); + memset(d->rx_ordinal_to_logic, 0xff, sizeof(d->rx_ordinal_to_logic)); const char* env_ch = getenv("DSDR_CH_RX"); if (env_ch) { - res = parse_overriden_cahnnel_info(env_ch, channels, &lchans); + res = parse_overriden_cahnnel_info(env_ch, channels, d->rx_chmap_info, d->logic_chcnt_rx, &lchans); if (res) return res; USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR RX channel mask is overriden to `%s`\n", env_ch); } - memcpy(d->rx_logic_to_hw, lchans.ch_map, sizeof(lchans.ch_map[0]) * channels->count); - + memcpy(d->rx_ordinal_to_logic, lchans.ch_map, sizeof(lchans.ch_map[0]) * channels->count); d->hw_enabled_rx = 0; + d->logic_enabled_rx = 0; for (unsigned i = 0; i < channels->count; i++) { - unsigned hw = d->rx_logic_to_hw[i]; - if (hw >= DSDR_CHANS_HW) { + unsigned logic = d->rx_ordinal_to_logic[i]; + unsigned hw = d->rx_lmap_info[logic].hwport; + if (hw >= d->hw_chcnt_rx) { + USDR_LOG("UDEV", USDR_LOG_ERROR, "Stream RX: Logical channel %d incorrectly mmaped to HW %d\n", i, hw); return -EINVAL; } d->hw_enabled_rx |= (1ull << hw); + d->logic_enabled_rx |= (1ull << logic); } res = res ? res : dsdr_update_rx_remap(d); - USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR RX channels %d remmaped: [%c, %c, %c, %c] mux, hw_mask %02x\n", channels->count, - dsdr_chan_name(d->rx_logic_to_hw[0]), dsdr_chan_name(d->rx_logic_to_hw[1]), - dsdr_chan_name(d->rx_logic_to_hw[2]), dsdr_chan_name(d->rx_logic_to_hw[3]), d->hw_enabled_rx); - - uint64_t v; + USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR RX channels %d remmaped: [%s, %s, %s, %s -- %s, %s, %s, %s] mux, hw_mask %02x logic_mask %02x\n", channels->count, + dsdr_chan_name(d, true, 0), dsdr_chan_name(d, true, 1), + dsdr_chan_name(d, true, 2), dsdr_chan_name(d, true, 3), + dsdr_chan_name(d, true, 4), dsdr_chan_name(d, true, 5), + dsdr_chan_name(d, true, 6), dsdr_chan_name(d, true, 7), + d->hw_enabled_rx, d->logic_enabled_rx); + + uint64_t v0, v1; for (unsigned ch = 0; ch < 4; ch++) { - d->st.libcapi79xx_get_nco(&d->st.capi, NCO_RX, ch, &v, 0, 0); - - USDR_LOG("UDEV", USDR_LOG_INFO, "RX NCO[%d] = %lld\n", ch, (long long)v); + d->st.libcapi79xx_get_nco(&d->st.capi, NCO_RX, ch, &v0, 0, 0); + d->st.libcapi79xx_get_nco(&d->st.capi, NCO_RX, ch, &v1, 0, 1); + USDR_LOG("UDEV", USDR_LOG_INFO, "RX NCO[%d] = %lld | NCO[%d] = %lld \n", ch, (long long)v0, ch, (long long)v1); + } + for (unsigned ch = 0; ch < 2; ch++) { + d->st.libcapi79xx_get_nco(&d->st.capi, NCO_FB, ch, &v0, 0, 0); + USDR_LOG("UDEV", USDR_LOG_INFO, "FB NCO[%d] = %lld \n", ch, (long long)v0); } struct sfetrx4_config rxcfg; @@ -2009,9 +2359,10 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char usleep(1000); res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x0); - res = (res) ? res : create_sfetrx4_stream(dev, CORE_EXFERX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, - flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, - SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &hwchs); + res = (res) ? res : create_sfetrx4_stream(dev, (d->logic_chcnt_rx == 8 || d->logic_chcnt_rx == 6) ? CORE_EXFERX_DMA32_R0_8 : CORE_EXFERX_DMA32_R0, + dformat, channels->count, &lchans, pktsyms, + flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, + SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &hwchs); if (res) { return res; } @@ -2020,9 +2371,9 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char d->rx_chans = lchans; // Restore cached parameters we couldn't set before activating streams - for (unsigned i = 0; i < SIZEOF_ARRAY(d->rx_freqs); i++) { - if (d->rx_freqs[i].set && (d->hw_enabled_rx & (1u << i))) { - res = (res) ? res : dsdr_set_rx_frequency_chan(d, d->rx_freqs[i].value, i); + for (unsigned i = 0; i < SIZEOF_ARRAY(d->rx_ord_freqs); i++) { + if (d->rx_ord_freqs[i].set && (d->hw_enabled_rx & (1u << i))) { + res = (res) ? res : dsdr_set_rx_frequency_chan(d, d->rx_ord_freqs[i].value, i); } } @@ -2031,38 +2382,53 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0x0); *out_handle = d->rx; - } else if (strstr(sid, "tx") != NULL) { + } else { if (d->tx) { return -EBUSY; - } - - d->hw_enabled_tx = 0; - memset(d->tx_hw_to_logic, 0xff, sizeof(d->tx_hw_to_logic)); + } + memset(d->tx_ordinal_to_logic, 0xff, sizeof(d->tx_ordinal_to_logic)); const char* env_ch = getenv("DSDR_CH_TX"); if (env_ch) { - res = parse_overriden_cahnnel_info(env_ch, channels, &lchans); + res = parse_overriden_cahnnel_info(env_ch, channels, d->tx_chmap_info, d->logic_chcnt_tx, &lchans); if (res) return res; USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR TX channel mask is overriden to `%s`\n", env_ch); } + memcpy(d->tx_ordinal_to_logic, lchans.ch_map, sizeof(lchans.ch_map[0]) * channels->count); + + //memset(d->tx_hw_to_logic, 0xff, sizeof(d->tx_hw_to_logic)); + + d->hw_enabled_tx = 0; + d->logic_enabled_tx = 0; + for (unsigned i = 0; i < channels->count; i++) { - unsigned hw = lchans.ch_map[i]; - if (hw >= DSDR_CHANS_HW) { + unsigned logic = d->tx_ordinal_to_logic[i]; + unsigned hw = d->tx_lmap_info[logic].hwport; + if (hw >= d->hw_chcnt_tx) { + USDR_LOG("UDEV", USDR_LOG_ERROR, "Stream TX: Logical channel %d incorrectly mmaped to HW %d\n", i, hw); return -EINVAL; } - d->tx_hw_to_logic[hw] = i; d->hw_enabled_tx |= (1ull << hw); - } + d->logic_enabled_tx |= (1ull << logic); + + //d->tx_hw_to_logic[hw] = i; + } // Map as single channel only res = res ? res : dsdr_update_tx_remap(d); - USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR TX channels %d remmaped: [A <= %c, B <= %c, C <= %c, D <= %c] mux, hw_mask %02x\n", - channels->count, dsdr_chan_num(d->tx_hw_to_logic[0]), dsdr_chan_num(d->tx_hw_to_logic[1]), - dsdr_chan_num(d->tx_hw_to_logic[2]), dsdr_chan_num(d->tx_hw_to_logic[3]), d->hw_enabled_tx); + USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR TX channels %d remmaped: [%s, %s, %s, %s -- %s, %s, %s, %s] mux, hw_mask %02x logic_mask %02x\n", channels->count, + dsdr_chan_name(d, false, 0), dsdr_chan_name(d, false, 1), + dsdr_chan_name(d, false, 2), dsdr_chan_name(d, false, 3), + dsdr_chan_name(d, false, 4), dsdr_chan_name(d, false, 5), + dsdr_chan_name(d, false, 6), dsdr_chan_name(d, false, 7), + d->hw_enabled_tx, d->logic_enabled_tx); + // USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR TX channels %d remmaped: [A <= %c, B <= %c, C <= %c, D <= %c] mux, hw_mask %02x\n", + // channels->count, dsdr_chan_num(d->tx_hw_to_logic[0]), dsdr_chan_num(d->tx_hw_to_logic[1]), + // dsdr_chan_num(d->tx_hw_to_logic[2]), dsdr_chan_num(d->tx_hw_to_logic[3]), d->hw_enabled_tx); struct sfetrx4_config txcfg; res = (res) ? res : parse_sfetrx4(dformat, &lchans, pktsyms, channels->count, &txcfg); @@ -2075,7 +2441,8 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char usleep(1000); res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_TX_RST, 0x0); - res = (res) ? res : create_sfetrx4_stream(dev, CORE_EXFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, + res = (res) ? res : create_sfetrx4_stream(dev, (d->logic_chcnt_tx == 8) ? CORE_EXFETX_DMA32_R0_8 : CORE_EXFETX_DMA32_R0, + dformat, channels->count, &lchans, pktsyms, flags | DMS_DONT_CHECK_FWID, M2PCI_REG_WR_TXDMA_CFG0, M2PCI_REG_WR_SYNC_CTRL, @@ -2089,9 +2456,9 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char d->tx_chans = lchans; // Restore cached parameters we couldn't set before activating streams - for (unsigned i = 0; i < SIZEOF_ARRAY(d->tx_freqs); i++) { - if (d->tx_freqs[i].set && (d->hw_enabled_tx & (1u << i))) { - res = (res) ? res : dsdr_set_tx_frequency_chan(d, d->tx_freqs[i].value, i); + for (unsigned i = 0; i < SIZEOF_ARRAY(d->tx_ord_freqs); i++) { + if (d->tx_ord_freqs[i].set && (d->hw_enabled_tx & (1u << i))) { + res = (res) ? res : dsdr_set_tx_frequency_chan(d, d->tx_ord_freqs[i].value, i); } } @@ -2173,22 +2540,37 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) d->hw_enabled_rx = 0; d->hw_mask_tx = 0; d->hw_mask_rx = 0; - d->hw_mask_fb = 0; + + d->logic_enabled_rx = 0; + d->logic_enabled_tx = 0; d->hw_fpga_jesd_rx_en = 0; d->hw_fpga_jesd_tx_en = 0; - memset(d->rx_logic_to_hw, 0xff, sizeof(d->rx_logic_to_hw)); - memset(d->tx_hw_to_logic, 0xff, sizeof(d->tx_hw_to_logic)); + memset(d->rx_ordinal_to_logic, 0xff, sizeof(d->rx_ordinal_to_logic)); + memset(d->tx_ordinal_to_logic, 0xff, sizeof(d->tx_ordinal_to_logic)); + //memset(d->tx_hw_to_logic, 0xff, sizeof(d->tx_hw_to_logic)); d->tx_activated = false; d->rx_activated = false; - for (unsigned i = 0; i < SIZEOF_ARRAY(d->rx_freqs); i++) { - opt_u64_set_null(&d->rx_freqs[i]); - opt_u64_set_null(&d->tx_freqs[i]); + for (unsigned i = 0; i < SIZEOF_ARRAY(d->rx_ord_freqs); i++) { + opt_u64_set_null(&d->rx_ord_freqs[i]); + opt_u64_set_null(&d->tx_ord_freqs[i]); + } + + for (unsigned i = 0; i < MAX_HIPER_FE_PORT; i++) { + for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { + opt_u64_set_null(&d->rx_bxfc[i][j]); + opt_u64_set_null(&d->tx_bxfc[i][j]); + + opt_u64_set_null(&d->rx_raw_nco[i][j]); + opt_u64_set_null(&d->tx_raw_nco[i][j]); + + } } + d->type = DSDR_PCIE_HIPER_R0; dev->pdev = &d->base; return 0; From cd22be78e9eecc27e97504285bc0900adcb3becc Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 9 Dec 2025 14:23:08 +0400 Subject: [PATCH 256/397] fgearbox: add US DSP layout --- src/lib/device/m2_dsdr/m2_dsdr.c | 4 +- src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c | 2 +- src/lib/ipblks/fgearbox.c | 97 ++++++++++++++++++++++- src/lib/ipblks/fgearbox.h | 11 ++- 4 files changed, 105 insertions(+), 9 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 04102e26..08c091c4 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1304,7 +1304,7 @@ static int dsdr_set_rates(dev_m2_dsdr_t* d, uint32_t rx_rate, uint32_t tx_rate) rx_rate / 1.0e6, d->rxbb_rate / 1.0e6, d->rxbb_decim, tx_rate / 1.0e6, d->txbb_rate / 1.0e6, d->txbb_inter); - res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_DSPCHAIN_PRG, (fgearbox_firs_t)d->rxbb_decim); + res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_DSPCHAIN_PRG, (fgearbox_firs_t)d->rxbb_decim, DSP_USSERIES); if (res) { USDR_LOG("LSDR", USDR_LOG_ERROR, "Unable to initialize decimation FIR gearbox, error = %d!\n", res); return res; @@ -1313,7 +1313,7 @@ static int dsdr_set_rates(dev_m2_dsdr_t* d, uint32_t rx_rate, uint32_t tx_rate) if (d->txbb_inter > 0) { d->txbb_rate = d->dac_rate / d->txbb_inter; - res = (res) ? res : fgearbox_load_fir_i(d->base.dev, IGPO_DSPCHAIN_TX_PRG, (fgearbox_firs_t)d->txbb_inter); + res = (res) ? res : fgearbox_load_fir_i(d->base.dev, IGPO_DSPCHAIN_TX_PRG, (fgearbox_firs_t)d->txbb_inter, DSP_USSERIES); if (res) { USDR_LOG("LSDR", USDR_LOG_ERROR, "Unable to initialize interpolation FIR gearbox, error = %d!\n", res); return res; diff --git a/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c b/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c index 40c8a83f..e04a41f3 100644 --- a/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c +++ b/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c @@ -799,7 +799,7 @@ int dev_m2_d09_4_ad45_2_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val USDR_LOG("LSDR", USDR_LOG_ERROR, "Decimation set to %d, ADC %d\n", d->rxbb_decim, d->adc_rate); res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_BANK_ADC_CHMSK, 0x0f); - res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_BANK_ADC_DSPCHAIN_PRG, (fgearbox_firs_t)d->rxbb_decim); + res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_BANK_ADC_DSPCHAIN_PRG, (fgearbox_firs_t)d->rxbb_decim, DSP_7SERIES); if (res) { USDR_LOG("LSDR", USDR_LOG_ERROR, "Unable to initialize FIR gearbox, error = %d!\n", res); return res; diff --git a/src/lib/ipblks/fgearbox.c b/src/lib/ipblks/fgearbox.c index 78f6768d..37bff85f 100644 --- a/src/lib/ipblks/fgearbox.c +++ b/src/lib/ipblks/fgearbox.c @@ -225,6 +225,50 @@ static const uint8_t fir_data_dec4_clkr2_S[1280] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0x01, 0x33, }; +static const uint8_t fir_data_dec4_clkr2_us[1280] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0x87, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x78, 0x79, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x3b, 0xbb, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x07, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x04, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x06, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x06, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78, 0x78, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x66, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x60, 0x66, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x2a, 0x2d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x7e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x61, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x50, 0x55, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x52, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x52, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x50, 0x56, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x52, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x50, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x56, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x60, 0x55, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x78, 0x57, 0x51, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x35, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x58, 0x03, 0x53, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x58, 0x1b, 0x55, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x4e, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x10, 0x77, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x30, 0x27, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x50, 0x71, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x66, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x50, 0x28, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x18, 0x00, 0x30, +}; + + const uint8_t fir_data_dec5_clkr2[1280] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x3e, @@ -355,6 +399,48 @@ const uint8_t fir_data_dec8_clkr2[1280] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x30, 0x00, 0x00, 0x10, 0x20, }; +static const uint8_t fir_data_dec10_clkr2_us[1280] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x9f, 0x9f, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x60, 0x61, 0x7f, 0x7f, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x2f, 0x2f, 0xaf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x1f, 0x1f, 0x1f, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x63, 0x7f, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7c, 0x63, 0x1c, 0x03, 0x7c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x0c, 0x6c, 0x0c, 0x6c, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x60, 0x7f, 0x00, 0x0f, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x40, 0x10, 0x7c, 0x6f, 0x03, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x20, 0x0c, 0x73, 0x0c, 0x73, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x4f, 0x58, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x4f, 0x58, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x40, 0x40, 0x4f, 0x58, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x5c, 0x4f, 0x58, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x52, 0x4f, 0x58, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x4b, 0x4f, 0x58, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x1d, 0x58, 0x58, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x6b, 0x40, 0x48, 0x43, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x4c, 0x25, 0x43, 0x53, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x74, 0x09, 0x0f, 0x4b, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0x6d, 0x0b, 0x79, 0x5f, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x20, 0x06, 0x5e, 0x26, 0x1a, 0x47, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x00, 0x4f, 0x6b, 0x41, 0x36, 0x4b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x52, 0x25, 0x1c, 0x41, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x40, 0x51, 0x70, 0x52, 0x76, 0x57, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x00, 0x0a, 0x6d, 0x18, 0x63, 0x6c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x0e, 0x40, 0x4d, 0x27, 0x3b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x68, 0x11, 0x02, 0x3c, 0x5c, +}; static const uint8_t fir_data_dec12_clkr2[1280] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, @@ -1071,7 +1157,7 @@ int fgearbox_load_ucode(lldev_t dev, unsigned gport, const uint8_t* ucode) } -int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir) +int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam) { const uint8_t* s_st8_dsp; @@ -1086,7 +1172,7 @@ int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir) s_st8_dsp = fir_data_dec3_clkr2; break; case FGBOX_X4: - s_st8_dsp = fir_data_dec4_clkr2_S; //fir_data_dec4_clkr8_3; + s_st8_dsp = (fam == DSP_USSERIES) ? fir_data_dec4_clkr2_us : fir_data_dec4_clkr2_S; //fir_data_dec4_clkr8_3; break; case FGBOX_X5: s_st8_dsp = fir_data_dec5_clkr2; @@ -1097,6 +1183,11 @@ int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir) case FGBOX_X8: s_st8_dsp = fir_data_dec8_clkr2; break; + case FGBOX_X10: + if (fam != DSP_USSERIES) + return -EINVAL; + s_st8_dsp = fir_data_dec10_clkr2_us; + break; case FGBOX_X12: s_st8_dsp = fir_data_dec12_clkr2; break; @@ -1129,7 +1220,7 @@ int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir) } -int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir) +int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam) { const uint8_t* s_st8_dsp; diff --git a/src/lib/ipblks/fgearbox.h b/src/lib/ipblks/fgearbox.h index 6f597576..af384c45 100644 --- a/src/lib/ipblks/fgearbox.h +++ b/src/lib/ipblks/fgearbox.h @@ -17,6 +17,8 @@ enum fgearbox_firs { FGBOX_X6 = 6, FGBOX_X8 = 8, + FGBOX_X10 = 10, + FGBOX_X12 = 12, FGBOX_X16 = 16, FGBOX_X24 = 24, @@ -29,10 +31,13 @@ enum fgearbox_firs { }; typedef enum fgearbox_firs fgearbox_firs_t; +typedef enum dspfamily { + DSP_7SERIES, + DSP_USSERIES, +} dspfamily_t; -int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir); - -int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir); +int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam); +int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam); #endif From 6eda83f438486785413d320c43368dde9f80b4ad Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Tue, 9 Dec 2025 20:56:22 +0300 Subject: [PATCH 257/397] add ci16->8ci16 to core transform function --- src/lib/xdsp/conv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/xdsp/conv.c b/src/lib/xdsp/conv.c index af6577ea..0ddfb269 100644 --- a/src/lib/xdsp/conv.c +++ b/src/lib/xdsp/conv.c @@ -29,6 +29,7 @@ #include "conv_4ci16_ci12_2.h" #include "conv_ci16_8cf32_2.h" +#include "conv_ci16_8ci16_2.h" #include #include @@ -134,6 +135,12 @@ transform_info_t get_transform_fn(const char* from, transform_info_t l_conv_ci16_8cf32 = { conv_get_ci16_8cf32(), tr_conv_i16_f32_sz }; return l_conv_ci16_8cf32; } + + if(isCI16(from) && isCI16(to)) + { + transform_info_t l_conv_ci16_8ci16 = { conv_get_ci16_8ci16(), tr_dummy_sz }; + return l_conv_ci16_8ci16; + } } /* Deinterleave 4 -> 1 */ From 4e41402af1bf907a436b08d6ed5c7ed9787b8aa8 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 10 Dec 2025 12:43:20 +0400 Subject: [PATCH 258/397] dsdr: fix reporting default temperature --- src/lib/device/m2_dsdr/dsdr_hiper.c | 12 ++++++++++ src/lib/device/m2_dsdr/dsdr_hiper.h | 2 ++ src/lib/device/m2_dsdr/m2_dsdr.c | 34 +++++++++++++++++++++-------- src/tools/usdr_dm_create.c | 11 +++++----- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index b3e48a2c..3c07d27f 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -753,7 +753,19 @@ int dsdr_hiper_sens2temp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue { return dsdr_hiper_sens_get((dsdr_hiper_fe_t*)obj->object, 2, ovalue); } +int dsdr_hiper_fe_get_temp_max(dsdr_hiper_fe_t* dfe, uint64_t* temp_max) +{ + int64_t tmp = 0, tmax = 0; + int res = 0; + for (unsigned i = 0; i < 3; i++) { + res = res ? res : dsdr_hiper_sens_get(dfe, i, (uint64_t*)&tmp); + if (tmp > tmax) + tmax = tmp; + } + *temp_max = tmax; + return res; +} static int dsdr_hiper_initialize_lms8(dsdr_hiper_fe_t* dfe, unsigned addr, unsigned stepping, lms8001_state_t* obj) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.h b/src/lib/device/m2_dsdr/dsdr_hiper.h index 799cd3d5..cf490514 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.h +++ b/src/lib/device/m2_dsdr/dsdr_hiper.h @@ -120,6 +120,8 @@ typedef struct dsdr_hiper_fe dsdr_hiper_fe_t; int dsdr_hiper_fe_create(lldev_t dev, unsigned spix_num, unsigned int *lms8_mpw_mask, dsdr_hiper_fe_t* dfe); int dsdr_hiper_fe_destroy(dsdr_hiper_fe_t* dfe); +int dsdr_hiper_fe_get_temp_max(dsdr_hiper_fe_t* dfe, uint64_t* temp_max); + int dsdr_hiper_fe_rx_freq_set(dsdr_hiper_fe_t* def, unsigned chno, uint64_t freq, uint64_t* ncotune, bool *p_swap_rxiq); int dsdr_hiper_fe_tx_freq_set(dsdr_hiper_fe_t* def, unsigned chno, uint64_t freq, uint64_t* ncotune, bool* p_swap_txiq); diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 08c091c4..03a41dae 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -26,6 +26,7 @@ #include "../hw/lmk05318/lmk05318.h" #include "../hw/lp875484/lp875484.h" #include "../hw/afe79xx/afe79xx.h" +#include "../hw/tmp114/tmp114.h" #include "dsdr_hiper.h" @@ -93,6 +94,8 @@ enum i2c_idx { I2C_AFE_PMIC = MAKE_LSOP_I2C_ADDR(0, 0, I2C_ADDR_PMIC_0P9), I2C_TPS63811 = MAKE_LSOP_I2C_ADDR(0, 1, I2C_DEV_DCDCBOOST), I2C_LMK = MAKE_LSOP_I2C_ADDR(0, 1, I2C_ADDR_LMK), + I2C_TEMP_AFE = MAKE_LSOP_I2C_ADDR(0, 0, I2C_DEV_TMP114NB), // Since M.2 rev1 + I2C_TEMP_FPGA = MAKE_LSOP_I2C_ADDR(0, 1, I2C_DEV_TMP114NB), // Since M.2 rev1 }; // LMK ports @@ -1483,15 +1486,28 @@ int dev_m2_dsdr_debug_lldev_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ova int dev_m2_dsdr_senstemp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue) { - // struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; - // lldev_t dev = d->base.dev; - // int temp, res; - // res = tmp108_temp_get(dev, 0, I2C_BUS_TMP108, &temp); - // if (res) - // return res; - - // *ovalue = (int64_t)temp; - return 0; + struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; + int res = 0; + + uint64_t fe_temp = 0; + unsigned board_temp = 0; + + if (dev_m2_dsdr_has_hiper(d)) { + res = res ? res : dsdr_hiper_fe_get_temp_max(&d->hiper, &fe_temp); + } + + if (d->type == DSDR_M2_R1) { + res = res ? res : tmp114_temp_get(d->base.dev, d->subdev, I2C_TEMP_AFE, (int*)&board_temp); + } else if (!dev_m2_dsdr_has_hiper(d)) { + // No temp sensors + return -EINVAL; + } else { + *ovalue = fe_temp; + return res; + } + + *ovalue = fe_temp > board_temp ? fe_temp : board_temp; + return res; } int dev_m2_dsdr_debug_all_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index eb50e5ba..e51d35f8 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -344,16 +344,17 @@ void* freq_gen_thread_cf32(void* obj) */ bool print_device_temperature(pdm_dev_t dev) { - uint64_t temp; + uint64_t temp = -1; int res = usdr_dme_get_uint(dev, "/dm/sensor/temp", &temp); + int traw = (temp & 0xffffffff); if (res) { - USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to get device temperature: errno %d", res); + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to get device temperature: errno %d\n", res); return false; - } else if (temp > 65535) { - USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "The temperature sensor doen't seem to be supported by your hardware - or your device has already melted)"); + } else if (traw > 65535 || traw < -65535) { + USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "The temperature sensor reports incorrect value!\n"); } else { - USDR_LOG(LOG_TAG, USDR_LOG_INFO, "Temp = %.1f C", temp / 256.0); + USDR_LOG(LOG_TAG, USDR_LOG_INFO, "Temp = %.1f C\n", traw / 256.0); } return true; } From fa2e3ad801d8d92494ba890fb503dd9ac32fa372 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 10 Dec 2025 12:44:08 +0400 Subject: [PATCH 259/397] dsdr: fix samplerate reinitialization --- src/lib/device/m2_dsdr/m2_dsdr.c | 56 +++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 03a41dae..fce38d30 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -277,6 +277,7 @@ const usdr_dev_param_constant_t s_params_m2_dsdr_rev000[] = { static int dev_m2_dsdr_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_dsdr_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_dsdr_rate_m_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); static int dev_m2_dsdr_rx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_dsdr_tx_enchan(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -353,7 +354,7 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { { "/ll/sdr/max_sw_tx_chans", { NULL, dev_m2_dsdr_ltxnumchans_get } }, { "/dm/rate/master", { dev_m2_dsdr_rate_set, NULL }}, - { "/dm/rate/rxtxadcdac", { dev_m2_dsdr_rate_m_set, NULL }}, + { "/dm/rate/rxtxadcdac", { dev_m2_dsdr_rate_m_set, dev_m2_dsdr_rate_m_get }}, { "/dm/sdr/0/rx_enchan", { dev_m2_dsdr_rx_enchan, NULL }}, { "/dm/sdr/0/tx_enchan", { dev_m2_dsdr_tx_enchan, NULL }}, @@ -481,7 +482,7 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { // HIPER FE channel map table static const uint8_t s_chanmap_hw_to_fe[MAX_HIPER_FE_PORT] = { 2, 3, 1, 0 }; -static const uint8_t s_chanmap_fe_to_hw[MAX_HIPER_FE_PORT] = { 3, 2, 0, 1 }; +// static const uint8_t s_chanmap_fe_to_hw[MAX_HIPER_FE_PORT] = { 3, 2, 0, 1 }; enum DSDR_STATE { STATE_IDLE = 0, @@ -968,7 +969,7 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned } // Ordinal to logic converter - const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, true, ord); + const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, false, ord); if (!w) { return -EINVAL; } @@ -1292,41 +1293,46 @@ static int dsdr_set_rates(dev_m2_dsdr_t* d, uint32_t rx_rate, uint32_t tx_rate) break; } + if (d->tx_activated && tx_inters[i] == 0) { + i = j; + } + d->rxbb_rate = d->adc_rate / rx_decims[i]; d->rxbb_decim = rx_decims[i]; d->txbb_rate = tx_inters[i] == 0 ? 0 : d->dac_rate / tx_inters[i]; d->txbb_inter = tx_inters[i]; - // Reset FIFO after rate change - if (rx_rate) { - res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x2); - } USDR_LOG("DSDR", USDR_LOG_ERROR, "Set rate: RX %.3f Mhz => %.3f (Decim: %d) -- TX %.3f Mhz => %.3f (Inter: %d)\n", rx_rate / 1.0e6, d->rxbb_rate / 1.0e6, d->rxbb_decim, tx_rate / 1.0e6, d->txbb_rate / 1.0e6, d->txbb_inter); - res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_DSPCHAIN_PRG, (fgearbox_firs_t)d->rxbb_decim, DSP_USSERIES); - if (res) { - USDR_LOG("LSDR", USDR_LOG_ERROR, "Unable to initialize decimation FIR gearbox, error = %d!\n", res); - return res; + // Reset FIFO after rate change + if (rx_rate) { + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x2); + res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_DSPCHAIN_PRG, (fgearbox_firs_t)d->rxbb_decim, DSP_USSERIES); + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x0); + + if (res) { + USDR_LOG("LSDR", USDR_LOG_ERROR, "Unable to initialize decimation RX FIR gearbox, error = %d!\n", res); + return res; + } } - if (d->txbb_inter > 0) { + if (tx_rate && (d->txbb_inter > 0)) { d->txbb_rate = d->dac_rate / d->txbb_inter; + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_TX_RST, 0x2); res = (res) ? res : fgearbox_load_fir_i(d->base.dev, IGPO_DSPCHAIN_TX_PRG, (fgearbox_firs_t)d->txbb_inter, DSP_USSERIES); + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_TX_RST, 0x0); + if (res) { - USDR_LOG("LSDR", USDR_LOG_ERROR, "Unable to initialize interpolation FIR gearbox, error = %d!\n", res); + USDR_LOG("LSDR", USDR_LOG_ERROR, "Unable to initialize interpolation TX FIR gearbox, error = %d!\n", res); return res; } } - if (rx_rate) { - res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x0); - } - return res; } @@ -1348,6 +1354,18 @@ int dev_m2_dsdr_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return dsdr_set_rates(d, rx_rate, tx_rate); } +int dev_m2_dsdr_rate_m_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; + uint32_t *rates = (uint32_t *)(uintptr_t)*ovalue; + + rates[0] = d->rxbb_rate; + rates[1] = d->txbb_rate; + rates[2] = d->adc_rate; + rates[3] = d->dac_rate; + + return 0; +} int dev_m2_dsdr_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { @@ -2388,7 +2406,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char // Restore cached parameters we couldn't set before activating streams for (unsigned i = 0; i < SIZEOF_ARRAY(d->rx_ord_freqs); i++) { - if (d->rx_ord_freqs[i].set && (d->hw_enabled_rx & (1u << i))) { + if (d->rx_ord_freqs[i].set && (d->logic_enabled_rx & (1u << i))) { res = (res) ? res : dsdr_set_rx_frequency_chan(d, d->rx_ord_freqs[i].value, i); } } @@ -2473,7 +2491,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char // Restore cached parameters we couldn't set before activating streams for (unsigned i = 0; i < SIZEOF_ARRAY(d->tx_ord_freqs); i++) { - if (d->tx_ord_freqs[i].set && (d->hw_enabled_tx & (1u << i))) { + if (d->tx_ord_freqs[i].set && (d->logic_enabled_rx & (1u << i))) { res = (res) ? res : dsdr_set_tx_frequency_chan(d, d->tx_ord_freqs[i].value, i); } } From 7b492e737a6fa03942e4f667ffcae36aec175053 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 10 Dec 2025 13:37:50 +0400 Subject: [PATCH 260/397] dsdr: fix TX x32 interpolation, x64,x128,x256 is buggy (due to regression) --- src/lib/device/m2_dsdr/m2_dsdr.c | 2 +- src/lib/ipblks/fgearbox.c | 177 ++++++++++++++++++++++++++++++- 2 files changed, 177 insertions(+), 2 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index fce38d30..f3bd1210 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -1273,7 +1273,7 @@ int dev_m2_dsdr_gain_rx_pga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu static int dsdr_set_rates(dev_m2_dsdr_t* d, uint32_t rx_rate, uint32_t tx_rate) { int res = 0; - unsigned tx_inters[] = { 1, 2, 0, 4, 0, 8, 16, 32, 64, 128, 256 }; + unsigned tx_inters[] = { 1, 2, 0, 4, 0, 8, 16, 32, 0, 0, 0 }; unsigned rx_decims[] = { 1, 2, 3, 4, 6, 8, 16, 32, 64, 128, 256 }; unsigned i = 0; unsigned ii; diff --git a/src/lib/ipblks/fgearbox.c b/src/lib/ipblks/fgearbox.c index 37bff85f..30ea70ae 100644 --- a/src/lib/ipblks/fgearbox.c +++ b/src/lib/ipblks/fgearbox.c @@ -832,6 +832,51 @@ static const uint8_t fir_data_int4_clkr2_S[1280] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const uint8_t fir_data_int4_clkr2_us[1280] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x17, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x77, 0x77, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x80, 0x88, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x40, 0x8b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x43, 0xbc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x55, 0x5d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x7f, 0x88, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x4c, 0xcc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x2a, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x25, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x05, 0x65, 0xda, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05, 0x25, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x05, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x65, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x55, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0f, 0x75, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x5d, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x06, 0x31, 0x32, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x37, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x09, 0x62, 0x72, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x05, 0x7c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0c, 0x79, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x05, 0x1d, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x69, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x04, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + + static const uint8_t fir_data_int8_clkr2[1280] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xf8, 0xf8, 0xf8, 0xe0, 0xe0, 0x00, @@ -963,6 +1008,93 @@ static const uint8_t fir_data_int32_clkr2[1280] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const uint8_t fir_data_int32_clkr2_us[1280] = { + 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xc0, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0xef, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x0d, 0x0d, 0x3f, 0x13, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x0d, 0x2f, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x06, 0x07, 0x04, 0x07, 0x00, 0x0f, 0x10, 0x3d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x0f, 0x0f, 0x30, 0x2f, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x07, 0x04, 0x07, 0x04, 0x0f, 0x00, 0x2f, 0x2d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x0d, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02, 0x01, 0x0e, 0x0d, 0x32, 0x2f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x0d, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x0d, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02, 0x01, 0x0e, 0x01, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x02, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x03, 0x02, 0x03, 0x0c, 0x0d, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x03, 0x0e, 0x01, 0x2e, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x0c, 0x0f, 0x3e, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x01, 0x0e, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x00, 0x02, 0x0f, 0x12, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x03, 0x02, 0x02, 0x0d, 0x01, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x00, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const uint8_t fir_data_int64_clkr2_us[1280] = { + 0x00, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0x80, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x0f, 0x1f, 0x1f, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0xdf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x1d, 0x1d, 0x7f, 0x23, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x1d, 0x5f, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x0e, 0x0f, 0x0c, 0x0f, 0x00, 0x1f, 0x20, 0x7d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x1f, 0x1f, 0x60, 0x5f, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x0f, 0x0c, 0x0f, 0x0c, 0x1f, 0x00, 0x5f, 0x5d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x1d, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02, 0x01, 0x1e, 0x1d, 0x62, 0x5f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x1d, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x1d, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02, 0x01, 0x1e, 0x01, 0x42, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x02, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x03, 0x02, 0x03, 0x1c, 0x1d, 0x62, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x03, 0x1e, 0x01, 0x5e, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x1c, 0x1f, 0x7e, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x01, 0x1e, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x00, 0x02, 0x1f, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x03, 0x02, 0x02, 0x1d, 0x01, 0x5c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x00, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + static const uint8_t fir_data_int64_clkr2[1280] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xfc, 0xe0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x1f, 0x1f, 0x80, 0x40, @@ -1049,6 +1181,49 @@ static const uint8_t fir_data_int128_clkr2[1280] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const uint8_t fir_data_int128_clkr2_us[1280] = { + 0x00, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0x00, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0xbf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x00, 0x00, 0x3d, 0x3d, 0xff, 0x43, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x01, 0x01, 0x02, 0x02, 0x3d, 0xbf, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0e, 0x0f, 0x0e, 0x0f, 0x0e, 0x0f, 0x0e, 0x0f, 0x1e, 0x1f, 0x1c, 0x1f, 0x00, 0x3f, 0x40, 0xfd, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x3f, 0x3f, 0xc0, 0xbf, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0e, 0x0f, 0x0e, 0x0f, 0x0e, 0x0f, 0x0e, 0x1f, 0x1c, 0x1f, 0x1c, 0x3f, 0x00, 0xbf, 0xbd, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x3d, 0x42, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02, 0x01, 0x3e, 0x3d, 0xc2, 0xbf, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x3d, 0x42, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x02, 0x3d, 0x42, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02, 0x01, 0x3e, 0x01, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x03, 0x02, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x03, 0x02, 0x03, 0x3c, 0x3d, 0xc2, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x03, 0x3e, 0x01, 0xbe, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x3c, 0x3f, 0xfe, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x03, 0x02, 0x01, 0x3e, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x03, 0x00, 0x02, 0x3f, 0x42, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x03, 0x02, 0x02, 0x3d, 0x01, 0xbc, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x00, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + static const uint8_t fir_data_int256_clkr2[1280] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xfc, 0x80, 0x80, 0x00, @@ -1241,7 +1416,7 @@ int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfam s_st8_dsp = fir_data_int16_clkr2; break; case FGBOX_X32: - s_st8_dsp = fir_data_int32_clkr2; + s_st8_dsp = (fam == DSP_USSERIES) ? fir_data_int32_clkr2_us : fir_data_int32_clkr2; break; case FGBOX_X64: s_st8_dsp = fir_data_int64_clkr2; From 9c2ef45f89733e5b6c6eb2a8bc38f25adbbca9c0 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 10 Dec 2025 15:18:59 +0400 Subject: [PATCH 261/397] xsdp: ci16->3cf32_2 generic --- src/lib/xdsp/CMakeLists.txt | 1 + src/lib/xdsp/conv.c | 11 +++++ src/lib/xdsp/conv.h | 7 ++++ src/lib/xdsp/conv_ci16_3cf32_2.c | 28 +++++++++++++ src/lib/xdsp/conv_ci16_3cf32_2.h | 12 ++++++ .../xdsp/templates/conv_ci16_3cf32_generic.t | 40 +++++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 src/lib/xdsp/conv_ci16_3cf32_2.c create mode 100644 src/lib/xdsp/conv_ci16_3cf32_2.h create mode 100644 src/lib/xdsp/templates/conv_ci16_3cf32_generic.t diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index 9e404d64..49f14b28 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -46,6 +46,7 @@ set(xdsplib_conv_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_6cf32_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8cf32_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8ci16_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_3cf32_2.c ) if(WVLT_ARCH_X86 OR WVLT_ARCH_X86_64) diff --git a/src/lib/xdsp/conv.c b/src/lib/xdsp/conv.c index 3087d1fc..c6d10def 100644 --- a/src/lib/xdsp/conv.c +++ b/src/lib/xdsp/conv.c @@ -34,6 +34,8 @@ #include "conv_ci16_8cf32_2.h" #include "conv_ci16_8ci16_2.h" +#include "conv_ci16_3cf32_2.h" + #include #include @@ -248,6 +250,15 @@ transform_info_t get_transform_fn(const char* from, } } + /* Interleave 1 -> 3 */ + if(inveccnt == 1 && outveccnt == 3) + { + if (isCI16(from) && isCF32(to)) { + transform_info_t l_conv_ci16_3f32 = { conv_get_ci16_3cf32(), tr_conv_i16_f32_sz }; + return l_conv_ci16_3f32; + } + } + /* Interleave 1 -> 2 */ if(inveccnt == 1 && outveccnt == 2) { diff --git a/src/lib/xdsp/conv.h b/src/lib/xdsp/conv.h index d5c1c1cd..89ce70d7 100644 --- a/src/lib/xdsp/conv.h +++ b/src/lib/xdsp/conv.h @@ -54,6 +54,13 @@ typedef void (*filter_function_t)(const int16_t *__restrict data, unsigned outdatabsz) \ { conv_fn(*indata, indatabsz, outdata[0], outdata[1], outdatabsz); } +#define DECLARE_TR_FUNC_1_3(conv_fn) \ +void tr_##conv_fn (const void *__restrict *__restrict indata, \ + unsigned indatabsz, \ + void *__restrict *__restrict outdata, \ + unsigned outdatabsz) \ +{ conv_fn(*indata, indatabsz, outdata[0], outdata[1], outdata[2], outdatabsz); } + #define DECLARE_TR_FUNC_1_4(conv_fn) \ void tr_##conv_fn (const void *__restrict *__restrict indata, \ unsigned indatabsz, \ diff --git a/src/lib/xdsp/conv_ci16_3cf32_2.c b/src/lib/xdsp/conv_ci16_3cf32_2.c new file mode 100644 index 00000000..15f6624f --- /dev/null +++ b/src/lib/xdsp/conv_ci16_3cf32_2.c @@ -0,0 +1,28 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_ci16_3cf32_2.h" +#include "attribute_switch.h" + +#define CONV_SCALE (1.0f/32767) + +#define TEMPLATE_FUNC_NAME conv_ci16_3cf32_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_3cf32_generic.t" +DECLARE_TR_FUNC_1_3(conv_ci16_3cf32_generic) + +conv_function_t conv_get_ci16_3cf32_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_3cf32_generic, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_ci16_3cf32() +{ + return conv_get_ci16_3cf32_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_ci16_3cf32_2.h b/src/lib/xdsp/conv_ci16_3cf32_2.h new file mode 100644 index 00000000..1d84f35b --- /dev/null +++ b/src/lib/xdsp/conv_ci16_3cf32_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_CI16_3CF32_H +#define CONV_CI16_3CF32_H + +#include "conv.h" + +conv_function_t conv_get_ci16_3cf32(); +conv_function_t conv_get_ci16_3cf32_c(generic_opts_t cpu_cap, const char **sfunc); + +#endif diff --git a/src/lib/xdsp/templates/conv_ci16_3cf32_generic.t b/src/lib/xdsp/templates/conv_ci16_3cf32_generic.t new file mode 100644 index 00000000..227d0871 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_3cf32_generic.t @@ -0,0 +1,40 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + const uint32_t *ld = (const uint32_t *)indata; + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + + for (; i >= 12; i -= 12, ld += 3) { + uint64_t v = *((uint64_t*)ld); + uint32_t w = *(ld + 2); + float a = (int16_t)(v); + float b = (int16_t)(v>>16); + float c = (int16_t)(v>>32); + float d = (int16_t)(v>>48); + float e = (int16_t)(w); + float f = (int16_t)(w>>16); + + *(outdata_0++) = a * CONV_SCALE; + *(outdata_0++) = b * CONV_SCALE; + *(outdata_1++) = c * CONV_SCALE; + *(outdata_1++) = d * CONV_SCALE; + *(outdata_2++) = e * CONV_SCALE; + *(outdata_2++) = f * CONV_SCALE; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME From 9d3068bb2023b4de744a604dce10b55cdedc9bd9 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 11 Dec 2025 01:28:51 +0400 Subject: [PATCH 262/397] xdsp add 3->1 mux for ci16/cf32 --- src/lib/xdsp/CMakeLists.txt | 2 ++ src/lib/xdsp/conv.c | 19 +++++++++++++++++++ src/lib/xdsp/conv.h | 7 +++++++ src/lib/xdsp/conv_3cf32_ci16_2.c | 28 ++++++++++++++++++++++++++++ src/lib/xdsp/conv_3cf32_ci16_2.h | 12 ++++++++++++ src/lib/xdsp/conv_3ci16_ci16_2.c | 26 ++++++++++++++++++++++++++ src/lib/xdsp/conv_3ci16_ci16_2.h | 12 ++++++++++++ 7 files changed, 106 insertions(+) create mode 100644 src/lib/xdsp/conv_3cf32_ci16_2.c create mode 100644 src/lib/xdsp/conv_3cf32_ci16_2.h create mode 100644 src/lib/xdsp/conv_3ci16_ci16_2.c create mode 100644 src/lib/xdsp/conv_3ci16_ci16_2.h diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index 49f14b28..300b1977 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -47,6 +47,8 @@ set(xdsplib_conv_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8cf32_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8ci16_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_3cf32_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_3cf32_ci16_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_3ci16_ci16_2.c ) if(WVLT_ARCH_X86 OR WVLT_ARCH_X86_64) diff --git a/src/lib/xdsp/conv.c b/src/lib/xdsp/conv.c index c6d10def..f688e6f1 100644 --- a/src/lib/xdsp/conv.c +++ b/src/lib/xdsp/conv.c @@ -36,6 +36,10 @@ #include "conv_ci16_3cf32_2.h" +#include "conv_3cf32_ci16_2.h" +#include "conv_3ci16_ci16_2.h" + + #include #include @@ -250,6 +254,21 @@ transform_info_t get_transform_fn(const char* from, } } + /* Deinterleave 3 -> 1 */ + if(inveccnt == 3 && outveccnt == 1) + { + if (isCF32(from) && isCI16(to)) { + transform_info_t l_conv_3cf32_ci16 = { conv_get_3cf32_ci16(), tr_conv_f32_i16_sz }; + return l_conv_3cf32_ci16; + } + + if (isCI16(from) && isCI16(to)) { + transform_info_t l_conv_3ci16_ci16 = { conv_get_3ci16_ci16(), tr_dummy_sz }; + return l_conv_3ci16_ci16; + } + + } + /* Interleave 1 -> 3 */ if(inveccnt == 1 && outveccnt == 3) { diff --git a/src/lib/xdsp/conv.h b/src/lib/xdsp/conv.h index 89ce70d7..656649e6 100644 --- a/src/lib/xdsp/conv.h +++ b/src/lib/xdsp/conv.h @@ -82,6 +82,13 @@ void tr_##conv_fn (const void *__restrict *__restrict indata, \ unsigned outdatabsz) \ { conv_fn(indata[0], indata[1], indatabsz, outdata[0], outdatabsz); } +#define DECLARE_TR_FUNC_3_1(conv_fn) \ +void tr_##conv_fn (const void *__restrict *__restrict indata, \ + unsigned indatabsz, \ + void *__restrict *__restrict outdata, \ + unsigned outdatabsz) \ +{ conv_fn(indata[0], indata[1], indata[2], indatabsz, outdata[0], outdatabsz); } + #define DECLARE_TR_FUNC_4_1(conv_fn) \ void tr_##conv_fn (const void *__restrict *__restrict indata, \ unsigned indatabsz, \ diff --git a/src/lib/xdsp/conv_3cf32_ci16_2.c b/src/lib/xdsp/conv_3cf32_ci16_2.c new file mode 100644 index 00000000..2b03f376 --- /dev/null +++ b/src/lib/xdsp/conv_3cf32_ci16_2.c @@ -0,0 +1,28 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_3cf32_ci16_2.h" +#include "attribute_switch.h" + +#define CONV_SCALE (1.0f/32767) + +#define TEMPLATE_FUNC_NAME conv_3cf32_ci16_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_3cf32_ci16_generic.t" +DECLARE_TR_FUNC_3_1(conv_3cf32_ci16_generic) + +conv_function_t conv_get_3cf32_ci16_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_3cf32_ci16_generic, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_3cf32_ci16() +{ + return conv_get_3cf32_ci16_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_3cf32_ci16_2.h b/src/lib/xdsp/conv_3cf32_ci16_2.h new file mode 100644 index 00000000..b1b61e05 --- /dev/null +++ b/src/lib/xdsp/conv_3cf32_ci16_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_3CF32_CI16_H +#define CONV_3CF32_CI16_H + +#include "conv.h" + +conv_function_t conv_get_3cf32_ci16(); +conv_function_t conv_get_3cf32_ci16_c(generic_opts_t cpu_cap, const char **sfunc); + +#endif diff --git a/src/lib/xdsp/conv_3ci16_ci16_2.c b/src/lib/xdsp/conv_3ci16_ci16_2.c new file mode 100644 index 00000000..dd665e3c --- /dev/null +++ b/src/lib/xdsp/conv_3ci16_ci16_2.c @@ -0,0 +1,26 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_3ci16_ci16_2.h" +#include "attribute_switch.h" + +#define TEMPLATE_FUNC_NAME conv_3ci16_ci16_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_3ci16_ci16_generic.t" +DECLARE_TR_FUNC_3_1(conv_3ci16_ci16_generic) + +conv_function_t conv_get_3ci16_ci16_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_3ci16_ci16_generic, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_3ci16_ci16() +{ + return conv_get_3ci16_ci16_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_3ci16_ci16_2.h b/src/lib/xdsp/conv_3ci16_ci16_2.h new file mode 100644 index 00000000..d72baad4 --- /dev/null +++ b/src/lib/xdsp/conv_3ci16_ci16_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_3CI16_CI16_H +#define CONV_3CI16_CI16_H + +#include "conv.h" + +conv_function_t conv_get_3ci16_ci16(); +conv_function_t conv_get_3ci16_ci16_c(generic_opts_t cpu_cap, const char **sfunc); + +#endif From 8f1c3f54d5ed78a145df8abe85f29e1658adfdac Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 11 Dec 2025 01:33:49 +0400 Subject: [PATCH 263/397] streaming: add x3 channel count support --- src/lib/device/m2_dsdr/m2_dsdr.c | 4 +- src/lib/ipblks/streams/sfe_rx_4.c | 41 +++++++++++++++---- src/lib/ipblks/streams/sfe_rx_4.h | 5 ++- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 34 ++++++++++----- 4 files changed, 60 insertions(+), 24 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index f3bd1210..c8c9ba3a 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -2327,8 +2327,8 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char if (res) { return res; } - if (channels->count > 8 || channels->count == 3 || channels->count == 5 || channels->count == 7 || channels->count == 6) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "DSDR %s: Unsupported channel count: %d, valid are (1, 2, 4)\n", sid, channels->count); + if (channels->count > 8 || channels->count == 5 || channels->count == 7) { + USDR_LOG("UDEV", USDR_LOG_ERROR, "DSDR %s: Unsupported channel count: %d, valid are (1, 2, 3, 4, 6, 8)\n", sid, channels->count); return -EINVAL; } diff --git a/src/lib/ipblks/streams/sfe_rx_4.c b/src/lib/ipblks/streams/sfe_rx_4.c index 68ba9e08..3c5e2212 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.c +++ b/src/lib/ipblks/streams/sfe_rx_4.c @@ -504,7 +504,7 @@ int sfe_rf4_nco_freq(const sfe_cfg_t* fe, int32_t freq) #define MAX_EXLG_CHANS 4 #define MAX_EX_CHANS (1<sfmt); unsigned bps = bfmt.bits; @@ -513,10 +513,18 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str return -EINVAL; } unsigned chns = psc->chcnt; + bool pack_3x16 = false; + if (bfmt.complex) { chns *= 2; } + if ((bps == 16) && (chns == 6 || chns == 12 || chns == 24 || chns == 48)) { + chns = (chns / 3) * 4; + pack_3x16 = true; + bps = 12; + } + unsigned j, chlg = 0; for (j = 1; j <= fe->cfg_raw_chans; j <<= 1, chlg++) { if (chns == j) @@ -553,8 +561,8 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str unsigned samplerperbursts = data.samples; unsigned raw_burst_sz = (bps == 12) ? (chns * samplerperbursts * 12 + 7) / 8 : chns * samplerperbursts * 2; - USDR_LOG("STRM", USDR_LOG_INFO, "EXFERX: Stream %s configured in %d bytes (%d samples x %d chans x %d bits) X %d bursts; naked burst size %d; fifo capacity %d\n", - psc->sfmt, bbytes, samplerperbursts, 1 << chlg, bps, bursts, raw_burst_sz, fifo_capacity); + USDR_LOG("STRM", USDR_LOG_INFO, "EXFERX: Stream %s configured in %d bytes (%d samples x %d chans x %d bits %s) X %d bursts; naked burst size %d; fifo capacity %d\n", + psc->sfmt, bbytes, samplerperbursts, 1 << chlg, bps, pack_3x16 ? "3x16 mode" : "", bursts, raw_burst_sz, fifo_capacity); res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_RESET, RX_SCMD_IDLE | @@ -566,14 +574,15 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_BURST_BYTES, bbytes - 1); res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_BURST_CAPACITY, fifo_capacity); res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_COMPACTER, chlg); - res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_PACKER, bps == 12 ? 1 : 0); + res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_PACKER, pack_3x16 ? 3 : bps == 12 ? 1 : 0); - res = res ? res : exfe_trx4_update_chmap(fe, false, bfmt.complex, chns, &psc->channels); + res = res ? res : exfe_trx4_update_chmap(fe, false, bfmt.complex, pack_3x16, chns, &psc->channels); pfc->bpb = bbytes; pfc->burstspblk = bursts; pfc->oob_len = 0; pfc->oob_off = 0; + *out_pack_3x16 = pack_3x16; return res; } @@ -581,8 +590,9 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str int exfe_trx4_update_chmap(const sfe_cfg_t* fe, bool mask, bool complex, + bool pack_3x16, unsigned total_chan_num, - const channel_info_t* newmap) + const channel_info_t* newmap_orig) { int res = 0; uint8_t chmap[MAX_EX_CHANS]; @@ -591,10 +601,23 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, uint16_t ch_remapped[MAX_EXLG_CHANS]; memset(ch_remapped, 0, sizeof(ch_remapped)); memset(flag_swap_iq, 0, sizeof(flag_swap_iq)); - + channel_info_t pack_3x16_mmap; unsigned lg_chans = (fe->cfg_raw_chans == 16) ? 4 : (fe->cfg_raw_chans == 8) ? 3 : (fe->cfg_raw_chans == 4) ? 2 : (fe->cfg_raw_chans == 2) ? 1 : 0; unsigned msk = mask ? ((complex ? total_chan_num / 2 : total_chan_num) - 1) : 0xff; + if (pack_3x16) { + // Every 7th and 8-th channel is ignored since it coinatins garbage anyway + for (unsigned g = 0, h = 0; g < fe->cfg_raw_chans; g++) { + if ((g % 8) == 6 || (g % 8) == 7) { + pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h + (g % 8) - 8]; + } else { + pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h++]; + } + } + } + + const channel_info_t* newmap = (pack_3x16) ? &pack_3x16_mmap : newmap_orig; + for (unsigned g = 0; g < fe->cfg_raw_chans; g = g + total_chan_num) { for (unsigned f = 0; f < total_chan_num; f++) { unsigned swp_msk = (g + f); @@ -633,11 +656,11 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, return res; } -int exfe_tx4_config(const sfe_cfg_t* fe, unsigned bmt, unsigned expand) +int exfe_tx4_config(const sfe_cfg_t* fe, unsigned bmt, unsigned expand, bool pack_3x16) { int res = 0; res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_EXPAND, expand); - res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_TXFMT12, bmt == 12 ? 1 : 0); + res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_TXFMT12, pack_3x16 ? 3 : bmt == 12 ? 1 : 0); return res; } diff --git a/src/lib/ipblks/streams/sfe_rx_4.h b/src/lib/ipblks/streams/sfe_rx_4.h index 62fb3dd9..8e9e038d 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.h +++ b/src/lib/ipblks/streams/sfe_rx_4.h @@ -23,16 +23,17 @@ int sfe_rf4_nco_freq(const sfe_cfg_t* fe, int32_t freq); int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, - struct fifo_config* pfc); + struct fifo_config* pfc, bool *out_pack_3x16); int exfe_trx4_update_chmap(const sfe_cfg_t* fe, bool mask, bool complex, + bool pack_3x16, unsigned total_chan_num, const channel_info_t *newmap); int exfe_tx4_mute(const sfe_cfg_t* fe, uint64_t mutemask); -int exfe_tx4_config(const sfe_cfg_t* fe, unsigned bmt, unsigned expand); +int exfe_tx4_config(const sfe_cfg_t* fe, unsigned bmt, unsigned expand, bool pack_3x16); #endif diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 8f4b20f7..f0f8450b 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -89,6 +89,7 @@ struct stream_sfetrx_dma32 { extxcfg_cache_t cstx4; uint64_t hw_pwr_mask; // Powered chans (hw) + uint8_t pack_3x16; }; typedef struct stream_sfetrx_dma32 stream_sfetrx_dma32_t; @@ -600,6 +601,7 @@ int _sfetrx4_option_set(stream_handle_t* str, const char* name, int64_t in_val) return exfe_trx4_update_chmap(&stream->storage.srx4, stream->type == USDR_ZCPY_TX, stream->fe_complex, + stream->pack_3x16, (stream->fe_complex ? 2 : 1) * stream->fe_chans, (const channel_info_t *)in_val); } else if (stream->type == USDR_ZCPY_TX && (strcmp(name, "mute") == 0)) { @@ -792,8 +794,9 @@ static int initialize_stream_rx_32(device_t* device, } // TODO obtain exfe configuration constants + bool pack_3x16 = false; res = (fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0 || fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0_8) ? - exfe_rx4_configure(fecfg, &sc, &fc) : + exfe_rx4_configure(fecfg, &sc, &fc, &pack_3x16) : sfe_rx4_configure(fecfg, &sc, &fc, &hw_chan_msk); if (res) return res; @@ -845,7 +848,7 @@ static int initialize_stream_rx_32(device_t* device, strdev->pkt_bytes = sparams.block_size; strdev->host_bytes = funcs.sfunc(sparams.block_size, false); - strdev->wire_bps = 8 * strdev->pkt_bytes / strdev->pkt_symbs; + strdev->wire_bps = 8 * strdev->pkt_bytes / strdev->pkt_symbs / strdev->channels; strdev->tf_data = funcs.cfunc; strdev->tf_size = funcs.sfunc; @@ -871,9 +874,9 @@ static int initialize_stream_rx_32(device_t* device, strdev->storage.srx4 = *fecfg; strdev->hw_pwr_mask = hw_chan_msk; - - USDR_LOG("DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64"\n", - strdev->pkt_symbs, strdev->wire_bps, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask); + strdev->pack_3x16 = pack_3x16; + USDR_LOG("DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", + strdev->pkt_symbs, strdev->wire_bps, strdev->channels, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask, strdev->pack_3x16); *outu = strdev; return 0; @@ -999,9 +1002,8 @@ static int initialize_stream_tx_32(device_t* device, } } - unsigned bits_per_single_sym = bfmt.bits * (bfmt.complex ? 2 : 1); - // Check core fe sanity + bool pack_3x16 = false; unsigned fe_old_tx_swap = 0; unsigned fe_old_tx_mute = 0; if (fecfg->cfg_fecore_id == CORE_SFETX_DMA32_R0) { @@ -1026,6 +1028,13 @@ static int initialize_stream_tx_32(device_t* device, unsigned llcanhs = (bfmt.complex ? 2 : 1) * sc.chcnt; unsigned expand; + unsigned lbits = bfmt.bits; + if ((lbits == 16) && (llcanhs == 6 || llcanhs == 12 || llcanhs == 24 || llcanhs == 48)) { + llcanhs = (llcanhs / 3) * 4; + pack_3x16 = true; + lbits = 12; + } + switch (llcanhs) { case 1: expand = 0; break; case 2: expand = 1; break; @@ -1034,12 +1043,13 @@ static int initialize_stream_tx_32(device_t* device, case 16: expand = 4; break; case 32: expand = 5; break; default: + USDR_LOG("DSTR", USDR_LOG_ERROR, "TX: Unable to deliver %d chans in %d bits!\n", llcanhs, lbits); return -EINVAL; } res = res ? res : exfe_tx4_mute(fecfg, 0); - res = res ? res : exfe_tx4_config(fecfg, bfmt.bits, expand); - res = res ? res : exfe_trx4_update_chmap(fecfg, true, bfmt.complex, llcanhs, &sc.channels); + res = res ? res : exfe_tx4_config(fecfg, lbits, expand, pack_3x16); + res = res ? res : exfe_trx4_update_chmap(fecfg, true, bfmt.complex, pack_3x16, llcanhs, &sc.channels); if (res) { return res; @@ -1050,6 +1060,7 @@ static int initialize_stream_tx_32(device_t* device, if (res) return res; + unsigned bits_per_single_sym = bfmt.bits * (bfmt.complex ? 2 : 1); lowlevel_stream_params_t sparams; stream_t sid; lowlevel_ops_t* dops = lowlevel_get_ops(device->dev); @@ -1157,8 +1168,9 @@ static int initialize_stream_tx_32(device_t* device, extxcfg_cache_init(&strdev->cstx4); strdev->hw_pwr_mask = pwr_hw_mask; - USDR_LOG("DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64"\n", - strdev->pkt_symbs, strdev->wire_bps, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask); + strdev->pack_3x16 = pack_3x16; + USDR_LOG("DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", + strdev->pkt_symbs, strdev->wire_bps, strdev->channels, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask, strdev->pack_3x16); *outu = strdev; return 0; From 6e96777dc94f9c677fc5b3b83744124124e9394d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 11 Dec 2025 01:34:26 +0400 Subject: [PATCH 264/397] xdsp: add x3 mux templates --- .../xdsp/templates/conv_3cf32_ci16_generic.t | 35 ++++++++++++++++++ .../xdsp/templates/conv_3ci16_ci16_generic.t | 36 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/lib/xdsp/templates/conv_3cf32_ci16_generic.t create mode 100644 src/lib/xdsp/templates/conv_3ci16_ci16_generic.t diff --git a/src/lib/xdsp/templates/conv_3cf32_ci16_generic.t b/src/lib/xdsp/templates/conv_3cf32_ci16_generic.t new file mode 100644 index 00000000..bfa818da --- /dev/null +++ b/src/lib/xdsp/templates/conv_3cf32_ci16_generic.t @@ -0,0 +1,35 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + const void *__restrict indata_2_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 2) < i) + i = (outdatabsz * 2); + + const float* indata_0 = (const float*)indata_0_p; + const float* indata_1 = (const float*)indata_1_p; + const float* indata_2 = (const float*)indata_2_p; + int16_t* outdata = (int16_t*)outdata_p; + + for (; i >= 24; i -= 24, indata_0 += 2, indata_1 += 2, indata_2 += 2, outdata += 6) { + int16_t a = indata_0[0] / CONV_SCALE; + int16_t b = indata_0[1] / CONV_SCALE; + int16_t c = indata_1[0] / CONV_SCALE; + int16_t d = indata_1[1] / CONV_SCALE; + int16_t e = indata_2[0] / CONV_SCALE; + int16_t f = indata_2[1] / CONV_SCALE; + + uint64_t v = (uint64_t)(uint16_t)a | ((uint64_t)(uint16_t)b << 16) | ((uint64_t)(uint16_t)c << 32) | ((uint64_t)(uint16_t)d << 48); + uint32_t w = (uint32_t)(uint16_t)e | ((uint32_t)(uint16_t)f << 16); + *(uint64_t*)outdata = v; + *(uint32_t*)(outdata + 4) = w; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_3ci16_ci16_generic.t b/src/lib/xdsp/templates/conv_3ci16_ci16_generic.t new file mode 100644 index 00000000..0f4988f0 --- /dev/null +++ b/src/lib/xdsp/templates/conv_3ci16_ci16_generic.t @@ -0,0 +1,36 @@ + +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + const void *__restrict indata_2_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + const int16_t* indata_0 = (int16_t*)indata_0_p; + const int16_t* indata_1 = (int16_t*)indata_1_p; + const int16_t* indata_2 = (int16_t*)indata_2_p; + int16_t* outdata = (int16_t*)outdata_p; + + for (; i >= 12; i -= 12, indata_0 += 2, indata_1 += 2, indata_2 += 2, outdata += 6) { + int16_t a = indata_0[0]; + int16_t b = indata_0[1]; + int16_t c = indata_1[0]; + int16_t d = indata_1[1]; + int16_t e = indata_2[0]; + int16_t f = indata_2[1]; + + uint64_t v = (uint64_t)(uint16_t)a | ((uint64_t)(uint16_t)b << 16) | ((uint64_t)(uint16_t)c << 32) | ((uint64_t)(uint16_t)d << 48); + uint32_t w = (uint32_t)(uint16_t)e | ((uint32_t)(uint16_t)f << 16); + *(uint64_t*)outdata = v; + *(uint32_t*)(outdata + 4) = w; + } + + // do nothing with leftover +} + +#undef TEMPLATE_FUNC_NAME From d365db53058e8f40abadd16a6c5d38c843170af2 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 11 Dec 2025 13:31:01 +0400 Subject: [PATCH 265/397] dsdr: remove old code --- src/lib/device/m2_dsdr/m2_dsdr.c | 83 +------------------------------- 1 file changed, 2 insertions(+), 81 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index c8c9ba3a..d77dbac4 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -616,7 +616,6 @@ struct dev_m2_dsdr { // 0xff means channel not wired uint8_t rx_ordinal_to_logic[MAX_LOGIC_CHANS]; uint8_t tx_ordinal_to_logic[MAX_LOGIC_CHANS]; - //uint8_t tx_hw_to_logic[MAX_LOGIC_CHANS]; // hw -> logic, index is hw chnum // Configuration parameters opt_u64_t rx_ord_freqs[MAX_LOGIC_CHANS]; @@ -734,18 +733,8 @@ static int dsdr_update_tx_remap(dev_m2_dsdr_t* d) int res = 0; for (unsigned i = 0; i < 4; i++) { - //if (d->tx_hw_to_logic[i] != 0xff) { - //tx_remap |= (d->tx_hw_to_logic[i] & 0x3) << (2 * i); - - //unsigned hw_chan = d->tx_lmap_info[d->rx_ordinal_to_logic[i]].hwport; - //if (hw_chan < MAX_ANT_PORT) { - // - //} - // hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[i]); - //} - if (d->tx_ordinal_to_logic[i] != 0xff) { - //tx_remap |= (d->rx_ordinal_to_logic[i] & 0x3) << (2 * i); + //tx_remap |= (d->tx_ordinal_to_logic[i] & 0x3) << (2 * i); unsigned hw_chan = d->tx_lmap_info[d->tx_ordinal_to_logic[i]].hwport; if (hw_chan < MAX_HIPER_FE_PORT) { @@ -821,31 +810,6 @@ static int dsdr_iterate_ordinal_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ res = res ? res : obj->ops.si64(&ph, val); } } - -#if 0 - for (unsigned i = 0; i < DSDR_CHANS_HW; i++) { - if (chmsk_is_set(&hw_msk, i)) { - ph.full_path[1] = rxchans ? d->hw_rxch_route[i] : d->hw_txch_route[i]; // i; - res = res ? res : obj->ops.si64(&ph, val); - } - } - - - for (unsigned i = 0; i < DSDR_CHANS_LOGIC; i++) { - if (chmsk_is_set(&logic_msk, i)) { - - uint8_t map = (rxchans) ? d->rx_ordinal_to_logic[i] : d->tx_ordinal_to_logic[i]; - if (map == 0xff) { - // Channel disabled - continue; - } - - ph.full_path[1] = rxchans ? d->hw_rxch_route[i] : d->hw_txch_route[i]; //i; - res = res ? res : obj->ops.si64(&ph, val); - - } - } -#endif return res; } @@ -1057,34 +1021,6 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f TX_NCO=%.3f\n", ord, hwidx + 'A', w->band, freq / 1.0e6, ncoval / 1.0e6); res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_TX, hwidx, ncoval / 1000, 0, w->band); return res; -#if 0 - uint64_t ncoval = freq; - if (dev_m2_dsdr_has_hiper(d)) { - bool ch_txiq; - bool mod = false; - unsigned fe_chan = s_chanmap_hw_to_fe[chno]; - int res = dsdr_hiper_fe_tx_freq_set(&d->hiper, fe_chan, freq, &ncoval, &ch_txiq); - if (res) - return res; - - // d->txbb_swap_iq = (ch_txiq) ? d->txbb_swap_iq | (1u << chno) : d->txbb_swap_iq & (~(1u << chno)); - for (unsigned k = 0; k < DSDR_CHANS_HW; k++) { - if ((d->tx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG) == chno) { - uint8_t nchan = (ch_txiq) ? d->tx_chans.ch_map[k] | CH_SWAP_IQ_FLAG : d->tx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG; - if (nchan != d->tx_chans.ch_map[k]) { - d->tx_chans.ch_map[k] = nchan; - mod = true; - } - } - } - if (mod) { - res = res ? res : d->tx->ops->option_set(d->tx, "chmap", (uintptr_t)&d->tx_chans); - } - } - - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d] F=%.3f TX_NCO=%.3f\n", chno, freq / 1.0e6, ncoval / 1.0e6); - return d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_TX, chno, ncoval / 1000, 0, 0); -#endif } int dev_m2_dsdr_sdr_rx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -1192,8 +1128,6 @@ int dev_m2_dsdr_gain_tx_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t v } unsigned hwidx = d->hw_txch_route[w->hwport]; return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); - //res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_TX, i, dsa_attn); - //return res; } int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t value) @@ -1219,7 +1153,6 @@ int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint6 res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[hwidx], rem_gain, NULL); } res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); - //res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, dsa_attn); return res; } @@ -1244,8 +1177,6 @@ int dev_m2_dsdr_gain_rx_lna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu } return -EINVAL; - //int res = dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[i], value, NULL); - //return res; } int dev_m2_dsdr_gain_rx_pga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -1265,15 +1196,13 @@ int dev_m2_dsdr_gain_rx_pga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu } unsigned hwidx = d->hw_rxch_route[w->hwport]; return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); - //int res = d->st.libcapi79xx_set_dsa(&d->st.capi, NCO_RX, i, 50 - 2 * value); - //return res; } static int dsdr_set_rates(dev_m2_dsdr_t* d, uint32_t rx_rate, uint32_t tx_rate) { int res = 0; - unsigned tx_inters[] = { 1, 2, 0, 4, 0, 8, 16, 32, 0, 0, 0 }; + unsigned tx_inters[] = { 1, 2, 0, 4, 0, 8, 16, 32, 64, 128, 256 }; unsigned rx_decims[] = { 1, 2, 3, 4, 6, 8, 16, 32, 64, 128, 256 }; unsigned i = 0; unsigned ii; @@ -2447,9 +2376,6 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char d->hw_enabled_tx |= (1ull << hw); d->logic_enabled_tx |= (1ull << logic); - - - //d->tx_hw_to_logic[hw] = i; } // Map as single channel only @@ -2460,9 +2386,6 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char dsdr_chan_name(d, false, 4), dsdr_chan_name(d, false, 5), dsdr_chan_name(d, false, 6), dsdr_chan_name(d, false, 7), d->hw_enabled_tx, d->logic_enabled_tx); - // USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR TX channels %d remmaped: [A <= %c, B <= %c, C <= %c, D <= %c] mux, hw_mask %02x\n", - // channels->count, dsdr_chan_num(d->tx_hw_to_logic[0]), dsdr_chan_num(d->tx_hw_to_logic[1]), - // dsdr_chan_num(d->tx_hw_to_logic[2]), dsdr_chan_num(d->tx_hw_to_logic[3]), d->hw_enabled_tx); struct sfetrx4_config txcfg; res = (res) ? res : parse_sfetrx4(dformat, &lchans, pktsyms, channels->count, &txcfg); @@ -2498,7 +2421,6 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char // TODO: set actual antenna mask res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0xf); - //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0x0); *out_handle = d->tx; } @@ -2583,7 +2505,6 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) memset(d->rx_ordinal_to_logic, 0xff, sizeof(d->rx_ordinal_to_logic)); memset(d->tx_ordinal_to_logic, 0xff, sizeof(d->tx_ordinal_to_logic)); - //memset(d->tx_hw_to_logic, 0xff, sizeof(d->tx_hw_to_logic)); d->tx_activated = false; d->rx_activated = false; From f2df45ea544907b00cb061d0c734248c1b762f0e Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Thu, 11 Dec 2025 19:20:31 +0400 Subject: [PATCH 266/397] Fixed build in case when the root folder have uppercase letters. --- Taskfile.box.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.box.yaml b/Taskfile.box.yaml index af9b1d87..ef2488b3 100644 --- a/Taskfile.box.yaml +++ b/Taskfile.box.yaml @@ -7,7 +7,7 @@ vars: NOW: sh: "date +%Y%m%d%H%m%S" LABEL: - sh: "echo box-$(basename {{.ROOT_DIR}})" + sh: "echo box-$(basename {{.ROOT_DIR}} | tr '[:upper:]' '[:lower:]')" DOCKER_FILE_PREFIX: "docker/Dockerfile.box" tasks: From b24d7de53a3eedcb40fcc6d411e450a406c790ed Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Mon, 15 Dec 2025 12:01:12 +0300 Subject: [PATCH 267/397] Fixed soapy timestamp --- src/soapysdr/usdr_soapy.cpp | 3 ++- src/soapysdr/usdr_soapy.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/soapysdr/usdr_soapy.cpp b/src/soapysdr/usdr_soapy.cpp index fe4f297a..b39aab6f 100644 --- a/src/soapysdr/usdr_soapy.cpp +++ b/src/soapysdr/usdr_soapy.cpp @@ -1455,7 +1455,8 @@ int SoapyUSDR::writeStream(SoapySDR::Stream *stream, unsigned toSend = numElems; int res = usdr_dms_send(ustr->strm, (const void **) buffs, numElems, ts, timeoutUs / 1000); - this->calc_ts += numElems; + if (this->calc_ts >= 0) + this->calc_ts += numElems; if (tx_pkts % 1000 == 0) { SoapySDR::logf(_dump_calls ? SOAPY_SDR_ERROR : SOAPY_SDR_TRACE, diff --git a/src/soapysdr/usdr_soapy.h b/src/soapysdr/usdr_soapy.h index c5cb1261..8e1d6f9a 100644 --- a/src/soapysdr/usdr_soapy.h +++ b/src/soapysdr/usdr_soapy.h @@ -366,7 +366,7 @@ class SoapyUSDR : public SoapySDR::Device int _txcorr = 0; - int64_t calc_ts = 0LL; + int64_t calc_ts = -1LL; std::string _clk_source = "internal"; }; From ed8c967d1716e456fa6c6dbe1ba0e5bcb49799c1 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 16 Dec 2025 23:57:22 +0400 Subject: [PATCH 268/397] afe79xx: add tdd call --- src/lib/hw/afe79xx/afe79xx.c | 4 +++- src/lib/hw/afe79xx/afe79xx.h | 2 ++ src/lib/hw/afe79xx/libcapi79xx_api.h | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib/hw/afe79xx/afe79xx.c b/src/lib/hw/afe79xx/afe79xx.c index 508f79e2..861dcd73 100644 --- a/src/lib/hw/afe79xx/afe79xx.c +++ b/src/lib/hw/afe79xx/afe79xx.c @@ -138,8 +138,10 @@ int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipT out->libcapi79xx_check_health = (libcapi79xx_check_health_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_CHECK_HEALTH_FN); + out->libcapi79xx_set_tdd = (libcapi79xx_set_tdd_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_SET_TDD_FN); + if (!out->libcapi79xx_create || !out->libcapi79xx_destroy || !out->libcapi79xx_init || - !out->libcapi79xx_set_dsa || + !out->libcapi79xx_set_dsa || !out->libcapi79xx_set_tdd || !out->libcapi79xx_upd_nco || !out->libcapi79xx_get_nco || !out->libcapi79xx_check_health) { USDR_LOG("79xx", USDR_LOG_ERROR, "Broken CAPI AFE79XX NDA LIB wrapper `%s`!\n", afe79xxlib); diff --git a/src/lib/hw/afe79xx/afe79xx.h b/src/lib/hw/afe79xx/afe79xx.h index e019aa96..5c1858ac 100644 --- a/src/lib/hw/afe79xx/afe79xx.h +++ b/src/lib/hw/afe79xx/afe79xx.h @@ -26,6 +26,8 @@ struct afe79xx_state { libcapi79xx_check_health_fn_t libcapi79xx_check_health; + libcapi79xx_set_tdd_fn_t libcapi79xx_set_tdd; + }; typedef struct afe79xx_state afe79xx_state_t; diff --git a/src/lib/hw/afe79xx/libcapi79xx_api.h b/src/lib/hw/afe79xx/libcapi79xx_api.h index b59ac5cd..9b8a99fa 100644 --- a/src/lib/hw/afe79xx/libcapi79xx_api.h +++ b/src/lib/hw/afe79xx/libcapi79xx_api.h @@ -50,6 +50,7 @@ typedef int (*libcapi79xx_set_dsa_fn_t)(libcapi79xx_t* o, unsigned type, unsigne typedef int (*libcapi79xx_check_health_fn_t)(libcapi79xx_t* o, int *ok, unsigned sz, char* buf); +typedef int (*libcapi79xx_set_tdd_fn_t)(libcapi79xx_t* o, uint8_t rx, uint8_t fb, uint8_t tx); #define LIBCAPI79XX_CREATE_FN "libcapi79xx_create" #define LIBCAPI79XX_DESTROY_FN "libcapi79xx_destroy" @@ -62,4 +63,6 @@ typedef int (*libcapi79xx_check_health_fn_t)(libcapi79xx_t* o, int *ok, unsigned #define LIBCAPI79XX_CHECK_HEALTH_FN "libcapi79xx_check_health" +#define LIBCAPI79XX_SET_TDD_FN "libcapi79xx_set_tdd" + #endif From 7a0ba7ada4eb3819b1e65a3c1912e40ec3efba21 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 16 Dec 2025 23:59:54 +0400 Subject: [PATCH 269/397] sfe_rx_4: fix 3x channel mapper --- src/lib/ipblks/streams/sfe_rx_4.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/lib/ipblks/streams/sfe_rx_4.c b/src/lib/ipblks/streams/sfe_rx_4.c index 3c5e2212..901c9938 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.c +++ b/src/lib/ipblks/streams/sfe_rx_4.c @@ -608,12 +608,25 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, if (pack_3x16) { // Every 7th and 8-th channel is ignored since it coinatins garbage anyway for (unsigned g = 0, h = 0; g < fe->cfg_raw_chans; g++) { - if ((g % 8) == 6 || (g % 8) == 7) { - pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h + (g % 8) - 8]; + if (complex) { + if ((g % 4) == 3) { + pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h + (g % 4) - 4]; + } else { + pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h++]; + } } else { - pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h++]; + if ((g % 8) == 6 || (g % 8) == 7) { + pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h + (g % 8) - 8]; + } else { + pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h++]; + } } } + + for (unsigned g = 0; g < fe->cfg_raw_chans; g++) { + USDR_LOG("STRM", USDR_LOG_INFO, "3x16_MAP[%d]: %d => %d\n", g, + newmap_orig->ch_map[g], pack_3x16_mmap.ch_map[g]); + } } const channel_info_t* newmap = (pack_3x16) ? &pack_3x16_mmap : newmap_orig; From b507e16203a7788a8831b0e945fd4fe2ce0c7ed6 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 17 Dec 2025 00:08:40 +0400 Subject: [PATCH 270/397] dsdr: introduce AFE_PROFILE --- src/lib/device/m2_dsdr/m2_dsdr.c | 647 +++++++++++++++++++++++++------ 1 file changed, 529 insertions(+), 118 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index d77dbac4..3b6ae33a 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -42,16 +42,12 @@ enum dsdr_type { DSDR_PCIE_HIPER_R0 = 0xcf, }; -enum dsdr_jesdv { - DSDR_JESD204B_810_245 = 1, - DSDR_JESD204C_6664_245 = 7, - DSDR_JESD204C_6664_491 = 3, -}; - enum dsdr_jesd_config { - JESD_MODE_4X_4X_491 = 0, - JESD_MODE_8X_8X_369 = 1, - JESD_MODE_8X_4X_491 = 8, + JESD_MODE_4X_4X_491 = 0x03, + + JESD_MODE_4X_4X_DYN = 0xc3, + JESD_MODE_8X_4X_DYN = 0xd3, + JESD_MODE_8X_8X_DYN = 0xe3, }; // I2C buses @@ -489,19 +485,49 @@ enum DSDR_STATE { STATE_AFE_INIT = 1, }; +// Total 10 DSP chains in RX+FB and 8 DSP chains in TX +#define MAX_DSP_CHAINS 10 +// 0: TX/RX A0 +// 1: TX/RX B0 +// 2: TX/RX C0 +// 3: TX/RX D0 +// 4: TX/RX A1 +// 5: TX/RX B1 +// 6: TX/RX C1 +// 7: TX/RX D1 +// 8: FB AB0 +// 9: FB CD0 + +static unsigned make_afe79xx_dsp_index(enum nco_type nco, unsigned idx, unsigned band) +{ + switch (nco) { + case NCO_TX: + case NCO_RX: + return 4 * band + idx; + default: + return 8 + idx; + } +} + +// afe79xx lib operates in RX/FB +#define GET_HWRX_TYPE(x) (((x) < 4) ? NCO_RX : NCO_FB) +#define GET_HWRX_IDX(x) (((x) < 4) ? (x) : ((x) - 4)) +#define GET_HWTX_TYPE(x) NCO_TX +#define GET_HWTX_IDX(x) (x) + struct channel_logic_dsp_wire { - uint8_t dsp_type; - uint8_t hwport; - uint8_t band; + uint8_t dsp_type; // DSP NCO chain type + uint8_t dsp_idx; // DSP NCO chain index + uint8_t dsp_band; // DSP NCO chain band + uint8_t hwport; // External ADC / DAC port 0, 1, 2, 3 -- for RX/TX and 4, 5 -- for FB }; typedef struct channel_logic_dsp_wire channel_logic_dsp_wire_t; - static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco[] = { - { NCO_RX, 0, 0 }, - { NCO_RX, 1, 0 }, - { NCO_RX, 2, 0 }, - { NCO_RX, 3, 0 }, + { NCO_RX, 0, 0, 0 }, + { NCO_RX, 1, 0, 1 }, + { NCO_RX, 2, 0, 2 }, + { NCO_RX, 3, 0, 3 }, }; static const channel_map_info_t s_dsdr_chmap_s_nco[] = { { "a", 0 }, @@ -511,15 +537,39 @@ static const channel_map_info_t s_dsdr_chmap_s_nco[] = { { NULL, CH_NULL }, }; + +static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco_fbrx[] = { + { NCO_RX, 0, 0, 0 }, + { NCO_RX, 1, 0, 1 }, + { NCO_RX, 2, 0, 2 }, + { NCO_RX, 3, 0, 3 }, + { NCO_FB, 0, 0, 0 }, + { NCO_FB, 1, 0, 2 }, + { NCO_FB, 0, 0, 0 }, + { NCO_FB, 1, 0, 2 }, + }; + +static const channel_map_info_t s_dsdr_chmap_s_nco_rxfb[] = { + { "a", 0 }, + { "b", 1 }, + { "c", 2 }, + { "d", 3 }, + { "a1", 4 }, + { "c1", 5 }, + { "a2", 6 }, + { "c2", 7 }, + { NULL, CH_NULL }, + }; + static const channel_logic_dsp_wire_t s_dsdr_lmap_d_nco[] = { - { NCO_RX, 0, 0 }, - { NCO_RX, 1, 0 }, - { NCO_RX, 2, 0 }, - { NCO_RX, 3, 0 }, - { NCO_RX, 0, 1 }, - { NCO_RX, 1, 1 }, - { NCO_RX, 2, 1 }, - { NCO_RX, 3, 1 }, + { NCO_RX, 0, 0, 0 }, + { NCO_RX, 1, 0, 1 }, + { NCO_RX, 2, 0, 2 }, + { NCO_RX, 3, 0, 3 }, + { NCO_RX, 0, 1, 0 }, + { NCO_RX, 1, 1, 1 }, + { NCO_RX, 2, 1, 2 }, + { NCO_RX, 3, 1, 3 }, }; static const channel_map_info_t s_dsdr_chmap_d_nco[] = { { "a0", 0 }, @@ -534,12 +584,14 @@ static const channel_map_info_t s_dsdr_chmap_d_nco[] = { }; static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco_fb[] = { - { NCO_RX, 0, 0 }, - { NCO_RX, 1, 0 }, - { NCO_RX, 2, 0 }, - { NCO_RX, 3, 0 }, - { NCO_FB, 4, 0 }, - { NCO_FB, 5, 0 }, + { NCO_RX, 0, 0, 0 }, + { NCO_RX, 1, 0, 1 }, + { NCO_RX, 2, 0, 2 }, + { NCO_RX, 3, 0, 3 }, + { NCO_FB, 0, 0, 4 }, + { NCO_FB, 1, 0, 5 }, + { NCO_FB, 0, 0, 4 }, + { NCO_FB, 1, 0, 5 }, }; static const channel_map_info_t s_dsdr_chmap_s_nco_fb[] = { { "a", 0 }, @@ -548,6 +600,9 @@ static const channel_map_info_t s_dsdr_chmap_s_nco_fb[] = { { "d", 3 }, { "f0", 4 }, { "f1", 5 }, + { "f2", 6 }, + { "f3", 7 }, + { NULL, CH_NULL }, }; @@ -559,7 +614,7 @@ struct dev_m2_dsdr { subdev_t subdev; unsigned type; - unsigned jesdv; + //unsigned jesdv; unsigned jesd_x8; stream_handle_t* rx; @@ -569,7 +624,7 @@ struct dev_m2_dsdr { dsdr_hiper_fe_t hiper; uint32_t dsdr_state; - uint32_t cfg_afe_type; + //uint32_t cfg_afe_type; uint32_t cfg_rx_lanemap; uint32_t cfg_tx_lanemap; @@ -587,20 +642,15 @@ struct dev_m2_dsdr { unsigned hw_enabled_rx; // HW Enabled channels unsigned logic_enabled_tx; // Logic Enabled channels unsigned logic_enabled_rx; // Logic Enabled channels - - unsigned hw_mask_tx; // Physically wired TX channels - unsigned hw_mask_rx; // Physically wired RX channels - unsigned hw_chcnt_rx; unsigned hw_chcnt_tx; unsigned logic_chcnt_rx; unsigned logic_chcnt_tx; - unsigned hw_fpga_jesd_rx_en; // Physical lanes enabled bitmask 0: X0Y4, 1: X0Y5, ... 3: X0Y7 unsigned hw_fpga_jesd_tx_en; // Physical lanes enabled bitmask 0: X0Y4, 1: X0Y5, ... 3: X0Y7 - uint8_t hw_rxch_route[MAX_LOGIC_CHANS]; // Physical channel reroute dueto absent physical channels (like in AFE7903) - uint8_t hw_txch_route[MAX_LOGIC_CHANS]; // Physical channel reroute dueto absent physical channels (like in AFE7903) + unsigned dsp_rx_chans; + unsigned dsp_tx_chans; uint32_t adc_rate; unsigned rxbb_rate; @@ -626,6 +676,7 @@ struct dev_m2_dsdr { opt_u64_t tx_bxfc[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; opt_u64_t rx_raw_nco[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; opt_u64_t tx_raw_nco[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; + opt_u64_t fb_raw_nco[2]; channel_info_t rx_chans; channel_info_t tx_chans; @@ -656,6 +707,121 @@ static int dev_gpi_get32(lldev_t dev, unsigned bank, unsigned* data) return lowlevel_reg_rd32(dev, 0, 16 + (bank / 4), data); } +// GTH USP ALL REGS MAP +static const uint16_t s_gth_usp_regs[] = { + 0x0008, + 0x0009, + 0x000D, + 0x000E, + 0x0010, + 0x0011, + 0x0012, + 0x0013, + 0x0014, + 0x0015, + 0x0016, + 0x0018, + 0x0019, + 0x001A, + 0x001B, + 0x001C, + 0x001D, + 0x001E, + 0x001F, + 0x0020, + 0x0021, + 0x0022, + 0x0023, + 0x0024, + 0x0025, + 0x0029, + 0x002D, + 0x0030, + 0x0081, + 0x0082, + 0x0083, + 0x0084, + 0x0086, + 0x0088, + 0x0089, + 0x008B, + 0x008D, + 0x008E, + 0x008F, + 0x0090, + 0x0091, + 0x0092, + 0x0093, + 0x0094, + 0x0095, + 0x0096, + 0x0098, + 0x0099, + 0x009A, + 0x009B, + 0x009C, + 0x009D, + 0x009E, + 0x009F, + 0x00A0, + 0x00A1, + 0x00A2, + 0x00A3, + 0x00A4, + 0x00A5, + 0x00A8, + 0x00A9, + 0x00AD, + 0x00B0, +}; + +#define MAKE_DSDR_DRP_CMD(wr, idx, addr, data) ((((wr) & 1) << 28) | (((idx) ? 2 : 1) << 29) | (((addr) & 0xfff) << 16) | ((data) & 0xffff)) +#define MAKE_DSDR_PHY_REG(addr, data) ((1<<31) | (((addr) & 0xff) << 16) | (((data) & 0xff))) + +// +enum { + GTH_CTR_TX_EN = 0, + GTH_CTR_RX_EN = 1, + GTH_CTR_QPLL_EN = 2, +}; + +static int dsdr_gth_control(lldev_t dev, uint16_t addr, uint16_t data) +{ + int res = 0; + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_PHY_REG(addr, data)); + return res; +} + +static int dsdr_drp_reg_wr(lldev_t dev, unsigned port, uint16_t addr, uint16_t data) +{ + int res = 0; + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_DRP_CMD(1, port, addr, data)); + res = res ? res : usleep(10); + return res; +} + +static int dsdr_drp_reg_rd(lldev_t dev, unsigned port, uint16_t addr, uint16_t *odata) +{ + int res = 0; + uint32_t val = 0; + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_DRP_CMD(0, port, addr, 0)); + res = res ? res : usleep(10); + res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &val); + *odata = val >> (port ? 16 : 0); + return res; +} + +int gthcommon_init(dev_m2_dsdr_t *d) +{ + uint16_t val = 0; + int res = 0; + for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_usp_regs); i++) { + res = res ? res : dsdr_drp_reg_rd(d->base.dev, 0, s_gth_usp_regs[i], &val); + USDR_LOG("GTHC", USDR_LOG_WARNING, "GRP[%04x] => %04x\n", s_gth_usp_regs[i], val); + } + return res; +} + bool dev_m2_dsdr_has_hiper(dev_m2_dsdr_t* d) { return d->type == DSDR_PCIE_HIPER_R0; @@ -838,20 +1004,20 @@ static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned if (!w) { return -EINVAL; } - unsigned hwidx = d->hw_rxch_route[w->hwport]; uint64_t ncoval = freq; - if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { + if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { bool ch_rxiq; bool mod = false; - const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; + const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; // Map to HW channels const uint8_t iter_shared_selector[4] = { 0, 0, 1, 1 }; uint64_t chan_mid = 0; unsigned cnt = 0; int res = 0; const bool shared_lo_cfg_mode = true; + unsigned hwidx = w->hwport; - opt_u64_set_val(&d->rx_bxfc[hwidx][w->band], freq); + opt_u64_set_val(&d->rx_bxfc[hwidx][w->dsp_band], freq); for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; @@ -877,7 +1043,7 @@ static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned if (logic_ch == 0xff) continue; - unsigned hw_iter = d->hw_rxch_route[d->rx_lmap_info[logic_ch].hwport]; + unsigned hw_iter = d->rx_lmap_info[logic_ch].hwport; for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; @@ -919,8 +1085,8 @@ static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned return res; } - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f RX_NCO=%.3f\n", ord, hwidx + 'A', w->band, freq / 1.0e6, ncoval / 1.0e6); - res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_RX, hwidx, ncoval / 1000, 0, w->band); + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f RX_NCO=%.3f\n", ord, w->hwport + 'A', w->dsp_band, freq / 1.0e6, ncoval / 1.0e6); + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, w->dsp_type, w->dsp_idx, ncoval / 1000, 0, w->dsp_band); return res; } @@ -937,10 +1103,9 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned if (!w) { return -EINVAL; } - unsigned hwidx = d->hw_txch_route[w->hwport]; uint64_t ncoval = freq; - if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { + if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { bool ch_txiq; bool mod = false; const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; @@ -949,8 +1114,9 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned unsigned cnt = 0; int res = 0; const bool shared_lo_cfg_mode = true; + unsigned hwidx = w->hwport; - opt_u64_set_val(&d->tx_bxfc[hwidx][w->band], freq); + opt_u64_set_val(&d->tx_bxfc[hwidx][w->dsp_band], freq); for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; @@ -976,7 +1142,7 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned if (logic_ch == 0xff) continue; - unsigned hw_iter = d->hw_txch_route[d->tx_lmap_info[logic_ch].hwport]; + unsigned hw_iter = d->tx_lmap_info[logic_ch].hwport; for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; @@ -1018,8 +1184,8 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned return res; } - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f TX_NCO=%.3f\n", ord, hwidx + 'A', w->band, freq / 1.0e6, ncoval / 1.0e6); - res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_TX, hwidx, ncoval / 1000, 0, w->band); + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f TX_NCO=%.3f\n", ord, w->hwport + 'A', w->dsp_band, freq / 1.0e6, ncoval / 1.0e6); + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, w->dsp_type, w->dsp_idx, ncoval / 1000, 0, w->dsp_band); return res; } @@ -1050,7 +1216,7 @@ int dev_m2_dsdr_sdr_rx_dsa_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value return -EINVAL; } - return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, d->hw_rxch_route[w->hwport], value); + return d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWRX_TYPE(w->hwport), GET_HWRX_IDX(w->hwport), value); } int dev_m2_dsdr_sdr_tx_dsa_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -1068,7 +1234,7 @@ int dev_m2_dsdr_sdr_tx_dsa_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value return -EINVAL; } - return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, d->hw_txch_route[w->hwport], value); + return d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWTX_TYPE(w->hwport), GET_HWTX_IDX(w->hwport), value); } @@ -1101,13 +1267,12 @@ int dev_m2_dsdr_gain_rx_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t v if (!w) { return -EINVAL; } - unsigned hwidx = d->hw_rxch_route[w->hwport]; - if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { - res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[hwidx], rem_gain, NULL); + if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); } - res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); + res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWRX_TYPE(w->hwport), GET_HWRX_IDX(w->hwport), dsa_attn); return res; } @@ -1126,8 +1291,8 @@ int dev_m2_dsdr_gain_tx_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t v if (!w) { return -EINVAL; } - unsigned hwidx = d->hw_txch_route[w->hwport]; - return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); + + return d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWTX_TYPE(w->hwport), GET_HWTX_IDX(w->hwport), dsa_attn); } int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t value) @@ -1147,12 +1312,11 @@ int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint6 if (!w) { return -EINVAL; } - unsigned hwidx = d->hw_rxch_route[w->hwport]; - if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { - res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[hwidx], rem_gain, NULL); + if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); } - res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); + res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWRX_TYPE(w->hwport), GET_HWRX_IDX(w->hwport), dsa_attn); return res; } @@ -1170,10 +1334,9 @@ int dev_m2_dsdr_gain_rx_lna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu if (!w) { return -EINVAL; } - unsigned hwidx = d->hw_rxch_route[w->hwport]; - if (dev_m2_dsdr_has_hiper(d) && (hwidx < MAX_HIPER_FE_PORT)) { - return dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[hwidx], value, NULL); + if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + return dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[w->hwport], value, NULL); } return -EINVAL; @@ -1194,8 +1357,7 @@ int dev_m2_dsdr_gain_rx_pga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu if (!w) { return -EINVAL; } - unsigned hwidx = d->hw_rxch_route[w->hwport]; - return d->st.libcapi79xx_set_dsa(&d->st.capi, w->dsp_type, hwidx, dsa_attn); + return d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWRX_TYPE(w->hwport), GET_HWRX_IDX(w->hwport), dsa_attn); } @@ -1319,11 +1481,11 @@ static int dsdr_check_fpga_gtrx(dev_m2_dsdr_t* o) delay = (fpga_jesd >> 16) & 0x3ff; USDR_LOG("DSDR", (fpga_err_0 != 0 || fpga_err_1 != 0) ? USDR_LOG_ERROR : USDR_LOG_INFO, - "FPGA JESD: SYSREF realign TX/RX = %08x Delay = %d PLL Locked %d BUFFER_OVERFLOW: %04x ERRS %04x %04x %04x %04x \n", + "FPGA JESD_QUAD[%d]: SYSREF realign TX/RX = %08x Delay = %d PLL Locked %d BUFFER_OVERFLOW: %04x ERRS %04x %04x %04x %04x \n", q, fpga_jesd & 0xff, delay, (fpga_jesd >> 26) & 3, fpga_jesd >> 28, fpga_err_0 >> 16, fpga_err_0 & 0xffff, fpga_err_1 >> 16, fpga_err_1 & 0xffff); - USDR_LOG("DSDR", USDR_LOG_INFO, "FPGA JESD lanes: 3 2 1 0\n"); + USDR_LOG("DSDR", USDR_LOG_INFO, "FPGA JESD lanes: %s\n", q == 0 ? " 3 2 1 0" : " 7 6 5 4"); USDR_LOG("DSDR", USDR_LOG_INFO, "Block Header errors: %2d %2d %2d %2d\n", (fpga_err_0 >> 12) & 0xf, (fpga_err_0 >> 8) & 0xf, (fpga_err_0 >> 4) & 0xf, (fpga_err_0 >> 0) & 0xf); USDR_LOG("DSDR", USDR_LOG_INFO, "End of Multi-Block errors: %2d %2d %2d %2d\n", (fpga_err_0 >> 28) & 0xf, (fpga_err_0 >> 24) & 0xf, (fpga_err_0 >> 20) & 0xf, (fpga_err_0 >> 16) & 0xf); USDR_LOG("DSDR", USDR_LOG_INFO, "End of Extended Multi-Block errors: %2d %2d %2d %2d\n", (fpga_err_1 >> 12) & 0xf, (fpga_err_1 >> 8) & 0xf, (fpga_err_1 >> 4) & 0xf, (fpga_err_1 >> 0) & 0xf); @@ -1507,6 +1669,12 @@ void usdr_device_m2_dsdr_destroy(pdevice_t udev) // Activity LED off dev_gpo_set(dev, IGPO_BANK_LEDS, 0); + // Put JESD into power-down mode + dev_gpo_set(dev, IGPO_TIAFE_MASTER_RESET_N, 0); + dsdr_gth_control(dev, GTH_CTR_TX_EN, 0); + dsdr_gth_control(dev, GTH_CTR_RX_EN, 0); + dsdr_gth_control(dev, GTH_CTR_QPLL_EN, 0); + usdr_device_base_destroy(udev); } @@ -1517,11 +1685,19 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) uint32_t d = 0; bool pll_ready = false; + res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, 0xffff); + res = res ? res : dsdr_gth_control(dev, GTH_CTR_RX_EN, 0xffff); + res = res ? res : dsdr_gth_control(dev, GTH_CTR_QPLL_EN, 0b0101); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 1); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_SYNC_RESET, 1); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_MASTER_RESET_N, 0); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_ENABLED, dd->hw_fpga_jesd_rx_en); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_ENABLED, dd->hw_fpga_jesd_tx_en); + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_BUFFER_RELDLY_0, 0); // 0 means autodetect and adjust + res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_BUFFER_RELDLY_1, 0); // 0 means autodetect and adjust res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_0, dd->cfg_rx_lanemap & 0xff); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_MAP_1, (dd->cfg_rx_lanemap >> 8) & 0xff); @@ -1536,9 +1712,6 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_POLARITY, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_POLARITY, 0x0); - res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_LANE_ENABLED, dd->hw_fpga_jesd_rx_en); - res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_TX_LANE_ENABLED, dd->hw_fpga_jesd_tx_en); - res = res ? res : usleep(1000); res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_MASTER_RESET_N, 1); @@ -1567,6 +1740,9 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) res = res ? res :dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); + + // Disable unused lanes after GTH reset is done. GTWiz expects all lanes to be initialized, otherwise DONE signal won't be asserted + //res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, dd->hw_fpga_jesd_tx_en); return res; } @@ -1578,12 +1754,116 @@ static int usdr_jesd204b_bringup_post(struct dev_m2_dsdr *dd) res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 0); res = res ? res : usleep(10000); + res = res ? res : dsdr_gth_control(dev, GTH_CTR_RX_EN, dd->hw_fpga_jesd_rx_en); + res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, dd->hw_fpga_jesd_tx_en); + res = res ? res : dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); + + //bool second_qpll_req = ((dd->hw_fpga_jesd_tx_en | dd->hw_fpga_jesd_rx_en) >> 4) ? true : false; + //if (!second_qpll_req) { + // res = res ? res : dsdr_gth_control(dev, GTH_CTR_QPLL_EN, 0b0001); + //} + return res; } +enum jesd_rates { + RATE_245_76 = 245760000, + RATE_368_64 = 368640000, + RATE_491_52 = 491520000, +}; + +static const uint16_t s_gth_qpll_ovrd_491[] = { 0x0008, 0x333c, 0x000d, 0x0f00, 0x011, 0x87c0, 0x0014, 0x0040, 0x0019, 0x031d, 0x001b, 0x87c0, 0x0030, 0x0045}; +static const uint16_t s_gth_qpll_ovrd_369[] = { 0x0008, 0x331c, 0x000d, 0x0800, 0x011, 0x87c1, 0x0014, 0x0040, 0x0019, 0x033f, 0x001b, 0x87c1, 0x0030, 0x0004}; +static const uint16_t s_gth_qpll_ovrd_245[] = { 0x0008, 0x333c, 0x000d, 0x0f00, 0x011, 0x87c0, 0x0014, 0x0082, 0x0019, 0x031d, 0x001b, 0x87c0, 0x0030, 0x0045}; + +static int dsdr_gth_set_rate(struct dev_m2_dsdr *d, unsigned rate) +{ + int res = 0; + const uint16_t* mode; + switch (rate) { + case RATE_245_76: mode = s_gth_qpll_ovrd_245; break; + case RATE_368_64: mode = s_gth_qpll_ovrd_369; break; + case RATE_491_52: mode = s_gth_qpll_ovrd_491; break; + default: + return -EINVAL; + } + + for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_qpll_ovrd_369); i += 2) { + res = res ? res : dsdr_drp_reg_wr(d->base.dev, 0, mode[i + 0], mode[i + 1]); + res = res ? res : dsdr_drp_reg_wr(d->base.dev, 1, mode[i + 0], mode[i + 1]); + } + return res; +} + +enum jesd_special_flags { + MODE_JESD204C = 0, + MODE_JESD204B = 2, + + // MODE_JESD_DUAL_QUAD = 4, + + // AFE_COMPAT_7900 = 1 << 8, + AFE_COMPAT_7901 = 1 << 9, + // AFE_COMPAT_7903 = 1 << 10, + AFE_COMPAT_7950 = 1 << 11, + + FPGA_COMPAT_4X_4X = 1 << 16, + FPGA_COMPAT_8X_4X = 1 << 17, + FPGA_COMPAT_8X_8X = 1 << 18, +}; + +struct jesd_config +{ + unsigned flags; + unsigned afe_jesd_rate; + + unsigned logic_chcnt_rx; + unsigned logic_chcnt_tx; + unsigned hw_chcnt_rx; + unsigned hw_chcnt_tx; + unsigned hw_fpga_jesd_tx_en; + unsigned hw_fpga_jesd_rx_en; + + const channel_map_info_t *rx_chmap; + const channel_map_info_t *tx_chmap; + const channel_logic_dsp_wire_t* rx_lchan; + const channel_logic_dsp_wire_t* tx_lchan; + + const char* config_name; + const char* config_rev_0x20; // Configuration file for 2.0 chip + const char* config_rev_0x13; // Configuration file for 1.3 chip + +}; + +struct jesd_config s_hwjesd_config[] = { + { MODE_JESD204C | AFE_COMPAT_7901 | AFE_COMPAT_7950 | FPGA_COMPAT_4X_4X | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, + RATE_491_52, 4, 4, 4, 4, 0x0f, 0x0f, s_dsdr_chmap_s_nco, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco, s_dsdr_lmap_s_nco, "4RX_4TX_491.52", "Afe79xxPg1_6664_491_4x1_4x1_20.txt", "Afe79xxPg1_6664_491_4x1_4x1_13.txt" }, + // "Afe79xxPg1_6664_491.txt", "Afe79xxPg1_6664_491_7950.txt" }, + + { MODE_JESD204C | AFE_COMPAT_7901 | AFE_COMPAT_7950 | FPGA_COMPAT_8X_8X, + RATE_368_64, 8, 8, 4, 4, 0xff, 0xff, s_dsdr_chmap_d_nco, s_dsdr_chmap_d_nco, s_dsdr_lmap_d_nco, s_dsdr_lmap_d_nco, "8RX_8TX_368.64", "Afe79xxPg1_6664_368_4x2_4x2_20.txt", "Afe79xxPg1_6664_368_4x2_4x2_13.txt" }, + //"Afe79xxPg1_6664_369_D.txt", NULL }, + + { MODE_JESD204C | AFE_COMPAT_7901 | AFE_COMPAT_7950 | FPGA_COMPAT_8X_8X | FPGA_COMPAT_8X_4X, + RATE_368_64, 8, 4, 4, 4, 0xff, 0x0f, s_dsdr_chmap_d_nco, s_dsdr_chmap_s_nco, s_dsdr_lmap_d_nco, s_dsdr_lmap_s_nco, "8RX_4TX_368.64", "Afe79xxPg1_6664_368_4x2_4x1_20.txt", "Afe79xxPg1_6664_368_4x2_4x1_13.txt" }, + //"Afe79xxPg1_6664_369_D.txt", NULL }, + + + { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, + RATE_491_52, 8, 4, 6, 4, 0xff, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_nco, "4RX_4TX_2FB_491.52", "Afe79xxPg1_6664_491_6x1_4x1_20.txt", "Afe79xxPg1_6664_491_6x1_4x1_13.txt" }, + //RATE_491_52, 6, 4, 6, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_nco, "4RX_4TX_2FB_491.52", NULL, "Afe79xxPg1_6664_2FB_491_7950.txt" }, + + { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, + RATE_368_64, 6, 4, 4, 4, 0xff, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_368.64", "Afe79xxPg1_6664_368_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_368_6x1FBRX_4x1_13.txt" }, + + { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, + RATE_491_52, 8, 4, 6, 4, 0xff, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_491.52", "Afe79xxPg1_6664_491_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_491_6x1FBRX_4x1_13.txt" }, + +}; + + static int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** devparam, const char** devval) { @@ -1592,14 +1872,22 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** int res = 0; uint32_t hwid, usr2, pg, los, devid, jesdv; unsigned afeType = 0; + const char* usr_config = NULL; + + for (unsigned i = 0; i < pcount; i++) { + if (strcmp(devparam[i], "afe_profile") == 0) { + usr_config = devval[i]; + } + } + if (usr_config == NULL) { + usr_config = getenv("AFE_PROFILE"); + } d->subdev = 0; d->dsdr_state = STATE_IDLE; - d->hw_mask_rx = 0xf; // RX_3 RX_2 RX_1 RX_0 - d->hw_mask_tx = 0xf; // TX_3 TX_2 TX_1 TX_0 - d->hw_fpga_jesd_rx_en = 0xf; - d->hw_fpga_jesd_tx_en = 0xf; + //d->hw_mask_rx = 0xf; // RX_3 RX_2 RX_1 RX_0 + //d->hw_mask_tx = 0xf; // TX_3 TX_2 TX_1 TX_0 res = res ? res : dev_gpi_get32(dev, IGPI_USR_ACCESS2, &usr2); res = res ? res : dev_gpi_get32(dev, IGPI_HWID, &hwid); @@ -1615,26 +1903,163 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : dev_gpo_set(dev, IGPO_TX_AFETDD, 0x0); res = res ? res : dev_gpo_set(dev, IGPO_RX_AFETDD, 0x0); + if (res) + return res; // TODO check for AFE7903 - if (getenv("DSDR_AFE7903")) { - d->hw_mask_rx = 0x5; // RX_3 RX_1 - d->hw_mask_tx = 0xA; // TX_4 TX_2 - } + //if (getenv("DSDR_AFE7903")) { + // d->hw_mask_rx = 0x5; // RX_3 RX_1 + // d->hw_mask_tx = 0xA; // TX_4 TX_2 + //} devid = (hwid >> 16) & 0xff; jesdv = (hwid >> 8) & 0xff; bool dpump_afe_clk = false; - bool jesd_x8 = false; if (jesdv & 0x08) { dpump_afe_clk = true; jesdv ^= 0x08; } + bool gt_is_gty = false; + if (jesdv & 0x04) { + gt_is_gty = true; + jesdv ^= 0x04; + } + + switch (devid) { + case DSDR_KCU116_EVM: + case DSDR_M2_R0: + case DSDR_M2_R1: + case DSDR_PCIE_HIPER_R0: + d->type = devid; + break; + + default: + USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported HWID = %08x, skipping initialization!\n", hwid); + return -EIO; + } + + if (getenv("DSDR_M2_R0")) { + d->type = DSDR_M2_R0; + } + + d->cfg_rx_lanemap = 0x76543210; + d->cfg_tx_lanemap = 0x76543210; + + unsigned master_rate; + unsigned dsp_rx_chans; + unsigned dsp_tx_chans; + bool gt_dyn = false; + const char* default_config; + bool jesd_204c_mode = true; + unsigned chip_rev = 0x20; //Default chip revision + + switch (jesdv) { + case JESD_MODE_4X_4X_491: dsp_rx_chans = 4; dsp_tx_chans = 4; default_config = "4RX_4TX_491.52"; master_rate = 491520000; break; + case JESD_MODE_4X_4X_DYN: dsp_rx_chans = 4; dsp_tx_chans = 4; default_config = "4RX_4TX_491.52"; master_rate = 0; gt_dyn = true; break; + case JESD_MODE_8X_4X_DYN: dsp_rx_chans = 8; dsp_tx_chans = 4; default_config = "4RX_4TX_491.52"; master_rate = 0; gt_dyn = true; break; + case JESD_MODE_8X_8X_DYN: dsp_rx_chans = 8; dsp_tx_chans = 8; default_config = "4RX_4TX_491.52"; master_rate = 0; gt_dyn = true; break; + default: + USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported JESD - DSP configuration: %08x!\n", jesdv); + return -EIO; + } + + if (usr_config == NULL) { + usr_config = default_config; + } + unsigned cfg_idx = ~0U; + for (unsigned i = 0; i < SIZEOF_ARRAY(s_hwjesd_config); i++) { + if (strcmp(s_hwjesd_config[i].config_name, usr_config) == 0) { + bool cfg_mode_204c = (s_hwjesd_config[i].flags & MODE_JESD204B) ? false : true; + if (jesd_204c_mode != cfg_mode_204c) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration `%s` JESD204%c != HW JESD204%c!\n", + s_hwjesd_config[i].config_name, cfg_mode_204c ? 'C' : 'B', jesd_204c_mode ? 'C' : 'B'); + return -EINVAL; + } + + if (master_rate != 0 && master_rate != s_hwjesd_config[i].afe_jesd_rate) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration `%s` rate mismatch %d != HW %d!\n", + s_hwjesd_config[i].config_name, s_hwjesd_config[i].afe_jesd_rate, master_rate); + return -EINVAL; + } + + if (s_hwjesd_config[i].logic_chcnt_rx > dsp_rx_chans || s_hwjesd_config[i].logic_chcnt_tx > dsp_tx_chans) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration `%s` insuficcient DSP chains in firmware: RXx%d TXx%d, required %d %d!\n", + s_hwjesd_config[i].config_name, dsp_rx_chans, dsp_tx_chans, s_hwjesd_config[i].logic_chcnt_rx, s_hwjesd_config[i].logic_chcnt_tx); + return -EINVAL; + } + + cfg_idx = i; + break; + } + } + + if (cfg_idx == ~0U) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration `%s` not found!\n", usr_config); + return -EINVAL; + } + + master_rate = s_hwjesd_config[cfg_idx].afe_jesd_rate; + + d->rx_chmap_info = s_hwjesd_config[cfg_idx].rx_chmap; + d->tx_chmap_info = s_hwjesd_config[cfg_idx].tx_chmap; + d->rx_lmap_info = s_hwjesd_config[cfg_idx].rx_lchan; + d->tx_lmap_info = s_hwjesd_config[cfg_idx].tx_lchan; + + d->logic_chcnt_rx = s_hwjesd_config[cfg_idx].logic_chcnt_rx; + d->logic_chcnt_tx = s_hwjesd_config[cfg_idx].logic_chcnt_tx; + d->hw_chcnt_rx = s_hwjesd_config[cfg_idx].hw_chcnt_rx; + d->hw_chcnt_tx = s_hwjesd_config[cfg_idx].hw_chcnt_tx; + d->hw_fpga_jesd_rx_en = s_hwjesd_config[cfg_idx].hw_fpga_jesd_rx_en; + d->hw_fpga_jesd_tx_en = s_hwjesd_config[cfg_idx].hw_fpga_jesd_tx_en; + + d->dac_rate = d->adc_rate = master_rate; + d->max_rate = master_rate * 1.15; + + d->dsp_rx_chans = dsp_rx_chans; + d->dsp_tx_chans = dsp_tx_chans; + + d->jesd_x8 = (dsp_rx_chans > 4) || (dsp_tx_chans > 4); + + // TODO Proper AFE revision detection + afeType = 7901; + + // Fixup for 7903 + if (getenv("DSDR_AFE7903")) { + // RX C/A + // TX D/B + afeType = 7903; + } + if (getenv("DSDR_M2_7950")) { + afeType = 7950; + chip_rev = 0x13; + } + + d->afecongiguration = (chip_rev == 0x20) ? s_hwjesd_config[cfg_idx].config_rev_0x20 : s_hwjesd_config[cfg_idx].config_rev_0x13; + if (!d->afecongiguration) { + USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration `%s` File not defined for chirev %02x!\n", s_hwjesd_config[cfg_idx].config_name, chip_rev); + return -EINVAL; + } + + if (gt_dyn) { + if (!gt_is_gty) { + res = res ? res : dsdr_gth_set_rate(d, master_rate); + } else { + USDR_LOG("XDEV", USDR_LOG_ERROR, "GTY reconfiguration isn't supported yet!\n"); + return -EINVAL; + } + } + if (res) + return res; + + USDR_LOG("XDEV", USDR_LOG_INFO, "DSP_RX=%d DSP_TX=%d AFE=%d Configuration `%s` RATE=%.2f == FILE:`%s`\n", + dsp_rx_chans, dsp_tx_chans, afeType, s_hwjesd_config[cfg_idx].config_name, master_rate / 1.0e6, d->afecongiguration); + + +#if 0 + const bool oveeride_m_369 = true; + dsdr_gth_set_rate(d, oveeride_m_369); + jesd_cfg = oveeride_m_369 ? JESD_MODE_8X_8X_369 : JESD_MODE_8X_4X_491; - unsigned master_rate = 491520000; - unsigned maxusr_rate = 520000000; - unsigned jesd_cfg = (jesdv >> 4); - jesdv &= 0x0f; switch (jesd_cfg) { case JESD_MODE_4X_4X_491: @@ -1681,6 +2106,9 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->hw_fpga_jesd_rx_en = 0x3f; jesd_x8 = true; + + d->hw_fpga_jesd_tx_en = 0x0f; //Fixup for incorrect config + d->hw_fpga_jesd_rx_en = 0x0f; //Fixup for incorrect config break; default: @@ -1690,32 +2118,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->jesd_x8 = jesd_x8; - switch (devid) { - case DSDR_KCU116_EVM: - case DSDR_M2_R0: - case DSDR_M2_R1: - case DSDR_PCIE_HIPER_R0: - d->type = devid; - break; - - default: - USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported HWID = %08x, skipping initialization!\n", hwid); - return -EIO; - } - - // - if (getenv("DSDR_M2_R0")) { - d->type = DSDR_M2_R0; - } - - d->cfg_rx_lanemap = 0x76543210; - d->cfg_tx_lanemap = 0x76543210; - - for (unsigned h = 0; h < MAX_LOGIC_CHANS; h++) { - d->hw_rxch_route[h] = h; - d->hw_txch_route[h] = h; - } - afeType = 7901; switch (jesdv) { case DSDR_JESD204B_810_245: @@ -1740,6 +2142,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->afecongiguration = "Afe79xxPg1_6664_369_D.txt"; } else if (jesd_x8 == true && master_rate == 491520000) { d->afecongiguration = "Afe79xxPg1_6664_491_fb3.txt"; + + d->afecongiguration = "Afe79xxPg1_6664_491.txt"; } if (d->hw_mask_rx == 0x5 && d->hw_mask_tx == 0xA) { @@ -1794,11 +2198,16 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** return -EIO; } + + gthcommon_init(d); + d->cfg_afe_type = afeType; d->jesdv = jesdv; USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s, Type: %d, AFE: %d, JESD204%c, CH_TX=%02x, CH_RX=%02x JESDx%d", d->afecongiguration, d->type, d->cfg_afe_type, (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx, jesd_x8 ? 8 : 4); +#endif + if (getenv("SKIPAFE")) { d->type = DSDR_KCU116_EVM; @@ -2047,6 +2456,8 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : usdr_jesd204b_bringup_post(d); } + d->st.libcapi79xx_set_tdd(&d->st.capi, 0xf, 0x3, 0xf); + if (d->type == DSDR_PCIE_HIPER_R0) { unsigned override = 0; unsigned* poverride = NULL; @@ -2322,7 +2733,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char usleep(1000); res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_RST, 0x0); - res = (res) ? res : create_sfetrx4_stream(dev, (d->logic_chcnt_rx == 8 || d->logic_chcnt_rx == 6) ? CORE_EXFERX_DMA32_R0_8 : CORE_EXFERX_DMA32_R0, + res = (res) ? res : create_sfetrx4_stream(dev, (d->dsp_rx_chans == 8) ? CORE_EXFERX_DMA32_R0_8 : CORE_EXFERX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &hwchs); @@ -2398,7 +2809,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char usleep(1000); res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSPCHAIN_TX_RST, 0x0); - res = (res) ? res : create_sfetrx4_stream(dev, (d->logic_chcnt_tx == 8) ? CORE_EXFETX_DMA32_R0_8 : CORE_EXFETX_DMA32_R0, + res = (res) ? res : create_sfetrx4_stream(dev, (d->dsp_tx_chans == 8) ? CORE_EXFETX_DMA32_R0_8 : CORE_EXFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, flags | DMS_DONT_CHECK_FWID, M2PCI_REG_WR_TXDMA_CFG0, @@ -2494,8 +2905,8 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) d->hw_enabled_tx = 0; d->hw_enabled_rx = 0; - d->hw_mask_tx = 0; - d->hw_mask_rx = 0; + //d->hw_mask_tx = 0; + //d->hw_mask_rx = 0; d->logic_enabled_rx = 0; d->logic_enabled_tx = 0; From 064f86b7acd1466c0b4aebbfe74ca4aac64de7a4 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 18 Dec 2025 01:19:22 +0400 Subject: [PATCH 271/397] fix dsdr --- src/lib/device/m2_dsdr/m2_dsdr.c | 366 ++++++++++++++++++++++++++++++- 1 file changed, 354 insertions(+), 12 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 3b6ae33a..0205ea54 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -775,7 +775,302 @@ static const uint16_t s_gth_usp_regs[] = { 0x00B0, }; -#define MAKE_DSDR_DRP_CMD(wr, idx, addr, data) ((((wr) & 1) << 28) | (((idx) ? 2 : 1) << 29) | (((addr) & 0xfff) << 16) | ((data) & 0xffff)) +static const uint16_t s_gth_usp_chan_regs[] = { + 0x0002, + 0x0003, + 0x0004, + 0x0005, + 0x0006, + 0x0009, + 0x000B, + 0x000C, + 0x000E, + 0x000F, + 0x0010, + 0x0011, + 0x0012, + 0x0013, + 0x0014, + 0x0015, + 0x0016, + 0x0017, + 0x0018, + 0x0019, + 0x001A, + 0x001B, + 0x001C, + 0x001D, + 0x001E, + 0x001F, + 0x0020, + 0x0021, + 0x0022, + 0x0023, + 0x0024, + 0x0025, + 0x0026, + 0x0027, + 0x0028, + 0x0029, + 0x002A, + 0x002B, + 0x002C, + 0x002D, + 0x002E, + 0x002F, + 0x0030, + 0x0031, + 0x0032, + 0x0033, + 0x0034, + 0x0035, + 0x0036, + 0x0037, + 0x0038, + 0x0039, + 0x003A, + 0x003C, + 0x003D, + 0x003E, + 0x003F, + 0x0040, + 0x0041, + 0x0042, + 0x0043, + 0x0044, + 0x0045, + 0x0046, + 0x0047, + 0x0048, + 0x0049, + 0x004A, + 0x004B, + 0x004C, + 0x004D, + 0x004E, + 0x004F, + 0x0050, + 0x0052, + 0x0053, + 0x0054, + 0x0055, + 0x0056, + 0x0057, + 0x0058, + 0x0059, + 0x005A, + 0x005B, + 0x005C, + 0x005D, + 0x005E, + 0x005F, + 0x0060, + 0x0061, + 0x0062, + 0x0063, + 0x0064, + 0x0065, + 0x0066, + 0x0067, + 0x0068, + 0x0069, + 0x006A, + 0x006B, + 0x006C, + 0x006D, + 0x006E, + 0x006F, + 0x0070, + 0x0071, + 0x0072, + 0x0073, + 0x0074, + 0x0075, + 0x0076, + 0x0077, + 0x0078, + 0x0079, + 0x007A, + 0x007B, + 0x007C, + 0x007D, + 0x007E, + 0x007F, + 0x0080, + 0x0081, + 0x0082, + 0x0083, + 0x0084, + 0x0085, + 0x0089, + 0x008A, + 0x008B, + 0x008C, + 0x008D, + 0x008E, + 0x008F, + 0x0090, + 0x0091, + 0x0092, + 0x0093, + 0x0094, + 0x0095, + 0x0097, + 0x0098, + 0x0099, + 0x009A, + 0x009B, + 0x009C, + 0x009D, + 0x009E, + 0x009F, + 0x00A0, + 0x00A1, + 0x00A2, + 0x00A3, + 0x00A4, + 0x00A5, + 0x00A6, + 0x00A7, + 0x00A8, + 0x00A9, + 0x00AA, + 0x00AB, + 0x00AC, + 0x00AD, + 0x00AE, + 0x00AF, + 0x00B0, + 0x00B1, + 0x00B2, + 0x00B3, + 0x00B4, + 0x00B5, + 0x00B6, + 0x00B7, + 0x00B8, + 0x00B9, + 0x00BA, + 0x00BB, + 0x00BC, + 0x00BD, + 0x00BE, + 0x00BF, + 0x00C0, + 0x00C1, + 0x00C2, + 0x00C3, + 0x00C4, + 0x00C5, + 0x00C6, + 0x00C7, + 0x00C8, + 0x00CA, + 0x00CB, + 0x00CC, + 0x00CD, + 0x00CE, + 0x00CF, + 0x00D0, + 0x00D1, + 0x00D2, + 0x00D3, + 0x00D4, + 0x00D5, + 0x00D6, + 0x00D7, + 0x00D8, + 0x00D9, + 0x00DA, + 0x00DB, + 0x00DD, + 0x00DE, + 0x00DF, + 0x00E0, + 0x00E1, + 0x00E2, + 0x00E7, + 0x00E8, + 0x00E9, + 0x00EA, + 0x00EB, + 0x00EC, + 0x00ED, + 0x00EE, + 0x00EF, + 0x00F0, + 0x00F1, + 0x00F2, + 0x00F3, + 0x00F4, + 0x00F5, + 0x00F6, + 0x00F7, + 0x00F8, + 0x00F9, + 0x00FA, + 0x00FB, + 0x00FB, + 0x00FC, + 0x00FD, + 0x00FE, + 0x00FF, + 0x0100, + 0x0101, + 0x0102, + 0x0103, + 0x0105, + 0x0106, + 0x0108, + 0x0109, + 0x010A, + 0x010B, + 0x010C, + 0x010D, + 0x010E, + 0x0110, + 0x0111, + 0x0112, + 0x0113, + 0x0114, + 0x0115, + 0x0116, + 0x0117, + 0x0118, + 0x0119, + 0x011A, + 0x011B, + 0x011C, + 0x011D, + 0x011E, + 0x011F, + 0x0120, + 0x0121, + 0x0122, + 0x0123, + 0x0124, + 0x0125, + 0x0250, + 0x0251, + 0x0252, + 0x0253, + 0x0254, + 0x0255, + 0x0256, + 0x0257, + 0x0258, + 0x0259, + 0x025A, + 0x025B, + 0x025C, + 0x025D, + 0x025E, + 0x025F, + 0x0263, + 0x0269, +}; + + #define MAKE_DSDR_PHY_REG(addr, data) ((1<<31) | (((addr) & 0xff) << 16) | (((data) & 0xff))) // @@ -792,6 +1087,9 @@ static int dsdr_gth_control(lldev_t dev, uint16_t addr, uint16_t data) return res; } +#if 0 +#define MAKE_DSDR_DRP_CMD(wr, idx, addr, data) ((((wr) & 1) << 28) | (((idx) ? 2 : 1) << 29) | (((addr) & 0xfff) << 16) | ((data) & 0xffff)) + static int dsdr_drp_reg_wr(lldev_t dev, unsigned port, uint16_t addr, uint16_t data) { int res = 0; @@ -810,14 +1108,58 @@ static int dsdr_drp_reg_rd(lldev_t dev, unsigned port, uint16_t addr, uint16_t * *odata = val >> (port ? 16 : 0); return res; } +#endif + +#define MAKE_DSDR_DRP_CMD(wr, idx, addr, data) ((((wr) & 1) << 30) | (((idx) & 0xf) << 26) | (((addr) & 0x3ff) << 16) | ((data) & 0xffff)) + +//localparam DRP_SE_BIT = 31; +//localparam DRP_WR_BIT = 30; +//localparam DRP_CH_BIT = 29; +//localparam DRP_C2_BIT = 28; +//localparam DRP_C1_BIT = 27; +//localparam DRP_C0_BIT = 26; + +enum { + DRP_QPLL_IDX0 = 0, + DRP_QPLL_IDX1 = 1, + DRP_CHAN_IDX0 = 8, +}; + +static int dsdr_drp_reg_wr(lldev_t dev, unsigned port, uint16_t addr, uint16_t data) +{ + int res = 0; + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_DRP_CMD(1, port, addr, data)); + res = res ? res : usleep(10); + return res; +} + +static int dsdr_drp_reg_rd(lldev_t dev, unsigned port, uint16_t addr, uint16_t *odata) +{ + int res = 0; + uint32_t val = 0, j; + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_DRP_CMD(0, port, addr, 0)); + for (j = 0; j < 100; j++) { + res = res ? res : usleep(10); + res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &val); + if (!(val >> 31)) + break; + } + *odata = val; + return res; +} + int gthcommon_init(dev_m2_dsdr_t *d) { uint16_t val = 0; int res = 0; for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_usp_regs); i++) { - res = res ? res : dsdr_drp_reg_rd(d->base.dev, 0, s_gth_usp_regs[i], &val); - USDR_LOG("GTHC", USDR_LOG_WARNING, "GRP[%04x] => %04x\n", s_gth_usp_regs[i], val); + res = res ? res : dsdr_drp_reg_rd(d->base.dev, DRP_QPLL_IDX0, s_gth_usp_regs[i], &val); + USDR_LOG("GTHQ", USDR_LOG_WARNING, "GTQ[%04x] => %04x\n", s_gth_usp_regs[i], val); + } + for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_usp_chan_regs); i++) { + res = res ? res : dsdr_drp_reg_rd(d->base.dev, DRP_CHAN_IDX0, s_gth_usp_chan_regs[i], &val); + USDR_LOG("GTHC", USDR_LOG_WARNING, "GTC[%04x] => %04x\n", s_gth_usp_chan_regs[i], val); } return res; } @@ -1754,8 +2096,8 @@ static int usdr_jesd204b_bringup_post(struct dev_m2_dsdr *dd) res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 0); res = res ? res : usleep(10000); - res = res ? res : dsdr_gth_control(dev, GTH_CTR_RX_EN, dd->hw_fpga_jesd_rx_en); - res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, dd->hw_fpga_jesd_tx_en); + // res = res ? res : dsdr_gth_control(dev, GTH_CTR_RX_EN, dd->hw_fpga_jesd_rx_en); + // res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, dd->hw_fpga_jesd_tx_en); res = res ? res : dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); @@ -1792,8 +2134,8 @@ static int dsdr_gth_set_rate(struct dev_m2_dsdr *d, unsigned rate) } for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_qpll_ovrd_369); i += 2) { - res = res ? res : dsdr_drp_reg_wr(d->base.dev, 0, mode[i + 0], mode[i + 1]); - res = res ? res : dsdr_drp_reg_wr(d->base.dev, 1, mode[i + 0], mode[i + 1]); + res = res ? res : dsdr_drp_reg_wr(d->base.dev, DRP_QPLL_IDX0, mode[i + 0], mode[i + 1]); + res = res ? res : dsdr_drp_reg_wr(d->base.dev, DRP_QPLL_IDX1, mode[i + 0], mode[i + 1]); } return res; } @@ -1823,8 +2165,8 @@ struct jesd_config unsigned logic_chcnt_tx; unsigned hw_chcnt_rx; unsigned hw_chcnt_tx; - unsigned hw_fpga_jesd_tx_en; unsigned hw_fpga_jesd_rx_en; + unsigned hw_fpga_jesd_tx_en; const channel_map_info_t *rx_chmap; const channel_map_info_t *tx_chmap; @@ -1852,14 +2194,14 @@ struct jesd_config s_hwjesd_config[] = { { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, - RATE_491_52, 8, 4, 6, 4, 0xff, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_nco, "4RX_4TX_2FB_491.52", "Afe79xxPg1_6664_491_6x1_4x1_20.txt", "Afe79xxPg1_6664_491_6x1_4x1_13.txt" }, + RATE_491_52, 8, 4, 6, 4, 0x03f, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_nco, "4RX_4TX_2FB_491.52", "Afe79xxPg1_6664_491_6x1_4x1_20.txt", "Afe79xxPg1_6664_491_6x1_4x1_13.txt" }, //RATE_491_52, 6, 4, 6, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_nco, "4RX_4TX_2FB_491.52", NULL, "Afe79xxPg1_6664_2FB_491_7950.txt" }, { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, - RATE_368_64, 6, 4, 4, 4, 0xff, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_368.64", "Afe79xxPg1_6664_368_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_368_6x1FBRX_4x1_13.txt" }, + RATE_368_64, 8, 4, 4, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_368.64", "Afe79xxPg1_6664_368_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_368_6x1FBRX_4x1_13.txt" }, { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, - RATE_491_52, 8, 4, 6, 4, 0xff, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_491.52", "Afe79xxPg1_6664_491_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_491_6x1FBRX_4x1_13.txt" }, + RATE_491_52, 8, 4, 4, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_491.52", "Afe79xxPg1_6664_491_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_491_6x1FBRX_4x1_13.txt" }, }; @@ -2752,7 +3094,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char } // TODO: set actual antenna mask - res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0xf); + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0x3f); // d->hw_enabled_rx //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0x0); *out_handle = d->rx; From 02a33f271cd23d486723b66dc87eab1e41970742 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 19 Dec 2025 19:39:58 +0400 Subject: [PATCH 272/397] xsdp: add relative REF field to compare algos --- src/lib/xdsp/utests/conv_4cf32_ci12_utest.c | 4 ++-- src/lib/xdsp/utests/conv_ci12_4cf32_utest.c | 14 ++++++++------ src/lib/xdsp/utests/conv_ci16_4cf32_utest.c | 8 +++++--- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c index b421f577..3bdfde40 100644 --- a/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c +++ b/src/lib/xdsp/utests/conv_4cf32_ci12_utest.c @@ -18,7 +18,7 @@ #define CONV_SCALE (1.0f/32767) #define EPS (5E-4) -static const unsigned packet_lens[3] = { 1111u, 4123u, PACKET_SIZE }; +static const unsigned packet_lens[4] = { 1111u, 4123u, PACKET_SIZE, 262144u }; #define SPEED_MEASURE_ITERS 1000000 @@ -241,7 +241,7 @@ Suite * conv_4cf32_ci12_suite(void) Suite* s = suite_create("conv_4cf32_ci12"); ADD_REGRESS_TEST(s, conv_4cf32_ci12_check_simd); - ADD_PERF_LOOP_TEST(s, conv_4cf32_ci12_speed, 60, 0, 3); + ADD_PERF_LOOP_TEST(s, conv_4cf32_ci12_speed, 60, 0, 4); return s; } diff --git a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c index f7a948f2..dcb8f3ac 100644 --- a/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci12_4cf32_utest.c @@ -15,10 +15,10 @@ #define WORD_COUNT (32u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * 12u / 8u) -#define SPEED_WORD_COUNT (8192u) +#define SPEED_WORD_COUNT (65536u) #define SPEED_SIZE_BZ (SPEED_WORD_COUNT * 12u / 8u) -static const unsigned packet_lens[3] = { 1235, 7777, SPEED_SIZE_BZ }; +static const unsigned packet_lens[4] = { 1235, 7777, 12288, SPEED_SIZE_BZ }; #define SPEED_MEASURE_ITERS 1000000 @@ -60,7 +60,7 @@ static void setup() uint8_t *pin = (uint8_t*)in; - for(int16_t i = SPEED_WORD_COUNT, j = SPEED_SIZE_BZ; i ; i -= 2, j -= 3) + for(int32_t i = SPEED_WORD_COUNT, j = SPEED_SIZE_BZ; i ; i -= 2, j -= 3) { int16_t v0 = i - 1; int16_t v1 = i - 2; @@ -207,8 +207,10 @@ START_TEST(conv_ci12_4cf32_speed) uint64_t tk = clock_get_time(); for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); uint64_t tk1 = clock_get_time() - tk; - fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", - tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + double ref = 1e6 * tk1 / SPEED_MEASURE_ITERS / (bzin * 8 / 3); + + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s REF=%.3f\n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1), ref); } } } @@ -222,7 +224,7 @@ Suite * conv_ci12_4cf32_suite(void) ADD_REGRESS_TEST(s, conv_ci12_4cf32_check); ADD_REGRESS_TEST(s, conv_ci12_4cf32_check_simd); - ADD_PERF_LOOP_TEST(s, conv_ci12_4cf32_speed, 60, 0, 3); + ADD_PERF_LOOP_TEST(s, conv_ci12_4cf32_speed, 60, 0, 4); return s; } diff --git a/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c index 3d9a264f..dcb621ec 100644 --- a/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c +++ b/src/lib/xdsp/utests/conv_ci16_4cf32_utest.c @@ -15,7 +15,7 @@ #define WORD_COUNT (4096u + 80u) #define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) -#define SPEED_WORD_COUNT (32768u) +#define SPEED_WORD_COUNT (65536u) #define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) static const unsigned packet_lens[3] = { 1024, 16384, SPEED_SIZE_BZ }; @@ -177,8 +177,10 @@ START_TEST(conv_ci16_4cf32_speed) uint64_t tk = clock_get_time(); for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); uint64_t tk1 = clock_get_time() - tk; - fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", - tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + double ref = 1e6 * tk1 / SPEED_MEASURE_ITERS / (bzin * 2); + + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s REF=%.3f\n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1), ref); } } } From f4acf000483ba8cffc3c368febaf0e9404fd64dc Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 19 Dec 2025 19:43:07 +0400 Subject: [PATCH 273/397] sfe_erx: fix 3/6-way transormation --- src/lib/ipblks/streams/sfe_rx_4.c | 40 ++++++++++++++++--- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 2 +- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/lib/ipblks/streams/sfe_rx_4.c b/src/lib/ipblks/streams/sfe_rx_4.c index 901c9938..48ebf9a3 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.c +++ b/src/lib/ipblks/streams/sfe_rx_4.c @@ -3,6 +3,7 @@ #include "sfe_rx_4.h" #include +#include "stream_sfetrx4_dma32.h" enum sfe_rx_regs { FE_CMD_REG_ROUTE, @@ -602,6 +603,7 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, memset(ch_remapped, 0, sizeof(ch_remapped)); memset(flag_swap_iq, 0, sizeof(flag_swap_iq)); channel_info_t pack_3x16_mmap; + channel_info_t reverse_map; unsigned lg_chans = (fe->cfg_raw_chans == 16) ? 4 : (fe->cfg_raw_chans == 8) ? 3 : (fe->cfg_raw_chans == 4) ? 2 : (fe->cfg_raw_chans == 2) ? 1 : 0; unsigned msk = mask ? ((complex ? total_chan_num / 2 : total_chan_num) - 1) : 0xff; @@ -610,26 +612,54 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, for (unsigned g = 0, h = 0; g < fe->cfg_raw_chans; g++) { if (complex) { if ((g % 4) == 3) { - pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h + (g % 4) - 4]; + pack_3x16_mmap.ch_map[g] = 0xff; //newmap_orig->ch_map[h + (g % 4) - h]; } else { pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h++]; } } else { if ((g % 8) == 6 || (g % 8) == 7) { - pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h + (g % 8) - 8]; + pack_3x16_mmap.ch_map[g] = 0xff; //newmap_orig->ch_map[h + (g % 8) - 8]; } else { pack_3x16_mmap.ch_map[g] = newmap_orig->ch_map[h++]; } } } + } + const channel_info_t* newmap = (pack_3x16) ? &pack_3x16_mmap : newmap_orig; + + // For TX we need invert in and out + if (fe->cfg_fecore_id == CORE_EXFETX_DMA32_R0 || fe->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { + memset(reverse_map.ch_map, ~CH_SWAP_IQ_FLAG, sizeof(reverse_map.ch_map)); + + for (unsigned g = 0; g < fe->cfg_raw_chans; g++) { + if (newmap->ch_map[g] == 0xff) + continue; + + unsigned idx = (newmap->ch_map[g] & ~CH_SWAP_IQ_FLAG); + if (idx >= fe->cfg_raw_chans) + return -EINVAL; + + reverse_map.ch_map[idx] = g; + } for (unsigned g = 0; g < fe->cfg_raw_chans; g++) { - USDR_LOG("STRM", USDR_LOG_INFO, "3x16_MAP[%d]: %d => %d\n", g, - newmap_orig->ch_map[g], pack_3x16_mmap.ch_map[g]); + if (newmap->ch_map[g] == 0xff) + continue; + + if (newmap->ch_map[g] & CH_SWAP_IQ_FLAG) { + reverse_map.ch_map[g] |= CH_SWAP_IQ_FLAG; + } } + + newmap = &reverse_map; } - const channel_info_t* newmap = (pack_3x16) ? &pack_3x16_mmap : newmap_orig; + + USDR_LOG("STRM", USDR_LOG_INFO, "NEW_MAP %d x %d CHANS:\n", total_chan_num, complex ? 2 : 1); + for (unsigned g = 0; g < fe->cfg_raw_chans; g++) { + USDR_LOG("STRM", USDR_LOG_INFO, "NEW_MAP[%d]: %d => %d\n", g, + newmap_orig->ch_map[g], newmap->ch_map[g]); + } for (unsigned g = 0; g < fe->cfg_raw_chans; g = g + total_chan_num) { for (unsigned f = 0; f < total_chan_num; f++) { diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index f0f8450b..e31f3a60 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -602,7 +602,7 @@ int _sfetrx4_option_set(stream_handle_t* str, const char* name, int64_t in_val) stream->type == USDR_ZCPY_TX, stream->fe_complex, stream->pack_3x16, - (stream->fe_complex ? 2 : 1) * stream->fe_chans, + (stream->fe_complex ? 2 : 1) * (stream->pack_3x16 ? (stream->fe_chans * 4 / 3) : stream->fe_chans), (const channel_info_t *)in_val); } else if (stream->type == USDR_ZCPY_TX && (strcmp(name, "mute") == 0)) { if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_8) { From 76b32b9bca01aeab5ca1c4cd7c29f056656f2de5 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 19 Dec 2025 20:32:57 +0400 Subject: [PATCH 274/397] dsdr: refactor AFE profiles --- src/lib/device/m2_dsdr/m2_dsdr.c | 972 +++++++++---------------------- 1 file changed, 275 insertions(+), 697 deletions(-) diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 0205ea54..fe672e7b 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -7,8 +7,7 @@ #include #include -#include - +#include #include "../device.h" #include "../device_vfs.h" @@ -498,7 +497,7 @@ enum DSDR_STATE { // 8: FB AB0 // 9: FB CD0 -static unsigned make_afe79xx_dsp_index(enum nco_type nco, unsigned idx, unsigned band) +static unsigned make_afe79xx_dspidx(enum nco_type nco, unsigned idx, unsigned band) { switch (nco) { case NCO_TX: @@ -515,6 +514,11 @@ static unsigned make_afe79xx_dsp_index(enum nco_type nco, unsigned idx, unsigned #define GET_HWTX_TYPE(x) NCO_TX #define GET_HWTX_IDX(x) (x) +enum { + MAX_DSP_NCO_RX = 10, + MAX_DSP_NCO_TX = 8, +}; + struct channel_logic_dsp_wire { uint8_t dsp_type; // DSP NCO chain type uint8_t dsp_idx; // DSP NCO chain index @@ -523,45 +527,34 @@ struct channel_logic_dsp_wire { }; typedef struct channel_logic_dsp_wire channel_logic_dsp_wire_t; -static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco[] = { +static unsigned make_afe79xx_idx_from_dsp_wire(const channel_logic_dsp_wire_t* w) +{ + return make_afe79xx_dspidx((enum nco_type)w->dsp_type, w->dsp_idx, w->dsp_band); +} + +static const channel_logic_dsp_wire_t s_dsdr_lmap_s_ncorx[] = { { NCO_RX, 0, 0, 0 }, { NCO_RX, 1, 0, 1 }, { NCO_RX, 2, 0, 2 }, { NCO_RX, 3, 0, 3 }, }; -static const channel_map_info_t s_dsdr_chmap_s_nco[] = { - { "a", 0 }, - { "b", 1 }, - { "c", 2 }, - { "d", 3 }, - { NULL, CH_NULL }, -}; - -static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco_fbrx[] = { - { NCO_RX, 0, 0, 0 }, - { NCO_RX, 1, 0, 1 }, - { NCO_RX, 2, 0, 2 }, - { NCO_RX, 3, 0, 3 }, - { NCO_FB, 0, 0, 0 }, - { NCO_FB, 1, 0, 2 }, - { NCO_FB, 0, 0, 0 }, - { NCO_FB, 1, 0, 2 }, +static const channel_logic_dsp_wire_t s_dsdr_lmap_s_ncotx[] = { + { NCO_TX, 0, 0, 0 }, + { NCO_TX, 1, 0, 1 }, + { NCO_TX, 2, 0, 2 }, + { NCO_TX, 3, 0, 3 }, }; -static const channel_map_info_t s_dsdr_chmap_s_nco_rxfb[] = { +static const channel_map_info_t s_dsdr_chmap_s_nco[] = { { "a", 0 }, { "b", 1 }, { "c", 2 }, { "d", 3 }, - { "a1", 4 }, - { "c1", 5 }, - { "a2", 6 }, - { "c2", 7 }, { NULL, CH_NULL }, - }; +}; -static const channel_logic_dsp_wire_t s_dsdr_lmap_d_nco[] = { +static const channel_logic_dsp_wire_t s_dsdr_lmap_d_ncorx[] = { { NCO_RX, 0, 0, 0 }, { NCO_RX, 1, 0, 1 }, { NCO_RX, 2, 0, 2 }, @@ -571,6 +564,18 @@ static const channel_logic_dsp_wire_t s_dsdr_lmap_d_nco[] = { { NCO_RX, 2, 1, 2 }, { NCO_RX, 3, 1, 3 }, }; +static const channel_logic_dsp_wire_t s_dsdr_lmap_d_ncotx[] = { + { NCO_TX, 0, 0, 0 }, + { NCO_TX, 1, 0, 1 }, + { NCO_TX, 2, 0, 2 }, + { NCO_TX, 3, 0, 3 }, + { NCO_TX, 0, 1, 0 }, + { NCO_TX, 1, 1, 1 }, + { NCO_TX, 2, 1, 2 }, + { NCO_TX, 3, 1, 3 }, + }; + + static const channel_map_info_t s_dsdr_chmap_d_nco[] = { { "a0", 0 }, { "b0", 1 }, @@ -606,6 +611,31 @@ static const channel_map_info_t s_dsdr_chmap_s_nco_fb[] = { { NULL, CH_NULL }, }; + +static const channel_logic_dsp_wire_t s_dsdr_lmap_s_nco_fbrx[] = { + { NCO_RX, 0, 0, 0 }, + { NCO_RX, 1, 0, 1 }, + { NCO_RX, 2, 0, 2 }, + { NCO_RX, 3, 0, 3 }, + { NCO_FB, 0, 0, 0 }, + { NCO_FB, 1, 0, 2 }, + { NCO_FB, 0, 0, 0 }, + { NCO_FB, 1, 0, 2 }, +}; +static const channel_map_info_t s_dsdr_chmap_s_nco_fbrx[] = { + { "a", 0 }, + { "b", 1 }, + { "c", 2 }, + { "d", 3 }, + { "a0", 4 }, + { "c0", 5 }, + { "a2", 6 }, + { "c2", 7 }, + + { NULL, CH_NULL }, +}; + + struct dev_m2_dsdr { device_t base; @@ -667,15 +697,19 @@ struct dev_m2_dsdr { uint8_t rx_ordinal_to_logic[MAX_LOGIC_CHANS]; uint8_t tx_ordinal_to_logic[MAX_LOGIC_CHANS]; + uint8_t rx_logic_to_ordinal[MAX_LOGIC_CHANS]; + uint8_t tx_logic_to_ordinal[MAX_LOGIC_CHANS]; + + // Configuration parameters opt_u64_t rx_ord_freqs[MAX_LOGIC_CHANS]; opt_u64_t tx_ord_freqs[MAX_LOGIC_CHANS]; - // For proper FE configuration in dual-band DSP configuration indexed by hwidx, band_no - opt_u64_t rx_bxfc[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; - opt_u64_t tx_bxfc[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; - opt_u64_t rx_raw_nco[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; - opt_u64_t tx_raw_nco[MAX_HIPER_FE_PORT][MAX_PORT_BANDS]; + opt_u64_t rx_bxfc[MAX_DSP_NCO_RX]; + opt_u64_t tx_bxfc[MAX_DSP_NCO_TX]; + opt_u64_t rx_raw_nco[MAX_DSP_NCO_RX]; + opt_u64_t tx_raw_nco[MAX_DSP_NCO_TX]; + opt_u64_t fb_raw_nco[2]; channel_info_t rx_chans; @@ -684,8 +718,6 @@ struct dev_m2_dsdr { }; typedef struct dev_m2_dsdr dev_m2_dsdr_t; - - enum dev_gpo { IGPO_BANK_LEDS = 0, IGPO_PWR_LMK = 1, @@ -708,366 +740,33 @@ static int dev_gpi_get32(lldev_t dev, unsigned bank, unsigned* data) } // GTH USP ALL REGS MAP -static const uint16_t s_gth_usp_regs[] = { - 0x0008, - 0x0009, - 0x000D, - 0x000E, - 0x0010, - 0x0011, - 0x0012, - 0x0013, - 0x0014, - 0x0015, - 0x0016, - 0x0018, - 0x0019, - 0x001A, - 0x001B, - 0x001C, - 0x001D, - 0x001E, - 0x001F, - 0x0020, - 0x0021, - 0x0022, - 0x0023, - 0x0024, - 0x0025, - 0x0029, - 0x002D, - 0x0030, - 0x0081, - 0x0082, - 0x0083, - 0x0084, - 0x0086, - 0x0088, - 0x0089, - 0x008B, - 0x008D, - 0x008E, - 0x008F, - 0x0090, - 0x0091, - 0x0092, - 0x0093, - 0x0094, - 0x0095, - 0x0096, - 0x0098, - 0x0099, - 0x009A, - 0x009B, - 0x009C, - 0x009D, - 0x009E, - 0x009F, - 0x00A0, - 0x00A1, - 0x00A2, - 0x00A3, - 0x00A4, - 0x00A5, - 0x00A8, - 0x00A9, - 0x00AD, - 0x00B0, +static const uint16_t s_gth_usp_qpll_regs[] = { + 0x008, 0x009, 0x00D, 0x00E, 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, 0x016, 0x018, 0x019, 0x01A, 0x01B, 0x01C, + 0x01D, 0x01E, 0x01F, 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x029, 0x02D, 0x030, 0x081, 0x082, 0x083, 0x084, + 0x086, 0x088, 0x089, 0x08B, 0x08D, 0x08E, 0x08F, 0x090, 0x091, 0x092, 0x093, 0x094, 0x095, 0x096, 0x098, 0x099, + 0x09A, 0x09B, 0x09C, 0x09D, 0x09E, 0x09F, 0x0A0, 0x0A1, 0x0A2, 0x0A3, 0x0A4, 0x0A5, 0x0A8, 0x0A9, 0x0AD, 0x0B0, }; static const uint16_t s_gth_usp_chan_regs[] = { - 0x0002, - 0x0003, - 0x0004, - 0x0005, - 0x0006, - 0x0009, - 0x000B, - 0x000C, - 0x000E, - 0x000F, - 0x0010, - 0x0011, - 0x0012, - 0x0013, - 0x0014, - 0x0015, - 0x0016, - 0x0017, - 0x0018, - 0x0019, - 0x001A, - 0x001B, - 0x001C, - 0x001D, - 0x001E, - 0x001F, - 0x0020, - 0x0021, - 0x0022, - 0x0023, - 0x0024, - 0x0025, - 0x0026, - 0x0027, - 0x0028, - 0x0029, - 0x002A, - 0x002B, - 0x002C, - 0x002D, - 0x002E, - 0x002F, - 0x0030, - 0x0031, - 0x0032, - 0x0033, - 0x0034, - 0x0035, - 0x0036, - 0x0037, - 0x0038, - 0x0039, - 0x003A, - 0x003C, - 0x003D, - 0x003E, - 0x003F, - 0x0040, - 0x0041, - 0x0042, - 0x0043, - 0x0044, - 0x0045, - 0x0046, - 0x0047, - 0x0048, - 0x0049, - 0x004A, - 0x004B, - 0x004C, - 0x004D, - 0x004E, - 0x004F, - 0x0050, - 0x0052, - 0x0053, - 0x0054, - 0x0055, - 0x0056, - 0x0057, - 0x0058, - 0x0059, - 0x005A, - 0x005B, - 0x005C, - 0x005D, - 0x005E, - 0x005F, - 0x0060, - 0x0061, - 0x0062, - 0x0063, - 0x0064, - 0x0065, - 0x0066, - 0x0067, - 0x0068, - 0x0069, - 0x006A, - 0x006B, - 0x006C, - 0x006D, - 0x006E, - 0x006F, - 0x0070, - 0x0071, - 0x0072, - 0x0073, - 0x0074, - 0x0075, - 0x0076, - 0x0077, - 0x0078, - 0x0079, - 0x007A, - 0x007B, - 0x007C, - 0x007D, - 0x007E, - 0x007F, - 0x0080, - 0x0081, - 0x0082, - 0x0083, - 0x0084, - 0x0085, - 0x0089, - 0x008A, - 0x008B, - 0x008C, - 0x008D, - 0x008E, - 0x008F, - 0x0090, - 0x0091, - 0x0092, - 0x0093, - 0x0094, - 0x0095, - 0x0097, - 0x0098, - 0x0099, - 0x009A, - 0x009B, - 0x009C, - 0x009D, - 0x009E, - 0x009F, - 0x00A0, - 0x00A1, - 0x00A2, - 0x00A3, - 0x00A4, - 0x00A5, - 0x00A6, - 0x00A7, - 0x00A8, - 0x00A9, - 0x00AA, - 0x00AB, - 0x00AC, - 0x00AD, - 0x00AE, - 0x00AF, - 0x00B0, - 0x00B1, - 0x00B2, - 0x00B3, - 0x00B4, - 0x00B5, - 0x00B6, - 0x00B7, - 0x00B8, - 0x00B9, - 0x00BA, - 0x00BB, - 0x00BC, - 0x00BD, - 0x00BE, - 0x00BF, - 0x00C0, - 0x00C1, - 0x00C2, - 0x00C3, - 0x00C4, - 0x00C5, - 0x00C6, - 0x00C7, - 0x00C8, - 0x00CA, - 0x00CB, - 0x00CC, - 0x00CD, - 0x00CE, - 0x00CF, - 0x00D0, - 0x00D1, - 0x00D2, - 0x00D3, - 0x00D4, - 0x00D5, - 0x00D6, - 0x00D7, - 0x00D8, - 0x00D9, - 0x00DA, - 0x00DB, - 0x00DD, - 0x00DE, - 0x00DF, - 0x00E0, - 0x00E1, - 0x00E2, - 0x00E7, - 0x00E8, - 0x00E9, - 0x00EA, - 0x00EB, - 0x00EC, - 0x00ED, - 0x00EE, - 0x00EF, - 0x00F0, - 0x00F1, - 0x00F2, - 0x00F3, - 0x00F4, - 0x00F5, - 0x00F6, - 0x00F7, - 0x00F8, - 0x00F9, - 0x00FA, - 0x00FB, - 0x00FB, - 0x00FC, - 0x00FD, - 0x00FE, - 0x00FF, - 0x0100, - 0x0101, - 0x0102, - 0x0103, - 0x0105, - 0x0106, - 0x0108, - 0x0109, - 0x010A, - 0x010B, - 0x010C, - 0x010D, - 0x010E, - 0x0110, - 0x0111, - 0x0112, - 0x0113, - 0x0114, - 0x0115, - 0x0116, - 0x0117, - 0x0118, - 0x0119, - 0x011A, - 0x011B, - 0x011C, - 0x011D, - 0x011E, - 0x011F, - 0x0120, - 0x0121, - 0x0122, - 0x0123, - 0x0124, - 0x0125, - 0x0250, - 0x0251, - 0x0252, - 0x0253, - 0x0254, - 0x0255, - 0x0256, - 0x0257, - 0x0258, - 0x0259, - 0x025A, - 0x025B, - 0x025C, - 0x025D, - 0x025E, - 0x025F, - 0x0263, - 0x0269, + 0x002, 0x003, 0x004, 0x005, 0x006, 0x009, 0x00B, 0x00C, 0x00E, 0x00F, 0x010, 0x011, 0x012, 0x013, 0x014, 0x015, + 0x016, 0x017, 0x018, 0x019, 0x01A, 0x01B, 0x01C, 0x01D, 0x01E, 0x01F, 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, + 0x026, 0x027, 0x028, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, + 0x036, 0x037, 0x038, 0x039, 0x03A, 0x03C, 0x03D, 0x03E, 0x03F, 0x040, 0x041, 0x042, 0x043, 0x044, 0x045, 0x046, + 0x047, 0x048, 0x049, 0x04A, 0x04B, 0x04C, 0x04D, 0x04E, 0x04F, 0x050, 0x052, 0x053, 0x054, 0x055, 0x056, 0x057, + 0x058, 0x059, 0x05A, 0x05B, 0x05C, 0x05D, 0x05E, 0x05F, 0x060, 0x061, 0x062, 0x063, 0x064, 0x065, 0x066, 0x067, + 0x068, 0x069, 0x06A, 0x06B, 0x06C, 0x06D, 0x06E, 0x06F, 0x070, 0x071, 0x072, 0x073, 0x074, 0x075, 0x076, 0x077, + 0x078, 0x079, 0x07A, 0x07B, 0x07C, 0x07D, 0x07E, 0x07F, 0x080, 0x081, 0x082, 0x083, 0x084, 0x085, 0x089, 0x08A, + 0x08B, 0x08C, 0x08D, 0x08E, 0x08F, 0x090, 0x091, 0x092, 0x093, 0x094, 0x095, 0x097, 0x098, 0x099, 0x09A, 0x09B, + 0x09C, 0x09D, 0x09E, 0x09F, 0x0A0, 0x0A1, 0x0A2, 0x0A3, 0x0A4, 0x0A5, 0x0A6, 0x0A7, 0x0A8, 0x0A9, 0x0AA, 0x0AB, + 0x0AC, 0x0AD, 0x0AE, 0x0AF, 0x0B0, 0x0B1, 0x0B2, 0x0B3, 0x0B4, 0x0B5, 0x0B6, 0x0B7, 0x0B8, 0x0B9, 0x0BA, 0x0BB, + 0x0BC, 0x0BD, 0x0BE, 0x0BF, 0x0C0, 0x0C1, 0x0C2, 0x0C3, 0x0C4, 0x0C5, 0x0C6, 0x0C7, 0x0C8, 0x0CA, 0x0CB, 0x0CC, + 0x0CD, 0x0CE, 0x0CF, 0x0D0, 0x0D1, 0x0D2, 0x0D3, 0x0D4, 0x0D5, 0x0D6, 0x0D7, 0x0D8, 0x0D9, 0x0DA, 0x0DB, 0x0DD, + 0x0DE, 0x0DF, 0x0E0, 0x0E1, 0x0E2, 0x0E7, 0x0E8, 0x0E9, 0x0EA, 0x0EB, 0x0EC, 0x0ED, 0x0EE, 0x0EF, 0x0F0, 0x0F1, + 0x0F2, 0x0F3, 0x0F4, 0x0F5, 0x0F6, 0x0F7, 0x0F8, 0x0F9, 0x0FA, 0x0FB, 0x0FB, 0x0FC, 0x0FD, 0x0FE, 0x0FF, 0x100, + 0x101, 0x102, 0x103, 0x105, 0x106, 0x108, 0x109, 0x10A, 0x10B, 0x10C, 0x10D, 0x10E, 0x110, 0x111, 0x112, 0x113, + 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x11A, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, 0x122, 0x123, + 0x124, 0x125, 0x250, 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257, 0x258, 0x259, 0x25A, 0x25B, 0x25C, 0x25D, + 0x25E, 0x25F, 0x263, 0x269, }; @@ -1087,38 +786,8 @@ static int dsdr_gth_control(lldev_t dev, uint16_t addr, uint16_t data) return res; } -#if 0 -#define MAKE_DSDR_DRP_CMD(wr, idx, addr, data) ((((wr) & 1) << 28) | (((idx) ? 2 : 1) << 29) | (((addr) & 0xfff) << 16) | ((data) & 0xffff)) - -static int dsdr_drp_reg_wr(lldev_t dev, unsigned port, uint16_t addr, uint16_t data) -{ - int res = 0; - res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_DRP_CMD(1, port, addr, data)); - res = res ? res : usleep(10); - return res; -} - -static int dsdr_drp_reg_rd(lldev_t dev, unsigned port, uint16_t addr, uint16_t *odata) -{ - int res = 0; - uint32_t val = 0; - res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_DRP_CMD(0, port, addr, 0)); - res = res ? res : usleep(10); - res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &val); - *odata = val >> (port ? 16 : 0); - return res; -} -#endif - #define MAKE_DSDR_DRP_CMD(wr, idx, addr, data) ((((wr) & 1) << 30) | (((idx) & 0xf) << 26) | (((addr) & 0x3ff) << 16) | ((data) & 0xffff)) -//localparam DRP_SE_BIT = 31; -//localparam DRP_WR_BIT = 30; -//localparam DRP_CH_BIT = 29; -//localparam DRP_C2_BIT = 28; -//localparam DRP_C1_BIT = 27; -//localparam DRP_C0_BIT = 26; - enum { DRP_QPLL_IDX0 = 0, DRP_QPLL_IDX1 = 1, @@ -1138,7 +807,7 @@ static int dsdr_drp_reg_rd(lldev_t dev, unsigned port, uint16_t addr, uint16_t * int res = 0; uint32_t val = 0, j; res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, MAKE_DSDR_DRP_CMD(0, port, addr, 0)); - for (j = 0; j < 100; j++) { + for (j = 0; j < 1000; j++) { res = res ? res : usleep(10); res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &val); if (!(val >> 31)) @@ -1149,13 +818,13 @@ static int dsdr_drp_reg_rd(lldev_t dev, unsigned port, uint16_t addr, uint16_t * } -int gthcommon_init(dev_m2_dsdr_t *d) +static int gth_dump_all_regs(dev_m2_dsdr_t *d) { uint16_t val = 0; int res = 0; - for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_usp_regs); i++) { - res = res ? res : dsdr_drp_reg_rd(d->base.dev, DRP_QPLL_IDX0, s_gth_usp_regs[i], &val); - USDR_LOG("GTHQ", USDR_LOG_WARNING, "GTQ[%04x] => %04x\n", s_gth_usp_regs[i], val); + for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_usp_qpll_regs); i++) { + res = res ? res : dsdr_drp_reg_rd(d->base.dev, DRP_QPLL_IDX0, s_gth_usp_qpll_regs[i], &val); + USDR_LOG("GTHQ", USDR_LOG_WARNING, "GTQ[%04x] => %04x\n", s_gth_usp_qpll_regs[i], val); } for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_usp_chan_regs); i++) { res = res ? res : dsdr_drp_reg_rd(d->base.dev, DRP_CHAN_IDX0, s_gth_usp_chan_regs[i], &val); @@ -1349,7 +1018,7 @@ static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned uint64_t ncoval = freq; if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { - bool ch_rxiq; + bool ch_rxiq; // 1 - need to mirror spectrum bool mod = false; const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; // Map to HW channels const uint8_t iter_shared_selector[4] = { 0, 0, 1, 1 }; @@ -1358,25 +1027,34 @@ static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned int res = 0; const bool shared_lo_cfg_mode = true; unsigned hwidx = w->hwport; + unsigned ncoidx = make_afe79xx_idx_from_dsp_wire(w); - opt_u64_set_val(&d->rx_bxfc[hwidx][w->dsp_band], freq); + assert(ncoidx < MAX_DSP_NCO_RX); + opt_u64_set_val(&d->rx_bxfc[ncoidx], freq); - for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { - unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; - for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { - if (d->rx_bxfc[iter_hwid][j].set) { - chan_mid += d->rx_bxfc[iter_hwid][j].value; + USDR_LOG("HIPR", USDR_LOG_WARNING, "RX ORD %d: Set NCO%d to %.3f\n", ord, ncoidx, freq / 1.0e6); + + // Calculate mid frequency for all HW-related channels in the same LMS8001 LO-shared chain + for (unsigned j = 0; j < d->logic_chcnt_rx; j++) { + const channel_logic_dsp_wire_t* chinfo = &d->rx_lmap_info[j]; + if ((shared_lo_cfg_mode && (chinfo->hwport == iter_shared_lo_chans[iter_shared_selector[hwidx]][0] || chinfo->hwport == iter_shared_lo_chans[iter_shared_selector[hwidx]][1])) || + (!shared_lo_cfg_mode && (chinfo->hwport == hwidx))) { + unsigned v = make_afe79xx_idx_from_dsp_wire(chinfo); + if (d->rx_bxfc[v].set) { + chan_mid += d->rx_bxfc[v].value; cnt++; + + USDR_LOG("HIPR", USDR_LOG_WARNING, "RX%d: IDX%d COMB_CH[%d] %.3f -- HWIDX: %d HWITER:%d\n", cnt, j, v, d->rx_bxfc[v].value / 1.0e6, hwidx, chinfo->hwport); } } } + assert(cnt != 0); chan_mid /= cnt; for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; res = res ? res : dsdr_hiper_fe_rx_freq_set(&d->hiper, s_chanmap_hw_to_fe[iter_hwid], chan_mid, &ncoval, &ch_rxiq); } - if (res) return res; @@ -1385,49 +1063,48 @@ static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned if (logic_ch == 0xff) continue; - unsigned hw_iter = d->rx_lmap_info[logic_ch].hwport; - for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { - unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + const channel_logic_dsp_wire_t* chinfo = &d->rx_lmap_info[logic_ch]; + unsigned hw_iter = chinfo->hwport; + if ((shared_lo_cfg_mode && (hw_iter == iter_shared_lo_chans[iter_shared_selector[hwidx]][0] || hw_iter == iter_shared_lo_chans[iter_shared_selector[hwidx]][1])) || + (!shared_lo_cfg_mode && (hw_iter == hwidx))) { - if (iter_hwid == hw_iter) { - uint8_t nchan = (ch_rxiq) ? d->rx_chans.ch_map[k] | CH_SWAP_IQ_FLAG : d->rx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG; - if (nchan != d->rx_chans.ch_map[k]) { - d->rx_chans.ch_map[k] = nchan; - mod = true; - } + uint8_t nchan = (ch_rxiq) ? (d->rx_chans.ch_map[k] | CH_SWAP_IQ_FLAG) : (d->rx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG); + if (nchan != d->rx_chans.ch_map[k]) { + d->rx_chans.ch_map[k] = nchan; + mod = true; } - } - } - if (mod) { - res = res ? res : d->rx->ops->option_set(d->rx, "chmap", (uintptr_t)&d->rx_chans); - } - - for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { - unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; - for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { - if (!d->rx_bxfc[iter_hwid][j].set) + unsigned rnco_idx = make_afe79xx_idx_from_dsp_wire(chinfo); + if (!d->rx_bxfc[rnco_idx].set) continue; - uint64_t freq_req = d->rx_bxfc[iter_hwid][j].value; + // Calculate individual offset, assume everything is in the same Nyquist zone + uint64_t freq_req = d->rx_bxfc[make_afe79xx_idx_from_dsp_wire(chinfo)].value; int64_t nco_offset = freq_req - chan_mid; uint64_t freq_mod = ch_rxiq ? (ncoval - nco_offset) : (ncoval + nco_offset); - if (d->rx_raw_nco[iter_hwid][j].set && d->rx_raw_nco[iter_hwid][j].value == freq_mod) + // Check cached value + if (d->rx_raw_nco[rnco_idx].set && d->rx_raw_nco[rnco_idx].value == freq_mod) continue; - res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_RX, iter_hwid, freq_mod / 1000, 0, j); - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f RX_NCO=%.3f MID_F=%.3f\n", - ord, iter_hwid + 'A', j, freq_req / 1.0e6, freq_mod / 1.0e6, chan_mid / 1.0e6); + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, chinfo->dsp_type, chinfo->dsp_idx, freq_mod / 1000, 0, chinfo->dsp_band); + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c: %s%d.Band%d] F=%.3f RX_NCO[%d]=%.3f MID_F=%.3f\n", + ord, hw_iter + 'A', chinfo->dsp_type == NCO_RX ? "RX" : "FB", chinfo->dsp_idx, chinfo->dsp_band, + freq_req / 1.0e6, rnco_idx, freq_mod / 1.0e6, chan_mid / 1.0e6); - opt_u64_set_val(&d->rx_raw_nco[iter_hwid][j], freq_mod); + opt_u64_set_val(&d->rx_raw_nco[rnco_idx], freq_mod); } } + if (mod) { + res = res ? res : d->rx->ops->option_set(d->rx, "chmap", (uintptr_t)&d->rx_chans); + } return res; } - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f RX_NCO=%.3f\n", ord, w->hwport + 'A', w->dsp_band, freq / 1.0e6, ncoval / 1.0e6); + USDR_LOG("DSDR", USDR_LOG_WARNING, "RX CH[%d => %c: %s%d.Band%d] NCO[%d]=%.3f\n", + ord, w->hwport + 'A', w->dsp_type == NCO_RX ? "RX" : "FB", w->dsp_idx, w->dsp_band, + make_afe79xx_idx_from_dsp_wire(w), freq / 1.0e6); res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, w->dsp_type, w->dsp_idx, ncoval / 1000, 0, w->dsp_band); return res; } @@ -1448,34 +1125,43 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned uint64_t ncoval = freq; if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { - bool ch_txiq; + bool ch_txiq; // 1 - need to mirror spectrum bool mod = false; - const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; + const uint8_t iter_shared_lo_chans[2][2] = { { 0, 1 }, { 2, 3 } }; // Map to HW channels const uint8_t iter_shared_selector[4] = { 0, 0, 1, 1 }; uint64_t chan_mid = 0; unsigned cnt = 0; int res = 0; const bool shared_lo_cfg_mode = true; unsigned hwidx = w->hwport; + unsigned ncoidx = make_afe79xx_idx_from_dsp_wire(w); - opt_u64_set_val(&d->tx_bxfc[hwidx][w->dsp_band], freq); + assert(ncoidx < MAX_DSP_NCO_TX); + opt_u64_set_val(&d->tx_bxfc[ncoidx], freq); - for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { - unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; - for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { - if (d->tx_bxfc[iter_hwid][j].set) { - chan_mid += d->tx_bxfc[iter_hwid][j].value; + USDR_LOG("HIPR", USDR_LOG_WARNING, "TX ORD %d: Set NCO%d to %.3f\n", ord, ncoidx, freq / 1.0e6); + + // Calculate mid frequency for all HW-related channels in the same LMS8001 LO-shared chain + for (unsigned j = 0; j < d->logic_chcnt_tx; j++) { + const channel_logic_dsp_wire_t* chinfo = &d->tx_lmap_info[j]; + if ((shared_lo_cfg_mode && (chinfo->hwport == iter_shared_lo_chans[iter_shared_selector[hwidx]][0] || chinfo->hwport == iter_shared_lo_chans[iter_shared_selector[hwidx]][1])) || + (!shared_lo_cfg_mode && (chinfo->hwport == hwidx))) { + unsigned v = make_afe79xx_idx_from_dsp_wire(chinfo); + if (d->tx_bxfc[v].set) { + chan_mid += d->tx_bxfc[v].value; cnt++; + + USDR_LOG("HIPR", USDR_LOG_WARNING, "TX%d: IDX%d COMB_CH[%d] %.3f -- HWIDX: %d HWITER:%d\n", cnt, j, v, d->tx_bxfc[v].value / 1.0e6, hwidx, chinfo->hwport); } } } + assert(cnt != 0); chan_mid /= cnt; for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; res = res ? res : dsdr_hiper_fe_tx_freq_set(&d->hiper, s_chanmap_hw_to_fe[iter_hwid], chan_mid, &ncoval, &ch_txiq); } - if (res) return res; @@ -1484,49 +1170,48 @@ static int dsdr_set_tx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned if (logic_ch == 0xff) continue; - unsigned hw_iter = d->tx_lmap_info[logic_ch].hwport; - for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { - unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; + const channel_logic_dsp_wire_t* chinfo = &d->tx_lmap_info[logic_ch]; + unsigned hw_iter = chinfo->hwport; + if ((shared_lo_cfg_mode && (hw_iter == iter_shared_lo_chans[iter_shared_selector[hwidx]][0] || hw_iter == iter_shared_lo_chans[iter_shared_selector[hwidx]][1])) || + (!shared_lo_cfg_mode && (hw_iter == hwidx))) { - if (iter_hwid == hw_iter) { - uint8_t nchan = (ch_txiq) ? d->tx_chans.ch_map[k] | CH_SWAP_IQ_FLAG : d->tx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG; - if (nchan != d->tx_chans.ch_map[k]) { - d->tx_chans.ch_map[k] = nchan; - mod = true; - } + uint8_t nchan = (ch_txiq) ? (d->tx_chans.ch_map[k] | CH_SWAP_IQ_FLAG) : (d->tx_chans.ch_map[k] & ~CH_SWAP_IQ_FLAG); + if (nchan != d->tx_chans.ch_map[k]) { + d->tx_chans.ch_map[k] = nchan; + mod = true; } - } - } - if (mod) { - res = res ? res : d->tx->ops->option_set(d->tx, "chmap", (uintptr_t)&d->tx_chans); - } - - for (unsigned s = 0; s < (shared_lo_cfg_mode ? 2 : 1); s++) { - unsigned iter_hwid = shared_lo_cfg_mode ? iter_shared_lo_chans[iter_shared_selector[hwidx]][s] : hwidx; - for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { - if (!d->tx_bxfc[iter_hwid][j].set) + unsigned rnco_idx = make_afe79xx_idx_from_dsp_wire(chinfo); + if (!d->tx_bxfc[rnco_idx].set) continue; - uint64_t freq_req = d->tx_bxfc[iter_hwid][j].value; + // Calculate individual offset, assume everything is in the same Nyquist zone + uint64_t freq_req = d->tx_bxfc[make_afe79xx_idx_from_dsp_wire(chinfo)].value; int64_t nco_offset = freq_req - chan_mid; uint64_t freq_mod = ch_txiq ? (ncoval - nco_offset) : (ncoval + nco_offset); - if (d->tx_raw_nco[iter_hwid][j].set && d->tx_raw_nco[iter_hwid][j].value == freq_mod) + // Check cached value + if (d->tx_raw_nco[rnco_idx].set && d->tx_raw_nco[rnco_idx].value == freq_mod) continue; - res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, NCO_TX, iter_hwid, freq_mod / 1000, 0, j); - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f TX_NCO=%.3f MID_F=%.3f\n", - ord, iter_hwid + 'A', j, freq_req / 1.0e6, freq_mod / 1.0e6, chan_mid / 1.0e6); + res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, chinfo->dsp_type, chinfo->dsp_idx, freq_mod / 1000, 0, chinfo->dsp_band); + USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c: %s%d.Band%d] F=%.3f TX_NCO[%d]=%.3f MID_F=%.3f\n", + ord, hw_iter + 'A', chinfo->dsp_type == NCO_TX ? "TX" : "FB", chinfo->dsp_idx, chinfo->dsp_band, + freq_req / 1.0e6, rnco_idx, freq_mod / 1.0e6, chan_mid / 1.0e6); - opt_u64_set_val(&d->tx_raw_nco[iter_hwid][j], freq_mod); + opt_u64_set_val(&d->tx_raw_nco[rnco_idx], freq_mod); } } + if (mod) { + res = res ? res : d->tx->ops->option_set(d->tx, "chmap", (uintptr_t)&d->tx_chans); + } return res; } - USDR_LOG("HIPR", USDR_LOG_WARNING, "CH[%d => %c Band%d] F=%.3f TX_NCO=%.3f\n", ord, w->hwport + 'A', w->dsp_band, freq / 1.0e6, ncoval / 1.0e6); + USDR_LOG("DSDR", USDR_LOG_WARNING, "TX CH[%d => %c: TX%d.Band%d] NCO[%d]=%.3f\n", + ord, w->hwport + 'A', w->dsp_idx, w->dsp_band, + make_afe79xx_idx_from_dsp_wire(w), freq / 1.0e6); res = res ? res : d->st.libcapi79xx_upd_nco(&d->st.capi, w->dsp_type, w->dsp_idx, ncoval / 1000, 0, w->dsp_band); return res; } @@ -1978,15 +1663,29 @@ static int dev_m2_dsdr_debug_rxtime_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint6 return 0; } +static int afe_update_chan_pwr(struct dev_m2_dsdr *d) +{ + int res = 0; + res = (d->st.libcapi79xx_set_tdd == NULL) ? -EINVAL : 0; + res = res ? res : d->st.libcapi79xx_set_tdd(&d->st.capi, d->hw_enabled_rx & 0xf, (d->hw_enabled_rx >> 4) & 0x3, d->hw_enabled_tx); + res = res ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, d->hw_enabled_tx); + res = res ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, d->hw_enabled_rx); -static -void usdr_device_m2_dsdr_destroy(pdevice_t udev) + USDR_LOG("XDEV", USDR_LOG_ERROR, "DSDR AFE CHANNEL POWER RX:%x TX:%x\n", d->hw_enabled_rx, d->hw_enabled_tx); + return res; +} + +static void usdr_device_m2_dsdr_destroy(pdevice_t udev) { struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)udev; lldev_t dev = d->base.dev; dev_m2_dsdr_afe_health_get(udev, NULL, NULL); + d->hw_enabled_rx = 0; + d->hw_enabled_tx = 0; + afe_update_chan_pwr(d); + // FE Power OFF if (dev_m2_dsdr_has_hiper(d)) { dsdr_hiper_fe_destroy(&d->hiper); @@ -2020,6 +1719,17 @@ void usdr_device_m2_dsdr_destroy(pdevice_t udev) usdr_device_base_destroy(udev); } +static unsigned make_quad_pwr_mask(unsigned enabled_ch) +{ + unsigned out = 0; + if (enabled_ch & 0xf) + out |= 0xf; + if (enabled_ch & 0xf0) + out |= 0xf0; + + return out; +} + static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) { lldev_t dev = dd->base.dev; @@ -2084,7 +1794,7 @@ static int usdr_jesd204b_bringup_pre(struct dev_m2_dsdr *dd) USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); // Disable unused lanes after GTH reset is done. GTWiz expects all lanes to be initialized, otherwise DONE signal won't be asserted - //res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, dd->hw_fpga_jesd_tx_en); + res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, make_quad_pwr_mask(dd->hw_fpga_jesd_tx_en | dd->hw_fpga_jesd_rx_en)); return res; } @@ -2096,19 +1806,14 @@ static int usdr_jesd204b_bringup_post(struct dev_m2_dsdr *dd) res = res ? res : dev_gpo_set(dev, IGPO_TIAFE_RX_SYNC_RESET, 0); res = res ? res : usleep(10000); - // res = res ? res : dsdr_gth_control(dev, GTH_CTR_RX_EN, dd->hw_fpga_jesd_rx_en); - // res = res ? res : dsdr_gth_control(dev, GTH_CTR_TX_EN, dd->hw_fpga_jesd_tx_en); + + //res = res ? res : dsdr_gth_control(dev, GTH_CTR_RX_EN, dd->hw_fpga_jesd_rx_en); + res = res ? res : dsdr_gth_control(dev, GTH_CTR_RX_EN, make_quad_pwr_mask(dd->hw_fpga_jesd_rx_en)); res = res ? res : dev_gpi_get32(dev, IGPI_JESD_SYSREF_RAC, &d); USDR_LOG("DSDR", USDR_LOG_ERROR, "STAT = %08x\n", d); - //bool second_qpll_req = ((dd->hw_fpga_jesd_tx_en | dd->hw_fpga_jesd_rx_en) >> 4) ? true : false; - //if (!second_qpll_req) { - // res = res ? res : dsdr_gth_control(dev, GTH_CTR_QPLL_EN, 0b0001); - //} - return res; - } enum jesd_rates { @@ -2119,24 +1824,45 @@ enum jesd_rates { static const uint16_t s_gth_qpll_ovrd_491[] = { 0x0008, 0x333c, 0x000d, 0x0f00, 0x011, 0x87c0, 0x0014, 0x0040, 0x0019, 0x031d, 0x001b, 0x87c0, 0x0030, 0x0045}; static const uint16_t s_gth_qpll_ovrd_369[] = { 0x0008, 0x331c, 0x000d, 0x0800, 0x011, 0x87c1, 0x0014, 0x0040, 0x0019, 0x033f, 0x001b, 0x87c1, 0x0030, 0x0004}; -static const uint16_t s_gth_qpll_ovrd_245[] = { 0x0008, 0x333c, 0x000d, 0x0f00, 0x011, 0x87c0, 0x0014, 0x0082, 0x0019, 0x031d, 0x001b, 0x87c0, 0x0030, 0x0045}; +//static const uint16_t s_gth_qpll_ovrd_245[] = { 0x0008, 0x333c, 0x000d, 0x0f00, 0x011, 0x87c0, 0x0014, 0x0082, 0x0019, 0x031d, 0x001b, 0x87c0, 0x0030, 0x0045}; static int dsdr_gth_set_rate(struct dev_m2_dsdr *d, unsigned rate) { int res = 0; const uint16_t* mode; switch (rate) { - case RATE_245_76: mode = s_gth_qpll_ovrd_245; break; + //case RATE_245_76: mode = s_gth_qpll_ovrd_245; break; case RATE_368_64: mode = s_gth_qpll_ovrd_369; break; case RATE_491_52: mode = s_gth_qpll_ovrd_491; break; default: return -EINVAL; } + res = res ? res : dsdr_gth_control(d->base.dev, GTH_CTR_TX_EN, 0); + res = res ? res : dsdr_gth_control(d->base.dev, GTH_CTR_RX_EN, 0); + res = res ? res : dsdr_gth_control(d->base.dev, GTH_CTR_QPLL_EN, 0); + for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_qpll_ovrd_369); i += 2) { res = res ? res : dsdr_drp_reg_wr(d->base.dev, DRP_QPLL_IDX0, mode[i + 0], mode[i + 1]); res = res ? res : dsdr_drp_reg_wr(d->base.dev, DRP_QPLL_IDX1, mode[i + 0], mode[i + 1]); } + +#if 0 + switch (rate) { + case RATE_245_76: mode = s_gth_chan_ovrd_245; break; + case RATE_368_64: + case RATE_491_52: mode = s_gth_chan_ovrd_491; break; + default: + return -EINVAL; + } + + for (unsigned i = 0; i < SIZEOF_ARRAY(s_gth_chan_ovrd_245); i += 2) { + for (unsigned j = 0; j < 8; j++) { + res = res ? res : dsdr_drp_reg_wr(d->base.dev, DRP_CHAN_IDX0 + j, mode[i + 0], mode[i + 1]); + res = res ? res : usleep(100); + } + } +#endif return res; } @@ -2144,8 +1870,6 @@ enum jesd_special_flags { MODE_JESD204C = 0, MODE_JESD204B = 2, - // MODE_JESD_DUAL_QUAD = 4, - // AFE_COMPAT_7900 = 1 << 8, AFE_COMPAT_7901 = 1 << 9, // AFE_COMPAT_7903 = 1 << 10, @@ -2181,31 +1905,27 @@ struct jesd_config struct jesd_config s_hwjesd_config[] = { { MODE_JESD204C | AFE_COMPAT_7901 | AFE_COMPAT_7950 | FPGA_COMPAT_4X_4X | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, - RATE_491_52, 4, 4, 4, 4, 0x0f, 0x0f, s_dsdr_chmap_s_nco, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco, s_dsdr_lmap_s_nco, "4RX_4TX_491.52", "Afe79xxPg1_6664_491_4x1_4x1_20.txt", "Afe79xxPg1_6664_491_4x1_4x1_13.txt" }, - // "Afe79xxPg1_6664_491.txt", "Afe79xxPg1_6664_491_7950.txt" }, + RATE_491_52, 4, 4, 4, 4, 0x0f, 0x0f, s_dsdr_chmap_s_nco, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_ncorx, s_dsdr_lmap_s_ncotx, "4RX_4TX_491.52", "Afe79xxPg1_6664_491_4x1_4x1_20.txt", "Afe79xxPg1_6664_491_4x1_4x1_13.txt" }, + + { MODE_JESD204C | AFE_COMPAT_7901 | AFE_COMPAT_7950 | FPGA_COMPAT_4X_4X | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, + RATE_368_64, 4, 4, 4, 4, 0x0f, 0x0f, s_dsdr_chmap_s_nco, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_ncorx, s_dsdr_lmap_s_ncotx, "4RX_4TX_368.64", "Afe79xxPg1_6664_368_4x1_4x1_20.txt", "Afe79xxPg1_6664_368_4x1_4x1_13.txt" }, { MODE_JESD204C | AFE_COMPAT_7901 | AFE_COMPAT_7950 | FPGA_COMPAT_8X_8X, - RATE_368_64, 8, 8, 4, 4, 0xff, 0xff, s_dsdr_chmap_d_nco, s_dsdr_chmap_d_nco, s_dsdr_lmap_d_nco, s_dsdr_lmap_d_nco, "8RX_8TX_368.64", "Afe79xxPg1_6664_368_4x2_4x2_20.txt", "Afe79xxPg1_6664_368_4x2_4x2_13.txt" }, - //"Afe79xxPg1_6664_369_D.txt", NULL }, + RATE_368_64, 8, 8, 4, 4, 0xff, 0xff, s_dsdr_chmap_d_nco, s_dsdr_chmap_d_nco, s_dsdr_lmap_d_ncorx, s_dsdr_lmap_d_ncotx, "8RX_8TX_368.64", "Afe79xxPg1_6664_368_4x2_4x2_20.txt", "Afe79xxPg1_6664_368_4x2_4x2_13.txt" }, { MODE_JESD204C | AFE_COMPAT_7901 | AFE_COMPAT_7950 | FPGA_COMPAT_8X_8X | FPGA_COMPAT_8X_4X, - RATE_368_64, 8, 4, 4, 4, 0xff, 0x0f, s_dsdr_chmap_d_nco, s_dsdr_chmap_s_nco, s_dsdr_lmap_d_nco, s_dsdr_lmap_s_nco, "8RX_4TX_368.64", "Afe79xxPg1_6664_368_4x2_4x1_20.txt", "Afe79xxPg1_6664_368_4x2_4x1_13.txt" }, - //"Afe79xxPg1_6664_369_D.txt", NULL }, - + RATE_368_64, 8, 4, 4, 4, 0xff, 0x0f, s_dsdr_chmap_d_nco, s_dsdr_chmap_s_nco, s_dsdr_lmap_d_ncorx, s_dsdr_lmap_s_ncotx, "8RX_4TX_368.64", "Afe79xxPg1_6664_368_4x2_4x1_20.txt", "Afe79xxPg1_6664_368_4x2_4x1_13.txt" }, { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, - RATE_491_52, 8, 4, 6, 4, 0x03f, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_nco, "4RX_4TX_2FB_491.52", "Afe79xxPg1_6664_491_6x1_4x1_20.txt", "Afe79xxPg1_6664_491_6x1_4x1_13.txt" }, - //RATE_491_52, 6, 4, 6, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_nco, "4RX_4TX_2FB_491.52", NULL, "Afe79xxPg1_6664_2FB_491_7950.txt" }, + RATE_491_52, 8, 4, 6, 4, 0x03f, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_ncotx, "4RX_4TX_2FB_491.52", "Afe79xxPg1_6664_491_6x1_4x1_20.txt", "Afe79xxPg1_6664_491_6x1_4x1_13.txt" }, { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, - RATE_368_64, 8, 4, 4, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_368.64", "Afe79xxPg1_6664_368_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_368_6x1FBRX_4x1_13.txt" }, + RATE_368_64, 8, 4, 6, 4, 0x03f, 0x0f, s_dsdr_chmap_s_nco_fb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fb, s_dsdr_lmap_s_ncotx, "4RX_4TX_2FB_368.64", "Afe79xxPg1_6664_368_6x1_4x1_20.txt", "Afe79xxPg1_6664_368_6x1_4x1_13.txt" }, { MODE_JESD204C | AFE_COMPAT_7950 | FPGA_COMPAT_8X_4X | FPGA_COMPAT_8X_8X, - RATE_491_52, 8, 4, 4, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_rxfb, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_nco, "4RX2FBRB_4TX_491.52", "Afe79xxPg1_6664_491_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_491_6x1FBRX_4x1_13.txt" }, - + RATE_368_64, 8, 4, 4, 4, 0x3f, 0x0f, s_dsdr_chmap_s_nco_fbrx, s_dsdr_chmap_s_nco, s_dsdr_lmap_s_nco_fbrx, s_dsdr_lmap_s_ncotx, "4RX2FBRX_4TX_368.64", "Afe79xxPg1_6664_368_6x1FBRX_4x1_20.txt", "Afe79xxPg1_6664_368_6x1FBRX_4x1_13.txt" }, }; - static int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** devparam, const char** devval) { @@ -2228,9 +1948,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->subdev = 0; d->dsdr_state = STATE_IDLE; - //d->hw_mask_rx = 0xf; // RX_3 RX_2 RX_1 RX_0 - //d->hw_mask_tx = 0xf; // TX_3 TX_2 TX_1 TX_0 - res = res ? res : dev_gpi_get32(dev, IGPI_USR_ACCESS2, &usr2); res = res ? res : dev_gpi_get32(dev, IGPI_HWID, &hwid); if (res) { @@ -2281,12 +1998,15 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } if (getenv("DSDR_M2_R0")) { + // Old HW revision d->type = DSDR_M2_R0; } d->cfg_rx_lanemap = 0x76543210; d->cfg_tx_lanemap = 0x76543210; + //gth_dump_all_regs(d); + unsigned master_rate; unsigned dsp_rx_chans; unsigned dsp_tx_chans; @@ -2362,15 +2082,11 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** d->jesd_x8 = (dsp_rx_chans > 4) || (dsp_tx_chans > 4); + d->hw_enabled_rx = 0; + d->hw_enabled_tx = 0; + // TODO Proper AFE revision detection afeType = 7901; - - // Fixup for 7903 - if (getenv("DSDR_AFE7903")) { - // RX C/A - // TX D/B - afeType = 7903; - } if (getenv("DSDR_M2_7950")) { afeType = 7950; chip_rev = 0x13; @@ -2396,161 +2112,6 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** USDR_LOG("XDEV", USDR_LOG_INFO, "DSP_RX=%d DSP_TX=%d AFE=%d Configuration `%s` RATE=%.2f == FILE:`%s`\n", dsp_rx_chans, dsp_tx_chans, afeType, s_hwjesd_config[cfg_idx].config_name, master_rate / 1.0e6, d->afecongiguration); - -#if 0 - const bool oveeride_m_369 = true; - dsdr_gth_set_rate(d, oveeride_m_369); - jesd_cfg = oveeride_m_369 ? JESD_MODE_8X_8X_369 : JESD_MODE_8X_4X_491; - - - switch (jesd_cfg) { - case JESD_MODE_4X_4X_491: - d->rx_chmap_info = s_dsdr_chmap_s_nco; - d->tx_chmap_info = s_dsdr_chmap_s_nco; - d->rx_lmap_info = s_dsdr_lmap_s_nco; - d->tx_lmap_info = s_dsdr_lmap_s_nco; - - d->logic_chcnt_rx = 4; - d->logic_chcnt_tx = 4; - d->hw_chcnt_rx = 4; - d->hw_chcnt_tx = 4; - break; - - case JESD_MODE_8X_8X_369: - d->rx_chmap_info = s_dsdr_chmap_d_nco; - d->tx_chmap_info = s_dsdr_chmap_d_nco; - d->rx_lmap_info = s_dsdr_lmap_d_nco; - d->tx_lmap_info = s_dsdr_lmap_d_nco; - - d->logic_chcnt_rx = 8; - d->logic_chcnt_tx = 4; //TODO: recompile to 8!!! - d->hw_chcnt_rx = 4; - d->hw_chcnt_tx = 4; - - master_rate = 368640000; - maxusr_rate = 380000000; - - d->hw_fpga_jesd_rx_en = 0xff; - d->hw_fpga_jesd_tx_en = 0xff; - jesd_x8 = true; - break; - - case JESD_MODE_8X_4X_491: - d->rx_chmap_info = s_dsdr_chmap_s_nco_fb; - d->tx_chmap_info = s_dsdr_chmap_s_nco; - d->rx_lmap_info = s_dsdr_lmap_s_nco_fb; - d->tx_lmap_info = s_dsdr_lmap_s_nco; - - d->logic_chcnt_rx = 6; // a FB channels can occupy x2 lanes, but we support only x1 at the moment - d->logic_chcnt_tx = 4; - d->hw_chcnt_rx = 6; - d->hw_chcnt_tx = 4; - - d->hw_fpga_jesd_rx_en = 0x3f; - jesd_x8 = true; - - d->hw_fpga_jesd_tx_en = 0x0f; //Fixup for incorrect config - d->hw_fpga_jesd_rx_en = 0x0f; //Fixup for incorrect config - break; - - default: - USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported JESD_CFG=%d!\n", jesd_cfg); - return -EIO; - } - - d->jesd_x8 = jesd_x8; - - afeType = 7901; - switch (jesdv) { - case DSDR_JESD204B_810_245: - d->max_rate = maxusr_rate / 2; - d->dac_rate = d->adc_rate = master_rate / 2; - d->afecongiguration = "Afe79xxPg1_02.txt"; - break; - - case DSDR_JESD204C_6664_245: - d->max_rate = maxusr_rate / 2; - d->dac_rate = d->adc_rate = master_rate / 2; - d->afecongiguration = "Afe79xxPg1_6664_245.txt"; - break; - - case DSDR_JESD204C_6664_491: - d->max_rate = maxusr_rate; - d->dac_rate = d->adc_rate = master_rate; - - if (jesd_x8 == false && master_rate == 491520000) { - d->afecongiguration = "Afe79xxPg1_6664_491.txt"; - } else if (jesd_x8 == true && master_rate == 368640000) { - d->afecongiguration = "Afe79xxPg1_6664_369_D.txt"; - } else if (jesd_x8 == true && master_rate == 491520000) { - d->afecongiguration = "Afe79xxPg1_6664_491_fb3.txt"; - - d->afecongiguration = "Afe79xxPg1_6664_491.txt"; - } - - if (d->hw_mask_rx == 0x5 && d->hw_mask_tx == 0xA) { - // RX C/A - // TX D/B - // d->afecongiguration = "Afe79xxPg1_dsdr_491_7903.txt"; - - afeType = 7903; - - d->hw_chcnt_rx = 2; - d->hw_chcnt_tx = 2; - - d->cfg_rx_lanemap = 0x76543120; - d->cfg_tx_lanemap = 0x76542031; - - d->hw_rxch_route[0] = 0; - d->hw_rxch_route[1] = 2; - d->hw_rxch_route[2] = 1; - d->hw_rxch_route[3] = 3; - d->hw_rxch_route[4] = 0; - d->hw_rxch_route[5] = 2; - d->hw_rxch_route[6] = 1; - d->hw_rxch_route[7] = 3; - - d->hw_txch_route[0] = 1; - d->hw_txch_route[1] = 3; - d->hw_txch_route[2] = 0; - d->hw_txch_route[3] = 2; - d->hw_txch_route[4] = 1; - d->hw_txch_route[5] = 3; - d->hw_txch_route[6] = 0; - d->hw_txch_route[7] = 2; - } - - if (getenv("DSDR_M2_7950")) { - if (master_rate != 491520000) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "No configuration for 7950@369MSPS!\n"); - return -EIO; - } - // AFE7950 - if (jesd_x8 == true) { - d->afecongiguration = "Afe79xxPg1_6664_491_7950_fb3.txt"; - } else { - d->afecongiguration = "Afe79xxPg1_6664_491_7950.txt"; - } - afeType = 7950; - } - break; - - default: - USDR_LOG("XDEV", USDR_LOG_ERROR, "Unsupported JESD type %x (HWID = %08x), skipping initialization!\n", jesdv, hwid); - return -EIO; - } - - - gthcommon_init(d); - - d->cfg_afe_type = afeType; - d->jesdv = jesdv; - USDR_LOG("XDEV", USDR_LOG_ERROR, "Configuration: %s, Type: %d, AFE: %d, JESD204%c, CH_TX=%02x, CH_RX=%02x JESDx%d", - d->afecongiguration, d->type, d->cfg_afe_type, (jesdv == DSDR_JESD204B_810_245) ? 'B' : 'C', d->hw_mask_tx, d->hw_mask_rx, - jesd_x8 ? 8 : 4); -#endif - - if (getenv("SKIPAFE")) { d->type = DSDR_KCU116_EVM; } @@ -2798,7 +2359,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : usdr_jesd204b_bringup_post(d); } - d->st.libcapi79xx_set_tdd(&d->st.capi, 0xf, 0x3, 0xf); + res = res ? res : afe_update_chan_pwr(d); if (d->type == DSDR_PCIE_HIPER_R0) { unsigned override = 0; @@ -3020,6 +2581,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char } memset(d->rx_ordinal_to_logic, 0xff, sizeof(d->rx_ordinal_to_logic)); + memset(d->rx_logic_to_ordinal, 0xff, sizeof(d->rx_logic_to_ordinal)); const char* env_ch = getenv("DSDR_CH_RX"); if (env_ch) { @@ -3031,6 +2593,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char memcpy(d->rx_ordinal_to_logic, lchans.ch_map, sizeof(lchans.ch_map[0]) * channels->count); + d->hw_enabled_rx = 0; d->logic_enabled_rx = 0; for (unsigned i = 0; i < channels->count; i++) { @@ -3040,6 +2603,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char USDR_LOG("UDEV", USDR_LOG_ERROR, "Stream RX: Logical channel %d incorrectly mmaped to HW %d\n", i, hw); return -EINVAL; } + d->rx_logic_to_ordinal[logic] = i; d->hw_enabled_rx |= (1ull << hw); d->logic_enabled_rx |= (1ull << logic); @@ -3094,8 +2658,9 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char } // TODO: set actual antenna mask - res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0x3f); // d->hw_enabled_rx + //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0x3f); // d->hw_enabled_rx //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0x0); + res = res ? res : afe_update_chan_pwr(d); *out_handle = d->rx; } else { @@ -3103,6 +2668,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char return -EBUSY; } memset(d->tx_ordinal_to_logic, 0xff, sizeof(d->tx_ordinal_to_logic)); + memset(d->tx_logic_to_ordinal, 0xff, sizeof(d->tx_logic_to_ordinal)); const char* env_ch = getenv("DSDR_CH_TX"); if (env_ch) { @@ -3126,6 +2692,7 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char USDR_LOG("UDEV", USDR_LOG_ERROR, "Stream TX: Logical channel %d incorrectly mmaped to HW %d\n", i, hw); return -EINVAL; } + d->tx_logic_to_ordinal[logic] = i; d->hw_enabled_tx |= (1ull << hw); d->logic_enabled_tx |= (1ull << logic); @@ -3173,7 +2740,8 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char } // TODO: set actual antenna mask - res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0xf); + //res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0xf); + res = res ? res : afe_update_chan_pwr(d); *out_handle = d->tx; } @@ -3195,7 +2763,8 @@ int usdr_device_m2_dsdr_unregister_stream(device_t* dev, stream_handle_t* stream res = dsdr_hiper_fe_rx_chan_en(&d->hiper, 0); } - dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0); + //dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0); + afe_update_chan_pwr(d); } else if (stream == d->tx) { d->tx = NULL; d->hw_enabled_rx = 0; @@ -3205,7 +2774,8 @@ int usdr_device_m2_dsdr_unregister_stream(device_t* dev, stream_handle_t* stream res = dsdr_hiper_fe_tx_chan_en(&d->hiper, 0); } - dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0); + //dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0); + afe_update_chan_pwr(d); } else { return -EINVAL; } @@ -3247,8 +2817,6 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) d->hw_enabled_tx = 0; d->hw_enabled_rx = 0; - //d->hw_mask_tx = 0; - //d->hw_mask_rx = 0; d->logic_enabled_rx = 0; d->logic_enabled_tx = 0; @@ -3267,6 +2835,7 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) opt_u64_set_null(&d->tx_ord_freqs[i]); } +#if 0 for (unsigned i = 0; i < MAX_HIPER_FE_PORT; i++) { for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { opt_u64_set_null(&d->rx_bxfc[i][j]); @@ -3274,9 +2843,18 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) opt_u64_set_null(&d->rx_raw_nco[i][j]); opt_u64_set_null(&d->tx_raw_nco[i][j]); - } } +#endif + + for (unsigned i = 0; i < MAX_DSP_NCO_RX; i++) { + opt_u64_set_null(&d->rx_bxfc[i]); + opt_u64_set_null(&d->rx_raw_nco[i]); + } + for (unsigned i = 0; i < MAX_DSP_NCO_TX; i++) { + opt_u64_set_null(&d->tx_bxfc[i]); + opt_u64_set_null(&d->tx_raw_nco[i]); + } d->type = DSDR_PCIE_HIPER_R0; From 8060875b0d6bc1b439759c13f44138b81089a7dc Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Thu, 8 Jan 2026 16:42:17 +0400 Subject: [PATCH 275/397] Fixed usdr_registers startup script. --- src/dmonitor/usdr_registers | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmonitor/usdr_registers b/src/dmonitor/usdr_registers index 26eab4c2..eb51d7f7 100755 --- a/src/dmonitor/usdr_registers +++ b/src/dmonitor/usdr_registers @@ -1,3 +1,3 @@ #!/usr/bin/env sh -exec /usr/bin/env python3 /usr/libexec/usdr_dmonitor/registers_widget.py +exec /usr/bin/env python3 /usr/libexec/usdr_dmonitor/registers_widget.py "$@" From 6bfad77ca6ddbbe75a1cfea66cd006d4101624d0 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Fri, 9 Jan 2026 22:08:03 +0300 Subject: [PATCH 276/397] intermediate commit, cleaning needed: --- src/lib/xdsp/CMakeLists.txt | 1 + src/lib/xdsp/conv.c | 6 + src/lib/xdsp/conv_3ci16_ci16_2.c | 10 + src/lib/xdsp/conv_ci16_3cf32_2.c | 8 + src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t | 112 ++++++++++ .../templates/conv_3ci16_ci16_generic.inc | 14 ++ .../xdsp/templates/conv_3ci16_ci16_generic.t | 18 +- src/lib/xdsp/templates/conv_ci16_3cf32_avx2.t | 80 +++++++ .../templates/conv_ci16_3cf32_generic.inc | 18 ++ .../xdsp/templates/conv_ci16_3cf32_generic.t | 23 +- src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t | 126 +++++++++++ .../templates/conv_ci16_3ci16_generic.inc | 12 + .../xdsp/templates/conv_ci16_3ci16_generic.t | 21 ++ src/lib/xdsp/utests/CMakeLists.txt | 6 + src/lib/xdsp/utests/conv_3ci16_ci16_utest.c | 194 ++++++++++++++++ src/lib/xdsp/utests/conv_ci16_3cf32_utest.c | 207 ++++++++++++++++++ src/lib/xdsp/utests/conv_ci16_3ci16_utest.c | 207 ++++++++++++++++++ src/lib/xdsp/utests/xdsp_utest_suite.c | 12 +- 18 files changed, 1035 insertions(+), 40 deletions(-) create mode 100644 src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t create mode 100644 src/lib/xdsp/templates/conv_3ci16_ci16_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci16_3cf32_avx2.t create mode 100644 src/lib/xdsp/templates/conv_ci16_3cf32_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t create mode 100644 src/lib/xdsp/templates/conv_ci16_3ci16_generic.inc create mode 100644 src/lib/xdsp/templates/conv_ci16_3ci16_generic.t create mode 100644 src/lib/xdsp/utests/conv_3ci16_ci16_utest.c create mode 100644 src/lib/xdsp/utests/conv_ci16_3cf32_utest.c create mode 100644 src/lib/xdsp/utests/conv_ci16_3ci16_utest.c diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index 300b1977..94cbaca8 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -46,6 +46,7 @@ set(xdsplib_conv_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_6cf32_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8cf32_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_8ci16_2.c + ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_3ci16_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_ci16_3cf32_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_3cf32_ci16_2.c ${CMAKE_CURRENT_SOURCE_DIR}/conv_3ci16_ci16_2.c diff --git a/src/lib/xdsp/conv.c b/src/lib/xdsp/conv.c index f688e6f1..74a2c5ee 100644 --- a/src/lib/xdsp/conv.c +++ b/src/lib/xdsp/conv.c @@ -35,6 +35,7 @@ #include "conv_ci16_8ci16_2.h" #include "conv_ci16_3cf32_2.h" +#include "conv_ci16_3ci16_2.h" #include "conv_3cf32_ci16_2.h" #include "conv_3ci16_ci16_2.h" @@ -272,6 +273,11 @@ transform_info_t get_transform_fn(const char* from, /* Interleave 1 -> 3 */ if(inveccnt == 1 && outveccnt == 3) { + if (isCI16(from) && isCI16(to)) { + transform_info_t l_conv_ci16_3ci16 = { conv_get_ci16_3ci16(), tr_dummy_sz }; + return l_conv_ci16_3ci16; + } + if (isCI16(from) && isCF32(to)) { transform_info_t l_conv_ci16_3f32 = { conv_get_ci16_3cf32(), tr_conv_i16_f32_sz }; return l_conv_ci16_3f32; diff --git a/src/lib/xdsp/conv_3ci16_ci16_2.c b/src/lib/xdsp/conv_3ci16_ci16_2.c index dd665e3c..29b8b46f 100644 --- a/src/lib/xdsp/conv_3ci16_ci16_2.c +++ b/src/lib/xdsp/conv_3ci16_ci16_2.c @@ -4,17 +4,27 @@ #include "conv_3ci16_ci16_2.h" #include "attribute_switch.h" +//#include + #define TEMPLATE_FUNC_NAME conv_3ci16_ci16_generic VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_3ci16_ci16_generic.t" DECLARE_TR_FUNC_3_1(conv_3ci16_ci16_generic) +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_3ci16_ci16_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_3ci16_ci16_avx2.t" +DECLARE_TR_FUNC_3_1(conv_3ci16_ci16_avx2) +#endif + conv_function_t conv_get_3ci16_ci16_c(generic_opts_t cpu_cap, const char** sfunc) { const char* fname; conv_function_t fn; SELECT_GENERIC_FN(fn, fname, tr_conv_3ci16_ci16_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_3ci16_ci16_avx2, cpu_cap); if (sfunc) *sfunc = fname; return fn; diff --git a/src/lib/xdsp/conv_ci16_3cf32_2.c b/src/lib/xdsp/conv_ci16_3cf32_2.c index 15f6624f..a803e35e 100644 --- a/src/lib/xdsp/conv_ci16_3cf32_2.c +++ b/src/lib/xdsp/conv_ci16_3cf32_2.c @@ -11,12 +11,20 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_ci16_3cf32_generic.t" DECLARE_TR_FUNC_1_3(conv_ci16_3cf32_generic) +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_ci16_3cf32_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_ci16_3cf32_avx2.t" +DECLARE_TR_FUNC_1_3(conv_ci16_3cf32_avx2) +#endif + conv_function_t conv_get_ci16_3cf32_c(generic_opts_t cpu_cap, const char** sfunc) { const char* fname; conv_function_t fn; SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_3cf32_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_ci16_3cf32_avx2, cpu_cap); if (sfunc) *sfunc = fname; return fn; diff --git a/src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t b/src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t new file mode 100644 index 00000000..8d5cc5ff --- /dev/null +++ b/src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t @@ -0,0 +1,112 @@ + +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + const void *__restrict indata_2_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + +#if 0 + typedef uint16_t v16si __attribute__ ((vector_size (32))); + union u_v16si { __m256i vect; v16si arr; }; + typedef union u_v16si u_v16si_t; + +#define RPRINT(reg) \ +{ \ + u_v16si_t p = {reg}; \ + for(int i = 15; i >= 0; --i) \ + { \ + printf("%2d ", p.arr[i]); \ + } \ + printf("\n"); \ +} + +#define RPRINT3(title, r0, r1, r2) \ +{ \ + printf("%s:\n", title); \ + RPRINT(r0); \ + RPRINT(r1); \ + RPRINT(r2); \ +} + +#else +#define RPRINT3(title, r0, r1, r2) {} +#endif + + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + const int16_t* indata_0 = (int16_t*)indata_0_p; + const int16_t* indata_1 = (int16_t*)indata_1_p; + const int16_t* indata_2 = (int16_t*)indata_2_p; + int16_t* outdata = (int16_t*)outdata_p; + + // + const __m256i mask0 = _mm256_set_epi32(-1, 0, -1, 0, -1, 0, -1, 0); + const __m256i mask1 = _mm256_set_epi32(0, -1, 0, -1, 0, -1, 0, -1); + + for (; i >= 32 * 3; i -= 32 * 3) + { + __m256i r0 = _mm256_load_si256((__m256i*)indata_0); + __m256i r1 = _mm256_load_si256((__m256i*)indata_1); + __m256i r2 = _mm256_load_si256((__m256i*)indata_2); + + indata_0 += 16; + indata_1 += 16; + indata_2 += 16; + + RPRINT3("init",r0,r1,r2); + + //(0) + __m256d ulo, uhi; + ulo = _mm256_castsi256_pd(_mm256_unpacklo_epi32(r0, r1)); + uhi = _mm256_castsi256_pd(_mm256_unpackhi_epi32(r0, r1)); + __m256i rs0 = _mm256_castpd_si256(_mm256_shuffle_pd(ulo, uhi, 0b0000)); + + ulo = _mm256_castsi256_pd(_mm256_unpacklo_epi32(r1, r2)); + uhi = _mm256_castsi256_pd(_mm256_unpackhi_epi32(r1, r2)); + __m256i rs2 = _mm256_castpd_si256(_mm256_shuffle_pd(ulo, uhi, 0b1111)); + + __m256i rs1 = _mm256_or_si256(_mm256_and_si256(r0, mask0), _mm256_and_si256(r2, mask1)); + + RPRINT3("(0)",rs0,rs1,rs2); + + //(1) + __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b0000)); + __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b1111)); + __m256i z2 = rs2; + + __m256i zz0 = z0; + __m256i zz1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b0000)); + __m256i zz2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b1111)); + + zz1 = _mm256_shuffle_epi32(zz1, _MM_SHUFFLE(1,0,3,2)); + + RPRINT3("(1)",zz0,zz1,zz2); + + //(2) + __m256i x0 = _mm256_permute2x128_si256(zz0, zz1, 0b00100000); + __m256i x1 = _mm256_permute2x128_si256(zz0, zz1, 0b00110001); + __m256i x2 = zz2; + + __m256i xx0 = x0; + __m256i xx1 = _mm256_permute2x128_si256(x1, x2, 0b00100000); + __m256i xx2 = _mm256_permute2x128_si256(x1, x2, 0b00110001); + + xx1 = _mm256_permute2x128_si256(xx1, xx1, 0x1); + + RPRINT3("(2)",xx0,xx1,xx2); + + _mm256_storeu_si256((__m256i*)(outdata + 0), xx0); + _mm256_storeu_si256((__m256i*)(outdata + 16), xx1); + _mm256_storeu_si256((__m256i*)(outdata + 32), xx2); + outdata += 48; + } + + #include "conv_3ci16_ci16_generic.inc" +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_3ci16_ci16_generic.inc b/src/lib/xdsp/templates/conv_3ci16_ci16_generic.inc new file mode 100644 index 00000000..162ee1fa --- /dev/null +++ b/src/lib/xdsp/templates/conv_3ci16_ci16_generic.inc @@ -0,0 +1,14 @@ + for (; i >= 12; i -= 12, indata_0 += 2, indata_1 += 2, indata_2 += 2, outdata += 6) { + int16_t a = indata_0[0]; + int16_t b = indata_0[1]; + int16_t c = indata_1[0]; + int16_t d = indata_1[1]; + int16_t e = indata_2[0]; + int16_t f = indata_2[1]; + + uint64_t v = (uint64_t)(uint16_t)a | ((uint64_t)(uint16_t)b << 16) | ((uint64_t)(uint16_t)c << 32) | ((uint64_t)(uint16_t)d << 48); + uint32_t w = (uint32_t)(uint16_t)e | ((uint32_t)(uint16_t)f << 16); + *(uint64_t*)outdata = v; + *(uint32_t*)(outdata + 4) = w; + } + // do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_3ci16_ci16_generic.t b/src/lib/xdsp/templates/conv_3ci16_ci16_generic.t index 0f4988f0..396ffc43 100644 --- a/src/lib/xdsp/templates/conv_3ci16_ci16_generic.t +++ b/src/lib/xdsp/templates/conv_3ci16_ci16_generic.t @@ -14,23 +14,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, const int16_t* indata_0 = (int16_t*)indata_0_p; const int16_t* indata_1 = (int16_t*)indata_1_p; const int16_t* indata_2 = (int16_t*)indata_2_p; - int16_t* outdata = (int16_t*)outdata_p; - - for (; i >= 12; i -= 12, indata_0 += 2, indata_1 += 2, indata_2 += 2, outdata += 6) { - int16_t a = indata_0[0]; - int16_t b = indata_0[1]; - int16_t c = indata_1[0]; - int16_t d = indata_1[1]; - int16_t e = indata_2[0]; - int16_t f = indata_2[1]; - uint64_t v = (uint64_t)(uint16_t)a | ((uint64_t)(uint16_t)b << 16) | ((uint64_t)(uint16_t)c << 32) | ((uint64_t)(uint16_t)d << 48); - uint32_t w = (uint32_t)(uint16_t)e | ((uint32_t)(uint16_t)f << 16); - *(uint64_t*)outdata = v; - *(uint32_t*)(outdata + 4) = w; - } - - // do nothing with leftover + int16_t* outdata = (int16_t*)outdata_p; + #include "conv_3ci16_ci16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_3cf32_avx2.t b/src/lib/xdsp/templates/conv_ci16_3cf32_avx2.t new file mode 100644 index 00000000..c2f58d88 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_3cf32_avx2.t @@ -0,0 +1,80 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz / 2) < i) + i = (outdatabsz / 2); + + float* outdata_0 = (float*)outdata_0_p; + float* outdata_1 = (float*)outdata_1_p; + float* outdata_2 = (float*)outdata_2_p; + + const __m256 scale = _mm256_set1_ps(CONV_SCALE); + const __m256i * inptr = (const __m256i*)indata; + +/* + r0: DCBA DCBA HGBA HGBA JGDA + r1: HGFE -> permute2x128_si256 -> FEHG permute2x128_si256 -> JIDC -> shuffle_epi32 -> IJCD -> _mm256_shuffle_pd -> KHEB + r2: LKJI LKJI LKFE LKJI LIFC +*/ + +#define CONV_3CF32(r0, r1, r2) \ +{ \ + r1 = _mm256_permute2x128_si256(r1, r1, 0x1); \ + \ + __m256i x0 = _mm256_permute2x128_si256(r0, r1, 0b00100000); \ + __m256i x1 = _mm256_permute2x128_si256(r0, r1, 0b00110001); \ + __m256i x2 = r2; \ + \ + __m256i xx0 = x0; \ + __m256i xx1 = _mm256_permute2x128_si256(x1, x2, 0b00100000); \ + __m256i xx2 = _mm256_permute2x128_si256(x1, x2, 0b00110001); \ + \ + xx1 = _mm256_shuffle_epi32(xx1, _MM_SHUFFLE(1,0,3,2)); \ + \ + __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(xx0), _mm256_castsi256_pd(xx1), 0b0000)); \ + __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(xx0), _mm256_castsi256_pd(xx1), 0b1111)); \ + __m256i z2 = xx2; \ + \ + __m256i zz0 = z0; \ + __m256i zz1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b0000)); \ + __m256i zz2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b1111)); \ + \ + _mm256_store_ps(outdata_0, _mm256_mul_ps(_mm256_cvtepi32_ps(zz0), scale)); \ + _mm256_store_ps(outdata_1, _mm256_mul_ps(_mm256_cvtepi32_ps(zz1), scale)); \ + _mm256_store_ps(outdata_2, _mm256_mul_ps(_mm256_cvtepi32_ps(zz2), scale)); \ + \ + outdata_0 += 8; \ + outdata_1 += 8; \ + outdata_2 += 8; \ +} + + for (; i >= 32 * 3; i -= 32 * 3) + { + __m256i a0 = _mm256_loadu_si256(inptr++); + __m256i a1 = _mm256_loadu_si256(inptr++); + __m256i a2 = _mm256_loadu_si256(inptr++); + + __m256i b0 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(a0)); + __m256i b1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(a0, 1)); + __m256i b2 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(a1)); + __m256i b3 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(a1,1)); + __m256i b4 = _mm256_cvtepi16_epi32(_mm256_castsi256_si128(a2)); + __m256i b5 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(a2, 1)); + + CONV_3CF32(b0, b1, b2); + CONV_3CF32(b3, b4, b5); + } + +#undef CONV_3CF32 + + const uint32_t *ld = (const uint32_t *)inptr; + #include "conv_ci16_3cf32_generic.inc" +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_3cf32_generic.inc b/src/lib/xdsp/templates/conv_ci16_3cf32_generic.inc new file mode 100644 index 00000000..e46ea903 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_3cf32_generic.inc @@ -0,0 +1,18 @@ + for (; i >= 12; i -= 12, ld += 3) { + uint64_t v = *((uint64_t*)ld); + uint32_t w = *(ld + 2); + float a = (int16_t)(v); + float b = (int16_t)(v>>16); + float c = (int16_t)(v>>32); + float d = (int16_t)(v>>48); + float e = (int16_t)(w); + float f = (int16_t)(w>>16); + + *(outdata_0++) = a * CONV_SCALE; + *(outdata_0++) = b * CONV_SCALE; + *(outdata_1++) = c * CONV_SCALE; + *(outdata_1++) = d * CONV_SCALE; + *(outdata_2++) = e * CONV_SCALE; + *(outdata_2++) = f * CONV_SCALE; + } + // do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_ci16_3cf32_generic.t b/src/lib/xdsp/templates/conv_ci16_3cf32_generic.t index 227d0871..2d3ab1b8 100644 --- a/src/lib/xdsp/templates/conv_ci16_3cf32_generic.t +++ b/src/lib/xdsp/templates/conv_ci16_3cf32_generic.t @@ -10,31 +10,12 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, if ((outdatabsz / 2) < i) i = (outdatabsz / 2); - const uint32_t *ld = (const uint32_t *)indata; - float* outdata_0 = (float*)outdata_0_p; float* outdata_1 = (float*)outdata_1_p; float* outdata_2 = (float*)outdata_2_p; - for (; i >= 12; i -= 12, ld += 3) { - uint64_t v = *((uint64_t*)ld); - uint32_t w = *(ld + 2); - float a = (int16_t)(v); - float b = (int16_t)(v>>16); - float c = (int16_t)(v>>32); - float d = (int16_t)(v>>48); - float e = (int16_t)(w); - float f = (int16_t)(w>>16); - - *(outdata_0++) = a * CONV_SCALE; - *(outdata_0++) = b * CONV_SCALE; - *(outdata_1++) = c * CONV_SCALE; - *(outdata_1++) = d * CONV_SCALE; - *(outdata_2++) = e * CONV_SCALE; - *(outdata_2++) = f * CONV_SCALE; - } - - // do nothing with leftover + const uint32_t *ld = (const uint32_t *)indata; + #include "conv_ci16_3cf32_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t b/src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t new file mode 100644 index 00000000..9e1d30c2 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t @@ -0,0 +1,126 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + unsigned outdatabsz) +{ +#if 0 + typedef uint16_t v16si __attribute__ ((vector_size (32))); + union u_v16si { __m256i vect; v16si arr; }; + typedef union u_v16si u_v16si_t; + +#define RPRINT(reg) \ +{ \ + u_v16si_t p = {reg}; \ + for(int i = 15; i >= 0; --i) \ + { \ + printf("%2d ", p.arr[i]); \ + } \ + printf("\n"); \ +} + +#define RPRINT3(title, r0, r1, r2) \ +{ \ + printf("%s:\n", title); \ + RPRINT(r0); \ + RPRINT(r1); \ + RPRINT(r2); \ +} + +#else +#define RPRINT3(title, r0, r1, r2) {} +#endif + + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + int16_t* outdata_0 = (int16_t*)outdata_0_p; + int16_t* outdata_1 = (int16_t*)outdata_1_p; + int16_t* outdata_2 = (int16_t*)outdata_2_p; + + const __m256i mask0 = _mm256_set_epi32(-1, 0, -1, 0, -1, 0, -1, 0); + const __m256i mask1 = _mm256_set_epi32(0, -1, 0, -1, 0, -1, 0, -1); + const __m256i * inptr = (const __m256i*)indata; + +/* +r0: HGFEDCBA HGFEDCBA 3210DCBA 3210DCBA 7610HGBA 7610HGBA 9630JGDA +r1: 3210LKJI -0- LKJI3210 -1- 7654HGFE -2- 5476FEHG -3- 9832JIDC -4- 8923IJCD -5- a741KHEB +r2: ba987654 ba987654 ba98LKJI ba98LKJI ba54LKFE ba54LKFE b852LIFC +*/ + + for (; i >= 32 * 3; i -= 32 * 3) + { + __m256i r0 = _mm256_loadu_si256(inptr++); + __m256i r1 = _mm256_loadu_si256(inptr++); + __m256i r2 = _mm256_loadu_si256(inptr++); + + RPRINT3("init",r0,r1,r2); + + //(0) + r1 = _mm256_permute2x128_si256(r1, r1, 0x1); + RPRINT3("(0)",r0,r1,r2); + + + //(1) + __m256i x0 = _mm256_permute2x128_si256(r0, r1, 0b00100000); + __m256i x1 = _mm256_permute2x128_si256(r0, r1, 0b00110001); + __m256i x2 = r2; + + __m256i xx0 = x0; + __m256i xx1 = _mm256_permute2x128_si256(x1, x2, 0b00100000); + __m256i xx2 = _mm256_permute2x128_si256(x1, x2, 0b00110001); + RPRINT3("(1)",xx0,xx1,xx2); + + + //(2) + xx1 = _mm256_shuffle_epi32(xx1, _MM_SHUFFLE(1,0,3,2)); + RPRINT3("(2)",xx0,xx1,xx2); + + + //(3) + __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(xx0), _mm256_castsi256_pd(xx1), 0b0000)); + __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(xx0), _mm256_castsi256_pd(xx1), 0b1111)); + __m256i z2 = xx2; + + __m256i zz0 = z0; + __m256i zz1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b0000)); + __m256i zz2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b1111)); + RPRINT3("(3)",zz0,zz1,zz2); + + + //(4) + zz1 = _mm256_shuffle_epi32(zz1, _MM_SHUFFLE(2,3,0,1)); + RPRINT3("(4)",zz0,zz1,zz2); + + //(5) + + __m256d ulo, uhi; + ulo = _mm256_castsi256_pd(_mm256_unpacklo_epi32(zz0, zz1)); + uhi = _mm256_castsi256_pd(_mm256_unpackhi_epi32(zz0, zz1)); + __m256i rs0 = _mm256_castpd_si256(_mm256_shuffle_pd(ulo, uhi, 0b0000)); + + ulo = _mm256_castsi256_pd(_mm256_unpacklo_epi32(zz1, zz2)); + uhi = _mm256_castsi256_pd(_mm256_unpackhi_epi32(zz1, zz2)); + __m256i rs2 = _mm256_castpd_si256(_mm256_shuffle_pd(ulo, uhi, 0b1111)); + + __m256i rs1 = _mm256_or_si256(_mm256_and_si256(zz0, mask0), _mm256_and_si256(zz2, mask1)); + rs1 = _mm256_shuffle_epi32(rs1, _MM_SHUFFLE(2,3,0,1)); + RPRINT3("(5)",rs0,rs1,rs2); + + _mm256_store_si256((__m256i*)outdata_0, rs0); + _mm256_store_si256((__m256i*)outdata_1, rs1); + _mm256_store_si256((__m256i*)outdata_2, rs2); + + outdata_0 += 16; + outdata_1 += 16; + outdata_2 += 16; + } + + const uint32_t *ld = (const uint32_t *)inptr; + #include "conv_ci16_3ci16_generic.inc" +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_ci16_3ci16_generic.inc b/src/lib/xdsp/templates/conv_ci16_3ci16_generic.inc new file mode 100644 index 00000000..5aaae27b --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_3ci16_generic.inc @@ -0,0 +1,12 @@ + for (; i >= 12; i -= 12, ld += 3) { + uint64_t v = *((uint64_t*)ld); + uint32_t w = *(ld + 2); + + *(outdata_0++) = (int16_t)(v); + *(outdata_0++) = (int16_t)(v>>16); + *(outdata_1++) = (int16_t)(v>>32); + *(outdata_1++) = (int16_t)(v>>48); + *(outdata_2++) = (int16_t)(w); + *(outdata_2++) = (int16_t)(w>>16); + } + // do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_ci16_3ci16_generic.t b/src/lib/xdsp/templates/conv_ci16_3ci16_generic.t new file mode 100644 index 00000000..54261060 --- /dev/null +++ b/src/lib/xdsp/templates/conv_ci16_3ci16_generic.t @@ -0,0 +1,21 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata, + unsigned indatabsz, + void *__restrict outdata_0_p, + void *__restrict outdata_1_p, + void *__restrict outdata_2_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz) < i) + i = (outdatabsz); + + int16_t* outdata_0 = (int16_t*)outdata_0_p; + int16_t* outdata_1 = (int16_t*)outdata_1_p; + int16_t* outdata_2 = (int16_t*)outdata_2_p; + + const uint32_t *ld = (const uint32_t *)indata; + #include "conv_ci16_3ci16_generic.inc" +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/CMakeLists.txt b/src/lib/xdsp/utests/CMakeLists.txt index bfdaca91..d7adc524 100644 --- a/src/lib/xdsp/utests/CMakeLists.txt +++ b/src/lib/xdsp/utests/CMakeLists.txt @@ -34,6 +34,9 @@ set(TEST_SUIT_SRCS conv_4ci16_ci12_utest.c conv_ci16_6ci16_utest.c conv_ci16_6cf32_utest.c + conv_ci16_3cf32_utest.c + conv_ci16_3ci16_utest.c + conv_3ci16_ci16_utest.c ../fft_window_functions.c ../fftad_functions.c @@ -65,6 +68,9 @@ set(TEST_SUIT_SRCS ../conv_4ci16_ci12_2.c ../conv_ci16_6ci16_2.c ../conv_ci16_6cf32_2.c + ../conv_ci16_3cf32_2.c + ../conv_ci16_3ci16_2.c + ../conv_3ci16_ci16_2.c ../vbase.c ) diff --git a/src/lib/xdsp/utests/conv_3ci16_ci16_utest.c b/src/lib/xdsp/utests/conv_3ci16_ci16_utest.c new file mode 100644 index 00000000..2c2e0a4f --- /dev/null +++ b/src/lib/xdsp/utests/conv_3ci16_ci16_utest.c @@ -0,0 +1,194 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_3ci16_ci16_2.h" + +#undef DEBUG_PRINT + +#define PACKET_SIZE (65536u) +#define OUT_BZ (PACKET_SIZE * sizeof(int16_t)) + +static const unsigned packet_lens[4] = { 8192u, 16384u, 32768u, PACKET_SIZE }; + +#define SPEED_MEASURE_ITERS 1000000 + +static int16_t* in_0 = NULL; +static int16_t* in_1 = NULL; +static int16_t* in_2 = NULL; +static int16_t* in[3] = {NULL, NULL, NULL}; + +static int16_t* out = NULL; +static int16_t* out_etalon = NULL; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, OUT_BZ / 3); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, OUT_BZ / 3); + res = res ? res : posix_memalign((void**)&in_2, ALIGN_BYTES, OUT_BZ / 3); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); + + in[0] = in_0; + in[1] = in_1; + in[2] = in_2; + + //fill + int16_t *p0 = in_0; + int16_t *p1 = in_1; + int16_t *p2 = in_2; + + srand( time(0) ); + + for(int i = 0; i < PACKET_SIZE; i += 6) + { + /* + *p0++ = (i + 0); + *p0++ = (i + 1); + *p1++ = (i + 2); + *p1++ = (i + 3); + *p2++ = (i + 4); + *p2++ = (i + 5); + */ + int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; + *p0++ = sign * (i + 0); + *p0++ = -sign * (i + 1); + *p1++ = -sign * (i + 2); + *p1++ = sign * (i + 3); + *p2++ = sign * (i + 4); + *p2++ = -sign * (i + 5); + } +} + +static void teardown() +{ + free(in_0); + free(in_1); + free(in_2); + free(out); + free(out_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_3ci16_ci16_c, &last_fn_name); +} + +static void print_data(const char* header) +{ + if(header) + fprintf(stderr, "%s:", header); + + for(unsigned n = 0; n < 3; ++n) + { + fprintf(stderr, "\n in%d: ", n); + for(unsigned i = 0; i < 8; ++i) + { + fprintf(stderr, "%4d ", in[n][i]); + } + } + + fprintf(stderr, "\n out: "); + for(unsigned i = 0; i < 24; ++i) + { + fprintf(stderr, "%d ", out[i]); + } + fprintf(stderr, "\n"); +} + +START_TEST(conv_3ci16_ci16_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void** pin = (const void**)in; + void* pout = (void*)out; + last_fn_name = NULL; + + const size_t bzin = OUT_BZ; + const size_t bzout = OUT_BZ; + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(out, 0, bzout); + (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); + memcpy(out_etalon, out, bzout); + +#ifdef DEBUG_PRINT + print_data("ETALON DATA"); +#endif + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out, 0, bzout); + (*fn)(pin, bzin, &pout, bzout); +#ifdef DEBUG_PRINT + print_data(NULL); +#endif + int res = memcmp(out, out_etalon, bzout); + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_3ci16_ci16_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void** pin = (const void**)in; + void* pout = (void*)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i] * sizeof(int16_t); + const size_t bzout = bzin; + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(pin, bzin, &pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(pin, bzin, &pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_3ci16_ci16_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_3ci16_ci16"); + + ADD_REGRESS_TEST(s, conv_3ci16_ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_3ci16_ci16_speed, 60, 0, 4); + + return s; +} diff --git a/src/lib/xdsp/utests/conv_ci16_3cf32_utest.c b/src/lib/xdsp/utests/conv_ci16_3cf32_utest.c new file mode 100644 index 00000000..539e16b5 --- /dev/null +++ b/src/lib/xdsp/utests/conv_ci16_3cf32_utest.c @@ -0,0 +1,207 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_ci16_3cf32_2.h" + +#undef DEBUG_PRINT + +#define WORD_COUNT (4098u) +#define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) + +#define SPEED_WORD_COUNT (32768u) +#define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) + +static const unsigned packet_lens[3] = { 1024, 16384, SPEED_SIZE_BZ }; + +#define SPEED_MEASURE_ITERS 1000000 + +static int16_t* in = NULL; +static float* out1 = NULL; +static float* out1_etalon = NULL; +static float* out2 = NULL; +static float* out2_etalon = NULL; +static float* out3 = NULL; +static float* out3_etalon = NULL; + +static float* out[3] = {NULL, NULL, NULL}; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(float) * SPEED_WORD_COUNT/3); + ck_assert_int_eq(res, 0); + + out[0] = out1; + out[1] = out2; + out[2] = out3; + + srand( time(0) ); + + //fill + int16_t n = 0; + for(unsigned i = 0; i < SPEED_WORD_COUNT; ++i) + { + int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; + in[i] = sign * 32767 * (float)(rand()) / (float)RAND_MAX; + } +#if 0 + for(unsigned i = 0; i < WORD_COUNT; ++i) + { + fprintf(stderr, "%x\n", pin[i]); + } +#endif +} + +static void teardown() +{ + free(in); + free(out1); + free(out1_etalon); + free(out2); + free(out2_etalon); + free(out3); + free(out3_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_ci16_3cf32_c, &last_fn_name); +} + +static void print_data(const char* header) +{ + if(header) + fprintf(stderr, "%s:", header); + + fprintf(stderr, "\n in: "); + for(unsigned i = 0; i < 24; ++i) + { + //fprintf(stderr, "%d ", in[i]); + fprintf(stderr, "%.4f ", (double)in[i] / 32767.f); + } + + for(unsigned n = 0; n < 3; ++n) + { + fprintf(stderr, "\n out%d: ", n); + for(unsigned i = 0; i < 8; ++i) + { + fprintf(stderr, "%+.4f ", out[n][i]); + } + } + fprintf(stderr, "\n"); +} + +#define CONV_SCALE (1.0f/32767) + +START_TEST(conv_ci16_3cf32_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = IN_STREAM_SIZE_BZ; + const size_t bzout = WORD_COUNT * sizeof(float); + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(out[0], 0, bzout / 3); + memset(out[1], 0, bzout / 3); + memset(out[2], 0, bzout / 3); + (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); + memcpy(out1_etalon, out[0], bzout / 3); + memcpy(out2_etalon, out[1], bzout / 3); + memcpy(out3_etalon, out[2], bzout / 3); + +#ifdef DEBUG_PRINT + print_data("ETALON"); +#endif + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out[0], 0, bzout / 3); + memset(out[1], 0, bzout / 3); + memset(out[2], 0, bzout / 3); + (*fn)(&pin, bzin, pout, bzout); + + int res = memcmp(out[0], out1_etalon, bzout / 3) || + memcmp(out[1], out2_etalon, bzout / 3) || + memcmp(out[2], out3_etalon, bzout / 3); + + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); + +#ifdef DEBUG_PRINT + print_data("TEST"); +#endif + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_ci16_3cf32_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i]; + const size_t bzout = SPEED_WORD_COUNT * sizeof(float); + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(&pin, bzin, pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_ci16_3cf32_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_ci16_3cf32"); + + ADD_REGRESS_TEST(s, conv_ci16_3cf32_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_3cf32_speed, 60, 0, 3); + + return s; +} diff --git a/src/lib/xdsp/utests/conv_ci16_3ci16_utest.c b/src/lib/xdsp/utests/conv_ci16_3ci16_utest.c new file mode 100644 index 00000000..bf2b5498 --- /dev/null +++ b/src/lib/xdsp/utests/conv_ci16_3ci16_utest.c @@ -0,0 +1,207 @@ +// Copyright (c) 2025 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_ci16_3ci16_2.h" + +#undef DEBUG_PRINT + +#define WORD_COUNT (4098u) +#define IN_STREAM_SIZE_BZ (WORD_COUNT * sizeof(int16_t)) + +#define SPEED_WORD_COUNT (32768u) +#define SPEED_SIZE_BZ (SPEED_WORD_COUNT * sizeof(int16_t)) + +static const unsigned packet_lens[3] = { 1024, 16384, SPEED_SIZE_BZ }; + +#define SPEED_MEASURE_ITERS 1000000 + +static int16_t* in = NULL; +static int16_t* out1 = NULL; +static int16_t* out1_etalon = NULL; +static int16_t* out2 = NULL; +static int16_t* out2_etalon = NULL; +static int16_t* out3 = NULL; +static int16_t* out3_etalon = NULL; + +static int16_t* out[3] = {NULL, NULL, NULL}; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + res = res ? res : posix_memalign((void**)&in, ALIGN_BYTES, SPEED_SIZE_BZ); + res = res ? res : posix_memalign((void**)&out1, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out1_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out2, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out2_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out3, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/3); + res = res ? res : posix_memalign((void**)&out3_etalon, ALIGN_BYTES, sizeof(int16_t) * SPEED_WORD_COUNT/3); + ck_assert_int_eq(res, 0); + + out[0] = out1; + out[1] = out2; + out[2] = out3; + + srand( time(0) ); + + //fill + int16_t n = 0; + for(unsigned i = 0; i < SPEED_WORD_COUNT; ++i) + { + int sign = (float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1; + in[i] = sign * 32767 * (float)(rand()) / (float)RAND_MAX; + //in[i] = i; + } +#if 0 + for(unsigned i = 0; i < WORD_COUNT; ++i) + { + fprintf(stderr, "%x\n", pin[i]); + } +#endif +} + +static void teardown() +{ + free(in); + free(out1); + free(out1_etalon); + free(out2); + free(out2_etalon); + free(out3); + free(out3_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_ci16_3ci16_c, &last_fn_name); +} + +static void print_data(const char* header) +{ + if(header) + fprintf(stderr, "%s:", header); + + fprintf(stderr, "\n in: "); + for(unsigned i = 0; i < 24; ++i) + { + fprintf(stderr, "%d ", in[i]); + } + + for(unsigned n = 0; n < 3; ++n) + { + fprintf(stderr, "\n out%d: ", n); + for(unsigned i = 0; i < 8; ++i) + { + fprintf(stderr, "%d ", out[n][i]); + } + } + fprintf(stderr, "\n"); +} + +#define CONV_SCALE (1.0f/32767) + +START_TEST(conv_ci16_3ci16_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = IN_STREAM_SIZE_BZ; + const size_t bzout = WORD_COUNT * sizeof(int16_t); + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(out[0], 0, bzout / 3); + memset(out[1], 0, bzout / 3); + memset(out[2], 0, bzout / 3); + (*get_fn(OPT_GENERIC, 0))(&pin, bzin, pout, bzout); + memcpy(out1_etalon, out[0], bzout / 3); + memcpy(out2_etalon, out[1], bzout / 3); + memcpy(out3_etalon, out[2], bzout / 3); + +#ifdef DEBUG_PRINT + print_data("ETALON"); +#endif + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out[0], 0, bzout / 3); + memset(out[1], 0, bzout / 3); + memset(out[2], 0, bzout / 3); + (*fn)(&pin, bzin, pout, bzout); + + int res = memcmp(out[0], out1_etalon, bzout / 3) || + memcmp(out[1], out2_etalon, bzout / 3) || + memcmp(out[2], out3_etalon, bzout / 3); + + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); + +#ifdef DEBUG_PRINT + print_data("TEST"); +#endif + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_ci16_3ci16_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void* pin = (const void*)in; + void** pout = (void**)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i]; + const size_t bzout = SPEED_WORD_COUNT * sizeof(int16_t); + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(&pin, bzin, pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(&pin, bzin, pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_ci16_3ci16_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_ci16_3ci16"); + + ADD_REGRESS_TEST(s, conv_ci16_3ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_ci16_3ci16_speed, 60, 0, 3); + + return s; +} diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index 24a86ebc..dee066bb 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -37,6 +37,9 @@ Suite * conv_ci16_6ci16_suite(void); Suite * conv_ci16_6cf32_suite(void); Suite * conv_ci16_8cf32_suite(void); Suite * conv_ci16_8ci16_suite(void); +Suite * conv_ci16_3cf32_suite(void); +Suite * conv_ci16_3ci16_suite(void); +Suite * conv_3ci16_ci16_suite(void); int main(int argc, char** argv) { @@ -46,7 +49,7 @@ int main(int argc, char** argv) int number_failed; SRunner *sr; -#if 1 +#if 0 sr = srunner_create( fftad_suite()); srunner_add_suite(sr, rtsa_suite()); srunner_add_suite(sr, fft_window_cf32_suite()); @@ -54,8 +57,10 @@ int main(int argc, char** argv) // srunner_add_suite(sr, conv_i16_f32_suite()); srunner_add_suite(sr, conv_ci16_2cf32_suite()); + srunner_add_suite(sr, conv_ci16_3cf32_suite()); srunner_add_suite(sr, conv_ci16_4cf32_suite()); srunner_add_suite(sr, conv_ci16_6cf32_suite()); + srunner_add_suite(sr, conv_ci16_8cf32_suite()); // srunner_add_suite(sr, conv_f32_i16_suite()); srunner_add_suite(sr, conv_2cf32_ci16_suite()); @@ -64,6 +69,7 @@ int main(int argc, char** argv) srunner_add_suite(sr, conv_ci16_2ci16_suite()); srunner_add_suite(sr, conv_ci16_4ci16_suite()); srunner_add_suite(sr, conv_ci16_6ci16_suite()); + srunner_add_suite(sr, conv_ci16_8ci16_suite()); srunner_add_suite(sr, conv_2ci16_ci16_suite()); srunner_add_suite(sr, conv_4ci16_ci16_suite()); // @@ -86,8 +92,8 @@ int main(int argc, char** argv) #else //sr = srunner_create(conv_i16_f32_suite()); //sr = srunner_create(fft_window_ci16_cf32_suite()); - sr = srunner_create(conv_ci16_8cf32_suite()); - srunner_add_suite(sr, conv_ci16_8ci16_suite()); + sr = srunner_create(conv_3ci16_ci16_suite()); + //srunner_add_suite(sr, conv_ci16_8ci16_suite()); //srunner_add_suite(sr, fft_window_cf32_suite()); //srunner_add_suite(sr, conv_f32_i12_suite()); From 6e212f5e8552951028a9c254c3c90c74665d066e Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 11 Jan 2026 22:53:59 +0300 Subject: [PATCH 277/397] final edition, cleaned and perfect --- src/lib/xdsp/conv_3cf32_ci16_2.c | 8 + src/lib/xdsp/conv_3ci16_ci16_2.c | 2 - src/lib/xdsp/conv_ci16_3ci16_2.c | 36 +++ src/lib/xdsp/conv_ci16_3ci16_2.h | 12 + src/lib/xdsp/templates/conv_3cf32_ci16_avx2.t | 91 ++++++++ .../templates/conv_3cf32_ci16_generic.inc | 14 ++ .../xdsp/templates/conv_3cf32_ci16_generic.t | 18 +- src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t | 37 --- src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t | 40 ---- src/lib/xdsp/utests/CMakeLists.txt | 2 + src/lib/xdsp/utests/conv_3cf32_ci16_utest.c | 210 ++++++++++++++++++ src/lib/xdsp/utests/xdsp_utest_suite.c | 18 +- 12 files changed, 384 insertions(+), 104 deletions(-) create mode 100644 src/lib/xdsp/conv_ci16_3ci16_2.c create mode 100644 src/lib/xdsp/conv_ci16_3ci16_2.h create mode 100644 src/lib/xdsp/templates/conv_3cf32_ci16_avx2.t create mode 100644 src/lib/xdsp/templates/conv_3cf32_ci16_generic.inc create mode 100644 src/lib/xdsp/utests/conv_3cf32_ci16_utest.c diff --git a/src/lib/xdsp/conv_3cf32_ci16_2.c b/src/lib/xdsp/conv_3cf32_ci16_2.c index 2b03f376..4ca30e51 100644 --- a/src/lib/xdsp/conv_3cf32_ci16_2.c +++ b/src/lib/xdsp/conv_3cf32_ci16_2.c @@ -11,12 +11,20 @@ VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_3cf32_ci16_generic.t" DECLARE_TR_FUNC_3_1(conv_3cf32_ci16_generic) +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_3cf32_ci16_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_3cf32_ci16_avx2.t" +DECLARE_TR_FUNC_3_1(conv_3cf32_ci16_avx2) +#endif + conv_function_t conv_get_3cf32_ci16_c(generic_opts_t cpu_cap, const char** sfunc) { const char* fname; conv_function_t fn; SELECT_GENERIC_FN(fn, fname, tr_conv_3cf32_ci16_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_3cf32_ci16_avx2, cpu_cap); if (sfunc) *sfunc = fname; return fn; diff --git a/src/lib/xdsp/conv_3ci16_ci16_2.c b/src/lib/xdsp/conv_3ci16_ci16_2.c index 29b8b46f..b12ffc5c 100644 --- a/src/lib/xdsp/conv_3ci16_ci16_2.c +++ b/src/lib/xdsp/conv_3ci16_ci16_2.c @@ -4,8 +4,6 @@ #include "conv_3ci16_ci16_2.h" #include "attribute_switch.h" -//#include - #define TEMPLATE_FUNC_NAME conv_3ci16_ci16_generic VWLT_ATTRIBUTE(optimize("-O3")) #include "templates/conv_3ci16_ci16_generic.t" diff --git a/src/lib/xdsp/conv_ci16_3ci16_2.c b/src/lib/xdsp/conv_ci16_3ci16_2.c new file mode 100644 index 00000000..a3dfbed6 --- /dev/null +++ b/src/lib/xdsp/conv_ci16_3ci16_2.c @@ -0,0 +1,36 @@ +// Copyright (c) 2026 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "conv_ci16_3ci16_2.h" +#include "attribute_switch.h" + +#define CONV_SCALE (1.0f/32767) + +#define TEMPLATE_FUNC_NAME conv_ci16_3ci16_generic +VWLT_ATTRIBUTE(optimize("-O3")) +#include "templates/conv_ci16_3ci16_generic.t" +DECLARE_TR_FUNC_1_3(conv_ci16_3ci16_generic) + +#ifdef WVLT_AVX2 +#define TEMPLATE_FUNC_NAME conv_ci16_3ci16_avx2 +VWLT_ATTRIBUTE(optimize("-O3"), target("avx2")) +#include "templates/conv_ci16_3ci16_avx2.t" +DECLARE_TR_FUNC_1_3(conv_ci16_3ci16_avx2) +#endif + +conv_function_t conv_get_ci16_3ci16_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + conv_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_conv_ci16_3ci16_generic, cpu_cap); + SELECT_AVX2_FN(fn, fname, tr_conv_ci16_3ci16_avx2, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +conv_function_t conv_get_ci16_3ci16() +{ + return conv_get_ci16_3ci16_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/conv_ci16_3ci16_2.h b/src/lib/xdsp/conv_ci16_3ci16_2.h new file mode 100644 index 00000000..d66e4366 --- /dev/null +++ b/src/lib/xdsp/conv_ci16_3ci16_2.h @@ -0,0 +1,12 @@ +// Copyright (c) 2026 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef CONV_CI16_3CI16_H +#define CONV_CI16_3CI16_H + +#include "conv.h" + +conv_function_t conv_get_ci16_3ci16(); +conv_function_t conv_get_ci16_3ci16_c(generic_opts_t cpu_cap, const char **sfunc); + +#endif //CONV_CI16_3CI16_H diff --git a/src/lib/xdsp/templates/conv_3cf32_ci16_avx2.t b/src/lib/xdsp/templates/conv_3cf32_ci16_avx2.t new file mode 100644 index 00000000..4dd1357e --- /dev/null +++ b/src/lib/xdsp/templates/conv_3cf32_ci16_avx2.t @@ -0,0 +1,91 @@ +static +void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, + const void *__restrict indata_1_p, + const void *__restrict indata_2_p, + unsigned indatabsz, + void *__restrict outdata_p, + unsigned outdatabsz) +{ + unsigned i = indatabsz; + if ((outdatabsz * 2) < i) + i = (outdatabsz * 2); + + const float* indata_0 = (const float*)indata_0_p; + const float* indata_1 = (const float*)indata_1_p; + const float* indata_2 = (const float*)indata_2_p; + int16_t* outdata = (int16_t*)outdata_p; + + const __m256 scale = _mm256_set1_ps(1.0f / CONV_SCALE); + +#define CONV_3CF32(r0, r1, r2) \ +{ \ + __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(r0), _mm256_castsi256_pd(r1), 0b0000)); \ + __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(r0), _mm256_castsi256_pd(r1), 0b1111)); \ + __m256i z2 = r2; \ + \ + __m256i zz0 = z0; \ + __m256i zz1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b0000)); \ + __m256i zz2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b1111)); \ + \ + \ + zz1 = _mm256_shuffle_epi32(zz1, _MM_SHUFFLE(1,0,3,2)); \ + \ + \ + __m256i x0 = _mm256_permute2x128_si256(zz0, zz1, 0b00100000); \ + __m256i x1 = _mm256_permute2x128_si256(zz0, zz1, 0b00110001); \ + __m256i x2 = zz2; \ + \ + r0 = x0; \ + r1 = _mm256_permute2x128_si256(x1, x2, 0b00100000); \ + r2 = _mm256_permute2x128_si256(x1, x2, 0b00110001); \ + \ + \ + r1 = _mm256_permute2x128_si256(r1, r1, 0x1); \ + \ +} + + for (; i >= 32 * 6; i -= 32 * 6) + { + __m256i a0 = _mm256_load_si256((const __m256i*)indata_0); + __m256i a1 = _mm256_load_si256((const __m256i*)indata_1); + __m256i a2 = _mm256_load_si256((const __m256i*)indata_2); + __m256i a3 = _mm256_load_si256((const __m256i*)(indata_0 + 8)); + __m256i a4 = _mm256_load_si256((const __m256i*)(indata_1 + 8)); + __m256i a5 = _mm256_load_si256((const __m256i*)(indata_2 + 8)); + indata_0 += 16; + indata_1 += 16; + indata_2 += 16; + + CONV_3CF32(a0, a1, a2); + CONV_3CF32(a3, a4, a5); + + __m256 p0 = _mm256_castsi256_ps(_mm256_permute2x128_si256(a0, a1, 0b00100000)); + __m256 p1 = _mm256_castsi256_ps(_mm256_permute2x128_si256(a0, a1, 0b00110001)); + __m256 p2 = _mm256_castsi256_ps(_mm256_permute2x128_si256(a2, a3, 0b00100000)); + __m256 p3 = _mm256_castsi256_ps(_mm256_permute2x128_si256(a2, a3, 0b00110001)); + __m256 p4 = _mm256_castsi256_ps(_mm256_permute2x128_si256(a4, a5, 0b00100000)); + __m256 p5 = _mm256_castsi256_ps(_mm256_permute2x128_si256(a4, a5, 0b00110001)); + + p0 = _mm256_mul_ps(p0, scale); + p1 = _mm256_mul_ps(p1, scale); + p2 = _mm256_mul_ps(p2, scale); + p3 = _mm256_mul_ps(p3, scale); + p4 = _mm256_mul_ps(p4, scale); + p5 = _mm256_mul_ps(p5, scale); + + __m256i res0 = _mm256_packs_epi32(_mm256_cvtps_epi32(p0), _mm256_cvtps_epi32(p1)); + __m256i res1 = _mm256_packs_epi32(_mm256_cvtps_epi32(p2), _mm256_cvtps_epi32(p3)); + __m256i res2 = _mm256_packs_epi32(_mm256_cvtps_epi32(p4), _mm256_cvtps_epi32(p5)); + + _mm256_storeu_si256((__m256i*)(outdata + 0), res0); + _mm256_storeu_si256((__m256i*)(outdata + 16), res1); + _mm256_storeu_si256((__m256i*)(outdata + 32), res2); + outdata += 48; + } + +#undef CONV_3CF32 + + #include "conv_3cf32_ci16_generic.inc" +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_3cf32_ci16_generic.inc b/src/lib/xdsp/templates/conv_3cf32_ci16_generic.inc new file mode 100644 index 00000000..8d1abc09 --- /dev/null +++ b/src/lib/xdsp/templates/conv_3cf32_ci16_generic.inc @@ -0,0 +1,14 @@ + for (; i >= 24; i -= 24, indata_0 += 2, indata_1 += 2, indata_2 += 2, outdata += 6) { + int16_t a = indata_0[0] / CONV_SCALE; + int16_t b = indata_0[1] / CONV_SCALE; + int16_t c = indata_1[0] / CONV_SCALE; + int16_t d = indata_1[1] / CONV_SCALE; + int16_t e = indata_2[0] / CONV_SCALE; + int16_t f = indata_2[1] / CONV_SCALE; + + uint64_t v = (uint64_t)(uint16_t)a | ((uint64_t)(uint16_t)b << 16) | ((uint64_t)(uint16_t)c << 32) | ((uint64_t)(uint16_t)d << 48); + uint32_t w = (uint32_t)(uint16_t)e | ((uint32_t)(uint16_t)f << 16); + *(uint64_t*)outdata = v; + *(uint32_t*)(outdata + 4) = w; + } + // do nothing with leftover diff --git a/src/lib/xdsp/templates/conv_3cf32_ci16_generic.t b/src/lib/xdsp/templates/conv_3cf32_ci16_generic.t index bfa818da..61704314 100644 --- a/src/lib/xdsp/templates/conv_3cf32_ci16_generic.t +++ b/src/lib/xdsp/templates/conv_3cf32_ci16_generic.t @@ -13,23 +13,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, const float* indata_0 = (const float*)indata_0_p; const float* indata_1 = (const float*)indata_1_p; const float* indata_2 = (const float*)indata_2_p; - int16_t* outdata = (int16_t*)outdata_p; - - for (; i >= 24; i -= 24, indata_0 += 2, indata_1 += 2, indata_2 += 2, outdata += 6) { - int16_t a = indata_0[0] / CONV_SCALE; - int16_t b = indata_0[1] / CONV_SCALE; - int16_t c = indata_1[0] / CONV_SCALE; - int16_t d = indata_1[1] / CONV_SCALE; - int16_t e = indata_2[0] / CONV_SCALE; - int16_t f = indata_2[1] / CONV_SCALE; - uint64_t v = (uint64_t)(uint16_t)a | ((uint64_t)(uint16_t)b << 16) | ((uint64_t)(uint16_t)c << 32) | ((uint64_t)(uint16_t)d << 48); - uint32_t w = (uint32_t)(uint16_t)e | ((uint32_t)(uint16_t)f << 16); - *(uint64_t*)outdata = v; - *(uint32_t*)(outdata + 4) = w; - } - - // do nothing with leftover + int16_t* outdata = (int16_t*)outdata_p; + #include "conv_3cf32_ci16_generic.inc" } #undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t b/src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t index 8d5cc5ff..0f373e82 100644 --- a/src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t +++ b/src/lib/xdsp/templates/conv_3ci16_ci16_avx2.t @@ -7,34 +7,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, void *__restrict outdata_p, unsigned outdatabsz) { - -#if 0 - typedef uint16_t v16si __attribute__ ((vector_size (32))); - union u_v16si { __m256i vect; v16si arr; }; - typedef union u_v16si u_v16si_t; - -#define RPRINT(reg) \ -{ \ - u_v16si_t p = {reg}; \ - for(int i = 15; i >= 0; --i) \ - { \ - printf("%2d ", p.arr[i]); \ - } \ - printf("\n"); \ -} - -#define RPRINT3(title, r0, r1, r2) \ -{ \ - printf("%s:\n", title); \ - RPRINT(r0); \ - RPRINT(r1); \ - RPRINT(r2); \ -} - -#else -#define RPRINT3(title, r0, r1, r2) {} -#endif - unsigned i = indatabsz; if ((outdatabsz) < i) i = (outdatabsz); @@ -44,7 +16,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, const int16_t* indata_2 = (int16_t*)indata_2_p; int16_t* outdata = (int16_t*)outdata_p; - // const __m256i mask0 = _mm256_set_epi32(-1, 0, -1, 0, -1, 0, -1, 0); const __m256i mask1 = _mm256_set_epi32(0, -1, 0, -1, 0, -1, 0, -1); @@ -58,8 +29,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, indata_1 += 16; indata_2 += 16; - RPRINT3("init",r0,r1,r2); - //(0) __m256d ulo, uhi; ulo = _mm256_castsi256_pd(_mm256_unpacklo_epi32(r0, r1)); @@ -72,8 +41,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, __m256i rs1 = _mm256_or_si256(_mm256_and_si256(r0, mask0), _mm256_and_si256(r2, mask1)); - RPRINT3("(0)",rs0,rs1,rs2); - //(1) __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b0000)); __m256i z1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(rs0), _mm256_castsi256_pd(rs1), 0b1111)); @@ -85,8 +52,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, zz1 = _mm256_shuffle_epi32(zz1, _MM_SHUFFLE(1,0,3,2)); - RPRINT3("(1)",zz0,zz1,zz2); - //(2) __m256i x0 = _mm256_permute2x128_si256(zz0, zz1, 0b00100000); __m256i x1 = _mm256_permute2x128_si256(zz0, zz1, 0b00110001); @@ -98,8 +63,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, xx1 = _mm256_permute2x128_si256(xx1, xx1, 0x1); - RPRINT3("(2)",xx0,xx1,xx2); - _mm256_storeu_si256((__m256i*)(outdata + 0), xx0); _mm256_storeu_si256((__m256i*)(outdata + 16), xx1); _mm256_storeu_si256((__m256i*)(outdata + 32), xx2); diff --git a/src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t b/src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t index 9e1d30c2..ae82468e 100644 --- a/src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t +++ b/src/lib/xdsp/templates/conv_ci16_3ci16_avx2.t @@ -6,33 +6,6 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, void *__restrict outdata_2_p, unsigned outdatabsz) { -#if 0 - typedef uint16_t v16si __attribute__ ((vector_size (32))); - union u_v16si { __m256i vect; v16si arr; }; - typedef union u_v16si u_v16si_t; - -#define RPRINT(reg) \ -{ \ - u_v16si_t p = {reg}; \ - for(int i = 15; i >= 0; --i) \ - { \ - printf("%2d ", p.arr[i]); \ - } \ - printf("\n"); \ -} - -#define RPRINT3(title, r0, r1, r2) \ -{ \ - printf("%s:\n", title); \ - RPRINT(r0); \ - RPRINT(r1); \ - RPRINT(r2); \ -} - -#else -#define RPRINT3(title, r0, r1, r2) {} -#endif - unsigned i = indatabsz; if ((outdatabsz) < i) i = (outdatabsz); @@ -57,12 +30,8 @@ r2: ba987654 ba987654 ba98LKJI ba98LKJI ba54LKFE ba54LKFE __m256i r1 = _mm256_loadu_si256(inptr++); __m256i r2 = _mm256_loadu_si256(inptr++); - RPRINT3("init",r0,r1,r2); - //(0) r1 = _mm256_permute2x128_si256(r1, r1, 0x1); - RPRINT3("(0)",r0,r1,r2); - //(1) __m256i x0 = _mm256_permute2x128_si256(r0, r1, 0b00100000); @@ -72,13 +41,9 @@ r2: ba987654 ba987654 ba98LKJI ba98LKJI ba54LKFE ba54LKFE __m256i xx0 = x0; __m256i xx1 = _mm256_permute2x128_si256(x1, x2, 0b00100000); __m256i xx2 = _mm256_permute2x128_si256(x1, x2, 0b00110001); - RPRINT3("(1)",xx0,xx1,xx2); - //(2) xx1 = _mm256_shuffle_epi32(xx1, _MM_SHUFFLE(1,0,3,2)); - RPRINT3("(2)",xx0,xx1,xx2); - //(3) __m256i z0 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(xx0), _mm256_castsi256_pd(xx1), 0b0000)); @@ -88,15 +53,11 @@ r2: ba987654 ba987654 ba98LKJI ba98LKJI ba54LKFE ba54LKFE __m256i zz0 = z0; __m256i zz1 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b0000)); __m256i zz2 = _mm256_castpd_si256(_mm256_shuffle_pd(_mm256_castsi256_pd(z1), _mm256_castsi256_pd(z2), 0b1111)); - RPRINT3("(3)",zz0,zz1,zz2); - //(4) zz1 = _mm256_shuffle_epi32(zz1, _MM_SHUFFLE(2,3,0,1)); - RPRINT3("(4)",zz0,zz1,zz2); //(5) - __m256d ulo, uhi; ulo = _mm256_castsi256_pd(_mm256_unpacklo_epi32(zz0, zz1)); uhi = _mm256_castsi256_pd(_mm256_unpackhi_epi32(zz0, zz1)); @@ -108,7 +69,6 @@ r2: ba987654 ba987654 ba98LKJI ba98LKJI ba54LKFE ba54LKFE __m256i rs1 = _mm256_or_si256(_mm256_and_si256(zz0, mask0), _mm256_and_si256(zz2, mask1)); rs1 = _mm256_shuffle_epi32(rs1, _MM_SHUFFLE(2,3,0,1)); - RPRINT3("(5)",rs0,rs1,rs2); _mm256_store_si256((__m256i*)outdata_0, rs0); _mm256_store_si256((__m256i*)outdata_1, rs1); diff --git a/src/lib/xdsp/utests/CMakeLists.txt b/src/lib/xdsp/utests/CMakeLists.txt index d7adc524..f7b193d6 100644 --- a/src/lib/xdsp/utests/CMakeLists.txt +++ b/src/lib/xdsp/utests/CMakeLists.txt @@ -37,6 +37,7 @@ set(TEST_SUIT_SRCS conv_ci16_3cf32_utest.c conv_ci16_3ci16_utest.c conv_3ci16_ci16_utest.c + conv_3cf32_ci16_utest.c ../fft_window_functions.c ../fftad_functions.c @@ -71,6 +72,7 @@ set(TEST_SUIT_SRCS ../conv_ci16_3cf32_2.c ../conv_ci16_3ci16_2.c ../conv_3ci16_ci16_2.c + ../conv_3cf32_ci16_2.c ../vbase.c ) diff --git a/src/lib/xdsp/utests/conv_3cf32_ci16_utest.c b/src/lib/xdsp/utests/conv_3cf32_ci16_utest.c new file mode 100644 index 00000000..a206007f --- /dev/null +++ b/src/lib/xdsp/utests/conv_3cf32_ci16_utest.c @@ -0,0 +1,210 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include "xdsp_utest_common.h" +#include "conv_3cf32_ci16_2.h" + +#undef DEBUG_PRINT + +#define WORD_COUNT (32768u) +#define OUT_BZ (WORD_COUNT * sizeof(int16_t)) + +#define CONV_SCALE (1.0f/32767) +#define EPS (0)//(5E-4) + +static const unsigned packet_lens[3] = { 1111u, 4123u, WORD_COUNT }; + +#define SPEED_MEASURE_ITERS 1000000 + +static float* in_0 = NULL; +static float* in_1 = NULL; +static float* in_2 = NULL; +static float* in[3] = {NULL, NULL, NULL}; + +static int16_t* out = NULL; +static int16_t* out_etalon = NULL; + +static const char* last_fn_name = NULL; +static generic_opts_t max_opt = OPT_GENERIC; + +static void setup() +{ + int res = 0; + res = res ? res : posix_memalign((void**)&in_0, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 3); + res = res ? res : posix_memalign((void**)&in_1, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 3); + res = res ? res : posix_memalign((void**)&in_2, ALIGN_BYTES, WORD_COUNT * sizeof(float) / 3); + res = res ? res : posix_memalign((void**)&out, ALIGN_BYTES, OUT_BZ); + res = res ? res : posix_memalign((void**)&out_etalon, ALIGN_BYTES, OUT_BZ); + ck_assert_int_eq(res, 0); + + in[0] = in_0; + in[1] = in_1; + in[2] = in_2; + + //fill + float *p0 = in_0; + float *p1 = in_1; + float *p2 = in_2; + + srand( time(0) ); + + for(int i = 0; i < WORD_COUNT;) + { + *p0++ = ((float)(i++) * CONV_SCALE) * ((float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1); + *p0++ = ((float)(i++) * CONV_SCALE) * ((float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1); + *p1++ = ((float)(i++) * CONV_SCALE) * ((float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1); + *p1++ = ((float)(i++) * CONV_SCALE) * ((float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1); + *p2++ = ((float)(i++) * CONV_SCALE) * ((float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1); + *p2++ = ((float)(i++) * CONV_SCALE) * ((float)(rand()) / (float)RAND_MAX > 0.5 ? -1 : 1); + } +} + +static void teardown() +{ + free(in_0); + free(in_1); + free(in_2); + free(out); + free(out_etalon); +} + +static conv_function_t get_fn(generic_opts_t o, int log) +{ + return generic_get_fn(o, log, conv_get_3cf32_ci16_c, &last_fn_name); +} + +static int is_equal() +{ + for(unsigned i = 0; i < WORD_COUNT; ++i) + { + float a = out[i]; + float b = out_etalon[i]; + + a *= CONV_SCALE; + b *= CONV_SCALE; + + float delta = fabs(a-b); + if(delta > EPS) + { + fprintf(stderr, "i = %d : out = %d, etalon = %d, delta = %.6f\n", i, out[i], out_etalon[i], delta); + return 1; + } + } + return 0; +} + +static void print_data(const char* header) +{ + if(header) + fprintf(stderr, "%s:", header); + + for(unsigned n = 0; n < 3; ++n) + { + fprintf(stderr, "\n in%d: ", n); + for(unsigned i = 0; i < 8; ++i) + { + //fprintf(stderr, "%+.4f ", in[n][i]); + fprintf(stderr, "%+2d ", (int16_t)(in[n][i] * 32767.f)); + } + } + + fprintf(stderr, "\n out: "); + for(unsigned i = 0; i < 24; ++i) + { + fprintf(stderr, "%+2d ", out[i]); + //fprintf(stderr, "%+.4f ", (double)(out[i] / 32767.f)); + } + fprintf(stderr, "\n"); +} + +START_TEST(conv_3cf32_ci16_check_simd) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void** pin = (const void**)in; + void* pout = (void*)out; + last_fn_name = NULL; + + const size_t bzin = WORD_COUNT * sizeof(float); + const size_t bzout = OUT_BZ; + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + //get etalon output data (generic foo) + memset(pout, 0, bzout); + (*get_fn(OPT_GENERIC, 0))(pin, bzin, &pout, bzout); + memcpy(out_etalon, out, bzout); + +#ifdef DEBUG_PRINT + print_data("ETALON"); +#endif + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + memset(out, 0, bzout); + (*fn)(pin, bzin, &pout, bzout); + int res = is_equal(); + res ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); +#ifdef DEBUG_PRINT + print_data(NULL); +#endif + ck_assert_int_eq( res, 0 ); + } + } +} +END_TEST + + +START_TEST(conv_3cf32_ci16_speed) +{ + generic_opts_t opt = max_opt; + conv_function_t fn = NULL; + const void** pin = (const void**)in; + void* pout = (void*)out; + last_fn_name = NULL; + + const size_t bzin = packet_lens[_i] * sizeof(float); + const size_t bzout = packet_lens[_i] * sizeof(int16_t); + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %lu bytes, iters: %u ***\n", bzin, SPEED_MEASURE_ITERS); + + while(opt != OPT_GENERIC) + { + conv_function_t fn = get_fn(opt--, 1); + if(fn) + { + //warming + for(int i = 0; i < 100; ++i) (*fn)(pin, bzin, &pout, bzout); + + //measuring + uint64_t tk = clock_get_time(); + for(int i = 0; i < SPEED_MEASURE_ITERS; ++i) (*fn)(pin, bzin, &pout, bzout); + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 call, ave speed = %" PRIu64 " calls/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_MEASURE_ITERS), (uint64_t)(1000000LL*SPEED_MEASURE_ITERS/tk1)); + } + } +} +END_TEST + +Suite * conv_3cf32_ci16_suite(void) +{ + max_opt = cpu_vcap_get(); + + Suite* s = suite_create("conv_3cf32_ci16"); + + ADD_REGRESS_TEST(s, conv_3cf32_ci16_check_simd); + ADD_PERF_LOOP_TEST(s, conv_3cf32_ci16_speed, 60, 0, 3); + + return s; +} diff --git a/src/lib/xdsp/utests/xdsp_utest_suite.c b/src/lib/xdsp/utests/xdsp_utest_suite.c index dee066bb..fc89b6a8 100644 --- a/src/lib/xdsp/utests/xdsp_utest_suite.c +++ b/src/lib/xdsp/utests/xdsp_utest_suite.c @@ -40,6 +40,7 @@ Suite * conv_ci16_8ci16_suite(void); Suite * conv_ci16_3cf32_suite(void); Suite * conv_ci16_3ci16_suite(void); Suite * conv_3ci16_ci16_suite(void); +Suite * conv_3cf32_ci16_suite(void); int main(int argc, char** argv) { @@ -49,7 +50,7 @@ int main(int argc, char** argv) int number_failed; SRunner *sr; -#if 0 +#if 1 sr = srunner_create( fftad_suite()); srunner_add_suite(sr, rtsa_suite()); srunner_add_suite(sr, fft_window_cf32_suite()); @@ -64,13 +65,16 @@ int main(int argc, char** argv) // srunner_add_suite(sr, conv_f32_i16_suite()); srunner_add_suite(sr, conv_2cf32_ci16_suite()); + srunner_add_suite(sr, conv_3cf32_ci16_suite()); srunner_add_suite(sr, conv_4cf32_ci16_suite()); // srunner_add_suite(sr, conv_ci16_2ci16_suite()); + srunner_add_suite(sr, conv_ci16_3ci16_suite()); srunner_add_suite(sr, conv_ci16_4ci16_suite()); srunner_add_suite(sr, conv_ci16_6ci16_suite()); srunner_add_suite(sr, conv_ci16_8ci16_suite()); srunner_add_suite(sr, conv_2ci16_ci16_suite()); + srunner_add_suite(sr, conv_3ci16_ci16_suite()); srunner_add_suite(sr, conv_4ci16_ci16_suite()); // srunner_add_suite(sr, conv_i16_i12_suite()); @@ -90,14 +94,10 @@ int main(int argc, char** argv) srunner_add_suite(sr, conv_ci12_4cf32_suite()); // #else - //sr = srunner_create(conv_i16_f32_suite()); - //sr = srunner_create(fft_window_ci16_cf32_suite()); - sr = srunner_create(conv_3ci16_ci16_suite()); - //srunner_add_suite(sr, conv_ci16_8ci16_suite()); - - //srunner_add_suite(sr, fft_window_cf32_suite()); - //srunner_add_suite(sr, conv_f32_i12_suite()); - //srunner_add_suite(sr, conv_2cf32_ci12_suite()); + sr = srunner_create( conv_3cf32_ci16_suite()); + srunner_add_suite(sr, conv_ci16_3cf32_suite()); + srunner_add_suite(sr, conv_3ci16_ci16_suite()); + srunner_add_suite(sr, conv_ci16_3ci16_suite()); #endif srunner_set_fork_status (sr, CK_NOFORK); srunner_run_all(sr, (argc > 1) ? CK_VERBOSE : CK_NORMAL); From 6df50b2c8c210351d7d96a880b628ab51bbdd64d Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:09:12 +0400 Subject: [PATCH 278/397] Fixed descriptions. --- src/lib/device/ext_xmass/ext_xmass_ctrl.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/device/ext_xmass/ext_xmass_ctrl.yaml b/src/lib/device/ext_xmass/ext_xmass_ctrl.yaml index 74f89f52..a1f2745c 100644 --- a/src/lib/device/ext_xmass/ext_xmass_ctrl.yaml +++ b/src/lib/device/ext_xmass/ext_xmass_ctrl.yaml @@ -25,7 +25,7 @@ pages: fields: - bits: "0" name: BDISTRIB - desc: Enable OUT_REF_B and OUT_SYREF_B[0 for 4 sync boards + desc: Enable OUT_REF_B and OUT_SYREF_B0 for 4 sync boards - bits: "1" name: BLOCAL desc: Enable local PPS and REF distribution @@ -68,4 +68,4 @@ pages: desc: 0 - TX_SYREF_MUX demuliplexing to CLK_SYSREF_OUT, 1 TX_SYREF_MUX to GPS_RX - bits: "7:5" name: RTS - desc: Interboard sync logic + desc: Interboard sync logic(Not used) From 2f3098c1bc3f5a871936c70e5c1e339ea220a336 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 15:00:35 +0400 Subject: [PATCH 279/397] usdr_dm_create: add -b precharge TX option to offset TX relative to RX --- src/tools/usdr_dm_create.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index e51d35f8..3f1ece2e 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -417,6 +417,7 @@ static void usage(int severity, const char* me) "\t[-g comma-separated list of sin generator gains (FP values, dBFS -100..0)] \n" "\t[-X ] \n" "\t[-z ] \n" + "\t[-b TX packet precharge count before doing RX (valid with -T flag) [16]\n" "\t[-l loglevel [3(INFO)]] \n" "\t[-G calibration [algo#]] \n" "\t[-Z param1=value1,param2=value2,...] \n" @@ -638,6 +639,7 @@ int main(UNUSED int argc, UNUSED char** argv) unsigned calibrate = 0; param_list_t extra_params[32]; unsigned extra_param_len = 0; + int tx_pkt_precharge = 16; memset(rx_thread_inputs, 0, sizeof(rx_thread_inputs)); memset(tx_thread_inputs, 0, sizeof(tx_thread_inputs)); @@ -678,7 +680,7 @@ int main(UNUSED int argc, UNUSED char** argv) //set colored log output usdrlog_enablecolorize(NULL); - while ((opt = getopt(argc, argv, "B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:")) != -1) { + while ((opt = getopt(argc, argv, "b:B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:")) != -1) { switch (opt) { //Time-division duplexing (TDD) frequency case 'q': dev_data[DD_TDD_FREQ].value = atof(optarg); dev_data[DD_TDD_FREQ].ignore = false; break; @@ -721,6 +723,9 @@ int main(UNUSED int argc, UNUSED char** argv) case 'x': fref = atof(optarg); break; + case 'b': + tx_pkt_precharge = atoi(optarg); + break; //Calibration frequency case 'B': cal_freq = atof(optarg); @@ -1302,8 +1307,19 @@ int main(UNUSED int argc, UNUSED char** argv) for (unsigned i = 0; !s_stop && (i < count); i++) { - if(dotx && !do_transmit(usds_tx, &stm, &snfo_tx, nots, i, &tx_samples_cnt, &txstat)) - goto stop; + if (tx_pkt_precharge < 0) { + if (tx_pkt_precharge != 0) { + ++tx_pkt_precharge; + } + } else { + if (dotx && !do_transmit(usds_tx, &stm, &snfo_tx, nots, i, &tx_samples_cnt, &txstat)) + goto stop; + + if (tx_pkt_precharge != 0) { + --tx_pkt_precharge; + continue; + } + } if(dorx && !do_receive(usds_rx, i, &rxstat)) goto stop; From 0e4be7e06cbf827dd43d6bf8a0b66180b860903a Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 15:01:19 +0400 Subject: [PATCH 280/397] espi_flash: fix uninitialized return when requested size == 0 --- src/lib/ipblks/espi_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/ipblks/espi_flash.c b/src/lib/ipblks/espi_flash.c index 9a3949e4..ecf6122f 100644 --- a/src/lib/ipblks/espi_flash.c +++ b/src/lib/ipblks/espi_flash.c @@ -330,7 +330,7 @@ int espi_flash_erase(lldev_t dev, subdev_t subdev, unsigned cfg_base, int espi_flash_write(lldev_t dev, subdev_t subdev, unsigned cfg_base, unsigned cfg_mmap_base, const uint8_t* in, uint32_t size, uint32_t flash_off, unsigned flags) { - int res; + int res = -EINVAL; if ((flags & ESPI_FLASH_DONT_ERASE) != ESPI_FLASH_DONT_ERASE) { res = _espi_flash_erase(dev, subdev, cfg_base, flash_off, size); if (res) From 6ce87aaaa5991a159581601f700a138e3d00ac09 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 15:03:22 +0400 Subject: [PATCH 281/397] add USDR_LL_LOG macro with optional tagging device name in messages --- src/lib/lowlevel/usdr_lowlevel.c | 48 ++++++++++++++++++++++++++++++++ src/lib/lowlevel/usdr_lowlevel.h | 28 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/src/lib/lowlevel/usdr_lowlevel.c b/src/lib/lowlevel/usdr_lowlevel.c index e1307d71..2800be5f 100644 --- a/src/lib/lowlevel/usdr_lowlevel.c +++ b/src/lib/lowlevel/usdr_lowlevel.c @@ -4,6 +4,9 @@ #include "usdr_lowlevel.h" #include "usb_uram/usb_uram_generic.h" #include +#include +#include +#include lowlevel_ops_t *lowlevel_get_ops(lldev_t dev) { @@ -112,6 +115,51 @@ void lowlevel_ops_set_custom(lldev_t obj, lowlevel_ops_t* newops) obj->ops = newops; } +static bool s_show_devname = false; + +void usdrlog_ll_devname_en(bool show_devname) +{ + s_show_devname = show_devname; +} + +void usdrlog_ll_out(lldev_t dev, + unsigned loglevel, + const char* subsystem, + const char* function, + const char* file, + int line, + const char* fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + usdrlog_ll_vout(dev, loglevel, subsystem, function, file, line, fmt, ap); + va_end(ap); +} + +void usdrlog_ll_vout(lldev_t dev, + unsigned loglevel, + const char* subsystem, + const char* function, + const char* file, + int line, + const char* fmt, + va_list list) +{ + if (s_show_devname) { + char buf[8192]; + int sz = snprintf(buf, sizeof(buf), "%s: %s", lowlevel_get_devname(dev), fmt); + if (sz < 0) { + buf[8192 - 1] = 0; + } + + return usdrlog_vout(loglevel, subsystem, function, file, line, buf, list); + } + + return usdrlog_vout(loglevel, subsystem, function, file, line, fmt, list); +} + + void __attribute__ ((constructor(110))) setup_lowlevel(void) { lowlevel_initialize_plugins(); } diff --git a/src/lib/lowlevel/usdr_lowlevel.h b/src/lib/lowlevel/usdr_lowlevel.h index 89fa5e2f..cdb4c3f4 100644 --- a/src/lib/lowlevel/usdr_lowlevel.h +++ b/src/lib/lowlevel/usdr_lowlevel.h @@ -8,6 +8,9 @@ #include #include +#include + + #define USBG_LOG_TAG "USBG" enum lowlevel_ls_ops { @@ -238,4 +241,29 @@ typedef struct lowlevel_dev lowlevel_dev_t; // Set new low-level device filter to specifically process some exceptions void lowlevel_ops_set_custom(lldev_t obj, lowlevel_ops_t* newops); + +void usdrlog_ll_devname_en(bool show_devname); + +void usdrlog_ll_out(lldev_t dev, + unsigned loglevel, + const char* subsystem, + const char* function, + const char* file, + int line, + const char* fmt, ...) __attribute__ ((format (printf, 7, 8))); + +void usdrlog_ll_vout(lldev_t dev, + unsigned loglevel, + const char* subsystem, + const char* function, + const char* file, + int line, + const char* fmt, + va_list list) __attribute__ ((format (printf, 7, 0))); + +#define USDR_LL_LOG(dev, system, level, ...) \ +do { \ + usdrlog_ll_out(dev, (level), (system), __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \ +} while (0) + #endif From 76c492391d573f2d961897a5a994bcc2cc81f276 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 15:06:55 +0400 Subject: [PATCH 282/397] use USDR_LL_LOG instead of USDR_LOG --- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 116 ++++++++---------- src/lib/device/m2_lm7_1/m2_lm7_1.c | 36 +++--- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 115 ++++++++--------- src/lib/ipblks/streams/dma_rx_32.c | 4 +- src/lib/ipblks/streams/sfe_rx_4.c | 60 +++++---- src/lib/ipblks/streams/sfe_tx_4.c | 2 +- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 64 +++++----- src/lib/lowlevel/pcie_uram/pcie_uram_main.c | 70 +++++------ 8 files changed, 233 insertions(+), 234 deletions(-) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 36babca8..653aa307 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -113,8 +113,8 @@ static int _lms7002m_set_lna_rx(lms7002_dev_t *d, unsigned cfg_idx) txlbband = lms7002m_trf_from_rfe_path(band); } - USDR_LOG("LMS7", USDR_LOG_INFO, "%s: Set RX band to %d (%s/%s) %s [TXLB:%d => ATEEN=%d,%d]\n", - lowlevel_get_devname(d->lmsstate.dev), band, + USDR_LL_LOG(d->lmsstate.dev, "LMS7", USDR_LOG_INFO, "Set RX band to %d (%s/%s) %s [TXLB:%d => ATEEN=%d,%d]\n", + band, cfg->name0, cfg->name1, d->rx_lna_lb_active ? "loopback enabled" : "", txlbband, d->trf_lb_atten, d->trf_lb_loss); @@ -141,8 +141,8 @@ static int _lms7002m_set_lna_tx(lms7002_dev_t *d, unsigned cfg_idx) int res = 0; d->tx_cfg_path = cfg_idx; - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Set TX band to %d (%s/%s)\n", - lowlevel_get_devname(d->lmsstate.dev), band, cfg->name0, cfg->name1); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set TX band to %d (%s/%s)\n", + band, cfg->name0, cfg->name1); if (d->rx_lna_lb_active) { res = lms7002m_rfe_path(&d->lmsstate, @@ -184,8 +184,8 @@ static int _lms7002m_signal_event(lms7002_dev_t *d, enum sigtype t) case XSDR_RX_LNA_CHANGED: if (d->rx_rfic_path == XSDR_RX_AUTO) { cfgidx = get_antenna_cfg_by_freq(d->rx_lo, d->cfg_auto_rx, MAX_RX_BANDS); - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Auto RX band selection: %s\n", - lowlevel_get_devname(d->lmsstate.dev), d->cfg_auto_rx[cfgidx].name0); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Auto RX band selection: %s\n", + d->cfg_auto_rx[cfgidx].name0); res = (res) ? res : _lms7002m_set_lna_rx(d, cfgidx); } @@ -195,8 +195,8 @@ static int _lms7002m_signal_event(lms7002_dev_t *d, enum sigtype t) case XSDR_TX_LNA_CHANGED: if (d->tx_rfic_path == XSDR_TX_AUTO) { cfgidx = get_antenna_cfg_by_freq(d->tx_lo, d->cfg_auto_tx, MAX_TX_BANDS); - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Auto TX band selection: %s\n", - lowlevel_get_devname(d->lmsstate.dev), d->cfg_auto_tx[cfgidx].name0); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Auto TX band selection: %s\n", + d->cfg_auto_tx[cfgidx].name0); res = (res) ? res : _lms7002m_set_lna_tx(d, cfgidx); } @@ -230,8 +230,7 @@ int lms7002m_set_gain(lms7002_dev_t *d, "TX_PGA", "{invalid}", }; - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Set gain %s to %d on %d channel\n", - lowlevel_get_devname(d->lmsstate.dev), + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set gain %s to %d on %d channel\n", s_gains[MIN(gain_type, SIZEOF_ARRAY(s_gains))], gain, channel); @@ -298,8 +297,8 @@ int lms7002m_set_gain(lms7002_dev_t *d, default: return -EINVAL; } - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Set gain %d (%d) to %d on %d channel => actual = %.3f\n", - lowlevel_get_devname(d->lmsstate.dev), gain, ogain, gain_type, channel, actual / 1e6); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set gain %d (%d) to %d on %d channel => actual = %.3f\n", + gain, ogain, gain_type, channel, actual / 1e6); if (actualgain) *actualgain = actual; @@ -338,8 +337,8 @@ int lms7002m_fe_set_freq(lms7002_dev_t *d, lms7002m_sxx_disable(&d->lmsstate, SXX_RX); } - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: FE_FREQ path=%d type=%d freq=%f ch=%d\n", - lowlevel_get_devname(d->lmsstate.dev), path, type, freq, channel); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "FE_FREQ path=%d type=%d freq=%f ch=%d\n", + path, type, freq, channel); res = lms7002m_sxx_tune(&d->lmsstate, path, d->fref, (unsigned)freq, @@ -384,8 +383,7 @@ static int _lms7002m_lb_status_changes(lms7002_dev_t *d) { int res = 0; if (!d->rx_lna_lb_active) { - USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Turning off loopback\n", - lowlevel_get_devname(d->lmsstate.dev)); + USDR_LL_LOG(d->lmsstate.dev, "UDEV", USDR_LOG_WARNING, "Turning off loopback\n"); res = (res) ? res : lms7002m_trf_gain(&d->lmsstate, TRF_GAIN_PAD, -10 * ((d->lmsstate.reg_mac & 1) ? d->tx_loss[0] : d->tx_loss[1]), @@ -404,8 +402,8 @@ static int _lms7002m_lb_status_changes(lms7002_dev_t *d) // res = (res) ? res : lms7002m_rfe_gain(&d->lmsstate, // d->rfe_lb_atten, &lb_loss); - USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Turning on loopback RX + TX loss: -- + %d dB\n", - lowlevel_get_devname(d->lmsstate.dev), /*lb_loss,*/ d->trf_lb_atten); + USDR_LL_LOG(d->lmsstate.dev, "UDEV", USDR_LOG_WARNING, "Turning on loopback RX + TX loss: -- + %d dB\n", + /*lb_loss,*/ d->trf_lb_atten); } // Update LNA / LOOPBACK gain after LB activated / deactivated @@ -434,13 +432,11 @@ int lms7002m_rfe_set_path(lms7002_dev_t *d, case XSDR_RX_AUTO: break; case XSDR_RX_ADC_EXT: - USDR_LOG("UDEV", USDR_LOG_INFO, "%s: Activating external ADC input NOT IMPLEMENTED\n", - lowlevel_get_devname(d->lmsstate.dev)); + USDR_LL_LOG(d->lmsstate.dev, "UDEV", USDR_LOG_INFO, "Activating external ADC input NOT IMPLEMENTED\n"); return -EINVAL; default: - USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Unknown FE path %d\n", - lowlevel_get_devname(d->lmsstate.dev), path); + USDR_LL_LOG(d->lmsstate.dev, "UDEV", USDR_LOG_WARNING, "Unknown FE path %d\n", path); return -EINVAL; } @@ -485,8 +481,7 @@ int lms7002m_tfe_set_path(lms7002_dev_t *d, d->rx_lna_lb_active = false; return _lms7002m_signal_event(d, XSDR_TX_LNA_CHANGED); default: - USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Unknown FE path %d\n", - lowlevel_get_devname(d->lmsstate.dev), path); + USDR_LL_LOG(d->lmsstate.dev, "UDEV", USDR_LOG_WARNING, "Unknown FE path %d\n", path); return -EINVAL; } @@ -592,8 +587,6 @@ int lms7002m_bb_set_freq(lms7002_dev_t *d, int64_t freq) { int res; - const char* devstr = lowlevel_get_devname(d->lmsstate.dev); - res = _lms7002m_check_chan(channel); if (res) return res; @@ -602,9 +595,9 @@ int lms7002m_bb_set_freq(lms7002_dev_t *d, double conv_freq = d->cgen_clk / (dir_tx ? d->txcgen_div : d->rxcgen_div); double rel_freq = freq / conv_freq; if (rel_freq > 0.5 || rel_freq < -0.5) { - USDR_LOG("XDEV", USDR_LOG_WARNING, - "%s: NCO %s ouf of range, requested %.3f while DAC %.3f\n", - devstr, dir_tx ? "TX" : "RX", + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_WARNING, + "NCO %s ouf of range, requested %.3f while DAC %.3f\n", + dir_tx ? "TX" : "RX", rel_freq / 1000, conv_freq / 1000); return -EINVAL; } @@ -624,8 +617,8 @@ int lms7002m_bb_set_freq(lms7002_dev_t *d, return res; } - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: NCO ch=%d type=%d freq=%lld\n", - devstr, channel, dir_tx, (long long)freq); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "NCO ch=%d type=%d freq=%lld\n", + channel, dir_tx, (long long)freq); return 0; } @@ -687,7 +680,6 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, bool txafen_b = d->tx_run[1]; int res; unsigned ich; - const char* devstr = lowlevel_get_devname(d->lmsstate.dev); if (dir & RFIC_LMS7_RX) { if (_lms7002m_check_chan(rx_chs_i)) { @@ -728,8 +720,8 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, if (res) return res; - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: AFE TX=[%d;%d] RX=[%d;%d]\n", - devstr, txafen_a, txafen_b, rxafen_a, rxafen_b); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "AFE TX=[%d;%d] RX=[%d;%d]\n", + txafen_a, txafen_b, rxafen_a, rxafen_b); if (dir & RFIC_LMS7_RX) { res = res ? res : lms7002m_mac_set(&d->lmsstate, rx_chs); @@ -765,20 +757,20 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, if (d->rx_bw[ich].set) { bandwidth = d->rx_bw[ich].value; - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: RBB Restore BW[%d]=%d\n", - devstr, ich, d->rx_bw[ich].value); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "RBB Restore BW[%d]=%d\n", + ich, d->rx_bw[ich].value); } else { bandwidth = d->cgen_clk / d->rxcgen_div / d->rxtsp_div / d->rx_dsp_decim; - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: No RBB[%d] was set; defaulting to current rx samplerate %u\n", - devstr, ich, bandwidth); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "No RBB[%d] was set; defaulting to current rx samplerate %u\n", + ich, bandwidth); } res = lms7002m_rbb_bandwidth(d, bandwidth, false); if (res) return res; if (d->rx_dsp[ich].set) { - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: RBB Restore DSP[%d]=%d\n", - devstr, ich, d->rx_dsp[ich].value); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "RBB Restore DSP[%d]=%d\n", + ich, d->rx_dsp[ich].value); freqoffset = d->rx_dsp[ich].value; } else { freqoffset = 0; @@ -811,21 +803,21 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, return res; if (d->tx_bw[ich].set) { - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: TBB Restore BW[%d]=%d\n", - devstr, ich, d->tx_bw[ich].value); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "TBB Restore BW[%d]=%d\n", + ich, d->tx_bw[ich].value); bandwidth = d->tx_bw[ich].value; } else { bandwidth = d->cgen_clk / d->txcgen_div / d->txtsp_div / d->tx_dsp_inter; - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: No TBB[%d] was set; defaulting to current rx samplerate %u\n", - devstr, ich, bandwidth); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "No TBB[%d] was set; defaulting to current rx samplerate %u\n", + ich, bandwidth); } res = lms7002m_tbb_bandwidth(d, bandwidth, false); if (res) return res; if (d->tx_dsp[ich].set) { - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: TBB Restore DSP[%d]=%d\n", - devstr, ich, d->tx_dsp[ich].value); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "TBB Restore DSP[%d]=%d\n", + ich, d->tx_dsp[ich].value); freqoffset = d->tx_dsp[ich].value; } else { freqoffset = 0; @@ -850,11 +842,11 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, lms7002m_limelight_conf_t nlml_mode = d->lml_mode; if (rx_flags & RFIC_DIGITAL_LB) { - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Enable digital loopback\n", devstr); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Enable digital loopback\n"); nlml_mode.rx_tx_dig_loopback = 1; } if (rx_flags & RFIC_LFSR) { - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Enable RX LFSR\n", devstr); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Enable RX LFSR\n"); nlml_mode.rx_lfsr = 1; } @@ -871,7 +863,7 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, return res; //res = lms7_dc_init(&d->lmsstate, d->rx_run[0], d->rx_run[1], d->tx_run[0], d->tx_run[1]); - USDR_LOG("XDEV", USDR_LOG_INFO, "%s: configure done RUN RX:%d%d TX:%d%d\n", devstr, + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "configure done RUN RX:%d%d TX:%d%d\n", d->rx_run[1], d->rx_run[0], d->tx_run[1], d->tx_run[0]); return 0; } @@ -946,7 +938,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, cgen_rate = MAX(mindecint_rx * rxrate * rx_host_div * mpy_adc, mindecint_tx * txrate * tx_host_mul * mpy_dac); - USDR_LOG("XDEV", USDR_LOG_NOTE, "Initial CGEN set to %03.1f Mhz\n", cgen_rate / 1.0e6); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_NOTE, "Initial CGEN set to %03.1f Mhz\n", cgen_rate / 1.0e6); // For low sample rate increase DAC/ADC due to frequency aliasing if ((rxrate > 1 && rxrate < 2e6) || (txrate > 1 && txrate < 2e6) || opt_decim_inter) { @@ -957,7 +949,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, if (rx_ndiv > LMS7_DECIM_MAX || tx_ndiv > LMS7_INTER_MAX) break; - USDR_LOG("XDEV", USDR_LOG_NOTE, "Increase RXdiv=%2d TXdiv=%2d => CGEN %03.1f Mhz\n", + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_NOTE, "Increase RXdiv=%2d TXdiv=%2d => CGEN %03.1f Mhz\n", rx_ndiv, tx_ndiv, cgen_rate * 2 / 1.0e6); } } @@ -971,7 +963,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, } if (rxrate > 1 && !_check_lime_decimation(rxdiv)) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "can't deliver " + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_ERROR, "can't deliver " "decimation: %d of %.3f MHz CGEN and %.3f MHz samplerate; TXm = %.3f RXm = %.3f\n", rxdiv, cgen_rate / 1e6, rxrate / 1e6, txmaster_min / 1e6, rxmaster_min / 1e6); @@ -979,7 +971,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, } if (txrate > 1 && !_check_lime_decimation(txdiv)) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "can't deliver " + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_ERROR, "can't deliver " "interpolation: %d of %.3f MHz CGEN and %.3f MHz samplerate; TXm = %.3f RXm = %.3f\n", txdiv, cgen_rate / 1e6, txrate / 1e6, txmaster_min / 1e6, rxmaster_min / 1e6); @@ -1011,7 +1003,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, } } if (res != 0) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "can't tune VCO for data clock\n"); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_ERROR, "can't tune VCO for data clock\n"); return -ERANGE; } d->cgen_clk = cgen_rate; @@ -1034,7 +1026,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, if (res) return res; - USDR_LOG("XDEV", USDR_LOG_INFO, "Update RXTSP divider\n"); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Update RXTSP divider\n"); res = lms7002m_xxtsp_int_dec(&d->lmsstate, LMS_RXTSP, _ulog(d->rxtsp_div)); if (res) return res; @@ -1044,7 +1036,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, if (res) return res; - USDR_LOG("XDEV", USDR_LOG_INFO, "Update TXTSP divider\n"); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Update TXTSP divider\n"); res = lms7002m_xxtsp_int_dec(&d->lmsstate, LMS_TXTSP, _ulog(d->txtsp_div)); if (res) return res; @@ -1068,7 +1060,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, // return res; d->lml_mode = cfg; - USDR_LOG("XDEV", USDR_LOG_INFO, "rxrate=%.3fMHz txrate=%.3fMHz" + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "rxrate=%.3fMHz txrate=%.3fMHz" " rxdecim=%d(h_%d) txinterp=%d(h_%d)" " RX_ADC=%.3fMHz TX_DAC=%.3fMHz hintr=%d hdecim=%d CGEN=%.3fMhz" " RX_TSP_div=%d TX_TSP_div=%d; SISO=%d/%d; refclk=%.3f\n", @@ -1082,13 +1074,13 @@ int lms7002m_samplerate(lms7002_dev_t *d, // Update BW if it's in auto mode for (unsigned i = 0; i < 2; i++) { if (rxrate > 1 && d->rx_run[i] && !d->rx_bw[i].set) { - USDR_LOG("XDEV", USDR_LOG_INFO, "Set RX[%d] bandwidth to %.3f Mhz\n", i, rxrate / 1e6); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set RX[%d] bandwidth to %.3f Mhz\n", i, rxrate / 1e6); res = res ? res : lms7002m_mac_set(&d->lmsstate, i == 0 ? LMS7_CH_A : LMS7_CH_B); res = res ? res : lms7002m_rbb_bandwidth(d, rxrate, false); } if (txrate > 1 && d->tx_run[i] && !d->tx_bw[i].set) { - USDR_LOG("XDEV", USDR_LOG_INFO, "Set TX[%d] bandwidth to %.3f Mhz\n", i, txrate / 1e6); + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set TX[%d] bandwidth to %.3f Mhz\n", i, txrate / 1e6); res = res ? res : lms7002m_mac_set(&d->lmsstate, i == 0 ? LMS7_CH_A : LMS7_CH_B); res = res ? res : lms7002m_tbb_bandwidth(d, txrate, false); @@ -1147,7 +1139,7 @@ int lms7002m_set_corr_param(lms7002_dev_t* d, int channel, int corr_type, int va switch (type) { case CORR_PARAM_I: case CORR_PARAM_Q: - USDR_LOG("LMS7", USDR_LOG_INFO, "Set %s%s%s to %d\n", + USDR_LL_LOG(d->lmsstate.dev, "LMS7", USDR_LOG_INFO, "Set %s%s%s to %d\n", rx ? "RX" : "TX", (channel == 0) ? "A" : "B", type == CORR_PARAM_I ? "I" : "Q", @@ -1155,7 +1147,7 @@ int lms7002m_set_corr_param(lms7002_dev_t* d, int channel, int corr_type, int va return lms7002m_dc_corr(&d->lmsstate, param_dc, value); case CORR_PARAM_A: - USDR_LOG("LMS7", USDR_LOG_INFO, "Set %sA to %d\n", rx ? "RX" : "TX", value); + USDR_LL_LOG(d->lmsstate.dev, "LMS7", USDR_LOG_INFO, "Set %sA to %d\n", rx ? "RX" : "TX", value); return lms7002m_xxtsp_iq_phcorr(&d->lmsstate, rx ? LMS_RXTSP : LMS_TXTSP, value); case CORR_PARAM_GIQ: @@ -1166,7 +1158,7 @@ int lms7002m_set_corr_param(lms7002_dev_t* d, int channel, int corr_type, int va qg = 2047; ig = 2047 - value; } - USDR_LOG("LMS7", USDR_LOG_INFO, "Set %sGIQ to %d => ig = %d qg = %d\n", + USDR_LL_LOG(d->lmsstate.dev, "LMS7", USDR_LOG_INFO, "Set %sGIQ to %d => ig = %d qg = %d\n", rx ? "RX" : "TX", value, ig, qg); return lms7002m_xxtsp_iq_gcorr(&d->lmsstate, rx ? LMS_RXTSP : LMS_TXTSP, ig, qg); diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 30ac7c07..1ad34b84 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -534,9 +534,8 @@ int dev_m2_lm7_1_debug_lms7002m_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint6 d->debug_lms7002m_last = ~0u; res = lowlevel_spi_tr32(d->base.dev, 0, SPI_LMS7, value & 0xffffffff, &d->debug_lms7002m_last); - USDR_LOG("XDEV", USDR_LOG_WARNING, "%s: Debug LMS7/%d REG %08x => %08x\n", - lowlevel_get_devname(d->base.dev), chan, (unsigned)value, - d->debug_lms7002m_last); + USDR_LL_LOG(d->base.dev, "XDEV", USDR_LOG_WARNING, "Debug LMS7/%d REG %08x => %08x\n", + chan, (unsigned)value, d->debug_lms7002m_last); return res; } @@ -544,9 +543,8 @@ int dev_m2_lm7_1_debug_lms8001_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; int res = xsdr_trspi_lms8(&d->xdev, value & 0xffffffff, &d->debug_lms8001_last); - USDR_LOG("XDEV", USDR_LOG_WARNING, "%s: Debug LMS8 REG %08x => %08x\n", - lowlevel_get_devname(d->base.dev), (unsigned)value, - d->debug_lms8001_last); + USDR_LL_LOG(d->base.dev, "XDEV", USDR_LOG_WARNING, "Debug LMS8 REG %08x => %08x\n", + (unsigned)value, d->debug_lms8001_last); return res; } @@ -598,7 +596,7 @@ int dev_m2_lm7_1_sdr_rx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 unsigned qg = ((value >> 16) & 0xffff); unsigned pcorr = ((value >> 48) & 0xffff); - USDR_LOG("UDEV", USDR_LOG_NOTE, "RXGAC CH=%d I=%d Q=%d A=%d\n", chan, ig, qg, pcorr); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_NOTE, "RXGAC CH=%d I=%d Q=%d A=%d\n", chan, ig, qg, pcorr); res = (res) ? res : lms7002m_xxtsp_iq_gcorr(&d->xdev.base.lmsstate, LMS_RXTSP, ig, qg); res = (res) ? res : lms7002m_xxtsp_iq_phcorr(&d->xdev.base.lmsstate, LMS_RXTSP, pcorr); @@ -616,7 +614,7 @@ int dev_m2_lm7_1_sdr_tx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 unsigned qg = ((value >> 16) & 0xffff); unsigned pcorr = ((value >> 48) & 0xffff); - USDR_LOG("UDEV", USDR_LOG_NOTE, "TXGAC CH=%d I=%d Q=%d A=%d\n", chan, ig, qg, pcorr); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_NOTE, "TXGAC CH=%d I=%d Q=%d A=%d\n", chan, ig, qg, pcorr); res = (res) ? res : lms7002m_xxtsp_iq_gcorr(&d->xdev.base.lmsstate, LMS_TXTSP, ig, qg); res = (res) ? res : lms7002m_xxtsp_iq_phcorr(&d->xdev.base.lmsstate, LMS_TXTSP, pcorr); @@ -740,7 +738,7 @@ int dev_m2_lm7_1_rfe_nco_pwrdc_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* res = lowlevel_reg_rdndw(d->base.dev, 0, /* REG_RD_UNUSED_0 */ 7, (uint32_t*)&val[0], 2); - USDR_LOG("UDEV", USDR_LOG_NOTE, "DCV I=%d Q=%d\n", val[0], val[1]); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_NOTE, "DCV I=%d Q=%d\n", val[0], val[1]); double i = val[0]; double q = val[1]; @@ -1027,7 +1025,7 @@ int _sdr_get_path(const char* param) { int idx = find_param_list(param, s_path_list, SIZEOF_ARRAY(s_path_list)); if (idx < 0) { - USDR_LOG("UDEV", USDR_LOG_WARNING, "m2_lm7_1_GPS: unknown '%s' path!\n", + USDR_LOG("UDEV", USDR_LOG_WARNING, "Unknown '%s' path!\n", param); return -EINVAL; } @@ -1079,7 +1077,7 @@ int dev_m2_lm7_1_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val int dev_m2_lm7_1_sdr_refclk_frequency_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - USDR_LOG("UDEV", USDR_LOG_WARNING, "m2_lm7_1_GPS: Set fref=%d\n", (unsigned)value); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "Set fref=%d\n", (unsigned)value); d->xdev.base.fref = value; return 0; } @@ -1106,7 +1104,7 @@ int dev_m2_lm7_1_sdr_refclk_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t } xsdr_set_extref(&d->xdev, value ? true : false, d->xdev.base.fref); - USDR_LOG("UDEV", USDR_LOG_INFO, "m2_lm7_1_GPS: set clk ref path to %d\n", (int)value); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_INFO, "Set clk ref path to %d\n", (int)value); return 0; } @@ -1124,7 +1122,7 @@ void usdr_device_m2_lm7_1_destroy(pdevice_t udev) } xsdr_dtor(&d->xdev); - USDR_LOG("UDEV", USDR_LOG_INFO, "m2_lm7_1_GPS: turnoff\n"); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_INFO, "Turnoff\n"); usdr_device_base_destroy(udev); } @@ -1132,7 +1130,7 @@ void usdr_device_m2_lm7_1_destroy(pdevice_t udev) int dev_m2_lm7_1_tx_antennat_port_cfg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - USDR_LOG("UDEV", USDR_LOG_INFO, "m2_lm7_1_GPS: tx antennat port cfg:%d\n", (unsigned)value); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_INFO, "Tx antennat port cfg:%d\n", (unsigned)value); return xsdr_tx_antennat_port_cfg(&d->xdev, value); } @@ -1213,13 +1211,13 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* { res = vfs_add_const_i64_vec(&udev->rootfs, ssdr_params_m2_lm7_1_rev000, SIZEOF_ARRAY(ssdr_params_m2_lm7_1_rev000)); if (res) - USDR_LOG("UDEV", USDR_LOG_WARNING, "Unable to set device name \"ssdr\"!\n"); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "Unable to set device name \"ssdr\"!\n"); } else { res = vfs_add_const_i64_vec(&udev->rootfs, xsdr_params_m2_lm7_1_rev000, SIZEOF_ARRAY(xsdr_params_m2_lm7_1_rev000)); if (res) - USDR_LOG("UDEV", USDR_LOG_WARNING, "Unable to set device name \"xsdr\"!\n"); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "Unable to set device name \"xsdr\"!\n"); } d->xdev.dpump = d->double_pump; @@ -1332,7 +1330,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha struct sfetrx4_config rxcfg; res = parse_sfetrx4(dformat, &lchans, pktsyms, channels->count, &rxcfg); if (res) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "Unable to parse RX stream configuration!\n"); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_ERROR, "Unable to parse RX stream configuration!\n"); return res; } @@ -1365,7 +1363,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &hwchs); if (res) { - USDR_LOG("XSDR", USDR_LOG_ERROR, "Unable to create stream '%s': error=%d\n", sid, res); + USDR_LL_LOG(d->base.dev, "XSDR", USDR_LOG_ERROR, "Unable to create stream '%s': error=%d\n", sid, res); return res; } @@ -1383,7 +1381,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha struct sfetrx4_config txcfg; res = parse_sfetrx4(dformat, &lchans, pktsyms, channels->count, &txcfg); if (res) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "Unable to parse TX stream configuration!\n"); + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_ERROR, "Unable to parse TX stream configuration!\n"); return res; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index d4e34868..44413a63 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -114,7 +114,7 @@ static int _xsdr_init_revo(xsdr_dev_t *d); static int _xsdr_checkpwr(xsdr_dev_t *d) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "checkpwr: %d\n", d->pwr_en); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "checkpwr: %d\n", d->pwr_en); if (!d->pwr_en) { return xsdr_pwren(d, true); } @@ -284,7 +284,7 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, if (res) return res; - USDR_LOG("XDEV", USDR_LOG_DEBUG, "MMCM DRP_TX CMD=%08x RB=%08x\n", drp_cmd, rb); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_DEBUG, "MMCM DRP_TX CMD=%08x RB=%08x\n", drp_cmd, rb); if (meminsz) { *((uint16_t*)pin) = rb >> 16; @@ -303,7 +303,7 @@ int xsdr_upd_phase(xsdr_dev_t *d) g_tx_cfg_raw.ports[CLKOUT_PORT_0].delay = (raw >> 3); } - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_TX set phase to %d.%d\n", g_tx_cfg_raw.ports[CLKOUT_PORT_0].delay, g_tx_cfg_raw.ports[CLKOUT_PORT_0].phase); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM_TX set phase to %d.%d\n", g_tx_cfg_raw.ports[CLKOUT_PORT_0].delay, g_tx_cfg_raw.ports[CLKOUT_PORT_0].phase); mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &g_tx_cfg_raw); // Reset MMCM @@ -441,13 +441,13 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; } - USDR_LOG("XDEV", USDR_LOG_INFO, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d VCO=%.3f MHZ OFF=%d\n", + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MMCM_TX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d FWDCLK_DELAY%s = %d (VCO %d) SISO_DDR=%d VCO=%.3f MHZ OFF=%d REF=%s\n", tx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io, (d->tx_override_phase) ? "_OVR" : "", cfg_raw.ports[CLKOUT_PORT_0].delay, cfg_raw.ports[CLKOUT_PORT_0].phase, d->base.lml_mode.txsisoddr, tx_mclk * (cfg_raw.ports[CLKOUT_PORT_FB].period_l + cfg_raw.ports[CLKOUT_PORT_FB].period_h) / 1.0e6, - txphase_off); + txphase_off, rx_master ? "RX" : "TX"); res = res ? res : mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &cfg_raw); @@ -467,7 +467,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, if (res) break; - USDR_LOG("XDEV", USDR_LOG_DEBUG, "MMCM FLAGS:%08x\n", rb); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_DEBUG, "MMCM FLAGS:%08x\n", rb); if (rb & (1 << 8)) { g_tx_cfg_raw = cfg_raw; return 0; @@ -476,7 +476,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, usleep(10); } - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM Redy flag timed out!\n"); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM Redy flag timed out!\n"); return -EIO; } @@ -521,7 +521,7 @@ int xsdr_configure_lml_mmcm_rx(xsdr_dev_t *d) cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; } - USDR_LOG("XDEV", USDR_LOG_ERROR, "MMCM_RX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d\n", + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM_RX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d\n", rx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io); res = (res) ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, @@ -557,7 +557,7 @@ int xsdr_configure_lml_mmcm_rx(xsdr_dev_t *d) if (res) break; - USDR_LOG("XDEV", USDR_LOG_INFO, "MMCM FLAGS:%08x\n", rb); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MMCM FLAGS:%08x\n", rb); if (rb & (1 << 16)) return 0; @@ -656,6 +656,7 @@ static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, static int _xsdr_calibrate_lml(xsdr_dev_t *d) { + lldev_t dev = d->base.lmsstate.dev; int res = 0; bool mmcm_rx_only_path = (!d->base.tx_run[0] && !d->base.tx_run[1]); bool old_rx_run[2] = { d->base.rx_run[0], d->base.rx_run[1] }; @@ -745,7 +746,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } badness *= 1.0 * check_to / (w + 1); // Rescale - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", ph - 1, w, + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", ph - 1, w, errs[0], errs[1], errs[2], errs[3], (long long)badness); if (res || (d->dpump ? noerrors_v2(errs, &badness) : noerrors_v4(errs, &badness))) { phase_m = ph; @@ -771,7 +772,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) phase_m = (phase_max + phase_min) / 2; } - USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring RX pahse to %d (bandness=%" PRId64 ") PH_MIN=%d PH_MAX=%d\n", + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Restoring RX pahse to %d (bandness=%" PRId64 ") PH_MIN=%d PH_MAX=%d\n", phase_m - 1, badness_m, phase_min, phase_max); // Try our best at least @@ -793,7 +794,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) badness *= 1.0 * check_to / (w + 1); // Rescale rx_badness = badness; if (badness > 100 /*badness_m * 2*/) { - USDR_LOG("XDEV", USDR_LOG_WARNING, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, errs[0], errs[1], errs[2], errs[3], (long long)badness); g_clk_reduce++; @@ -836,7 +837,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : usleep(100); res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { - USDR_LOG("XDEV", USDR_LOG_WARNING, "FAIL_PHASE_RX=%2d PH=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", d->lmlcal_rx_phase, ph - 1, + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "FAIL_PHASE_RX=%2d PH=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", d->lmlcal_rx_phase, ph - 1, errs[0], errs[1], errs[2], errs[3], (long long)badness); if (badness > 20) { if (failed_rxcnt < 6) { @@ -851,7 +852,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness); - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e\n", ph - 1, + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e\n", ph - 1, errs[0], errs[1], errs[2], errs[3], iqserrs, (double)badness); if (res || (noerrors_v4(errs, &badness) /* && (iqserrs == 0)*/) || (rty > 1 && badness < 20)) { phase_m = ph; @@ -867,7 +868,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) return res; if ((rty == 0 && iqserrs != 0) || iqserrs > 40) { - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX[%d]=%2d ABIQ=%d\n", g, ph - 1, iqserrs); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX[%d]=%2d ABIQ=%d\n", g, ph - 1, iqserrs); unsigned msk[12] = { 0b1100, 0b0110, 0b0011, 0b1001, 0b1000, 0b0100, 0b0010, 0b0001, 0b1100, 0b0110, 0b1001, 0b1100 }; res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : msk[g + 1]); @@ -877,13 +878,13 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : usleep(10); } else if (g > 0) { - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); break; } } if ((rty == 0 && iqserrs != 0) || iqserrs > 40) { - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); continue; } @@ -903,7 +904,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_limelight_toggle_ntx(&d->base.lmsstate); check_rx = true; } - USDR_LOG("XDEV", USDR_LOG_WARNING, "Restoring TX pahse to %d (bandness=%" PRId64 ")\n", + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Restoring TX pahse to %d (bandness=%" PRId64 ")\n", phase_m, badness_m); // Try our best at least @@ -926,7 +927,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) tx_badness = badness_m; tx_iqerrs = iqserrs2; - USDR_LOG("XDEV", USDR_LOG_INFO, "RESTORE PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d - %6d] BD=%.3e\n", phase_m - 1, + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "RESTORE PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d - %6d] BD=%.3e\n", phase_m - 1, errs[0], errs[1], errs[2], errs[3], iqserrs, iqserrs2, (double)badness_m); phase_tx_calibrated: @@ -951,7 +952,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (rx_badness || (!mmcm_rx_only_path && (tx_badness || tx_iqerrs))) { bool severe = (rx_badness > 100) || (!mmcm_rx_only_path && (tx_badness > 100 || tx_iqerrs > 10)); - USDR_LOG("XDEV", severe ? USDR_LOG_ERROR : USDR_LOG_WARNING, "LML Calibration failed: RX_BADNESS=%"PRId64" TX_BADNESS=%"PRId64" TX_IQERRS=%d\n", + USDR_LL_LOG(dev, "XDEV", severe ? USDR_LOG_ERROR : USDR_LOG_WARNING, "LML Calibration failed: RX_BADNESS=%"PRId64" TX_BADNESS=%"PRId64" TX_IQERRS=%d\n", rx_badness, mmcm_rx_only_path ? 0 : tx_badness, mmcm_rx_only_path ? 0 : tx_iqerrs); if (res == 0 && severe) @@ -971,7 +972,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, int res; if (!(((d->hwid) & 0xff) & PHY_CFG_VALID_MSK)) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "Incompatible firmware, please update to 20250501 at least!\n"); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "Incompatible firmware, please update to 20250501 at least!\n"); return -ENOTSUP; } @@ -1032,7 +1033,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); - USDR_LOG("XDEV", USDR_LOG_INFO, "PHASE=%d\n", h); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE=%d\n", h); res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x00000000); unsigned tmp; //, tmp2; for (unsigned k = 0; k < 100; k++) { @@ -1087,7 +1088,7 @@ int xsdr_clk_debug_info(xsdr_dev_t *d) } - USDR_LOG("XDEV", USDR_LOG_WARNING, "PHY - RX %08x (%d) / TX %08x (%d) / AUX %08x (%d) %d/%d/%d/%d %d/%d/%d/%d %d/%d/%d/%d -- %d \n", + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "PHY - RX %08x (%d) / TX %08x (%d) / AUX %08x (%d) %d/%d/%d/%d %d/%d/%d/%d %d/%d/%d/%d -- %d \n", crx, crx & 0xfffffff, ctx, ctx & 0xfffffff, caux, caux & 0xfffffff, @@ -1098,13 +1099,13 @@ int xsdr_clk_debug_info(xsdr_dev_t *d) int xsdr_set_rx_port_switch(xsdr_dev_t *d, unsigned path) { - USDR_LOG("XDEV", USDR_LOG_INFO, "RXSW:%d\n", path); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "RXSW:%d\n", path); return dev_gpo_set(d->base.lmsstate.dev, IGPO_RXSW, path); } int xsdr_set_tx_port_switch(xsdr_dev_t *d, unsigned path) { - USDR_LOG("XDEV", USDR_LOG_INFO, "TXSW:%d\n", path); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "TXSW:%d\n", path); return dev_gpo_set(d->base.lmsstate.dev, IGPO_TXSW, path); } @@ -1276,7 +1277,7 @@ const lms7002m_lml_map_t lms7nfe_get_lml_portcfg_o(unsigned chs, unsigned flags, // else if (flags & RFIC_SWAP_IQA) // diqidx |= 12; - USDR_LOG("XDEV", USDR_LOG_WARNING, "diqidx=%d\n", diqidx); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "diqidx=%d\n", diqidx); assert(diqidx < (sizeof(diqarray)/sizeof(diqarray[0]))); return diqarray[diqidx]; } @@ -1386,7 +1387,7 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, if (res) return res; - USDR_LOG("XDEV", USDR_LOG_INFO, "Setting FREQ %.3f Mhz, LNB %.3f Mhz\n", freq / 1.0e6, d->lms7_lob / 1.0e6); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "Setting FREQ %.3f Mhz, LNB %.3f Mhz\n", freq / 1.0e6, d->lms7_lob / 1.0e6); freq = d->lms7_lob; } else { d->lms7_lob = 0; @@ -1545,7 +1546,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) d->pmic_ch145_valid = true; } - USDR_LOG("XDEV", (good_pmic) ? USDR_LOG_INFO : USDR_LOG_ERROR, "PMIC_RFIC ver %04x (%d)\n", + USDR_LL_LOG(dev, "XDEV", (good_pmic) ? USDR_LOG_INFO : USDR_LOG_ERROR, "PMIC_RFIC ver %04x (%d)\n", rev, d->pmic_ch145_valid); if (hwid == SSDRPRO_DEV) { @@ -1580,7 +1581,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) } if (!pg) { - USDR_LOG("XDEV", USDR_LOG_INFO, "Couldn't set PMIC voltages!\n"); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "Couldn't set PMIC voltages!\n"); return -EIO; } @@ -1601,7 +1602,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) usleep(100000); res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x002F0000, &chipver); - USDR_LOG("XDEV", USDR_LOG_INFO, "LMS7002 version %08x\n", chipver); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "LMS7002 version %08x\n", chipver); for (unsigned j = 0; j < 5; j++) { res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x81); @@ -1609,7 +1610,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x800000ff, &chipver); res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x000f0000, &chipver); - USDR_LOG("XDEV", USDR_LOG_INFO, "LMS8001 version %08x\n", chipver); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "LMS8001 version %08x\n", chipver); res = res ? res : lms8001_create(dev, d->base.lmsstate.subdev, 0, lms8_step, &d->lms8); @@ -1627,7 +1628,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) } if (!getenv("USDR_BARE_DEV") && (!d->lms8_alive)) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "LMS8001 not detected, check the board!\n"); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "LMS8001 not detected, check the board!\n"); return -EFAULT; } @@ -1710,7 +1711,7 @@ int _xsdr_init_revo(xsdr_dev_t *d) if (res) return res; - USDR_LOG("XDEV", USDR_LOG_INFO, "PMIC_LMS7 ver %04x\n", rev); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PMIC_LMS7 ver %04x\n", rev); if (rev != 0xe001) { return -EIO; } @@ -1739,7 +1740,7 @@ int _xsdr_init_revo(xsdr_dev_t *d) usleep(1000); } if (!bpg) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "PMIC_LMS7: couldn't set LMS7 volatges, giving up!\n"); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "PMIC_LMS7: couldn't set LMS7 volatges, giving up!\n"); return -EIO; } @@ -1751,7 +1752,7 @@ int _xsdr_init_revo(xsdr_dev_t *d) if (res) return res; - USDR_LOG("XDEV", USDR_LOG_INFO, "PMIC_RFIC ver %04x\n", rev); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PMIC_RFIC ver %04x\n", rev); if (rev != 0xe001) { return -EIO; } @@ -1769,7 +1770,7 @@ int _xsdr_init_revo(xsdr_dev_t *d) if (res) return res; - USDR_LOG("XDEV", USDR_LOG_INFO, "DAC_ID=%x\n", devid); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "DAC_ID=%x\n", devid); switch (devid) { case 0x0194: case 0x0195: @@ -1793,7 +1794,7 @@ int _xsdr_init_revo(xsdr_dev_t *d) return res; d->dac_old_r5 = true; - USDR_LOG("XDEV", USDR_LOG_INFO, "Detected r5\n"); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "Detected r5\n"); return 0; rev4_check: @@ -1806,7 +1807,7 @@ int _xsdr_init_revo(xsdr_dev_t *d) return res; if (cfg == 0xdeadbeef) { - USDR_LOG("XDEV", USDR_LOG_ERROR, "MCP Config = %08x\n", cfg); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "MCP Config = %08x\n", cfg); } // unsigned q, r; @@ -1826,7 +1827,7 @@ int _xsdr_init_revo(xsdr_dev_t *d) // } d->dac_old_r5 = false; - USDR_LOG("XDEV", USDR_LOG_INFO, "Detected r4\n"); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "Detected r4\n"); return 0; } @@ -1836,14 +1837,14 @@ int _xsdr_pwren_revx(xsdr_dev_t *d, bool on) int res; lldev_t dev = d->base.lmsstate.dev; - USDR_LOG("XDEV", (on && !d->pmic_ch145_valid) ? USDR_LOG_ERROR : USDR_LOG_INFO, + USDR_LL_LOG(dev, "XDEV", (on && !d->pmic_ch145_valid) ? USDR_LOG_ERROR : USDR_LOG_INFO, "RFIC PWR:%d CH145:%d\n", on, d->pmic_ch145_valid); if (on && !d->pmic_ch145_valid) { // 1V45 is cricial for Rev0 XSDR and can be ignored in Rev2 int id = -1; res = xsdr_gettemp_id(d, &id); if (res == 0) { - USDR_LOG("XDEV", USDR_LOG_WARNING, "TEMP ID: %04x\n", id); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "TEMP ID: %04x\n", id); } return -EIO; @@ -1885,7 +1886,7 @@ int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) else if (vio_mv < 1600) vio_mv = 1600; - USDR_LOG("XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, vio_mv); } @@ -1894,7 +1895,7 @@ int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) else if (vio_mv < 1600) vio_mv = 1600; - USDR_LOG("XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, d->ssdr_pro ? 3 : 1, vio_mv); } @@ -1953,7 +1954,7 @@ int xsdr_init(xsdr_dev_t *d) return res; hwcfg_devid = (hwid >> 16) & 0xff; - USDR_LOG("XDEV", USDR_LOG_ERROR, "HWID %08x\n", hwid); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "HWID %08x\n", hwid); const uint8_t phycfg_id = hwid & 0xff; const bool rx_port_is_1 = ((phycfg_id & PHY_CFG_LML2_IS_RX) != PHY_CFG_LML2_IS_RX); @@ -1984,7 +1985,7 @@ int xsdr_init(xsdr_dev_t *d) case SSDR_DEV: d->new_rev = true; d->ssdr = true; break; case SSDRPRO_DEV: d->new_rev = true; d->ssdr = true; d->ssdr_pro = true; break; default: - USDR_LOG("XDEV", USDR_LOG_ERROR, "unsupported hwcfg_devid=%02x\n", hwcfg_devid); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "unsupported hwcfg_devid=%02x\n", hwcfg_devid); if (getenv("XSDR_FORCE")) { d->new_rev = true; @@ -2035,7 +2036,7 @@ int xsdr_dtor(xsdr_dev_t *d) res = res ? res : lp8758_vout_ctrl(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, 0, 1); } - USDR_LOG("XDEV", USDR_LOG_INFO, "destroyed\n"); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "destroyed\n"); return res; } @@ -2047,7 +2048,7 @@ int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen) if (d->base.cgen_clk == 0) { const unsigned default_rate = 1000000; - USDR_LOG("XDEV", USDR_LOG_WARNING, "clock rate isn't set, defaulting to %d!\n", default_rate); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "clock rate isn't set, defaulting to %d!\n", default_rate); res = xsdr_set_samplerate_ex(d, rxen ? default_rate : 0, txen ? default_rate : 0, @@ -2274,7 +2275,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) uint8_t old_rx_lna = d->base.rx_rfic_path; uint8_t old_tx_lna = d->base.tx_rfic_path; uint8_t tx_loss[2] = { d->base.tx_loss[0] , d->base.tx_loss[1] }; - + lldev_t dev = d->base.lmsstate.dev; if (channel > 1) { return -EINVAL; } @@ -2298,7 +2299,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) return res; if ((param & XSDR_CAL_RXLO) && (rx_lo > 0)) { - USDR_LOG("LMS7", USDR_LOG_INFO, "------------------ Calibration RXLO(%c) ------------------\n", 'A' + channel); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "------------------ Calibration RXLO(%c) ------------------\n", 'A' + channel); // Do not touch anything since it may affect optimal I/Q correction values // Turn OFF digital RX LO cancellation in RSP @@ -2335,7 +2336,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if ((param & XSDR_CAL_RXIQIMB) && (rx_lo > 0)) { // TODO if TX was disabled enable TX - USDR_LOG("LMS7", USDR_LOG_INFO, "------------------ Calibration RXIQIMB(%c) ------------------\n", 'A' + channel); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "------------------ Calibration RXIQIMB(%c) ------------------\n", 'A' + channel); if (!externallb) { res = (res) ? res : _xsdr_path_lb(d, rx_rfic_lna, tx_rfic_band, channel, true); } @@ -2350,7 +2351,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) //res = (res) ? res : lms7_afe_ctrl(&d->lmsstate, true, false, false, false); } if (res) { - USDR_LOG("LMS7", USDR_LOG_WARNING, " RXIQIMB failed: res=%d\n", res); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " RXIQIMB failed: res=%d\n", res); return res; } if (sarray) { @@ -2372,12 +2373,12 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) return res; if (param & XSDR_CAL_TXLO) { - USDR_LOG("LMS7", USDR_LOG_INFO, "------------------ Calibration TXLO(%c) ------------------\n", 'A' + channel); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "------------------ Calibration TXLO(%c) ------------------\n", 'A' + channel); // res = (res) ? res : lms7_txtsp_dc_corr(&d->base.lmsstate, true); // res = (res) ? res : lms7002m_xxtsp_dc_corr(&d->base.lmsstate, LMS_TXTSP, false, 0); res = (res) ? res : calibrate_txlo(&cops); if (res) { - USDR_LOG("LMS7", USDR_LOG_WARNING, " TXLO failed: res=%d\n", res); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " TXLO failed: res=%d\n", res); return res; } if (sarray) { @@ -2387,10 +2388,10 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) } if (param & XSDR_CAL_TXIQIMB) { - USDR_LOG("LMS7", USDR_LOG_INFO, "------------------ Calibration TXIQIMB(%c) ------------------\n", 'A' + channel); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "------------------ Calibration TXIQIMB(%c) ------------------\n", 'A' + channel); res = (res) ? res : calibrate_txiqimb(&cops); if (res) { - USDR_LOG("LMS7", USDR_LOG_WARNING, " TXIQIMB failed: res=%d\n", res); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " TXIQIMB failed: res=%d\n", res); return res; } if (sarray) { @@ -2405,14 +2406,14 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) res = (res) ? res : lms7002m_sxx_disable(&d->base.lmsstate, SXX_TX); } if (res) { - USDR_LOG("LMS7", USDR_LOG_WARNING, "restore configuration failed: res=%d\n", res); + USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, "restore configuration failed: res=%d\n", res); return res; } } if (norestore) return 0; - USDR_LOG("LMS7", USDR_LOG_INFO, "Calibration: restoring RXPATH=%d TXPATH=%d TXCFG=%d RXCFG=%d\n", + USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "Calibration: restoring RXPATH=%d TXPATH=%d TXCFG=%d RXCFG=%d\n", old_rx_lna, old_tx_lna, old_dsp_txcfg, old_dsp_rxcfg); // Restore individual PAD attenuation diff --git a/src/lib/ipblks/streams/dma_rx_32.c b/src/lib/ipblks/streams/dma_rx_32.c index 7440aedc..2d663f02 100644 --- a/src/lib/ipblks/streams/dma_rx_32.c +++ b/src/lib/ipblks/streams/dma_rx_32.c @@ -27,10 +27,10 @@ int dma_rx32_reset(lldev_t lldev, if (tmp & 0x40000000) { if (tmp == 0xffffffff) { - USDR_LOG("DMRX", USDR_LOG_ERROR, "DMA engine is dead!\n"); + USDR_LL_LOG(lldev, "DMRX", USDR_LOG_ERROR, "DMA engine is dead!\n"); return -EIO; } - USDR_LOG("DMRX", USDR_LOG_WARNING, "DMA engine is active!\n"); + USDR_LL_LOG(lldev, "DMRX", USDR_LOG_WARNING, "DMA engine is active!\n"); } // DMA STOP, FE RESET diff --git a/src/lib/ipblks/streams/sfe_rx_4.c b/src/lib/ipblks/streams/sfe_rx_4.c index 48ebf9a3..6513703c 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.c +++ b/src/lib/ipblks/streams/sfe_rx_4.c @@ -174,15 +174,15 @@ struct rfe_burster_data { }; typedef struct rfe_burster_data rfe_burster_data_t; -static int burst_fe_calculate(const rfe_config_t* cfg, const struct stream_config* psc, unsigned chans_raw, unsigned ch_bits, rfe_burster_data_t* out) +static int burst_fe_calculate(lldev_t lldev, const rfe_config_t* cfg, const struct stream_config* psc, unsigned chans_raw, unsigned ch_bits, rfe_burster_data_t* out) { if (psc->burstspblk > cfg->cfg_max_bursts) { - USDR_LOG("STRM", USDR_LOG_ERROR, "SFERX4: bursts count `%d' exeeds maximum %d!\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_ERROR, "SFERX4: bursts count `%d' exeeds maximum %d!\n", psc->burstspblk, cfg->cfg_max_bursts); return -EINVAL; } if (chans_raw > cfg->cfg_data_lanes) { - USDR_LOG("STRM", USDR_LOG_ERROR, "SFERX4: channel count %d isn't supported!\n", chans_raw); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_ERROR, "SFERX4: channel count %d isn't supported!\n", chans_raw); return -EINVAL; } @@ -197,7 +197,7 @@ static int burst_fe_calculate(const rfe_config_t* cfg, const struct stream_confi unsigned fifo_capacity = cfg->cfg_fifo_ram_bytes / (bwords * cfg->cfg_data_lanes_bytes); if ((bursts != 0) && (bwords > cfg->limit_burst_words)) { - USDR_LOG("STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: %d samples @%s exeeds max burst size: %d words!\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: %d samples @%s exeeds max burst size: %d words!\n", psc->spburst, psc->sfmt, cfg->limit_burst_words); return -EINVAL; } @@ -239,10 +239,10 @@ static int burst_fe_calculate(const rfe_config_t* cfg, const struct stream_confi unsigned ex_bytes = ((bwords + best_bursts - 1) / best_bursts) * cfg->cfg_data_lanes_bytes - (samplerperbursts / best_bursts) * bps / 8; - USDR_LOG("STRM", USDR_LOG_INFO, "SFERX4: Adding stub %d bytes to transfer for %d burst configuration\n", ex_bytes, best_bursts); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "SFERX4: Adding stub %d bytes to transfer for %d burst configuration\n", ex_bytes, best_bursts); bursts = best_bursts; } else { - USDR_LOG("STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: %d samples @%s can't be represented with any burst count, capacity %d (FIFO is %d)!\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: %d samples @%s can't be represented with any burst count, capacity %d (FIFO is %d)!\n", psc->spburst, psc->sfmt, fifo_capacity, cfg->cfg_fifo_ram_bytes); return -EINVAL; } @@ -261,13 +261,13 @@ static int burst_fe_calculate(const rfe_config_t* cfg, const struct stream_confi } if (samplerperbursts % cfg->limit_samples_mod) { - USDR_LOG("STRM", USDR_LOG_ERROR, "SFERX4: Burst size should be multiple of %d, requested %d x %d!\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_ERROR, "SFERX4: Burst size should be multiple of %d, requested %d x %d!\n", cfg->limit_samples_mod, samplerperbursts, bursts); return -EINVAL; } if (fifo_capacity > SFE_CMD_BF_BTOTAL_MASK) { - USDR_LOG("STRM", USDR_LOG_WARNING, "SFERX4: fifo capacity exceeds fe capabilities, requested: %d!", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_WARNING, "SFERX4: fifo capacity exceeds fe capabilities, requested: %d!", fifo_capacity); fifo_capacity = SFE_CMD_BF_BTOTAL_MASK; } @@ -302,6 +302,7 @@ static int _configure_simple_fe_generic(const sfe_cfg_t* fe, unsigned chns, struct fifo_config* pfc) { + lldev_t lldev = fe->dev; // Some constants are derived from IPBLK_PARAM_BUFFER_SIZE_ADDR // and any other value may break configuration if ((1 << IPBLK_PARAM_BUFFER_SIZE_ADDR) != fe->cfg_fifomaxbytes) @@ -318,7 +319,7 @@ static int _configure_simple_fe_generic(const sfe_cfg_t* fe, cfg.limit_burst_samples = (1u << IPBLK_PARAM_BWORDS); // Replace to cfg_fifomaxbytes rfe_burster_data_t data; - res = burst_fe_calculate(&cfg, psc, chns, bps, &data); + res = burst_fe_calculate(lldev, &cfg, psc, chns, bps, &data); if (res) { return res; } @@ -328,7 +329,7 @@ static int _configure_simple_fe_generic(const sfe_cfg_t* fe, unsigned fifo_capacity = data.capacity; unsigned samplerperbursts = data.samples; - USDR_LOG("STRM", USDR_LOG_INFO, "SFERX4: Stream %s/%d configured in %d words (%d samples) X %d bursts (%d bits per sym); fifo capacity %d (FMT:%x FE:%d)\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "SFERX4: Stream %s/%d configured in %d words (%d samples) X %d bursts (%d bits per sym); fifo capacity %d (FMT:%x FE:%d)\n", psc->sfmt, samples_mod, bwords, samplerperbursts, bursts, bps, fifo_capacity, chfmt, fe_format); // Put everything into reset @@ -359,6 +360,7 @@ int sfe_rx4_configure(const sfe_cfg_t* fe, struct fifo_config* pfc, uint64_t *pwr_ch_mask) { + lldev_t lldev = fe->dev; struct bitsfmt bfmt = get_bits_fmt(psc->sfmt); if (strcmp((const char*)bfmt.func, &DSPFUNC_CFFT_LPWR_I16[1]) == 0) { unsigned fft_size = 512; @@ -367,14 +369,14 @@ int sfe_rx4_configure(const sfe_cfg_t* fe, // Check why /2 is here if ((psc->burstspblk != 0) && (bwords > ((1u << SFE_CMD_BF_BWORDS_WIDTH)/2))) { - USDR_LOG("STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: FFT512 %d samples @%s exeeds max burst size!\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: FFT512 %d samples @%s exeeds max burst size!\n", psc->spburst, psc->sfmt); return -EINVAL; } return _configure_simple_fe_generic(fe, psc, bps, fft_size, IFMT_DSP, IFMT_CH_xx10, 1, pfc); } else if (bfmt.bits == 0) { - USDR_LOG("STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: RX Stream format `%s' not supported!\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: RX Stream format `%s' not supported!\n", psc->sfmt); return -EINVAL; } @@ -426,7 +428,7 @@ int sfe_rx4_configure(const sfe_cfg_t* fe, } if (chns == 0) { - USDR_LOG("STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: RX channel count %d is not supported in configuration [%d, %d, %d, %d, %d, %d, %d, %d ... ]!\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_CRITICAL_WARNING, "SFERX4: RX channel count %d is not supported in configuration [%d, %d, %d, %d, %d, %d, %d, %d ... ]!\n", psc->chcnt, psc->channels.ch_map[0], psc->channels.ch_map[1], psc->channels.ch_map[2], psc->channels.ch_map[3], psc->channels.ch_map[4], psc->channels.ch_map[5], psc->channels.ch_map[6], psc->channels.ch_map[7]); return -EINVAL; @@ -450,6 +452,7 @@ int sfe_rx4_configure(const sfe_cfg_t* fe, int sfe_rx4_throttle(const sfe_cfg_t* fe, bool enable, uint8_t send, uint8_t skip) { + lldev_t lldev = fe->dev; int res; // Put everything into reset @@ -461,9 +464,9 @@ int sfe_rx4_throttle(const sfe_cfg_t* fe, bool enable, uint8_t send, uint8_t ski return res; if (!enable) { - USDR_LOG("STRM", USDR_LOG_INFO, "SFERX4: burst throttling is disabled\n"); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "SFERX4: burst throttling is disabled\n"); } else { - USDR_LOG("STRM", USDR_LOG_INFO, "SFERX4: burst throttling is enabled %d/%d\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "SFERX4: burst throttling is enabled %d/%d\n", send + 1, (unsigned)send + skip + 2); } return 0; @@ -472,11 +475,12 @@ int sfe_rx4_throttle(const sfe_cfg_t* fe, bool enable, uint8_t send, uint8_t ski int sfe_rx4_startstop(const sfe_cfg_t* fe, bool start) { + lldev_t lldev = fe->dev; int res = _sfe_srx4_reg_set(fe, FE_CMD_RESET, (start) ? RX_SCMD_START_IMM : RX_SCMD_STOP_IMM); if (res) return res; - USDR_LOG("STRM", USDR_LOG_NOTE, "SFERX4: RX Stream configured to %s\n", (start) ? "start" : "stop"); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_NOTE, "SFERX4: RX Stream configured to %s\n", (start) ? "start" : "stop"); return 0; } @@ -491,13 +495,13 @@ int sfe_rf4_nco_enable(const sfe_cfg_t* fe, bool enable, unsigned iqaccum) res = (res) ? res : lowlevel_reg_wr32(fe->dev, fe->subdev, fe->cfg_base + FE_CMD_REG_CFG_CORDIC, 0); } - USDR_LOG("STRM", USDR_LOG_INFO, "SFERX4: NCO Active: %d\n", enable); + USDR_LL_LOG(fe->dev, "STRM", USDR_LOG_INFO, "SFERX4: NCO Active: %d\n", enable); return res; } int sfe_rf4_nco_freq(const sfe_cfg_t* fe, int32_t freq) { - USDR_LOG("STRM", USDR_LOG_INFO, "SFERX4: NCO FREQ Set to %d\n", freq); + USDR_LL_LOG(fe->dev, "STRM", USDR_LOG_INFO, "SFERX4: NCO FREQ Set to %d\n", freq); return lowlevel_reg_wr32(fe->dev, fe->subdev, fe->cfg_base + FE_CMD_REG_FREQ_CORDIC, freq); } @@ -507,10 +511,11 @@ int sfe_rf4_nco_freq(const sfe_cfg_t* fe, int32_t freq) int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, struct fifo_config* pfc, bool* out_pack_3x16) { + lldev_t lldev = fe->dev; struct bitsfmt bfmt = get_bits_fmt(psc->sfmt); unsigned bps = bfmt.bits; if (bps != 12 && bps != 16) { - USDR_LOG("STRM", USDR_LOG_ERROR, "EXFERX: sample size %d isn't supported!\n", bps); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_ERROR, "EXFERX: sample size %d isn't supported!\n", bps); return -EINVAL; } unsigned chns = psc->chcnt; @@ -532,11 +537,11 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str break; } if (j > fe->cfg_raw_chans || j == 0) { - USDR_LOG("STRM", USDR_LOG_ERROR, "EXFERX: Unsupported channel count %d!\n", chns); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_ERROR, "EXFERX: Unsupported channel count %d!\n", chns); return -EINVAL; } if (fe->cfg_raw_chans > MAX_EX_CHANS) { - USDR_LOG("STRM", USDR_LOG_ERROR, "EXFERX: Maximum channel count supported by the core is 16, requested %d!", fe->cfg_raw_chans); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_ERROR, "EXFERX: Maximum channel count supported by the core is 16, requested %d!", fe->cfg_raw_chans); return -EINVAL; } @@ -551,7 +556,7 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str cfg.limit_burst_samples = fe->cfg_fifomaxbytes; rfe_burster_data_t data; - res = burst_fe_calculate(&cfg, psc, chns, bps, &data); + res = burst_fe_calculate(lldev, &cfg, psc, chns, bps, &data); if (res) { return res; } @@ -562,7 +567,7 @@ int exfe_rx4_configure(const sfe_cfg_t* fe, const struct stream_config* psc, str unsigned samplerperbursts = data.samples; unsigned raw_burst_sz = (bps == 12) ? (chns * samplerperbursts * 12 + 7) / 8 : chns * samplerperbursts * 2; - USDR_LOG("STRM", USDR_LOG_INFO, "EXFERX: Stream %s configured in %d bytes (%d samples x %d chans x %d bits %s) X %d bursts; naked burst size %d; fifo capacity %d\n", + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "EXFERX: Stream %s configured in %d bytes (%d samples x %d chans x %d bits %s) X %d bursts; naked burst size %d; fifo capacity %d\n", psc->sfmt, bbytes, samplerperbursts, 1 << chlg, bps, pack_3x16 ? "3x16 mode" : "", bursts, raw_burst_sz, fifo_capacity); @@ -595,6 +600,7 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, unsigned total_chan_num, const channel_info_t* newmap_orig) { + lldev_t lldev = fe->dev; int res = 0; uint8_t chmap[MAX_EX_CHANS]; uint8_t chmap_o[MAX_EX_CHANS]; @@ -655,9 +661,9 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, } - USDR_LOG("STRM", USDR_LOG_INFO, "NEW_MAP %d x %d CHANS:\n", total_chan_num, complex ? 2 : 1); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "NEW_MAP %d x %d CHANS:\n", total_chan_num, complex ? 2 : 1); for (unsigned g = 0; g < fe->cfg_raw_chans; g++) { - USDR_LOG("STRM", USDR_LOG_INFO, "NEW_MAP[%d]: %d => %d\n", g, + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "NEW_MAP[%d]: %d => %d\n", g, newmap_orig->ch_map[g], newmap->ch_map[g]); } @@ -686,10 +692,10 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, } for (unsigned g = 0; g < fe->cfg_raw_chans; g++) { - USDR_LOG("STRM", USDR_LOG_INFO, "EXFE: CH%d => %d (orig %d MSK %x/%d) %s", g, chmap[g], chmap_o[g], msk, total_chan_num, flag_swap_iq[g] ? "SWAP_IQ" : ""); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "EXFE: CH%d => %d (orig %d MSK %x/%d) %s", g, chmap[g], chmap_o[g], msk, total_chan_num, flag_swap_iq[g] ? "SWAP_IQ" : ""); } for (unsigned f = 0; f < lg_chans; f++) { - USDR_LOG("STRM", USDR_LOG_INFO, "EXFE: STAGE_%d: %04x", f, ch_remapped[f]); + USDR_LL_LOG(lldev, "STRM", USDR_LOG_INFO, "EXFE: STAGE_%d: %04x", f, ch_remapped[f]); } res = res ? res : _sfe_exrx_reg_set(fe, EXFE_CMD_SHUFFLE_0, ch_remapped[0]); diff --git a/src/lib/ipblks/streams/sfe_tx_4.c b/src/lib/ipblks/streams/sfe_tx_4.c index ff9d33e1..b82d988a 100644 --- a/src/lib/ipblks/streams/sfe_tx_4.c +++ b/src/lib/ipblks/streams/sfe_tx_4.c @@ -77,7 +77,7 @@ int sfe_extx4_push_ring_buffer(lldev_t dev, *creg2 = tsh; } - USDR_LOG("EXTX", USDR_LOG_DEBUG, "Push buffer %d [%08x:%08x:%08x:%08x] SZ=%d SPS=%d BRST=%d TS=%" PRId64 "\n",cfg_base, + USDR_LL_LOG(dev, "EXTX", USDR_LOG_DEBUG, "Push buffer %d [%08x:%08x:%08x:%08x] SZ=%d SPS=%d BRST=%d TS=%" PRId64 "\n",cfg_base, cfg0, cfg1, tsh, tsl, bytes, samples, bursts, timestamp); return res ? res : lowlevel_reg_wr32(dev, subdev, cfg_base + 3, tsl); diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index e31f3a60..6a6aee21 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -104,7 +104,7 @@ int _sfetrx4_destroy(stream_handle_t* str) stream_sfetrx_dma32_t* stream = (stream_sfetrx_dma32_t*)str; lldev_t dev = stream->base.dev->dev; - USDR_LOG("DSTR", USDR_LOG_DEBUG, "Destroying strem %d\n", stream->ll_streamo); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_DEBUG, "Destroying strem %d\n", stream->ll_streamo); int res; if (stream->type == USDR_ZCPY_RX) { @@ -196,24 +196,24 @@ int _sfetrx4_stream_recv(stream_handle_t* str, #endif if (res == -ETIMEDOUT) { - USDR_LOG("UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " TIMEDOUT:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], res, dma_buf, + USDR_LL_LOG(dev, "UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " TIMEDOUT:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], res, dma_buf, stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); return res; } if (oob_data[0] & 0xffffff) { unsigned pkt_lost = oob_data[0] & 0xffffff; - USDR_LOG("UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " EXTRA:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], res, dma_buf, + USDR_LL_LOG(dev, "UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " EXTRA:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], res, dma_buf, stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); stream->stats.fe_drop += pkt_lost; stream->r_ts += stream->pkt_symbs * pkt_lost; } else if ((oob_data[0] >> 32) != stream->burst_mask) { - USDR_LOG("UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " [%08x] EXTRA:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], stream->burst_mask, res, dma_buf, + USDR_LL_LOG(dev, "UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_INFO, "Recv %016" PRIx64 ".%016" PRIx64 " [%08x] EXTRA:%d buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], stream->burst_mask, res, dma_buf, stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); } else { - USDR_LOG("UDMS", + USDR_LL_LOG(dev, "UDMS", santify_fail ? USDR_LOG_ERROR : USDR_LOG_DEBUG, "Recv %016" PRIx64 ".%016" PRIx64 " EXTRA:- buf=%p seq=%16" PRIu64 " %d.%2d/%2d/%2d/%2d/%2d\n", oob_data[0], oob_data[1], dma_buf, stream->rcnt, srdy, fe_stat, dbno_inram, dbno_xfred, dbno_ntfysent, dbno_confirmed); } @@ -407,7 +407,7 @@ int _sfetrx4_stream_send(stream_handle_t* str, } parse_txcore_stat(stat, &st); - USDR_LOG("UDMS", USDR_LOG_ERROR, "Send timed out (Pstd/Reqd/Cpld/Aired) %2d/%2d/%2d/%2d TAGS:%d FIFO:%d DROP_DMA:%d DROP_FE:%d OVF:%d FULL:%d CPL_NO_DATA:%d FE_SENT:%d READY:%d -- %08x.%08x.%08x.%08x --\n", + USDR_LL_LOG(dev, "UDMS", USDR_LOG_ERROR, "Send timed out (Pstd/Reqd/Cpld/Aired) %2d/%2d/%2d/%2d TAGS:%d FIFO:%d DROP_DMA:%d DROP_FE:%d OVF:%d FULL:%d CPL_NO_DATA:%d FE_SENT:%d READY:%d -- %08x.%08x.%08x.%08x --\n", st.usrbuf_posted, st.usrbuf_requested, st.usrbuf_completed, st.usrbuf_aired, st.pcietags, st.fifo_used, st.drop_dma, st.drop_fe, st.stat_dmareq_ovf, st.fifo_full, st.stat_cpl_nodata, st.bursts_sent, st.core_ready, @@ -443,7 +443,7 @@ int _sfetrx4_stream_send(stream_handle_t* str, //unsigned burst_lost = (stream->stats.fe_drop - pfe) + (stream->stats.dma_drop - pda); stream->stats.pktok ++; - USDR_LOG("UDMS", USDR_LOG_DEBUG, "Send stat %d -- %08x.%08x.%08x.%08x -- HOST:%d WIRE:%d\n" + USDR_LL_LOG(dev, "UDMS", USDR_LOG_DEBUG, "Send stat %d -- %08x.%08x.%08x.%08x -- HOST:%d WIRE:%d\n" " Buff (Pstd/Reqd/Cpld/Aired) %2d/%2d/%2d/%2d DropFE:%"PRId64" DropDMA:%"PRId64" TAGS:%d FIFO:%d\n", stat_sz, stat[0], stat[1], stat[2], stat[3], host_bytes, wire_bytes, st.usrbuf_posted, st.usrbuf_requested, st.usrbuf_completed, st.usrbuf_aired, @@ -483,7 +483,7 @@ int _sfetrx4_stream_send(stream_handle_t* str, stream->tf_data((const void**)stream_buffs, host_bytes * bursts, &buffer, wire_len); } - USDR_LOG("UDMS", USDR_LOG_DEBUG, "Send %lld [TS:%lld LG:%d BRST:%d]\n", + USDR_LL_LOG(dev, "UDMS", USDR_LOG_DEBUG, "Send %lld [TS:%lld LG:%d BRST:%d]\n", (long long)stream->rcnt, (long long)timestamp, lgbursts, (unsigned)wire_len); stream->rcnt++; @@ -513,7 +513,7 @@ static int _sfetrx4_op(stream_handle_t* str, start = true; break; default: - USDR_LOG("UDMS", USDR_LOG_INFO, "Stream[%d] STOP; STATS bytes = %" PRIu64 ", samples = %" PRIu64 ", dropped_fe/dropped_dma/rcvd = %"PRIu64"/%"PRIu64"/%"PRIu64"\n", + USDR_LL_LOG(dev, "UDMS", USDR_LOG_INFO, "Stream[%d] STOP; STATS bytes = %" PRIu64 ", samples = %" PRIu64 ", dropped_fe/dropped_dma/rcvd = %"PRIu64"/%"PRIu64"/%"PRIu64"\n", stream->ll_streamo, stream->stats.wirebytes, stream->stats.symbols, stream->stats.fe_drop, stream->stats.dma_drop, stream->stats.pktok); start = false; } @@ -718,10 +718,11 @@ static int initialize_stream_rx_32(device_t* device, bool data_lane_bifurcation) { int res; + lldev_t dev = device->dev; stream_sfetrx_dma32_t* strdev; uint64_t hw_chan_msk = 0; - res = dma_rx32_reset(device->dev, 0, sx_base); + res = dma_rx32_reset(dev, 0, sx_base); if (res) return res; @@ -743,7 +744,7 @@ static int initialize_stream_rx_32(device_t* device, res = sfe_rx4_check_format(&sc); if (res) { if (pfmt.wire_fmt != NULL) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "Unsupported wire format '%s' by the core\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "Unsupported wire format '%s' by the core\n", sc.sfmt); return res; } @@ -760,12 +761,12 @@ static int initialize_stream_rx_32(device_t* device, 1, logicchs); if (funcs.cfunc == NULL || funcs.sfunc == NULL) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "No transform function '%s'->'%s' are available for 1->%d demux\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "No transform function '%s'->'%s' are available for 1->%d demux\n", sc.sfmt, pfmt.host_fmt, logicchs); return -EINVAL; } if (is_transform_dummy(funcs.cfunc)) { - USDR_LOG("DSTR", USDR_LOG_INFO, "No transformation!\n"); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "No transformation!\n"); } struct bitsfmt bfmt = get_bits_fmt(sc.sfmt); @@ -782,11 +783,11 @@ static int initialize_stream_rx_32(device_t* device, sc.channels.ch_map[2] = sc.channels.ch_map[0] + 2; sc.channels.ch_map[3] = sc.channels.ch_map[1] + 2; } else { - USDR_LOG("DSTR", USDR_LOG_ERROR, "Bifurcation is only valid for single channel complex\n"); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "Bifurcation is only valid for single channel complex\n"); return -EINVAL; } if (sc.spburst % 2) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "In Bifurcation number of samples should be even\n"); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "In Bifurcation number of samples should be even\n"); return -EINVAL; } @@ -875,7 +876,7 @@ static int initialize_stream_rx_32(device_t* device, strdev->hw_pwr_mask = hw_chan_msk; strdev->pack_3x16 = pack_3x16; - USDR_LOG("DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", strdev->pkt_symbs, strdev->wire_bps, strdev->channels, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask, strdev->pack_3x16); *outu = strdev; @@ -927,6 +928,7 @@ static int initialize_stream_tx_32(device_t* device, bool dont_check_fw) { int res; + lldev_t dev = device->dev; stream_sfetrx_dma32_t* strdev; uint64_t pwr_hw_mask = 0; struct stream_config sc; @@ -945,10 +947,10 @@ static int initialize_stream_tx_32(device_t* device, uint64_t fwid; res = usdr_device_vfs_obj_val_get_u64(device, "/dm/revision", &fwid); if (res) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "Unable to check comatability firmware!\n"); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "Unable to check comatability firmware!\n"); } if (get_xilinx_rev_h(fwid & 0xffffffff) < get_xilinx_rev_h(MINIM_FWID_COMPAT)) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "You're running outdated firmware, please update! CurrentID=%08x MinimalID=%08x\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "You're running outdated firmware, please update! CurrentID=%08x MinimalID=%08x\n", (uint32_t)(fwid & 0xffffffff), MINIM_FWID_COMPAT); return -ECONNRESET; @@ -964,7 +966,7 @@ static int initialize_stream_tx_32(device_t* device, res = sfe_tx4_check_format(&sc); if (res) { if (pfmt.wire_fmt != NULL) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "TX Stream:Unsupported wire format '%s' by the core\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "TX Stream:Unsupported wire format '%s' by the core\n", sc.sfmt); return res; } @@ -981,12 +983,12 @@ static int initialize_stream_tx_32(device_t* device, logicchs, 1); if (funcs.cfunc == NULL || funcs.sfunc == NULL) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "TX Stream: No transform function '%s'->'%s' are available for %d->1 mux\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "TX Stream: No transform function '%s'->'%s' are available for %d->1 mux\n", pfmt.host_fmt, sc.sfmt, logicchs); return -EINVAL; } if (is_transform_dummy(funcs.cfunc)) { - USDR_LOG("DSTR", USDR_LOG_INFO, "TX Stream: No transformation!\n"); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "TX Stream: No transformation!\n"); } struct bitsfmt bfmt = get_bits_fmt(sc.sfmt); @@ -997,7 +999,7 @@ static int initialize_stream_tx_32(device_t* device, if ((bfmt.complex) && (sc.chcnt == 1)) { sc.chcnt = 2; } else { - USDR_LOG("DSTR", USDR_LOG_ERROR, "Bifurcation is only valid for single channel complex"); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "Bifurcation is only valid for single channel complex"); return -EINVAL; } } @@ -1008,7 +1010,7 @@ static int initialize_stream_tx_32(device_t* device, unsigned fe_old_tx_mute = 0; if (fecfg->cfg_fecore_id == CORE_SFETX_DMA32_R0) { if (!bfmt.complex || bfmt.bits != 16) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "Only 16 bit complex signals supported in Simple TX FE!\n"); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "Only 16 bit complex signals supported in Simple TX FE!\n"); return -EINVAL; } @@ -1043,7 +1045,7 @@ static int initialize_stream_tx_32(device_t* device, case 16: expand = 4; break; case 32: expand = 5; break; default: - USDR_LOG("DSTR", USDR_LOG_ERROR, "TX: Unable to deliver %d chans in %d bits!\n", llcanhs, lbits); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_ERROR, "TX: Unable to deliver %d chans in %d bits!\n", llcanhs, lbits); return -EINVAL; } @@ -1089,14 +1091,14 @@ static int initialize_stream_tx_32(device_t* device, unsigned lgbrst; res = _extx_burstup(pktsyms, max_burst_sps, &lgbrst); if (res) { - USDR_LOG("DSTR", USDR_LOG_CRITICAL_WARNING, "TX Stream couldn't breakup %d bytes in bursts, maximum per burst is %d!\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_CRITICAL_WARNING, "TX Stream couldn't breakup %d bytes in bursts, maximum per burst is %d!\n", sparams.block_size, max_mtu); goto fail_dealloc; } sparams.out_max_bursts = (1 << lgbrst); } else { - USDR_LOG("DSTR", USDR_LOG_CRITICAL_WARNING, "TX Stream maximum MTU is %d bytes, we need %d to deliver %d samples blocksize!\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_CRITICAL_WARNING, "TX Stream maximum MTU is %d bytes, we need %d to deliver %d samples blocksize!\n", max_mtu, sparams.block_size, pktsyms); res = -EINVAL; goto fail_dealloc; @@ -1105,7 +1107,7 @@ static int initialize_stream_tx_32(device_t* device, res = dops->stream_initialize(device->dev, 0, &sparams, &sid); if (res) { - USDR_LOG("DSTR", USDR_LOG_CRITICAL_WARNING, "TX Stream couldn't initialize for %d block size\n", sparams.block_size); + USDR_LL_LOG(dev, "DSTR", USDR_LOG_CRITICAL_WARNING, "TX Stream couldn't initialize for %d block size\n", sparams.block_size); goto fail_dealloc; } @@ -1116,7 +1118,7 @@ static int initialize_stream_tx_32(device_t* device, } pktsyms = 8 * sparams.out_mtu_size / (hardware_channels * bits_per_single_sym); - USDR_LOG("DSTR", USDR_LOG_INFO, "TX Stream: No desired packetsize were set, assuminng maximum %d x %d sps (%d blocksize per burst)\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "TX Stream: No desired packetsize were set, assuminng maximum %d x %d sps (%d blocksize per burst)\n", pktsyms, sparams.out_max_bursts, (unsigned)sparams.out_mtu_size); sparams.block_size = sparams.out_mtu_size; @@ -1169,7 +1171,7 @@ static int initialize_stream_tx_32(device_t* device, strdev->hw_pwr_mask = pwr_hw_mask; strdev->pack_3x16 = pack_3x16; - USDR_LOG("DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", strdev->pkt_symbs, strdev->wire_bps, strdev->channels, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask, strdev->pack_3x16); *outu = strdev; return 0; @@ -1273,7 +1275,7 @@ int sfetrx4_stream_sync(device_t* device, stream_sfetrx_dma32_t** pstream = (stream_sfetrx_dma32_t**)pstr; res = usdr_device_vfs_obj_val_get_u64(device, "/ll/sync/0/base", &sync_base); if (res) { - USDR_LOG("DSTR", USDR_LOG_ERROR, "SYNC: Broken device! Coulnd't obtain sync addr: %d\n", res); + USDR_LL_LOG(device->dev, "DSTR", USDR_LOG_ERROR, "SYNC: Broken device! Coulnd't obtain sync addr: %d\n", res); return res; } retimer_base = sync_base; @@ -1319,7 +1321,7 @@ int sfetrx4_stream_sync(device_t* device, res = -EINVAL; } - USDR_LOG("DSTR", USDR_LOG_NOTE, "SYNC[%x] Streams %d: %s => %d\n", retimer_base, scount, synctype, res); + USDR_LL_LOG(device->dev, "DSTR", USDR_LOG_NOTE, "SYNC[%x] Streams %d: %s => %d\n", retimer_base, scount, synctype, res); return res; } diff --git a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c index ab9abe80..a10f470f 100644 --- a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c +++ b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c @@ -98,12 +98,12 @@ int pcie_reg_write32_ioctl(pcie_uram_dev_t* dev, unsigned dwoff, unsigned data) int res = ioctl(dev->fd, PCIE_DRIVER_HWREG_WR32, &rop); if (res == -1) { int err = -errno; - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "pcie:%s unable to write register %d, error %d\n", dev->name, dwoff, err); return err; } - USDR_LOG("PCIE", USDR_LOG_TRACE, "Write[%d] <= %08x\n", + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_TRACE, "Write[%d] <= %08x\n", dwoff, data); return 0; } @@ -117,12 +117,12 @@ int pcie_reg_read32_ioctl(pcie_uram_dev_t* dev, unsigned dwoff, unsigned* data) int res = ioctl(dev->fd, PCIE_DRIVER_HWREG_RD32, &rop); if (res == -1) { int err = -errno; - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "pcie:%s unable to read register %d, error %d\n", dev->name, dwoff, err); return err; } - USDR_LOG("PCIE", USDR_LOG_TRACE, "Read [%d] => %08x\n", + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_TRACE, "Read [%d] => %08x\n", dwoff, rop.value); *data = rop.value; return 0; @@ -198,14 +198,14 @@ int pcie_reg_op_iommap(struct pcie_uram_dev* d, unsigned ls_op_addr, d->mmaped_io[d->db.idxreg_base[k]] = htobe32(ls_op_addr - d->db.idxreg_virt_base[k] + i); if (i < memoutsz / 4) { d->mmaped_io[d->db.idxreg_base[k] + 1] = htobe32(outa[i]);\ - USDR_LOG("PCIE", USDR_LOG_TRACE, "Write[%d+%d -> %d] <= %08x\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_TRACE, "Write[%d+%d -> %d] <= %08x\n", d->db.idxreg_virt_base[k], ls_op_addr - d->db.idxreg_virt_base[k] + i, d->db.idxreg_base[k] + 1, outa[i]); } if (i < meminsz / 4) { ina[i] = be32toh(d->mmaped_io[d->db.idxreg_base[k] + 1]); - USDR_LOG("PCIE", USDR_LOG_TRACE, "Read [%d+%d -> %d] => %08x\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_TRACE, "Read [%d+%d -> %d] => %08x\n", d->db.idxreg_virt_base[k], ls_op_addr - d->db.idxreg_virt_base[k] + i, d->db.idxreg_base[k] + 1, ina[i]); @@ -224,18 +224,18 @@ int pcie_reg_op_iommap(struct pcie_uram_dev* d, unsigned ls_op_addr, uint64_t outb = htobe32(outa[i]) | (((uint64_t)htobe32(outa[i + 1])) << 32); *((uint64_t*)&d->mmaped_io[ls_op_addr + i]) = outb; - USDR_LOG("PCIE", USDR_LOG_TRACE, "Write64[%d] <= %08x%08x\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_TRACE, "Write64[%d] <= %08x%08x\n", ls_op_addr + i, outa[i], outa[i + 1]); i++; } else { d->mmaped_io[ls_op_addr + i] = htobe32(outa[i]); - USDR_LOG("PCIE", USDR_LOG_TRACE, "Write32[%d] <= %08x\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_TRACE, "Write32[%d] <= %08x\n", ls_op_addr + i, outa[i]); } } for (i = 0; i < indwsz; i++) { ina[i] = be32toh(d->mmaped_io[ls_op_addr + i]); - USDR_LOG("PCIE", USDR_LOG_TRACE, "Read [%d] => %08x\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_TRACE, "Read [%d] => %08x\n", ls_op_addr + i, ina[i]); } return 0; @@ -261,7 +261,7 @@ int pcie_i2c_read(pcie_uram_dev_t* dev, unsigned reg_base, unsigned control, uns break; } if (i == 100) { - USDR_LOG("PCIE", USDR_LOG_ERROR, "i2c: data not ready, status = %08x!\n", stat); + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "i2c: data not ready, status = %08x!\n", stat); return -EIO; } @@ -287,7 +287,7 @@ int pcie_spi_transact(pcie_uram_dev_t* dev, unsigned bus, unsigned in, unsigned break; } if (i == 100) { - USDR_LOG("PCIE", USDR_LOG_ERROR, "spi: data not ready, status = %08x!\n", out); + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "spi: data not ready, status = %08x!\n", out); return -EIO; } @@ -359,7 +359,7 @@ int pcie_uram_ls_op(lldev_t dev, subdev_t subdev, if (res) return -errno; - USDR_LOG("PCIE", USDR_LOG_NOTE, "SPI%d: DW=%08x => %08x\n", SPIEXT_LSOP_GET_BUS(ls_op_addr), *(const uint32_t*)pout, iospi.dw_io); + USDR_LL_LOG(dev, "PCIE", USDR_LOG_NOTE, "SPI%d: DW=%08x => %08x\n", SPIEXT_LSOP_GET_BUS(ls_op_addr), *(const uint32_t*)pout, iospi.dw_io); if (meminsz) { if (pdb->spi_core[SPIEXT_LSOP_GET_BUS(ls_op_addr)] == SPI_CORE_32W) { @@ -390,7 +390,7 @@ int pcie_uram_ls_op(lldev_t dev, subdev_t subdev, usleep(1000); - USDR_LOG("PCIE", USDR_LOG_NOTE, "I2C%d.%d.%d: W=%d R=%d OUT=%s\n", + USDR_LL_LOG(dev, "PCIE", USDR_LOG_NOTE, "I2C%d.%d.%d: W=%d R=%d OUT=%s\n", LSOP_I2C_INSTANCE(ls_op_addr), LSOP_I2C_BUSNO(ls_op_addr), LSOP_I2C_ADDR(ls_op_addr), ioi2c.wcnt, ioi2c.rcnt, _dump_buffer(memoutsz, pout)); @@ -401,7 +401,7 @@ int pcie_uram_ls_op(lldev_t dev, subdev_t subdev, if (meminsz <= sizeof(ioi2c.rdb)) { memcpy(pin, ioi2c.rdb, meminsz); } - USDR_LOG("PCIE", USDR_LOG_NOTE, "I2C%d.%d.%d: => %s\n", + USDR_LL_LOG(dev, "PCIE", USDR_LOG_NOTE, "I2C%d.%d.%d: => %s\n", LSOP_I2C_INSTANCE(ls_op_addr), LSOP_I2C_BUSNO(ls_op_addr), LSOP_I2C_ADDR(ls_op_addr), _dump_buffer(meminsz, pin)); @@ -440,11 +440,11 @@ int pcie_uram_stream_initialize(lldev_t dev, subdev_t subdev, res = ioctl(d->fd, PCIE_DRIVER_DMA_CONF, &pdsc); if (res) { res = -errno; - USDR_LOG("PCIE", USDR_LOG_ERROR, "Unable to initialize driver DMA configuration, error %d\n", res); + USDR_LL_LOG(dev, "PCIE", USDR_LOG_ERROR, "Unable to initialize driver DMA configuration, error %d\n", res); return res; } if (pdsc.sno >= SIZEOF_ARRAY(d->scache)) { - USDR_LOG("PCIE", USDR_LOG_ERROR, "ioctl(PCIE_DRIVER_DMA_CONF) returned incorrect stream index! idx=%d\n", pdsc.sno); + USDR_LL_LOG(dev, "PCIE", USDR_LOG_ERROR, "ioctl(PCIE_DRIVER_DMA_CONF) returned incorrect stream index! idx=%d\n", pdsc.sno); return -EINVAL; } @@ -485,7 +485,7 @@ int pcie_uram_stream_initialize(lldev_t dev, subdev_t subdev, //d->bit_per_all_sym[pdsc.sno] = params->bits_per_sym; params->underlying_fd = d->fd; params->out_mtu_size = pdsc.dma_buf_sz; - USDR_LOG("PCIE", USDR_LOG_INFO, "Configured stream%d: %d X %d (vma_off=%08lx vma_len=%08lx)\n", + USDR_LL_LOG(dev, "PCIE", USDR_LOG_INFO, "Configured stream%d: %d X %d (vma_off=%08lx vma_len=%08lx)\n", pdsc.sno, pdsc.dma_buf_sz, pdsc.dma_bufs, pdsc.out_vma_off, pdsc.out_vma_length); return 0; @@ -563,19 +563,19 @@ int pcie_uram_dma_wait_or_alloc(struct pcie_uram_dev* d, bool rx, stream_t chann sc->oob_idx = 0; if (res * 16 != data.ooblength) { - USDR_LOG("PCIE", USDR_LOG_CRITICAL_WARNING, " RES %d != %d OOBLEN\n", res, sc->oob_size); + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_CRITICAL_WARNING, " RES %d != %d OOBLEN\n", res, sc->oob_size); } } if (res < 0) { res = -errno; if (res != -ETIMEDOUT) { - USDR_LOG("PCIE", USDR_LOG_CRITICAL_WARNING, "STR[%d]: PCIe %s dma buffer alloc error: %d!\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_CRITICAL_WARNING, "STR[%d]: PCIe %s dma buffer alloc error: %d!\n", channel, rx ? "recv" : "send", res); } else if (rx) { unsigned stat[4]; // TODO: Remove hardcoded address to upper layer pcie_reg_op_iommap(d, 4, &stat[0], 12, NULL, 0); - USDR_LOG("PCIE", USDR_LOG_NOTE, "STR[%d]: PCIe recv dma buffer alloc timed out stat=%08x:%08x:%08x %08x!\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_NOTE, "STR[%d]: PCIe recv dma buffer alloc timed out stat=%08x:%08x:%08x %08x!\n", channel, stat[0], stat[1], stat[2], stat[3]); uint32_t* oob32 = (uint32_t*)oob_ptr; @@ -586,7 +586,7 @@ int pcie_uram_dma_wait_or_alloc(struct pcie_uram_dev* d, bool rx, stream_t chann unsigned stat[4]; // TODO: Remove hardcoded address to upper layer pcie_reg_op_iommap(d, 28, &stat[0], 16, NULL, 0); - USDR_LOG("PCIE", USDR_LOG_NOTE, "STR[%d]: PCIe send dma buffer alloc timed out stat=%08x:%08x:%08x %08x!\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_NOTE, "STR[%d]: PCIe send dma buffer alloc timed out stat=%08x:%08x:%08x %08x!\n", channel, stat[0], stat[1], stat[2], stat[3]); } return res; @@ -594,7 +594,7 @@ int pcie_uram_dma_wait_or_alloc(struct pcie_uram_dev* d, bool rx, stream_t chann } sc->bufavail = res; - USDR_LOG("PCIE", (res > 1) ? USDR_LOG_NOTE : USDR_LOG_DEBUG, "STR[%d]: Alloced %d buffs, BNO=%d (%016lx) seq=%16ld OOB_sz=%d\n", + USDR_LL_LOG(&d->ll, "PCIE", (res > 1) ? USDR_LOG_NOTE : USDR_LOG_DEBUG, "STR[%d]: Alloced %d buffs, BNO=%d (%016lx) seq=%16ld OOB_sz=%d\n", channel, res, sc->bno, (oob_ptr) ? (*(uint64_t*)sc->oob_cache) : 0, sc->seq, sc->oob_size); } @@ -613,7 +613,7 @@ int pcie_uram_dma_wait_or_alloc(struct pcie_uram_dev* d, bool rx, stream_t chann *oob_size = 2 * sizeof(uint64_t); sc->oob_idx++; } else { - USDR_LOG("PCIE", USDR_LOG_CRITICAL_WARNING, "No OOB data available for %d idx (%d size)!\n", + USDR_LL_LOG(&d->ll, "PCIE", USDR_LOG_CRITICAL_WARNING, "No OOB data available for %d idx (%d size)!\n", sc->oob_idx, sc->oob_size); sc->oob_idx++; @@ -648,7 +648,7 @@ int pcie_uram_recv_dma_release(lldev_t dev, subdev_t subdev, stream_t channel, v if (res) { res = -errno; if (res != -EAGAIN) { - USDR_LOG("PCIE", USDR_LOG_CRITICAL_WARNING, "PCIe recv dma buffer release error: %d!\n", res); + USDR_LL_LOG(dev, "PCIE", USDR_LOG_CRITICAL_WARNING, "PCIe recv dma buffer release error: %d!\n", res); } return res; } @@ -674,7 +674,7 @@ int pcie_uram_send_dma_commit(lldev_t dev, subdev_t subdev, stream_t channel, vo return -EINVAL; if (sc->cfg_bufsize < sz) { - USDR_LOG("PCIE", USDR_LOG_CRITICAL_WARNING, "Stream was configured with %d DMA buffer but tried to write %d!\n", + USDR_LL_LOG(dev, "PCIE", USDR_LOG_CRITICAL_WARNING, "Stream was configured with %d DMA buffer but tried to write %d!\n", d->scache[channel].cfg_bufsize, sz); return -EINVAL; } @@ -727,7 +727,7 @@ int pcie_uram_destroy(lldev_t dev) close(d->fd); d->fd = -1; - USDR_LOG("PCIE", USDR_LOG_INFO, "Device %s destroyed!\n", d->name); + USDR_LL_LOG(dev, "PCIE", USDR_LOG_INFO, "Device %s destroyed!\n", d->name); free(d); return 0; @@ -781,7 +781,7 @@ static int pcie_filtering_params_parse(unsigned pcount, const char** filterparam j = 3; } else { // Non-compatible bus - USDR_LOG("USBX", USDR_LOG_TRACE, "`%s` ignored by PCI driver\n", val); + USDR_LOG("PCIE", USDR_LOG_TRACE, "`%s` ignored by PCI driver\n", val); return -ENODEV; } @@ -931,7 +931,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** err = ioctl(fd, PCIE_DRIVER_GET_UUID, &did); if (err) { err = -errno; - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "Unable to get device uuid, error %d\n", err); goto remove_dev; } @@ -939,7 +939,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** err = ioctl(fd, PCIE_DRIVER_CLAIM_VERSION, USDR_DRIVER_ABI_VERSION); if (err) { err = -errno; - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "ABI verification failed %d, you need to update the driver or host libraries!\n", err); goto remove_dev; } @@ -949,7 +949,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** err = usdr_device_create(&dev->ll, did); if (err) { - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "Unable to find device spcec for %s, uuid %s! Update software!\n", dev->name, usdr_device_id_to_str(did)); @@ -959,7 +959,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** err = device_bus_init(dev->ll.pdev, &dev->db); if (err) { - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "Unable to initialize bus parameters for the device %s!\n", dev->name); goto remove_dev; @@ -982,7 +982,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** goto remove_dev; } if (dev->db.bucket_count != 1) { - USDR_LOG("PCIE", USDR_LOG_ERROR, "Broken device description: no bucket!\n"); + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "Broken device description: no bucket!\n"); err = -ENOSPC; goto remove_dev; } @@ -1049,7 +1049,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** err = err ? err : ioctl(fd, PCIE_DRIVER_SET_DEVLAYOUT, &dl); if (err) { err = -errno; - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "Unable to set device driver layout, error %d\n", err); goto remove_dev; } @@ -1057,7 +1057,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** if (mmapedio) { dev->mmaped_io = mmap(NULL, iospacesz, PROT_READ | PROT_WRITE, MAP_SHARED, dev->fd, 0); if (dev->mmaped_io == MAP_FAILED) { - USDR_LOG("PCIE", USDR_LOG_CRITICAL_WARNING, "Unable to use MMAPed IO, falling back to ioctl(), error: %d", + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_CRITICAL_WARNING, "Unable to use MMAPed IO, falling back to ioctl(), error: %d", errno); dev->mmaped_io = NULL; @@ -1067,7 +1067,7 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** // Device initialization err = err ? err : dev->ll.pdev->initialize(dev->ll.pdev, pcount, devparam, devval); if (err) { - USDR_LOG("PCIE", USDR_LOG_ERROR, + USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, "Unable to initialize device, error %d\n", err); goto clear_map; } From 8a249030a244a24bb0b569976ef7a69c4e31034e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 15:07:50 +0400 Subject: [PATCH 283/397] mdev: enable device tagging in log messages --- src/lib/device/mdev.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/device/mdev.c b/src/lib/device/mdev.c index 1809876b..4e17c3b4 100644 --- a/src/lib/device/mdev.c +++ b/src/lib/device/mdev.c @@ -550,6 +550,10 @@ int mdev_create(unsigned pcnt, const char** names, const char** values, lldev_t* } memset(obj, 0, sizeof(*obj)); + if (bus_cnt > 1) { + usdrlog_ll_devname_en(true); + } + // Creating sub-device for (i = 0; i < bus_cnt; i++) { values[idx] = bus_names[i]; From 7deac0d5a8211683956b6fc0af8e7585d6a5a061 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 15:08:26 +0400 Subject: [PATCH 284/397] usdr_dm_sensors add -D option to select device --- src/tools/usdr_dm_sensors.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/usdr_dm_sensors.c b/src/tools/usdr_dm_sensors.c index b2588167..2814281e 100644 --- a/src/tools/usdr_dm_sensors.c +++ b/src/tools/usdr_dm_sensors.c @@ -47,7 +47,7 @@ int main(UNUSED int argc, UNUSED char** argv) enum sensor_type type = 0; const char *list_pattern = NULL; - while ((opt = getopt(argc, argv, "d:i:l:s:S:r:c:t:L:")) != -1) { + while ((opt = getopt(argc, argv, "D:d:i:l:s:S:r:c:t:L:")) != -1) { switch (opt) { case 't': if (strcmp(optarg, "temp") == 0) @@ -61,6 +61,7 @@ int main(UNUSED int argc, UNUSED char** argv) exit(1); } break; + case 'D': case 'd': device = optarg; break; From 53066c63f3b89e2ffcfa066a79baa4bcff6396e5 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 20:20:54 +0400 Subject: [PATCH 285/397] tmp114: add configuration & UID functions --- src/lib/hw/tmp114/tmp114.c | 36 ++++++++++++++++++++++++++++++++++++ src/lib/hw/tmp114/tmp114.h | 10 ++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/lib/hw/tmp114/tmp114.c b/src/lib/hw/tmp114/tmp114.c index a05f134d..a912133f 100644 --- a/src/lib/hw/tmp114/tmp114.c +++ b/src/lib/hw/tmp114/tmp114.c @@ -27,6 +27,16 @@ int tmp114_reg_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, 2, pv, 1, &taddr); } +static +int tmp114_reg_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint8_t taddr, uint16_t pv) +{ + uint8_t cmd[3] = { taddr, pv >> 8, pv }; + return lowlevel_get_ops(dev)->ls_op(dev, subdev, + USDR_LSOP_I2C_DEV, ls_op_addr, + 0, NULL, 3, cmd); +} + int tmp114_temp_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, int* outtemp) { @@ -36,6 +46,18 @@ int tmp114_temp_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, return res; } +int tmp114_config_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint16_t* config) +{ + return tmp114_reg_get(dev, subdev, ls_op_addr, TMP114_Configuration, config); +} + +int tmp114_config_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint16_t config) +{ + return tmp114_reg_set(dev, subdev, ls_op_addr, TMP114_Configuration, config); +} + int tmp114_devid_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, int* devid) { @@ -45,3 +67,17 @@ int tmp114_devid_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, return res; } +int tmp114_uid_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint64_t* devuid) +{ + uint16_t uid[3]; + for (int i = 0; i < 3; i++) { + int res = tmp114_reg_get(dev, subdev, ls_op_addr, TMP114_Unique_ID1 + i, &uid[i]); + if (res) + return res; + } + + *devuid = ((uint64_t)uid[0] << 32) | ((uint64_t)uid[1] << 16) | ((uint64_t)uid[2] << 0); + return 0; +} + diff --git a/src/lib/hw/tmp114/tmp114.h b/src/lib/hw/tmp114/tmp114.h index 40d2433a..e8861d55 100644 --- a/src/lib/hw/tmp114/tmp114.h +++ b/src/lib/hw/tmp114/tmp114.h @@ -8,10 +8,20 @@ #define TMP114_DEVICE_ID 0x1114 + int tmp114_temp_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, int* outtemp); +int tmp114_config_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint16_t* config); + +int tmp114_config_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint16_t config); + int tmp114_devid_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, int* devid); +int tmp114_uid_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, + uint64_t* devuid); + #endif From 427456918df3df91481f7469e8cc6629675a81ba Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 20:21:28 +0400 Subject: [PATCH 286/397] style fix --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 1ad34b84..537b434c 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -1207,14 +1207,11 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* if (res) return res; - if (d->xdev.ssdr) - { + if (d->xdev.ssdr) { res = vfs_add_const_i64_vec(&udev->rootfs, ssdr_params_m2_lm7_1_rev000, SIZEOF_ARRAY(ssdr_params_m2_lm7_1_rev000)); if (res) USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "Unable to set device name \"ssdr\"!\n"); - } - else - { + } else { res = vfs_add_const_i64_vec(&udev->rootfs, xsdr_params_m2_lm7_1_rev000, SIZEOF_ARRAY(xsdr_params_m2_lm7_1_rev000)); if (res) USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "Unable to set device name \"xsdr\"!\n"); From b141cf84c7b5f9f3447fe620c123496629e8a25d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 20:22:00 +0400 Subject: [PATCH 287/397] ext_fe_ch4_400_7200: improve logging --- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c index 4886cb54..48bf83b3 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c @@ -638,12 +638,19 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U300, TCA6424_CFG0, &val16[2]); res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U301, TCA6424_CFG0, &val16[3]); - USDR_LOG("FE4C", USDR_LOG_ERROR, "Temp ID = %4x, {U114/U110/U300/U301}_Cfg0 = %4x/%4x/%4x/%4x\n", val, - val16[0], val16[1], val16[2], val16[3]); + if (res) { + USDR_LOG("FE4C", USDR_LOG_ERROR, "Unable to initialize I2C bus, error: %d\n", res); + } else { + USDR_LOG("FE4C", USDR_LOG_ERROR, "Temp ID = %4x, {U114/U110/U300/U301}_Cfg0 = %4x/%4x/%4x/%4x\n", val, + val16[0], val16[1], val16[2], val16[3]); + } if (res || val != TMP114_DEVICE_ID) return res; + //res = (res) ? res : tmp114_config_set(dev, subdev, I2C_TEMP_U69, 0x4); + //res = (res) ? res : tmp114_temp_get(dev, subdev, I2C_TEMP_U69, &val); + res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO_1PPS, GPIO_CFG_ALT0); res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, 0); @@ -656,9 +663,6 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_CFG0, 0); res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_CFG0 + 2, 0); - res = (res) ? res : tmp114_temp_get(dev, subdev, I2C_TEMP_U69, &val); - USDR_LOG("FE4C", USDR_LOG_ERROR, "Temp %.2fC\n", val / 256.0); - // User initialization ob->ref_gps = 1; ob->if_vbyp = 1; @@ -688,6 +692,14 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, // ob->dac_present = false; } + uint64_t uid; + res = (res) ? res : tmp114_uid_get(dev, subdev, I2C_TEMP_U69, &uid); + res = (res) ? res : tmp114_temp_get(dev, subdev, I2C_TEMP_U69, &val); + if (res) + return res; + + USDR_LOG("FE4C", USDR_LOG_WARNING, "BoardID %012llx, Temp %.2fC\n", (long long)uid, val / 256.0); + res = (res) ? res : usdr_vfs_obj_param_init_array_param(base, (void*)ob, s_fe_parameters, From 31801e92e4f23e5774e86b029217e589cd0ec33e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 26 Jan 2026 20:23:12 +0400 Subject: [PATCH 288/397] usdr: allow RD32 ioctl() in order to properly detect device --- src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index 97f17b4b..fe635b0c 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -1189,7 +1189,8 @@ static long usdrfd_ioctl(struct file *filp, if (ioctl_num != PCIE_DRIVER_GET_UUID && ioctl_num != PCIE_DRIVER_CLAIM && ioctl_num != PCIE_DRIVER_SET_DEVLAYOUT && - ioctl_num != PCIE_DRIVER_CLAIM_VERSION) { + ioctl_num != PCIE_DRIVER_CLAIM_VERSION && + ioctl_num != PCIE_DRIVER_HWREG_RD32) { dev_notice(&usdrdev->pdev->dev, "Device not ready!"); return -EINVAL; From 85b7baba4a20fe9a156ff1774efb9dfa4aedd18e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 29 Jan 2026 12:08:33 +0400 Subject: [PATCH 289/397] dsdr: add proper control of 4ch0472 board --- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c | 93 +++++++++++++++---- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h | 15 ++- src/lib/device/m2_dsdr/dsdr_hiper.c | 9 ++ src/lib/device/m2_dsdr/dsdr_hiper.h | 1 + src/lib/device/m2_dsdr/m2_dsdr.c | 84 ++++++++++++++++- 5 files changed, 173 insertions(+), 29 deletions(-) diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c index 48bf83b3..85cd4113 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c @@ -28,7 +28,7 @@ // // 10 SSDR_GPLED0 GPIO33_0 EXT_I2C_SDA // 20 SSDR_GPIO1 -------- AUX_MUX_GPIO1 -- *EXT2_I2C_SDA / FAN0_TACH -// 38 SSDR_GPLED1_P FGPIO_N +// 38 SSDR_GPLED1_P GPIO33_3 FGPIO_N // 40 SSDR_GPLED1_N FGPIO_P // 54 SSDR_GPIO6 GPIO33_1 EXT_I2C_SCL // 56 SSDR_GPIO3_P -------- n/c GPS_TX @@ -36,12 +36,13 @@ // 68 SSDR_GPIO5 GPIO33_2 AUX_MUX_GPIO0 -- *EXT2_I2C_SCL / FAN1_TACH // // I2C3: -// SSDR_GPLED0 M1 -// SSDR_GPIO6 H2 +// SSDR_GPLED0 M1 | GPIO33_0 +// SSDR_GPIO6 H2 | GPIO33_1 // I2C4: -// SSDR_GPIO1 L1 -// SSDR_GPIO5 J2 - +// SSDR_GPIO1 L1 | GPIO_EXT_18_5 +// SSDR_GPIO5 J2 | GPIO33_2 through R2012 GPIO_EXT_18_4 +// +// For DSDR GPIO33_2 / GPIO33_3 must be configured as Inputs enum { GPIO_1PPS = GPIO2, @@ -73,6 +74,8 @@ enum i2c_idx_extra { enum { RX_DSA_MAX_ATTN = 15, + + TX_GAIN_1ST = 20, }; static const uint64_t s_filerbank_ranges[] = { @@ -235,8 +238,8 @@ static void _ext_fe_antenna_sw_map_exp(unsigned antenna, bool rxen, bool txen, *exp_tx_onoff = EXP_TX_ONOFF_P1_TRX_SW; *exp_rxtx = EXP_RXTX_SW_P1_TX; *exp_tddfdd = EXP_TDDFDD_P3_ANT_RX; - *exp_led_trx = LED_TRX_TXO; - *exp_led_rx = LED_RX_ON; + *exp_led_trx = txen ? LED_TRX_TXO : LED_TRX_OFF; + *exp_led_rx = rxen ? LED_RX_ON : LED_RX_OFF; *arx = rxen; *atx = txen; break; @@ -245,7 +248,7 @@ static void _ext_fe_antenna_sw_map_exp(unsigned antenna, bool rxen, bool txen, *exp_tx_onoff = EXP_TX_ONOFF_P2_LB_SW; *exp_rxtx = EXP_RXTX_SW_P2_RX; *exp_tddfdd = EXP_TDDFDD_P2_TRX_SW; - *exp_led_trx = LED_TRX_RXO; + *exp_led_trx = rxen ? LED_TRX_RXO : LED_TRX_OFF; *exp_led_rx = LED_RX_OFF; *arx = rxen; *atx = 0; @@ -256,7 +259,7 @@ static void _ext_fe_antenna_sw_map_exp(unsigned antenna, bool rxen, bool txen, *exp_rxtx = EXP_RXTX_SW_P1_TX; *exp_tddfdd = EXP_TDDFDD_P3_ANT_RX; *exp_led_trx = LED_TRX_OFF; - *exp_led_rx = LED_RX_ON; + *exp_led_rx = rxen ? LED_RX_ON : LED_RX_OFF; *arx = rxen; *atx = 0; break; @@ -273,7 +276,7 @@ static void _ext_fe_antenna_sw_map_exp(unsigned antenna, bool rxen, bool txen, case ANT_HW_TDD: // TODO - *exp_led_trx = LED_TRX_TRX; + *exp_led_trx = (rxen && txen) ? LED_TRX_TRX : txen ? LED_TRX_TXO : rxen ? LED_TRX_RXO : LED_TRX_OFF; *exp_led_rx = LED_RX_OFF; *arx = rxen; *atx = txen; @@ -448,6 +451,21 @@ int ext_fe_rx_gain_set(ext_fe_ch4_400_7200_t* def, unsigned chno, unsigned gain, return ext_fe_update_user(def); } +int ext_fe_tx_gain_set(ext_fe_ch4_400_7200_t* def, unsigned chno, unsigned gain, unsigned* actual_gain) +{ + if (chno >= FE_MAX_HW_CHANS) + return -EINVAL; + if (!def->ucfg[chno].tx_en) + return 0; + + def->ucfg[chno].tx_ss = (gain <= TX_GAIN_1ST); + + if (actual_gain) { + *actual_gain = (gain > TX_GAIN_1ST) ? TX_GAIN_1ST : 0; + } + + return ext_fe_update_user(def); +} int ext_fe_ch4_sens_get(ext_fe_ch4_400_7200_t* fe, uint64_t *ovalue) @@ -459,8 +477,6 @@ int ext_fe_ch4_sens_get(ext_fe_ch4_400_7200_t* fe, uint64_t *ovalue) } - - static int ext_fe_ch4_400_7200_ctrl_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { ext_fe_ch4_400_7200_t* fe = (ext_fe_ch4_400_7200_t*)obj->object; @@ -602,7 +618,6 @@ static const usdr_dev_param_func_t s_fe_parameters[] = { }; - int ext_fe_ch4_400_7200_init(lldev_t dev, unsigned subdev, unsigned gpio_base, @@ -645,19 +660,51 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, val16[0], val16[1], val16[2], val16[3]); } - if (res || val != TMP114_DEVICE_ID) + if (res) return res; + if (val != TMP114_DEVICE_ID) + return -ENODEV; //res = (res) ? res : tmp114_config_set(dev, subdev, I2C_TEMP_U69, 0x4); //res = (res) ? res : tmp114_temp_get(dev, subdev, I2C_TEMP_U69, &val); + enum { + TEST_OUT_U114 = 0xf070, + TEST_OUT_U110 = 0x00e0, + TEST_OUT_U300 = 0x001e, + TEST_OUT_U301 = 0x003c, + }; res = (res) ? res : gpio_config(dev, subdev, gpio_base, GPIO_1PPS, GPIO_CFG_ALT0); - res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, 0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, TEST_OUT_U114); res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0 + 2, 0); - res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0, 0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0, TEST_OUT_U110); res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0 + 2, 0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U300, TCA6424_OUT0, TEST_OUT_U300); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U301, TCA6424_OUT0, TEST_OUT_U301); + + // Readback test vectors to test expanders + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, &val16[0]); + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0, &val16[1]); + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U300, TCA6424_OUT0, &val16[2]); + res = (res) ? res : tca6424a_reg16_get(dev, subdev, I2C_TCA6424AR_U301, TCA6424_OUT0, &val16[3]); + + // Set default + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_OUT0, 0); + res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_OUT0, 0); + + if (res) + return res; + if (val16[0] != TEST_OUT_U114 || val16[1] != TEST_OUT_U110 || val16[2] != TEST_OUT_U300 || val16[3] != TEST_OUT_U301) { + USDR_LOG("FE4C", USDR_LOG_ERROR, "Expander test vectors failed: %04x.%04x.%04x.%04x, giving up!\n", + val16[0], val16[1], val16[2], val16[3]); + + return -ENODEV; + } + + + // Enable outputs res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_CFG0, 0); res = (res) ? res : tca6424a_reg8_set(dev, subdev, I2C_TCA6424AR_U114, TCA6424_CFG0 + 2, 0); res = (res) ? res : tca6424a_reg16_set(dev, subdev, I2C_TCA6424AR_U110, TCA6424_CFG0, 0); @@ -669,7 +716,7 @@ int ext_fe_ch4_400_7200_init(lldev_t dev, for (unsigned ch = 0; ch < FE_MAX_HW_CHANS; ch++) { ob->ucfg[ch].rx_fb_sel = RX_FB_AUTO; // rx_filterbank ob->ucfg[ch].rx_dsa = 0; - ob->ucfg[ch].ant_sel = ANT_OFF; + ob->ucfg[ch].ant_sel = ANT_RX_TRX; // ANT_OFF; ob->ucfg[ch].tx_ss = 0; // Single stage PA ob->ucfg[ch].tx_en = 0; // Channel enabled on device side ob->ucfg[ch].rx_en = 0; // Channel enabled on device side @@ -726,6 +773,14 @@ int ext_fe_destroy(ext_fe_ch4_400_7200_t* dfe) int ext_fe_set_dac(ext_fe_ch4_400_7200_t* brd, unsigned value) { - USDR_LOG("M2PE", USDR_LOG_ERROR, "DAC set to: %d\n", value); + USDR_LOG("M2PE", USDR_LOG_WARNING, "DAC set to: %d\n", value); return dac80501_dac_set(brd->dev, brd->subdev, I2C_DAC, value); } + +int ext_fe_get_temp_max(ext_fe_ch4_400_7200_t* dfe, uint64_t* temp_max) +{ + int temp = 0; + int res = tmp114_temp_get(dfe->dev, dfe->subdev, I2C_TEMP_U69, &temp); + *temp_max = temp; + return res; +} diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h index 0b2f97c4..e5b335d6 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h @@ -20,7 +20,8 @@ #define FE_CTRL_REGS 10 -enum rx_filterbank { +#ifndef NO_ECFG_DEFS +enum ext_fe_rx_filterbank { RX_FB_400_1000M, RX_FB_1000_2000M, RX_FB_2000_3500M, @@ -30,7 +31,7 @@ enum rx_filterbank { RX_FB_AUTO = 8, }; -enum antenna_cfg { +enum ext_fe_antenna_cfg { ANT_RX_TRX, // RX connected to RX antenna and TX connected to TRX antenna ANT_TRX_TERM, // RX connected to TRX antenna and TX terminated ANT_RX_TERM, // RX connected to RX antenna and TX terminated @@ -39,8 +40,9 @@ enum antenna_cfg { ANT_HW_TDD, // TRX antenna is dynamically switched to TX/RX ports based on burst information ANT_OFF, }; +#endif -struct fe_chan_config { +struct fe_echan_config { uint8_t rx_fb_sel; // rx_filterbank uint8_t rx_dsa; uint8_t ant_sel; // antenna selector @@ -52,7 +54,7 @@ struct fe_chan_config { // For auto band & filter selection uint64_t rx_freq; }; -typedef struct fe_chan_config fe_chan_config_t; +typedef struct fe_echan_config fe_echan_config_t; struct ext_fe_ch4_400_7200 { lldev_t dev; @@ -69,7 +71,7 @@ struct ext_fe_ch4_400_7200 { // High level control uint8_t ref_gps; // Globally enable GPS uint8_t if_vbyp; // Globally enable IF BYP - fe_chan_config_t ucfg[FE_MAX_HW_CHANS]; + fe_echan_config_t ucfg[FE_MAX_HW_CHANS]; }; typedef struct ext_fe_ch4_400_7200 ext_fe_ch4_400_7200_t; @@ -87,7 +89,10 @@ int ext_fe_rx_chan_en(ext_fe_ch4_400_7200_t* def, unsigned ch_fe_mask_rx); int ext_fe_tx_chan_en(ext_fe_ch4_400_7200_t* def, unsigned ch_fe_mask_tx); int ext_fe_rx_gain_set(ext_fe_ch4_400_7200_t* def, unsigned chno, unsigned gain, unsigned* actual_gain); +int ext_fe_tx_gain_set(ext_fe_ch4_400_7200_t* def, unsigned chno, unsigned gain, unsigned* actual_gain); int ext_fe_set_dac(ext_fe_ch4_400_7200_t* brd, unsigned value); +int ext_fe_get_temp_max(ext_fe_ch4_400_7200_t* dfe, uint64_t* temp_max); + #endif diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 3c07d27f..7642bce6 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -1932,6 +1932,8 @@ int dsdr_hiper_fe_tx_gain_set(dsdr_hiper_fe_t* def, unsigned chno, unsigned gain if (!def->ucfg[chno].tx_en) return 0; + // TODO check bypass path + unsigned lms8pa_gain = (gain >= RX_LMS8B_MIX_LOSS) ? RX_LMS8B_MIX_LOSS : gain; def->ucfg[chno].lms8_tx_hlmix_gain = lms8pa_gain; if (actual_gain) { @@ -1942,3 +1944,10 @@ int dsdr_hiper_fe_tx_gain_set(dsdr_hiper_fe_t* def, unsigned chno, unsigned gain chno, gain, lms8pa_gain); return dsdr_hiper_lms8001b_gain_update(def, chno, false); } + + +int dsdr_hiper_fe_set_dac(dsdr_hiper_fe_t* def, unsigned value) +{ + USDR_LOG("HIPR", USDR_LOG_WARNING, "DAC set to: %d\n", value); + return dac80501_dac_set(def->dev, def->subdev, I2C_DAC, value); +} diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.h b/src/lib/device/m2_dsdr/dsdr_hiper.h index cf490514..16ac083a 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.h +++ b/src/lib/device/m2_dsdr/dsdr_hiper.h @@ -133,6 +133,7 @@ int dsdr_hiper_fe_tx_gain_set(dsdr_hiper_fe_t* def, unsigned chno, unsigned gain int dsdr_hiper_fe_rx_chan_en(dsdr_hiper_fe_t* def, unsigned ch_fe_mask_rx); int dsdr_hiper_fe_tx_chan_en(dsdr_hiper_fe_t* def, unsigned ch_fe_mask_tx); +int dsdr_hiper_fe_set_dac(dsdr_hiper_fe_t* def, unsigned value); #endif diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index fe672e7b..2ec631e5 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -28,6 +28,8 @@ #include "../hw/tmp114/tmp114.h" #include "dsdr_hiper.h" +#define NO_ECFG_DEFS +#include "../device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h" // Board revisions: // 1 - DSDR @@ -301,6 +303,8 @@ static int dev_m2_dsdr_sdr_tx_dsa_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_ static int dev_m2_dsdr_afe_health_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int dev_m2_dsdr_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_dsdr_dummy(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { return 0; @@ -309,7 +313,6 @@ static int dev_m2_dsdr_dummy(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) static int _debug_lmk05318_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int _debug_lmk05318_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); - static int dev_m2_dsdr_sdr_rx_remap_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_dsdr_sdr_rx_remap_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); static int dev_m2_dsdr_sdr_tx_remap_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -464,6 +467,9 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { { "/dm/stat", { NULL, dev_m2_dsdr_stat }}, { "/debug/lldev", { NULL, dev_m2_dsdr_debug_lldev_get}}, { "/dm/sdr/refclk/path", { dev_m2_dsdr_dummy, NULL}}, + + { "/dm/sdr/0/dac_vctcxo", { dev_m2_dsdr_vctcxo_set, NULL }}, + { "/debug/clk_info", { dev_m2_dsdr_debug_clk_info, dev_m2_dsdr_debug_clk_info_get }}, { "/debug/hw/lmk05318/0/reg", { _debug_lmk05318_reg_set, _debug_lmk05318_reg_get }}, @@ -646,12 +652,14 @@ struct dev_m2_dsdr { unsigned type; //unsigned jesdv; unsigned jesd_x8; + unsigned has_extfe; stream_handle_t* rx; stream_handle_t* tx; afe79xx_state_t st; dsdr_hiper_fe_t hiper; + ext_fe_ch4_400_7200_t extfe; uint32_t dsdr_state; //uint32_t cfg_afe_type; @@ -838,6 +846,11 @@ bool dev_m2_dsdr_has_hiper(dev_m2_dsdr_t* d) return d->type == DSDR_PCIE_HIPER_R0; } +bool dev_m2_dsdr_has_extfe0472(dev_m2_dsdr_t* d) +{ + return d->has_extfe; +} + int dev_m2_dsdr_lrxnumchans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { @@ -879,6 +892,8 @@ static int dsdr_update_rx_remap(dev_m2_dsdr_t* d) { // Mark corresponding RX chanel uint64_t hiper_cfg_msk = 0; + unsigned hw_cfg_msk = 0; + //unsigned rx_remap = 0; int res = 0; @@ -890,11 +905,14 @@ static int dsdr_update_rx_remap(dev_m2_dsdr_t* d) if (hw_chan < MAX_HIPER_FE_PORT) { hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[hw_chan]); } + hw_cfg_msk |= (1 << hw_chan); } } if (dev_m2_dsdr_has_hiper(d)) { res = dsdr_hiper_fe_rx_chan_en(&d->hiper, hiper_cfg_msk); + } else if (dev_m2_dsdr_has_extfe0472(d)) { + res = ext_fe_rx_chan_en(&d->extfe, hw_cfg_msk); } // TODO issue FE cmd // return res ? res : dev_gpo_set(d->base.dev, IGPO_RX_MAP, rx_remap); @@ -906,6 +924,8 @@ static int dsdr_update_tx_remap(dev_m2_dsdr_t* d) { // Mark corresponding TX chanel uint64_t hiper_cfg_msk = 0; + unsigned hw_cfg_msk = 0; + //unsigned tx_remap = 0; int res = 0; @@ -917,11 +937,14 @@ static int dsdr_update_tx_remap(dev_m2_dsdr_t* d) if (hw_chan < MAX_HIPER_FE_PORT) { hiper_cfg_msk |= (1u << s_chanmap_hw_to_fe[hw_chan]); } + hw_cfg_msk |= (1 << hw_chan); } } if (dev_m2_dsdr_has_hiper(d)) { res = dsdr_hiper_fe_tx_chan_en(&d->hiper, hiper_cfg_msk); + } else if (dev_m2_dsdr_has_extfe0472(d)) { + res = ext_fe_tx_chan_en(&d->extfe, hw_cfg_msk); } // TODO issue FE cmd //return res ? res : dev_gpo_set(d->base.dev, IGPO_TX_MAP, tx_remap); @@ -1100,6 +1123,8 @@ static int dsdr_set_rx_frequency_chan(dev_m2_dsdr_t* d, uint64_t freq, unsigned res = res ? res : d->rx->ops->option_set(d->rx, "chmap", (uintptr_t)&d->rx_chans); } return res; + } else if (dev_m2_dsdr_has_extfe0472(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + res = res ? res : ext_fe_rx_freq_set(&d->extfe, w->hwport, ncoval); } USDR_LOG("DSDR", USDR_LOG_WARNING, "RX CH[%d => %c: %s%d.Band%d] NCO[%d]=%.3f\n", @@ -1297,6 +1322,8 @@ int dev_m2_dsdr_gain_rx_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t v if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); + } else if (dev_m2_dsdr_has_extfe0472(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + res = res ? res : ext_fe_rx_gain_set(&d->extfe, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); } res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWRX_TYPE(w->hwport), GET_HWRX_IDX(w->hwport), dsa_attn); @@ -1312,14 +1339,22 @@ int dev_m2_dsdr_gain_tx_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t v if (obj->full_path[0]) return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/tx/gain", false); + int res = 0; unsigned i = obj->full_path[1]; unsigned dsa_attn = (value > 29) ? 0 : 29 - value; + unsigned rem_gain = (value > 25) ? value - 29 : 0; const channel_logic_dsp_wire_t* w = get_chmapnfo_from_ordinal(d, false, i); if (!w) { return -EINVAL; } - return d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWTX_TYPE(w->hwport), GET_HWTX_IDX(w->hwport), dsa_attn); + if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + res = res ? res : dsdr_hiper_fe_tx_gain_set(&d->hiper, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); + } else if (dev_m2_dsdr_has_extfe0472(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + res = res ? res : ext_fe_tx_gain_set(&d->extfe, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); + } + res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWTX_TYPE(w->hwport), GET_HWTX_IDX(w->hwport), dsa_attn); + return res; } int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint64_t value) @@ -1342,6 +1377,8 @@ int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint6 if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { res = res ? res : dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); + } else if (dev_m2_dsdr_has_extfe0472(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + res = res ? res : ext_fe_rx_gain_set(&d->extfe, s_chanmap_hw_to_fe[w->hwport], rem_gain, NULL); } res = res ? res : d->st.libcapi79xx_set_dsa(&d->st.capi, GET_HWRX_TYPE(w->hwport), GET_HWRX_IDX(w->hwport), dsa_attn); return res; @@ -1350,7 +1387,7 @@ int dev_m2_dsdr_gain_rx_auto_set(pdevice_t ud, pusdr_vfs_obj_t UNUSED obj, uint6 int dev_m2_dsdr_gain_rx_lna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; - if (!dev_m2_dsdr_has_hiper(d)) + if (!dev_m2_dsdr_has_hiper(d) && !dev_m2_dsdr_has_extfe0472(d)) return -ENOTSUP; if (obj->full_path[0]) @@ -1364,6 +1401,8 @@ int dev_m2_dsdr_gain_rx_lna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu if (dev_m2_dsdr_has_hiper(d) && (w->hwport < MAX_HIPER_FE_PORT)) { return dsdr_hiper_fe_rx_gain_set(&d->hiper, s_chanmap_hw_to_fe[w->hwport], value, NULL); + } else if (dev_m2_dsdr_has_extfe0472(d) && (w->hwport < MAX_HIPER_FE_PORT)) { + return ext_fe_rx_gain_set(&d->extfe, s_chanmap_hw_to_fe[w->hwport], value, NULL); } return -EINVAL; @@ -1630,11 +1669,13 @@ int dev_m2_dsdr_senstemp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue if (dev_m2_dsdr_has_hiper(d)) { res = res ? res : dsdr_hiper_fe_get_temp_max(&d->hiper, &fe_temp); + } else if (dev_m2_dsdr_has_extfe0472(d)) { + res = res ? res : ext_fe_get_temp_max(&d->extfe, &fe_temp); } if (d->type == DSDR_M2_R1) { res = res ? res : tmp114_temp_get(d->base.dev, d->subdev, I2C_TEMP_AFE, (int*)&board_temp); - } else if (!dev_m2_dsdr_has_hiper(d)) { + } else if (!dev_m2_dsdr_has_hiper(d) && !dev_m2_dsdr_has_extfe0472(d)) { // No temp sensors return -EINVAL; } else { @@ -1646,6 +1687,19 @@ int dev_m2_dsdr_senstemp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue return res; } +int dev_m2_dsdr_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_dsdr *d = (struct dev_m2_dsdr *)ud; + int res = -ENOTSUP; + + if (dev_m2_dsdr_has_hiper(d)) { + res = res ? res : dsdr_hiper_fe_set_dac(&d->hiper, value); + } else if (dev_m2_dsdr_has_extfe0472(d)) { + res = res ? res : ext_fe_set_dac(&d->extfe, value); + } + return res; +} + int dev_m2_dsdr_debug_all_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { *ovalue = 0; @@ -1689,6 +1743,8 @@ static void usdr_device_m2_dsdr_destroy(pdevice_t udev) // FE Power OFF if (dev_m2_dsdr_has_hiper(d)) { dsdr_hiper_fe_destroy(&d->hiper); + } else if (dev_m2_dsdr_has_extfe0472(d)) { + ext_fe_destroy(&d->extfe); } dev_gpo_set(dev, IGPO_AFE_RST, 0x1); @@ -2103,7 +2159,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : dsdr_gth_set_rate(d, master_rate); } else { USDR_LOG("XDEV", USDR_LOG_ERROR, "GTY reconfiguration isn't supported yet!\n"); - return -EINVAL; + //return -EINVAL; } } if (res) @@ -2389,6 +2445,16 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** } res = res ? res : dsdr_hiper_fe_create(dev, SPI_BUS_HIPER_FE, poverride, &d->hiper); + } else if (d->type == DSDR_M2_R0 || d->type == DSDR_M2_R1) { + if (res) + return res; + + res = ext_fe_ch4_400_7200_init(dev, 0, M2PCI_REG_GPIO_S, "", "m2m", &d->extfe); + if (res && res != -ENODEV) + return res; + + d->has_extfe = (res == 0); + res = 0; } res = res ? res : usleep(100000); @@ -2761,6 +2827,8 @@ int usdr_device_m2_dsdr_unregister_stream(device_t* dev, stream_handle_t* stream if (dev_m2_dsdr_has_hiper(d)) { res = dsdr_hiper_fe_rx_chan_en(&d->hiper, 0); + } else if (dev_m2_dsdr_has_extfe0472(d)) { + res = ext_fe_rx_chan_en(&d->extfe, 0); } //dev_gpo_set(d->base.dev, IGPO_RX_CHEN, 0); @@ -2772,6 +2840,8 @@ int usdr_device_m2_dsdr_unregister_stream(device_t* dev, stream_handle_t* stream if (dev_m2_dsdr_has_hiper(d)) { res = dsdr_hiper_fe_tx_chan_en(&d->hiper, 0); + } else if (dev_m2_dsdr_has_extfe0472(d)) { + res = ext_fe_tx_chan_en(&d->extfe, 0); } //dev_gpo_set(d->base.dev, IGPO_TX_CHEN, 0); @@ -2812,6 +2882,8 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) d->base.unregister_stream = &usdr_device_m2_dsdr_unregister_stream; d->base.timer_op = &sfetrx4_stream_sync; + memset(&d->st, 0, sizeof(d->st)); + d->rx = NULL; d->tx = NULL; @@ -2835,6 +2907,8 @@ int usdr_device_m2_dsdr_create(lldev_t dev, device_id_t devid) opt_u64_set_null(&d->tx_ord_freqs[i]); } + d->has_extfe = false; + #if 0 for (unsigned i = 0; i < MAX_HIPER_FE_PORT; i++) { for (unsigned j = 0; j < MAX_PORT_BANDS; j++) { From 7c9436ccd655ed3a67fbb9ac644a7bd70fb3431e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 29 Jan 2026 12:09:44 +0400 Subject: [PATCH 290/397] afe79xx: be more verbosive whet it fails to load --- src/lib/hw/afe79xx/afe79xx.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/lib/hw/afe79xx/afe79xx.c b/src/lib/hw/afe79xx/afe79xx.c index 861dcd73..2d0ec4d2 100644 --- a/src/lib/hw/afe79xx/afe79xx.c +++ b/src/lib/hw/afe79xx/afe79xx.c @@ -94,6 +94,7 @@ int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipT const char* afe79xxlib = "liblibcapi79xx.so"; unsigned g; + memset(out, 0, sizeof(*out)); out->dev = dev; out->subdev = subdev; out->addr = lsaddr; @@ -143,8 +144,16 @@ int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipT if (!out->libcapi79xx_create || !out->libcapi79xx_destroy || !out->libcapi79xx_init || !out->libcapi79xx_set_dsa || !out->libcapi79xx_set_tdd || !out->libcapi79xx_upd_nco || !out->libcapi79xx_get_nco || !out->libcapi79xx_check_health) { - USDR_LOG("79xx", USDR_LOG_ERROR, "Broken CAPI AFE79XX NDA LIB wrapper `%s`!\n", - afe79xxlib); + USDR_LOG("79xx", USDR_LOG_ERROR, "Broken CAPI AFE79XX NDA LIB wrapper `%s`: %d%d%d%d.%d%d%d%d!\n", + afe79xxlib, + out->libcapi79xx_create != NULL, + out->libcapi79xx_destroy != NULL, + out->libcapi79xx_init != NULL, + out->libcapi79xx_upd_nco != NULL, + out->libcapi79xx_get_nco != NULL, + out->libcapi79xx_set_dsa != NULL, + out->libcapi79xx_check_health != NULL, + out->libcapi79xx_set_tdd != NULL); dlclose(out->dl_handle); return -EFAULT; From dc59aa1c07599f4dc529b201aaff4e14ccb7deb2 Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Tue, 3 Feb 2026 20:40:01 +0400 Subject: [PATCH 291/397] Fixed filter name for FE board control. --- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c | 14 +++++++------- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h | 2 +- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml | 4 ++-- .../ext_fe_ch4_400_7200_usr.yaml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c index 85cd4113..49603108 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c @@ -79,7 +79,7 @@ enum { }; static const uint64_t s_filerbank_ranges[] = { - 400e6, 1000e6, + 50e6, 1000e6, 1000e6, 2000e6, 2000e6, 3500e6, 2500e6, 5000e6, @@ -165,23 +165,23 @@ static int _ext_fe_ch4_400_7200_exp_get(ext_fe_ch4_400_7200_t *fe, unsigned addr static void _ext_fe_fbank_map(unsigned filsel, unsigned *bout, unsigned *bin) { // Sanity check YAML <-> internal ABI constants - CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_400_1000M, RX_FB_400_1000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_50_1000M, RX_FB_50_1000M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_1000_2000M, RX_FB_1000_2000M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_2000_3500M, RX_FB_2000_3500M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_2500_5000M, RX_FB_2500_5000M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_FILT_3500_7100M, RX_FB_3500_7100M); - CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_400_1000M, RX_FB_AUTO | RX_FB_400_1000M); + CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_50_1000M, RX_FB_AUTO | RX_FB_50_1000M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_1000_2000M, RX_FB_AUTO | RX_FB_1000_2000M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_2000_3500M, RX_FB_AUTO | RX_FB_2000_3500M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_2500_5000M, RX_FB_AUTO | RX_FB_2500_5000M); CHECK_CONSTANT_EQ(RX_FILT_OPTS_AUTO_3500_7100M, RX_FB_AUTO | RX_FB_3500_7100M); - CHECK_CONSTANT_EQ(SW_RX_FILTER_IN_CHA_400_1000M, SW_RX_FILTER_OUT_CHA_400_1000M); + CHECK_CONSTANT_EQ(SW_RX_FILTER_IN_CHA_50_1000M, SW_RX_FILTER_OUT_CHA_50_1000M); unsigned fb_f_sel = (~RX_FB_AUTO & filsel); switch (fb_f_sel) { - case RX_FB_400_1000M: *bout = SW_RX_FILTER_OUT_CHA_400_1000M; *bin = SW_RX_FILTER_IN_CHA_400_1000M; break; + case RX_FB_50_1000M: *bout = SW_RX_FILTER_OUT_CHA_50_1000M; *bin = SW_RX_FILTER_IN_CHA_50_1000M; break; case RX_FB_1000_2000M: *bout = SW_RX_FILTER_OUT_CHA_1000_2000M; *bin = SW_RX_FILTER_IN_CHA_1000_2000M; break; case RX_FB_2000_3500M: *bout = SW_RX_FILTER_OUT_CHA_2000_3500M; *bin = SW_RX_FILTER_IN_CHA_2000_3500M; break; case RX_FB_2500_5000M: *bout = SW_RX_FILTER_OUT_CHA_2500_5000M; *bin = SW_RX_FILTER_IN_CHA_2500_5000M; break; @@ -297,7 +297,7 @@ static void _ext_fe_antenna_sw_map_exp(unsigned antenna, bool rxen, bool txen, void ext_fe_rx_filterbank_upd(ext_fe_ch4_400_7200_t* def, unsigned chno) { - if (def->ucfg[chno].rx_fb_sel < RX_FILT_OPTS_AUTO_400_1000M) + if (def->ucfg[chno].rx_fb_sel < RX_FILT_OPTS_AUTO_50_1000M) return; unsigned best_idx = 0; @@ -322,7 +322,7 @@ void ext_fe_rx_filterbank_upd(ext_fe_ch4_400_7200_t* def, unsigned chno) i, s_filerbank_ranges[i] / 1.0e6, s_filerbank_ranges[i + 1] / 1.0e6, (unsigned)doff, off); } - def->ucfg[chno].rx_fb_sel = RX_FILT_OPTS_AUTO_400_1000M | best_idx; + def->ucfg[chno].rx_fb_sel = RX_FILT_OPTS_AUTO_50_1000M | best_idx; USDR_LOG("FE4C", USDR_LOG_WARNING, "RXFBabk[%d] = %d\n", chno, def->ucfg[chno].rx_fb_sel); } diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h index e5b335d6..f84bf68f 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.h @@ -22,7 +22,7 @@ #ifndef NO_ECFG_DEFS enum ext_fe_rx_filterbank { - RX_FB_400_1000M, + RX_FB_50_1000M, RX_FB_1000_2000M, RX_FB_2000_3500M, RX_FB_2500_5000M, diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml index 2e1ccfed..e2be614e 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_e.yaml @@ -18,7 +18,7 @@ field_macros: True x-rx-filt-in-opts: &rx-filt-in-opts 0b000: MUTE0 - 0b011: 400_1000M + 0b011: 50_1000M 0b010: 1000_2000M 0b001: 2000_3500M 0b101: 2500_5000M @@ -29,7 +29,7 @@ x-rx-filt-in-opts: &rx-filt-in-opts x-rx-filt-out-opts: &rx-filt-out-opts 0b000: MUTE0 - 0b011: 400_1000M + 0b011: 50_1000M 0b100: 1000_2000M 0b101: 2000_3500M 0b001: 2500_5000M diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml index ea0ada57..5693fad3 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200_usr.yaml @@ -17,12 +17,12 @@ field_prefix: [ RegName ] field_macros: True x-rx-filt-opts: &rx-filt-opts - 0b0000: FILT_400_1000M + 0b0000: FILT_50_1000M 0b0001: FILT_1000_2000M 0b0010: FILT_2000_3500M 0b0011: FILT_2500_5000M 0b0100: FILT_3500_7100M - 0b1000: AUTO_400_1000M + 0b1000: AUTO_50_1000M 0b1001: AUTO_1000_2000M 0b1010: AUTO_2000_3500M 0b1011: AUTO_2500_5000M From 9b943f3184bc0a4ddfd5a525170807ebc79d07b3 Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 13:36:58 +0400 Subject: [PATCH 292/397] lmk04832: fix conflicting type --- src/lib/hw/lmk04832/lmk04832.c | 2 +- src/lib/hw/lmk04832/lmk04832.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/hw/lmk04832/lmk04832.c b/src/lib/hw/lmk04832/lmk04832.c index 5bc96473..d3dd1988 100644 --- a/src/lib/hw/lmk04832/lmk04832.c +++ b/src/lib/hw/lmk04832/lmk04832.c @@ -10,7 +10,7 @@ #include enum { - REG_ID_DEVICE_TYPE = DEVICE_TYPE, + REG_ID_DEVICE_TYPE = LMKDEV_TYPE, REG_ID_PROD_HI = PROD_HI, REG_ID_PROD_LOW = PROD_LOW, REG_ID_MASKREV = MASKREV, diff --git a/src/lib/hw/lmk04832/lmk04832.yaml b/src/lib/hw/lmk04832/lmk04832.yaml index 29a2e501..ef055e9c 100644 --- a/src/lib/hw/lmk04832/lmk04832.yaml +++ b/src/lib/hw/lmk04832/lmk04832.yaml @@ -27,11 +27,11 @@ pages: bits: '4' desc: 3 Wire Mode disabled - addr: '0x0003' - name: DEVICE_TYPE + name: LMKDEV_TYPE fields: - - name: DEVICE_TYPE + - name: LMKDEV_TYPE bits: '7:0' - desc: DEVICE_TYPE + desc: LMKDEV_TYPE - addr: '0x0004' name: PROD_HI fields: From c290821e4fdc544417bb4611f38b1f5847adef28 Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 13:44:19 +0400 Subject: [PATCH 293/397] cmake: x86_64 is AMD64 under windows --- src/cmake/detect_arch.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmake/detect_arch.cmake b/src/cmake/detect_arch.cmake index a5f8fe72..2a6507cd 100644 --- a/src/cmake/detect_arch.cmake +++ b/src/cmake/detect_arch.cmake @@ -9,7 +9,7 @@ if(${WVLT_ARCH} STREQUAL "x86") message(STATUS "Will compile for ${WVLT_ARCH} architecture") message(STATUS "Intel SIMD intrinsics will be used") -elseif(${WVLT_ARCH} STREQUAL "x86_64") +elseif(${WVLT_ARCH} STREQUAL "x86_64" OR ${WVLT_ARCH} STREQUAL "AMD64") add_definitions(-DWVLT_ARCH_X86_64) set(WVLT_ARCH_X86_64 1 CACHE BOOL "Arch x86_64") message(STATUS "Will compile for ${WVLT_ARCH} architecture") From 65ee898e88af554ff372a6bb92a03e04dbcceca5 Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 13:45:39 +0400 Subject: [PATCH 294/397] dmonitor: use PySide6 if available or fallback to pyqt5 --- src/dmonitor/pyqt5_widget.py | 40 ++++++++++++++++++++------------ src/dmonitor/registers_widget.py | 18 +++++++------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/dmonitor/pyqt5_widget.py b/src/dmonitor/pyqt5_widget.py index e48cceab..35b83c7e 100644 --- a/src/dmonitor/pyqt5_widget.py +++ b/src/dmonitor/pyqt5_widget.py @@ -1,25 +1,31 @@ #!/usr/bin/python3 -# Copyright (c) 2023-2024 Wavelet Lab +# Copyright (c) 2023-2026 Wavelet Lab # SPDX-License-Identifier: MIT import sys -from PyQt5.QtWidgets import * -from PyQt5.QtGui import QRegExpValidator, QPalette, QColor, QIcon -from PyQt5.QtCore import Qt, QObject, pyqtSignal, QRegExp +try: + from PySide6.QtWidgets import * + from PySide6.QtGui import QRegularExpressionValidator, QPalette, QColor, QIcon + from PySide6.QtCore import Qt, QObject, Signal, QRegularExpression + QT_VER = 6 +except ImportError: + from PyQt5.QtWidgets import * + from PyQt5.QtGui import QRegExpValidator, QPalette, QColor, QIcon + from PyQt5.QtCore import Qt, QObject, pyqtSignal, QRegExp + QT_VER = 5 + import math import configparser import re import time import os - ABS_PATH = os.path.dirname(os.path.abspath(__file__)) - class LongSpinBox(QAbstractSpinBox): - valueChanged = pyqtSignal(int) - clicked = pyqtSignal(Qt.MouseButton) + valueChanged = Signal(int) if QT_VER == 6 else pyqtSignal(int) + clicked = Signal(Qt.MouseButton)if QT_VER == 6 else pyqtSignal(Qt.MouseButton) def __init__(self, parent = None): super(LongSpinBox, self).__init__(parent) @@ -28,7 +34,11 @@ def __init__(self, parent = None): self.setMaximum(255) self.lineEdit().setText("0") self.lineEdit().textChanged.connect(lambda t: self.setValue(int(t))) - self.lineEdit().setValidator(QRegExpValidator(QRegExp("[0-9]*"), self.lineEdit())) + + if QT_VER == 6: + self.lineEdit().setValidator(QRegularExpressionValidator(QRegularExpression("[0-9]*"), self.lineEdit())) + else: + self.lineEdit().setValidator(QRegExpValidator(QRegExp("[0-9]*"), self.lineEdit())) def setMaximum(self, max_value): self.maximum = max_value @@ -312,11 +322,11 @@ def load_button_clicked(self)->None: if(not line): break - line = line.rstrip('\n').strip() + line = line.rstrip(r'\n').strip() if(found): - if re.match('^\[(.*)\]$', line) is not None: + if re.match(r'^\[(.*)\]$', line) is not None: break parts = line.split('=') @@ -334,14 +344,14 @@ def load_button_clicked(self)->None: regcnt += 1 #print('loaded 0x%04x=0x%04x' % (addr, val)) else: - found = ('[%s]' % ini_section_name) == line + found = (r'[%s]' % ini_section_name) == line if(found): - print('LOAD: found section [%s] in file "%s"' % (ini_section_name, inifile_name)) + print(r'LOAD: found section [%s] in file "%s"' % (ini_section_name, inifile_name)) if(not found): - print('LOAD: section [%s] not found in file "%s", registers were not loaded!' % (ini_section_name, inifile_name)) + print(r'LOAD: section [%s] not found in file "%s", registers were not loaded!' % (ini_section_name, inifile_name)) else: - print('LOAD: %d registers were loaded from "%s".[%s]' % (regcnt, inifile_name, ini_section_name)) + print(r'LOAD: %d registers were loaded from "%s".[%s]' % (regcnt, inifile_name, ini_section_name)) self.update() f.close() diff --git a/src/dmonitor/registers_widget.py b/src/dmonitor/registers_widget.py index 1d2f83b7..f49b8e08 100755 --- a/src/dmonitor/registers_widget.py +++ b/src/dmonitor/registers_widget.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # -*- coding: utf-8 -*- -# Copyright (c) 2023-2024 Wavelet Lab +# Copyright (c) 2023-2026 Wavelet Lab # SPDX-License-Identifier: MIT import os @@ -18,13 +18,17 @@ from conn_pipe import ConnDebugPipe -from PyQt5.QtWidgets import * -from PyQt5.QtGui import QPalette, QColor, QIcon -from PyQt5.QtCore import Qt, QTimer +try: + from PySide6.QtWidgets import * + from PySide6.QtGui import QPalette, QColor, QIcon + from PySide6.QtCore import Qt, QTimer +except ImportError: + from PyQt5.QtWidgets import * + from PyQt5.QtGui import QPalette, QColor, QIcon + from PyQt5.QtCore import Qt, QTimer import pyqtgraph as pg - ABS_PATH = os.path.dirname(os.path.abspath(__file__)) SCHEMA_PATH = "/usr/share/usdr/schema/" @@ -95,8 +99,6 @@ def update(self): pass - - class GeneralProperties(QScrollArea): def __init__(self, params, pipe): super(GeneralProperties, self).__init__() @@ -227,7 +229,7 @@ def __init__(self, paths): def find_hw_parser(self, pf): for p in self.parsers: - pattern = '^\s*' + str(p.path).replace('*', '([a-zA-Z0-9]+)') + '\s*$' + pattern = r'^\s*' + str(p.path).replace(r'*', r'([a-zA-Z0-9]+)') + r'\s*$' res = re.match(pattern, pf) if res is not None: return p From 012a0ae2ce322f18fd8bd3e38f5efb120bb9bf5a Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 14:08:37 +0400 Subject: [PATCH 295/397] use usdr_alignalloc / usdr_alignfree to allocate & free aligned memory --- src/lib/common/ring_buffer.c | 6 ++-- src/lib/common/ring_buffer.h | 11 +++++-- src/lib/common/ring_circbuf.c | 4 +-- src/lib/common/ring_circbuf.h | 3 +- src/lib/lowlevel/libusb_generic.c | 29 ++++++++++++++---- src/lib/lowlevel/libusb_generic.h | 1 + src/lib/port/usdr_port.h | 51 +++++++++++++++++++++++++++++++ src/lib/xdsp/filter.c | 4 +-- 8 files changed, 91 insertions(+), 18 deletions(-) diff --git a/src/lib/common/ring_buffer.c b/src/lib/common/ring_buffer.c index 0322a6ef..7bc706fe 100644 --- a/src/lib/common/ring_buffer.c +++ b/src/lib/common/ring_buffer.c @@ -15,7 +15,7 @@ struct ring_buffer* ring_buffer_create(unsigned items, unsigned isize) if (items == 0 || isize == 0) return NULL; - int res = posix_memalign((void**)&obj, CACHE_SIZE, sz); + int res = usdr_alignalloc((void**)&obj, CACHE_SIZE, sz); if (res) return NULL; @@ -36,7 +36,7 @@ struct ring_buffer* ring_buffer_create(unsigned items, unsigned isize) failed_s1: sem_destroy(&obj->producer); failed_s0: - free(obj); + usdr_alignfree(obj); return NULL; } @@ -44,7 +44,7 @@ void ring_buffer_destroy(struct ring_buffer* rb) { sem_destroy(&rb->producer); sem_destroy(&rb->consumer); - free(rb); + usdr_alignfree(rb); } char* ring_buffer_at(struct ring_buffer* rb, unsigned idx) diff --git a/src/lib/common/ring_buffer.h b/src/lib/common/ring_buffer.h index 233e706c..71778952 100644 --- a/src/lib/common/ring_buffer.h +++ b/src/lib/common/ring_buffer.h @@ -4,11 +4,9 @@ #ifndef RING_BUFFER_H #define RING_BUFFER_H -#include +#include #include -#define CACHE_SIZE 64 - // Fixed size circular array struct ring_buffer { @@ -18,10 +16,17 @@ struct ring_buffer unsigned pidx; unsigned cidx; +#ifdef _WIN32 + sem_t producer; + sem_t consumer; + + char reserved[CACHE_SIZE - 4*sizeof(unsigned) - 2*sizeof(sem_t)]; +#else char reserved[CACHE_SIZE - 4*sizeof(unsigned)]; sem_t producer; sem_t consumer; +#endif char data[0]; }; diff --git a/src/lib/common/ring_circbuf.c b/src/lib/common/ring_circbuf.c index d0b716bf..1edc324b 100644 --- a/src/lib/common/ring_circbuf.c +++ b/src/lib/common/ring_circbuf.c @@ -10,7 +10,7 @@ ring_circbuf_t* ring_circbuf_create(size_t max_size) { size_t sz = sizeof(ring_circbuf_t) + max_size; ring_circbuf_t* b; - int res = posix_memalign((void**)&b, 16, sz); + int res = usdr_alignalloc((void**)&b, CACHE_SIZE, sz); if (res) { return NULL; } @@ -23,7 +23,7 @@ ring_circbuf_t* ring_circbuf_create(size_t max_size) void ring_circbuf_destroy(ring_circbuf_t* rb) { - free(rb); + usdr_alignfree(rb); } diff --git a/src/lib/common/ring_circbuf.h b/src/lib/common/ring_circbuf.h index 8517abac..25c85b54 100644 --- a/src/lib/common/ring_circbuf.h +++ b/src/lib/common/ring_circbuf.h @@ -4,8 +4,7 @@ #ifndef RING_CIRCBUF_H #define RING_CIRCBUF_H -#include -#include +#include // Simple circbuffer struct ring_circbuf { diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index b78be016..e77dab4b 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -430,19 +430,27 @@ int buffers_realloc(struct buffers* rb, unsigned allocsz) int res; unsigned i; - free(rb->rqueuebuf_ptr); + usdr_alignfree(rb->rqueuebuf_ptr); free(rb->bd); rb->allocsz = allocsz; + rb->rqueuebuf_ptr = NULL; + rb->bd = NULL; + // Round up to maximum transfer in Bulk and reserve two more transfer in the case rb->allocsz_rounded = (allocsz + 4095) & (~4095u); rb->bd = (struct buffer_discriptor *)malloc(sizeof(struct buffer_discriptor) * (rb->buf_max + 1)); + if (rb->bd == NULL) + return -ENOMEM; - res = posix_memalign((void**)&rb->rqueuebuf_ptr, 4096, + res = usdr_alignalloc((void**)&rb->rqueuebuf_ptr, 4096, rb->allocsz_rounded * (rb->buf_max + 1)); - if (res != 0) + if (res != 0) { + free(rb->bd); + rb->bd = NULL; return -res; + } for (i = 0; i <= rb->buf_max; i++) { rb->bd[i].b = rb; @@ -450,8 +458,8 @@ int buffers_realloc(struct buffers* rb, unsigned allocsz) rb->bd[i].buffer_sz = 0; } - USDR_LOG("USBX", USDR_LOG_ERROR, "RX buffer configured to %d bytes for %d original\n", - rb->allocsz_rounded, allocsz); + USDR_LOG("USBX", USDR_LOG_ERROR, "RX buffer configured to %d x %d bytes for %d original\n", + rb->allocsz_rounded, rb->buf_max, allocsz); rb->bufno_prod = 0; rb->bufno_cons = 0; @@ -537,6 +545,10 @@ int buffers_usb_transfer_post(struct buffers *prxb, unsigned buffer_idx, unsigne unsigned transfer_idx) { int res; + + assert(buffer_idx <= prxb->buf_max); + assert(transfer_idx < prxb->transfers_count); + prxb->transfers[transfer_idx]->buffer = prxb->rqueuebuf_ptr + buffer_idx * prxb->allocsz_rounded; prxb->transfers[transfer_idx]->length = length; //prxb->allocsz_rounded; prxb->transfers[transfer_idx]->user_data = &prxb->bd[buffer_idx]; @@ -567,6 +579,7 @@ void LIBUSB_CALL libusb_transfer_buffers_cb(struct libusb_transfer *transfer) break; } assert(idx < rxb->transfers_count); + assert(rxbd->bno <= rxb->buf_max); USDR_LOG("USBX", USDR_LOG_DEBUG, "%s_STRM[%d] transfer %d => %d / %d\n", tr_type, idx, transfer->status, transfer->actual_length, transfer->length); @@ -628,6 +641,10 @@ int buffers_usb_init(libusb_generic_dev_t* gdev, struct buffers *prxb, max_reqs = BUFFERS_MAX_TRANS; } + if (max_reqs > max_buffs) { + max_reqs = max_buffs; + } + res = res ? res : buffers_init(prxb, max_buffs, usb_in ? 0 : max_buffs, eventfd_ntfy); res = res ? res : buffers_realloc(prxb, max_blocksize); res = res ? res : libusb_generic_prepare_transfer(gdev, NULL, endpoint, @@ -661,7 +678,7 @@ int buffers_usb_free(struct buffers *prxb) prxb->transfers[j] = NULL; } - free(prxb->rqueuebuf_ptr); + usdr_alignfree(prxb->rqueuebuf_ptr); prxb->rqueuebuf_ptr = NULL; free(prxb->bd); diff --git a/src/lib/lowlevel/libusb_generic.h b/src/lib/lowlevel/libusb_generic.h index 093410ce..6ceb5e61 100644 --- a/src/lib/lowlevel/libusb_generic.h +++ b/src/lib/lowlevel/libusb_generic.h @@ -4,6 +4,7 @@ #ifndef _LIBUSB_GENERIC_H #define _LIBUSB_GENERIC_H +#include #include #include #include diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index d977360d..9492afd1 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -13,6 +13,9 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif #define PORT_THREAD __thread @@ -34,4 +37,52 @@ #define SAFE_STRCPY(dst, src) ({strncpy((dst), (src), sizeof(dst) - 1); dst[SIZEOF_ARRAY(dst) - 1] = 0; }) +#ifdef _WIN32 +static inline int usdr_alignalloc(void **memptr, size_t alignment, size_t size) { + *memptr = _aligned_malloc(size, alignment); + return (*memptr) ? 0 : ENOMEM; +} +static inline void usdr_alignfree(void* ptr) { + _aligned_free(ptr); +} + +#define localtime_r(T,Tm) (localtime_s(Tm,T) ? NULL : Tm) + +#define ENAVAIL ENOENT + +static inline int gettid(void) +{ + return GetCurrentThreadId(); +} + +#else +static inline int usdr_alignalloc(void **memptr, size_t alignment, size_t size) { + return posix_memalign(memptr, alignment, size); +} +static inline void usdr_alignfree(void* ptr) { + free(ptr); +} +#endif + +#ifdef _WIN32 +typedef HANDLE library_hdl_t; +typedef off64_t off_long_t; +#define ftell_long ftello64 +#else +typedef void* library_hdl_t; +typedef off_t off_long_t; +#define ftell_long ftello +#endif + +library_hdl_t usdr_lib_load(const char* s); +void usdr_lib_close(library_hdl_t h); +void* usdr_lib_sym(library_hdl_t h, const char* proc); + + +#define CACHE_SIZE 64 + +#ifdef __cplusplus +}; +#endif + #endif diff --git a/src/lib/xdsp/filter.c b/src/lib/xdsp/filter.c index 736f09ee..0c789b3c 100644 --- a/src/lib/xdsp/filter.c +++ b/src/lib/xdsp/filter.c @@ -328,7 +328,7 @@ filter_data_t* filter_data_alloc(unsigned origblksz, if (flags & FDAF_SEPARATED) return NULL; - int res = posix_memalign((void**)&f, CACHE_LINE, sizeof(filter_data_t) + + int res = usdr_alignalloc((void**)&f, CACHE_LINE, sizeof(filter_data_t) + 3 * tapssz + datasz); if (res) { return NULL; @@ -424,7 +424,7 @@ filter_data_t* filter_data_alloc(unsigned origblksz, void filter_data_free(filter_data_t* o) { - free(o); + usdr_alignfree(o); } int16_t* filter_data_ptr(filter_data_t* o) From 9b39b4b2ef4ab959a82ee32ae30df11631a6f5ec Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 14:10:50 +0400 Subject: [PATCH 296/397] use ftell_long for cross platform 64-bit offset access --- src/lib/port/usdr_helpers.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/lib/port/usdr_helpers.c b/src/lib/port/usdr_helpers.c index 62a42c66..c99ac3a1 100644 --- a/src/lib/port/usdr_helpers.c +++ b/src/lib/port/usdr_helpers.c @@ -11,7 +11,7 @@ void* usdr_read_file(const char* filename, size_t* len) { char *buffer = NULL; - size_t length; + off_long_t length; FILE * f = fopen(filename, "rb"); if (!f) { int err = errno; @@ -23,15 +23,22 @@ void* usdr_read_file(const char* filename, size_t* len) } fseek(f, 0, SEEK_END); - length = ftell(f); + length = ftell_long(f); fseek(f, 0, SEEK_SET); + + if (length > INTPTR_MAX) { + fclose(f); + USDR_LOG("FILE", USDR_LOG_CRITICAL_WARNING, "File is too big!\n"); + return NULL; + } + buffer = (char*)malloc(length); if (buffer) { size_t rd = fread(buffer, 1, length, f); USDR_LOG("FILE", USDR_LOG_DEBUG, - "File %s was read %zu bytes\n", - filename, rd); + "File %s was read %llu bytes\n", + filename, (long long)rd); *len = rd; } fclose(f); From 1142caa365210c627bdce569b0ed5543f18db9be Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 14:13:42 +0400 Subject: [PATCH 297/397] add portable fnmatch() for windows-like systems --- src/lib/device/device.c | 2 +- src/lib/port/portable_fnmatch.c | 270 ++++++++++++++++++++++++++++++++ src/lib/port/portable_fnmatch.h | 72 +++++++++ src/lib/port/test_fnmatch.c | 238 ++++++++++++++++++++++++++++ src/lib/port/usdr_port.h | 3 + 5 files changed, 584 insertions(+), 1 deletion(-) create mode 100644 src/lib/port/portable_fnmatch.c create mode 100644 src/lib/port/portable_fnmatch.h create mode 100644 src/lib/port/test_fnmatch.c diff --git a/src/lib/device/device.c b/src/lib/device/device.c index bd74cfca..7e9f1acc 100644 --- a/src/lib/device/device.c +++ b/src/lib/device/device.c @@ -4,12 +4,12 @@ #include "device.h" #include #include +#include #include #include #include #include "device_vfs.h" #include "device_names.h" -#include static int _usdr_device_vfs_get_by_path(device_t *base, const char* fullpath, pusdr_vfs_obj_t *obj); int usdr_device_base_create(pdevice_t dev, lldev_t lldev) diff --git a/src/lib/port/portable_fnmatch.c b/src/lib/port/portable_fnmatch.c new file mode 100644 index 00000000..8daea43e --- /dev/null +++ b/src/lib/port/portable_fnmatch.c @@ -0,0 +1,270 @@ +#include "portable_fnmatch.h" + +#include +#include + +static int is_sep(char c, int flags) { + if (flags & FNM_WINPATH) + return (c == '/' || c == '\\'); + return (c == '/'); +} + +static unsigned char fold_ch(unsigned char c, int flags) { + if (flags & FNM_CASEFOLD) + return (unsigned char)tolower(c); + return c; +} + +static int ch_eq(char a, char b, int flags) { + return fold_ch((unsigned char)a, flags) == fold_ch((unsigned char)b, flags); +} + +static int is_leading_period(const char *s, const char *s0, int flags) { + if (!(flags & FNM_PERIOD)) + return 0; + if (*s != '.') + return 0; + if (s == s0) + return 1; + if ((flags & FNM_PATHNAME) && is_sep(s[-1], flags)) + return 1; + return 0; +} + +static int match_posix_class(const char *name, char test) { + unsigned char c = (unsigned char)test; + if (strcmp(name, "alnum") == 0) return isalnum(c); + if (strcmp(name, "alpha") == 0) return isalpha(c); + if (strcmp(name, "blank") == 0) return (c == ' ' || c == '\t'); + if (strcmp(name, "cntrl") == 0) return iscntrl(c); + if (strcmp(name, "digit") == 0) return isdigit(c); + if (strcmp(name, "graph") == 0) return isgraph(c); + if (strcmp(name, "lower") == 0) return islower(c); + if (strcmp(name, "print") == 0) return isprint(c); + if (strcmp(name, "punct") == 0) return ispunct(c); + if (strcmp(name, "space") == 0) return isspace(c); + if (strcmp(name, "upper") == 0) return isupper(c); + if (strcmp(name, "xdigit") == 0) return isxdigit(c); + return 0; +} + +/* + * Bracket expression matcher. + * Returns: + * 1 if matched + * 0 if not matched + * -1 if invalid (no closing ']') -> caller can treat '[' literally + * On success/nomatch, *newp is set to the position after the closing ']'. + */ +static int bracket_match(const char *p, char test, int flags, const char **newp) { + const char *pp = p + 1; + int negate = 0; + int ok = 0; + + if (*pp == '\0') { + if (newp) *newp = p; + return -1; + } + + if (*pp == '!' || *pp == '^') { + negate = 1; + pp++; + } + + /* ']' allowed first in class */ + if (*pp == ']') { + if (ch_eq(']', test, flags)) + ok = 1; + pp++; + } + + for (; *pp != '\0' && *pp != ']'; pp++) { + /* POSIX character class: [[:digit:]] etc */ + if (pp[0] == '[' && pp[1] == ':' ) { + const char *name_start = pp + 2; + const char *end = strstr(name_start, ":]"); + if (end) { + char name[32]; + size_t nlen = (size_t)(end - name_start); + if (nlen < sizeof(name)) { + memcpy(name, name_start, nlen); + name[nlen] = '\0'; + if (match_posix_class(name, test)) + ok = 1; + pp = end + 1; /* loop will ++pp => char after ']' of :]' */ + continue; + } + } + } + + char c1 = *pp; + + if (c1 == '\\' && !(flags & FNM_NOESCAPE) && pp[1] != '\0') { + pp++; + c1 = *pp; + } + + /* Range a-b */ + if (pp[1] == '-' && pp[2] != '\0' && pp[2] != ']') { + const char *pp2 = pp + 2; + char c2 = *pp2; + + if (c2 == '\\' && !(flags & FNM_NOESCAPE) && pp2[1] != '\0') { + pp2++; + c2 = *pp2; + } + + unsigned char a = fold_ch((unsigned char)c1, flags); + unsigned char b = fold_ch((unsigned char)c2, flags); + unsigned char t = fold_ch((unsigned char)test, flags); + if (a <= t && t <= b) + ok = 1; + + pp = pp2; /* loop will ++pp -> next char after range end */ + continue; + } + + if (ch_eq(c1, test, flags)) + ok = 1; + } + + if (*pp != ']') { + if (newp) *newp = p; + return -1; + } + + pp++; /* consume ']' */ + if (newp) *newp = pp; + + if (negate) + ok = !ok; + + return ok; +} + +static int match_here(const char *p, const char *s, const char *s0, int flags) { + for (;;) { + char pc = *p; + + switch (pc) { + case '\0': + if ((flags & FNM_LEADING_DIR) && is_sep(*s, flags)) + return 0; + return (*s == '\0') ? 0 : FNM_NOMATCH; + + case '?': + if (*s == '\0') + return FNM_NOMATCH; + if ((flags & FNM_PATHNAME) && is_sep(*s, flags)) + return FNM_NOMATCH; + if (is_leading_period(s, s0, flags)) + return FNM_NOMATCH; + p++; s++; + continue; + + case '*': { + if (is_leading_period(s, s0, flags)) + return FNM_NOMATCH; + + while (*p == '*') + p++; + + if (*p == '\0') { + if (flags & FNM_PATHNAME) { + if (flags & FNM_LEADING_DIR) + return 0; + /* must not consume a separator */ + for (const char *t = s; *t; t++) { + if (is_sep(*t, flags)) + return FNM_NOMATCH; + } + return 0; + } + return 0; + } + + for (const char *ss = s;; ss++) { + int r = match_here(p, ss, s0, flags); + if (r == 0) + return 0; + + if (*ss == '\0') + break; + if ((flags & FNM_PATHNAME) && is_sep(*ss, flags)) + break; + } + return FNM_NOMATCH; + } + + case '[': { + const char *np = NULL; + int br; + + if (*s == '\0') + return FNM_NOMATCH; + if ((flags & FNM_PATHNAME) && is_sep(*s, flags)) + return FNM_NOMATCH; + if (is_leading_period(s, s0, flags)) + return FNM_NOMATCH; + + br = bracket_match(p, *s, flags, &np); + if (br == -1) { + if (!ch_eq('[', *s, flags)) + return FNM_NOMATCH; + p++; s++; + continue; + } + if (br == 0) + return FNM_NOMATCH; + + p = np; + s++; + continue; + } + + case '\\': + if (!(flags & FNM_NOESCAPE) && p[1] != '\0') { + p++; + pc = *p; + } + /* fallthrough */ + default: + if (*s == '\0') + return FNM_NOMATCH; + + /* If PATHNAME, separators are special and must match separators */ + if ((flags & FNM_PATHNAME) && is_sep(*s, flags)) { + if (!is_sep(pc, flags)) + return FNM_NOMATCH; + /* Treat '/' and '\\' as equivalent when WINPATH is set */ + p++; s++; + continue; + } + + if (!ch_eq(pc, *s, flags)) + return FNM_NOMATCH; + p++; s++; + continue; + } + } +} + +int portable_fnmatch(const char *pattern, const char *string, int flags) { + if (!pattern || !string) + return FNM_NOMATCH; + return match_here(pattern, string, string, flags); +} + +/* + * Optional drop-in: if the platform lacks a system fnmatch(), export one. + * This is mainly for Windows/MinGW. + * + * Define PORTABLE_FNMATCH_FORCE_EXPORT_FNMATCH to export fnmatch() even if + * a system was found. + */ +#if !PORTABLE_FNMATCH_HAVE_SYSTEM_HEADER || defined(PORTABLE_FNMATCH_FORCE_EXPORT_FNMATCH) +int fnmatch(const char *pattern, const char *string, int flags) { + return portable_fnmatch(pattern, string, flags); +} +#endif + diff --git a/src/lib/port/portable_fnmatch.h b/src/lib/port/portable_fnmatch.h new file mode 100644 index 00000000..7c0714a9 --- /dev/null +++ b/src/lib/port/portable_fnmatch.h @@ -0,0 +1,72 @@ +#ifndef PORTABLE_FNMATCH_H +#define PORTABLE_FNMATCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * If a system exists, include it so we inherit the platform's + * flag bit assignments (they are NOT universal across libcs). + * + * On MinGW/Windows, this header typically does not exist, so we fall back + * to defining the common POSIX bits. + */ +#if !defined(PORTABLE_FNMATCH_NO_SYSTEM_HEADERS) +#if defined(__has_include) +#if __has_include() +#include +#define PORTABLE_FNMATCH_HAVE_SYSTEM_HEADER 1 +#else +#define PORTABLE_FNMATCH_HAVE_SYSTEM_HEADER 0 +#endif +#else +/* Conservative fallback: assume no system header */ +#define PORTABLE_FNMATCH_HAVE_SYSTEM_HEADER 0 +#endif +#else +#define PORTABLE_FNMATCH_HAVE_SYSTEM_HEADER 0 +#endif + +/* Return codes */ +#ifndef FNM_NOMATCH +#define FNM_NOMATCH 1 +#endif + +/* POSIX flags (define only if the platform header didn't) */ +#ifndef FNM_NOESCAPE +#define FNM_NOESCAPE 0x01 +#endif +#ifndef FNM_PATHNAME +#define FNM_PATHNAME 0x02 +#endif +#ifndef FNM_PERIOD +#define FNM_PERIOD 0x04 +#endif + +/* Common extensions (define if missing) */ +#ifndef FNM_LEADING_DIR +#define FNM_LEADING_DIR 0x08 +#endif +#ifndef FNM_CASEFOLD +#define FNM_CASEFOLD 0x10 +#endif + +/* Windows-friendly extension: treat '\\' as a path separator too */ +#ifndef FNM_WINPATH +#define FNM_WINPATH 0x20 +#endif + +/* Preferred API: doesn't collide with system fnmatch() */ +int portable_fnmatch(const char *pattern, const char *string, int flags); + +#if !PORTABLE_FNMATCH_HAVE_SYSTEM_HEADER || defined(PORTABLE_FNMATCH_FORCE_EXPORT_FNMATCH) +int fnmatch(const char *pattern, const char *string, int flags); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PORTABLE_FNMATCH_H */ + diff --git a/src/lib/port/test_fnmatch.c b/src/lib/port/test_fnmatch.c new file mode 100644 index 00000000..356b33f7 --- /dev/null +++ b/src/lib/port/test_fnmatch.c @@ -0,0 +1,238 @@ +#include +#include +#include + +#include "portable_fnmatch.h" + +/* If system fnmatch exists, include it for reference comparisons */ +#if defined(__unix__) || defined(__APPLE__) +#include +#define HAVE_SYSTEM_FNMATCH 1 +#else +#define HAVE_SYSTEM_FNMATCH 0 +#endif + +/* Compare portable to system fnmatch when available. + * You can force-disable with -DNO_SYSTEM_COMPARE. + */ +#if HAVE_SYSTEM_FNMATCH && !defined(NO_SYSTEM_COMPARE) +#define DO_SYSTEM_COMPARE 1 +#else +#define DO_SYSTEM_COMPARE 0 +#endif + +typedef struct { + const char *pat; + const char *str; + int flags; + int expect; /* 0 or FNM_NOMATCH */ + const char *desc; +} tc_t; + +static const tc_t cases[] = { + {"", "", 0, 0, "empty matches empty"}, + {"", "a", 0, FNM_NOMATCH, "empty does not match non-empty"}, + {"a", "a", 0, 0, "literal"}, + {"abc", "abc", 0, 0, "literal multi"}, + {"abc", "ab", 0, FNM_NOMATCH, "literal length"}, + + {"a?c", "abc", 0, 0, "? wildcard"}, + {"a?c", "ac", 0, FNM_NOMATCH, "? requires one char"}, + + {"a*c", "abbbc", 0, 0, "* wildcard"}, + {"a*c", "ac", 0, 0, "* can be empty"}, + {"*", "anything", 0, 0, "* matches all"}, + + {"a\\*c", "a*c", 0, 0, "escaped *"}, + {"a\\?c", "a?c", 0, 0, "escaped ?"}, + {"a\\*c", "abbbc", 0, FNM_NOMATCH, "escaped * is literal"}, + {"a\\*c", "a*c", FNM_NOESCAPE, FNM_NOMATCH, "noescape treats backslash literally"}, + + {"[ab]", "a", 0, 0, "bracket set"}, + {"[ab]", "c", 0, FNM_NOMATCH, "bracket set no"}, + {"[a-c]", "b", 0, 0, "bracket range"}, + {"[!a-c]", "z", 0, 0, "bracket negate"}, + {"[!a-c]", "b", 0, FNM_NOMATCH, "bracket negate no"}, + {"[]]", "]", 0, 0, "']' first in class"}, + {"[-a]", "-", 0, 0, "'-' literal at start"}, + {"[a-]", "-", 0, 0, "'-' literal at end"}, + + {"[[:digit:]]", "5", 0, 0, "posix class digit"}, + {"[[:alpha:]]", "Z", 0, 0, "posix class alpha"}, + {"[[:xdigit:]]", "f", 0, 0, "posix class xdigit"}, + {"[[:digit:]]", "x", 0, FNM_NOMATCH, "posix class digit no"}, + + {"ABC", "abc", FNM_CASEFOLD, 0, "casefold literal"}, + {"[A-C]", "b", FNM_CASEFOLD, 0, "casefold in range"}, + + {"*", ".bashrc", FNM_PERIOD, FNM_NOMATCH, "period blocks leading dot"}, + {".*", ".bashrc", FNM_PERIOD, 0, "period explicit dot"}, + {"?", ".x", FNM_PERIOD, FNM_NOMATCH, "period blocks leading dot with ?"}, + + {"a/*", "a/.b", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH, "period blocks dot after /"}, + {"a/.*", "a/.b", FNM_PATHNAME | FNM_PERIOD, 0, "period explicit dot after /"}, + + {"a*b", "a/x/b", FNM_PATHNAME, FNM_NOMATCH, "pathname: * cannot cross /"}, + {"a*b", "a/x/b", 0, 0, "no pathname: * can cross /"}, + {"a?b", "a/b", FNM_PATHNAME, FNM_NOMATCH, "pathname: ? cannot match /"}, + {"a[/]b", "a/b", FNM_PATHNAME, FNM_NOMATCH, "pathname: bracket cannot match /"}, + + {"abc", "abc/def", FNM_PATHNAME | FNM_LEADING_DIR, 0, "leading_dir: literal prefix"}, + {"a*", "abcd/ef", FNM_PATHNAME | FNM_LEADING_DIR, 0, "leading_dir: star prefix"}, + {"a*", "abcd/ef", FNM_PATHNAME, FNM_NOMATCH, "no leading_dir: needs full match"}, + + /* WINPATH extension */ + {"a/b", "a\\b", FNM_PATHNAME | FNM_WINPATH, 0, "winpath: / matches \\\\ in string"}, + {"a/*", "a\\b", FNM_PATHNAME | FNM_WINPATH, 0, "winpath: separator then component"}, + {"a/*", "a\\b\\c", FNM_PATHNAME | FNM_WINPATH, FNM_NOMATCH, "winpath: * cannot cross \\\\ separator"}, + + /* invalid bracket treated literally */ + {"[", "[", 0, 0, "invalid bracket treated as literal"}, + }; + +static const char *flags_to_str(int f, char *buf, size_t n) { + buf[0] = 0; + int first = 1; +#define ADD(name, val) do { if (f & (val)) { if (!first) strncat(buf, "|", n-1); strncat(buf, name, n-1); first = 0; } } while(0) + ADD("NOESCAPE", FNM_NOESCAPE); + ADD("PATHNAME", FNM_PATHNAME); + ADD("PERIOD", FNM_PERIOD); + ADD("LEADING_DIR", FNM_LEADING_DIR); + ADD("CASEFOLD", FNM_CASEFOLD); + ADD("WINPATH", FNM_WINPATH); +#undef ADD + if (first) strncpy(buf, "0", n); + buf[n-1] = 0; + return buf; +} + +static void run_fixed_tests(void) { + int fails = 0; + int sys_mismatch = 0; + + for (size_t i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) { + const tc_t *t = &cases[i]; + int r = portable_fnmatch(t->pat, t->str, t->flags); + int ok = (r == t->expect); + + if (!ok) { + char fb[128]; + fprintf(stderr, "FAIL[%zu]: %s\n pat='%s' str='%s' flags=%s\n got=%d expect=%d\n", + i, t->desc, t->pat, t->str, flags_to_str(t->flags, fb, sizeof(fb)), r, t->expect); + fails++; + } + +#if DO_SYSTEM_COMPARE + { + /* System fnmatch doesn't know WINPATH; mask it out for reference comparison */ + int sys_flags = t->flags & ~FNM_WINPATH; + + int sr = fnmatch(t->pat, t->str, sys_flags); + sr = (sr == 0) ? 0 : FNM_NOMATCH; + + int pr = (r == 0) ? 0 : FNM_NOMATCH; + + if (sr != pr) { + char fb[128]; + fprintf(stderr, "SYS MISMATCH[%zu]: %s\n pat='%s' str='%s' flags=%s\n portable=%d system=%d\n", + i, t->desc, t->pat, t->str, flags_to_str(t->flags, fb, sizeof(fb)), pr, sr); + sys_mismatch++; + } + } +#endif + } + + if (fails == 0) + printf("Fixed tests: PASS (%zu cases)\n", sizeof(cases)/sizeof(cases[0])); + else { + printf("Fixed tests: FAIL (%d/%zu failed)\n", fails, sizeof(cases)/sizeof(cases[0])); + exit(1); + } + +#if DO_SYSTEM_COMPARE + if (sys_mismatch == 0) + printf("System compare: OK (no mismatches on comparable cases)\n"); + else { + printf("System compare: %d mismatches (see stderr)\n", sys_mismatch); + exit(2); + } +#endif +} + +/* Simple fuzz: generate random patterns/strings (restricted alphabet) and compare to system fnmatch. + Only enabled when system compare is available. */ +static unsigned rng_u32(unsigned *st) { + *st = (*st * 1103515245u + 12345u); + return *st; +} + +static void rand_str(unsigned *st, char *out, size_t maxlen, int want_pattern) { + static const char alpha[] = "abcXYZ012-._/"; + static const char meta[] = "*?[]!\\"; + size_t len = (rng_u32(st) % (unsigned)maxlen); + + for (size_t i = 0; i < len; i++) { + unsigned r = rng_u32(st); + if (want_pattern && (r % 6 == 0)) + out[i] = meta[r % (sizeof(meta)-1)]; + else + out[i] = alpha[r % (sizeof(alpha)-1)]; + } + out[len] = '\0'; + + if (want_pattern && (rng_u32(st) % 5 == 0)) + strcat(out, "*"); +} + +static void run_fuzz(int iters) { +#if DO_SYSTEM_COMPARE + unsigned st = 0xC0FFEEu; + int mism = 0; + + for (int i = 0; i < iters; i++) { + char pat[64], str[64]; + rand_str(&st, pat, 20, 1); + rand_str(&st, str, 20, 0); + + int flags = 0; + if (rng_u32(&st) & 1) flags |= FNM_NOESCAPE; + if (rng_u32(&st) & 1) flags |= FNM_PATHNAME; + if (rng_u32(&st) & 1) flags |= FNM_PERIOD; + + int pr = portable_fnmatch(pat, str, flags); + int sr = fnmatch(pat, str, flags); + + sr = (sr == 0) ? 0 : FNM_NOMATCH; + pr = (pr == 0) ? 0 : FNM_NOMATCH; + + if (pr != sr) { + char fb[128]; + fprintf(stderr, "FUZZ MISMATCH[%d]: pat='%s' str='%s' flags=%s portable=%d system=%d\n", + i, pat, str, flags_to_str(flags, fb, sizeof(fb)), pr, sr); + mism++; + if (mism > 50) break; + } + } + + if (mism == 0) + printf("Fuzz: OK (%d iterations)\n", iters); + else { + printf("Fuzz: %d mismatches (see stderr)\n", mism); + exit(3); + } +#else + (void)iters; + printf("Fuzz: skipped (no system fnmatch available)\n"); +#endif +} + +int main(int argc, char **argv) { + run_fixed_tests(); + + if (argc == 3 && strcmp(argv[1], "--fuzz") == 0) { + int iters = atoi(argv[2]); + if (iters <= 0) iters = 10000; + run_fuzz(iters); + } + return 0; +} diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index 9492afd1..cba05bf6 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -12,6 +12,9 @@ #include #include #include +#include + +#include "portable_fnmatch.h" #ifdef __cplusplus extern "C" { From 88dd1075ef8b6eac0c8216ce613f708d96756a5f Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 14:29:59 +0400 Subject: [PATCH 298/397] add conditional compilation fixes for WIN32 --- src/lib/device/mdev.c | 3 ++ src/lib/ipblks/lms64c_proto.c | 2 +- src/lib/ipblks/si2c.h | 2 +- src/lib/ipblks/spiext.h | 2 +- src/lib/ipblks/streams/stream_limesdr.c | 2 +- src/lib/lowlevel/libusb_generic.c | 24 +++++++++++++--- src/lib/lowlevel/libusb_generic.h | 6 ++++ src/lib/lowlevel/pcie_uram/pcie_uram_main.c | 4 +++ src/lib/lowlevel/usdr_lowlevel.c | 2 +- src/lib/lowlevel/usdr_lowlevel.h | 3 -- src/lib/models/dm_debug.c | 32 +++++++++++++-------- src/lib/models/dm_dev.c | 5 +++- src/tools/usdr_dm_gpsdo.c | 13 +++++++-- 13 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/lib/device/mdev.c b/src/lib/device/mdev.c index 4e17c3b4..3aa575ce 100644 --- a/src/lib/device/mdev.c +++ b/src/lib/device/mdev.c @@ -1,5 +1,6 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +#ifndef _WIN32 #include #include @@ -620,3 +621,5 @@ int mdev_create(unsigned pcnt, const char** names, const char** values, lldev_t* free(obj); return res; } + +#endif diff --git a/src/lib/ipblks/lms64c_proto.c b/src/lib/ipblks/lms64c_proto.c index e5c46725..e359f7c8 100644 --- a/src/lib/ipblks/lms64c_proto.c +++ b/src/lib/ipblks/lms64c_proto.c @@ -3,7 +3,7 @@ #include #include -#include +#include #include "lms64c_cmds.h" #include "lms64c_proto.h" diff --git a/src/lib/ipblks/si2c.h b/src/lib/ipblks/si2c.h index f953dc86..a344245e 100644 --- a/src/lib/ipblks/si2c.h +++ b/src/lib/ipblks/si2c.h @@ -8,7 +8,7 @@ #ifndef SI2C_H #define SI2C_H -#if defined(__EMSCRIPTEN__) +#if defined(__EMSCRIPTEN__) || defined(_WIN32) #include #include #else diff --git a/src/lib/ipblks/spiext.h b/src/lib/ipblks/spiext.h index 8e7faa10..a71c8900 100644 --- a/src/lib/ipblks/spiext.h +++ b/src/lib/ipblks/spiext.h @@ -8,7 +8,7 @@ #ifndef SPIEXT_H #define SPIEXT_H -#if defined(__EMSCRIPTEN__) +#if defined(__EMSCRIPTEN__) || defined(_WIN32) #include #include typedef uint8_t __u8; diff --git a/src/lib/ipblks/streams/stream_limesdr.c b/src/lib/ipblks/streams/stream_limesdr.c index 4668bd02..f68921a8 100644 --- a/src/lib/ipblks/streams/stream_limesdr.c +++ b/src/lib/ipblks/streams/stream_limesdr.c @@ -1,12 +1,12 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +#include #include #include #include #include #include -#include #include #include "stream_limesdr.h" diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index e77dab4b..39f7b238 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -379,7 +379,11 @@ int buffers_init(struct buffers* rb, unsigned max, unsigned zerosemval, bool has } if (has_event) { +#ifdef WIN32 + rb->fd_event = -ENOTSUP; +#else rb->fd_event = fdevent_create(zerosemval); +#endif if (rb->fd_event < 0) { int err = -errno; USDR_LOG("USBX", USDR_LOG_ERROR, "Unable to create eventfd! err=%d\n", err); @@ -415,14 +419,16 @@ void buffers_deinit(struct buffers* rb) usleep(10000); sem_destroy(&rb->buf_ready); - free(rb->rqueuebuf_ptr); - free(rb->bd); + // usdr_alignfree(rb->rqueuebuf_ptr); + // free(rb->bd); +#ifndef WIN32 if (rb->fd_event >= 0) fdevent_destroy(rb->fd_event); +#endif rb->fd_event = -101; - rb->rqueuebuf_ptr = NULL; - rb->bd = NULL; + // rb->rqueuebuf_ptr = NULL; + // rb->bd = NULL; } int buffers_realloc(struct buffers* rb, unsigned allocsz) @@ -474,8 +480,10 @@ void buffers_reset(struct buffers* rb) sem_destroy(&rb->buf_ready); sem_init(&rb->buf_ready, 0, 0); +#ifndef WIN32 if (rb->fd_event > 0) fdevent_get(rb->fd_event, NULL); +#endif } // Ready buffer to or from IO @@ -494,7 +502,11 @@ int buffers_ready_wait(struct buffers *rxb, int64_t timeout_us) { int res; if (rxb->fd_event >= 0) { +#ifndef WIN32 res = fdevent_get(rxb->fd_event, NULL); +#else + res = -ENOTSUP; +#endif } else { res = sem_wait_ex(&rxb->buf_ready, timeout_us * 1000); } @@ -505,7 +517,11 @@ int buffers_ready_post(struct buffers *rxb) { int res; if (rxb->fd_event >= 0) { +#ifndef WIN32 res = fdevent_post(rxb->fd_event, 1); +#else + res = -ENOTSUP; +#endif } else { res = sem_post(&rxb->buf_ready); } diff --git a/src/lib/lowlevel/libusb_generic.h b/src/lib/lowlevel/libusb_generic.h index 6ceb5e61..5b57623e 100644 --- a/src/lib/lowlevel/libusb_generic.h +++ b/src/lib/lowlevel/libusb_generic.h @@ -7,7 +7,13 @@ #include #include #include + +#ifdef WIN32 +#include +#else #include +#endif + #include #include #include diff --git a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c index a10f470f..bcaf9b06 100644 --- a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c +++ b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c @@ -1,5 +1,6 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +#ifndef WIN32 #include "pcie_uram_main.h" @@ -1100,3 +1101,6 @@ const struct lowlevel_plugin *pcie_uram_register() { return &s_pcie_uram_plugin; } + +#endif + diff --git a/src/lib/lowlevel/usdr_lowlevel.c b/src/lib/lowlevel/usdr_lowlevel.c index 2800be5f..cc46dfc1 100644 --- a/src/lib/lowlevel/usdr_lowlevel.c +++ b/src/lib/lowlevel/usdr_lowlevel.c @@ -62,7 +62,7 @@ unsigned lowlevel_initialize_plugins() //TODO driver loading plugins[s_driver_count++] = usbft601_uram_register(); plugins[s_driver_count++] = usb_uram_register(); -#if !defined(__EMSCRIPTEN__) && !defined(WVLT_WEBUSB_BUILD) +#if !defined(__EMSCRIPTEN__) && !defined(WVLT_WEBUSB_BUILD) && !defined(WIN32) plugins[s_driver_count++] = pcie_uram_register(); #endif diff --git a/src/lib/lowlevel/usdr_lowlevel.h b/src/lib/lowlevel/usdr_lowlevel.h index cdb4c3f4..6a9cf32d 100644 --- a/src/lib/lowlevel/usdr_lowlevel.h +++ b/src/lib/lowlevel/usdr_lowlevel.h @@ -4,10 +4,7 @@ #ifndef USDR_LOWLEVEL_H #define USDR_LOWLEVEL_H -#include -#include #include - #include diff --git a/src/lib/models/dm_debug.c b/src/lib/models/dm_debug.c index 97f4bb72..b77ab398 100644 --- a/src/lib/models/dm_debug.c +++ b/src/lib/models/dm_debug.c @@ -4,25 +4,30 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif + +#include #include #include #include #include #include #include +#include +#include +#ifdef _WIN32 +#include +#include +#else #include -#ifndef WIN32 -#include #include +#include #endif -#include -#include - #include "dm_dev.h" -#include "dm_dev_impl.h" #include "dm_debug.h" +#include + static int usdr_dif_process_cmd(struct usdr_debug_ctx* ctx, char *cmd, unsigned len, char* reply, unsigned rlen) @@ -76,19 +81,21 @@ int usdr_dif_process_cmd(struct usdr_debug_ctx* ctx, char *cmd, unsigned len, } } -#if !defined(WIN32) && !defined(__EMSCRIPTEN__) +#if !defined(__EMSCRIPTEN__) static void* usdr_dif_thread(void* param) { int ret; struct sockaddr_un name; struct usdr_debug_ctx* ctx = (struct usdr_debug_ctx*)param; USDR_LOG("DBGS", USDR_LOG_INFO, "Starting USDR debug thread\n"); + +#ifndef _WIN32 sigset_t set; pthread_setname_np(pthread_self(), "debug_io"); sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); - +#endif pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); const char* fifoname = "usdr_debug_pipe"; unlink(fifoname); @@ -193,9 +200,10 @@ int usdr_dif_init(const char *params, //void *obj, struct usdr_debug_ctx** octx) { -#if !defined(WIN32) && !defined(__EMSCRIPTEN__) - +#if !defined(__EMSCRIPTEN__) int res; + +#ifndef _WIN32 const char* fifoname = "usdr_debug_pipe"; int fd = mkfifo(fifoname, 0666); if (fd < 0 && errno != EEXIST) { @@ -204,7 +212,7 @@ int usdr_dif_init(const char *params, fifoname, err); return err; } - +#endif struct usdr_debug_ctx* ctx = (struct usdr_debug_ctx*)malloc(sizeof(struct usdr_debug_ctx)); if (!ctx) return -ENOMEM; @@ -230,7 +238,7 @@ int usdr_dif_init(const char *params, int usdr_dif_free(struct usdr_debug_ctx* ctx) { -#if !defined(WIN32) && !defined(__EMSCRIPTEN__) +#if !defined(__EMSCRIPTEN__) close(ctx->fd); pthread_cancel(ctx->debug_thread); diff --git a/src/lib/models/dm_dev.c b/src/lib/models/dm_dev.c index 3f63d7a0..91c4ba22 100644 --- a/src/lib/models/dm_dev.c +++ b/src/lib/models/dm_dev.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "dm_stream.h" #include "../ipblks/streams/streams_api.h" @@ -101,8 +100,12 @@ int _usdr_dmd_create(const struct dev_params *par, pdm_dev_t* odev, if (bus_cnt <= 1) { res = lowlevel_create(par->num, (const char**)par->params, (const char**)par->value, &lldev, vidpid, webops, param); } else { +#ifdef WIN32 + res = -ENOTSUP; +#else res = mdev_create(par->num, (const char**)par->params, (const char**)par->value, &lldev, idx, bus_names, bus_cnt); +#endif } if (res) return res; diff --git a/src/tools/usdr_dm_gpsdo.c b/src/tools/usdr_dm_gpsdo.c index e17eb444..d8c0c610 100644 --- a/src/tools/usdr_dm_gpsdo.c +++ b/src/tools/usdr_dm_gpsdo.c @@ -13,8 +13,10 @@ #include #include #include +#ifndef WIN32 #include #include +#endif // PID parameters #define KP 0.75 // Proportional gain @@ -259,7 +261,7 @@ int main(int argc, char **argv) struct timespec start_time; clock_gettime(CLOCK_MONOTONIC, &start_time); - +#ifndef WIN32 // Create timerfd for 100 ms polling int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); if (timer_fd == -1) { @@ -280,6 +282,7 @@ int main(int argc, char **argv) struct pollfd fds[1]; fds[0].fd = timer_fd; fds[0].events = POLLIN; +#endif const double holdover_interval = 2 * dt; uint32_t dac_offset = dac.center; // initial @@ -287,6 +290,10 @@ int main(int argc, char **argv) while (true) { // Wait for timer event +#ifdef WIN32 + Sleep(100); + { +#else int ret = poll(fds, 1, -1); if (ret == -1) { perror("poll"); @@ -296,7 +303,7 @@ int main(int argc, char **argv) if (fds[0].revents & POLLIN) { uint64_t expirations; read(timer_fd, &expirations, sizeof(expirations)); // Clear timer event - +#endif res = usdr_dme_get_uint(dev, pps_path, &ppsparm); if (res) { fprintf(stderr, "Unable to get pps: errno %d\n", res); @@ -364,7 +371,9 @@ int main(int argc, char **argv) } } +#ifndef WIN32 close(timer_fd); +#endif usdr_dmd_close(dev); return 0; From 0752e14cec24843dd620fdb391f3c706d1edcca7 Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 14:31:28 +0400 Subject: [PATCH 299/397] use portable dynamic library API wrapper --- src/lib/hw/afe79xx/afe79xx.c | 38 ++++++++++++++++------------ src/lib/port/usdr_port.c | 48 ++++++++++++++++++++++++++++++++++++ src/lib/port/usdr_port.h | 15 +++++++++++ 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/src/lib/hw/afe79xx/afe79xx.c b/src/lib/hw/afe79xx/afe79xx.c index 2d0ec4d2..1d016fc6 100644 --- a/src/lib/hw/afe79xx/afe79xx.c +++ b/src/lib/hw/afe79xx/afe79xx.c @@ -1,9 +1,7 @@ #include "afe79xx.h" #include +#include #include -#include -#include - enum afe79xx_regs { CHIP_TYPE = 3, @@ -91,9 +89,12 @@ int afe79xx_create_dummy(afe79xx_state_t* out) int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipType, afe79xx_state_t* out) { int res; - const char* afe79xxlib = "liblibcapi79xx.so"; - unsigned g; - + const char* afe79xxlib = +#ifdef _WIN32 + "liblibcapi79xx.dll"; +#else + "liblibcapi79xx.so"; +#endif memset(out, 0, sizeof(*out)); out->dev = dev; out->subdev = subdev; @@ -121,25 +122,30 @@ int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipT out->capi.user = NULL; out->capi.driver_handle = NULL; - out->dl_handle = dlopen(afe79xxlib, RTLD_NOW); + out->dl_handle = usdr_lib_load(afe79xxlib); // dlopen(afe79xxlib, RTLD_NOW); if (out->dl_handle == NULL) { +#ifdef _WIN32 + USDR_LOG("79xx", USDR_LOG_ERROR, "Couldn't load CAPI AFE79XX NDA LIB wrapper `%s`!\n", + afe79xxlib); +#else USDR_LOG("79xx", USDR_LOG_ERROR, "Couldn't load CAPI AFE79XX NDA LIB wrapper `%s`: %s!\n", afe79xxlib, dlerror()); +#endif return -EFAULT; } - out->libcapi79xx_create = (libcapi79xx_create_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_CREATE_FN); - out->libcapi79xx_destroy = (libcapi79xx_destroy_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_DESTROY_FN); - out->libcapi79xx_init = (libcapi79xx_init_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_INIT_FN); + out->libcapi79xx_create = (libcapi79xx_create_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_CREATE_FN); + out->libcapi79xx_destroy = (libcapi79xx_destroy_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_DESTROY_FN); + out->libcapi79xx_init = (libcapi79xx_init_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_INIT_FN); - out->libcapi79xx_upd_nco = (libcapi79xx_upd_nco_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_UPD_NCO_FN); - out->libcapi79xx_get_nco = (libcapi79xx_get_nco_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_GET_NCO_FN); + out->libcapi79xx_upd_nco = (libcapi79xx_upd_nco_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_UPD_NCO_FN); + out->libcapi79xx_get_nco = (libcapi79xx_get_nco_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_GET_NCO_FN); - out->libcapi79xx_set_dsa = (libcapi79xx_set_dsa_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_SET_DSA_FN); + out->libcapi79xx_set_dsa = (libcapi79xx_set_dsa_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_SET_DSA_FN); - out->libcapi79xx_check_health = (libcapi79xx_check_health_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_CHECK_HEALTH_FN); + out->libcapi79xx_check_health = (libcapi79xx_check_health_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_CHECK_HEALTH_FN); - out->libcapi79xx_set_tdd = (libcapi79xx_set_tdd_fn_t)dlsym(out->dl_handle, LIBCAPI79XX_SET_TDD_FN); + out->libcapi79xx_set_tdd = (libcapi79xx_set_tdd_fn_t)usdr_lib_sym(out->dl_handle, LIBCAPI79XX_SET_TDD_FN); if (!out->libcapi79xx_create || !out->libcapi79xx_destroy || !out->libcapi79xx_init || !out->libcapi79xx_set_dsa || !out->libcapi79xx_set_tdd || @@ -155,7 +161,7 @@ int afe79xx_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned chipT out->libcapi79xx_check_health != NULL, out->libcapi79xx_set_tdd != NULL); - dlclose(out->dl_handle); + usdr_lib_close(out->dl_handle); return -EFAULT; } diff --git a/src/lib/port/usdr_port.c b/src/lib/port/usdr_port.c index e69de29b..02bd47d2 100644 --- a/src/lib/port/usdr_port.c +++ b/src/lib/port/usdr_port.c @@ -0,0 +1,48 @@ +#include "usdr_port.h" + +#ifdef _WIN32 +void __attribute__ ((constructor(220))) setup_winsocks(void) { + WSADATA wsaData; + int iResult; + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (iResult != 0) { + _exit(2); + } +} + +library_hdl_t usdr_lib_load(const char* s) +{ + return LoadLibraryA(s); +} + +void usdr_lib_close(library_hdl_t h) +{ + CloseHandle(h); +} + +void* usdr_lib_sym(library_hdl_t h, const char* proc) +{ + return GetProcAddress(h, proc); +} + +#else + +library_hdl_t usdr_lib_load(const char* s) +{ + return dlopen(s, RTLD_LAZY | RTLD_DEEPBIND | RTLD_GLOBAL); +} + +void usdr_lib_close(library_hdl_t h) +{ + dlclose(h); +} + +void* usdr_lib_sym(library_hdl_t h, const char* proc) +{ + return dlsym(h, proc); +} + +#endif + diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index cba05bf6..cd78a02a 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -3,13 +3,28 @@ #ifndef USDR_PORT_H #define USDR_PORT_H + +#define _FILE_OFFSET_BITS 64 + +#ifdef _WIN32 +#include +#endif + #include #include #include #include #include #include + +#ifdef _WIN32 +#define htobe32(x) htonl(x) +#define be32toh(x) ntohl(x) +#else #include +#include +#include +#endif #include #include #include From 6636a6995f86e1bc16925ff0d7de2e7760f4b97c Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 14:32:22 +0400 Subject: [PATCH 300/397] fix printf() format for 4/8 byte long type --- src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c | 12 +++--------- src/lib/lowlevel/usb_uram/usb_uram_libusb.c | 16 +++++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c b/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c index efd277c3..581caf56 100644 --- a/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c +++ b/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c @@ -7,16 +7,10 @@ #include #include #include -#include -#include #include -#include #include #include -#include #include -#include -#include #include #include "../device/device.h" @@ -257,8 +251,8 @@ int usbft601_uram_recv_dma_wait(lldev_t dev, subdev_t subdev, stream_t channel, USDR_LOG("USBX", (rxb->allocsz == bd->buffer_sz) ? USDR_LOG_DEBUG : USDR_LOG_ERROR, - "Buffer %d / %08x %08x %08x %08x TO=%d SEQ=%16ld\n", - bd->buffer_sz, pkt[0], pkt[1], pkt[2], pkt[3], timeout, cnt); + "Buffer %d / %08x %08x %08x %08x TO=%d SEQ=%16lld\n", + bd->buffer_sz, pkt[0], pkt[1], pkt[2], pkt[3], timeout, (long long)cnt); *buffer = tr_buffer; @@ -298,7 +292,7 @@ int usbft601_uram_send_dma_get(lldev_t dev, subdev_t subdev, stream_t channel, v unsigned bno = buffers_produce(rxb); *buffer = buffers_get_ptr(rxb, bno); - USDR_LOG("USBX", USDR_LOG_DEBUG, "TX Alloc BNO=%d %ld\n", bno, cnt); + USDR_LOG("USBX", USDR_LOG_DEBUG, "TX Alloc BNO=%d %lld\n", bno, (long long)cnt); cnt++; return 0; diff --git a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c index 9fbc730b..60c71f51 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c @@ -7,16 +7,10 @@ #include #include #include -#include -#include #include -#include #include #include -#include #include -#include -#include #include "usb_uram_generic.h" #include "../device/device.h" @@ -515,6 +509,10 @@ int _usb_uram_init_rxstream(usb_dev_t* d, res = buffers_usb_init(&d->gdev, prxb, transfers, params->buffer_count, params->block_size + trailer_sz, EP_IN_DEFSTREAM, eventtype); + if (res) { + USDR_LOG("USBX", USDR_LOG_ERROR, "Stream RX initialization failed: %d!\n", res); + return res; + } prxb->auto_restart = true; d->rx_buffer_missed[0] = 0; @@ -655,8 +653,8 @@ int usb_uram_recv_dma_wait(lldev_t dev, subdev_t subdev, stream_t channel, void* USDR_LOG("USBX", (rxb->allocsz == bd->buffer_sz) ? USDR_LOG_DEBUG : USDR_LOG_ERROR, - "Buffer %d / %08x %08x TO=%d SEQ=%16ld\n", - buffer_sz, bursts, skipped, timeout, cnt); + "Buffer %d / %08x %08x TO=%d SEQ=%16lld\n", + buffer_sz, bursts, skipped, timeout, (long long)cnt); if (oob_size && *oob_size >= 8) { // memset(oob_ptr, 0, *oob_size); @@ -709,7 +707,7 @@ int usb_uram_send_dma_get(lldev_t dev, subdev_t subdev, stream_t channel, void** unsigned bno = buffers_produce(rxb); *buffer = buffers_get_ptr(rxb, bno) + TXSTRM_META_SZ; - USDR_LOG("USBX", USDR_LOG_DEBUG, "TX Alloc BNO=%d %ld\n", bno, cnt); + USDR_LOG("USBX", USDR_LOG_DEBUG, "TX Alloc BNO=%d %lld\n", bno, (long long)cnt); // Trottle statistics to relax extra load if (oob_size) { From 6c3ae96267f783133ed38a0c1c5aa785736bd58e Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 5 Feb 2026 14:39:49 +0400 Subject: [PATCH 301/397] cmake: fix windows build --- src/lib/CMakeLists.txt | 13 +++++++++++-- src/lib/port/CMakeLists.txt | 3 +++ src/tools/CMakeLists.txt | 8 ++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 2c3ab942..78647913 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -7,7 +7,7 @@ project(usdr_lib C) # Auto generating register descriptors list(APPEND USDR_LIBRARY_FILES "") list(APPEND USDR_INCLUDE_FILES "") -list(APPEND USDR_LINK_FILES pthread rt) +list(APPEND USDR_LINK_FILES pthread) list(APPEND USDR_DEPEND_TARGETS "") include_directories(port) @@ -32,7 +32,16 @@ include_directories(${USDR_INCLUDE_DIRS}) add_library(usdr ${USDR_LIBRARY_FILES}) -target_link_libraries(usdr dl pthread rt ${USDR_LINK_FILES} usdr-dsp) + +if(NOT WIN32) + set(USDR_PLATFORM_LIBS dl rt) +else() + set(USDR_PLATFORM_LIBS kernel32 ws2_32) +endif() + +message(NOTICE "Usdr link:${USDR_LINK_FILES}") + +target_link_libraries(usdr pthread ${USDR_PLATFORM_LIBS} ${USDR_LINK_FILES} usdr-dsp) add_dependencies(usdr ${USDR_DEPEND_TARGETS}) target_compile_options(usdr PRIVATE "-Wall" "-Werror=implicit-function-declaration") diff --git a/src/lib/port/CMakeLists.txt b/src/lib/port/CMakeLists.txt index 561158dc..17e9d5a9 100644 --- a/src/lib/port/CMakeLists.txt +++ b/src/lib/port/CMakeLists.txt @@ -5,9 +5,12 @@ set(USDR_PORT_LIB_FILES ${CMAKE_CURRENT_SOURCE_DIR}/usdr_logging.c ${CMAKE_CURRENT_SOURCE_DIR}/usdr_port.c ${CMAKE_CURRENT_SOURCE_DIR}/usdr_helpers.c + ${CMAKE_CURRENT_SOURCE_DIR}/portable_fnmatch.c ) list(APPEND USDR_LIBRARY_FILES ${USDR_PORT_LIB_FILES}) set(USDR_LIBRARY_FILES ${USDR_LIBRARY_FILES} PARENT_SCOPE) +add_executable(test_fnmatch test_fnmatch.c portable_fnmatch.c) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION include/usdr FILES_MATCHING PATTERN "*.h") diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 83fa4400..12783783 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -33,3 +33,11 @@ list(APPEND WVLT_SCRIPTS wvlt_sdr_wrapper.py ) configure_file(${WVLT_SCRIPTS} . USE_SOURCE_PERMISSIONS COPYONLY) + +if(WIN32) + set_target_properties(usdr_dm_create PROPERTIES WIN32_EXECUTABLE FALSE) + set_target_properties(usdr_dm_sensors PROPERTIES WIN32_EXECUTABLE FALSE) + set_target_properties(usdr_flash PROPERTIES WIN32_EXECUTABLE FALSE) + set_target_properties(usdr_lml7_test PROPERTIES WIN32_EXECUTABLE FALSE) + set_target_properties(usdr_dm_gpsdo PROPERTIES WIN32_EXECUTABLE FALSE) +endif() From 65cbca6070c5cb8b0aa412cab5338929f71545a9 Mon Sep 17 00:00:00 2001 From: Timur <62694921+dtv-comp@users.noreply.github.com> Date: Tue, 18 Nov 2025 22:20:24 +0300 Subject: [PATCH 302/397] Fixed WASM build (#95) * Fixed WASM build Fixed LimeSDR Mini support * Workaround for broken MaxReadReq configuration --- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 9 +- src/lib/hw/lms8001/lms8001.c | 103 ++++++++++-------- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 10 +- src/lib/json_controller/controller.c | 7 +- src/lib/lowlevel/usb_ft601/usb_ft601_webusb.c | 8 +- 5 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 653aa307..1f89afce 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -256,7 +256,6 @@ int lms7002m_set_gain(lms7002_dev_t *d, res = lms7002m_rbb_pga(&d->lmsstate, gain * 10); break; case RFIC_LMS7_RX_LB_GAIN: - res = lms7002m_rfe_gain(&d->lmsstate, RFE_GAIN_RFB, gain * 10, &aret); actual = aret / 10; @@ -269,6 +268,7 @@ int lms7002m_set_gain(lms7002_dev_t *d, if (gain > 0) gain = 0; actual = gain; + res = lms7002m_trf_gain(&d->lmsstate, TRF_GAIN_PAD, -10 * gain, &aret); if (channel & LMS7_CH_A) d->tx_loss[0] = aret / -10; @@ -283,13 +283,10 @@ int lms7002m_set_gain(lms7002_dev_t *d, d->trf_lb_atten = -gain; d->trf_lb_loss = 0; //res = lms7002m_trf_gain(&d->lmsstate, d->trf_lb_atten, d->trf_lb_loss); - res = lms7002m_trf_gain(&d->lmsstate, TRF_GAIN_PAD, -10 * gain, &aret); + res = lms7002m_trf_gain(&d->lmsstate, TRF_GAIN_LB, -10 * gain, &aret); break; case RFIC_LMS7_TX_PGA_GAIN: - if (gain > 63) - gain = 63; - else if (gain < -62) - gain = -62; + gain = clamp(gain, -62, 63); actual = 0; res = lms7002m_tbb_gain(&d->lmsstate, gain); diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index bf8d425b..26ebbb59 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -655,6 +655,8 @@ static int _lms8001_center_vtune(lms8001_state_t* m, uint64_t fvco, int fref, ui int swvdd_list[4] = { 3, 2, 1, 0 }; int amp_list[4] = { 3, 2, 1, 0 }; + bool continue_vtune = true; + for (int i = 0; i < 4; i++) { int vdiv_swvdd = swvdd_list[i]; if (vdiv_swvdd_init != vdiv_swvdd) { @@ -662,71 +664,76 @@ static int _lms8001_center_vtune(lms8001_state_t* m, uint64_t fvco, int fref, ui res = _lms8001_change_pll_vco_cfg(m, fvco, fref, flags, &vco_settings); if (res == 1) { USDR_LOG("8001", USDR_LOG_INFO, "VTUNE voltage centered successfuly by changing VDIV_SWVDD value = %d\n", vdiv_swvdd); - goto restore_autotune; + continue_vtune = false; + break; } else if (res) { return res; } } } - // Set back VDIV_SWVDD<1:0> and FREQ<7:0> to inital values - SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VDIV_SWVDD_n(curr->VCO_CFG, vdiv_swvdd_init); - SET_LMS8001_PLL_PROFILE_0_PLL_VCO_FREQ_N_VCO_FREQ_n(curr->VCO_FREQ, freq_init); - uint32_t lms_init2[] = { - _mk_pav(m, PLL_PROFILE_0_PLL_VCO_CFG_n, curr->VCO_CFG), - _mk_pav(m, PLL_PROFILE_0_PLL_VCO_FREQ_n, curr->VCO_FREQ), - }; - res = lms8001_spi_post(m, lms_init2, SIZEOF_ARRAY(lms_init2)); - if (res) { - return res; - } + if (continue_vtune) { + // Set back VDIV_SWVDD<1:0> and FREQ<7:0> to inital values + SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VDIV_SWVDD_n(curr->VCO_CFG, vdiv_swvdd_init); + SET_LMS8001_PLL_PROFILE_0_PLL_VCO_FREQ_N_VCO_FREQ_n(curr->VCO_FREQ, freq_init); + uint32_t lms_init2[] = { + _mk_pav(m, PLL_PROFILE_0_PLL_VCO_CFG_n, curr->VCO_CFG), + _mk_pav(m, PLL_PROFILE_0_PLL_VCO_FREQ_n, curr->VCO_FREQ), + }; + res = lms8001_spi_post(m, lms_init2, SIZEOF_ARRAY(lms_init2)); + if (res) { + return res; + } - for (int i = 0; i < 4; i++) { - int amp = amp_list[i]; - if (amp_init != amp) { - SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, amp); - SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, 1); - res = _lms8001_change_pll_vco_cfg(m, fvco, fref, flags, &vco_settings); - if (res == 1) { - USDR_LOG("8001", USDR_LOG_INFO, "VTUNE voltage centered successfuly by changing VCO_AMP value = %d\n", amp); - goto restore_autotune; - } else if (res) { - return res; + for (int i = 0; i < 4; i++) { + int amp = amp_list[i]; + if (amp_init != amp) { + SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, amp); + SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, 1); + res = _lms8001_change_pll_vco_cfg(m, fvco, fref, flags, &vco_settings); + if (res == 1) { + USDR_LOG("8001", USDR_LOG_INFO, "VTUNE voltage centered successfuly by changing VCO_AMP value = %d\n", amp); + continue_vtune = false; + break; + } else if (res) { + return res; + } } } } - // Set back VCO_AMP, VCO_AAC_EN, and FREQ<7:0> to inital values - SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, amp_init); - SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, aac_en_init); - SET_LMS8001_PLL_PROFILE_0_PLL_VCO_FREQ_N_VCO_FREQ_n(curr->VCO_FREQ, freq_init); + if (continue_vtune) { + // Set back VCO_AMP, VCO_AAC_EN, and FREQ<7:0> to inital values + SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, amp_init); + SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, aac_en_init); + SET_LMS8001_PLL_PROFILE_0_PLL_VCO_FREQ_N_VCO_FREQ_n(curr->VCO_FREQ, freq_init); - uint32_t lms_init3[] = { - _mk_pav(m, PLL_PROFILE_0_PLL_VCO_CFG_n, curr->VCO_CFG), - _mk_pav(m, PLL_PROFILE_0_PLL_VCO_FREQ_n, curr->VCO_FREQ), - }; - res = lms8001_spi_post(m, lms_init3, SIZEOF_ARRAY(lms_init3)); - if (res) { - return res; - } + uint32_t lms_init3[] = { + _mk_pav(m, PLL_PROFILE_0_PLL_VCO_CFG_n, curr->VCO_CFG), + _mk_pav(m, PLL_PROFILE_0_PLL_VCO_FREQ_n, curr->VCO_FREQ), + }; + res = lms8001_spi_post(m, lms_init3, SIZEOF_ARRAY(lms_init3)); + if (res) { + return res; + } - // FIXME: somehow it helps! - // Last resort check - usleep(5000); - res = _lms8001_lock_status(m, &vtune_high, &vtune_low, &pll_lock); - if (res) - return res; + // FIXME: somehow it helps! + // Last resort check + usleep(5000); + res = _lms8001_lock_status(m, &vtune_high, &vtune_low, &pll_lock); + if (res) + return res; - if ((vtune_high == 0) && (vtune_low == 0)) { - USDR_LOG("8001", USDR_LOG_INFO, "Centering of VTUNE back to origianl\n"); - return 0; - } + if ((vtune_high == 0) && (vtune_low == 0)) { + USDR_LOG("8001", USDR_LOG_INFO, "Centering of VTUNE back to origianl\n"); + return 0; + } - USDR_LOG("8001", USDR_LOG_ERROR, "Centering VTUNE using VDIV_SWVDD and VCO_AMP failed!\n"); - return -ERANGE; + USDR_LOG("8001", USDR_LOG_ERROR, "Centering VTUNE using VDIV_SWVDD and VCO_AMP failed!\n"); + return -ERANGE; + } -restore_autotune: // Set back PLL_CAL_AUTO1 to starting values SET_LMS8001_PLL_CONFIGURATION_PLL_CAL_AUTO1_VCO_SEL_FORCE(m->pll.PLL_CAL_AUTO1, vco_sel_force_init); SET_LMS8001_PLL_CONFIGURATION_PLL_CAL_AUTO1_VCO_SEL_INIT(m->pll.PLL_CAL_AUTO1, vco_sel_init); diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 6a6aee21..2017d8f5 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -444,7 +444,7 @@ int _sfetrx4_stream_send(stream_handle_t* str, stream->stats.pktok ++; USDR_LL_LOG(dev, "UDMS", USDR_LOG_DEBUG, "Send stat %d -- %08x.%08x.%08x.%08x -- HOST:%d WIRE:%d\n" - " Buff (Pstd/Reqd/Cpld/Aired) %2d/%2d/%2d/%2d DropFE:%"PRId64" DropDMA:%"PRId64" TAGS:%d FIFO:%d\n", + " Buff (Pstd/Reqd/Cpld/Aired) %2d/%2d/%2d/%2d DropFE:%" PRId64 " DropDMA:%" PRId64 " TAGS:%d FIFO:%d\n", stat_sz, stat[0], stat[1], stat[2], stat[3], host_bytes, wire_bytes, st.usrbuf_posted, st.usrbuf_requested, st.usrbuf_completed, st.usrbuf_aired, stream->stats.fe_drop, stream->stats.dma_drop, st.pcietags, st.fifo_used); @@ -473,11 +473,11 @@ int _sfetrx4_stream_send(stream_handle_t* str, for (unsigned b = 0; b < bursts; b++) { stream->tf_data(nstreams, host_bytes, &dma_buffer, wire_bytes); for (unsigned i = 0; i < stream->channels; i++) { - nstreams[i] += host_off; + nstreams[i] = (char*)nstreams[i] + host_off; } - dma_buffer += (wire_bytes + brst_align) & ~brst_align; + dma_buffer = (char*)dma_buffer + ((wire_bytes + brst_align) & ~brst_align); } - wire_len = dma_buffer - buffer; + wire_len = (char*)dma_buffer - (char*)buffer; } else { wire_len = wire_bytes * bursts; stream->tf_data((const void**)stream_buffs, host_bytes * bursts, &buffer, wire_len); @@ -513,7 +513,7 @@ static int _sfetrx4_op(stream_handle_t* str, start = true; break; default: - USDR_LL_LOG(dev, "UDMS", USDR_LOG_INFO, "Stream[%d] STOP; STATS bytes = %" PRIu64 ", samples = %" PRIu64 ", dropped_fe/dropped_dma/rcvd = %"PRIu64"/%"PRIu64"/%"PRIu64"\n", + USDR_LL_LOG(dev, "UDMS", USDR_LOG_INFO, "Stream[%d] STOP; STATS bytes = %" PRIu64 ", samples = %" PRIu64 ", dropped_fe/dropped_dma/rcvd = %" PRIu64 "/%" PRIu64 "/%" PRIu64 "\n", stream->ll_streamo, stream->stats.wirebytes, stream->stats.symbols, stream->stats.fe_drop, stream->stats.dma_drop, stream->stats.pktok); start = false; } diff --git a/src/lib/json_controller/controller.c b/src/lib/json_controller/controller.c index 4aa51806..1aea5959 100644 --- a/src/lib/json_controller/controller.c +++ b/src/lib/json_controller/controller.c @@ -387,6 +387,10 @@ int generic_rpc_call(pdm_dev_t dmdev, { int gain = (pcall->params.parameters_type[SDRC_GAIN] == SDRC_PARAM_TYPE_INT) ? pcall->params.parameters_uint[SDRC_GAIN] : 0; + if (sdrtype == SDR_LIME && pcall->call_type == SDR_TX_GAIN) { + //LimeSDR TX gain correction + gain = -32 - gain; + } uint64_t actual; res = set_endpoint_uint_param(dmdev, @@ -492,7 +496,8 @@ int generic_rpc_call(pdm_dev_t dmdev, if(mode & (i+1)) res = res ? res : usdr_dms_op(usds[i], stream_start ? USDR_DMS_START : USDR_DMS_STOP, 0); - res = res ? res : set_throttle(dmdev, throttleon, samplerate); + if (!(mode & 2)) + res = res ? res : set_throttle(dmdev, throttleon, samplerate); res = res ? res : usdr_dms_sync(dmdev, stypes, streams_num, streams); if(res) diff --git a/src/lib/lowlevel/usb_ft601/usb_ft601_webusb.c b/src/lib/lowlevel/usb_ft601/usb_ft601_webusb.c index 5d404ac9..13e16911 100644 --- a/src/lib/lowlevel/usb_ft601/usb_ft601_webusb.c +++ b/src/lib/lowlevel/usb_ft601/usb_ft601_webusb.c @@ -123,7 +123,13 @@ static int webusb_ll_stream_initialize(lldev_t dev, subdev_t subdev, lowlevel_stream_params_t* params, stream_t* channel) { int res = 0; - UNUSED const unsigned data_endpoint = (params->streamno == DEV_RX_STREAM_NO) ? EP_IN_DEFSTREAM : EP_OUT_DEFSTREAM; + const unsigned data_endpoint = (params->streamno == DEV_RX_STREAM_NO) ? EP_IN_DEFSTREAM : EP_OUT_DEFSTREAM; + + res = res ? res : ft601_flush_pipe(dev, data_endpoint); + res = res ? res : ft601_set_stream_pipe(dev, data_endpoint, DATA_PACKET_SIZE); + + if (res) + return res; USDR_LOG("USBX", USDR_LOG_ERROR, "webusb_ll_stream_initialize(streamno=%d)\n", params->streamno); *channel = params->streamno; From 0b62f292237f6e7155ab85d28306dc32259f4d6f Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 5 Feb 2026 17:20:08 +0400 Subject: [PATCH 303/397] Fix WASM build error in the feature_pe_sync branch --- src/lib/device/m2_lm6_1/m2_lm6_1.c | 4 +- src/lib/device/m2_lm7_1/m2_lm7_1.c | 10 +-- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 7 +- src/lib/hw/lmk05318/lmk05318.c | 69 +++++++++---------- src/lib/hw/lmx1204/lmx1204.c | 10 +-- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 4 +- src/lib/port/CMakeLists.txt | 4 +- src/lib/port/usdr_port.c | 6 +- 8 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index 763c7350..f1fea306 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -889,8 +889,8 @@ usdr_dev_t* get_usdr_dev(pdevice_t udev) int dev_m2_lm6_1_sdr_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - board_ext_pciefe_t* board_fe = device_fe_to(d->fe, "pciefe"); - board_exm2pe_t* board = device_fe_to(d->fe, "exm2pe"); + board_ext_pciefe_t* board_fe = (board_ext_pciefe_t*)device_fe_to(d->fe, "pciefe"); + board_exm2pe_t* board = (board_exm2pe_t*)device_fe_to(d->fe, "exm2pe"); if (board_fe) { return board_ext_pciefe_set_dac(board_fe, value); } else if (board) { diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 537b434c..f714b67b 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -399,9 +399,9 @@ int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t v int dev_m2_lm7_1_dev_dac_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - board_ext_pciefe_t* board_fe = device_fe_to(d->fe, "pciefe"); - board_exm2pe_t* board = device_fe_to(d->fe, "exm2pe"); - ext_fe_ch4_400_7200_t* fe = device_fe_to(d->fe, "fe4ch4007200"); + board_ext_pciefe_t* board_fe = (board_ext_pciefe_t*)device_fe_to(d->fe, "pciefe"); + board_exm2pe_t* board = (board_exm2pe_t*)device_fe_to(d->fe, "exm2pe"); + ext_fe_ch4_400_7200_t* fe = (ext_fe_ch4_400_7200_t*)device_fe_to(d->fe, "fe4ch4007200"); if (board_fe) { return board_ext_pciefe_set_dac(board_fe, value); } else if (board) { @@ -1442,7 +1442,7 @@ static int usdr_device_m2_lm7_1_create(lldev_t dev, device_id_t devid) { int res; - unsigned hwid; + unsigned hwid, did; struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)malloc(sizeof(struct dev_m2_lm7_1_gps)); res = xsdr_ctor(dev, &d->xdev); @@ -1459,7 +1459,7 @@ int usdr_device_m2_lm7_1_create(lldev_t dev, device_id_t devid) //if (res) { // goto failed_free; //} - unsigned did = ((hwid >> 16) & 0xff); + did = ((hwid >> 16) & 0xff); if ((res == 0) && (did == SSDR_DEV || did == SSDRPRO_DEV)) { res = vfs_add_const_i64_vec(&d->base.rootfs, diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 44413a63..d6e72b74 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -664,6 +664,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) uint64_t rx_badness = UINT64_MAX; uint64_t tx_badness = UINT64_MAX; unsigned tx_iqerrs = UINT_MAX; + unsigned iqserrs2 = -1; g_clk_reduce = 0; @@ -692,7 +693,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (!(d->base.rx_run[0] || d->base.rx_run[1])) { res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, IGPO_LMS_PWR_LDOEN | IGPO_LMS_PWR_NRESET | IGPO_LMS_PWR_RXEN | IGPO_LMS_PWR_TXEN); res = res ? res : usleep(1000); - res = res ? res : lms7002m_streaming_up(&d->base, RFIC_LMS7_RX, LMS7_CH_AB, 0, 0, 0); + res = res ? res : lms7002m_streaming_up(&d->base, RFIC_LMS7_RX, LMS7_CH_AB, 0, LMS7_CH_NONE, 0); } res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, 0, 0, 0); @@ -913,8 +914,6 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) // Make sure it's a good value res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness_m); - unsigned iqserrs2 = -1; - // Check A/B & I/Q aligment is ok res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); res = res ? res : usleep(10); @@ -952,7 +951,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (rx_badness || (!mmcm_rx_only_path && (tx_badness || tx_iqerrs))) { bool severe = (rx_badness > 100) || (!mmcm_rx_only_path && (tx_badness > 100 || tx_iqerrs > 10)); - USDR_LL_LOG(dev, "XDEV", severe ? USDR_LOG_ERROR : USDR_LOG_WARNING, "LML Calibration failed: RX_BADNESS=%"PRId64" TX_BADNESS=%"PRId64" TX_IQERRS=%d\n", + USDR_LL_LOG(dev, "XDEV", severe ? USDR_LOG_ERROR : USDR_LOG_WARNING, "LML Calibration failed: RX_BADNESS=%" PRId64 " TX_BADNESS=%" PRId64 " TX_IQERRS=%d\n", rx_badness, mmcm_rx_only_path ? 0 : tx_badness, mmcm_rx_only_path ? 0 : tx_iqerrs); if (res == 0 && severe) diff --git a/src/lib/hw/lmk05318/lmk05318.c b/src/lib/hw/lmk05318/lmk05318.c index 370e7175..280584b6 100644 --- a/src/lib/hw/lmk05318/lmk05318.c +++ b/src/lib/hw/lmk05318/lmk05318.c @@ -316,9 +316,9 @@ int lmk05318_dpll_config(lmk05318_state_t* d, lmk05318_dpll_settings_t* dpll) USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] %s:enabled FREF:%" PRIu64 " DC_MODE:%u(%s) BUF_MODE:%u(%s) TYPE:%u(%s) RDIV:%u", nm, dpll->fref[i], - dpll->dc_mode[i], lmk05318_dpll_decode_ref_dc_mode(dpll->dc_mode[i]), - dpll->buf_mode[i], lmk05318_dpll_decode_ref_buf_mode(dpll->buf_mode[i]), - dpll->type[i], lmk05318_dpll_decode_ref_type(dpll->type[i]), + dpll->dc_mode[i], lmk05318_dpll_decode_ref_dc_mode((enum lmk05318_ref_dc_mode_t)dpll->dc_mode[i]), + dpll->buf_mode[i], lmk05318_dpll_decode_ref_buf_mode((enum lmk05318_ref_buf_mode_t)dpll->buf_mode[i]), + dpll->type[i], lmk05318_dpll_decode_ref_type((enum lmk05318_ref_input_type_t)dpll->type[i]), d->dpll.rdiv[i]); else USDR_LOG("5318", USDR_LOG_INFO, "[DPLL] %s:disabled", nm); @@ -1182,7 +1182,7 @@ int lmk05318_set_xo_fref(lmk05318_state_t* d) USDR_LOG("5318", USDR_LOG_INFO, "[XO] FREF:%u TYPE:%u(%s) DOUBLER:%u RDIV:%u FDET_BYPASS:%u", xo_fref, - xo_type_raw, lmk05318_decode_xo_type(xo_type_raw), + xo_type_raw, lmk05318_decode_xo_type((enum xo_type_options)xo_type_raw), d->xo.doubler_enabled, d->xo.pll1_fref_rdiv, xo_fdet_bypass); uint32_t regs[] = { @@ -2199,46 +2199,43 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned outs[i].port, outs[i].wanted.freq, outs[i].wanted.freq_delta_minus, outs[i].wanted.freq_delta_plus); } - if(!cnt_to_solve) - goto have_complete_solution; + if(cnt_to_solve) { + static const uint64_t fvco2_pd_min = VCO_APLL2_MIN / APLL2_PDIV_MAX; + static const uint64_t fvco2_pd_max = VCO_APLL2_MAX / APLL2_PDIV_MIN; - static const uint64_t fvco2_pd_min = VCO_APLL2_MIN / APLL2_PDIV_MAX; - static const uint64_t fvco2_pd_max = VCO_APLL2_MAX / APLL2_PDIV_MIN; + //determine valid PD ranges for our frequencies + for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) + { + lmk05318_out_config_t* out = outs + i; + if(out->solved) + continue; - //determine valid PD ranges for our frequencies - for(unsigned i = 0; i < LMK05318_MAX_REAL_PORTS; ++i) - { - lmk05318_out_config_t* out = outs + i; - if(out->solved) - continue; + const range_t r = lmk05318_get_freq_range(out); + const range_t ifreq = {MAX(r.min, fvco2_pd_min) , MIN(r.max * lmk05318_max_odiv(out->port), fvco2_pd_max)}; - const range_t r = lmk05318_get_freq_range(out); - const range_t ifreq = {MAX(r.min, fvco2_pd_min) , MIN(r.max * lmk05318_max_odiv(out->port), fvco2_pd_max)}; + if(ifreq.min > ifreq.max) + { + USDR_LOG("5318", USDR_LOG_ERROR, "port#%d freq:%d (-%d, +%d) is totally out of available range", + out->port, out->wanted.freq, out->wanted.freq_delta_minus, out->wanted.freq_delta_plus); + return -EINVAL; + } - if(ifreq.min > ifreq.max) - { - USDR_LOG("5318", USDR_LOG_ERROR, "port#%d freq:%d (-%d, +%d) is totally out of available range", - out->port, out->wanted.freq, out->wanted.freq_delta_minus, out->wanted.freq_delta_plus); - return -EINVAL; - } + const int pd_min = VCO_APLL2_MAX / ifreq.max; + const int pd_max = VCO_APLL2_MAX / ifreq.min; - const int pd_min = VCO_APLL2_MAX / ifreq.max; - const int pd_max = VCO_APLL2_MAX / ifreq.min; + out->pd_min = pd_min; + out->pd_max = pd_max; - out->pd_min = pd_min; - out->pd_max = pd_max; + USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d pre-OD freq range:[%" PRIu64", %" PRIu64"], PD:[%d, %d]", + out->port, ifreq.min, ifreq.max, pd_min, pd_max); + } - USDR_LOG("5318", USDR_LOG_DEBUG, "port:%d pre-OD freq range:[%" PRIu64", %" PRIu64"], PD:[%d, %d]", - out->port, ifreq.min, ifreq.max, pd_min, pd_max); + const uint64_t f_mid = (VCO_APLL2_MAX + VCO_APLL2_MIN) / 2; + res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, d); + if(res) + return res; } - const uint64_t f_mid = (VCO_APLL2_MAX + VCO_APLL2_MIN) / 2; - res = lmk05318_solver_helper(outs, cnt_to_solve, f_mid, d); - if(res) - return res; - -have_complete_solution: - //if ok - update the results qsort(_outs, n_outs, sizeof(lmk05318_out_config_t), lmk05318_comp_port); @@ -2272,7 +2269,7 @@ int lmk05318_solver(lmk05318_state_t* d, lmk05318_out_config_t* _outs, unsigned USDR_LOG("5318", is_freq_ok ? USDR_LOG_DEBUG : USDR_LOG_ERROR, "port:%d solved [OD:%" PRIu64 " freq:%.8f mux:%d(%s) fmt:%u(%s)] %s", out_dst->port, out_dst->result.out_div, out_dst->result.freq, out_dst->result.mux, - lmk05318_decode_mux(out_dst->result.mux), out_dst->wanted.type, lmk05318_decode_fmt_to_string(out_dst->wanted.type), + lmk05318_decode_mux((enum lmk05318_out_pll_sel_t)out_dst->result.mux), out_dst->wanted.type, lmk05318_decode_fmt_to_string(out_dst->wanted.type), is_freq_ok ? "**OK**" : "**BAD**"); } diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index 12c1e26d..a8ce8ae2 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -136,8 +136,8 @@ int lmx1204_read_status(lmx1204_state_t* st, lmx1204_stats_t* status) USDR_LOG("1204", USDR_LOG_DEBUG, "STATUS> Temp:%.2fC LOCK:%u(%s) VCO_SEL:%u(%s)", status->temperature, - status->lock_detect_status, lmx1204_decode_lock_status(status->lock_detect_status), - status->vco_sel, lmx1204_decode_vco_core(status->vco_sel)); + status->lock_detect_status, lmx1204_decode_lock_status((enum rb_ld_options)status->lock_detect_status), + status->vco_sel, lmx1204_decode_vco_core((enum rb_vco_sel_options)status->vco_sel)); return 0; } @@ -612,7 +612,7 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) st->sysref_div = div; USDR_LOG("1204", USDR_LOG_DEBUG, "[SYSREFCLK] SYSREFREQ:%" PRIu64 " SYSREF_MODE:%s(%u) SYSREFOUT:%.4f", - st->sysrefreq, lmx1204_decode_sysref_mode(st->sysref_mode), st->sysref_mode, st->sysrefout); + st->sysrefreq, lmx1204_decode_sysref_mode((enum sysref_mode_options)st->sysref_mode), st->sysref_mode, st->sysrefout); if(st->sysref_mode != SYSREF_MODE_REPEATER_REPEATER_MODE) { @@ -634,9 +634,9 @@ int lmx1204_solver(lmx1204_state_t* st, bool prec_mode, bool dry_run) USDR_LOG("1204", USDR_LOG_INFO, "SYSREFOUT%u:%.4f EN:%u", i, st->sysrefout, st->sysref_en && st->ch_en[0] && st->sysrefout_en[0]); } USDR_LOG("1204", USDR_LOG_INFO, "LOGICLKOUT :%.4f EN:%u FMT:%s", - st->logiclkout, st->ch_en[LMX1204_CH_LOGIC] && st->clkout_en[LMX1204_CH_LOGIC], lmx1204_decode_fmt(st->logiclkout_fmt)); + st->logiclkout, st->ch_en[LMX1204_CH_LOGIC] && st->clkout_en[LMX1204_CH_LOGIC], lmx1204_decode_fmt((enum logiclkout_fmt_options)st->logiclkout_fmt)); USDR_LOG("1204", USDR_LOG_INFO, "LOGICSYSREFOUT:%.4f EN:%u FMT:%s", - st->sysrefout, st->sysref_en && st->ch_en[LMX1204_CH_LOGIC] && st->sysrefout_en[LMX1204_CH_LOGIC], lmx1204_decode_fmt(st->logisysrefout_fmt)); + st->sysrefout, st->sysref_en && st->ch_en[LMX1204_CH_LOGIC] && st->sysrefout_en[LMX1204_CH_LOGIC], lmx1204_decode_fmt((enum logiclkout_fmt_options)st->logisysrefout_fmt)); USDR_LOG("1204", USDR_LOG_INFO, "--------------"); //registers diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 2017d8f5..cc6ea132 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -876,7 +876,7 @@ static int initialize_stream_rx_32(device_t* device, strdev->hw_pwr_mask = hw_chan_msk; strdev->pack_3x16 = pack_3x16; - USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "RX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%" PRIx64 " Pack3x16=%d\n", strdev->pkt_symbs, strdev->wire_bps, strdev->channels, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask, strdev->pack_3x16); *outu = strdev; @@ -1171,7 +1171,7 @@ static int initialize_stream_tx_32(device_t* device, strdev->hw_pwr_mask = pwr_hw_mask; strdev->pack_3x16 = pack_3x16; - USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%"PRIx64" Pack3x16=%d\n", + USDR_LL_LOG(dev, "DSTR", USDR_LOG_INFO, "TX: Samples=%d Bps=%dx%d WireBytes=%d HostBytes=%d Bursts=%d PwrMask=%" PRIx64 " Pack3x16=%d\n", strdev->pkt_symbs, strdev->wire_bps, strdev->channels, strdev->pkt_bytes, strdev->host_bytes, strdev->burst_count, strdev->hw_pwr_mask, strdev->pack_3x16); *outu = strdev; return 0; diff --git a/src/lib/port/CMakeLists.txt b/src/lib/port/CMakeLists.txt index 17e9d5a9..050f670d 100644 --- a/src/lib/port/CMakeLists.txt +++ b/src/lib/port/CMakeLists.txt @@ -11,6 +11,8 @@ set(USDR_PORT_LIB_FILES list(APPEND USDR_LIBRARY_FILES ${USDR_PORT_LIB_FILES}) set(USDR_LIBRARY_FILES ${USDR_LIBRARY_FILES} PARENT_SCOPE) -add_executable(test_fnmatch test_fnmatch.c portable_fnmatch.c) +if(NOT EMSCRIPTEN) + add_executable(test_fnmatch test_fnmatch.c portable_fnmatch.c) +endif() install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION include/usdr FILES_MATCHING PATTERN "*.h") diff --git a/src/lib/port/usdr_port.c b/src/lib/port/usdr_port.c index 02bd47d2..efa7b423 100644 --- a/src/lib/port/usdr_port.c +++ b/src/lib/port/usdr_port.c @@ -31,7 +31,11 @@ void* usdr_lib_sym(library_hdl_t h, const char* proc) library_hdl_t usdr_lib_load(const char* s) { - return dlopen(s, RTLD_LAZY | RTLD_DEEPBIND | RTLD_GLOBAL); + int mode = RTLD_LAZY | RTLD_GLOBAL; +#ifdef RTLD_DEEPBIND + mode |= RTLD_DEEPBIND; +#endif + return dlopen(s, mode); } void usdr_lib_close(library_hdl_t h) From d6e945b3f55201688e39b66b15a9835173698607 Mon Sep 17 00:00:00 2001 From: sergey Date: Mon, 9 Feb 2026 02:38:24 +0400 Subject: [PATCH 304/397] usdr_port: add asprintf/vasprintf for Windows environment --- src/lib/port/CMakeLists.txt | 3 +++ src/lib/port/usdr_port.c | 34 ++++++++++++++++++++++++++++++++++ src/lib/port/usdr_port.h | 9 +++++++++ 3 files changed, 46 insertions(+) diff --git a/src/lib/port/CMakeLists.txt b/src/lib/port/CMakeLists.txt index 050f670d..f3892428 100644 --- a/src/lib/port/CMakeLists.txt +++ b/src/lib/port/CMakeLists.txt @@ -13,6 +13,9 @@ set(USDR_LIBRARY_FILES ${USDR_LIBRARY_FILES} PARENT_SCOPE) if(NOT EMSCRIPTEN) add_executable(test_fnmatch test_fnmatch.c portable_fnmatch.c) + if(WIN32) + set_target_properties(test_fnmatch PROPERTIES WIN32_EXECUTABLE FALSE) + endif() endif() install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION include/usdr FILES_MATCHING PATTERN "*.h") diff --git a/src/lib/port/usdr_port.c b/src/lib/port/usdr_port.c index efa7b423..8f669fe7 100644 --- a/src/lib/port/usdr_port.c +++ b/src/lib/port/usdr_port.c @@ -27,6 +27,40 @@ void* usdr_lib_sym(library_hdl_t h, const char* proc) return GetProcAddress(h, proc); } + +int vasprintf(char **strp, const char *fmt, va_list ap) +{ + int len = _vscprintf(fmt, ap); + if (len == -1) { + return -1; + } + + size_t size = (size_t)len + 1; + char *str = malloc(size); + if (!str) { + return -1; + } + + int r = _vsprintf_s_l(str, len + 1, fmt, NULL, ap); + if (r == -1) { + free(str); + return -1; + } + + *strp = str; + return r; +} + +int asprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int r = vasprintf(strp, fmt, ap); + va_end(ap); + return r; +} + + #else library_hdl_t usdr_lib_load(const char* s) diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index cd78a02a..ea55e616 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -8,6 +8,7 @@ #ifdef _WIN32 #include +#include #endif #include @@ -24,6 +25,8 @@ #include #include #include + +#include #endif #include #include @@ -96,9 +99,15 @@ library_hdl_t usdr_lib_load(const char* s); void usdr_lib_close(library_hdl_t h); void* usdr_lib_sym(library_hdl_t h, const char* proc); +#ifdef _WIN32 +int vasprintf(char **strp, const char *fmt, va_list ap) __attribute__ ((format (printf, 2, 0))); +int asprintf(char **strp, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); + +#endif #define CACHE_SIZE 64 + #ifdef __cplusplus }; #endif From be4159dc366c8e59e957078524a18ddd0e17eb80 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 17 Feb 2026 02:14:49 +0400 Subject: [PATCH 305/397] xlnx validate file CRC before being written --- src/lib/ipblks/xlnx_bitstream.c | 149 ++++++++++++++++++++++++-------- src/lib/ipblks/xlnx_bitstream.h | 8 ++ src/tools/usdr_flash.c | 12 ++- 3 files changed, 132 insertions(+), 37 deletions(-) diff --git a/src/lib/ipblks/xlnx_bitstream.c b/src/lib/ipblks/xlnx_bitstream.c index e6b55c9b..fc09dc77 100644 --- a/src/lib/ipblks/xlnx_bitstream.c +++ b/src/lib/ipblks/xlnx_bitstream.c @@ -4,6 +4,7 @@ #include "xlnx_bitstream.h" #include #include +#include enum { W_DUMMY = 0xffffffff, @@ -13,14 +14,65 @@ enum { W_NOP = 0x20000000, }; -int xlnx_btstrm_parse_header(const uint32_t* mem, unsigned len, xlnx_image_params_t* stat) +enum { + XLNX_REG_CRC = 0x00, + XLNX_REG_FDRI = 0x02, + XLNX_REG_CMD = 0x04, + XLNX_REG_IDCODE = 0x0c, + XLNX_REG_AXSS = 0x0d, + XLNX_REG_WBSTAR = 0x10, +}; + +enum { + XLNX_CMD_RCRC = 0x07, + XLNX_CMD_IPROG = 0x0f, +}; + +#define CRC32C_REFLECTED_POLY 0x82F63B78u +static inline uint32_t xlnx_btstrm_crc32_pushbit(uint32_t crc, uint32_t bit) +{ + uint32_t mix = (crc ^ bit) & 1; + crc >>= 1; + if (mix) { + crc ^= CRC32C_REFLECTED_POLY; + } + + return crc; +} + +static uint32_t xlnx_btstrm_crc32_regw(uint32_t crc, uint16_t reg, uint32_t data) +{ + switch (reg) { + case 0x16: // BOOTSTS + case 0x0F: // CSOB (undocumented) + case 0x12: // unknown, skipped + case 0x14: // unknown, skipped + case 0x15: // unknown, skipped + return crc; + } + + for (unsigned i = 0; i < 32; i++) { + crc = xlnx_btstrm_crc32_pushbit(crc, (data >> i) & 1); + } + + for (unsigned i = 0; i < 5; i++) { + crc = xlnx_btstrm_crc32_pushbit(crc, (reg >> i) & 1); + } + + return crc; +} + +int xlnx_btstrm_parse_header_ex(const uint32_t* mem, + unsigned len, + xlnx_image_params_t* stat, + unsigned flags) { - uint16_t blk_param; - uint16_t blk_pcount; uint32_t w; unsigned ptr = 0; bool devid_found = false; bool wbstar_found = false; + uint32_t stream_crc = 0; + uint32_t crc_word_cnt = 0; memset(stat, 0, sizeof(*stat)); @@ -51,59 +103,86 @@ int xlnx_btstrm_parse_header(const uint32_t* mem, unsigned len, xlnx_image_param if (!bo_seen || !bw_seen) return -EINVAL; - // Block FSM - bool in_param = false; - bool in_devid = false; - bool in_wbstar = false; - bool in_icmd = false; - bool in_axss = false; + uint16_t last_reg = XLNX_REG_CRC; for (; ptr < len; ptr++) { w = be32toh(mem[ptr]); - if (in_param) { - --blk_pcount; + uint8_t ptype = (w >> 29) & 0x7; + uint8_t op; + uint16_t reg; + uint32_t count; + + if (ptype == 1) { + op = (w >> 27) & 0x3; + reg = (w >> 13) & 0x3fff; + count = w & 0x7ff; + last_reg = reg; + } else if (ptype == 2) { + op = (w >> 27) & 0x3; + reg = last_reg; + count = w & 0x7ffffff; + } else { + USDR_LOG("BSTR", USDR_LOG_DEBUG, "Unrecognised WORD: n=%d w=%08x\n", ptr, w); + return -EINVAL; + } - if (blk_pcount == 0) - in_param = 0; + if (op != 2 || count == 0) { + continue; + } + + for (unsigned i = 0; i < count; i++) { + if (++ptr >= len) + return -EINVAL; - if (in_devid) { + w = be32toh(mem[ptr]); + if (reg == XLNX_REG_IDCODE) { stat->devid = w; devid_found = true; - } else if (in_wbstar) { + } else if (reg == XLNX_REG_WBSTAR) { stat->wbstar = w; wbstar_found = true; - } else if (in_icmd) { - if (w == 0x0000000f) + } else if (reg == XLNX_REG_CMD) { + if (w == XLNX_CMD_IPROG) stat->iprog = true; - } else if (in_axss) { + } else if (reg == XLNX_REG_AXSS) { stat->usr_access2 = w; } - continue; - } - if (w == W_NOP) - continue; + if (flags & XLNX_BSTRM_PARSE_F_CRC_CHECK) { + if (reg == XLNX_REG_CRC) { + crc_word_cnt++; - if (w >> 24 == 0x30) { - blk_param = (w >> 8) & 0xffff; - blk_pcount = w & 0xff; + USDR_LOG("BSTR", USDR_LOG_DEBUG, "CRC BLOCK=%d FILE=%8x STR=%8x\n", crc_word_cnt, w, stream_crc); + if (w != stream_crc) { + USDR_LOG("BSTR", USDR_LOG_ERROR, "Bitstream CRC mismatch: block=%d stream=%08x infile=%08x\n", + crc_word_cnt, stream_crc, w); + return -EBADMSG; + } - if (blk_pcount > 0) { - in_param = true; - in_devid = (blk_param == 0x0180); - in_wbstar = (blk_param == 0x0200); - in_icmd = (blk_param == 0x0080); - in_axss = (blk_param == 0x01A0); + stream_crc = 0; + } else if (reg == XLNX_REG_CMD && w == XLNX_CMD_RCRC) { + stream_crc = 0; + } else { + stream_crc = xlnx_btstrm_crc32_regw(stream_crc, reg, w); + } } - continue; } - - USDR_LOG("BSTR", USDR_LOG_DEBUG, "Unrecognised WORD: n=%d w=%08x\n", ptr, w); - return -EINVAL; } + if (flags & XLNX_BSTRM_PARSE_F_CRC_CHECK) { + if (crc_word_cnt == 0) { + USDR_LOG("BSTR", USDR_LOG_ERROR, "Bitstream no CRC blocks found!\n"); + return -EBADMSG; + } + USDR_LOG("BSTR", USDR_LOG_INFO, "Bitstream CRC %d block(s) validated\n", crc_word_cnt); + } return devid_found && wbstar_found ? 0 : -ENOENT; } +int xlnx_btstrm_parse_header(const uint32_t* mem, unsigned len, xlnx_image_params_t* stat) +{ + return xlnx_btstrm_parse_header_ex(mem, len, stat, 0); +} + int xlnx_btstrm_iprgcheck( const xlnx_image_params_t* internal_golden, const xlnx_image_params_t* newimg, diff --git a/src/lib/ipblks/xlnx_bitstream.h b/src/lib/ipblks/xlnx_bitstream.h index a2253afb..1f2fc1de 100644 --- a/src/lib/ipblks/xlnx_bitstream.h +++ b/src/lib/ipblks/xlnx_bitstream.h @@ -41,7 +41,15 @@ struct xlnx_image_params { }; typedef struct xlnx_image_params xlnx_image_params_t; +enum xlnx_btstrm_parse_flags { + XLNX_BSTRM_PARSE_F_CRC_CHECK = 1 << 0, +}; + int xlnx_btstrm_parse_header(const uint32_t* mem, unsigned len, xlnx_image_params_t* stat); +int xlnx_btstrm_parse_header_ex(const uint32_t* mem, + unsigned len, + xlnx_image_params_t* stat, + unsigned flags); int xlnx_btstrm_iprgcheck( const xlnx_image_params_t* internal_golden, const xlnx_image_params_t* newimg, diff --git a/src/tools/usdr_flash.c b/src/tools/usdr_flash.c index eb9f694e..46872074 100644 --- a/src/tools/usdr_flash.c +++ b/src/tools/usdr_flash.c @@ -51,6 +51,7 @@ int main(int argc, char** argv) bool verbose = false; uint32_t curfwid; bool no_device = false; + bool crc_check = true; uint64_t master_offset = MASTER_IMAGE_OFF; uint64_t qspi_base = 10; @@ -60,7 +61,7 @@ int main(int argc, char** argv) usdrlog_setlevel(NULL, USDR_LOG_WARNING); usdrlog_enablecolorize(NULL); - while ((opt = getopt(argc, argv, "U:l:i:w:r:FGCv")) != -1) { + while ((opt = getopt(argc, argv, "U:l:i:w:r:FGCvk")) != -1) { switch (opt) { case 'U': busname = optarg; @@ -92,6 +93,9 @@ int main(int argc, char** argv) case 'v': verbose = true; break; + case 'k': + crc_check = false; + break; default: fprintf(stderr, "Usage: %s [-U device_bus] [-l loglevel] [-r filename | -w filename | -i filename] [-G]\n", argv[0]); @@ -215,7 +219,11 @@ int main(int argc, char** argv) } fclose(w); - res = xlnx_btstrm_parse_header((const uint32_t* )outa, 256/4, &file); + // res = xlnx_btstrm_parse_header((const uint32_t* )outa, 256/4, &file); + res = xlnx_btstrm_parse_header_ex((const uint32_t* )outa, + crc_check ? (total_length / 4) : (256 / 4), + &file, + crc_check ? XLNX_BSTRM_PARSE_F_CRC_CHECK : 0); if (res) { fprintf(stderr, "It looks like the file is corrupted! res=%d\n", res); return 4; From e614b5e24d0b1a434944c00f87e27deab2869b5f Mon Sep 17 00:00:00 2001 From: sergey Date: Tue, 17 Feb 2026 14:45:53 +0400 Subject: [PATCH 306/397] Add option to blank master firmware --- src/lib/ipblks/xlnx_bitstream.c | 13 +++++++- src/lib/ipblks/xlnx_bitstream.h | 1 + src/tools/usdr_flash.c | 55 ++++++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/lib/ipblks/xlnx_bitstream.c b/src/lib/ipblks/xlnx_bitstream.c index fc09dc77..8c00110d 100644 --- a/src/lib/ipblks/xlnx_bitstream.c +++ b/src/lib/ipblks/xlnx_bitstream.c @@ -21,6 +21,7 @@ enum { XLNX_REG_IDCODE = 0x0c, XLNX_REG_AXSS = 0x0d, XLNX_REG_WBSTAR = 0x10, + XLNX_REG_USERID = 0x19, }; enum { @@ -130,8 +131,12 @@ int xlnx_btstrm_parse_header_ex(const uint32_t* mem, } for (unsigned i = 0; i < count; i++) { - if (++ptr >= len) + if (++ptr >= len) { + if (flags & XLNX_BSTRM_ALLOW_CROP) + break; + return -EINVAL; + } w = be32toh(mem[ptr]); if (reg == XLNX_REG_IDCODE) { @@ -145,6 +150,12 @@ int xlnx_btstrm_parse_header_ex(const uint32_t* mem, stat->iprog = true; } else if (reg == XLNX_REG_AXSS) { stat->usr_access2 = w; + } else if (reg == XLNX_REG_USERID) { + USDR_LOG("BSTR", USDR_LOG_NOTE, "UserID = %x\n", w); + } + + if (count == 1 && ptype == 1 && reg != 1 && reg != 4) { + USDR_LOG("BSTR", USDR_LOG_NOTE, "Rgister %x: %x\n", reg, w); } if (flags & XLNX_BSTRM_PARSE_F_CRC_CHECK) { diff --git a/src/lib/ipblks/xlnx_bitstream.h b/src/lib/ipblks/xlnx_bitstream.h index 1f2fc1de..f3349a8a 100644 --- a/src/lib/ipblks/xlnx_bitstream.h +++ b/src/lib/ipblks/xlnx_bitstream.h @@ -43,6 +43,7 @@ typedef struct xlnx_image_params xlnx_image_params_t; enum xlnx_btstrm_parse_flags { XLNX_BSTRM_PARSE_F_CRC_CHECK = 1 << 0, + XLNX_BSTRM_ALLOW_CROP = 1 << 1, }; int xlnx_btstrm_parse_header(const uint32_t* mem, unsigned len, xlnx_image_params_t* stat); diff --git a/src/tools/usdr_flash.c b/src/tools/usdr_flash.c index 46872074..95b7ca66 100644 --- a/src/tools/usdr_flash.c +++ b/src/tools/usdr_flash.c @@ -36,6 +36,7 @@ enum flash_action { ACTION_READBACK, ACTION_WRITE, ACTION_INFO, + ACTION_ERASE_MASTER, }; int main(int argc, char** argv) @@ -61,7 +62,7 @@ int main(int argc, char** argv) usdrlog_setlevel(NULL, USDR_LOG_WARNING); usdrlog_enablecolorize(NULL); - while ((opt = getopt(argc, argv, "U:l:i:w:r:FGCvk")) != -1) { + while ((opt = getopt(argc, argv, "U:l:i:w:r:FGCvkE")) != -1) { switch (opt) { case 'U': busname = optarg; @@ -96,6 +97,9 @@ int main(int argc, char** argv) case 'k': crc_check = false; break; + case 'E': + rdwr = ACTION_ERASE_MASTER; + break; default: fprintf(stderr, "Usage: %s [-U device_bus] [-l loglevel] [-r filename | -w filename | -i filename] [-G]\n", argv[0]); @@ -172,12 +176,12 @@ int main(int argc, char** argv) return 4; } - res = (no_device) ? 0 : xlnx_btstrm_parse_header((const uint32_t* )outb, 256/4, &image); + res = (no_device) ? 0 : xlnx_btstrm_parse_header_ex((const uint32_t* )outb, 256/4, &image, XLNX_BSTRM_ALLOW_CROP); if (res) { fprintf(stderr, "It looks like the FPGA G image is corrupted! res=%d\n", res); return 4; } - res = (no_device) ? 0 : xlnx_btstrm_parse_header((const uint32_t* )(outb + 256), 256/4, &image_master); + res = (no_device) ? 0 : xlnx_btstrm_parse_header_ex((const uint32_t* )(outb + 256), 256/4, &image_master, XLNX_BSTRM_ALLOW_CROP); if (res) { fprintf(stderr, "It looks like the FPGA M image is corrupted! res=%d\n", res); } else { @@ -223,7 +227,7 @@ int main(int argc, char** argv) res = xlnx_btstrm_parse_header_ex((const uint32_t* )outa, crc_check ? (total_length / 4) : (256 / 4), &file, - crc_check ? XLNX_BSTRM_PARSE_F_CRC_CHECK : 0); + crc_check ? XLNX_BSTRM_PARSE_F_CRC_CHECK : XLNX_BSTRM_ALLOW_CROP); if (res) { fprintf(stderr, "It looks like the file is corrupted! res=%d\n", res); return 4; @@ -309,6 +313,49 @@ int main(int argc, char** argv) } } + if (rdwr == ACTION_ERASE_MASTER) { + char reply[100]; + char* term; + + if (!mp) { + fprintf(stderr, "Master image is not detected!\n\n"); + } + + fprintf(stderr, " ===========================================\n"); + fprintf(stderr, " == YOU'RE GOING TO BLANK MASTER FIRMWARE ==\n"); + fprintf(stderr, " ===========================================\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Type YES if you know what're doing: "); + + if (fgets(reply, sizeof(reply), stdin) == NULL) + return 0; + + term = strstr(reply, "\n"); + if (term) { + *term = 0; + } + + if (strcmp(reply, "YES") != 0) + return 0; + + if (image.wbstar == 0) { + fprintf(stderr, "No Master support detected: WBSTAR is 0!\n"); + return 7; + } + if (image.wbstar != master_offset) { + fprintf(stderr, "Master trampoline mismatches: WBSTAR is %08x != %08x in the software!\n", + image.wbstar, master_offset); + return 8; + } + + fprintf(stderr, "Blanking flash starting from %08x...\n", image.wbstar); + res = espi_flash_erase(dev, 0, qspi_base, 65536, master_offset); + if (res) { + fprintf(stderr, "Failed to blank flash header! res=%d", res); + return 4; + } + } + if (rdwr == ACTION_WRITE || rdwr == ACTION_READBACK) { fprintf(stderr, "Reading %d bytes!\n", total_length); res = espi_flash_read(dev, 0, qspi_base, 512, off, total_length, outb); From ebb5708d24b2b6b3d65382d80e8e73691664b201 Mon Sep 17 00:00:00 2001 From: sergey Date: Wed, 18 Feb 2026 15:16:51 +0400 Subject: [PATCH 307/397] fix bitstream parsing constants --- src/lib/ipblks/xlnx_bitstream.c | 44 +++++++++++++++++++++++++-------- src/tools/usdr_flash.c | 2 +- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/lib/ipblks/xlnx_bitstream.c b/src/lib/ipblks/xlnx_bitstream.c index 8c00110d..bfd40918 100644 --- a/src/lib/ipblks/xlnx_bitstream.c +++ b/src/lib/ipblks/xlnx_bitstream.c @@ -16,12 +16,37 @@ enum { enum { XLNX_REG_CRC = 0x00, + XLNX_REG_FAR = 0x01, XLNX_REG_FDRI = 0x02, + XLNX_REG_FDRO = 0x03, XLNX_REG_CMD = 0x04, + XLNX_REG_CTL0 = 0x05, + XLNX_REG_MASK = 0x06, + XLNX_REG_STAT = 0x07, + XLNX_REG_LOUT = 0x08, + XLNX_REG_COR0 = 0x09, + XLNX_REG_MFWR = 0x0a, + XLNX_REG_CBC = 0x0b, XLNX_REG_IDCODE = 0x0c, XLNX_REG_AXSS = 0x0d, + XLNX_REG_COR1 = 0x0e, + XLNX_REG_CSOB = 0x0f, XLNX_REG_WBSTAR = 0x10, - XLNX_REG_USERID = 0x19, + XLNX_REG_TIMER = 0x11, + XLNX_REG_UNK12 = 0x12, + XLNX_REG_RBCRC_SW = 0x13, + XLNX_REG_UNK14 = 0x14, + XLNX_REG_UNK15 = 0x15, + XLNX_REG_BOOTSTS = 0x16, + XLNX_REG_UNK17 = 0x17, + XLNX_REG_CTL1 = 0x18, + XLNX_REG_UNK19 = 0x19, + XLNX_REG_UNK1A = 0x1a, + XLNX_REG_UNK1B = 0x1b, + XLNX_REG_UNK1C = 0x1c, + XLNX_REG_UNK1D = 0x1d, + XLNX_REG_UNK1E = 0x1e, + XLNX_REG_BSPI = 0x1f }; enum { @@ -43,12 +68,13 @@ static inline uint32_t xlnx_btstrm_crc32_pushbit(uint32_t crc, uint32_t bit) static uint32_t xlnx_btstrm_crc32_regw(uint32_t crc, uint16_t reg, uint32_t data) { + // Not sure which ones to skip, but so far it works well switch (reg) { - case 0x16: // BOOTSTS - case 0x0F: // CSOB (undocumented) - case 0x12: // unknown, skipped - case 0x14: // unknown, skipped - case 0x15: // unknown, skipped + case XLNX_REG_BOOTSTS: + case XLNX_REG_CSOB: + case XLNX_REG_UNK12: + case XLNX_REG_UNK14: + case XLNX_REG_UNK15: return crc; } @@ -150,11 +176,9 @@ int xlnx_btstrm_parse_header_ex(const uint32_t* mem, stat->iprog = true; } else if (reg == XLNX_REG_AXSS) { stat->usr_access2 = w; - } else if (reg == XLNX_REG_USERID) { - USDR_LOG("BSTR", USDR_LOG_NOTE, "UserID = %x\n", w); } - if (count == 1 && ptype == 1 && reg != 1 && reg != 4) { + if (count == 1 && ptype == 1 && reg != 1 && reg != XLNX_REG_CMD) { USDR_LOG("BSTR", USDR_LOG_NOTE, "Rgister %x: %x\n", reg, w); } @@ -162,7 +186,7 @@ int xlnx_btstrm_parse_header_ex(const uint32_t* mem, if (reg == XLNX_REG_CRC) { crc_word_cnt++; - USDR_LOG("BSTR", USDR_LOG_DEBUG, "CRC BLOCK=%d FILE=%8x STR=%8x\n", crc_word_cnt, w, stream_crc); + USDR_LOG("BSTR", USDR_LOG_NOTE, "CRC BLOCK=%d BIN=%8x STR=%8x\n", crc_word_cnt, w, stream_crc); if (w != stream_crc) { USDR_LOG("BSTR", USDR_LOG_ERROR, "Bitstream CRC mismatch: block=%d stream=%08x infile=%08x\n", crc_word_cnt, stream_crc, w); diff --git a/src/tools/usdr_flash.c b/src/tools/usdr_flash.c index 95b7ca66..c6cc990d 100644 --- a/src/tools/usdr_flash.c +++ b/src/tools/usdr_flash.c @@ -344,7 +344,7 @@ int main(int argc, char** argv) } if (image.wbstar != master_offset) { fprintf(stderr, "Master trampoline mismatches: WBSTAR is %08x != %08x in the software!\n", - image.wbstar, master_offset); + image.wbstar, (unsigned)master_offset); return 8; } From c1ff7b7e2a8917bd240b70c716880efa1abcd663 Mon Sep 17 00:00:00 2001 From: sergey Date: Wed, 18 Feb 2026 15:19:47 +0400 Subject: [PATCH 308/397] fix device vfs for string objects and links --- src/lib/device/device.c | 37 +++++++++++++++++++--------- src/lib/device/device.h | 16 ++++++++++++ src/lib/device/device_vfs.c | 49 +++++++++++++++++++++++++++++++++++-- src/lib/device/device_vfs.h | 22 +++++++++++------ 4 files changed, 103 insertions(+), 21 deletions(-) diff --git a/src/lib/device/device.c b/src/lib/device/device.c index 7e9f1acc..78bcd1d5 100644 --- a/src/lib/device/device.c +++ b/src/lib/device/device.c @@ -133,7 +133,7 @@ int usdr_device_vfs_filter(pdevice_t dev, const char* filter, unsigned max_objec unsigned i, cnt; for (i = 0, cnt = 0; cnt < max_objects && i < root->eparam[0]; i++) { - if (fnmatch(filter, nodes[i].full_path, FNM_NOESCAPE) == 0) { + if (fnmatch(filter, nodes[i].full_path, FNM_NOESCAPE) == 0 && !(nodes[i].flags & VFS_FLAG_HIDDEN)) { objs[cnt].fullpath = nodes[i].full_path; cnt++; } @@ -144,18 +144,11 @@ int usdr_device_vfs_filter(pdevice_t dev, const char* filter, unsigned max_objec int _usdr_device_vfs_get_by_path(device_t *base, const char* filter, pusdr_vfs_obj_t *obj) { - vfs_object_t *root = &base->rootfs; - vfs_object_t *nodes = (vfs_object_t *)root->data.obj; - - for (unsigned i = 0; i < base->rootfs.eparam[0]; i++) { - if (fnmatch(filter, nodes[i].full_path, FNM_NOESCAPE) == 0) { - *obj = &nodes[i]; - return 0; - } + int res = vfs_get_by_path(&base->rootfs, filter, obj); + if (res) { + USDR_LOG("UDEV", USDR_LOG_NOTE, "vfs '%s' not found!\n", filter); } - - USDR_LOG("UDEV", USDR_LOG_NOTE, "vfs '%s' not found!\n", filter); - return -ENOENT; + return res; } @@ -214,6 +207,26 @@ int usdr_vfs_obj_param_init_array_param(pdevice_t dev, return 0; } +int usdr_vfs_obj_link_init_array_param(pdevice_t dev, + void *param, + const usdr_dev_link_t* links, + unsigned count) +{ + unsigned i; + int res; + + for (i = 0; i < count; i++) { + res = vfs_add_obj_link(&dev->rootfs, + links[i].fullpath, + param == NULL ? dev : param, + links[i].linkpath); + if (res) + return res; + } + + return 0; +} + static int _usdr_device_vfs_concat(pdevice_t dev, const char* path, const char* entity, unsigned max, char* out) { snprintf(out, max, "%s/%s", path, entity); diff --git a/src/lib/device/device.h b/src/lib/device/device.h index 4b1562cb..1471179a 100644 --- a/src/lib/device/device.h +++ b/src/lib/device/device.h @@ -150,5 +150,21 @@ static inline int usdr_vfs_obj_param_init_array(pdevice_t dev, return usdr_vfs_obj_param_init_array_param(dev, NULL, params, count); } +struct usdr_dev_link { + const char* fullpath; + const char* linkpath; +}; +typedef struct usdr_dev_link usdr_dev_link_t; + +int usdr_vfs_obj_link_init_array_param(pdevice_t dev, + void *param, + const usdr_dev_link_t* links, + unsigned count); + +static inline int usdr_vfs_obj_link_init_array(pdevice_t dev, + const usdr_dev_link_t* links, + unsigned count) { + return usdr_vfs_obj_link_init_array_param(dev, NULL, links, count); +} #endif diff --git a/src/lib/device/device_vfs.c b/src/lib/device/device_vfs.c index b705a419..e4961786 100644 --- a/src/lib/device/device_vfs.c +++ b/src/lib/device/device_vfs.c @@ -2,11 +2,12 @@ // SPDX-License-Identifier: MIT #include "device_vfs.h" +#include #include #include #include #include -#include +#include #define STD_FOLDER_QTY 16 @@ -23,7 +24,7 @@ enum { int vfs_folder_init(vfs_object_t* o, const char* path, void* user) { o->type = VFST_FOLDER; - o->amask = 0; + o->flags = 0; o->eparam[RP_USED] = 0; o->eparam[RP_TOTAL] = STD_FOLDER_QTY; o->eparam[RP_UNUSED] = 0; @@ -42,12 +43,29 @@ int vfs_folder_init(vfs_object_t* o, const char* path, void* user) void vfs_folder_destroy(vfs_object_t* o) { + assert(o->type == VFST_FOLDER); + o->eparam[RP_USED] = 0; o->eparam[RP_TOTAL] = 0; + free(o->data.obj); o->data.obj = NULL; } +int vfs_get_by_path(vfs_object_t* root, const char* path, vfs_object_t** obj) +{ + vfs_object_t *nodes = (vfs_object_t *)root->data.obj; + + for (unsigned i = 0; i < root->eparam[RP_USED]; i++) { + if (fnmatch(path, nodes[i].full_path, FNM_NOESCAPE) == 0) { + *obj = &nodes[i]; + return 0; + } + } + + return -ENOENT; +} + static int _vfs_reserve(vfs_object_t* root, unsigned extra) { if (root->type != VFST_FOLDER) { @@ -244,3 +262,30 @@ int vfs_add_obj_i64(vfs_object_t* root, const char* fullpath, void* obj, uint64_ return 0; } + +int vfs_add_obj_link(vfs_object_t* root, const char* fullpath, void* obj, const char* link) +{ + vfs_object_t* no; + vfs_object_t* lnk_obj; + int res = vfs_get_by_path(root, link, &lnk_obj); + if (res) + return res; + if (lnk_obj->type == VFST_FOLDER) + return -EINVAL; + + // Save found object links, since _vfs_alloc_object may realloc the pool and lnk_obj will be invalid + struct vfs_ops orig_ops = lnk_obj->ops; + union vfs_variant orig_data = lnk_obj->data; + + res = _vfs_alloc_object(root, &no, lnk_obj->type, fullpath); + if (res) + return res; + + // Mark that'a a link + no->flags = VFS_FLAG_LINK; + no->object = obj; + no->data = orig_data; + no->ops = orig_ops; + + return 0; +} diff --git a/src/lib/device/device_vfs.h b/src/lib/device/device_vfs.h index de810624..108916b6 100644 --- a/src/lib/device/device_vfs.h +++ b/src/lib/device/device_vfs.h @@ -7,7 +7,6 @@ #include enum vfs_type { - VFST_LINK = 'l', VFST_FOLDER = 'f', VFST_I64 = 'i', @@ -47,10 +46,14 @@ struct vfs_ops { vfs_get_ai64_func_t gai64; }; +enum vfs_flags { + VFS_FLAG_LINK = 1, + VFS_FLAG_HIDDEN = 2, /* skip when iterating */ +}; struct vfs_object { uint8_t type; - uint8_t amask; + uint8_t flags; uint16_t eparam[3]; // Object specific paramenets void* object; // User associated object with the vfs @@ -62,16 +65,20 @@ struct vfs_object { typedef struct vfs_object vfs_object_t; int vfs_folder_init(vfs_object_t* o, const char* path, void* user); + +int vfs_get_by_path(vfs_object_t* o, const char* path, vfs_object_t** obj); + void vfs_folder_destroy(vfs_object_t* o); struct vfs_constant_i64 { const char* fullpath; uint64_t value; }; +typedef struct vfs_constant_i64 vfs_constant_i64_t; -int vfs_add_const_i64_vec(vfs_object_t* root, const struct vfs_constant_i64* params, unsigned count); +int vfs_add_const_i64_vec(vfs_object_t* root, const vfs_constant_i64_t* params, unsigned count); -static inline int vfs_add_const_i64(vfs_object_t* root, const struct vfs_constant_i64* params) { +static inline int vfs_add_const_i64(vfs_object_t* root, vfs_constant_i64_t* params) { return vfs_add_const_i64_vec(root, params, 1); } @@ -79,15 +86,16 @@ struct vfs_constant_str { const char* fullpath; const char* value; }; +typedef struct vfs_constant_str vfs_constant_str_t; -int vfs_add_const_str_vec(vfs_object_t* root, const struct vfs_constant_str* params, unsigned count); +int vfs_add_const_str_vec(vfs_object_t* root, const vfs_constant_str_t* params, unsigned count); -static inline int vfs_add_const_str(vfs_object_t* root, const struct vfs_constant_str* params) { +static inline int vfs_add_const_str(vfs_object_t* root, vfs_constant_str_t* params) { return vfs_add_const_str_vec(root, params, 1); } int vfs_add_obj_i64(vfs_object_t* root, const char* fullpath, void* obj, uint64_t defval, vfs_set_i64_func_t fs, vfs_get_i64_func_t fg); - +int vfs_add_obj_link(vfs_object_t* root, const char* fullpath, void* obj, const char* link); #endif From 47448d8a192fa35633f2cc207233b804570301fa Mon Sep 17 00:00:00 2001 From: sergey Date: Wed, 18 Feb 2026 15:30:49 +0400 Subject: [PATCH 309/397] si5332 improve spurs --- src/lib/hw/si5332/si5332.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/lib/hw/si5332/si5332.c b/src/lib/hw/si5332/si5332.c index 0c55a760..d03664a7 100644 --- a/src/lib/hw/si5332/si5332.c +++ b/src/lib/hw/si5332/si5332.c @@ -562,6 +562,14 @@ int si5332_set_layout(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, unsigned idpa_den = 32767; unsigned idpa_res = (uint64_t)idpa_den * idpa_frac / pllfreq; + unsigned error; + for (idpa_den = 2; idpa_den < 32767; idpa_den++) { + error = (idpa_den * idpa_frac) % pllfreq; + if (error == 0) + break; + } + idpa_res = (uint64_t)idpa_den * idpa_frac / pllfreq; + unsigned pll_freq_div = 0; bool jdiv = false; @@ -577,20 +585,9 @@ int si5332_set_layout(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, if (vcofreq) { *vcofreq = vco; } - // TODO alternative PLL ref - // if (altref) { - // pll_freq_div = (vco + 41000000) / 41000000; - // *altref = pll_freq_div; - // } - - USDR_LOG("5332", USDR_LOG_INFO, "VCO=%u IDPA_INTG=%u IDPA_RES=%u HSDIV=%u ODIV=%u JDIV=%d MXLO=%u\n", - vco, idpa_intg, idpa_res, hsdiv, odiv, jdiv, vco / lodiv); - - // terms of an a + b/c desired divider settingmust be processed into - //IDPA_INTG, ID-PA_RES, and IDPA_DEN register - //terms.intg =floor(((a*c+b)*128/c) - 512). - //res = mod(b*128, c) + USDR_LOG("5332", USDR_LOG_INFO, "VCO=%u IDPA_INTG=%u IDPA_RES/DEV=%u/%u HSDIV=%u ODIV=%u JDIV=%d MXLO=%u OLD=%d\n", + vco, idpa_intg, idpa_res, idpa_den, hsdiv, odiv, jdiv, vco / lodiv, old); // slew 0 -- fastest ; 3 -- slowest const uint8_t program_regs_init[] = { @@ -604,7 +601,7 @@ int si5332_set_layout(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, IDPA_DEN_L, idpa_den >> 8, PDIV_DIV, prescaler, //Prescaler - PLL_MODE, (pllfreq > 30e6) ? 11 : 4, // 4 - 500kHz | 7 - 175khz + PLL_MODE, (pllfreq > 30e6) ? 8 : 4, // 4 - 500kHz | 7 - 175khz HSDIV0A_DIV, hsdiv, HSDIV0B_DIV, hsdiv, @@ -612,8 +609,9 @@ int si5332_set_layout(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, HSDIV1A_DIV, pll_freq_div, HSDIV2A_DIV, pll_freq_div, - old ? OUT0_CMOS_SLEW : OUT1_CMOS_SLEW, (nfo->out > 110e6) ? 1 : (nfo->out > 50e6) ? 1 : 2, - OUT2_CMOS_SLEW, (nfo->out > 110e6) ? 1 : (nfo->out > 50e6) ? 1 : 2, + + old ? OUT0_CMOS_SLEW : OUT1_CMOS_SLEW, (nfo->out > 110e6) ? 0 : (nfo->out > 50e6) ? 1 : (nfo->out > 25e6) ? 2 : 3, + OUT2_CMOS_SLEW, (nfo->out > 110e6) ? 0 : (nfo->out > 50e6) ? 1 : (nfo->out > 25e6) ? 2 : 3, old ? OUT0_DIV : OUT1_DIV, odiv, OUT2_DIV, odiv, From c73c3b7b828e2c27a6a5cb7836ae62a5326517a1 Mon Sep 17 00:00:00 2001 From: sergey Date: Wed, 18 Feb 2026 15:31:42 +0400 Subject: [PATCH 310/397] Add ip2corr for lms6 --- src/lib/hw/lms6002d/lms6002d.c | 10 ++++++++++ src/lib/hw/lms6002d/lms6002d.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/lib/hw/lms6002d/lms6002d.c b/src/lib/hw/lms6002d/lms6002d.c index fdc0e767..795d26bf 100644 --- a/src/lib/hw/lms6002d/lms6002d.c +++ b/src/lib/hw/lms6002d/lms6002d.c @@ -860,3 +860,13 @@ int lms6002d_set_tia_rfb(lms6002d_state_t* obj, uint8_t value) }; return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); } + +int lms6002d_set_rxfe_ip2corr(lms6002d_state_t* obj, int8_t i, int8_t q) +{ + uint16_t regs[] = { + MAKE_LMS6002D_RFE_XLD_IP2I(0, i), + MAKE_LMS6002D_RFE_IP2Q(q), + }; + return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); +} + diff --git a/src/lib/hw/lms6002d/lms6002d.h b/src/lib/hw/lms6002d/lms6002d.h index a8cf1898..89263fa1 100644 --- a/src/lib/hw/lms6002d/lms6002d.h +++ b/src/lib/hw/lms6002d/lms6002d.h @@ -67,6 +67,7 @@ int lms6002d_set_txvga2_gain(lms6002d_state_t* obj, unsigned vga); int lms6002d_set_rx_extterm(lms6002d_state_t* obj, bool extterm); + enum lms6002d_rx_path { RXPATH_OFF = 0, RXPATH_LNA1 = 1, @@ -87,6 +88,7 @@ typedef enum lms6002d_tx_path lms6002d_tx_path_t; int lms6002d_set_tx_path(lms6002d_state_t* obj, unsigned path); int lms6002d_set_rxfedc(lms6002d_state_t* obj, int8_t dci, int8_t dcq); +int lms6002d_set_rxfe_ip2corr(lms6002d_state_t* obj, int8_t i, int8_t q); int lms6002d_cal_lpf(lms6002d_state_t* obj); From 7764d518d21dbe96339533f6128ed08e00fb8010 Mon Sep 17 00:00:00 2001 From: sergey Date: Wed, 18 Feb 2026 16:24:51 +0400 Subject: [PATCH 311/397] improve dc calibration --- src/lib/device/m2_lm6_1/m2_lm6_1.c | 198 ++++++++++++---------------- src/lib/device/m2_lm6_1/usdr_ctrl.c | 122 +++++++++++------ src/lib/device/m2_lm6_1/usdr_ctrl.h | 27 ++-- src/lib/hw/lms6002d/lms6002d.c | 4 +- src/lib/hw/lms6002d/lms6002d.h | 2 +- 5 files changed, 181 insertions(+), 172 deletions(-) diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index f1fea306..d9796fa3 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -81,7 +81,7 @@ const usdr_dev_param_constant_t s_params_m2_lm6_1_rev000[] = { { "/ll/srx/0/cfg_base",VIRT_CFG_SFX_BASE }, { "/ll/srx/0/irq", M2PCI_INT_RX}, { "/ll/srx/0/dmacap", 0x855 }, - { "/ll/srx/0/rfe", (uintptr_t)"/ll/rfe/0" }, +// { "/ll/srx/0/rfe", (uintptr_t)"/ll/rfe/0" }, { "/ll/rfe/0/fifobsz", SRF4_FIFOBSZ }, { "/ll/rfe/0/core", USDR_MAKE_COREID(USDR_CS_FE, USDR_FC_BRSTN) }, { "/ll/rfe/0/base", CSR_RFE4_BASE /*VIRT_CFG_SFX_BASE + 256 */}, @@ -110,8 +110,8 @@ const usdr_dev_param_constant_t s_params_m2_lm6_1_rev000[] = { { "/ll/dsp/atcrbs/0/core", USDR_MAKE_COREID(USDR_CS_DSP, 0x23675e) }, { "/ll/dsp/atcrbs/0/base", M2PCI_REG_WR_LBDSP }, - { "/ll/sdr/0/rfic/0", (uintptr_t)"lms6002d" }, - { "/ll/device/name", (uintptr_t)"usdr"}, +// { "/ll/sdr/0/rfic/0", (uintptr_t)"lms6002d" }, +// { "/ll/device/name", (uintptr_t)"usdr"}, { "/ll/sdr/max_hw_rx_chans", 1 }, { "/ll/sdr/max_hw_tx_chans", 1 }, @@ -130,6 +130,13 @@ const usdr_dev_param_constant_t s_params_m2_lm6_1_rev000[] = { { "/ll/fe/0/i2c_busno/0", -1}, }; +static const vfs_constant_str_t s_params_m2_lm6_1_rev000_s[] = { + { "/ll/srx/0/rfe", "/ll/rfe/0" }, + { "/ll/sdr/0/rfic/0", "lms6002d" }, + { "/ll/device/name", "usdr"}, +}; + + static int dev_m2_lm6_1_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -150,6 +157,9 @@ static int dev_m2_lm6_1_sdr_tx_bandwidth_set(pdevice_t ud, pusdr_vfs_obj_t obj, static int dev_m2_lm6_1_sdr_rx_gainpga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_gainvga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm6_1_sdr_rx_gainvga2a_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm6_1_sdr_rx_gainvga2b_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_lm6_1_sdr_rx_gainlna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_gainauto_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -159,6 +169,7 @@ static int dev_m2_lm6_1_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint6 static int dev_m2_lm6_1_sdr_dc_calib(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm6_1_sdr_rx_ip2corr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_tx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_dc_meas_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); @@ -166,9 +177,6 @@ static int dev_m2_lm6_1_sdr_rx_dc_meas_get(pdevice_t ud, pusdr_vfs_obj_t obj, ui static int dev_m2_lm6_1_sdr_rx_tia_cfb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_tia_rfb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); -static int dev_m2_lm6_1_sdr_tx_waveform_gen_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); -static int dev_m2_lm6_1_sdr_tx_enable_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); - static int dev_m2_lm6_1_sdr_tx_antennat_port_cfg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_refclk_frequency_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -188,8 +196,6 @@ static int dev_m2_lm6_1_debug_tps6381x_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj static int dev_m2_lm6_1_sdr_atcrbs_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_atcrbs_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* value); -static int dev_m2_lm6_1_sdr_tx_bbloopbackm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); - static int dev_m2_lm6_1_sdr_senstemp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); static int dev_m2_lm6_1_sdr_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -221,6 +227,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/rx/dc/meas", { NULL, dev_m2_lm6_1_sdr_rx_dc_meas_get }}, { "/dm/sdr/0/rx/dccorr", { dev_m2_lm6_1_sdr_rx_dccorr_set, dev_m2_lm6_1_sdr_dccorr_get }}, + { "/dm/sdr/0/rx/ip2corr", { dev_m2_lm6_1_sdr_rx_ip2corr_set, NULL }}, { "/dm/sdr/0/tx/dccorr", { dev_m2_lm6_1_sdr_tx_dccorr_set, NULL }}, { "/dm/sdr/0/calibrate", { dev_m2_lm6_1_sdr_dc_calib, NULL }}, @@ -234,6 +241,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/tx/gain/vga2", { dev_m2_lm6_1_sdr_tx_gain_vga2_set, NULL }}, { "/dm/sdr/0/rx/gain/pga", { dev_m2_lm6_1_sdr_rx_gainpga_set, NULL }}, { "/dm/sdr/0/rx/gain/vga", { dev_m2_lm6_1_sdr_rx_gainvga_set, NULL }}, + { "/dm/sdr/0/rx/gain/vga2a",{ dev_m2_lm6_1_sdr_rx_gainvga2a_set, NULL }}, + { "/dm/sdr/0/rx/gain/vga2b",{ dev_m2_lm6_1_sdr_rx_gainvga2b_set, NULL }}, { "/dm/sdr/0/rx/gain/lna", { dev_m2_lm6_1_sdr_rx_gainlna_set, NULL }}, { "/dm/sdr/0/rx/gain/auto", { dev_m2_lm6_1_sdr_rx_gainauto_set, NULL }}, @@ -245,19 +254,13 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/rx/bandwidth", { dev_m2_lm6_1_sdr_rx_bandwidth_set, NULL }}, { "/dm/sdr/0/tx/bandwidth", { dev_m2_lm6_1_sdr_tx_bandwidth_set, NULL }}, - { "/dm/sdr/0/tx/waveform_gen", { dev_m2_lm6_1_sdr_tx_waveform_gen_set, NULL}}, - { "/debug/hw/lms6002d/0/reg", { dev_m2_lm6_1_debug_lms6002d_reg_set, dev_m2_lm6_1_debug_lms6002d_reg_get }}, { "/debug/hw/si5332/0/reg", { dev_m2_lm6_1_debug_si5332_reg_set, dev_m2_lm6_1_debug_si5332_reg_get }}, { "/debug/hw/tps6381x/0/reg", { dev_m2_lm6_1_debug_tps6381x_reg_set, dev_m2_lm6_1_debug_tps6381x_reg_get }}, - - { "/dm/sdr/0/tx/enable", { dev_m2_lm6_1_sdr_tx_enable_set, NULL }}, - { "/dm/sdr/0/tfe/antcfg", { dev_m2_lm6_1_sdr_tx_antennat_port_cfg_set, NULL }}, { "/dm/sdr/0/core/atcrbs/reg", { dev_m2_lm6_1_sdr_atcrbs_set, dev_m2_lm6_1_sdr_atcrbs_get }}, - { "/dm/sdr/0/tx/bbloopbackm", { dev_m2_lm6_1_sdr_tx_bbloopbackm_set, NULL }}, { "/dm/sdr/0/dac_vctcxo", { dev_m2_lm6_1_sdr_vctcxo_set, NULL }}, { "/dm/sdr/0/clkmeas", { dev_m2_lm6_1_sdr_clkmeas_set, dev_m2_lm6_1_sdr_clkmeas_get }}, @@ -335,12 +338,18 @@ int dev_m2_lm6_1_sdr_clkmeas_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ov int dev_m2_lm6_1_sdr_dccorr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { - // struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; uint32_t v = 0; int res = dev_gpi_get32(ud->dev, 20, &v); if (res) return res; + int16_t i, q; + i = (v >> 0) & 0xffff; + q = (v >> 16) & 0xffff; + + USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: DC_AAVG I=%d Q=%d\n", lowlevel_get_devname(d->base.dev), i, q); + *ovalue = v; return 0; } @@ -353,7 +362,7 @@ int dev_m2_lm6_1_debug_lms6002d_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint6 d->debug_lms6002d_last = ~0u; res = lowlevel_spi_tr32(d->base.dev, 0, 0, value & 0xffff, &d->debug_lms6002d_last); - USDR_LOG("XDEV", USDR_LOG_WARNING, "%s: Debug LMS6 REG %04x => %04x\n", + USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Debug LMS6 REG %04x => %04x\n", lowlevel_get_devname(d->base.dev), (unsigned)value, d->debug_lms6002d_last); return res; @@ -427,15 +436,6 @@ int dev_m2_lm6_1_sdr_senstemp_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *o return res; } - -int dev_m2_lm6_1_sdr_tx_waveform_gen_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) -{ - //struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - //USDR_LOG("UDEV", USDR_LOG_WARNING, "M2_LM6_1: TX WAVEFORM GEN %d\n", (int)value); - //return dev_txbuffill(d, value); - return -EINVAL; -} - int dev_m2_lm6_1_sdr_dc_calib(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; @@ -484,18 +484,6 @@ int dev_m2_lm6_1_sdr_atcrbs_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* val return res; } -int dev_m2_lm6_1_sdr_tx_bbloopbackm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) -{ - //struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - //int res; - // res = sfe_tx4_ctl(d->base.dev, 0, M2PCI_REG_WR_TXDMA_CNF_L, 0, 0, - // value > 1 ? true : false, - // true); - //return res; - return -EINVAL; -} - - int dev_m2_lm6_1_sdr_refclk_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; @@ -590,13 +578,6 @@ int dev_m2_lm6_1_pwren_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return 0; } -int dev_m2_lm6_1_sdr_tx_enable_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) -{ - //struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - USDR_LOG("UDEV", USDR_LOG_INFO, "M2_LM6_1: TX en:%d\n", (int)value); - return 0; -} - int dev_m2_lm6_1_sdr_rx_freq_lob_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; @@ -663,6 +644,18 @@ int dev_m2_lm6_1_sdr_rx_gainvga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t return usdr_rfic_set_gain(&d->d, GAIN_RX_VGA1, value, NULL); } +int dev_m2_lm6_1_sdr_rx_gainvga2a_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + return usdr_rfic_set_gain(&d->d, GAIN_RX_VGA2A, value, NULL); +} + +int dev_m2_lm6_1_sdr_rx_gainvga2b_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + return usdr_rfic_set_gain(&d->d, GAIN_RX_VGA2B, value, NULL); +} + int dev_m2_lm6_1_sdr_rx_gainlna_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; @@ -679,53 +672,10 @@ int dev_m2_lm6_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - // 00 –All output buffers powered down; - // 01 –First buffer enabled for LNA1 path (default); WB: 250 - 2700 - // 10 –Second buffer enabledfor LNA2 path; HB: 2700 - 3800 - // 11 –Third buffer enabledfor LNA3 path LB: external / MIXER -#if 0 - enum { - LMS6_PATH_NONE = 0, - LMS6_PATH_WB = 1, - LMS6_PATH_HB = 2, - LMS6_PATH_LB = 3, - }; - - int bandsw = -1; - if (value > 4096) { - const char* param = (const char*)value; - if (strcasecmp("rxl", param) == 0) { - value = LMS6_PATH_LB; - } else if (strcasecmp("rxw", param) == 0) { - value = LMS6_PATH_WB; bandsw = 0; - } else if (strcasecmp("rxh", param) == 0) { - value = LMS6_PATH_HB; bandsw = 1; - } else { - value = LMS6_PATH_NONE; - } - } - - if (bandsw != -1) { - int res = dev_gpo_set(d->base.dev, IGPO_RXSW, (d->revision == 0) ? !bandsw : bandsw); - if (res) - return res; - } - - return lms6002d_set_rx_path(&d->lms, value); -#endif - - // if (value > 4096) { - // const char* param = (const char*)value; - // int idx = find_param_list(param, s_rx_path_list, SIZEOF_ARRAY(s_rx_path_list)); - // if (idx < 0) { - // USDR_LOG("UDEV", USDR_LOG_WARNING, "MP_LM7_1_GPS: unknown '%s' path!\n", - // param); - // return -EINVAL; - // } - - // value = s_rx_path_list[idx].param; - // } - + // 00 – All output buffers powered down; + // 01 – First buffer enabled for LNA1 path (default); WB: 250 - 2700 + // 10 – Second buffer enabledfor LNA2 path; HB: 2700 - 3800 + // 11 – Third buffer enabledfor LNA3 path LB: external / MIXER if (value > 4096) { const char* param = (const char*)value; if (strcasecmp("rxl", param) == 0) { @@ -742,48 +692,42 @@ int dev_m2_lm6_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val int dev_m2_lm6_1_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - //struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - return 0; -#if 0 - int bandsw = -1; + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + if (value > 4096) { const char* param = (const char*)value; if (strcasecmp("txw", param) == 0) { - bandsw = 1; value = TXPATH_PA1; + value = (uintptr_t)"W"; } else if (strcasecmp("txh", param) == 0) { - bandsw = 0; value = TXPATH_PA2; - } else { - value = TXPATH_OFF; + value = (uintptr_t)"H"; } } - if (bandsw != -1) { - int res = dev_gpo_set(d->base.dev, IGPO_TXSW, (d->revision == 0) ? !bandsw : bandsw); - if (res) - return res; - } - - return lms6002d_set_tx_path(&d->lms, value); -#endif + return usdr_rfic_fe_set_txlna(&d->d, (const char *)(uintptr_t)value); } int dev_m2_lm6_1_sdr_rx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { -#if 0 struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; int res; - unsigned chan = (unsigned)(value >> 32); + //unsigned chan = (unsigned)(value >> 32); unsigned vi = (value >> 16) & 0xffff; unsigned vq = (value >> 0) & 0xffff; - if (chan == 1) - res = lms6002d_set_rxfedc(&d->lms, vi, vq); - else - res = -EINVAL; + res = lms6002d_set_rxfedc(&d->d.lms, vi, vq); + return res; +} +int dev_m2_lm6_1_sdr_rx_ip2corr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + int res; + //unsigned chan = (unsigned)(value >> 32); + unsigned vi = (value >> 16) & 0xffff; + unsigned vq = (value >> 0) & 0xffff; + + res = lms6002d_set_rxfe_ip2corr(&d->d.lms, vi, vq); return res; -#endif - return -EINVAL; } int dev_m2_lm6_1_sdr_tx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -984,6 +928,24 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha return res; } + if (d->d.rx_lo == 0) { + res = usdr_rfic_fe_set_freq(&d->d, false, 320e6, NULL); + if (res) { + return res; + } + + d->d.rx_lo = 0; + } + + res = usdr_calib_dc(&d->d, true); + if (res) { + return res; + } + + if (d->d.rx_lo != 0) { + usdr_rfic_fe_set_freq(&d->d, false, d->d.rx_lo, NULL); + } + res = create_sfetrx4_stream(dev, CORE_SFERX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &chans); @@ -1048,6 +1010,12 @@ int usdr_device_m2_lm6_1_create(lldev_t dev, /*UNUSED*/ device_id_t devid) if (res) goto failed_tree_creation; + res = vfs_add_const_str_vec(&d->base.rootfs, + s_params_m2_lm6_1_rev000_s, + SIZEOF_ARRAY(s_params_m2_lm6_1_rev000_s)); + if (res) + goto failed_tree_creation; + res = usdr_vfs_obj_param_init_array(&d->base, s_fparams_m2_lm6_1_rev000, SIZEOF_ARRAY(s_fparams_m2_lm6_1_rev000)); diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 902461d1..44ce1343 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -21,6 +21,8 @@ #include "../generic_usdr/generic_regs.h" +#include "../ipblks/fgearbox.h" + // Clock configuration // rev4/rev3 rev2 rev1 // port0 - LMS_PLLCLK | RXCLK | RXCLK @@ -57,6 +59,11 @@ enum usdr_rev000 { SPI_LMS6 = 0, }; +enum lms6_vios { + LMS6_VIO_NORM = 1800, + LMS6_VIO_BOOST = 1950, +}; + // RX chain // LNA_GAIN -> mixer -> VGA1_GAIN -> lpf -> VGA2_GAIN[a,b] -> adc @@ -243,15 +250,6 @@ static int _usdr_set_lna_rx(usdr_dev_t *d, unsigned cfg_idx) int res; d->rx_cfg_path = cfg_idx; - /* - if (d->rx_lna_lb_active) { - switch (band) { - case RFE_LNAL: band = RFE_LBL; txlbband = 2; break; - case RFE_LNAW: band = RFE_LBW; txlbband = 1; break; - case RFE_LNAH: band = RFE_LBH; txlbband = 1; break; - } - } - */ USDR_LOG("UDEV", USDR_LOG_INFO, "%s: Set RX band to %d (%s/%s) %s [TXLB:%d => ATEEN=%d,%d]\n", lowlevel_get_devname(d->base.dev), band, @@ -260,9 +258,6 @@ static int _usdr_set_lna_rx(usdr_dev_t *d, unsigned cfg_idx) txlbband, 0, 0 /* d->trf_lb_atten, d->trf_lb_loss */ ); res = lms6002d_set_rx_path(&d->lms, ((d->rx_rfic_lna = band))); - //if (txlbband) { - // res = (res) ? res : lms7_trf_set_path(&d->lmsstate, ((d->tx_rfic_band = txlbband))); - //} if (res) return res; @@ -280,11 +275,6 @@ static int _usdr_set_lna_tx(usdr_dev_t *d, unsigned cfg_idx) USDR_LOG("XDEV", USDR_LOG_INFO, "%s: Set TX band to %d (%s/%s)\n", lowlevel_get_devname(d->base.dev), band, cfg->name0, cfg->name1); -// if (d->rx_lna_lb_active) { -// res = lms7_rfe_set_path(&d->lmsstate, band == 1 ? RFE_LBW : RFE_LBL, -// d->rx_run[0], d->rx_run[1]); -// } - res = lms6002d_set_tx_path(&d->lms, ((d->tx_rfic_band = band))); if (res) return res; @@ -346,8 +336,8 @@ static int _usdr_signal_event(usdr_dev_t *d, enum sigtype t) case USDR_SAMPLERATE_CHANGED: if (d->mexir_en && (d->cfg_auto_rx[d->rx_cfg_path].band == RXPATH_LNA3)) { d->rfic_rx_lo = d->mixer_lo + d->rx_lo; - USDR_LOG("UDEV", USDR_LOG_ERROR, "%s: RX LO corrected to %.3f Mhz (LNB = %.3f)\n", - lowlevel_get_devname(d->base.dev), d->rfic_rx_lo / 1.0e6, d->mixer_lo / 1.0e6); + USDR_LOG("UDEV", USDR_LOG_ERROR, "%s: RX LO corrected to %.3f -> %.3f Mhz (LNB = %.3f)\n", + lowlevel_get_devname(d->base.dev), d->rx_lo / 1.0e6, d->rfic_rx_lo / 1.0e6, d->mixer_lo / 1.0e6); return lms6002d_tune_pll(&d->lms, false, d->rfic_rx_lo); } @@ -360,6 +350,8 @@ int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob) { if (d->si_vco_freq == 0 || d->rawsamplerate == 0) return -EINVAL; + if (freqlob == 0) + return -EINVAL; float ceff = d->si_vco_freq / freqlob; if (ceff < 8) @@ -384,13 +376,46 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, unsigned freq = rate << 1; //Link speed x2 sample rate struct si5332_layout_info nfo = { d->fref, freq }; int res = 0; + unsigned i = 0; + unsigned int_decim[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + + /* + for (unsigned ii = 0; ii < SIZEOF_ARRAY(int_decim); ii++) { + if (rxrate * int_decim[ii] < 60e6) + i = ii; + else + break; + } + */ + + nfo.out *= int_decim[i]; + + if (rate >= 60e6 && !d->vio_boost) { + USDR_LOG("UDEV", USDR_LOG_WARNING, "Boosting Vio to get stable samplerates over 60Msps\n"); + + res = res ? res : lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 3, LMS6_VIO_BOOST); + d->vio_boost = true; + } else if (rate < 60e6 && d->vio_boost) { + res = res ? res : lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 3, LMS6_VIO_NORM); + d->vio_boost = false; + } res = res ? res : _usdr_pwr_state(d, false, true); res = res ? res : si5332_set_layout(dev, 0, I2C_BUS_SI5332A, &nfo, d->hw_board_rev == USDR_REV_3 ? false : true, d->si_vco_div, &d->si_vco_freq); // TODO: Add ability to alter it d->mixer_lo = d->si_vco_freq / d->si_vco_div; - d->rawsamplerate = rate; + d->rawsamplerate = nfo.out; + /* + if (d->rxbb_decim != int_decim[i]) { + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSP_RX_CTRL, 0x0); + res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_DSP_RX_CFG, (fgearbox_firs_t)d->rxbb_decim, DSP_7SERIES); + res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSP_RX_CTRL, 0x0); + } + */ + + d->rxbb_decim = int_decim[i]; + d->txbb_intr = int_decim[i]; // Apply automatic RF Freq correction if external mixer is active if (d->mexir_en) { @@ -405,7 +430,7 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, res = res ? res : lms6002d_set_bandwidth(&d->lms, true, txrate); } - USDR_LOG("UDEV", USDR_LOG_INFO, "RX_RATE %.3f TX_RATE %.3f MXLO %.3f\n", rxrate / 1.0e6, txrate / 1.0e6, d->mixer_lo / 1.0e6); + USDR_LOG("UDEV", USDR_LOG_INFO, "INTR %d RX_RATE %.3f TX_RATE %.3f MXLO %.3f\n", int_decim[i], rxrate / 1.0e6, txrate / 1.0e6, d->mixer_lo / 1.0e6); return res; } @@ -413,19 +438,26 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, int usdr_rfic_streaming_up(struct usdr_dev *d, unsigned dir) { int res = 0; + bool wakeup_delay = false; if (dir & RFIC_LMS6_TX) { + wakeup_delay |= !d->tx_run; d->tx_run = true; res = (res) ? res : _usdr_pwr_state(d, true, true); } if (dir & RFIC_LMS6_RX) { + wakeup_delay |= !d->rx_run; d->rx_run = true; res = (res) ? res : _usdr_pwr_state(d, false, true); } + if (wakeup_delay) { + usleep(1000); + } + // TODO enable clock - //return lms6002d_rf_enable(&d->lms, d->tx_run, d->rx_run); + // return lms6002d_rf_enable(&d->lms, d->tx_run, d->rx_run); return res; } @@ -580,8 +612,11 @@ int usdr_init(struct usdr_dev *d, int ext_clk, unsigned ext_fref) if (res) return res; - if (devid != 0x1114) { + if (devid != TMP114_DEVICE_ID) { USDR_LOG("UDEV", USDR_LOG_ERROR, "TMP114 DEVID=%x\n", devid); + if (!getenv("USDR_IGNORE_TMP")) { + return -EIO; + } } } @@ -605,11 +640,11 @@ int usdr_init(struct usdr_dev *d, int ext_clk, unsigned ext_fref) //res = lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 1, // d->hw_board_rev == USDR_REV_1 ? 3360 : 1800); + // Set GPIO bank voltage to 1.8V to be compatible with xSDR res = res ? res : lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 1, 1800); - // Increase 1.8V rail to get more samplerate - // res = lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 3, 2100); - // if (res) - // return res; + + // Reset 1.8V rail default VIO + res = res ? res : lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 3, LMS6_VIO_NORM); res = res ? res : lp8758_vout_ctrl(dev, d->subdev, I2C_BUS_LP8758, 0, 1, 1); //1v0 -- less affected res = res ? res : lp8758_vout_ctrl(dev, d->subdev, I2C_BUS_LP8758, 1, 1, 1); //2v5 -- less affected @@ -693,19 +728,6 @@ int usdr_dtor(struct usdr_dev *d) return 0; } -// We need to enable RX RF to get forward clocking -#if 0 -int usdr_pwren(struct usdr_dev *d, bool on) -{ - // TODO RX / TX selection - lms6002d_rf_enable(&d->lms, false, on); - // TX off - lms6002d_rf_enable(&d->lms, true, on /* false */); - return 0; -} -#endif - - static int _usdr_lms6002_dc_calib(struct usdr_dev *d) { @@ -714,7 +736,7 @@ int _usdr_lms6002_dc_calib(struct usdr_dev *d) res = res ? res : lms6002d_cal_lpf(&d->lms); for (unsigned i = 0; i < 16; i++) { - res = res ? res : lms6002d_cal_lpf_bandwidth(&d->lms, i); + res = res ? res : lms6002d_cal_lpf_bandwidth(&d->lms, i, i == 0); } res = res ? res : lms6002d_cal_txrxlpfdc(&d->lms, true); @@ -726,6 +748,9 @@ int _usdr_lms6002_dc_calib(struct usdr_dev *d) res = res ? res : lms6002d_cal_vga2(&d->lms); res = res ? res : lms6002d_set_rx_extterm(&d->lms, false); + // Restore initial VGA2 gain values + res = res ? res : lms6002d_set_rxvga2ab_gain(&d->lms, d->rx_vga2a, d->rx_vga2b); + return res; } @@ -925,6 +950,21 @@ int usdr_rfic_fe_set_rxlna(struct usdr_dev *d, return _usdr_set_lna_rx(d, d->rx_rfic_path); } +int usdr_rfic_fe_set_txlna(struct usdr_dev *d, + const char *lna) +{ + int res = get_antenna_cfg_by_name(lna, d->cfg_auto_tx, SIZEOF_ARRAY(d->cfg_auto_tx)); + USDR_LOG("UDEV", USDR_LOG_INFO, "TX_PATH set to %s from `%s`\n", (res < 0) ? "AUTO" : d->cfg_auto_tx[res].name0, lna); + + if (res == -1) { + d->tx_rfic_path = USDR_TX_AUTO; + return _usdr_signal_event(d, USDR_TX_LNA_CHANGED); + } + + d->tx_rfic_path = res; + return _usdr_set_lna_tx(d, d->tx_rfic_path); +} + int usdr_set_rx_port_switch(struct usdr_dev *d, unsigned path) { diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.h b/src/lib/device/m2_lm6_1/usdr_ctrl.h index d8cf456f..5ce90796 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.h +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.h @@ -65,7 +65,6 @@ struct usdr_dev lms6002d_state_t lms; unsigned refclkpath; unsigned fref; - unsigned rawsamplerate; uint8_t rx_cfg_path; uint8_t tx_cfg_path; @@ -75,25 +74,28 @@ struct usdr_dev uint8_t tx_rfic_path; uint8_t tx_rfic_band; - unsigned dsp_clk; - - unsigned rx_lo; - unsigned tx_lo; - - // Gain settings uint8_t rx_lna; uint8_t rx_vga1; uint8_t rx_vga2a; uint8_t rx_vga2b; - bool rx_run; bool tx_run; bool rx_pwren; bool tx_pwren; bool mexir_en; + bool vio_boost; + + unsigned rawsamplerate; + unsigned rxbb_decim; + unsigned txbb_intr; + + unsigned dsp_clk; + unsigned rx_lo; + unsigned tx_lo; + unsigned mixer_lo; unsigned rfic_rx_lo; @@ -128,6 +130,8 @@ int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob); int usdr_rfic_fe_set_rxlna(struct usdr_dev *d, const char* lna); +int usdr_rfic_fe_set_txlna(struct usdr_dev *d, + const char *lna); int usdr_rfic_fe_set_freq(struct usdr_dev *d, bool dir_tx, @@ -149,11 +153,6 @@ int usdr_init(struct usdr_dev *d, int ext_clk, unsigned int ext_fref); int usdr_dtor(struct usdr_dev *d); -// int usdr_pwren(struct usdr_dev *d, bool on); - -int usdr_lob_set(struct usdr_dev *d, unsigned freq); - - int usdr_calib_dc(struct usdr_dev *d, bool rx); int usdr_gettemp(struct usdr_dev *d, int* temp256); @@ -179,6 +178,8 @@ enum { IGPO_LED = 8, IGPO_DCCORR = 9, + IGPO_DSP_RX_CTRL = 10, + IGPO_FRONT = 15, IGPO_CLKMEAS = 16, IGPO_ENABLE_OSC = 17, diff --git a/src/lib/hw/lms6002d/lms6002d.c b/src/lib/hw/lms6002d/lms6002d.c index 795d26bf..3ae61455 100644 --- a/src/lib/hw/lms6002d/lms6002d.c +++ b/src/lib/hw/lms6002d/lms6002d.c @@ -790,7 +790,7 @@ int lms6002d_cal_vga2(lms6002d_state_t* obj) return 0; } -int lms6002d_cal_lpf_bandwidth(lms6002d_state_t* obj, unsigned bcode) +int lms6002d_cal_lpf_bandwidth(lms6002d_state_t* obj, unsigned bcode, bool do_tune) { // TURN ON tx, SET tx to 320Mhz int res = 0; @@ -801,7 +801,7 @@ int lms6002d_cal_lpf_bandwidth(lms6002d_state_t* obj, unsigned bcode) bool txen = GET_LMS6002D_TOP_ENCFG_STXEN(obj->top_encfg); res = res ? res : lms6002d_trf_enable(obj, 1); - res = res ? res : lms6002d_tune_pll(obj, true, 320000000); + res = (!do_tune || res) ? res : lms6002d_tune_pll(obj, true, 320000000); uint16_t regs_0[] = { MAKE_LMS6002D_TOP_LPF_CTRL(0, 0, 0, 0), diff --git a/src/lib/hw/lms6002d/lms6002d.h b/src/lib/hw/lms6002d/lms6002d.h index 89263fa1..355797ad 100644 --- a/src/lib/hw/lms6002d/lms6002d.h +++ b/src/lib/hw/lms6002d/lms6002d.h @@ -94,7 +94,7 @@ int lms6002d_set_rxfe_ip2corr(lms6002d_state_t* obj, int8_t i, int8_t q); int lms6002d_cal_lpf(lms6002d_state_t* obj); int lms6002d_cal_txrxlpfdc(lms6002d_state_t* obj, bool tx); int lms6002d_cal_vga2(lms6002d_state_t* obj); -int lms6002d_cal_lpf_bandwidth(lms6002d_state_t* obj, unsigned bcode); +int lms6002d_cal_lpf_bandwidth(lms6002d_state_t* obj, unsigned bcode, bool do_tune); // For TIA calibration From bb349e820b2e289b479e065b6db6995078189c4a Mon Sep 17 00:00:00 2001 From: sergey Date: Wed, 18 Feb 2026 18:54:00 +0400 Subject: [PATCH 312/397] fix xmass build --- src/lib/device/mdev.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/lib/device/mdev.c b/src/lib/device/mdev.c index 3aa575ce..5a098ce4 100644 --- a/src/lib/device/mdev.c +++ b/src/lib/device/mdev.c @@ -1,11 +1,16 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT -#ifndef _WIN32 +//#ifndef _WIN32 + #include #include #include +#ifndef _WIN32 #include +#else +//TODO add proper poll emulation +#endif #include "device.h" #include "device_vfs.h" @@ -182,7 +187,7 @@ int _mdev_get_obj(pdevice_t dev, const char* fullpath, pusdr_vfs_obj_t *vfsobj) vfs_object_t *vfso = &obj->vfs_obj; vfso->type = VFST_I64; - vfso->amask = 0; + vfso->flags = 0; vfso->eparam[0] = 0; vfso->eparam[1] = 0; vfso->eparam[2] = 0; @@ -622,4 +627,3 @@ int mdev_create(unsigned pcnt, const char** names, const char** values, lldev_t* return res; } -#endif From f40d33a5b3f55c191ddfeae57bfb560b2d7b78a0 Mon Sep 17 00:00:00 2001 From: sergey Date: Thu, 19 Feb 2026 00:33:50 +0400 Subject: [PATCH 313/397] fix ports --- src/lib/port/usdr_port.c | 48 ++++++++++++++++++++++++++++++++++++++++ src/lib/port/usdr_port.h | 15 +++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/lib/port/usdr_port.c b/src/lib/port/usdr_port.c index 8f669fe7..be175a48 100644 --- a/src/lib/port/usdr_port.c +++ b/src/lib/port/usdr_port.c @@ -84,3 +84,51 @@ void* usdr_lib_sym(library_hdl_t h, const char* proc) #endif + +#ifdef __APPLE__ +#include +#include + +/** + * A wrapper for sem_timedwait functionality using Mach semaphores. + * @param sem The Mach semaphore_t to wait on. + * @param abs_timeout The absolute wall-clock time to wait until. + * @return 0 on success, -1 on error (with errno set). + */ +int mach_sem_timedwait(semaphore_t sem, const struct timespec *abs_timeout) { + // 1. Get current wall-clock time + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + // 2. Calculate relative timeout in nanoseconds + int64_t rel_ns = (abs_timeout->tv_sec - now.tv_sec) * 1000000000LL + + (abs_timeout->tv_nsec - now.tv_nsec); + + if (rel_ns <= 0) { + // Time has already passed + return (semaphore_wait_noblock(sem) == KERN_SUCCESS) ? 0 : (errno = ETIMEDOUT, -1); + } + + // 3. Convert relative nanoseconds to Mach ticks (deadline) + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + uint64_t rel_ticks = rel_ns * timebase.denom / timebase.numer; + uint64_t deadline = mach_absolute_time() + rel_ticks; + + // 4. Perform the wait + kern_return_t kr = semaphore_wait_deadline(sem, deadline); + + if (kr == KERN_SUCCESS) { + return 0; + } else if (kr == KERN_OPERATION_TIMED_OUT) { + errno = ETIMEDOUT; + return -1; + } else { + errno = EINVAL; + return -1; + } +} + +#endif + + diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index ea55e616..4ebb7f99 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -21,6 +21,16 @@ #ifdef _WIN32 #define htobe32(x) htonl(x) #define be32toh(x) ntohl(x) +#elif defined(__APPLE__) +#include +#include +#include + +#include +#include +#include + +#include #else #include #include @@ -105,6 +115,11 @@ int asprintf(char **strp, const char *fmt, ...) __attribute__ ((format (printf, #endif +#ifdef __APPLE__ +int mach_sem_timedwait(semaphore_t sem, const struct timespec *abs_timeout); +#define sem_timedwait mach_sem_timedwait +#endif + #define CACHE_SIZE 64 From d3b50a8c570ea2a411fc18351db22dd031a674ee Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 19 Feb 2026 01:42:38 +0400 Subject: [PATCH 314/397] cmake: install CMake package config/targets and generate usdr.pc --- src/CMakeLists.txt | 7 +++- src/cmake/UsdrPackage.cmake | 73 +++++++++++++++++++++++++++++++++++ src/cmake/usdr.pc.in | 11 ++++++ src/cmake/usdrConfig.cmake.in | 8 ++++ src/lib/CMakeLists.txt | 24 +++++++++--- src/lib/xdsp/CMakeLists.txt | 10 ++++- 6 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 src/cmake/UsdrPackage.cmake create mode 100644 src/cmake/usdr.pc.in create mode 100644 src/cmake/usdrConfig.cmake.in diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 86d6008c..3888614a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2023-2024 Wavelet Lab +# Copyright (c) 2023-2026 Wavelet Lab # SPDX-License-Identifier: MIT cmake_minimum_required(VERSION 3.8) @@ -94,3 +94,8 @@ message(STATUS "Install libs: ${CMAKE_INSTALL_LIBDIR}") message(STATUS "Shared libs: ${BUILD_SHARED_LIBS}") message(STATUS "Data dir: ${CMAKE_INSTALL_FULL_DATADIR}") message(STATUS "######################################################") + +include(cmake/UsdrPackage.cmake) + +# Use helper to generate/install CMake config, exported targets and pkg-config file +usdr_install_package(NAME usdr VERSION ${USDR_VERSION} TARGETS usdrTargets PKGCONFIG ON) diff --git a/src/cmake/UsdrPackage.cmake b/src/cmake/UsdrPackage.cmake new file mode 100644 index 00000000..9f079f65 --- /dev/null +++ b/src/cmake/UsdrPackage.cmake @@ -0,0 +1,73 @@ +# Usdr CMake package helper +# Provides a function `usdr_install_package(NAME VERSION TARGETS PKGCONFIG )` + +include(CMakePackageConfigHelpers) +get_filename_component(USDR_PACKAGE_HELPER_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) + +function(usdr_install_package) + cmake_parse_arguments(_u "" "NAME;VERSION;PKGCONFIG" "TARGETS" ${ARGN}) + + if(NOT _u_NAME) + message(FATAL_ERROR "usdr_install_package: NAME is required") + endif() + if(NOT _u_VERSION) + message(FATAL_ERROR "usdr_install_package: VERSION is required") + endif() + + set(_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${_u_NAME}") + + # Helper dir (set at include-time) points to this file's directory + set(_usdr_helper_dir "${USDR_PACKAGE_HELPER_DIR}") + + # Configure and write CMake package config files + set(_config_in "${_usdr_helper_dir}/${_u_NAME}Config.cmake.in") + if(NOT IS_ABSOLUTE "${_config_in}") + get_filename_component(_config_in "${_config_in}" REALPATH BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + configure_package_config_file( + "${_config_in}" + "${CMAKE_CURRENT_BINARY_DIR}/${_u_NAME}Config.cmake" + INSTALL_DESTINATION "${_install_dir}" + ) + + write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${_u_NAME}ConfigVersion.cmake" + VERSION ${_u_VERSION} + COMPATIBILITY AnyNewerVersion + ) + + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${_u_NAME}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${_u_NAME}ConfigVersion.cmake" + DESTINATION "${_install_dir}" + ) + + # Install exported CMake targets + if(_u_TARGETS) + install(EXPORT ${_u_TARGETS} + FILE ${_u_NAME}Targets.cmake + NAMESPACE ${_u_NAME}:: + DESTINATION "${_install_dir}" + ) + endif() + + # Optionally generate and install a pkg-config file + if(_u_PKGCONFIG STREQUAL "ON") + set(_pc_in "${_usdr_helper_dir}/${_u_NAME}.pc.in") + if(NOT IS_ABSOLUTE "${_pc_in}") + get_filename_component(_pc_in "${_pc_in}" REALPATH BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + # Provide substitutions for the pkg-config template + set(PACKAGE_NAME "${_u_NAME}") + set(PACKAGE_VERSION "${_u_VERSION}") + + configure_file("${_pc_in}" + "${CMAKE_CURRENT_BINARY_DIR}/${_u_NAME}.pc" @ONLY) + unset(PACKAGE_NAME CACHE) + unset(PACKAGE_VERSION CACHE) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${_u_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + endif() +endfunction() diff --git a/src/cmake/usdr.pc.in b/src/cmake/usdr.pc.in new file mode 100644 index 00000000..fca1cbc6 --- /dev/null +++ b/src/cmake/usdr.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=@CMAKE_INSTALL_LIBDIR@ +includedir=@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PACKAGE_NAME@ +Description: usdr library +Version: @PACKAGE_VERSION@ +Requires: libusb-1.0 +Libs: -L${libdir} -l@PACKAGE_NAME@ +Cflags: -I${includedir} diff --git a/src/cmake/usdrConfig.cmake.in b/src/cmake/usdrConfig.cmake.in new file mode 100644 index 00000000..a2755b58 --- /dev/null +++ b/src/cmake/usdrConfig.cmake.in @@ -0,0 +1,8 @@ +@PACKAGE_INIT@ + +# Find dependencies used by the usdr package +include(CMakeFindDependencyMacro) +find_dependency(LIBUSB_1 REQUIRED) + +# Import the targets exported by the usdr build +include("${CMAKE_CURRENT_LIST_DIR}/usdrTargets.cmake") diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 78647913..32235e0e 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2023-2024 Wavelet Lab +# Copyright (c) 2023-2026 Wavelet Lab # SPDX-License-Identifier: MIT cmake_minimum_required(VERSION 3.8) @@ -27,9 +27,6 @@ message("INC - ${USDR_INCLUDE_FILES}") message("LNK - ${USDR_LINK_FILES}") message("DEP - ${USDR_DEPEND_TARGETS}") -include_directories(${USDR_INCLUDE_FILES}) -include_directories(${USDR_INCLUDE_DIRS}) - add_library(usdr ${USDR_LIBRARY_FILES}) @@ -45,7 +42,24 @@ target_link_libraries(usdr pthread ${USDR_PLATFORM_LIBS} ${USDR_LINK_FILES} usdr add_dependencies(usdr ${USDR_DEPEND_TARGETS}) target_compile_options(usdr PRIVATE "-Wall" "-Werror=implicit-function-declaration") +# Propagate include directories to consumers via the target interface +target_include_directories(usdr PUBLIC + $ + $ +) + +# Ensure exported INTERFACE include directories are exactly the intended ones +set_target_properties(usdr PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "$;$" +) + set_target_properties(usdr PROPERTIES SOVERSION ${USDR_ABI_VERSION}) set_target_properties(usdr PROPERTIES VERSION ${USDR_LIBVER}) -install(TARGETS usdr LIBRARY) +install(TARGETS usdr + EXPORT usdrTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index 94cbaca8..d36f9e5e 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2023-2024 Wavelet Lab +# Copyright (c) 2023-2026 Wavelet Lab # SPDX-License-Identifier: MIT # Populate a CMake variable with the sources @@ -89,7 +89,13 @@ else() add_library(usdr-dsp ${xdsplib_SRCS}) target_link_libraries(usdr-dsp m pthread) target_compile_options(usdr-dsp PRIVATE "-Wall" "-Werror=implicit-function-declaration") - install(TARGETS usdr-dsp LIBRARY) + install(TARGETS usdr-dsp EXPORT usdrTargets LIBRARY + DESTINATION ${CMAKE_INSTALL_LIBDIR}) + + # Prevent exporting build-tree include paths for the dsp target + set_target_properties(usdr-dsp PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "$;$" + ) set_target_properties(usdr-dsp PROPERTIES SOVERSION ${USDR_ABI_VERSION}) set_target_properties(usdr-dsp PROPERTIES VERSION ${USDR_LIBVER}) From f1b2638dd174f7c5446ba74ff2886fa6c7a99833 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 19 Feb 2026 02:05:25 +0400 Subject: [PATCH 315/397] pkg-config: fix libdir/includedir to use prefix/exec_prefix --- src/cmake/usdr.pc.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmake/usdr.pc.in b/src/cmake/usdr.pc.in index fca1cbc6..850290f3 100644 --- a/src/cmake/usdr.pc.in +++ b/src/cmake/usdr.pc.in @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} -libdir=@CMAKE_INSTALL_LIBDIR@ -includedir=@CMAKE_INSTALL_INCLUDEDIR@ +libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: @PACKAGE_NAME@ Description: usdr library From 4ecec5640433bd0a399ec85805444ec58b528d48 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Thu, 19 Feb 2026 02:19:12 +0400 Subject: [PATCH 316/397] docs: add instructions for locating installed usdr via pkg-config and CMake --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index 4bedd902..23435b54 100644 --- a/README.md +++ b/README.md @@ -116,3 +116,43 @@ cd ../src/lib/lowlevel/pcie_uram/driver make sudo insmod usdr_pcie_uram.ko ```` + +## Finding the installed `usdr` library + +You can find and use the installed library in two common ways — with `pkg-config` or with CMake's `find_package`. + +- Using pkg-config + +```bash +# set to the install prefix used during `make install` +export INSTALL_PREFIX=/path/to/install +export PKG_CONFIG_PATH="$INSTALL_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH" + +# Get version, cflags and libs +pkg-config --modversion usdr +pkg-config --cflags usdr # include flags, e.g. -I/path/to/install/include +pkg-config --libs usdr # link flags, e.g. -L/path/to/install/lib -lusdr +``` + +- Using CMake `find_package` (CONFIG-mode) + +Create a small CMake project that uses the installed package (replace `/path/to/install` with your install prefix): + +```cmake +cmake_minimum_required(VERSION 3.8) +project(example C) +find_package(usdr CONFIG REQUIRED) +add_executable(example main.c) +target_link_libraries(example PRIVATE usdr::usdr) +``` + +Then configure and build: + +```bash +mkdir build && cd build +cmake -DCMAKE_PREFIX_PATH=/path/to/install .. +cmake --build . +``` + +If `find_package` fails, ensure the file `usdrConfig.cmake` is installed under `/lib/cmake/usdr/` (or the corresponding `libdir/cmake/usdr` for your system) and pass that prefix via `CMAKE_PREFIX_PATH`. + From 5fe4602c906ab75550722254169158106b91b1bb Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Thu, 19 Feb 2026 02:31:49 +0400 Subject: [PATCH 317/397] refactor: replace POSIX semaphores with usdr semaphores for macOS compatibility --- src/CMakeLists.txt | 8 +- src/lib/CMakeLists.txt | 4 +- src/lib/common/ring_buffer.c | 22 +-- src/lib/common/ring_buffer.h | 11 +- src/lib/common/ring_circbuf.c | 1 - src/lib/ipblks/si2c.h | 2 +- src/lib/ipblks/spiext.h | 2 +- src/lib/ipblks/xlnx_bitstream.c | 1 + src/lib/lowlevel/CMakeLists.txt | 2 + src/lib/lowlevel/libusb_generic.c | 51 +++--- src/lib/lowlevel/libusb_generic.h | 11 +- src/lib/lowlevel/pcie_uram/pcie_uram_main.c | 4 +- src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c | 19 +- src/lib/lowlevel/usb_uram/usb_uram_libusb.c | 45 +++-- src/lib/lowlevel/usdr_lowlevel.c | 4 +- .../lowlevel/verilator_ll/verilatorll_wrap.c | 34 ++-- src/lib/models/dm_debug.c | 2 +- src/lib/port/usdr_port.c | 168 ++++++++++++++++-- src/lib/port/usdr_port.h | 57 +++++- src/lib/xdsp/fmquad.c | 2 +- src/lib/xdsp/templates/conv_2ci16_ci16_neon.t | 4 +- src/lib/xdsp/templates/conv_4ci16_ci16_neon.t | 3 +- .../xdsp/templates/wvlt_sincos_i16_generic.t | 2 +- ...wvlt_sincos_i16_interleaved_ctrl_generic.t | 2 +- .../wvlt_sincos_i16_interleaved_ctrl_neon.t | 2 +- src/lib/xdsp/templates/wvlt_sincos_i16_neon.t | 2 +- src/tools/usdr_dm_gpsdo.c | 11 +- 27 files changed, 331 insertions(+), 145 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 86d6008c..003adb47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,11 +30,11 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") find_package(LIBUSB_1 REQUIRED) option(BUILD_SHARED_LIBS "Build shared libraries(otherwise static libraries will be produced)" ON) -option(ENABLE_DMONITOR "Enable debug tools" ON) +option(ENABLE_DMONITOR "Enable debug tools" OFF) option(ENABLE_VERILATOR "Enable verilator lowlevel bridge" OFF) -option(ENABLE_SOAPY "Enable SopaySDR support" ON) -option(ENABLE_GUI "Enable USDR QT5 simple GUI" ON) -option(ENABLE_TESTS "Enable tests" ON) +option(ENABLE_SOAPY "Enable SopaySDR support" OFF) +option(ENABLE_GUI "Enable USDR QT5 simple GUI" OFF) +option(ENABLE_TESTS "Enable tests" OFF) add_feature_info(VerilatorBridge ENABLE_VERILATOR "Verilator support for emulated devices") diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 78647913..4157987e 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -33,7 +33,9 @@ include_directories(${USDR_INCLUDE_DIRS}) add_library(usdr ${USDR_LIBRARY_FILES}) -if(NOT WIN32) +if (APPLE) + set(USDR_PLATFORM_LIBS dl) +elseif(NOT WIN32) set(USDR_PLATFORM_LIBS dl rt) else() set(USDR_PLATFORM_LIBS kernel32 ws2_32) diff --git a/src/lib/common/ring_buffer.c b/src/lib/common/ring_buffer.c index 7bc706fe..8936cbd9 100644 --- a/src/lib/common/ring_buffer.c +++ b/src/lib/common/ring_buffer.c @@ -24,17 +24,17 @@ struct ring_buffer* ring_buffer_create(unsigned items, unsigned isize) obj->pidx = 0; obj->cidx = 0; - res = sem_init(&obj->producer, 0, items); + res = usdr_sem_init(&obj->producer, 0, items); if (res) goto failed_s0; - res = sem_init(&obj->consumer, 0, 0); + res = usdr_sem_init(&obj->consumer, 0, 0); if (res) goto failed_s1; return obj; failed_s1: - sem_destroy(&obj->producer); + usdr_sem_destroy(&obj->producer); failed_s0: usdr_alignfree(obj); return NULL; @@ -42,8 +42,8 @@ struct ring_buffer* ring_buffer_create(unsigned items, unsigned isize) void ring_buffer_destroy(struct ring_buffer* rb) { - sem_destroy(&rb->producer); - sem_destroy(&rb->consumer); + usdr_sem_destroy(&rb->producer); + usdr_sem_destroy(&rb->consumer); usdr_alignfree(rb); } @@ -53,13 +53,13 @@ char* ring_buffer_at(struct ring_buffer* rb, unsigned idx) return &rb->data[rb->isize * int_idx]; } -static int ring_buffer_stdwait(sem_t* sem, int usecs) +static int ring_buffer_stdwait(usdr_sem_t* sem, int usecs) { int res; if (usecs == -1) { - res = sem_wait(sem); + res = usdr_sem_wait(sem); } else if (usecs == 0) { - res = sem_trywait(sem); + res = usdr_sem_trywait(sem); } else { struct timespec t; res = clock_gettime(CLOCK_REALTIME, &t); @@ -73,7 +73,7 @@ static int ring_buffer_stdwait(sem_t* sem, int usecs) t.tv_sec++; } - res = sem_timedwait(sem, &t); + res = usdr_sem_timedwait(sem, &t); } return res; } @@ -92,7 +92,7 @@ unsigned ring_buffer_pwait(struct ring_buffer* rb, int usecs) void ring_buffer_ppost(struct ring_buffer* rb) { - __attribute__((unused)) int res = sem_post(&rb->consumer); + __attribute__((unused)) int res = usdr_sem_post(&rb->consumer); assert(res == 0); } @@ -110,7 +110,7 @@ unsigned ring_buffer_cwait(struct ring_buffer* rb, int usecs) void ring_buffer_cpost(struct ring_buffer* rb) { - __attribute__((unused)) int res = sem_post(&rb->producer); + __attribute__((unused)) int res = usdr_sem_post(&rb->producer); assert(res == 0); } diff --git a/src/lib/common/ring_buffer.h b/src/lib/common/ring_buffer.h index 71778952..a64b68ea 100644 --- a/src/lib/common/ring_buffer.h +++ b/src/lib/common/ring_buffer.h @@ -5,7 +5,6 @@ #define RING_BUFFER_H #include -#include // Fixed size circular array struct ring_buffer @@ -17,15 +16,15 @@ struct ring_buffer unsigned cidx; #ifdef _WIN32 - sem_t producer; - sem_t consumer; + usdr_sem_t producer; + usdr_sem_t consumer; - char reserved[CACHE_SIZE - 4*sizeof(unsigned) - 2*sizeof(sem_t)]; + char reserved[CACHE_SIZE - 4*sizeof(unsigned) - 2*sizeof(usdr_sem_t)]; #else char reserved[CACHE_SIZE - 4*sizeof(unsigned)]; - sem_t producer; - sem_t consumer; + usdr_sem_t producer; + usdr_sem_t consumer; #endif char data[0]; diff --git a/src/lib/common/ring_circbuf.c b/src/lib/common/ring_circbuf.c index 1edc324b..1cbaffbe 100644 --- a/src/lib/common/ring_circbuf.c +++ b/src/lib/common/ring_circbuf.c @@ -1,7 +1,6 @@ #include "ring_circbuf.h" #include #include -#include #include // Can be MT-safe if rpos and wpos updated atomic diff --git a/src/lib/ipblks/si2c.h b/src/lib/ipblks/si2c.h index a344245e..d0b6b035 100644 --- a/src/lib/ipblks/si2c.h +++ b/src/lib/ipblks/si2c.h @@ -8,7 +8,7 @@ #ifndef SI2C_H #define SI2C_H -#if defined(__EMSCRIPTEN__) || defined(_WIN32) +#if defined(__EMSCRIPTEN__) || defined(_WIN32) || defined(__APPLE__) #include #include #else diff --git a/src/lib/ipblks/spiext.h b/src/lib/ipblks/spiext.h index a71c8900..250744c3 100644 --- a/src/lib/ipblks/spiext.h +++ b/src/lib/ipblks/spiext.h @@ -8,7 +8,7 @@ #ifndef SPIEXT_H #define SPIEXT_H -#if defined(__EMSCRIPTEN__) || defined(_WIN32) +#if defined(__EMSCRIPTEN__) || defined(_WIN32) || defined(__APPLE__) #include #include typedef uint8_t __u8; diff --git a/src/lib/ipblks/xlnx_bitstream.c b/src/lib/ipblks/xlnx_bitstream.c index bfd40918..30144fcf 100644 --- a/src/lib/ipblks/xlnx_bitstream.c +++ b/src/lib/ipblks/xlnx_bitstream.c @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MIT #include "xlnx_bitstream.h" +#include #include #include #include diff --git a/src/lib/lowlevel/CMakeLists.txt b/src/lib/lowlevel/CMakeLists.txt index 887cbd83..0fba5425 100644 --- a/src/lib/lowlevel/CMakeLists.txt +++ b/src/lib/lowlevel/CMakeLists.txt @@ -14,6 +14,8 @@ if(NOT EMSCRIPTEN) add_subdirectory(pcie_uram) endif() +include_directories(${LIBUSB_1_INCLUDE_DIRS}) + add_subdirectory(usb_uram) add_subdirectory(usb_ft601) diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index 39f7b238..d2ebaa15 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -48,11 +48,16 @@ unsigned find_usb_match(libusb_device **usbdev, size_t devices, struct matched_devs* md = &devs[k]; res = libusb_get_device_descriptor(usbdev[i], &desc); - if (res) + if (res) { + USDR_LOG("USBX", USDR_LOG_ERROR, "Unable to get device descriptor for device %d: %s\n", i, libusb_strerror(res)); continue; + } - j = libusb_find_dev_index_ex( busname,desc.idProduct, desc.idVendor, known_devices, known_device_count ); - if( j < 0 ) continue; + j = libusb_find_dev_index_ex(busname, desc.idProduct, desc.idVendor, known_devices, known_device_count ); + if (j < 0) { + USDR_LOG("USBX", USDR_LOG_ERROR, "Skipping device %s: %04x:%04x, not in known devices list\n", busname, desc.idVendor, desc.idProduct); + continue; + } md->uuid_idx = j; md->sdrtype = libusb_get_dev_sdrtype(j); @@ -65,7 +70,7 @@ unsigned find_usb_match(libusb_device **usbdev, size_t devices, md->devid = (unsigned)bus * 1000000 + (unsigned)port * 1000 + addr; snprintf(md->devid_s, sizeof(md->devid_s), "%d/%d/%d", bus, port, addr); - USDR_LOG("USBX", USDR_LOG_DEBUG, "checking device %04x:%04x %d/%d/%d against %d/%d/%d mask devid=%d\n", + USDR_LOG("USBX", USDR_LOG_ERROR, "checking device %04x:%04x %d/%d/%d against %d/%d/%d mask devid=%d\n", desc.idVendor, desc.idProduct, fparams->usb_bus, fparams->usb_port, fparams->usb_addr, bus, port, addr, j); @@ -214,8 +219,8 @@ int libusb_generic_plugin_create(unsigned pcount, const char** devparam, fcnt = find_usb_match(usbdev, devices, &fparams, 1, &md , known_devs, known_devs_cnt, busname); if (fcnt == 0) { USDR_LOG("USBX", USDR_LOG_NOTE, - "No USB device was found to match %d/%d/%d\n", - fparams.usb_bus, fparams.usb_port, fparams.usb_addr); + "No USB device was found to match %d/%d/%d, total=%d\n", + fparams.usb_bus, fparams.usb_port, fparams.usb_addr, devices); libusb_exit(uctx); return -ENODEV; } @@ -310,7 +315,7 @@ void* libusb_generic_io_thread(void *arg) #if defined(__linux) || defined(__APPLE__) sigset_t set; - pthread_setname_np(pthread_self(), "usb_io"); + usdr_set_thread_name("usb_io"); sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); @@ -374,12 +379,12 @@ int buffers_init(struct buffers* rb, unsigned max, unsigned zerosemval, bool has rb->buf_available = rb->buf_max = max; - if (sem_init(&rb->buf_ready, 0, zerosemval)) { + if (usdr_sem_init(&rb->buf_ready, 0, zerosemval)) { return -errno; } if (has_event) { -#ifdef WIN32 +#ifndef __linux__ rb->fd_event = -ENOTSUP; #else rb->fd_event = fdevent_create(zerosemval); @@ -418,10 +423,10 @@ void buffers_deinit(struct buffers* rb) // TODO Add synchronization to get all outstanging endpoints usleep(10000); - sem_destroy(&rb->buf_ready); + usdr_sem_destroy(&rb->buf_ready); // usdr_alignfree(rb->rqueuebuf_ptr); // free(rb->bd); -#ifndef WIN32 +#ifdef __linux__ if (rb->fd_event >= 0) fdevent_destroy(rb->fd_event); #endif @@ -477,10 +482,10 @@ void buffers_reset(struct buffers* rb) rb->bufno_cons = 0; rb->bufno_prod = 0; rb->buf_available = rb->buf_max; - sem_destroy(&rb->buf_ready); - sem_init(&rb->buf_ready, 0, 0); + usdr_sem_destroy(&rb->buf_ready); + usdr_sem_init(&rb->buf_ready, 0, 0); -#ifndef WIN32 +#ifdef __linux__ if (rb->fd_event > 0) fdevent_get(rb->fd_event, NULL); #endif @@ -502,13 +507,13 @@ int buffers_ready_wait(struct buffers *rxb, int64_t timeout_us) { int res; if (rxb->fd_event >= 0) { -#ifndef WIN32 +#ifdef __linux__ res = fdevent_get(rxb->fd_event, NULL); #else res = -ENOTSUP; #endif } else { - res = sem_wait_ex(&rxb->buf_ready, timeout_us * 1000); + res = usdr_sem_wait_ex(&rxb->buf_ready, timeout_us * 1000); } return res; } @@ -517,13 +522,13 @@ int buffers_ready_post(struct buffers *rxb) { int res; if (rxb->fd_event >= 0) { -#ifndef WIN32 +#ifdef __linux__ res = fdevent_post(rxb->fd_event, 1); #else res = -ENOTSUP; #endif } else { - res = sem_post(&rxb->buf_ready); + res = usdr_sem_post(&rxb->buf_ready); } return res; } @@ -706,7 +711,7 @@ int buffers_usb_free(struct buffers *prxb) // Helpers -int sem_wait_ex(sem_t *s, int64_t timeout_ns) +int usdr_sem_wait_ex(usdr_sem_t *s, int64_t timeout_ns) { int res; if (timeout_ns > 0) { @@ -720,17 +725,17 @@ int sem_wait_ex(sem_t *s, int64_t timeout_ns) ts.tv_sec += secs; timeout_ns -= (int64_t)1000 * 1000 * 1000 * secs; - ts.tv_nsec += timeout_ns * 1000; + ts.tv_nsec += timeout_ns; while (ts.tv_nsec > 1000 * 1000 * 1000) { ts.tv_nsec -= 1000 * 1000 * 1000; ts.tv_sec++; } - res = sem_timedwait(s, &ts); + res = usdr_sem_timedwait(s, &ts); } else if (timeout_ns < 0) { - res = sem_wait(s); + res = usdr_sem_wait(s); } else { - res = sem_trywait(s); + res = usdr_sem_trywait(s); } if (res) { // sem_* function on error returns -1, get proper error diff --git a/src/lib/lowlevel/libusb_generic.h b/src/lib/lowlevel/libusb_generic.h index 5b57623e..ffc6031e 100644 --- a/src/lib/lowlevel/libusb_generic.h +++ b/src/lib/lowlevel/libusb_generic.h @@ -7,15 +7,8 @@ #include #include #include - -#ifdef WIN32 #include -#else -#include -#endif - #include -#include #include #include @@ -153,7 +146,7 @@ int libusb_generic_stop_thread(libusb_generic_dev_t *dev); // Return -errno if fails -int sem_wait_ex(sem_t *s, int64_t timeout_ns); +int usdr_sem_wait_ex(usdr_sem_t *s, int64_t timeout_ns); // Buffers @@ -170,7 +163,7 @@ struct buffer_discriptor struct buffers { - sem_t buf_ready; + usdr_sem_t buf_ready; uint8_t* rqueuebuf_ptr; // cache aligned pointer to rx_queuebuf diff --git a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c index bcaf9b06..a5443c1e 100644 --- a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c +++ b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c @@ -1,6 +1,6 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT -#ifndef WIN32 +#ifdef __linux__ #include "pcie_uram_main.h" @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include "../device/device.h" diff --git a/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c b/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c index 581caf56..02acb1b9 100644 --- a/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c +++ b/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "../device/device.h" @@ -31,8 +30,8 @@ struct usbft601_dev libusb_generic_dev_t gdev; usb_ft601_generic_t ft601_generic; - sem_t tr_ctrl_out; - sem_t tr_ctrl_rb; + usdr_sem_t tr_ctrl_out; + usdr_sem_t tr_ctrl_rb; unsigned len_ctrl_in_rb; struct libusb_transfer *transfer_in_ctrl[MAX_IN_CTRL_REQS]; @@ -78,7 +77,7 @@ int usbft601_uram_ctrl_out_pkt(lldev_t lld, unsigned pkt_szb, unsigned timeout_m { usbft601_dev_t* d = (usbft601_dev_t*)lld; int res; - res = sem_wait_ex(&d->tr_ctrl_out, timeout_ms * 1000 * 1000); + res = usdr_sem_wait_ex(&d->tr_ctrl_out, timeout_ms * 1000 * 1000); if (res) { return res; } @@ -92,7 +91,7 @@ int usbft601_uram_ctrl_out_pkt(lldev_t lld, unsigned pkt_szb, unsigned timeout_m res = libusb_to_errno(libusb_submit_transfer(transfer)); if (res) { USDR_LOG("USBX", USDR_LOG_ERROR, "FAILED to post CTRL_OUT %d\n", res); - sem_post(&d->tr_ctrl_out); + usdr_sem_post(&d->tr_ctrl_out); return res; } @@ -141,13 +140,13 @@ int usbft601_uram_ctrl_in_pkt(lldev_t lld, unsigned pkt_szb, unsigned timeout_ms static int usbft601_sem_ctrl_rb_wait(lldev_t lld, int64_t timeout) { usbft601_dev_t* d = (usbft601_dev_t*)lld; - return sem_wait_ex(&d->tr_ctrl_rb, timeout); + return usdr_sem_wait_ex(&d->tr_ctrl_rb, timeout); } static void usbft601_sem_ctrl_out_post(lldev_t lld) { usbft601_dev_t* d = (usbft601_dev_t*)lld; - sem_post(&d->tr_ctrl_out); + usdr_sem_post(&d->tr_ctrl_out); } void LIBUSB_CALL libusb_transfer_ctrl_rb(struct libusb_transfer *transfer) @@ -169,7 +168,7 @@ void LIBUSB_CALL libusb_transfer_ctrl_rb(struct libusb_transfer *transfer) return; } - sem_post(&dev->tr_ctrl_rb); + usdr_sem_post(&dev->tr_ctrl_rb); } static @@ -431,12 +430,12 @@ int usbft601_uram_async_start(lldev_t lld) int res; usbft601_dev_t* dev = (usbft601_dev_t*)lld; - res = sem_init(&dev->tr_ctrl_out, 0, MAX_OUT_CTRL_REQS); + res = usdr_sem_init(&dev->tr_ctrl_out, 0, MAX_OUT_CTRL_REQS); if (res) { goto failed_prepare; } - res = sem_init(&dev->tr_ctrl_rb, 0, 0); + res = usdr_sem_init(&dev->tr_ctrl_rb, 0, 0); if (res) { goto failed_prepare; } diff --git a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c index 60c71f51..ea8dbc19 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "usb_uram_generic.h" #include "../device/device.h" @@ -93,13 +92,13 @@ struct usb_dev libusb_generic_dev_t gdev; usb_uram_generic_t uram_generic; - sem_t interrupts[MAX_INTERRUPTS]; + usdr_sem_t interrupts[MAX_INTERRUPTS]; uint32_t rbvalue[MAX_INTERRUPTS]; bool stop; - sem_t tr_regout_a; - sem_t tr_rb_a; - sem_t rb_valid[MAX_RB_THREADS]; + usdr_sem_t tr_regout_a; + usdr_sem_t tr_rb_a; + usdr_sem_t rb_valid[MAX_RB_THREADS]; struct libusb_transfer *transfer_regout[MAX_REGOUT_REQS]; struct libusb_transfer *transfer_rb[MAX_RB_REQS]; @@ -147,13 +146,13 @@ int usb_async_start(usb_dev_t* dev) int res; unsigned i; for (i = 0; i < MAX_INTERRUPTS; i++) { - res = sem_init(&dev->interrupts[i], 0, 0); + res = usdr_sem_init(&dev->interrupts[i], 0, 0); } - res = sem_init(&dev->tr_regout_a, 0, MAX_REGOUT_REQS); - res = sem_init(&dev->tr_rb_a, 0, MAX_RB_REQS); + res = usdr_sem_init(&dev->tr_regout_a, 0, MAX_REGOUT_REQS); + res = usdr_sem_init(&dev->tr_rb_a, 0, MAX_RB_REQS); for (i = 0; i < MAX_RB_THREADS; i++) { - res = sem_init(&dev->rb_valid[i], 0, 0); + res = usdr_sem_init(&dev->rb_valid[i], 0, 0); } // Prepare transfer queues @@ -232,7 +231,7 @@ static int usb_post_regout(usb_dev_t* dev, uint32_t *regoutbuffer, unsigned coun dev->gdev.name, count_dw, tot_wrs, tot_rbs, tot_reqlen_dw, s_dump_buffer(regoutbuffer, count_dw * 4)); - res = sem_wait(&dev->tr_regout_a); + res = usdr_sem_wait(&dev->tr_regout_a); if (res) { res = -errno; return res; @@ -258,7 +257,7 @@ static int usb_post_regout(usb_dev_t* dev, uint32_t *regoutbuffer, unsigned coun static int usb_post_rb(usb_dev_t* dev, uint32_t* buffer, unsigned max_buffer_dw, unsigned* ridx) { int res; - res = sem_wait(&dev->tr_rb_a); + res = usdr_sem_wait(&dev->tr_rb_a); if (res) { res = -errno; return res; @@ -291,7 +290,7 @@ void LIBUSB_CALL libusb_transfer_regout(struct libusb_transfer *transfer) return; } - sem_post(&dev->tr_regout_a); + usdr_sem_post(&dev->tr_regout_a); } void LIBUSB_CALL libusb_transfer_rb(struct libusb_transfer *transfer) @@ -308,12 +307,12 @@ void LIBUSB_CALL libusb_transfer_rb(struct libusb_transfer *transfer) transfer->status, transfer->actual_length); return; } - sem_post(&dev->tr_rb_a); + usdr_sem_post(&dev->tr_rb_a); //Signal reply ready unsigned pidx = (*arefptr) & (MAX_RB_THREADS - 1); *arefptr = alen; - sem_post(&dev->rb_valid[pidx]); + usdr_sem_post(&dev->rb_valid[pidx]); } void LIBUSB_CALL libusb_transfer_ntfy(struct libusb_transfer *transfer) @@ -357,7 +356,7 @@ void LIBUSB_CALL libusb_transfer_ntfy(struct libusb_transfer *transfer) USDR_LOG("USBX", USDR_LOG_NOTE, "Got notification seq %04x event %d => %08x\n", seqnum, event, buff[i + 1]); dev->rbvalue[event] = buff[++i]; - sem_post(&dev->interrupts[event]); + usdr_sem_post(&dev->interrupts[event]); } else if ((i + 1 + blen) < packet_len / 4) { i += blen + 1; @@ -408,7 +407,7 @@ static int usb_async_regread32(lldev_t d, unsigned addr, uint32_t* data, unsigne if (res) { return res; } - res = sem_wait(&dev->rb_valid[idx]); + res = usdr_sem_wait(&dev->rb_valid[idx]); if (res) { res = -errno; return res; @@ -439,7 +438,7 @@ int usb_uram_generic_get(lldev_t dev, int generic_op, const char** pout) static int usb_uram_wait_msi(usb_dev_t* dev, unsigned i, int timeout_ms) { - return sem_wait_ex(&dev->interrupts[i], timeout_ms * 1000); + return usdr_sem_wait_ex(&dev->interrupts[i], timeout_ms * 1000 * 1000); } static int usb_read_bus(lldev_t dev, unsigned interrupt_number, UNUSED unsigned reg, size_t meminsz, void* pin) @@ -824,12 +823,12 @@ int usb_uram_destroy(lldev_t dev) libusb_close(d->gdev.dh); for (unsigned i = 0; i < MAX_INTERRUPTS; i++) - sem_destroy(&d->interrupts[i]); + usdr_sem_destroy(&d->interrupts[i]); - sem_destroy(&d->tr_regout_a); - sem_destroy(&d->tr_rb_a); + usdr_sem_destroy(&d->tr_regout_a); + usdr_sem_destroy(&d->tr_rb_a); for (unsigned i = 0; i < MAX_RB_THREADS; i++) - sem_destroy(&d->rb_valid[i]); + usdr_sem_destroy(&d->rb_valid[i]); free(d); return 0; @@ -911,7 +910,7 @@ int usb_uram_plugin_create(unsigned pcount, const char** devparam, } for (unsigned i = 0; i < MAX_INTERRUPTS; i++) { - res = sem_init(&dev->interrupts[i], 0, 0); + res = usdr_sem_init(&dev->interrupts[i], 0, 0); if (res) goto usballoc_fail; } @@ -948,7 +947,7 @@ int usb_uram_plugin_create(unsigned pcount, const char** devparam, //usb_async_stop(dev->mgr); usb_astart_fail: for (unsigned i = 0; i < MAX_INTERRUPTS; i++) { - sem_destroy(&dev->interrupts[i]); + usdr_sem_destroy(&dev->interrupts[i]); } usballoc_fail: free(dev); diff --git a/src/lib/lowlevel/usdr_lowlevel.c b/src/lib/lowlevel/usdr_lowlevel.c index cc46dfc1..ef313785 100644 --- a/src/lib/lowlevel/usdr_lowlevel.c +++ b/src/lib/lowlevel/usdr_lowlevel.c @@ -60,9 +60,9 @@ unsigned lowlevel_initialize_plugins() } //TODO driver loading - plugins[s_driver_count++] = usbft601_uram_register(); plugins[s_driver_count++] = usb_uram_register(); -#if !defined(__EMSCRIPTEN__) && !defined(WVLT_WEBUSB_BUILD) && !defined(WIN32) + plugins[s_driver_count++] = usbft601_uram_register(); +#if !defined(__EMSCRIPTEN__) && !defined(WVLT_WEBUSB_BUILD) && !defined(WIN32) && !defined(__APPLE__) plugins[s_driver_count++] = pcie_uram_register(); #endif diff --git a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c index c904412e..2bea5a23 100644 --- a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c +++ b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c @@ -12,10 +12,10 @@ #include #include #include -#include #include #include +#include #include #include @@ -49,8 +49,8 @@ struct rbdata { struct verilator_protocol_unix { - sem_t tags[MAX_TAGS]; - sem_t tags_avail; + usdr_sem_t tags[MAX_TAGS]; + usdr_sem_t tags_avail; uint32_t tags_free_idx; @@ -68,12 +68,12 @@ int vpu_init(verilator_protocol_unix_t* pvpu, const char* dev) int res; for (unsigned i = 0; i < MAX_INTERRUPTS; i++) { - res = sem_init(&pvpu->tags[i], 0, 0); + res = usdr_sem_init(&pvpu->tags[i], 0, 0); if (res) goto sem_tag_fail; } - res = sem_init(&pvpu->tags_avail, 0, 1); + res = usdr_sem_init(&pvpu->tags_avail, 0, 1); if (res) goto sem_tag_avail_fail; @@ -122,7 +122,7 @@ struct verilator_dev device_id_t devid; device_bus_t db; - sem_t interrupts[MAX_INTERRUPTS]; + usdr_sem_t interrupts[MAX_INTERRUPTS]; verilator_protocol_unix_t proto; bool terminated; @@ -184,7 +184,7 @@ int verilator_process_recv(verilator_dev_t* dev) USDR_LOG("VERI", USDR_LOG_TRACE, "Readback #%d => %08x\n", hdr.tag, buffer[0]); memcpy(dev->proto.rb[hdr.tag].data, buffer, hdr.size - sizeof(hdr)); - res = sem_post(&dev->proto.tags[hdr.tag]); + res = usdr_sem_post(&dev->proto.tags[hdr.tag]); if (res) return res; @@ -195,7 +195,7 @@ int verilator_process_recv(verilator_dev_t* dev) return -EFAULT; USDR_LOG("VERI", USDR_LOG_TRACE, "Interrupt %d\n", hdr.tag); #ifdef OLD_INTERRUPTS - res = sem_post(&dev->interrupts[hdr.tag]); + res = usdr_sem_post(&dev->interrupts[hdr.tag]); if (res) return res; #else @@ -259,7 +259,7 @@ int verilator_process_recv(verilator_dev_t* dev) } for (;;) { - res = sem_post(&dev->interrupts[irq]); + res = usdr_sem_post(&dev->interrupts[irq]); if (res) return res; if (irq != 0) @@ -317,7 +317,7 @@ int verilator_process_recv(verilator_dev_t* dev) } for (;;) { - res = sem_post(&dev->interrupts[irq]); + res = usdr_sem_post(&dev->interrupts[irq]); if (res) return res; if (irq != 0) @@ -342,7 +342,7 @@ static int verilator_tag_alloc(verilator_protocol_unix_t* dev) { int res, tag = -1; - res = sem_wait(&dev->tags_avail); + res = usdr_sem_wait(&dev->tags_avail); if (res) return res; @@ -362,7 +362,7 @@ static int verilator_tag_release(verilator_protocol_unix_t* dev, unsigned tag) { int res; - res = sem_post(&dev->tags_avail); + res = usdr_sem_post(&dev->tags_avail); if (res) return res; @@ -381,7 +381,7 @@ int verilator_in(verilator_dev_t* dev, unsigned addr, uint32_t *pinval, const un if (res < 0) return res; - res = sem_wait(&dev->proto.tags[tag]); + res = usdr_sem_wait(&dev->proto.tags[tag]); if (res) return res; @@ -570,11 +570,11 @@ static int verilator_wrap_wait_msi(verilator_dev_t* dev, unsigned i, int timeout ts.tv_nsec -= 1000 * 1000 * 1000; ts.tv_sec++; } - res = sem_timedwait(&dev->interrupts[i], &ts); + res = usdr_sem_timedwait(&dev->interrupts[i], &ts); } else if (timeout_ms < 0) { - res = sem_wait(&dev->interrupts[i]); + res = usdr_sem_wait(&dev->interrupts[i]); } else { - res = sem_trywait(&dev->interrupts[i]); + res = usdr_sem_trywait(&dev->interrupts[i]); } if (res) { // sem_* function on error returns -1, get proper error @@ -910,7 +910,7 @@ int verilator_wrap_plugin_create(unsigned pcount, const char** devparam, strncpy(dev->devid_str, usdr_device_id_to_str(did), sizeof(dev->devid_str) - 1); for (unsigned i = 0; i < MAX_INTERRUPTS; i++) { - res = sem_init(&dev->interrupts[i], 0, 0); + res = usdr_sem_init(&dev->interrupts[i], 0, 0); if (res) goto alloc_fail; } diff --git a/src/lib/models/dm_debug.c b/src/lib/models/dm_debug.c index b77ab398..92721fbe 100644 --- a/src/lib/models/dm_debug.c +++ b/src/lib/models/dm_debug.c @@ -92,7 +92,7 @@ static void* usdr_dif_thread(void* param) #ifndef _WIN32 sigset_t set; - pthread_setname_np(pthread_self(), "debug_io"); + usdr_set_thread_name("debug_io"); sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, NULL); #endif diff --git a/src/lib/port/usdr_port.c b/src/lib/port/usdr_port.c index be175a48..991e9ba8 100644 --- a/src/lib/port/usdr_port.c +++ b/src/lib/port/usdr_port.c @@ -88,35 +88,100 @@ void* usdr_lib_sym(library_hdl_t h, const char* proc) #ifdef __APPLE__ #include #include +#include +#include +#include /** - * A wrapper for sem_timedwait functionality using Mach semaphores. - * @param sem The Mach semaphore_t to wait on. - * @param abs_timeout The absolute wall-clock time to wait until. - * @return 0 on success, -1 on error (with errno set). + * Cross-platform semaphore implementation using Mach semaphores on macOS */ -int mach_sem_timedwait(semaphore_t sem, const struct timespec *abs_timeout) { + +int usdr_sem_init(usdr_sem_t *sem, int pshared, unsigned int value) { + (void)pshared; // Mach semaphores don't support pshared + kern_return_t kr = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, (int)value); + if (kr != KERN_SUCCESS) { + errno = ENOMEM; + return -1; + } + return 0; +} + +int usdr_sem_destroy(usdr_sem_t *sem) { + kern_return_t kr = semaphore_destroy(mach_task_self(), *sem); + if (kr != KERN_SUCCESS) { + errno = EINVAL; + return -1; + } + return 0; +} + +int usdr_sem_post(usdr_sem_t *sem) { + kern_return_t kr = semaphore_signal(*sem); + if (kr != KERN_SUCCESS) { + errno = EINVAL; + return -1; + } + return 0; +} + +int usdr_sem_wait(usdr_sem_t *sem) { + kern_return_t kr; + do { + kr = semaphore_wait(*sem); + } while (kr == KERN_ABORTED); // Handle spurious wakeups + + if (kr != KERN_SUCCESS) { + errno = EINVAL; + return -1; + } + return 0; +} + +int usdr_sem_trywait(usdr_sem_t *sem) { + mach_timespec_t zero_timeout = {0, 0}; + kern_return_t kr = semaphore_timedwait(*sem, zero_timeout); + + if (kr == KERN_SUCCESS) { + return 0; + } else if (kr == KERN_OPERATION_TIMED_OUT) { + errno = EAGAIN; + return -1; + } else { + errno = EINVAL; + return -1; + } +} + +int usdr_sem_timedwait(usdr_sem_t *sem, const struct timespec *abs_timeout) { // 1. Get current wall-clock time struct timespec now; clock_gettime(CLOCK_REALTIME, &now); - // 2. Calculate relative timeout in nanoseconds - int64_t rel_ns = (abs_timeout->tv_sec - now.tv_sec) * 1000000000LL + - (abs_timeout->tv_nsec - now.tv_nsec); + // 2. Calculate relative timeout + int64_t rel_sec = abs_timeout->tv_sec - now.tv_sec; + int64_t rel_nsec = abs_timeout->tv_nsec - now.tv_nsec; - if (rel_ns <= 0) { - // Time has already passed - return (semaphore_wait_noblock(sem) == KERN_SUCCESS) ? 0 : (errno = ETIMEDOUT, -1); + // Normalize nanoseconds + if (rel_nsec < 0) { + rel_sec--; + rel_nsec += 1000000000LL; } - // 3. Convert relative nanoseconds to Mach ticks (deadline) - mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); - uint64_t rel_ticks = rel_ns * timebase.denom / timebase.numer; - uint64_t deadline = mach_absolute_time() + rel_ticks; + if (rel_sec < 0) { + // Time has already passed, try a non-blocking wait + return usdr_sem_trywait(sem); + } + + // 3. Convert to mach_timespec_t (relative timeout) + mach_timespec_t wait_time; + wait_time.tv_sec = (unsigned int)rel_sec; + wait_time.tv_nsec = (clock_res_t)rel_nsec; // 4. Perform the wait - kern_return_t kr = semaphore_wait_deadline(sem, deadline); + kern_return_t kr; + do { + kr = semaphore_timedwait(*sem, wait_time); + } while (kr == KERN_ABORTED); // Handle spurious wakeups if (kr == KERN_SUCCESS) { return 0; @@ -129,6 +194,75 @@ int mach_sem_timedwait(semaphore_t sem, const struct timespec *abs_timeout) { } } +#else +/* Non-Apple: use POSIX semaphores */ +#include +#include +#include + +int usdr_sem_init(usdr_sem_t *sem, int pshared, unsigned int value) { + return sem_init(sem, pshared, value); +} + +int usdr_sem_destroy(usdr_sem_t *sem) { + return sem_destroy(sem); +} + +int usdr_sem_post(usdr_sem_t *sem) { + return sem_post(sem); +} + +int usdr_sem_wait(usdr_sem_t *sem) { + return sem_wait(sem); +} + +int usdr_sem_trywait(usdr_sem_t *sem) { + return sem_trywait(sem); +} + +int usdr_sem_timedwait(usdr_sem_t *sem, const struct timespec *abs_timeout) { + return sem_timedwait(sem, abs_timeout); +} + +#endif + +/** + * Cross-platform thread naming implementation + */ +int usdr_set_thread_name(const char* name) { +#ifdef _WIN32 + // Windows: SetThreadDescription requires Windows 10 1607+ + // For older versions, we'd need to use the SEH exception trick + // For now, just return success without doing anything + (void)name; + return 0; +#elif defined(__APPLE__) + // macOS: pthread_setname_np takes only the name, sets current thread + return pthread_setname_np(name); +#elif defined(__linux__) + // Linux: pthread_setname_np takes thread and name + return pthread_setname_np(pthread_self(), name); +#else + // Unknown platform + (void)name; + return 0; +#endif +} + +/** + * sincosf implementation for macOS + * Computes sine and cosine of x simultaneously + * On Linux this is a GNU extension, but macOS doesn't provide it + */ +#ifdef __APPLE__ +#include + +void sincosf(float x, float *sin_val, float *cos_val) { + // macOS provides __sincosf_stret on some versions, but it's not reliable + // Use the straightforward implementation + *sin_val = sinf(x); + *cos_val = cosf(x); +} #endif diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index 4ebb7f99..51a80c22 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -23,6 +23,7 @@ #define be32toh(x) ntohl(x) #elif defined(__APPLE__) #include +#include #include #include @@ -31,6 +32,23 @@ #include #include + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define htole16(x) OSSwapHostToLittleInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define le16toh(x) OSSwapLittleToHostInt16(x) + +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) + +#define htobe64(x) OSSwapHostToBigInt64(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) + + #else #include #include @@ -79,8 +97,6 @@ static inline void usdr_alignfree(void* ptr) { #define localtime_r(T,Tm) (localtime_s(Tm,T) ? NULL : Tm) -#define ENAVAIL ENOENT - static inline int gettid(void) { return GetCurrentThreadId(); @@ -115,13 +131,46 @@ int asprintf(char **strp, const char *fmt, ...) __attribute__ ((format (printf, #endif +/** + * Cross-platform semaphore abstraction + * Uses Mach semaphores on macOS, POSIX semaphores elsewhere + */ #ifdef __APPLE__ -int mach_sem_timedwait(semaphore_t sem, const struct timespec *abs_timeout); -#define sem_timedwait mach_sem_timedwait +typedef semaphore_t usdr_sem_t; +#else +#include +typedef sem_t usdr_sem_t; +#endif + +int usdr_sem_init(usdr_sem_t *sem, int pshared, unsigned int value); +int usdr_sem_destroy(usdr_sem_t *sem); +int usdr_sem_post(usdr_sem_t *sem); +int usdr_sem_wait(usdr_sem_t *sem); +int usdr_sem_trywait(usdr_sem_t *sem); +int usdr_sem_timedwait(usdr_sem_t *sem, const struct timespec *abs_timeout); + +/** + * Cross-platform thread naming + * Sets the name of the current thread for debugging purposes + * @param name Thread name (max 15 characters on Linux, 63 on macOS) + * @return 0 on success, -1 on error + */ +int usdr_set_thread_name(const char* name); + +/** + * sincosf - compute sine and cosine simultaneously + * Available natively on Linux (GNU extension), needs implementation on macOS/Windows + */ +#ifdef __APPLE__ +#include +void sincosf(float x, float *sin_val, float *cos_val); #endif #define CACHE_SIZE 64 +#if defined(_WIN32) || defined(__APPLE__) +#define ENAVAIL ENOENT +#endif #ifdef __cplusplus }; diff --git a/src/lib/xdsp/fmquad.c b/src/lib/xdsp/fmquad.c index b9e65d4f..5da5d587 100644 --- a/src/lib/xdsp/fmquad.c +++ b/src/lib/xdsp/fmquad.c @@ -23,7 +23,7 @@ float quadfm_encode(unsigned samples, float fi, fq; iangle += da; - sincosf(iangle, &fq, &fi); + //sincosf(iangle, &fq, &fi); int16_t vi, vq; vi = (int16_t)(fi * 0.7f * 32767.0f); diff --git a/src/lib/xdsp/templates/conv_2ci16_ci16_neon.t b/src/lib/xdsp/templates/conv_2ci16_ci16_neon.t index 8335d69c..a626dcc1 100644 --- a/src/lib/xdsp/templates/conv_2ci16_ci16_neon.t +++ b/src/lib/xdsp/templates/conv_2ci16_ci16_neon.t @@ -15,8 +15,8 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, while(i >= 32) { - vst2q_u32((uint32_t*)outdata, - (uint32x4x2_t){ {vld1q_u32((uint32_t*)indata_0), vld1q_u32((uint32_t*)indata_1)} }); + uint32x4x2_t z = {vld1q_u32((uint32_t*)indata_0), vld1q_u32((uint32_t*)indata_1)}; + vst2q_u32((uint32_t*)outdata, z); i -= 32; indata_0 += 8; diff --git a/src/lib/xdsp/templates/conv_4ci16_ci16_neon.t b/src/lib/xdsp/templates/conv_4ci16_ci16_neon.t index e79fe7d0..9aa6dfe3 100644 --- a/src/lib/xdsp/templates/conv_4ci16_ci16_neon.t +++ b/src/lib/xdsp/templates/conv_4ci16_ci16_neon.t @@ -20,8 +20,9 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata_0_p, while(i >= 64) { + uint32x4x4_t z = {vld1q_u32(indata_0), vld1q_u32(indata_1), vld1q_u32(indata_2), vld1q_u32(indata_3)}; vst4q_u32((uint32_t*)outdata, - (uint32x4x4_t){ {vld1q_u32(indata_0), vld1q_u32(indata_1), vld1q_u32(indata_2), vld1q_u32(indata_3)} }); + z); i -= 64; indata_0 += 4; diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t b/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t index e8e88fa9..69651901 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t @@ -17,7 +17,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, { const float ph = WVLT_SINCOS_I16_PHSCALE * *phase++; float ssin, scos; - sincosf(ph, &ssin, &scos); + //sincosf(ph, &ssin, &scos); *sindata++ = ssin * WVLT_SINCOS_I16_SCALE; *cosdata++ = scos * WVLT_SINCOS_I16_SCALE; i -= 2; diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t index 6bd65779..cd826fa9 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t @@ -17,7 +17,7 @@ void TEMPLATE_FUNC_NAME(int32_t *__restrict start_phase, const float ph = WVLT_SINCOS_I32_PHSCALE * phase; float ssin, scos; - sincosf(ph, &ssin, &scos); + //sincosf(ph, &ssin, &scos); *outdata++ = ssin * gain * sign_sin; *outdata++ = scos * gain * sign_cos; diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t index 1b0e7f66..ee2b5160 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t @@ -66,7 +66,7 @@ void TEMPLATE_FUNC_NAME(int32_t *__restrict start_phase, const float ph = WVLT_SINCOS_I32_PHSCALE * phase; float ssin, scos; - sincosf(ph, &ssin, &scos); + //sincosf(ph, &ssin, &scos); *outdata++ = ssin * gain * sign_sin; *outdata++ = scos * gain * sign_cos; diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t b/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t index 4d14a8c8..1c35fe69 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t @@ -36,7 +36,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, { const float ph = WVLT_SINCOS_I16_PHSCALE * *phase++; float ssin, scos; - sincosf(ph, &ssin, &scos); + //sincosf(ph, &ssin, &scos); *sindata++ = ssin * WVLT_SINCOS_I16_SCALE; *cosdata++ = scos * WVLT_SINCOS_I16_SCALE; i -= 2; diff --git a/src/tools/usdr_dm_gpsdo.c b/src/tools/usdr_dm_gpsdo.c index d8c0c610..eeac4e21 100644 --- a/src/tools/usdr_dm_gpsdo.c +++ b/src/tools/usdr_dm_gpsdo.c @@ -13,7 +13,7 @@ #include #include #include -#ifndef WIN32 +#ifdef __linux__ #include #include #endif @@ -261,7 +261,7 @@ int main(int argc, char **argv) struct timespec start_time; clock_gettime(CLOCK_MONOTONIC, &start_time); -#ifndef WIN32 +#ifdef __linux__ // Create timerfd for 100 ms polling int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); if (timer_fd == -1) { @@ -290,9 +290,12 @@ int main(int argc, char **argv) while (true) { // Wait for timer event -#ifdef WIN32 +#ifdef _WIN32 Sleep(100); { +#elif defined(__APPLE__) + usleep(100000); // 100 ms + { #else int ret = poll(fds, 1, -1); if (ret == -1) { @@ -371,7 +374,7 @@ int main(int argc, char **argv) } } -#ifndef WIN32 +#ifdef __linux__ close(timer_fd); #endif usdr_dmd_close(dev); From 98455011a5a43042e353b66ae37bb76c26a06d50 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Fri, 20 Feb 2026 23:30:09 +0400 Subject: [PATCH 318/397] build: fix pkg-config paths and add URL to usdr.pc --- src/cmake/usdr.pc.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cmake/usdr.pc.in b/src/cmake/usdr.pc.in index 850290f3..71e54fdf 100644 --- a/src/cmake/usdr.pc.in +++ b/src/cmake/usdr.pc.in @@ -1,10 +1,11 @@ prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} +exec_prefix=${prefix}/@CMAKE_INSTALL_BINDIR@ libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ -includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/usdr Name: @PACKAGE_NAME@ Description: usdr library +URL: https://docs.wsdr.io Version: @PACKAGE_VERSION@ Requires: libusb-1.0 Libs: -L${libdir} -l@PACKAGE_NAME@ From 99e78ee22eebb29461f46f77b27b4230482b84aa Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sun, 22 Feb 2026 00:15:41 +0400 Subject: [PATCH 319/397] add at24 EEPROM memory interface --- src/lib/device/generic_usdr/generic_regs.h | 14 ++++++----- src/lib/hw/at24/at24.c | 29 ++++++++++++++++++++++ src/lib/hw/at24/at24.h | 18 ++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/lib/hw/at24/at24.c create mode 100644 src/lib/hw/at24/at24.h diff --git a/src/lib/device/generic_usdr/generic_regs.h b/src/lib/device/generic_usdr/generic_regs.h index 3d163c7b..cc94db19 100644 --- a/src/lib/device/generic_usdr/generic_regs.h +++ b/src/lib/device/generic_usdr/generic_regs.h @@ -100,17 +100,19 @@ enum RFE_BUS_ADDRS { // All I2C devices used accross the famaly enum { I2C_GENERAL_CALL = 0x00, - I2C_DEV_PMIC_FPGA = 0x60, //7'b110_0000; - I2C_DEV_EXTDAC = 0x48, //7'b100_1000; - I2C_DEV_TMP114B = 0x49, //7'b100_1001; + I2C_DEV_AT24_MEM = 0x50, //7'b101_0000; + I2C_DEV_AT24_SEC = 0x58, //7'b101_1000; + I2C_DEV_PMIC_FPGA = 0x60, //7'b110_0000; + I2C_DEV_EXTDAC = 0x48, //7'b100_1000; + I2C_DEV_TMP114B = 0x49, //7'b100_1001; I2C_DEV_TMP108A_A0_SDA = 0x4A, //7'b100_1010; I2C_DEV_DAC80501M_A0_GND = 0x48, //7'b100_1000; I2C_DEV_DAC80501M_A0_VDD = 0x49, //7'b100_1001; I2C_DEV_DAC80501M_A0_SDA = 0x4A, //7'b100_1001; I2C_DEV_DAC80501M_A0_SCL = 0x4B, //7'b100_1011; - I2C_DEV_TMP114NB = 0x4E, //7'b100_1110; - I2C_DEV_CLKGEN = 0x6A, //7'b110_1010; - I2C_DEV_DCDCBOOST = 0x75, //7'b111_0101; + I2C_DEV_TMP114NB = 0x4E, //7'b100_1110; + I2C_DEV_CLKGEN = 0x6A, //7'b110_1010; + I2C_DEV_DCDCBOOST = 0x75, //7'b111_0101; }; #define MAKE_I2C_LUT(a,b,c,d) \ diff --git a/src/lib/hw/at24/at24.c b/src/lib/hw/at24/at24.c new file mode 100644 index 00000000..cf4c64fb --- /dev/null +++ b/src/lib/hw/at24/at24.c @@ -0,0 +1,29 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "at24.h" + +#include + +// int at24_1addr_mem_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, uint8_t addr, unsigned size, const uint8_t *pdata); +int at24_saddr_mem_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, uint8_t addr, unsigned size, uint8_t *pdata) +{ + int res = 0; + for (unsigned off = 0; off < size;) { + uint8_t odata[4] = { 0xff, 0xff, 0xff, 0xff }; + unsigned rem = size - off; + if (rem > 4) + rem = 4; + + uint8_t byte_addr = addr + off; + res = res ? res : lowlevel_ls_op(dev, subdev, USDR_LSOP_I2C_DEV, ls_op_addr, rem, odata, 1, &byte_addr); + + for (unsigned j = 0; j < rem; j++) + pdata[off + j] = odata[j]; + + off += rem; + } + + return res; +} + diff --git a/src/lib/hw/at24/at24.h b/src/lib/hw/at24/at24.h new file mode 100644 index 00000000..b1111d21 --- /dev/null +++ b/src/lib/hw/at24/at24.h @@ -0,0 +1,18 @@ +// Copyright (c) 2023-2024 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef AT24_H +#define AT24_H + +#include + +enum { + AT24_SECURE_SERIAL_OFF = 0x80, + AT24_SECURE_USER_OFF = 0x90, +}; + +// single byte addres functions +int at24_saddr_mem_set(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, uint8_t addr, unsigned size, const uint8_t *pdata); +int at24_saddr_mem_get(lldev_t dev, subdev_t subdev, lsopaddr_t ls_op_addr, uint8_t addr, unsigned size, uint8_t *pdata); + +#endif From 3acf96bb782df219965713e9d94ca16fc9bf10be Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sun, 22 Feb 2026 00:16:15 +0400 Subject: [PATCH 320/397] xsdr fix for ssdr pro --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index d6e72b74..851156b9 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -7,7 +7,7 @@ #include "../hw/tmp114/tmp114.h" #include "../hw/tmp108/tmp108.h" #include "../hw/dac80501/dac80501.h" - +#include "../hw/at24/at24.h" #include #include @@ -1550,7 +1550,7 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) if (hwid == SSDRPRO_DEV) { res = lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 3, 2040); - } if (hwid == SSDR_DEV) { + } else if (hwid == SSDR_DEV) { res = lp8758_vout_set(dev, subdev, I2C_BUS_LP8758_FPGA, 1, 2040); } else { // TODO check if we need this rail @@ -1631,6 +1631,13 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) return -EFAULT; } + if (hwid == SSDRPRO_DEV) { + uint8_t s[16] = { 0, }; + res = res ? res : at24_saddr_mem_get(dev, d->base.lmsstate.subdev, I2C_DEV_AT24_SEC, AT24_SECURE_SERIAL_OFF, 16, s); + + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "AT24_SERIAL: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]); + } } return res; } @@ -2027,10 +2034,11 @@ int xsdr_dtor(xsdr_dev_t *d) res = (res) ? res : _xsdr_mmcm_pd(d); + // Set LMS8 power to 0.9V if (d->ssdr_pro) { res = res ? res : lp8758_vout_set(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, 900); res = res ? res : lp8758_vout_ctrl(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 3, 0, 1); - } if (d->ssdr) { + } else if (d->ssdr) { res = res ? res : lp8758_vout_set(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, 900); res = res ? res : lp8758_vout_ctrl(dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, 1, 0, 1); } From 17df5dafa1743f04254a640be86a5054afb36b3c Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sun, 22 Feb 2026 01:42:04 +0400 Subject: [PATCH 321/397] add at24 control --- src/lib/hw/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/hw/CMakeLists.txt b/src/lib/hw/CMakeLists.txt index 5d3fcfcf..5c04840d 100644 --- a/src/lib/hw/CMakeLists.txt +++ b/src/lib/hw/CMakeLists.txt @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT set(HW_FILES common si549 si5332 ads42lbx9 tps6594 tmp108 tmp114 lms6002d lms7002m lms8001 lp8758 lmk05318 lmk5c33216 tps6381x dac80501 - lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820 tca9555) + lmk04832 tca6424a adf4002b lp875484 afe79xx lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820 tca9555 at24) # YAML registers generators set(HW_FILES_YAML si5332 lmk05318 lmk5c33216 lms6002d lms7002m lms8001 tps6381x dac80501 lmk04832 xra1405 tca6424a adf4002b lp875484 lmx1204 lmx1214 lmk1d1208i ad5662 lmx1205 lp87524j lmx2820 tca9555) From 0786bdc46784f49f25e745abe5e841177ebf4dd7 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sun, 22 Feb 2026 03:19:53 +0400 Subject: [PATCH 322/397] add initial python wrappers --- src/tools/python/example_fft_rx.py | 102 ++++ src/tools/python/example_minimal.py | 54 ++ src/tools/python/usdr_bindings.py | 733 ++++++++++++++++++++++++++++ 3 files changed, 889 insertions(+) create mode 100755 src/tools/python/example_fft_rx.py create mode 100755 src/tools/python/example_minimal.py create mode 100644 src/tools/python/usdr_bindings.py diff --git a/src/tools/python/example_fft_rx.py b/src/tools/python/example_fft_rx.py new file mode 100755 index 00000000..7a999fda --- /dev/null +++ b/src/tools/python/example_fft_rx.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +"""Receive IQ samples from USDR and plot accumulated FFT magnitude. + +Example: + python3 example_fft_rx.py \ + --device "" \ + --rx-frequency 900e6 \ + --rx-bandwidth 1e6 \ + --rx-gain 15 \ + --samplerate 50e6 \ + --accumulation 16 \ + --fft-size 4096 \ + --window hann +""" + +from __future__ import annotations + +import argparse +import numpy as np +from scipy import signal +import matplotlib.pyplot as plt + +from usdr_bindings import USDR_DMS_START, USDR_DMS_STOP, UsdrDevice + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="USDR RX FFT plotter") + parser.add_argument("--device", default="", help="USDR device string") + parser.add_argument("--samplerate", type=float, default=5e6, help="Sample rate in SPS") + parser.add_argument("--loglevel", type=int, default=None, help="Optional libusdr log level") + parser.add_argument("--rx-frequency", type=float, required=True, help="RX frequency in Hz") + parser.add_argument("--rx-bandwidth", type=float, required=True, help="RX bandwidth in Hz") + parser.add_argument("--rx-gain", type=float, default=15, help="RX gain value (mapped to LNA gain)") + + parser.add_argument("--fft-size", type=int, default=4096, help="FFT bin size") + parser.add_argument("--accumulation", type=int, default=16, help="Number of FFT frames to accumulate") + parser.add_argument("--window", default="hann", help="Scipy window name (e.g. hann, blackman, flattop)") + parser.add_argument("--channel", type=int, default=0, help="RX channel index") + parser.add_argument("--timeout-ms", type=int, default=1000, help="Receive timeout in milliseconds") + + return parser.parse_args() + + +def main() -> None: + args = parse_args() + + if args.fft_size <= 0: + raise ValueError("--fft-size must be > 0") + if args.accumulation <= 0: + raise ValueError("--accumulation must be > 0") + + fft_size = int(args.fft_size) + window = signal.get_window(args.window, fft_size, fftbins=True).astype(np.float32) + + with UsdrDevice(args.device, loglevel=args.loglevel) as dev: + dev.set_samplerate(int(args.samplerate)) + dev.set_rx_frequency(int(args.rx_frequency)) + dev.set_rx_bandwidth(int(args.rx_bandwidth)) + dev.set_rx_gain_lna(int(args.rx_gain)) + + with dev.create_stream( + sobj="/ll/srx/0", + dformat="cf32", + channels=[int(args.channel)], + pktsyms=fft_size, + ) as rx_stream: + rx_stream.sync("any") + rx_stream.op(USDR_DMS_START) + + psd_acc = np.zeros(fft_size, dtype=np.float64) + + for _ in range(args.accumulation): + arrays, _ = rx_stream.recv(timeout_ms=args.timeout_ms, with_info=False) + iq = arrays[0] + + if iq.shape[0] < fft_size: + raise RuntimeError(f"Received {iq.shape[0]} samples, expected at least {fft_size}") + + x = iq[:fft_size] * window + spec = np.fft.fftshift(np.fft.fft(x, n=fft_size)) + psd_acc += np.abs(spec) ** 2 + + rx_stream.op(USDR_DMS_STOP) + + psd = psd_acc / args.accumulation + psd_db = 10.0 * np.log10(psd + 1e-20) + + fs = float(args.samplerate) + f_axis = np.fft.fftshift(np.fft.fftfreq(fft_size, d=1.0 / fs)) + + plt.figure(figsize=(10, 5)) + plt.plot(f_axis / 1e6, psd_db) + plt.title("USDR RX FFT") + plt.xlabel("Frequency offset (MHz)") + plt.ylabel("Power (dB, arbitrary)") + plt.grid(True, alpha=0.3) + plt.tight_layout() + plt.show() + + +if __name__ == "__main__": + main() diff --git a/src/tools/python/example_minimal.py b/src/tools/python/example_minimal.py new file mode 100755 index 00000000..5543d695 --- /dev/null +++ b/src/tools/python/example_minimal.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""Minimal usage example for high-level UsdrDevice/UsdrStream API.""" + +import argparse +import numpy as np + +from usdr_bindings import USDR_DMS_START, USDR_DMS_STOP, UsdrDevice + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="USDR minimal RX/TX example") + parser.add_argument("--device", default="", help="USDR device string") + parser.add_argument("--loglevel", type=int, default=None, help="Optional libusdr log level") + return parser.parse_args() + + +def main() -> None: + args = parse_args() + + with UsdrDevice(args.device, loglevel=args.loglevel) as dev: + dev.set_samplerate(5_000_000) + dev.configure_rf( + rx_freq=900_000_000, + tx_freq=920_000_000, + rx_bandwidth=1_000_000, + tx_bandwidth=1_000_000, + rx_gain_lna=15, + rx_gain_vga=15, + rx_gain_pga=15, + tx_gain=0, + rx_path="rx_auto", + tx_path="tx_auto", + ) + + with dev.create_stream("/ll/srx/0", "cf32", [0], 8*2048) as rx_stream, dev.create_stream("/ll/stx/0", "ci16", [0], 2048) as tx_stream: + info = rx_stream.info() + print(f"RX stream: channels={info.channels} pktsyms={info.pktsyms} pktbytes={info.pktbszie}") + + rx_stream.sync("any", tx_stream) + rx_stream.op(USDR_DMS_START) + tx_stream.op(USDR_DMS_START) + + rx_arrays, rx_nfo = rx_stream.recv(timeout_ms=1000, with_info=True) + print(f"RX dtype={rx_arrays[0].dtype} shape={rx_arrays[0].shape}") + print(f"Received symbols={rx_nfo.totsyms} lost={rx_nfo.totlost} hw_time={rx_nfo.fsymtime}") + + tx_data = np.zeros((info.pktsyms, 2), dtype=np.int16) + tx_stream.send([tx_data], timestamp=0, timeout_ms=1000) + + rx_stream.op(USDR_DMS_STOP) + tx_stream.op(USDR_DMS_STOP) + + +if __name__ == "__main__": + main() diff --git a/src/tools/python/usdr_bindings.py b/src/tools/python/usdr_bindings.py new file mode 100644 index 00000000..3fc7649c --- /dev/null +++ b/src/tools/python/usdr_bindings.py @@ -0,0 +1,733 @@ +"""Minimal ctypes bindings and high-level Pythonic wrappers for libusdr.""" + +from __future__ import annotations + +import ctypes +import errno +import ctypes.util +from dataclasses import dataclass +from typing import Dict, Iterable, Optional, Sequence, Tuple, Union + + +class UsdrException(RuntimeError): + """Raised by high-level wrappers when a libusdr operation fails.""" + + def __init__(self, fn_name: str, code: int): + super().__init__(f"{fn_name} failed with error code {code}") + self.fn_name = fn_name + self.code = code + + +# Backward-compatible alias from previous revisions. +USDRError = UsdrException + + +class UsdrDmsNfo(ctypes.Structure): + _fields_ = [ + ("type", ctypes.c_uint), + ("channels", ctypes.c_uint), + ("pktbszie", ctypes.c_uint), + ("pktsyms", ctypes.c_uint), + ("totsamptick", ctypes.c_uint), + ("burst_count", ctypes.c_uint), + ] + + +class UsdrChannelInfo(ctypes.Structure): + _fields_ = [ + ("count", ctypes.c_uint), + ("flags", ctypes.c_uint), + ("phys_names", ctypes.POINTER(ctypes.c_char_p)), + ("phys_nums", ctypes.POINTER(ctypes.c_uint)), + ] + + +class UsdrDmsRecvNfo(ctypes.Structure): + _fields_ = [ + ("fsymtime", ctypes.c_uint64), + ("totsyms", ctypes.c_uint), + ("totlost", ctypes.c_uint), + ("max_parts", ctypes.c_uint), + ("extra", ctypes.c_uint64), + ] + + +@dataclass(frozen=True) +class UsdrStreamInfo: + """Pure-Python stream metadata object returned by :meth:`UsdrStream.info`.""" + + type: int + channels: int + pktbszie: int + pktsyms: int + totsamptick: int + burst_count: int + + @classmethod + def from_ctypes(cls, nfo: "UsdrDmsNfo") -> "UsdrStreamInfo": + return cls( + type=int(nfo.type), + channels=int(nfo.channels), + pktbszie=int(nfo.pktbszie), + pktsyms=int(nfo.pktsyms), + totsamptick=int(nfo.totsamptick), + burst_count=int(nfo.burst_count), + ) + + def __str__(self) -> str: + return ( + f"UsdrStreamInfo(type={self.type}, channels={self.channels}, " + f"pktbytes={self.pktbszie}, pktsyms={self.pktsyms}, " + f"totsamptick={self.totsamptick}, burst_count={self.burst_count})" + ) + + +USDR_DMS_START = 0 +USDR_DMS_STOP = 1 +USDR_DMS_START_AT = 2 +USDR_DMS_STOP_AT = 3 + +ChannelId = Union[int, str] +ChannelMap = Optional[Sequence[ChannelId]] + + +def empty_aligned_complex64(shape, alignment=64): + """ + Creates an uninitialized complex64 array aligned to the specified byte boundary. + """ + import numpy as np + + dtype = np.dtype(np.complex64) + # Calculate total bytes needed + n_bytes = np.prod(shape) * dtype.itemsize + + # Allocate extra 'alignment' bytes to ensure we can find an aligned start + raw_buffer = np.empty(n_bytes + alignment, dtype=np.uint8) + + # Find the starting address and calculate the offset to the next 64-byte boundary + start_address = raw_buffer.ctypes.data + offset = (alignment - (start_address % alignment)) % alignment + + # Create the view starting at the aligned offset + aligned_array = raw_buffer[offset : offset + n_bytes].view(dtype).reshape(shape) + return aligned_array + + +class UsdrLib: + """Thin low-level wrapper around selected libusdr C APIs (non-raising).""" + + def __init__(self, library_path: Optional[str] = None) -> None: + candidates = [ + library_path, + ctypes.util.find_library("usdr"), + "libusdr.so", + "libusdr.dylib", + "usdr.dll", + ] + + last_exc = None + self._lib = None + self._stream_meta: Dict[int, Tuple[str, UsdrDmsNfo]] = {} + for name in candidates: + if not name: + continue + try: + self._lib = ctypes.CDLL(name) + break + except OSError as exc: + last_exc = exc + + if self._lib is None: + raise OSError(f"Unable to load libusdr: {last_exc}") + + self._configure_signatures() + + def _configure_signatures(self) -> None: + self._lib.usdr_dmd_create_string.argtypes = [ctypes.c_char_p, ctypes.POINTER(ctypes.c_void_p)] + self._lib.usdr_dmd_create_string.restype = ctypes.c_int + + self._lib.usdr_dmd_close.argtypes = [ctypes.c_void_p] + self._lib.usdr_dmd_close.restype = ctypes.c_int + + self._lib.usdr_dme_set_uint.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint64] + self._lib.usdr_dme_set_uint.restype = ctypes.c_int + + self._lib.usdr_dme_set_string.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_char_p] + self._lib.usdr_dme_set_string.restype = ctypes.c_int + + self._lib.usdr_dme_get_uint.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint64)] + self._lib.usdr_dme_get_uint.restype = ctypes.c_int + + self._lib.usdr_dme_get_u32.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.POINTER(ctypes.c_uint32)] + self._lib.usdr_dme_get_u32.restype = ctypes.c_int + + self._lib.usdr_dmr_rate_set.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint] + self._lib.usdr_dmr_rate_set.restype = ctypes.c_int + + self._lib.usdr_dms_create_ex2.argtypes = [ + ctypes.c_void_p, + ctypes.c_char_p, + ctypes.c_char_p, + ctypes.POINTER(UsdrChannelInfo), + ctypes.c_uint, + ctypes.c_uint, + ctypes.c_char_p, + ctypes.POINTER(ctypes.c_void_p), + ] + self._lib.usdr_dms_create_ex2.restype = ctypes.c_int + + self._lib.usdr_dms_destroy.argtypes = [ctypes.c_void_p] + self._lib.usdr_dms_destroy.restype = ctypes.c_int + + self._lib.usdr_dms_info.argtypes = [ctypes.c_void_p, ctypes.POINTER(UsdrDmsNfo)] + self._lib.usdr_dms_info.restype = ctypes.c_int + + self._lib.usdr_dms_op.argtypes = [ctypes.c_void_p, ctypes.c_uint, ctypes.c_uint64] + self._lib.usdr_dms_op.restype = ctypes.c_int + + self._lib.usdr_dms_sync.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_uint, ctypes.POINTER(ctypes.c_void_p)] + self._lib.usdr_dms_sync.restype = ctypes.c_int + + self._lib.usdr_dms_recv.argtypes = [ + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_void_p), + ctypes.c_uint, + ctypes.POINTER(UsdrDmsRecvNfo), + ] + self._lib.usdr_dms_recv.restype = ctypes.c_int + + self._lib.usdr_dms_send.argtypes = [ + ctypes.c_void_p, + ctypes.POINTER(ctypes.c_void_p), + ctypes.c_uint, + ctypes.c_uint64, + ctypes.c_uint, + ] + self._lib.usdr_dms_send.restype = ctypes.c_int + + @staticmethod + def _normalize_host_format(dformat: str) -> str: + host_fmt = dformat.split("@", 1)[0] + host_fmt = host_fmt.split(";", 1)[0] + return host_fmt.strip().lower() + + def _stream_key(self, stream: ctypes.c_void_p) -> int: + return int(ctypes.cast(stream, ctypes.c_void_p).value) + + @staticmethod + def _validate_channels(channels: ChannelMap) -> Tuple[int, Sequence[ChannelId]]: + if channels is None: + return 0, [0] + if not isinstance(channels, Sequence) or isinstance(channels, (str, bytes)): + return -errno.EINVAL, [] + if len(channels) == 0: + return -errno.EINVAL, [] + + all_int = all(isinstance(ch, int) and not isinstance(ch, bool) for ch in channels) + all_str = all(isinstance(ch, str) for ch in channels) + if not (all_int or all_str): + return -errno.EINVAL, [] + + return 0, channels + + # Low-level methods return integer status codes (0 on success). + def usdrlog_setlevel(self, loglevel: int, subsystem: Optional[str] = None) -> None: + """Set libusdr logging level for a subsystem or default (None).""" + self._lib.usdrlog_setlevel(subsystem.encode("utf-8") if subsystem else None, int(loglevel)) + + # Low-level methods return integer status codes (0 on success). + def usdr_dmd_create_string(self, connection_string: str) -> Tuple[int, ctypes.c_void_p]: + """Create device handle from a connection string. + + Returns: + Tuple of ``(res, dev_handle)`` where ``res == 0`` on success. + """ + dev = ctypes.c_void_p() + res = self._lib.usdr_dmd_create_string(connection_string.encode("utf-8"), ctypes.byref(dev)) + return int(res), dev + + def usdr_dmd_close(self, device: ctypes.c_void_p) -> int: + """Close device handle previously created by :meth:`usdr_dmd_create_string`.""" + return int(self._lib.usdr_dmd_close(device)) + + def usdr_dme_set_uint(self, device: ctypes.c_void_p, path: str, value: int) -> int: + """Set unsigned integer parameter by full path.""" + return int(self._lib.usdr_dme_set_uint(device, path.encode("utf-8"), int(value))) + + def usdr_dme_set_string(self, device: ctypes.c_void_p, path: str, value: str) -> int: + """Set string parameter by full path.""" + return int(self._lib.usdr_dme_set_string(device, path.encode("utf-8"), value.encode("utf-8"))) + + def usdr_dme_get_uint(self, device: ctypes.c_void_p, path: str) -> Tuple[int, int]: + """Read unsigned integer parameter by full path. + + Returns: + ``(res, value)`` where value is valid when ``res == 0``. + """ + out = ctypes.c_uint64() + res = self._lib.usdr_dme_get_uint(device, path.encode("utf-8"), ctypes.byref(out)) + return int(res), int(out.value) + + def usdr_dme_get_u32(self, device: ctypes.c_void_p, path: str) -> Tuple[int, int]: + """Read 32-bit unsigned parameter by full path.""" + out = ctypes.c_uint32() + res = self._lib.usdr_dme_get_u32(device, path.encode("utf-8"), ctypes.byref(out)) + return int(res), int(out.value) + + def usdr_dmr_rate_set(self, device: ctypes.c_void_p, rate: int, rate_name: Optional[str] = None) -> int: + """Set sample rate for device (master rate when ``rate_name`` is ``None``).""" + return int(self._lib.usdr_dmr_rate_set(device, rate_name.encode("utf-8") if rate_name else None, int(rate))) + + def usdr_dms_create_ex2( + self, + device: ctypes.c_void_p, + sobj: str, + dformat: str = "cf32", + channels: ChannelMap = None, + pktsyms: int = 4096, + flags: int = 0, + parameters: Optional[str] = None, + ) -> Tuple[int, ctypes.c_void_p]: + """Create stream handle with explicit channel mapping and format. + + ``channels`` may be either a list of integers (mapped to ``phys_nums``) or a + list of strings (mapped to ``phys_names``). If omitted, ``[0]`` is used. + + Returns: + ``(res, stream_handle)`` where ``res == 0`` on success. + """ + vres, channels = self._validate_channels(channels) + if vres != 0: + return vres, ctypes.c_void_p() + + chan_info = UsdrChannelInfo(count=len(channels), flags=0, phys_names=None, phys_nums=None) + + chan_nums = None + chan_names_arr = None + chan_names_storage = None + if isinstance(channels[0], int): + chan_nums = (ctypes.c_uint * len(channels))(*[int(ch) for ch in channels]) + chan_info.phys_nums = chan_nums + else: + chan_names_storage = [ch.encode("utf-8") for ch in channels] + chan_names_arr = (ctypes.c_char_p * len(channels))(*chan_names_storage) + chan_info.phys_names = chan_names_arr + + out_stream = ctypes.c_void_p() + res = self._lib.usdr_dms_create_ex2( + device, + sobj.encode("utf-8"), + dformat.encode("utf-8"), + ctypes.byref(chan_info), + pktsyms, + flags, + parameters.encode("utf-8") if parameters is not None else None, + ctypes.byref(out_stream), + ) + + if res == 0: + info_res, stream_info = self.usdr_dms_info(out_stream) + if info_res == 0: + self._stream_meta[self._stream_key(out_stream)] = (self._normalize_host_format(dformat), stream_info) + return int(res), out_stream + + def usdr_dms_destroy(self, stream: ctypes.c_void_p) -> int: + """Destroy stream handle.""" + res = int(self._lib.usdr_dms_destroy(stream)) + if res == 0: + self._stream_meta.pop(self._stream_key(stream), None) + return res + + def usdr_dms_info(self, stream: ctypes.c_void_p) -> Tuple[int, UsdrDmsNfo]: + """Get low-level stream information struct.""" + info = UsdrDmsNfo() + res = self._lib.usdr_dms_info(stream, ctypes.byref(info)) + return int(res), info + + def usdr_dms_op(self, stream: ctypes.c_void_p, command: int, tm: int = 0) -> int: + """Perform stream operation (`START`, `STOP`, timed variants).""" + return int(self._lib.usdr_dms_op(stream, command, tm)) + + def usdr_dms_sync(self, device: ctypes.c_void_p, synctype: str, streams: Iterable[ctypes.c_void_p]) -> int: + """Synchronize one or more streams using a named sync policy.""" + stream_list = list(streams) + arr = (ctypes.c_void_p * len(stream_list))(*stream_list) + return int(self._lib.usdr_dms_sync(device, synctype.encode("utf-8"), len(stream_list), arr)) + + def usdr_dms_recv( + self, + stream: ctypes.c_void_p, + buffers: Sequence[ctypes.Array], + timeout_ms: int, + with_info: bool = True, + ) -> Tuple[int, Optional[UsdrDmsRecvNfo]]: + """Receive into caller-provided ctypes buffers.""" + c_bufs = (ctypes.c_void_p * len(buffers))(*(ctypes.addressof(b) for b in buffers)) + print(c_bufs) + rx_nfo = UsdrDmsRecvNfo() if with_info else None + res = self._lib.usdr_dms_recv(stream, c_bufs, timeout_ms, ctypes.byref(rx_nfo) if rx_nfo else None) + return int(res), rx_nfo + + def usdr_dms_recv_numpy(self, stream: ctypes.c_void_p, timeout_ms: int, with_info: bool = True): + """Receive into numpy arrays based on stream host format metadata. + + Returns: + ``(res, arrays, rx_info)``. ``arrays`` is ``None`` when ``res != 0``. + """ + import numpy as np + + meta = self._stream_meta.get(self._stream_key(stream)) + if meta is None: + return -errno.EINVAL, None, None + + host_fmt, stream_info = meta + if host_fmt not in ("ci16", "cf32"): + return -errno.EOPNOTSUPP, None, None + + out = [ empty_aligned_complex64(stream_info.pktsyms) if host_fmt == "cf32" else np.empty((stream_info.pktsyms, 2), dtype=np.int16) for _ in range(stream_info.channels)] + raw_buffers_t = ctypes.c_void_p * stream_info.channels + raw_buffers = raw_buffers_t() + for i in range(stream_info.channels): + raw_buffers[i] = out[i].ctypes.data_as(ctypes.c_void_p) + + rx_nfo = UsdrDmsRecvNfo() if with_info else None + res = self._lib.usdr_dms_recv(stream, raw_buffers, timeout_ms, ctypes.byref(rx_nfo) if rx_nfo else None) + if res != 0: + return res, None, rx_nfo + + return 0, out, rx_nfo + + def usdr_dms_send(self, stream: ctypes.c_void_p, buffers: Sequence[ctypes.Array], samples: int, timestamp: int, timeout_ms: int) -> int: + """Send from caller-provided ctypes buffers.""" + c_bufs = (ctypes.c_void_p * len(buffers))(*(ctypes.addressof(b) for b in buffers)) + return int(self._lib.usdr_dms_send(stream, c_bufs, samples, timestamp, timeout_ms)) + + def usdr_dms_send_numpy(self, stream: ctypes.c_void_p, buffers, timestamp: int, timeout_ms: int, samples: Optional[int] = None) -> int: + """Send from numpy arrays validated against stream host format metadata.""" + import numpy as np + + meta = self._stream_meta.get(self._stream_key(stream)) + if meta is None: + return -errno.EINVAL + + host_fmt, stream_info = meta + if host_fmt not in ("ci16", "cf32"): + return -errno.EOPNOTSUPP + if len(buffers) != stream_info.channels: + return -errno.EINVAL + + np_buffers = [] + inferred_samples = None + for buf in buffers: + arr = np.asarray(buf) + if host_fmt == "ci16": + if arr.dtype != np.int16 or arr.ndim != 2 or arr.shape[1] != 2: + return -errno.EINVAL + n = arr.shape[0] + else: + if arr.dtype != np.complex64 or arr.ndim != 1: + return -errno.EINVAL + n = arr.shape[0] + if inferred_samples is None: + inferred_samples = int(n) + elif int(n) != inferred_samples: + return -errno.EINVAL + np_buffers.append(np.ascontiguousarray(arr)) + + send_samples = inferred_samples if samples is None else int(samples) + c_bufs = (ctypes.c_void_p * len(np_buffers))(*(ctypes.c_void_p(arr.ctypes.data) for arr in np_buffers)) + return int(self._lib.usdr_dms_send(stream, c_bufs, send_samples, timestamp, timeout_ms)) + + +class UsdrDevice: + """Create device wrapper and optionally set global libusdr log level. + Args: + device_string: Connection string passed to ``usdr_dmd_create_string``. + loglevel: Optional log level passed to ``usdrlog_setlevel(NULL, loglevel)`` before opening device. + lib: Optional pre-created low-level wrapper. + """ + def __init__(self, device_string: str = "", loglevel: Optional[int] = None, lib: Optional[UsdrLib] = None) -> None: + self._lib = lib or UsdrLib() + if loglevel is not None: + self._lib.usdrlog_setlevel(loglevel) + self._closed = True + res, dev = self._lib.usdr_dmd_create_string(device_string) + if res != 0: + raise UsdrException("usdr_dmd_create_string", res) + self._dev = dev + self._closed = False + + def __enter__(self) -> "UsdrDevice": + return self + + def __exit__(self, exc_type, exc, tb) -> None: + self.close() + + def __del__(self) -> None: + try: + self.close() + except Exception: + pass + + @property + def handle(self) -> ctypes.c_void_p: + return self._dev + + @staticmethod + def _raise_if_error(fn_name: str, code: int) -> None: + if code != 0: + raise UsdrException(fn_name, code) + + def _ensure_open(self) -> None: + if self._closed: + raise UsdrException("device_closed", -errno.EBADF) + + def close(self) -> None: + """Close device and release underlying low-level handle.""" + if not self._closed: + res = self._lib.usdr_dmd_close(self._dev) + self._raise_if_error("usdr_dmd_close", res) + self._closed = True + + def set_uint(self, path: str, value: int) -> None: + """Set arbitrary unsigned integer parameter by full path.""" + self._ensure_open() + res = self._lib.usdr_dme_set_uint(self._dev, path, value) + self._raise_if_error("usdr_dme_set_uint", res) + + def set_string(self, path: str, value: str) -> None: + """Set arbitrary string parameter by full path.""" + self._ensure_open() + res = self._lib.usdr_dme_set_string(self._dev, path, value) + self._raise_if_error("usdr_dme_set_string", res) + + def get_uint(self, path: str) -> int: + """Get arbitrary unsigned integer parameter by full path.""" + self._ensure_open() + res, value = self._lib.usdr_dme_get_uint(self._dev, path) + self._raise_if_error("usdr_dme_get_uint", res) + return value + + def get_u32(self, path: str) -> int: + """Get arbitrary 32-bit unsigned parameter by full path.""" + self._ensure_open() + res, value = self._lib.usdr_dme_get_u32(self._dev, path) + self._raise_if_error("usdr_dme_get_u32", res) + return value + + def set_samplerate(self, rate: int, rate_name: Optional[str] = None) -> None: + """Set device sample rate in samples per second. + + Mirrors `usdr_dm_create` behavior (`usdr_dmr_rate_set(dev, NULL, rate)`) when + `rate_name` is omitted. + + Args: + rate: Target sample rate in SPS (e.g. 50_000_000). + rate_name: Optional named rate domain; use ``None`` for master rate. + """ + self._ensure_open() + res = self._lib.usdr_dmr_rate_set(self._dev, rate=rate, rate_name=rate_name) + self._raise_if_error("usdr_dmr_rate_set", res) + + def _set_sdr0_uint(self, endpoint: str, value: int) -> None: + self.set_uint(f"/dm/sdr/0/{endpoint}", value) + + def _set_sdr0_string(self, endpoint: str, value: str) -> None: + self.set_string(f"/dm/sdr/0/{endpoint}", value) + + def set_rx_frequency(self, hz: int) -> None: + """Set RX LO frequency in Hz (`/dm/sdr/0/rx/freqency`).""" + self._set_sdr0_uint("rx/freqency", hz) + + def set_tx_frequency(self, hz: int) -> None: + """Set TX LO frequency in Hz (`/dm/sdr/0/tx/freqency`).""" + self._set_sdr0_uint("tx/freqency", hz) + + def set_tdd_frequency(self, hz: int) -> None: + """Set TDD frequency in Hz (`/dm/sdr/0/tdd/freqency`).""" + self._set_sdr0_uint("tdd/freqency", hz) + + def set_rx_bandwidth(self, hz: int) -> None: + """Set RX bandwidth in Hz (`/dm/sdr/0/rx/bandwidth`).""" + self._set_sdr0_uint("rx/bandwidth", hz) + + def set_tx_bandwidth(self, hz: int) -> None: + """Set TX bandwidth in Hz (`/dm/sdr/0/tx/bandwidth`).""" + self._set_sdr0_uint("tx/bandwidth", hz) + + def set_rx_gain_lna(self, gain_db: int) -> None: + """Set RX LNA gain (`/dm/sdr/0/rx/gain/lna`).""" + self._set_sdr0_uint("rx/gain/lna", gain_db) + + def set_rx_gain_vga(self, gain_db: int) -> None: + """Set RX VGA gain (`/dm/sdr/0/rx/gain/vga`).""" + self._set_sdr0_uint("rx/gain/vga", gain_db) + + def set_rx_gain_pga(self, gain_db: int) -> None: + """Set RX PGA gain (`/dm/sdr/0/rx/gain/pga`).""" + self._set_sdr0_uint("rx/gain/pga", gain_db) + + def set_tx_gain(self, gain_db: int) -> None: + """Set TX gain (`/dm/sdr/0/tx/gain`).""" + self._set_sdr0_uint("tx/gain", gain_db) + + def set_rx_path(self, path: str) -> None: + """Set RX path (`/dm/sdr/0/rx/path`). + + Typical values from `usdr_dm_create`: `rx_auto`, `rxl`, `rxw`, `rxh`, `adc`, + `rxl_lb`, `rxw_lb`, `rxh_lb`. + """ + self._set_sdr0_string("rx/path", path) + + def set_tx_path(self, path: str) -> None: + """Set TX path (`/dm/sdr/0/tx/path`). + + Typical values from `usdr_dm_create`: `tx_auto`, `txb1`, `txb2`, `txw`, `txh`. + """ + self._set_sdr0_string("tx/path", path) + + def configure_rf( + self, + *, + rx_freq: Optional[int] = None, + tx_freq: Optional[int] = None, + tdd_freq: Optional[int] = None, + rx_bandwidth: Optional[int] = None, + tx_bandwidth: Optional[int] = None, + rx_gain_lna: Optional[int] = None, + rx_gain_vga: Optional[int] = None, + rx_gain_pga: Optional[int] = None, + tx_gain: Optional[int] = None, + rx_path: Optional[str] = None, + tx_path: Optional[str] = None, + ) -> None: + """Apply multiple RF parameters from one call. + + This mirrors the `dev_data`/CLI controls used by `usdr_dm_create.c` and writes + corresponding `/dm/sdr/0/*` endpoints. Only non-``None`` values are applied. + """ + if rx_freq is not None: + self.set_rx_frequency(rx_freq) + if tx_freq is not None: + self.set_tx_frequency(tx_freq) + if tdd_freq is not None: + self.set_tdd_frequency(tdd_freq) + if rx_bandwidth is not None: + self.set_rx_bandwidth(rx_bandwidth) + if tx_bandwidth is not None: + self.set_tx_bandwidth(tx_bandwidth) + if rx_gain_lna is not None: + self.set_rx_gain_lna(rx_gain_lna) + if rx_gain_vga is not None: + self.set_rx_gain_vga(rx_gain_vga) + if rx_gain_pga is not None: + self.set_rx_gain_pga(rx_gain_pga) + if tx_gain is not None: + self.set_tx_gain(tx_gain) + if rx_path is not None: + self.set_rx_path(rx_path) + if tx_path is not None: + self.set_tx_path(tx_path) + + def create_stream( + self, + sobj: str, + dformat: str = "cf32", + channels: ChannelMap = None, + pktsyms: int = 4096, + flags: int = 0, + parameters: Optional[str] = None, + ) -> "UsdrStream": + """Create and return a high-level :class:`UsdrStream` wrapper. + + Args: + channels: Either list of int channel IDs (``phys_nums``), list of str + physical channel names (``phys_names``), or ``None`` (defaults to ``[0]``). + + Raises: + UsdrException: When channel type is invalid or stream creation fails. + """ + self._ensure_open() + vres, _ = self._lib._validate_channels(channels) + self._raise_if_error("create_stream(channels)", vres) + res, handle = self._lib.usdr_dms_create_ex2(self._dev, sobj, dformat, channels, pktsyms, flags, parameters) + self._raise_if_error("usdr_dms_create_ex2", res) + return UsdrStream(self, handle) + + +class UsdrStream: + """High-level stream wrapper bound to a UsdrDevice.""" + + def __init__(self, device: UsdrDevice, handle: ctypes.c_void_p) -> None: + self._device = device + self._lib = device._lib + self._stream = handle + self._closed = False + + def __enter__(self) -> "UsdrStream": + return self + + def __exit__(self, exc_type, exc, tb) -> None: + self.close() + + def __del__(self) -> None: + try: + self.close() + except Exception: + pass + + @property + def handle(self) -> ctypes.c_void_p: + return self._stream + + @staticmethod + def _raise_if_error(fn_name: str, code: int) -> None: + if code != 0: + raise UsdrException(fn_name, code) + + def _ensure_open(self) -> None: + if self._closed: + raise UsdrException("stream_closed", -errno.EBADF) + + def close(self) -> None: + """Close stream and release underlying low-level handle.""" + if not self._closed: + res = self._lib.usdr_dms_destroy(self._stream) + self._raise_if_error("usdr_dms_destroy", res) + self._closed = True + + def info(self) -> UsdrStreamInfo: + """Return stream metadata as a pure-Python :class:`UsdrStreamInfo` object.""" + self._ensure_open() + res, info = self._lib.usdr_dms_info(self._stream) + self._raise_if_error("usdr_dms_info", res) + return UsdrStreamInfo.from_ctypes(info) + + def op(self, command: int, tm: int = 0) -> None: + """Run stream operation command (start/stop/timed variants).""" + self._ensure_open() + res = self._lib.usdr_dms_op(self._stream, command, tm) + self._raise_if_error("usdr_dms_op", res) + + def sync(self, synctype: str = "off", *other_streams: "UsdrStream") -> None: + """Synchronize this stream together with optional peer streams.""" + self._ensure_open() + streams = [self._stream] + for st in other_streams: + st._ensure_open() + streams.append(st._stream) + res = self._lib.usdr_dms_sync(self._device.handle, synctype, streams) + self._raise_if_error("usdr_dms_sync", res) + + def recv(self, timeout_ms: int, with_info: bool = True): + """Receive one block as numpy arrays; returns ``(arrays, recv_info)``.""" + self._ensure_open() + res, arrays, rx_nfo = self._lib.usdr_dms_recv_numpy(self._stream, timeout_ms=timeout_ms, with_info=with_info) + self._raise_if_error("usdr_dms_recv", res) + return arrays, rx_nfo + + def send(self, buffers, timestamp: int = 0, timeout_ms: int = 1000, samples: Optional[int] = None) -> None: + """Send one block from numpy arrays using stored stream format metadata.""" + self._ensure_open() + res = self._lib.usdr_dms_send_numpy(self._stream, buffers, timestamp=timestamp, timeout_ms=timeout_ms, samples=samples) + self._raise_if_error("usdr_dms_send", res) From f389a59bef5f0d09693a3a0d59e917279cbb5457 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sun, 22 Feb 2026 03:21:28 +0400 Subject: [PATCH 323/397] add python utilities to CMake --- src/tools/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 12783783..c1075ba2 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -31,6 +31,9 @@ install(TARGETS usdr_dm_gpsdo RUNTIME) list(APPEND WVLT_SCRIPTS wvlt_sdr_wrapper.py + python/usdr_bindings.py + python/example_minimal.py + python/example_fft_rx.py ) configure_file(${WVLT_SCRIPTS} . USE_SOURCE_PERMISSIONS COPYONLY) From 7de8219fd9ebe7b60ce1944ed85daa38e10aab66 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Tue, 24 Feb 2026 22:32:55 +0400 Subject: [PATCH 324/397] fix: correct typos in comments, logs, and frequency endpoints - Fix multiple spelling errors in comments and log messages - Rename incorrect SDR parameter paths from */freqency to */frequency (old paths are kept for several releases for backward compatibility) - Improve wording consistency in low-level and stream modules - Minor formatting alignment in log messages --- src/lib/common/clock_gen.c | 2 +- src/lib/device/device_cores.h | 4 +-- src/lib/device/m2_dsdr/dsdr_hiper.c | 8 ++++++ src/lib/device/m2_dsdr/m2_dsdr.c | 26 +++++++++++++++++-- src/lib/device/m2_lm6_1/m2_lm6_1.c | 6 +++++ src/lib/device/m2_lm7_1/m2_lm7_1.c | 22 ++++++++++++++++ src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c | 4 +++ src/lib/device/u3_limesdr/u3_limesdr.c | 5 ++++ src/lib/hw/lmk04832/lmk04832.c | 4 +-- src/lib/hw/lms8001/lms8001.c | 2 +- src/lib/ipblks/lms64c_proto.c | 4 +-- src/lib/ipblks/streams/stream_limesdr.c | 2 +- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 12 ++++----- src/lib/ipblks/streams/stream_sfetrx4_dma32.h | 2 +- src/lib/ipblks/xlnx_bitstream.c | 2 +- src/lib/json_controller/controller.c | 2 +- src/lib/lowlevel/libusb_generic.c | 2 +- src/lib/lowlevel/pcie_uram/pcie_uram_main.c | 8 +++--- .../lowlevel/usb_ft601/usb_ft601_generic.c | 6 ++--- src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c | 2 +- src/lib/lowlevel/usb_uram/usb_uram_generic.c | 4 +-- src/lib/lowlevel/usb_uram/usb_uram_libusb.c | 2 +- .../lowlevel/verilator_ll/verilatorll_wrap.c | 4 +-- .../lowlevel/verilator_ll/verilatorll_wrap.h | 2 +- src/lib/lowlevel/verilator_ll/vpu.h | 2 +- src/lib/xdsp/sincos_functions.h | 2 +- src/soapysdr/usdr_soapy.cpp | 2 +- src/tests/lms7_cal.c | 4 +-- src/tests/lowlevel_lvds_perf.c | 2 +- src/tests/simpleapi.c | 10 +++---- src/tests/usdr_simple_api_test.c | 12 ++++----- src/tools/usdr_dm_create.c | 6 ++--- 32 files changed, 122 insertions(+), 55 deletions(-) diff --git a/src/lib/common/clock_gen.c b/src/lib/common/clock_gen.c index a425ecc3..28ef0def 100644 --- a/src/lib/common/clock_gen.c +++ b/src/lib/common/clock_gen.c @@ -147,7 +147,7 @@ int find_best_vco(const vco_range_t* pvcos, unsigned vco_count, } } - // Freqency can't be delivered + // Frequency can't be delivered return -1; } diff --git a/src/lib/device/device_cores.h b/src/lib/device/device_cores.h index 496bdada..1a65c7bd 100644 --- a/src/lib/device/device_cores.h +++ b/src/lib/device/device_cores.h @@ -32,7 +32,7 @@ enum usdr_core_subtype { // internal MCU glue logic USDR_CS_MCU = 0x7, - // Syncronization core (1PPS, Sysref, etc.) + // Synchronization core (1PPS, Sysref, etc.) USDR_CS_SYNC = 0x8, // Int bucket @@ -109,7 +109,7 @@ enum usdr_gpi_cores { #define USDR_CORE_GET_ID(c) ((c) >> 8) -// Prdefined cores +// Predefined cores #define I2C_CORE_AUTO_LUTUPD USDR_MAKE_COREID(USDR_CS_BUS, USDR_BS_DI2C_SIMPLE) #define SPI_CORE_32W USDR_MAKE_COREID(USDR_CS_BUS, USDR_BS_SPI_SIMPLE) #define SPI_CORE_CFGW_CS8 USDR_MAKE_COREID(USDR_CS_BUS, USDR_BS_SPI_CFG_CS8) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 7642bce6..734a49b3 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -272,6 +272,14 @@ static const usdr_dev_param_func_t s_fe_parameters[] = { { "/dm/sdr/0/smart_tune/int_mod", { dsdr_hiper_lms8001_smart_tune_int_mod_set, dsdr_hiper_lms8001_smart_tune_int_mod_get }}, { "/dm/sdr/0/smart_tune/enabled", { dsdr_hiper_lms8001_smart_tune_enabled_set, dsdr_hiper_lms8001_smart_tune_enabled_get }}, + { "/dm/sdr/0/rx/ab_l/frequency", { dsdr_hiper_lms8001_rabl_reg_set, dsdr_hiper_lms8001_rabl_reg_get }}, + { "/dm/sdr/0/rx/cd_l/frequency", { dsdr_hiper_lms8001_rcdl_reg_set, dsdr_hiper_lms8001_rcdl_reg_get }}, + { "/dm/sdr/0/rx/ab_h/frequency", { dsdr_hiper_lms8001_rabh_reg_set, dsdr_hiper_lms8001_rabh_reg_get }}, + { "/dm/sdr/0/rx/cd_h/frequency", { dsdr_hiper_lms8001_rcdh_reg_set, dsdr_hiper_lms8001_rcdh_reg_get }}, + { "/dm/sdr/0/tx/ab/frequency", { dsdr_hiper_lms8001_tab_reg_set, dsdr_hiper_lms8001_tab_reg_get }}, + { "/dm/sdr/0/tx/cd/frequency", { dsdr_hiper_lms8001_tcd_reg_set, dsdr_hiper_lms8001_tcd_reg_get }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/ab_l/freqency", { dsdr_hiper_lms8001_rabl_reg_set, dsdr_hiper_lms8001_rabl_reg_get }}, { "/dm/sdr/0/rx/cd_l/freqency", { dsdr_hiper_lms8001_rcdl_reg_set, dsdr_hiper_lms8001_rcdl_reg_get }}, { "/dm/sdr/0/rx/ab_h/freqency", { dsdr_hiper_lms8001_rabh_reg_set, dsdr_hiper_lms8001_rabh_reg_get }}, diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index 2ec631e5..cc3ba7f9 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -410,6 +410,17 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { { "/dm/sdr/0/tx/gain/6", { dev_m2_dsdr_gain_tx_set, NULL }}, { "/dm/sdr/0/tx/gain/7", { dev_m2_dsdr_gain_tx_set, NULL }}, + { "/dm/sdr/0/rx/frequency", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/0", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/1", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/2", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/3", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/4", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/5", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/6", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/7", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/freqency", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/rx/freqency/0", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/rx/freqency/1", { dev_m2_dsdr_sdr_rx_freq_set, NULL }}, @@ -430,6 +441,17 @@ const usdr_dev_param_func_t s_fparams_m2_dsdr_rev000[] = { { "/dm/sdr/0/rx/dsa/6", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, { "/dm/sdr/0/rx/dsa/7", { dev_m2_dsdr_sdr_rx_dsa_set, NULL }}, + { "/dm/sdr/0/tx/frequency", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/0", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/1", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/2", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/3", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/4", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/5", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/6", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/7", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/tx/freqency", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency/0", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency/1", { dev_m2_dsdr_sdr_tx_freq_set, NULL }}, @@ -1248,7 +1270,7 @@ int dev_m2_dsdr_sdr_rx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu return 0; if (obj->full_path[0]) - return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/freqency", true); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/frequency", true); return dsdr_set_rx_frequency_chan(d, value, obj->full_path[1]); } @@ -1297,7 +1319,7 @@ int dev_m2_dsdr_sdr_tx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t valu return 0; if (obj->full_path[0]) - return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/tx/freqency", false); + return dsdr_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/tx/frequency", false); return dsdr_set_tx_frequency_chan(d, value, obj->full_path[1]); } diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index d9796fa3..ee33b0bc 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -232,9 +232,15 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/calibrate", { dev_m2_lm6_1_sdr_dc_calib, NULL }}, + { "/dm/sdr/0/rx/frequency/lob",{ dev_m2_lm6_1_sdr_rx_freq_lob_set, NULL }}, + { "/dm/sdr/0/rx/frequency", { dev_m2_lm6_1_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency", { dev_m2_lm6_1_sdr_tx_freq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/freqency/lob",{ dev_m2_lm6_1_sdr_rx_freq_lob_set, NULL }}, { "/dm/sdr/0/rx/freqency", { dev_m2_lm6_1_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency", { dev_m2_lm6_1_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/rx/gain", { dev_m2_lm6_1_sdr_rx_gain_set, NULL }}, { "/dm/sdr/0/tx/gain", { dev_m2_lm6_1_sdr_tx_gain_set, NULL }}, { "/dm/sdr/0/tx/gain/vga1", { dev_m2_lm6_1_sdr_tx_gain_vga1_set, NULL }}, diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index f714b67b..8fff8333 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -297,11 +297,20 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/rx/phgaincorr",{ dev_m2_lm7_1_sdr_rx_phgaincorr_set, NULL }}, { "/dm/sdr/0/tx/phgaincorr",{ dev_m2_lm7_1_sdr_tx_phgaincorr_set, NULL }}, + { "/dm/sdr/0/rx/frequency/bb", { dev_m2_lm7_1_sdr_rx_bbfreq_set, NULL }}, + { "/dm/sdr/0/tx/frequency/bb", { dev_m2_lm7_1_sdr_tx_bbfreq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/freqency/bb", { dev_m2_lm7_1_sdr_rx_bbfreq_set, NULL }}, { "/dm/sdr/0/tx/freqency/bb", { dev_m2_lm7_1_sdr_tx_bbfreq_set, NULL }}, + { "/dm/sdr/0/rx/frequency", { dev_m2_lm7_1_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency", { dev_m2_lm7_1_sdr_tx_freq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/freqency", { dev_m2_lm7_1_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency", { dev_m2_lm7_1_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/rx/gain", { dev_m2_lm7_1_sdr_rx_gain_set, NULL }}, { "/dm/sdr/0/tx/gain", { dev_m2_lm7_1_sdr_tx_gain_set, NULL }}, { "/dm/sdr/0/tx/gain/lb", { dev_m2_lm7_1_sdr_tx_gainlb_set, NULL }}, @@ -325,19 +334,32 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/rxdsp/swapab", { dev_m2_lm7_1_sdr_rxdsp_swapab_set, NULL }}, + { "/dm/sdr/0/tdd/frequency", { dev_m2_lm7_1_sdr_tdd_freq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/tdd/freqency", { dev_m2_lm7_1_sdr_tdd_freq_set, NULL }}, + { "/dm/sdr/0/tfe/antcfg", { dev_m2_lm7_1_tx_antennat_port_cfg_set, NULL }}, { "/dm/sdr/0/tfe/generator/enable", { dev_m2_lm7_1_tfe_gen_en_set, NULL }}, { "/dm/sdr/0/tfe/generator/const", { dev_m2_lm7_1_tfe_gen_const_set, NULL }}, { "/dm/sdr/0/tfe/generator/tone", { dev_m2_lm7_1_tfe_gen_tone_set, NULL }}, { "/dm/sdr/0/tfe/nco/enable", { dev_m2_lm7_1_tfe_nco_enable_set, NULL }}, + + { "/dm/sdr/0/tfe/nco/frequency", { dev_m2_lm7_1_tfe_nco_enable_frequency, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/tfe/nco/freqency", { dev_m2_lm7_1_tfe_nco_enable_frequency, NULL }}, { "/dm/sdr/0/rfe/throttle", { dev_m2_lm7_1_rfe_throttle_set, NULL }}, { "/dm/sdr/0/rfe/nco/enable", { dev_m2_lm7_1_rfe_nco_enable_set, NULL }}, + + { "/dm/sdr/0/rfe/nco/frequency",{ dev_m2_lm7_1_rfe_nco_enable_frequency, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rfe/nco/freqency",{ dev_m2_lm7_1_rfe_nco_enable_frequency, NULL }}, + { "/dm/sdr/0/rfe/pwrdc", { NULL, dev_m2_lm7_1_rfe_nco_pwrdc_get }}, // Debug interface diff --git a/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c b/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c index e04a41f3..632c791f 100644 --- a/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c +++ b/src/lib/device/m2_lsdr/m2_da09_4_ad45_2.c @@ -180,7 +180,11 @@ const usdr_dev_param_func_t s_fparams_m2_da09_4_ad45_2_rev000[] = { { "/dm/sdr/0/rx/gain/vga", { dev_m2_d09_4_ad45_2_gainvga_set, NULL }}, { "/dm/sdr/0/rx/gain/lna", { dev_m2_d09_4_ad45_2_gainlna_set, NULL }}, + { "/dm/sdr/0/rx/frequency", { dev_m2_d09_4_ad45_2_sdr_rx_freq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/freqency", { dev_m2_d09_4_ad45_2_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/rx/bandwidth", { dev_m2_d09_4_ad45_2_sdr_rx_bandwidth_set, NULL }}, { "/dm/sdr/0/rx/path", { dev_m2_d09_4_ad45_2_dummy, NULL }}, diff --git a/src/lib/device/u3_limesdr/u3_limesdr.c b/src/lib/device/u3_limesdr/u3_limesdr.c index 127722b5..6418b066 100644 --- a/src/lib/device/u3_limesdr/u3_limesdr.c +++ b/src/lib/device/u3_limesdr/u3_limesdr.c @@ -91,8 +91,13 @@ const usdr_dev_param_func_t s_fparams_u3_limesdr_0[] = { { "/dm/sdr/refclk/path", { dev_limesdr_refclk_path_set, NULL }}, { "/dm/power/en", { dev_limesdr_pwren_set, NULL }}, + { "/dm/sdr/0/rx/frequency", { dev_limesdr_sdr_rx_freq_set, NULL }}, + { "/dm/sdr/0/tx/frequency", { dev_limesdr_sdr_tx_freq_set, NULL }}, + + /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/freqency", { dev_limesdr_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/tx/freqency", { dev_limesdr_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/rx/gain", { dev_limesdr_sdr_rx_gain_set, NULL }}, { "/dm/sdr/0/tx/gain", { dev_limesdr_sdr_tx_gain_set, NULL }}, { "/dm/sdr/0/tx/gain/lb", { dev_limesdr_sdr_tx_gainlb_set, NULL }}, diff --git a/src/lib/hw/lmk04832/lmk04832.c b/src/lib/hw/lmk04832/lmk04832.c index d3dd1988..408db7a3 100644 --- a/src/lib/hw/lmk04832/lmk04832.c +++ b/src/lib/hw/lmk04832/lmk04832.c @@ -335,7 +335,7 @@ pll2_configured:; MAKE_LMK04832_PLL2_N_LOW(pll2_n), 0x016959, //PLL2_DLD_EN - //SYSREF enable in continous from data clock + //SYSREF enable in continuous from data clock //0x013903, //0x013a00, //0x013b08, @@ -432,7 +432,7 @@ int lmk04832_sysref_div_set(lldev_t dev, subdev_t subdev, lsopaddr_t addr, 0x014310, 0x0144ff, - //SYSREF enable in continous from data clock + //SYSREF enable in continuous from data clock 0x013903, //DDIV diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index 26ebbb59..05de2387 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -1146,7 +1146,7 @@ int lms8001_smart_tune(lms8001_state_t* m, unsigned tune_flags, uint64_t flo, in int lms8001_reg_set(lms8001_state_t* m, uint16_t addr, uint16_t val) { - // Update internal state to syncronze cahce values + // Update internal state to synchronize cache values if (addr >= PLL_CONFIGURATION_PLL_VREG) { switch (addr) { diff --git a/src/lib/ipblks/lms64c_proto.c b/src/lib/ipblks/lms64c_proto.c index e359f7c8..4dbfe39d 100644 --- a/src/lib/ipblks/lms64c_proto.c +++ b/src/lib/ipblks/lms64c_proto.c @@ -114,7 +114,7 @@ int lms64c_fill_packet(uint8_t cmd, uint8_t status, uint8_t id, const uint8_t* d } else if (mod == MOD_INT16) { const uint16_t* d = (const uint16_t*)&data[off]; for (unsigned i = 0; i < this_pkt_data; i += 2) { - // TODO: Endianess + // TODO: Endianness out[k].data[i + 0] = d[i >> 1] >> 8; out[k].data[i + 1] = d[i >> 1] & 0xFF; } @@ -140,7 +140,7 @@ int lms64c_parse_packet(uint8_t cmd, const proto_lms64c_t* in, unsigned in_cnt, unsigned bsz = (remaining > LMS64C_DATA_LENGTH) ? LMS64C_DATA_LENGTH : remaining; if (mod == MOD_INT32_16) { - // TODO: Endianess + // TODO: Endianness const uint16_t* d = (const uint16_t*)in[i].data; for (unsigned j = 0; j < bsz; j += 2) { data[off + j + 0] = d[j + 1] >> 8; diff --git a/src/lib/ipblks/streams/stream_limesdr.c b/src/lib/ipblks/streams/stream_limesdr.c index f68921a8..73504815 100644 --- a/src/lib/ipblks/streams/stream_limesdr.c +++ b/src/lib/ipblks/streams/stream_limesdr.c @@ -47,7 +47,7 @@ struct stream_limesdr { // Streaming parameters unsigned burst_count; // Bursts in packet unsigned burst_symbs; - unsigned burst_bytes; // Busrt bytes contating samples + unsigned burst_bytes; // Burst bytes containing samples unsigned burst_host_bytes; unsigned block_samples; // Number samples in one process block (4K) unsigned tx_sampl_c; diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index cc6ea132..7dd90b58 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -57,7 +57,7 @@ struct stream_sfetrx_dma32 { // Cached values unsigned cnf_base; unsigned sync_base; // TODO: for compatibility with OLD APIs - unsigned cnfrd_base; // Reabdack address for OLD API + unsigned cnfrd_base; // Readback address for OLD API unsigned pkt_symbs; // Total number of symbols in a transaction (all bursts) unsigned pkt_bytes; // Wire bytes for a transaction (excl. packing overhead) @@ -81,7 +81,7 @@ struct stream_sfetrx_dma32 { uint8_t fe_old_tx_mute; // keep OLD TX FE in sync with host state uint8_t fe_old_tx_swap; // keep OLD TX FE in sync with host state unsigned fe_chans; // Number of active channels in frontend - unsigned fe_complex; // Compex data streaming + unsigned fe_complex; // Complex data streaming union { sfe_cfg_t srx4; } storage; @@ -108,7 +108,7 @@ int _sfetrx4_destroy(stream_handle_t* str) int res; if (stream->type == USDR_ZCPY_RX) { - //Grcefull stop + //Gracefull stop res = lowlevel_reg_wr32(dev, 0, stream->cnf_base + 1, 0); if (res) @@ -296,7 +296,7 @@ void parse_txcore_stat(uint32_t stat[4], txcore_statistics_t* s) // Understanding counters (PCIe mode) // usrbuf_posted -- PCIe Buffer metadata posted // usrbuf_requested -- PCIe Buffer all MemRd requests are sent - // usrbuf_completed -- PCIe Beffer data has been placed into FIFO RAM + // usrbuf_completed -- PCIe Buffer data has been placed into FIFO RAM // usrbuf_aired -- PCIe Buffer has been completly played out (available for reuse) bool usb = (stat[0] & 0x8); @@ -529,7 +529,7 @@ static int _sfetrx4_op(stream_handle_t* str, if (res) return res; } else { - // Assuming Compex IQ + // Assuming Complex IQ unsigned lgchcnt = (stream->fe_chans == 1) ? 0 : (stream->fe_chans == 2) ? 1 : (stream->fe_chans == 4) ? 2 : 3; @@ -1275,7 +1275,7 @@ int sfetrx4_stream_sync(device_t* device, stream_sfetrx_dma32_t** pstream = (stream_sfetrx_dma32_t**)pstr; res = usdr_device_vfs_obj_val_get_u64(device, "/ll/sync/0/base", &sync_base); if (res) { - USDR_LL_LOG(device->dev, "DSTR", USDR_LOG_ERROR, "SYNC: Broken device! Coulnd't obtain sync addr: %d\n", res); + USDR_LL_LOG(device->dev, "DSTR", USDR_LOG_ERROR, "SYNC: Broken device! Couldn't obtain sync addr: %d\n", res); return res; } retimer_base = sync_base; diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.h b/src/lib/ipblks/streams/stream_sfetrx4_dma32.h index 326bbd4a..d6f896b8 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.h +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.h @@ -56,7 +56,7 @@ int create_sfetrx4_stream(device_t* device, stream_handle_t** outu, unsigned *hw_chans_cnt); -// Syncronize streams +// Synchronize streams int sfetrx4_stream_sync(device_t* device, stream_handle_t** pstream, unsigned scount, const char* synctype); diff --git a/src/lib/ipblks/xlnx_bitstream.c b/src/lib/ipblks/xlnx_bitstream.c index bfd40918..f067871d 100644 --- a/src/lib/ipblks/xlnx_bitstream.c +++ b/src/lib/ipblks/xlnx_bitstream.c @@ -179,7 +179,7 @@ int xlnx_btstrm_parse_header_ex(const uint32_t* mem, } if (count == 1 && ptype == 1 && reg != 1 && reg != XLNX_REG_CMD) { - USDR_LOG("BSTR", USDR_LOG_NOTE, "Rgister %x: %x\n", reg, w); + USDR_LOG("BSTR", USDR_LOG_NOTE, "Register %x: %x\n", reg, w); } if (flags & XLNX_BSTRM_PARSE_F_CRC_CHECK) { diff --git a/src/lib/json_controller/controller.c b/src/lib/json_controller/controller.c index 1aea5959..342e467e 100644 --- a/src/lib/json_controller/controller.c +++ b/src/lib/json_controller/controller.c @@ -356,7 +356,7 @@ int generic_rpc_call(pdm_dev_t dmdev, uint64_t actual; res = set_endpoint_uint_param(dmdev, - (pcall->call_type == SDR_RX_FREQUENCY) ? "/dm/sdr/0/rx/freqency" : "/dm/sdr/0/tx/freqency", + (pcall->call_type == SDR_RX_FREQUENCY) ? "/dm/sdr/0/rx/frequency" : "/dm/sdr/0/tx/frequency", freq, &actual); if (res) diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index 39f7b238..3b00a108 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -601,7 +601,7 @@ void LIBUSB_CALL libusb_transfer_buffers_cb(struct libusb_transfer *transfer) idx, transfer->status, transfer->actual_length, transfer->length); if (rxb->stop) { - // TODO: Syncronize EPs + // TODO: Synchronize EPs return; } diff --git a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c index bcaf9b06..5aaf5732 100644 --- a/src/lib/lowlevel/pcie_uram/pcie_uram_main.c +++ b/src/lib/lowlevel/pcie_uram/pcie_uram_main.c @@ -595,7 +595,7 @@ int pcie_uram_dma_wait_or_alloc(struct pcie_uram_dev* d, bool rx, stream_t chann } sc->bufavail = res; - USDR_LL_LOG(&d->ll, "PCIE", (res > 1) ? USDR_LOG_NOTE : USDR_LOG_DEBUG, "STR[%d]: Alloced %d buffs, BNO=%d (%016lx) seq=%16ld OOB_sz=%d\n", + USDR_LL_LOG(&d->ll, "PCIE", (res > 1) ? USDR_LOG_NOTE : USDR_LOG_DEBUG, "STR[%d]: Allocated %d buffs, BNO=%d (%016lx) seq=%16ld OOB_sz=%d\n", channel, res, sc->bno, (oob_ptr) ? (*(uint64_t*)sc->oob_cache) : 0, sc->seq, sc->oob_size); } @@ -951,9 +951,9 @@ int pcie_uram_plugin_create(unsigned pcount, const char** devparam, const char** err = usdr_device_create(&dev->ll, did); if (err) { USDR_LL_LOG(&dev->ll, "PCIE", USDR_LOG_ERROR, - "Unable to find device spcec for %s, uuid %s! Update software!\n", - dev->name, - usdr_device_id_to_str(did)); + "Unable to find device spec for %s, uuid %s! Update software!\n", + dev->name, + usdr_device_id_to_str(did)); goto remove_dev; } diff --git a/src/lib/lowlevel/usb_ft601/usb_ft601_generic.c b/src/lib/lowlevel/usb_ft601/usb_ft601_generic.c index 2164d9fd..00b0d4e1 100644 --- a/src/lib/lowlevel/usb_ft601/usb_ft601_generic.c +++ b/src/lib/lowlevel/usb_ft601/usb_ft601_generic.c @@ -100,7 +100,7 @@ int usbft601_uram_ls_op(lldev_t dev, subdev_t subdev, if (memoutsz * 2 > sizeof(tmpbuf_out)) return -E2BIG; - // Rgister write + // Register write const uint16_t* out_s = (const uint16_t* )pout; for (unsigned i = 0; i < memoutsz / 2; i++) { tmpbuf_out[2 * i + 1] = ls_op_addr + i; @@ -200,8 +200,8 @@ int usbft601_uram_generic_create_and_init(lldev_t lld, unsigned pcount, const ch res = usdr_device_create(lld, *pdevid); if (res) { USDR_LOG(USBG_LOG_TAG, USDR_LOG_ERROR, - "Unable to find device spcec for %s, uuid %s! Update software!\n", - devname, usdr_device_id_to_str(*pdevid)); + "Unable to find device spec for %s, uuid %s! Update software!\n", + devname, usdr_device_id_to_str(*pdevid)); return res; } diff --git a/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c b/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c index 581caf56..f78d5d10 100644 --- a/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c +++ b/src/lib/lowlevel/usb_ft601/usb_ft601_libusb.c @@ -325,7 +325,7 @@ int usbft601_uram_send_dma_commit(lldev_t dev, subdev_t subdev, stream_t channel // Add to senq res = buffers_usb_transfer_post(rxb, bno, sz, bno); if (res) { - USDR_LOG("USBX", USDR_LOG_ERROR,"USB TX%d unable to post busrt to sendq (error %d)\n", channel, res); + USDR_LOG("USBX", USDR_LOG_ERROR,"USB TX%d unable to post burst to sendq (error %d)\n", channel, res); return res; } diff --git a/src/lib/lowlevel/usb_uram/usb_uram_generic.c b/src/lib/lowlevel/usb_uram/usb_uram_generic.c index 0d1587c2..85222572 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_generic.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_generic.c @@ -301,8 +301,8 @@ int usb_uram_generic_create_and_init(lldev_t dev, unsigned pcount, const char** res = usdr_device_create(dev, *pdevid); if (res) { USDR_LOG(USBG_LOG_TAG, USDR_LOG_ERROR, - "Unable to find device spcec for %s, uuid %s! Update software!\n", - devname, usdr_device_id_to_str(*pdevid)); + "Unable to find device spec for %s, uuid %s! Update software!\n", + devname, usdr_device_id_to_str(*pdevid)); return res; } diff --git a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c index 60c71f51..8dc6777e 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c @@ -777,7 +777,7 @@ int usb_uram_send_dma_commit(lldev_t dev, subdev_t subdev, stream_t channel, voi // Add to senq res = buffers_usb_transfer_post(rxb, bno, sz + 16, bno); if (res) { - USDR_LOG("USBX", USDR_LOG_ERROR,"USB TX%d unable to post busrt to sendq (error %d)\n", channel, res); + USDR_LOG("USBX", USDR_LOG_ERROR,"USB TX%d unable to post burst to sendq (error %d)\n", channel, res); return res; } return 0; diff --git a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c index c904412e..b9253576 100644 --- a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c +++ b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c @@ -923,8 +923,8 @@ int verilator_wrap_plugin_create(unsigned pcount, const char** devparam, res = usdr_device_create(dev, did, &dev->udev); if (res) { USDR_LOG("VERI", USDR_LOG_ERROR, - "Unable to find device spcec for %s, uuid %s! Update software!\n", - dev->name, usdr_device_id_to_str(did)); + "Unable to find device spec for %s, uuid %s! Update software!\n", + dev->name, usdr_device_id_to_str(did)); goto remove_dev; } diff --git a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.h b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.h index a40684f7..012f9369 100644 --- a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.h +++ b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.h @@ -1,7 +1,7 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT -// Communiction protocol +// Communication protocol #include diff --git a/src/lib/lowlevel/verilator_ll/vpu.h b/src/lib/lowlevel/verilator_ll/vpu.h index b68534b4..6bd543a4 100644 --- a/src/lib/lowlevel/verilator_ll/vpu.h +++ b/src/lib/lowlevel/verilator_ll/vpu.h @@ -1,7 +1,7 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT -// Communiction protocol +// Communication protocol #ifndef VPU_H #define VPU_H diff --git a/src/lib/xdsp/sincos_functions.h b/src/lib/xdsp/sincos_functions.h index 0666d33b..4fb4a261 100644 --- a/src/lib/xdsp/sincos_functions.h +++ b/src/lib/xdsp/sincos_functions.h @@ -32,7 +32,7 @@ sincos_i16_interleaved_ctrl_function_t get_wvlt_sincos_i16_interleaved_ctrl(); * wvlt_sincos_i16_interleaved_ctrl() * * int32_t* start_phase: Starting phase. - * Diapazon [-PI..+PI) mapped to int32 range INT32_MIN..INT32_MAX. + * Range [-PI..+PI) mapped to int32 range INT32_MIN..INT32_MAX. * The next starting phase for consequent calls is returned by ptr. * int32_t delta_phase: Delta, applying to starting phase. int32_t range is just the same as for start_phase. * int16_t gain: Output max amplitude diff --git a/src/soapysdr/usdr_soapy.cpp b/src/soapysdr/usdr_soapy.cpp index b39aab6f..ed05edff 100644 --- a/src/soapysdr/usdr_soapy.cpp +++ b/src/soapysdr/usdr_soapy.cpp @@ -593,7 +593,7 @@ void SoapyUSDR::setFrequency(const int direction, const size_t channel, const st int res; const char* dir = (direction == SOAPY_SDR_TX) ? "tx" : "rx"; - const char* pname = get_sdr_param(0, dir, "freqency", (name == "BB") ? "bb" : NULL); + const char* pname = get_sdr_param(0, dir, "frequency", (name == "BB") ? "bb" : NULL); uint64_t val = (((uint64_t)channel) << 32) | (uint32_t)frequency; diff --git a/src/tests/lms7_cal.c b/src/tests/lms7_cal.c index 0a56fb53..a0dd360b 100644 --- a/src/tests/lms7_cal.c +++ b/src/tests/lms7_cal.c @@ -162,14 +162,14 @@ int dev_initialize(const char* devstring, unsigned spb, unsigned loglevel, float fprintf(stderr, "Configured %d x %d buffs\n", blksz, bufcnt); - res = usdr_dme_set_uint(dev, usdr_dmd_find_entity(dev, "/dm/sdr/0/rx/freqency"), freq); + res = usdr_dme_set_uint(dev, usdr_dmd_find_entity(dev, "/dm/sdr/0/rx/frequency"), freq); if (res) { fprintf(stderr, "Unable to set rx frequency: errno %d\n", res); goto dev_close; } if (freq_tx > 0) { - res = usdr_dme_set_uint(dev, usdr_dmd_find_entity(dev, "/dm/sdr/0/tx/freqency"), freq_tx); + res = usdr_dme_set_uint(dev, usdr_dmd_find_entity(dev, "/dm/sdr/0/tx/frequency"), freq_tx); if (res) { fprintf(stderr, "Unable to set tx frequency: errno %d\n", res); goto dev_close; diff --git a/src/tests/lowlevel_lvds_perf.c b/src/tests/lowlevel_lvds_perf.c index b64187b4..ed3aaf25 100644 --- a/src/tests/lowlevel_lvds_perf.c +++ b/src/tests/lowlevel_lvds_perf.c @@ -479,7 +479,7 @@ int main(int argc, char** argv) usdrlog_setlevel(NULL, USDR_LOG_TRACE); usdrlog_enablecolorize(NULL); unsigned iten = 100; // Iterate over smaplerate - unsigned cont = 0; // Continous test + unsigned cont = 0; // Continuous test unsigned longtest = 0; unsigned loglevel = 2; unsigned verbosity = 1; diff --git a/src/tests/simpleapi.c b/src/tests/simpleapi.c index ac041a3c..196437a3 100644 --- a/src/tests/simpleapi.c +++ b/src/tests/simpleapi.c @@ -54,7 +54,7 @@ void Initialize(const char* device_string, int loglevel, CheckErrorAndDie(res, "rx info"); res = usdr_dms_sync(pdev->dev, "off", 2, pdev->strms); - CheckErrorAndDie(res, "tx & rx syncronization off"); + CheckErrorAndDie(res, "tx & rx synchronization off"); res = usdr_dms_op(pdev->strms[0], USDR_DMS_START, 0); CheckErrorAndDie(res, "rx stream precharge"); @@ -179,14 +179,14 @@ void SetRxPgaGain(sdr_data_t* pdev, int gain) void SetTxFreq(sdr_data_t* pdev, unsigned freq) { int res; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/freqency", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/frequency", freq); CheckErrorAndDie(res, "SetTxFreq"); } void SetRxFreq(sdr_data_t* pdev, unsigned freq) { int res; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/freqency", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/frequency", freq); CheckErrorAndDie(res, "SetRxFreq"); } @@ -195,7 +195,7 @@ void SetBBTxFreq(sdr_data_t* pdev, int chan, int freq) { int res; uint64_t val = (((uint64_t)chan) << 32) | (uint32_t)freq; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/freqency/bb", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/frequency/bb", val); CheckErrorAndDie(res, "SetBBTxFreq"); } @@ -203,7 +203,7 @@ void SetBBRxFreq(sdr_data_t* pdev, int chan, int freq) { int res; uint64_t val = (((uint64_t)chan) << 32) | (uint32_t)freq; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/freqency/bb", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/frequency/bb", val); CheckErrorAndDie(res, "SetBBRxFreq"); } diff --git a/src/tests/usdr_simple_api_test.c b/src/tests/usdr_simple_api_test.c index 838ba576..b6cda5de 100644 --- a/src/tests/usdr_simple_api_test.c +++ b/src/tests/usdr_simple_api_test.c @@ -120,7 +120,7 @@ void Initialize(const char* device_string, int loglevel, CheckErrorAndDie(res, "rx info"); res = usdr_dms_sync(pdev->dev, "off", 2, pdev->strms); - CheckErrorAndDie(res, "tx & rx syncronization off"); + CheckErrorAndDie(res, "tx & rx synchronization off"); res = usdr_dms_op(pdev->strms[0], USDR_DMS_START, 0); CheckErrorAndDie(res, "rx stream precharge"); @@ -235,14 +235,14 @@ void SetRxPgaGain(sdr_data_t* pdev, int gain) void SetTxFreq(sdr_data_t* pdev, unsigned freq) { int res; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/freqency", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/frequency", freq); CheckErrorAndDie(res, "SetTxFreq"); } void SetRxFreq(sdr_data_t* pdev, unsigned freq) { int res; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/freqency", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/frequency", freq); CheckErrorAndDie(res, "SetRxFreq"); } @@ -251,7 +251,7 @@ void SetBBTxFreq(sdr_data_t* pdev, int chan, int freq) { int res; uint64_t val = (((uint64_t)chan) << 32) | (uint32_t)freq; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/freqency/bb", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/tx/frequency/bb", val); CheckErrorAndDie(res, "SetBBTxFreq"); } @@ -259,7 +259,7 @@ void SetBBRxFreq(sdr_data_t* pdev, int chan, int freq) { int res; uint64_t val = (((uint64_t)chan) << 32) | (uint32_t)freq; - res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/freqency/bb", + res = usdr_dme_set_uint(pdev->dev, "/dm/sdr/0/rx/frequency/bb", val); CheckErrorAndDie(res, "SetBBRxFreq"); } @@ -378,7 +378,7 @@ int main(int argc, char** argv) SetTxBandwidth(&data, tx_bandwidth); SetRxBandwidth(&data, rx_bandwidth); - // Optionall tune frequency offset + // Optionally tune frequency offset // TrimDacVCTCXO(&data, 43981); // Do calibration only when All gains / freqs are set but before actual start diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index 3f1ece2e..8d459052 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -657,10 +657,10 @@ int main(UNUSED int argc, UNUSED char** argv) //Device parameters // { endpoint, default_value, ignore flag, stop_on_fail flag } struct dme_findsetv_data dev_data[] = { - [DD_RX_FREQ] = { "rx/freqency", 900e6, true, true }, - [DD_TX_FREQ] = { "tx/freqency", 920e6, true, true }, + [DD_RX_FREQ] = { "rx/frequency", 900e6, true, true }, + [DD_TX_FREQ] = { "tx/frequency", 920e6, true, true }, - [DD_TDD_FREQ] = { "tdd/freqency", 910e6, true, true }, + [DD_TDD_FREQ] = { "tdd/frequency", 910e6, true, true }, [DD_RX_BANDWIDTH] = { "rx/bandwidth", 1e6, true, true }, [DD_TX_BANDWIDTH] = { "tx/bandwidth", 1e6, true, true }, From 4dbfdf1c2cfa3c2cb6aa1fbd74525c96ca9de419 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 27 Feb 2026 14:36:39 +0400 Subject: [PATCH 325/397] ssdrrev3: fix for ultrascale --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 19 ++++++++++++++----- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 8 ++++++++ src/lib/ipblks/xlnx_mmcm.c | 3 ++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 851156b9..cddd1249 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -344,6 +344,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, int res = 0; struct mmcm_config_raw cfg_raw; memset(&cfg_raw, 0, sizeof(cfg_raw)); + cfg_raw.type = (d->xilinx_usp) ? MT_USP_MMCM : MT_7SERIES_MMCM; if (vco_div_io * io_clk < MMCM_VCO_MIN && vco_div_io < 63) { if ((vco_div_io + 2) * io_clk > MMCM_VCO_MAX) { @@ -365,8 +366,6 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, // 6 - FCLK_TX #define SEP_CLKDIV - - cfg_raw.type = MT_7SERIES_MMCM; #ifndef SEP_CLKDIV cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; // IO_TX_IQSEL cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; // IO_TX_IQSEL @@ -490,11 +489,11 @@ int xsdr_configure_lml_mmcm_rx(xsdr_dev_t *d) int res = 0; struct mmcm_config_raw cfg_raw; memset(&cfg_raw, 0, sizeof(cfg_raw)); + cfg_raw.type = (d->xilinx_usp) ? MT_USP_MMCM : MT_7SERIES_MMCM; if (vco_div_io > 63) vco_div_io = 63; - cfg_raw.type = MT_7SERIES_MMCM; cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; @@ -669,14 +668,17 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) g_clk_reduce = 0; // Fixup for SSDR_PRO +#if 0 if (d->ssdr_pro) { // RX SISO DDR res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, d->siso_sdr_active_rx ? (1u << 9) : 0); return res; } +#endif if (d->mmcm_tx) { + if (!d->ssdr_pro) { // Boost IO voltage for stable high speed link if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && (d->s_rxrate > 85e6 || d->s_txrate > 85e6)) { res = res ? res : xsdr_set_vio(d, 1910); @@ -689,6 +691,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (!mmcm_rx_only_path && d->new_rev && !d->ssdr && (d->s_txrate >= 53e6 && d->s_txrate <= 60e6)) { res = res ? res : xsdr_set_lms125vdd(d, 1360); } + } if (!(d->base.rx_run[0] || d->base.rx_run[1])) { res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS_PWR, IGPO_LMS_PWR_LDOEN | IGPO_LMS_PWR_NRESET | IGPO_LMS_PWR_RXEN | IGPO_LMS_PWR_TXEN); @@ -767,6 +770,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) badness_m = badness; phase_m = ph; } + + //goto skip_cal; } if (phase_max > phase_min) { @@ -805,7 +810,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) break; } - +skip_cal: d->lmlcal_rx_phase = phase_m; if (mmcm_rx_only_path) @@ -1051,6 +1056,8 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, if (txrate || d->ssdr_pro) { res = res ? res : _xsdr_calibrate_lml(d); + + //TODO check tsp/rsp states } return res; @@ -1886,6 +1893,7 @@ int xsdr_set_lms125vdd(xsdr_dev_t *d, unsigned vdd_mv) int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) { + if (!d->new_rev) { if (vio_mv > 3300) vio_mv = 3300; @@ -1979,6 +1987,7 @@ int xsdr_init(xsdr_dev_t *d) d->cfg_srate_siso_tx = 0; d->dpump = false; d->ssdr_pro = false; + d->xilinx_usp = false; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); if (res) { @@ -1989,7 +1998,7 @@ int xsdr_init(xsdr_dev_t *d) case XSDR_DEV: d->new_rev = true; d->ssdr = false; break; case XTRX_DEV: d->new_rev = false; d->ssdr = false; break; case SSDR_DEV: d->new_rev = true; d->ssdr = true; break; - case SSDRPRO_DEV: d->new_rev = true; d->ssdr = true; d->ssdr_pro = true; break; + case SSDRPRO_DEV: d->new_rev = true; d->ssdr = true; d->ssdr_pro = true; d->xilinx_usp = true; break; default: USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "unsupported hwcfg_devid=%02x\n", hwcfg_devid); diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 55ffcd75..20414443 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -23,6 +23,13 @@ enum xsdr_devices { XTRX_DEV = 0x2e, }; +enum xsdr_lml_phy_modes { + MODE_INVALID = 0, + MODE_SHARED_MMCM_RX_TX = 1, // Single MMCM for RX / TX + MODE_MMCM_TX_ONLY = 2, + MODE_DUAL_MMCM_RX_TX = 3, +}; +typedef enum xsdr_lml_phy_modes xsdr_lml_phy_modes_t; // =================================================================== // Frequency LMS7 DAC/ADC LML interface Baseband @@ -71,6 +78,7 @@ struct xsdr_dev bool ssdr; bool ssdr_pro; bool lms8_alive; + bool xilinx_usp; bool dpump; //Dual pump data union { diff --git a/src/lib/ipblks/xlnx_mmcm.c b/src/lib/ipblks/xlnx_mmcm.c index 7c872510..427e32f8 100644 --- a/src/lib/ipblks/xlnx_mmcm.c +++ b/src/lib/ipblks/xlnx_mmcm.c @@ -217,7 +217,8 @@ int mmcm_init_raw(lldev_t dev, subdev_t subdev, int res; unsigned clkfbdiv = cfg->ports[CLKOUT_PORT_FB].period_h + cfg->ports[CLKOUT_PORT_FB].period_l; - res = lowlevel_drp_wr16(dev, subdev, drp_port, PowerRegV7, 0xffff); + res = lowlevel_drp_wr16(dev, subdev, drp_port, + (cfg->type == MT_7SERIES_MMCM || cfg->type == MT_7SERIES_PLLE2) ? PowerRegV7 : PowerRegUS, 0xffff); if (res) { USDR_LOG("MMCM", USDR_LOG_ERROR, " unable to turn it on\n"); return res; From f73eb83ade92de2770848136457a9fd13953e78f Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 27 Feb 2026 14:38:05 +0400 Subject: [PATCH 326/397] usdr_dm_create: add loopback option --- src/tools/usdr_dm_create.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index 8d459052..31fbe6ca 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -371,6 +371,8 @@ enum { DD_TX_GAIN, DD_TX_PATH, DD_RX_PATH, + + DD_TX_GAIN_LB, //Must be followed by DD_TX_PATH & DD_RX_PATH }; /* @@ -673,6 +675,7 @@ int main(UNUSED int argc, UNUSED char** argv) [DD_RX_PATH] = { "rx/path", (uintptr_t)"rx_auto", false, true }, [DD_TX_PATH] = { "tx/path", (uintptr_t)"tx_auto", false, true }, + [DD_TX_GAIN_LB] = { "tx/gain/lb", 0, true, true }, }; //primary logging for proper usage() call - may be overriden below @@ -680,7 +683,8 @@ int main(UNUSED int argc, UNUSED char** argv) //set colored log output usdrlog_enablecolorize(NULL); - while ((opt = getopt(argc, argv, "b:B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:")) != -1) { + // Still available: kmMvVL + while ((opt = getopt(argc, argv, "b:B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:K:")) != -1) { switch (opt) { //Time-division duplexing (TDD) frequency case 'q': dev_data[DD_TDD_FREQ].value = atof(optarg); dev_data[DD_TDD_FREQ].ignore = false; break; @@ -704,6 +708,8 @@ int main(UNUSED int argc, UNUSED char** argv) case 'u': dev_data[DD_RX_GAIN_PGA].value = atoi(optarg); dev_data[DD_RX_GAIN_PGA].ignore = false; break; //RX VGA gain case 'U': dev_data[DD_RX_GAIN_VGA].value = atoi(optarg); dev_data[DD_RX_GAIN_VGA].ignore = false; break; + //TX loopback gain + case 'K': dev_data[DD_TX_GAIN_LB].value = atoi(optarg); dev_data[DD_TX_GAIN_LB].ignore = false; break; case 'G': calibrate = atoi(optarg); break; @@ -1060,7 +1066,7 @@ int main(UNUSED int argc, UNUSED char** argv) res = res ? res : usdr_dms_info(usds_rx, &snfo_rx); if (res) { USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to get RX data stream info: errno %d", res); - goto dev_close; + if (stop_on_error) goto dev_close; } else { s_rx_blksampl = snfo_rx.pktsyms; s_rx_blksz = snfo_rx.pktbszie; @@ -1084,7 +1090,7 @@ int main(UNUSED int argc, UNUSED char** argv) res = res ? res : usdr_dms_info(usds_tx, &snfo_tx); if (res) { USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to get TX data stream info: errno %d", res); - goto dev_close; + if (stop_on_error) goto dev_close; } else { s_tx_blksz = snfo_tx.pktbszie; s_tx_blksampl = snfo_tx.pktsyms; @@ -1259,6 +1265,11 @@ int main(UNUSED int argc, UNUSED char** argv) //Set device parameters from the dev_data struct (see above) if (!noinit) { + if (!stop_on_error) { + for (unsigned i = 0; i < SIZEOF_ARRAY(dev_data); i++) { + dev_data[i].stopOnFail = false; + } + } res = usdr_dme_findsetv_uint(dev, "/dm/sdr/0/", SIZEOF_ARRAY(dev_data), dev_data); if (res) { USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to set device parameters: errno %d", res); From 1f603b9189d67ee24e1d70def98d6d2648686517 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 28 Feb 2026 02:13:09 +0400 Subject: [PATCH 327/397] mac: fix sincosf() --- src/lib/port/usdr_port.c | 9 +++++++++ src/lib/xdsp/fmquad.c | 2 +- src/lib/xdsp/templates/wvlt_sincos_i16_generic.t | 2 +- .../templates/wvlt_sincos_i16_interleaved_ctrl_generic.t | 2 +- .../templates/wvlt_sincos_i16_interleaved_ctrl_neon.t | 2 +- src/lib/xdsp/templates/wvlt_sincos_i16_neon.t | 2 +- 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/lib/port/usdr_port.c b/src/lib/port/usdr_port.c index 991e9ba8..f063a7b3 100644 --- a/src/lib/port/usdr_port.c +++ b/src/lib/port/usdr_port.c @@ -257,7 +257,16 @@ int usdr_set_thread_name(const char* name) { #ifdef __APPLE__ #include +extern void __sincosf(float x, float *s, float *c); + void sincosf(float x, float *sin_val, float *cos_val) { + + // __sincosf exists starting macOS 10.9 + if (__builtin_available(macOS 10.9, *)) { + __sincosf(x, s, c); + return; + } + // macOS provides __sincosf_stret on some versions, but it's not reliable // Use the straightforward implementation *sin_val = sinf(x); diff --git a/src/lib/xdsp/fmquad.c b/src/lib/xdsp/fmquad.c index 5da5d587..b9e65d4f 100644 --- a/src/lib/xdsp/fmquad.c +++ b/src/lib/xdsp/fmquad.c @@ -23,7 +23,7 @@ float quadfm_encode(unsigned samples, float fi, fq; iangle += da; - //sincosf(iangle, &fq, &fi); + sincosf(iangle, &fq, &fi); int16_t vi, vq; vi = (int16_t)(fi * 0.7f * 32767.0f); diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t b/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t index 69651901..e8e88fa9 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_generic.t @@ -17,7 +17,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, { const float ph = WVLT_SINCOS_I16_PHSCALE * *phase++; float ssin, scos; - //sincosf(ph, &ssin, &scos); + sincosf(ph, &ssin, &scos); *sindata++ = ssin * WVLT_SINCOS_I16_SCALE; *cosdata++ = scos * WVLT_SINCOS_I16_SCALE; i -= 2; diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t index cd826fa9..6bd65779 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_generic.t @@ -17,7 +17,7 @@ void TEMPLATE_FUNC_NAME(int32_t *__restrict start_phase, const float ph = WVLT_SINCOS_I32_PHSCALE * phase; float ssin, scos; - //sincosf(ph, &ssin, &scos); + sincosf(ph, &ssin, &scos); *outdata++ = ssin * gain * sign_sin; *outdata++ = scos * gain * sign_cos; diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t index ee2b5160..1b0e7f66 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_ctrl_neon.t @@ -66,7 +66,7 @@ void TEMPLATE_FUNC_NAME(int32_t *__restrict start_phase, const float ph = WVLT_SINCOS_I32_PHSCALE * phase; float ssin, scos; - //sincosf(ph, &ssin, &scos); + sincosf(ph, &ssin, &scos); *outdata++ = ssin * gain * sign_sin; *outdata++ = scos * gain * sign_cos; diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t b/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t index 1c35fe69..4d14a8c8 100644 --- a/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_neon.t @@ -36,7 +36,7 @@ void TEMPLATE_FUNC_NAME(const void *__restrict indata, { const float ph = WVLT_SINCOS_I16_PHSCALE * *phase++; float ssin, scos; - //sincosf(ph, &ssin, &scos); + sincosf(ph, &ssin, &scos); *sindata++ = ssin * WVLT_SINCOS_I16_SCALE; *cosdata++ = scos * WVLT_SINCOS_I16_SCALE; i -= 2; From 22489e258a5a82f145a90790a16ab99fbf98e55e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 28 Feb 2026 02:13:43 +0400 Subject: [PATCH 328/397] printf: fix formatting --- src/lib/lowlevel/libusb_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index d2ebaa15..53e970ec 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -220,7 +220,7 @@ int libusb_generic_plugin_create(unsigned pcount, const char** devparam, if (fcnt == 0) { USDR_LOG("USBX", USDR_LOG_NOTE, "No USB device was found to match %d/%d/%d, total=%d\n", - fparams.usb_bus, fparams.usb_port, fparams.usb_addr, devices); + fparams.usb_bus, fparams.usb_port, fparams.usb_addr, (unsigned)devices); libusb_exit(uctx); return -ENODEV; } From 5b3ac8a4d27582f3cad5c7516d49490de36084e4 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 28 Feb 2026 02:14:06 +0400 Subject: [PATCH 329/397] port: define _GNU_SOURCE to use extended c library functions --- src/lib/port/usdr_port.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index 51a80c22..2bce377b 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -9,6 +9,10 @@ #ifdef _WIN32 #include #include +#else +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif #endif #include From efe691472f1ecaf149ddc1fe4a9d640a7de8441d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 28 Feb 2026 02:14:46 +0400 Subject: [PATCH 330/397] mac: increse default buffer size --- src/lib/lowlevel/usb_uram/usb_uram_libusb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c index ea8dbc19..2ad16197 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c @@ -65,7 +65,11 @@ enum { // Streams IN_STRM_SIZE = 512, +#ifdef __APPLE__ + MAX_IN_STRM_REQS = 64, +#else MAX_IN_STRM_REQS = 8, +#endif MAX_OUT_STRM_REQS = 32, RX_PKT_TRAILER_EX = 16, From 2aa36515627b7a1b3303b65eceafd21b309f6932 Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Sat, 28 Feb 2026 02:47:31 +0400 Subject: [PATCH 331/397] mac: replace sincosf implementation with inline version for compatibility --- src/lib/port/usdr_port.c | 24 ------------------------ src/lib/port/usdr_port.h | 8 +++++++- src/lib/xdsp/fmquad.c | 1 + 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/src/lib/port/usdr_port.c b/src/lib/port/usdr_port.c index f063a7b3..c4ffed1f 100644 --- a/src/lib/port/usdr_port.c +++ b/src/lib/port/usdr_port.c @@ -249,29 +249,5 @@ int usdr_set_thread_name(const char* name) { #endif } -/** - * sincosf implementation for macOS - * Computes sine and cosine of x simultaneously - * On Linux this is a GNU extension, but macOS doesn't provide it - */ -#ifdef __APPLE__ -#include - -extern void __sincosf(float x, float *s, float *c); - -void sincosf(float x, float *sin_val, float *cos_val) { - - // __sincosf exists starting macOS 10.9 - if (__builtin_available(macOS 10.9, *)) { - __sincosf(x, s, c); - return; - } - - // macOS provides __sincosf_stret on some versions, but it's not reliable - // Use the straightforward implementation - *sin_val = sinf(x); - *cos_val = cosf(x); -} -#endif diff --git a/src/lib/port/usdr_port.h b/src/lib/port/usdr_port.h index 2bce377b..3cc29d06 100644 --- a/src/lib/port/usdr_port.h +++ b/src/lib/port/usdr_port.h @@ -167,7 +167,13 @@ int usdr_set_thread_name(const char* name); */ #ifdef __APPLE__ #include -void sincosf(float x, float *sin_val, float *cos_val); + +// Use straightforward implementation on macOS +// Note: __sincosf is a private Apple symbol and may cause linker issues +static inline void sincosf(float x, float *sin_val, float *cos_val) { + *sin_val = sinf(x); + *cos_val = cosf(x); +} #endif #define CACHE_SIZE 64 diff --git a/src/lib/xdsp/fmquad.c b/src/lib/xdsp/fmquad.c index b9e65d4f..5ab8f69c 100644 --- a/src/lib/xdsp/fmquad.c +++ b/src/lib/xdsp/fmquad.c @@ -4,6 +4,7 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include "usdr_port.h" #include #include #include "fmquad.h" From acd19d0042af110cedd9fedaec9453348f3193b2 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Sun, 1 Mar 2026 14:21:10 +0400 Subject: [PATCH 332/397] logging: downgrade unknown device message from ERROR to DEBUG --- src/lib/lowlevel/libusb_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index 269f359f..79ea4ac8 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -55,7 +55,7 @@ unsigned find_usb_match(libusb_device **usbdev, size_t devices, j = libusb_find_dev_index_ex(busname, desc.idProduct, desc.idVendor, known_devices, known_device_count ); if (j < 0) { - USDR_LOG("USBX", USDR_LOG_ERROR, "Skipping device %s: %04x:%04x, not in known devices list\n", busname, desc.idVendor, desc.idProduct); + USDR_LOG("USBX", USDR_LOG_DEBUG, "Skipping device %s: %04x:%04x, not in known devices list\n", busname, desc.idVendor, desc.idProduct); continue; } md->uuid_idx = j; From 36f84af0a72a70cb57535e5e16583308ae6b4ad1 Mon Sep 17 00:00:00 2001 From: Chase Valentine Date: Sun, 1 Mar 2026 06:32:17 -0600 Subject: [PATCH 333/397] logging: fix additional misleveled messages and typo in libusb_generic Downgrade "checking device" and "RX buffer configured" messages from ERROR to DEBUG/INFO respectively, as these are normal operational messages not error conditions. Also fix "termitaed" typo. Co-Authored-By: Chase Valentine --- src/lib/lowlevel/libusb_generic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/lowlevel/libusb_generic.c b/src/lib/lowlevel/libusb_generic.c index 79ea4ac8..a992fbaa 100644 --- a/src/lib/lowlevel/libusb_generic.c +++ b/src/lib/lowlevel/libusb_generic.c @@ -70,7 +70,7 @@ unsigned find_usb_match(libusb_device **usbdev, size_t devices, md->devid = (unsigned)bus * 1000000 + (unsigned)port * 1000 + addr; snprintf(md->devid_s, sizeof(md->devid_s), "%d/%d/%d", bus, port, addr); - USDR_LOG("USBX", USDR_LOG_ERROR, "checking device %04x:%04x %d/%d/%d against %d/%d/%d mask devid=%d\n", + USDR_LOG("USBX", USDR_LOG_DEBUG, "checking device %04x:%04x %d/%d/%d against %d/%d/%d mask devid=%d\n", desc.idVendor, desc.idProduct, fparams->usb_bus, fparams->usb_port, fparams->usb_addr, bus, port, addr, j); @@ -339,7 +339,7 @@ void* libusb_generic_io_thread(void *arg) // TODO: check res } - USDR_LOG("USBX", USDR_LOG_INFO, "IO thread termitaed with result %d", res); + USDR_LOG("USBX", USDR_LOG_INFO, "IO thread terminated with result %d", res); return (void*)((intptr_t)res); } @@ -469,7 +469,7 @@ int buffers_realloc(struct buffers* rb, unsigned allocsz) rb->bd[i].buffer_sz = 0; } - USDR_LOG("USBX", USDR_LOG_ERROR, "RX buffer configured to %d x %d bytes for %d original\n", + USDR_LOG("USBX", USDR_LOG_INFO, "RX buffer configured to %d x %d bytes for %d original\n", rb->allocsz_rounded, rb->buf_max, allocsz); rb->bufno_prod = 0; From fa2e5db35a777d022a21545833e54abc08df16ed Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 2 Mar 2026 15:13:47 +0400 Subject: [PATCH 334/397] ssdr: improve lml calibration --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 122 +++++++++++++++++----------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 1 + 2 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index cddd1249..9b1f7e22 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -323,6 +323,7 @@ static int _xsdr_mmcm_pd(xsdr_dev_t *d) return xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 2); } +// sep_clkdiv -- experimental mode with dual MMCM path to CLK/CLKDIV static int g_clk_reduce = 0; int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned txphase, unsigned txphase_off) { @@ -335,11 +336,17 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned io_mclk = (rx_master) ? rx_mclk : tx_mclk; unsigned io_clk = (nomul) ? io_mclk : io_mclk * 2; unsigned vco_div_io = (MMCM_VCO_MAX + io_clk - 1) / io_clk; + bool sep_clkdiv = d->sep_clkdiv; vco_div_io += g_clk_reduce; - if (vco_div_io > 63) - vco_div_io = 63; + if (nomul && !sep_clkdiv) { + if (vco_div_io > 127) + vco_div_io = 127; + } else { + if (vco_div_io > 63) + vco_div_io = 63; + } int res = 0; struct mmcm_config_raw cfg_raw; @@ -357,32 +364,33 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 0); res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); - // 0 - IO_TX_DIV ( was IO_TX_IQSEL -- individual phase delay ) + // 0 - n/a or IO_TX_DIV ( was IO_TX_IQSEL -- individual phase delay ) // 1 - IO_TX // 2 - IO_RX - // 3 - n/a ( was LOGIC_TX ) + // 3 - n/a ( was LOGIC_TX ) // 4 - n/a // 5 - FCLK_RX // 6 - FCLK_TX -#define SEP_CLKDIV -#ifndef SEP_CLKDIV - cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; // IO_TX_IQSEL - cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; // IO_TX_IQSEL -#else - cfg_raw.ports[CLKOUT_PORT_0].period_l = vco_div_io; // IO_TX CLKDIV - cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io; // IO_TX CLKDIV -#endif + if (!sep_clkdiv) { + cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; // IO_TX_IQSEL or unused + cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; // IO_TX_IQSEL or unused + } else { + cfg_raw.ports[CLKOUT_PORT_0].period_l = vco_div_io; // IO_TX CLKDIV + cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io; // IO_TX CLKDIV + } cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; // IO_TX cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; // IO_TX cfg_raw.ports[CLKOUT_PORT_2].period_l = (vco_div_io + 1) / 2; // IO_RX cfg_raw.ports[CLKOUT_PORT_2].period_h = vco_div_io / 2; // IO_RX - cfg_raw.ports[CLKOUT_PORT_3].period_l = vco_div_io; // not used - cfg_raw.ports[CLKOUT_PORT_3].period_h = vco_div_io; // not used - cfg_raw.ports[CLKOUT_PORT_4].period_l = vco_div_io; // not used - cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io; // not used + cfg_raw.ports[CLKOUT_PORT_3].period_l = (vco_div_io + 1) / 2; // not used + cfg_raw.ports[CLKOUT_PORT_3].period_h = vco_div_io / 2; // not used + + cfg_raw.ports[CLKOUT_PORT_4].period_l = (vco_div_io + 1) / 2; // not used + cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io / 2; // not used + cfg_raw.ports[CLKOUT_PORT_5].period_l = (vco_div_io + 1) / 2; cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io / 2; cfg_raw.ports[CLKOUT_PORT_6].period_l = (vco_div_io + 1) / 2; @@ -395,21 +403,23 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, cfg_raw.ports[CLKOUT_PORT_6].phase = phase % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = phase / 8; -#ifndef SEP_CLKDIV - cfg_raw.ports[CLKOUT_PORT_0].phase = phase_iq % 8; - cfg_raw.ports[CLKOUT_PORT_0].delay = phase_iq / 8; + if (!sep_clkdiv) { +#if 0 + cfg_raw.ports[CLKOUT_PORT_0].phase = phase_iq % 8; + cfg_raw.ports[CLKOUT_PORT_0].delay = phase_iq / 8; - if (d->tx_override_phase_iq || txphase || txphase_off) { - //unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase_iq - 1; + if (d->tx_override_phase_iq || txphase || txphase_off) { + //unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase_iq - 1; - unsigned raw = (txphase != 0) ? txphase_off : d->tx_override_phase_iq - 1; - cfg_raw.ports[CLKOUT_PORT_0].phase = raw % 8; - cfg_raw.ports[CLKOUT_PORT_0].delay = raw / 8; - } -#else - cfg_raw.ports[CLKOUT_PORT_0].phase = 0; - cfg_raw.ports[CLKOUT_PORT_0].delay = 0; + unsigned raw = (txphase != 0) ? txphase_off : d->tx_override_phase_iq - 1; + cfg_raw.ports[CLKOUT_PORT_0].phase = raw % 8; + cfg_raw.ports[CLKOUT_PORT_0].delay = raw / 8; + } #endif + } else { + cfg_raw.ports[CLKOUT_PORT_0].phase = 0; + cfg_raw.ports[CLKOUT_PORT_0].delay = 0; + } // if (d->tx_override_phase || txphase) { // unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase - 1; // cfg_raw.ports[CLKOUT_PORT_1].phase = raw % 8; @@ -590,7 +600,8 @@ int xsdr_hwchans_cnt(xsdr_dev_t *d, bool rx, unsigned chans) } enum { - PHY_CFG_VALID_MSK = 0x80, + //PHY_CFG_VALID_MSK = 0x80, + PHY_CFG_SEP_CLKDIV_MSK = 0x80, PHY_CFG_LML2_IS_RX = 0x40, PHY_CFG_TX_MMCM = 0x20, PHY_CFG_RX_MMCM = 0x10, @@ -679,18 +690,21 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (d->mmcm_tx) { if (!d->ssdr_pro) { - // Boost IO voltage for stable high speed link - if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && (d->s_rxrate > 85e6 || d->s_txrate > 85e6)) { - res = res ? res : xsdr_set_vio(d, 1910); - } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && (d->s_rxrate > 70e6 || d->s_txrate > 70e6)) { - res = res ? res : xsdr_set_vio(d, 1940); - res = res ? res : xsdr_set_lms125vdd(d, 1320); - } + // Boost IO voltage for stable high speed link + if (!d->siso_sdr_active_rx && d->new_rev && d->ssdr && (d->s_rxrate > 85e6 || d->s_txrate > 85e6)) { + res = res ? res : xsdr_set_vio(d, 1910); + } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && (d->s_rxrate > 70e6 || d->s_txrate > 70e6)) { + res = res ? res : xsdr_set_vio(d, 1940); + res = res ? res : xsdr_set_lms125vdd(d, 1320); + } - // Fixup for 53-58 MSPS range, but still 58 to 60 might be unoperable on some chips, and 60+ works fine again - if (!mmcm_rx_only_path && d->new_rev && !d->ssdr && (d->s_txrate >= 53e6 && d->s_txrate <= 60e6)) { - res = res ? res : xsdr_set_lms125vdd(d, 1360); - } + // Fixup for 53-58 MSPS range, but still 58 to 60 might be unoperable on some chips, and 60+ works fine again + if (!mmcm_rx_only_path && d->new_rev && !d->ssdr && (d->s_txrate >= 53e6 && d->s_txrate <= 60e6)) { + res = res ? res : xsdr_set_lms125vdd(d, 1360); + } + } else { + bool boost_vio = (!d->siso_sdr_active_rx) && (d->s_rxrate > 85e6 || d->s_txrate > 85e6); + res = res ? res : xsdr_set_vio(d, boost_vio ? 1825 : 1800); } if (!(d->base.rx_run[0] || d->base.rx_run[1])) { @@ -884,8 +898,22 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : usleep(10); } else if (g > 0) { - USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d\n", ph - 1, iqserrs); - break; + // sometimes IQ err reports 0 while it's out of sync, check if LFSR still intact + + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + res = res ? res : usleep(100); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d ABIQ=%d [%6d/%6d/%6d/%6d] \n", ph - 1, iqserrs, + errs[0], errs[1], errs[2], errs[3]); + + if (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness)) { + iqserrs = 500; + } else { + break; + } } } @@ -975,10 +1003,10 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, // unsigned sisosdrflag; int res; - if (!(((d->hwid) & 0xff) & PHY_CFG_VALID_MSK)) { - USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "Incompatible firmware, please update to 20250501 at least!\n"); - return -ENOTSUP; - } + //if (!(((d->hwid) & 0xff) & PHY_CFG_VALID_MSK)) { + // USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "Incompatible firmware, please update to 20250501 at least!\n"); + // return -ENOTSUP; + //} res = _xsdr_checkpwr(d); if (res) @@ -1974,6 +2002,7 @@ int xsdr_init(xsdr_dev_t *d) const bool rx_port_is_1 = ((phycfg_id & PHY_CFG_LML2_IS_RX) != PHY_CFG_LML2_IS_RX); const bool tx_mmcm = ((phycfg_id & PHY_CFG_TX_MMCM) == PHY_CFG_TX_MMCM); const bool rx_mmcm = ((phycfg_id & PHY_CFG_RX_MMCM) == PHY_CFG_RX_MMCM); + const bool sep_clkdiv = ((phycfg_id & PHY_CFG_SEP_CLKDIV_MSK) == PHY_CFG_SEP_CLKDIV_MSK); d->hwid = hwid; d->hwchans_rx = 2; // Defaults to MIMO; @@ -1983,6 +2012,7 @@ int xsdr_init(xsdr_dev_t *d) d->rx_port_is_1 = rx_port_is_1; d->mmcm_rx = rx_mmcm; d->mmcm_tx = tx_mmcm; + d->sep_clkdiv = sep_clkdiv; d->cfg_srate_siso_rx = 0; d->cfg_srate_siso_tx = 0; d->dpump = false; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 20414443..df8e4d1d 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -73,6 +73,7 @@ struct xsdr_dev bool rx_port_is_1; bool mmcm_tx; bool mmcm_rx; + bool sep_clkdiv; bool pwr_en; bool new_rev; bool ssdr; From a7ef47fd87264aa1fc23bb6bf844c5553a82465e Mon Sep 17 00:00:00 2001 From: Ivan <33198864+vd2org@users.noreply.github.com> Date: Mon, 2 Mar 2026 18:52:07 +0400 Subject: [PATCH 335/397] Restored defaults. --- docker/Taskfile.yaml | 2 ++ src/CMakeLists.txt | 6 +++--- src/lib/CMakeLists.txt | 5 ++--- src/lib/xdsp/CMakeLists.txt | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docker/Taskfile.yaml b/docker/Taskfile.yaml index 101cb792..aaa5b2be 100644 --- a/docker/Taskfile.yaml +++ b/docker/Taskfile.yaml @@ -42,6 +42,8 @@ tasks: - prepare dir: /work/build/source cmds: + - echo "#!/usr/bin/env sh" > /usr/bin/lintian # dirty hack to disable lintian + - echo "exit 0" >> /usr/bin/lintian - debuild -us -uc -eDH_VERBOSE=1 - cp -ra /work/build/*.deb /work/output/{{.OUTPUT_DIR_NAME}}/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a2994a3c..6900e30f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,10 +30,10 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") find_package(LIBUSB_1 REQUIRED) option(BUILD_SHARED_LIBS "Build shared libraries(otherwise static libraries will be produced)" ON) -option(ENABLE_DMONITOR "Enable debug tools" OFF) +option(ENABLE_DMONITOR "Enable debug tools" ON) option(ENABLE_VERILATOR "Enable verilator lowlevel bridge" OFF) -option(ENABLE_SOAPY "Enable SopaySDR support" OFF) -option(ENABLE_GUI "Enable USDR QT5 simple GUI" OFF) +option(ENABLE_SOAPY "Enable SopaySDR support" ON) +option(ENABLE_GUI "Enable USDR QT5 simple GUI" ON) option(ENABLE_TESTS "Enable tests" OFF) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index f0383216..00b0bc5f 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.8) project(usdr_lib C) -# Auto generating register descriptors +# Auto generating registor descriptors list(APPEND USDR_LIBRARY_FILES "") list(APPEND USDR_INCLUDE_FILES "") list(APPEND USDR_LINK_FILES pthread) @@ -27,8 +27,7 @@ message("INC - ${USDR_INCLUDE_FILES}") message("LNK - ${USDR_LINK_FILES}") message("DEP - ${USDR_DEPEND_TARGETS}") - -add_library(usdr ${USDR_LIBRARY_FILES}) +add_library(usdr SHARED ${USDR_LIBRARY_FILES}) if (APPLE) set(USDR_PLATFORM_LIBS dl) diff --git a/src/lib/xdsp/CMakeLists.txt b/src/lib/xdsp/CMakeLists.txt index d36f9e5e..de8f84e2 100644 --- a/src/lib/xdsp/CMakeLists.txt +++ b/src/lib/xdsp/CMakeLists.txt @@ -86,7 +86,7 @@ else() #add_definitions("-mfpu=neon") endif() - add_library(usdr-dsp ${xdsplib_SRCS}) + add_library(usdr-dsp SHARED ${xdsplib_SRCS}) target_link_libraries(usdr-dsp m pthread) target_compile_options(usdr-dsp PRIVATE "-Wall" "-Werror=implicit-function-declaration") install(TARGETS usdr-dsp EXPORT usdrTargets LIBRARY From a18e6085b2da764c70b08b18bf5d2d2c80556886 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 2 Mar 2026 19:50:07 +0400 Subject: [PATCH 336/397] xsdr: fix incorrect vio set function --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 9b1f7e22..76d1c645 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -704,7 +704,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } } else { bool boost_vio = (!d->siso_sdr_active_rx) && (d->s_rxrate > 85e6 || d->s_txrate > 85e6); - res = res ? res : xsdr_set_vio(d, boost_vio ? 1825 : 1800); + res = res ? res : xsdr_set_vio(d, boost_vio ? 1850 : 1800); } if (!(d->base.rx_run[0] || d->base.rx_run[1])) { @@ -784,8 +784,6 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) badness_m = badness; phase_m = ph; } - - //goto skip_cal; } if (phase_max > phase_min) { @@ -824,7 +822,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) break; } -skip_cal: + d->lmlcal_rx_phase = phase_m; if (mmcm_rx_only_path) @@ -1939,7 +1937,7 @@ int xsdr_set_vio(xsdr_dev_t *d, unsigned vio_mv) USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_WARNING, "VIO set to %d mV\n", vio_mv); return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, - d->ssdr_pro ? 3 : 1, vio_mv); + d->ssdr_pro ? 2 : 1, vio_mv); } int xsdr_pwren(xsdr_dev_t *d, bool on) From c7ad1bb52300361eedcadf5d4453705ca69a743f Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Mon, 2 Mar 2026 20:41:19 +0400 Subject: [PATCH 337/397] fix: clean up typos in logs, comments and YAML descriptions - Fix spelling/wording in error messages and comments across hwparser, drivers and tools - Normalize "overridden" wording in channel override helpers and logs - Fix various documentation typos in YAML register descriptions --- src/hwparser/gen_h.py | 2 +- src/lib/common/clock_gen.c | 2 +- src/lib/common/clock_gen.h | 2 +- src/lib/device/device_vfs.c | 2 +- .../ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c | 4 ++-- src/lib/device/ext_pciefe/ext_pciefe.c | 6 +++--- src/lib/device/ext_pciefe/pciefe.yaml | 6 +++--- src/lib/device/ext_pciefe/pciefe_cmd.yaml | 2 +- src/lib/device/m2_dsdr/dsdr_hiper.c | 2 +- src/lib/device/m2_dsdr/m2_dsdr.c | 14 +++++++------- src/lib/device/m2_dsdr/m2_dsdr_e.yaml | 2 +- src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml | 2 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 12 ++++++------ src/lib/device/mdev.c | 2 +- src/lib/hw/lmk04832/lmk04832.c | 2 +- src/lib/hw/lmk04832/lmk04832.yaml | 4 ++-- src/lib/hw/lms8001/lms8001.c | 12 ++++++------ src/lib/hw/lmx1204/lmx1204.c | 2 +- src/lib/hw/si5332/si5332.c | 2 +- src/lib/hw/si5332/si5332.yaml | 4 ++-- src/lib/lowlevel/verilator_ll/verilatorll_wrap.c | 4 ++-- src/lib/webusb/test_webusb_libusb.c | 2 +- src/tools/usdr_dm_create.c | 2 +- src/tools/usdr_flash.c | 10 +++++----- 24 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/hwparser/gen_h.py b/src/hwparser/gen_h.py index b1b7a111..d2f88213 100755 --- a/src/hwparser/gen_h.py +++ b/src/hwparser/gen_h.py @@ -36,7 +36,7 @@ def __init__(self, parser: reg_parser.ParserTop, filename: str) -> None: name = "%s_%s" % (pname, r.name) if self.page_prefix else r.name if name in self.regs.keys(): - raise (Exception("Rigester `%s` is already in flat map! Rename it" % name)) + raise (Exception("Register `%s` is already in flat map! Rename it" % name)) # TODO: parse ucnt if r.ucnt == 1: diff --git a/src/lib/common/clock_gen.c b/src/lib/common/clock_gen.c index 28ef0def..03a85d64 100644 --- a/src/lib/common/clock_gen.c +++ b/src/lib/common/clock_gen.c @@ -108,7 +108,7 @@ int find_best_vco(const vco_range_t* pvcos, unsigned vco_count, } // find which VCO fits the capable dividers - // we need to be first deviders to be max (prescalers) + // we need to be first deviders to be max (prescallers) for (i = 0; i < vco_count; i++) { const struct div_range* div_next = (div_cascade_count > 1) ? &div[1] : &nodiv; unsigned nxt_cmb_div = pvcos[i].vcomin / lcm_freq / div[0].maxdiv; diff --git a/src/lib/common/clock_gen.h b/src/lib/common/clock_gen.h index aa6f7293..3b4c1866 100644 --- a/src/lib/common/clock_gen.h +++ b/src/lib/common/clock_gen.h @@ -22,7 +22,7 @@ struct div_range { unsigned mindiv; unsigned maxdiv; unsigned step; - unsigned count; // number of div devices in the group, e.g. number of VCO prescalers you can choise from the next stage + unsigned count; // number of div devices in the group, e.g. number of VCO prescallers you can choise from the next stage const unsigned *pinvlid; // pointer to sorted array of invalid dividers if any }; typedef struct div_range div_range_t; diff --git a/src/lib/device/device_vfs.c b/src/lib/device/device_vfs.c index e4961786..a1d4c294 100644 --- a/src/lib/device/device_vfs.c +++ b/src/lib/device/device_vfs.c @@ -281,7 +281,7 @@ int vfs_add_obj_link(vfs_object_t* root, const char* fullpath, void* obj, const if (res) return res; - // Mark that'a a link + // Mark that's a link no->flags = VFS_FLAG_LINK; no->object = obj; no->data = orig_data; diff --git a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c index 49603108..a1829be8 100644 --- a/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c +++ b/src/lib/device/ext_fe_ch4_400_7200/ext_fe_ch4_400_7200.c @@ -355,7 +355,7 @@ int ext_fe_update_user(ext_fe_ch4_400_7200_t* fe) // RX filterbank _ext_fe_fbank_map(fe->ucfg[i].rx_fb_sel, &fbanksel_out[i], &fbanksel_in[i]); // SW_RX_FILTER_OUT_CHA_MUTE1 if not enabled? - // Antanna switch, RF PA/LNA switch, loopback switch + // Antenna switch, RF PA/LNA switch, loopback switch _ext_fe_antenna_sw_map_exp(fe->ucfg[i].ant_sel, rxen, txen, &exp_tddfdd[i], &exp_rxtx[i], &exp_tx_onoff[i], &trx_led[i], &rx_led[i], &act_rx[i], &act_tx[i]); @@ -368,7 +368,7 @@ int ext_fe_update_user(ext_fe_ch4_400_7200_t* fe) fbanksel_in[H_CHD], fbanksel_in[H_CHC], fbanksel_in[H_CHB], fbanksel_in[H_CHA], fbanksel_out[H_CHA], fbanksel_out[H_CHB], fbanksel_out[H_CHC], fbanksel_out[H_CHD]); - // Gobal enable + // Global enable fe->fe_exp_regs[1] = MAKE_EXT_FE_CH4_400_7200_E_ENABLE( fe->ucfg[H_CHD].tx_ss, fe->ucfg[H_CHC].tx_ss, fe->ucfg[H_CHB].tx_ss, fe->ucfg[H_CHA].tx_ss, fe->if_vbyp, fe->ref_gps, enanble_tx, enanble_rx); diff --git a/src/lib/device/ext_pciefe/ext_pciefe.c b/src/lib/device/ext_pciefe/ext_pciefe.c index 04a1e2ac..09bbf6c7 100644 --- a/src/lib/device/ext_pciefe/ext_pciefe.c +++ b/src/lib/device/ext_pciefe/ext_pciefe.c @@ -16,8 +16,8 @@ #include "def_pciefe_cmd.h" enum { - GPIO_SDA = GPIO0, // Alternatide mode - GPIO_SCL = GPIO1, // Alternatide mode + GPIO_SDA = GPIO0, // Alternative mode + GPIO_SCL = GPIO1, // Alternative mode GPIO_FATTN_0 = GPIO0, // Fast Attenuator interface GPIO_FATTN_1 = GPIO1, // Fast Attenuator interface @@ -43,7 +43,7 @@ enum { // GPIO14, GPIO15 -- DIRCD }; -// GPIO Translatos +// GPIO Translators // DIRxx 0: PLD -> USDR (usdr in) // DIRxx 1: USDR -> PLD (usdr out) diff --git a/src/lib/device/ext_pciefe/pciefe.yaml b/src/lib/device/ext_pciefe/pciefe.yaml index b6b8194c..08d07bfb 100644 --- a/src/lib/device/ext_pciefe/pciefe.yaml +++ b/src/lib/device/ext_pciefe/pciefe.yaml @@ -83,7 +83,7 @@ pages: desc: Activate TX - RX loopback, while TX is still active; Inverted - bits: "2:0" name: DUPL_PATH - desc: Dumplexer path + desc: Duplexer path opts: 0b001: RF1_BAND5 0b010: RF2_BAND8 @@ -209,7 +209,7 @@ pages: desc: Activate TX - RX loopback, while TX is still active; Inverted - bits: "2:0" name: ADUPL_PATH - desc: Dumplexer path + desc: Duplexer path opts: 0b000: ARF1_BAND2 0b100: ARF2_BAND7 @@ -244,7 +244,7 @@ pages: desc: Enable RX LNA 1 - bits: "9:7" name: DUPL_PATH - desc: Dumplexer path + desc: Duplexer path opts: 0b001: RF1_BAND5 0b010: RF2_BAND8 diff --git a/src/lib/device/ext_pciefe/pciefe_cmd.yaml b/src/lib/device/ext_pciefe/pciefe_cmd.yaml index 6a5d336b..13257a6e 100644 --- a/src/lib/device/ext_pciefe/pciefe_cmd.yaml +++ b/src/lib/device/ext_pciefe/pciefe_cmd.yaml @@ -51,7 +51,7 @@ pages: fields: - bits: "2:0" name: DUPLSEL - desc: Dumplexer path + desc: Duplexer path opts: 0: TRX_BYPASS 1: TRX_BAND2 diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 734a49b3..4499ee96 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -1493,7 +1493,7 @@ int dsdr_hiper_update_fe_user(dsdr_hiper_fe_t* fe) // RX filterbank _hiper_fbank_map(fe->ucfg[i].rx_fb_sel, &fbanksel_out[i], &fbanksel_in[i]); // SW_RX_FILTER_OUT_CHA_MUTE1 if not enabled? - // Antanna switch, RF PA/LNA switch, loopback switch + // Antenna switch, RF PA/LNA switch, loopback switch _hiper_antenna_sw_map(rev2, fe->ucfg[i].ant_sel, rxen, txen, &fe->fe_gpo_regs[CHA - REFCTRL + i], &lbrxtx[i], &act_rx[i], &act_tx[i], &exp_led_trx[i], &exp_led_rx[i]); // Update RX DSA diff --git a/src/lib/device/m2_dsdr/m2_dsdr.c b/src/lib/device/m2_dsdr/m2_dsdr.c index cc3ba7f9..d7a3a519 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr.c +++ b/src/lib/device/m2_dsdr/m2_dsdr.c @@ -2354,7 +2354,7 @@ int usdr_device_m2_dsdr_initialize(pdevice_t udev, unsigned pcount, const char** res = res ? res : usleep(10000); //res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x3); // Enable VIOSYS, hold RESET res = res ? res : lp875484_init(dev, d->subdev, I2C_AFE_PMIC); - res = res ? res : lp875484_set_vout(dev, d->subdev, I2C_AFE_PMIC, 930); // Recomended 925mV + res = res ? res : lp875484_set_vout(dev, d->subdev, I2C_AFE_PMIC, 930); // Recommended 925mV res = res ? res : dev_gpo_set(dev, IGPO_PWR_AFE, 0x3); // Enable VIOSYS, release RESET if (res) return res; @@ -2607,7 +2607,7 @@ int device_path_to_chmsk(const char* full_path, const char* basename, const chan return 0; } -static int parse_overriden_cahnnel_info(const char* env_string, const usdr_channel_info_t* orig, const channel_map_info_t* map, const unsigned max_lchan, channel_info_t* override) +static int parse_overridden_channel_info(const char* env_string, const usdr_channel_info_t* orig, const channel_map_info_t* map, const unsigned max_lchan, channel_info_t* override) { char chanlist[64*4]; char* phys_names[DSDR_CHANS_LOGIC]; @@ -2623,7 +2623,7 @@ static int parse_overriden_cahnnel_info(const char* env_string, const usdr_chann return res; if (nfo.count != orig->count) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "Overriden channel count %d != requested %d count!\n", nfo.count, orig->count); + USDR_LOG("UDEV", USDR_LOG_ERROR, "Overridden channel count %d != requested %d count!\n", nfo.count, orig->count); return -EINVAL; } @@ -2673,10 +2673,10 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char const char* env_ch = getenv("DSDR_CH_RX"); if (env_ch) { - res = parse_overriden_cahnnel_info(env_ch, channels, d->rx_chmap_info, d->logic_chcnt_rx, &lchans); + res = parse_overridden_channel_info(env_ch, channels, d->rx_chmap_info, d->logic_chcnt_rx, &lchans); if (res) return res; - USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR RX channel mask is overriden to `%s`\n", env_ch); + USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR RX channel mask is overridden to `%s`\n", env_ch); } memcpy(d->rx_ordinal_to_logic, lchans.ch_map, sizeof(lchans.ch_map[0]) * channels->count); @@ -2760,10 +2760,10 @@ int usdr_device_m2_dsdr_create_stream(device_t* dev, const char* sid, const char const char* env_ch = getenv("DSDR_CH_TX"); if (env_ch) { - res = parse_overriden_cahnnel_info(env_ch, channels, d->tx_chmap_info, d->logic_chcnt_tx, &lchans); + res = parse_overridden_channel_info(env_ch, channels, d->tx_chmap_info, d->logic_chcnt_tx, &lchans); if (res) return res; - USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR TX channel mask is overriden to `%s`\n", env_ch); + USDR_LOG("UDEV", USDR_LOG_INFO, "DSDR TX channel mask is overridden to `%s`\n", env_ch); } memcpy(d->tx_ordinal_to_logic, lchans.ch_map, sizeof(lchans.ch_map[0]) * channels->count); diff --git a/src/lib/device/m2_dsdr/m2_dsdr_e.yaml b/src/lib/device/m2_dsdr/m2_dsdr_e.yaml index 6b09c1bd..5db3ae20 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_e.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_e.yaml @@ -206,7 +206,7 @@ pages: desc: Rev2 Enable +5v power for (IF Amplifier) - bits: "6" name: REV2_P5V_EXTLO - desc: Rev2 Eanble +5v power for EXT_LO clock distributor + desc: Rev2 Enable +5v power for EXT_LO clock distributor - bits: "5" name: REV2_PG_6P0 desc: PG signal for 6P0 line diff --git a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml index 464006fe..71d01995 100644 --- a/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml +++ b/src/lib/device/m2_dsdr/m2_dsdr_e_v2.yaml @@ -197,7 +197,7 @@ pages: desc: Rev2 Enable +5v power for (IF Amplifier) - bits: "6" name: REV2_P5V_EXTLO - desc: Rev2 Eanble +5v power for EXT_LO clock distributor + desc: Rev2 Enable +5v power for EXT_LO clock distributor - bits: "5" name: REV2_PG_6P0 desc: PG signal for 6P0 line diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 76d1c645..3a76e386 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -485,7 +485,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, usleep(10); } - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM Redy flag timed out!\n"); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM Ready flag timed out!\n"); return -EIO; } @@ -720,7 +720,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (res) return res; - // Autocalibration if RX phase wasn't set + // Autocallibration if RX phase wasn't set if (d->rx_override_phase == 0) { const unsigned check_to = 10; unsigned phase_m; @@ -790,7 +790,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) phase_m = (phase_max + phase_min) / 2; } - USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Restoring RX pahse to %d (bandness=%" PRId64 ") PH_MIN=%d PH_MAX=%d\n", + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Restoring RX phase to %d (bandness=%" PRId64 ") PH_MIN=%d PH_MAX=%d\n", phase_m - 1, badness_m, phase_min, phase_max); // Try our best at least @@ -936,7 +936,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_limelight_toggle_ntx(&d->base.lmsstate); check_rx = true; } - USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Restoring TX pahse to %d (bandness=%" PRId64 ")\n", + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Restoring TX phase to %d (bandness=%" PRId64 ")\n", phase_m, badness_m); // Try our best at least @@ -1894,7 +1894,7 @@ int _xsdr_pwren_revx(xsdr_dev_t *d, bool on) return res; if (d->ssdr) { - // Haevy load on 1.8VA + // Heavy load on 1.8VA usleep(100000); } usleep(1000); @@ -1945,7 +1945,7 @@ int xsdr_pwren(xsdr_dev_t *d, bool on) int res; lldev_t dev = d->base.lmsstate.dev; - res = dev_gpo_set(dev, IGPO_LMS_PWR, 0); //Disble, put into reset + res = dev_gpo_set(dev, IGPO_LMS_PWR, 0); //Disable, put into reset if (res) return res; usleep(5000); diff --git a/src/lib/device/mdev.c b/src/lib/device/mdev.c index 5a098ce4..5d46dc59 100644 --- a/src/lib/device/mdev.c +++ b/src/lib/device/mdev.c @@ -105,7 +105,7 @@ int mdev_generic_destroy(lldev_t dev) // Destroy underlying lldevs for (unsigned i = 0; i < obj->cnt; i++) { if (obj->real[i] == NULL) { - USDR_LOG("MDEV", USDR_LOG_WARNING, "Uderlying device has been destroyed already!\n"); + USDR_LOG("MDEV", USDR_LOG_WARNING, "Underlying device has been destroyed already!\n"); continue; } diff --git a/src/lib/hw/lmk04832/lmk04832.c b/src/lib/hw/lmk04832/lmk04832.c index 408db7a3..73616ab4 100644 --- a/src/lib/hw/lmk04832/lmk04832.c +++ b/src/lib/hw/lmk04832/lmk04832.c @@ -189,7 +189,7 @@ int lmk04832_configure_layout(lldev_t dev, subdev_t subdev, lsopaddr_t addr, pcfg->distribution_frequency); return -ERANGE; } - // PLL2 N Prescaler from 2 to 8 + // PLL2 N Prescaller from 2 to 8 // PLL2 PFD up to 320Mhz // Fin // Fpfd = Fin / R diff --git a/src/lib/hw/lmk04832/lmk04832.yaml b/src/lib/hw/lmk04832/lmk04832.yaml index ef055e9c..87e1ab2c 100644 --- a/src/lib/hw/lmk04832/lmk04832.yaml +++ b/src/lib/hw/lmk04832/lmk04832.yaml @@ -465,7 +465,7 @@ pages: 1: OSC_FREQ_63_127 - name: PLL2_P bits: '7:5' - desc: The PLL2 N Prescaler divides the output of the VCO as selected + desc: The PLL2 N Prescaller divides the output of the VCO as selected by Mode_MUX1 and is connected to the PLL2 N divider - name: PLL2_REF_2X_EN bits: '0' @@ -521,4 +521,4 @@ pages: 16: PLL2_PD_RESERVED - name: PLL2_PRE_PD bits: '6' - desc: Powerdown PLL2 prescaler + desc: Powerdown PLL2 prescaller diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index 05de2387..ff2cdd76 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -127,7 +127,7 @@ static int _lms8001_calc_vco(lms8001_state_t* obj, uint64_t outfreq, lms8001_vco struct lms8001_pll_settings { unsigned nint; unsigned nfrac; - unsigned nfix; // /2 prescaler activated + unsigned nfix; // /2 prescaller activated }; typedef struct lms8001_pll_settings lms8001_pll_settings_t; @@ -168,7 +168,7 @@ int lms8001_tune(lms8001_state_t* state, unsigned fref, uint64_t out) USDR_LOG("8001", USDR_LOG_ERROR, "OUT=%.3f VCO=%.3f PLL NINT=%d FRAC=%d DIV=%d\n", out / 1.0e6, st.fvco / 1.0e6, pll.nint, pll.nfrac, (1 << st.divi)); - // TODO: Prescaler DIV + // TODO: Prescaller DIV uint32_t pll_regs[] = { MAKE_LMS8001_PLL_PROFILE_0_PLL_LPF_CFG1_n(1, 1, 8, 8), MAKE_LMS8001_PLL_PROFILE_0_PLL_LPF_CFG2_n(1, 0, 8), @@ -218,7 +218,7 @@ int lms8001_tune(lms8001_state_t* state, unsigned fref, uint64_t out) int cal_freq = GET_LMS8001_PLL_CONFIGURATION_PLL_CAL_AUTO0_FREQ_FINAL(rb); if (!(fcst == 0 && vco_sel_v == 1 && freq_sel_v == 1)) { - USDR_LOG("8001", USDR_LOG_ERROR, "Can't perform VCO autocalibration! VCO = %.3f Mhz REF = %.3f Mhz\n", st.fvco / 1.0e6, fref / 1.0e6); + USDR_LOG("8001", USDR_LOG_ERROR, "Can't perform VCO autocallibration! VCO = %.3f Mhz REF = %.3f Mhz\n", st.fvco / 1.0e6, fref / 1.0e6); return -ERANGE; } @@ -948,11 +948,11 @@ static int _lms8001_optim_cp_ld(lms8001_state_t* m) // Calculate OFS and LD_VCT optimal values if (INTMOD_EN) { - // Set Offset Current and Lock Detector Threashold for IntN - Operating Mode + // Set Offset Current and Lock Detector Threshold for IntN - Operating Mode LD_VCT = 2; OFS = 0; } else { - // Set Offset Current and Lock Detector Threashold for IntN - Operating Mode + // Set Offset Current and Lock Detector Threshold for IntN - Operating Mode LD_VCT = 0; double Icp = (25.0 * ICT_CP / 16.0) * PULSE; // Calculate Target Value for Offset Current, as 3 % of Pulse current value @@ -1077,7 +1077,7 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, return res; } - // Step 4 - Optimize CP offset current Lock Detector Threashold depending on operating mode chosen(IntN or FracN) + // Step 4 - Optimize CP offset current Lock Detector Threshold depending on operating mode chosen(IntN or FracN) res = _lms8001_optim_cp_ld(m); if (res) { return res; diff --git a/src/lib/hw/lmx1204/lmx1204.c b/src/lib/hw/lmx1204/lmx1204.c index a8ce8ae2..a7049617 100644 --- a/src/lib/hw/lmx1204/lmx1204.c +++ b/src/lib/hw/lmx1204/lmx1204.c @@ -152,7 +152,7 @@ int lmx1204_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lmx1204_state_ st->lsaddr = lsaddr; //SYSREF individual channel delays defaults (according to TICS Pro) - //Could be overriden before solver call (lmx1204_set_sysrefout_ch_delay()) + //Could be overridden before solver call (lmx1204_set_sysrefout_ch_delay()) for(unsigned i = 0; i < SIZEOF_ARRAY(st->sysref_indiv_ch_delay); ++i) { lmx1204_sysrefout_channel_delay_t* d = &st->sysref_indiv_ch_delay[i]; diff --git a/src/lib/hw/si5332/si5332.c b/src/lib/hw/si5332/si5332.c index d03664a7..f0f76cc7 100644 --- a/src/lib/hw/si5332/si5332.c +++ b/src/lib/hw/si5332/si5332.c @@ -600,7 +600,7 @@ int si5332_set_layout(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, IDPA_DEN_H, idpa_den, IDPA_DEN_L, idpa_den >> 8, - PDIV_DIV, prescaler, //Prescaler + PDIV_DIV, prescaler, //Prescaller PLL_MODE, (pllfreq > 30e6) ? 8 : 4, // 4 - 500kHz | 7 - 175khz HSDIV0A_DIV, hsdiv, diff --git a/src/lib/hw/si5332/si5332.yaml b/src/lib/hw/si5332/si5332.yaml index f86531e7..c9a3bec6 100644 --- a/src/lib/hw/si5332/si5332.yaml +++ b/src/lib/hw/si5332/si5332.yaml @@ -18,8 +18,8 @@ field_prefix: field_macros: true x-opt-1: &id001 - 0b00: PLL reference clock before prescaler - 0b01: PLL reference clock after prescaler + 0b00: PLL reference clock before prescaller + 0b01: PLL reference clock after prescaller 0b10: Clock from input buffer CLKIN_2 0b11: Clock from input buffer CLKIN_3 x-opt-2: &id002 diff --git a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c index 136f0448..f4c66fa3 100644 --- a/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c +++ b/src/lib/lowlevel/verilator_ll/verilatorll_wrap.c @@ -84,7 +84,7 @@ int vpu_init(verilator_protocol_unix_t* pvpu, const char* dev) res = vll_chan_connect(&pvpu->vch, dev); if (res) { - USDR_LOG("VERI", USDR_LOG_CRITICAL_WARNING, "Connecton to verilator filed: error %d\n", res); + USDR_LOG("VERI", USDR_LOG_CRITICAL_WARNING, "Connection to verilator failed: error %d\n", res); goto conn_failed; } @@ -92,7 +92,7 @@ int vpu_init(verilator_protocol_unix_t* pvpu, const char* dev) snprintf(mmapfile, sizeof (mmapfile), "%s.mmap", dev); res = vll_mem_open(&pvpu->vchm, mmapfile, MMAP_SIZE); if (res) { - USDR_LOG("VERI", USDR_LOG_CRITICAL_WARNING, "Openning MMAP area failed: error %d\n", res); + USDR_LOG("VERI", USDR_LOG_CRITICAL_WARNING, "Opening MMAP area failed: error %d\n", res); goto conn_failed; } diff --git a/src/lib/webusb/test_webusb_libusb.c b/src/lib/webusb/test_webusb_libusb.c index a3f2eb5b..5aef74fb 100644 --- a/src/lib/webusb/test_webusb_libusb.c +++ b/src/lib/webusb/test_webusb_libusb.c @@ -296,7 +296,7 @@ int main(int argc, char** argv) return 1; } - // Recieve test packet + // Receive test packet res = libusb_bulk_transfer(wsdr->dh, 0x03 | LIBUSB_ENDPOINT_IN, (unsigned char*)dummy_buffer, diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index 31fbe6ca..28ea2633 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -678,7 +678,7 @@ int main(UNUSED int argc, UNUSED char** argv) [DD_TX_GAIN_LB] = { "tx/gain/lb", 0, true, true }, }; - //primary logging for proper usage() call - may be overriden below + //primary logging for proper usage() call - may be overridden below usdrlog_setlevel(NULL, loglevel); //set colored log output usdrlog_enablecolorize(NULL); diff --git a/src/tools/usdr_flash.c b/src/tools/usdr_flash.c index c6cc990d..8ebb28e0 100644 --- a/src/tools/usdr_flash.c +++ b/src/tools/usdr_flash.c @@ -202,23 +202,23 @@ int main(int argc, char** argv) if (rdwr == ACTION_WRITE || rdwr == ACTION_INFO) { FILE* w = fopen(filename, "rb"); if (w == NULL) { - fprintf(stderr, "Unabe to read file '%s': %s\n", filename, strerror(errno)); + fprintf(stderr, "Unable to read file '%s': %s\n", filename, strerror(errno)); return 3; } res = fseek(w, 0, SEEK_END); if (res) { - fprintf(stderr, "Unabe to seek file '%s': %s\n", filename, strerror(errno)); + fprintf(stderr, "Unable to seek file '%s': %s\n", filename, strerror(errno)); return 3; } total_length = ftell(w); res = fseek(w, 0, SEEK_SET); if (res) { - fprintf(stderr, "Unabe to seek file '%s': %s\n", filename, strerror(errno)); + fprintf(stderr, "Unable to seek file '%s': %s\n", filename, strerror(errno)); return 3; } res = fread(outa, 1, total_length, w); if ((unsigned)res != total_length) { - fprintf(stderr, "Unabe to read file '%s': %d read\n", filename, res); + fprintf(stderr, "Unable to read file '%s': %d read\n", filename, res); return 3; } fclose(w); @@ -385,7 +385,7 @@ int main(int argc, char** argv) } else if (rdwr == ACTION_READBACK) { FILE* w = fopen(filename, "wb"); if (w == NULL) { - fprintf(stderr, "Unabe to create file '%s': %s\n", filename, strerror(errno)); + fprintf(stderr, "Unable to create file '%s': %s\n", filename, strerror(errno)); return 3; } fwrite(outb, 1, total_length, w); From c4c1e5c5dbbfc97bd4469952b99506b4f5f724df Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Mon, 2 Mar 2026 20:51:28 +0400 Subject: [PATCH 338/397] fix: prescaller typo --- src/lib/common/clock_gen.c | 2 +- src/lib/common/clock_gen.h | 2 +- src/lib/hw/lmk04832/lmk04832.c | 2 +- src/lib/hw/lmk04832/lmk04832.yaml | 4 ++-- src/lib/hw/lms8001/lms8001.c | 4 ++-- src/lib/hw/si5332/si5332.c | 2 +- src/lib/hw/si5332/si5332.yaml | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lib/common/clock_gen.c b/src/lib/common/clock_gen.c index 03a85d64..28ef0def 100644 --- a/src/lib/common/clock_gen.c +++ b/src/lib/common/clock_gen.c @@ -108,7 +108,7 @@ int find_best_vco(const vco_range_t* pvcos, unsigned vco_count, } // find which VCO fits the capable dividers - // we need to be first deviders to be max (prescallers) + // we need to be first deviders to be max (prescalers) for (i = 0; i < vco_count; i++) { const struct div_range* div_next = (div_cascade_count > 1) ? &div[1] : &nodiv; unsigned nxt_cmb_div = pvcos[i].vcomin / lcm_freq / div[0].maxdiv; diff --git a/src/lib/common/clock_gen.h b/src/lib/common/clock_gen.h index 3b4c1866..aa6f7293 100644 --- a/src/lib/common/clock_gen.h +++ b/src/lib/common/clock_gen.h @@ -22,7 +22,7 @@ struct div_range { unsigned mindiv; unsigned maxdiv; unsigned step; - unsigned count; // number of div devices in the group, e.g. number of VCO prescallers you can choise from the next stage + unsigned count; // number of div devices in the group, e.g. number of VCO prescalers you can choise from the next stage const unsigned *pinvlid; // pointer to sorted array of invalid dividers if any }; typedef struct div_range div_range_t; diff --git a/src/lib/hw/lmk04832/lmk04832.c b/src/lib/hw/lmk04832/lmk04832.c index 73616ab4..408db7a3 100644 --- a/src/lib/hw/lmk04832/lmk04832.c +++ b/src/lib/hw/lmk04832/lmk04832.c @@ -189,7 +189,7 @@ int lmk04832_configure_layout(lldev_t dev, subdev_t subdev, lsopaddr_t addr, pcfg->distribution_frequency); return -ERANGE; } - // PLL2 N Prescaller from 2 to 8 + // PLL2 N Prescaler from 2 to 8 // PLL2 PFD up to 320Mhz // Fin // Fpfd = Fin / R diff --git a/src/lib/hw/lmk04832/lmk04832.yaml b/src/lib/hw/lmk04832/lmk04832.yaml index 87e1ab2c..ef055e9c 100644 --- a/src/lib/hw/lmk04832/lmk04832.yaml +++ b/src/lib/hw/lmk04832/lmk04832.yaml @@ -465,7 +465,7 @@ pages: 1: OSC_FREQ_63_127 - name: PLL2_P bits: '7:5' - desc: The PLL2 N Prescaller divides the output of the VCO as selected + desc: The PLL2 N Prescaler divides the output of the VCO as selected by Mode_MUX1 and is connected to the PLL2 N divider - name: PLL2_REF_2X_EN bits: '0' @@ -521,4 +521,4 @@ pages: 16: PLL2_PD_RESERVED - name: PLL2_PRE_PD bits: '6' - desc: Powerdown PLL2 prescaller + desc: Powerdown PLL2 prescaler diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index ff2cdd76..0cb5a75d 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -127,7 +127,7 @@ static int _lms8001_calc_vco(lms8001_state_t* obj, uint64_t outfreq, lms8001_vco struct lms8001_pll_settings { unsigned nint; unsigned nfrac; - unsigned nfix; // /2 prescaller activated + unsigned nfix; // /2 prescaler activated }; typedef struct lms8001_pll_settings lms8001_pll_settings_t; @@ -168,7 +168,7 @@ int lms8001_tune(lms8001_state_t* state, unsigned fref, uint64_t out) USDR_LOG("8001", USDR_LOG_ERROR, "OUT=%.3f VCO=%.3f PLL NINT=%d FRAC=%d DIV=%d\n", out / 1.0e6, st.fvco / 1.0e6, pll.nint, pll.nfrac, (1 << st.divi)); - // TODO: Prescaller DIV + // TODO: Prescaler DIV uint32_t pll_regs[] = { MAKE_LMS8001_PLL_PROFILE_0_PLL_LPF_CFG1_n(1, 1, 8, 8), MAKE_LMS8001_PLL_PROFILE_0_PLL_LPF_CFG2_n(1, 0, 8), diff --git a/src/lib/hw/si5332/si5332.c b/src/lib/hw/si5332/si5332.c index f0f76cc7..d03664a7 100644 --- a/src/lib/hw/si5332/si5332.c +++ b/src/lib/hw/si5332/si5332.c @@ -600,7 +600,7 @@ int si5332_set_layout(lldev_t dev, subdev_t subdev, lsopaddr_t lsopaddr, IDPA_DEN_H, idpa_den, IDPA_DEN_L, idpa_den >> 8, - PDIV_DIV, prescaler, //Prescaller + PDIV_DIV, prescaler, //Prescaler PLL_MODE, (pllfreq > 30e6) ? 8 : 4, // 4 - 500kHz | 7 - 175khz HSDIV0A_DIV, hsdiv, diff --git a/src/lib/hw/si5332/si5332.yaml b/src/lib/hw/si5332/si5332.yaml index c9a3bec6..f86531e7 100644 --- a/src/lib/hw/si5332/si5332.yaml +++ b/src/lib/hw/si5332/si5332.yaml @@ -18,8 +18,8 @@ field_prefix: field_macros: true x-opt-1: &id001 - 0b00: PLL reference clock before prescaller - 0b01: PLL reference clock after prescaller + 0b00: PLL reference clock before prescaler + 0b01: PLL reference clock after prescaler 0b10: Clock from input buffer CLKIN_2 0b11: Clock from input buffer CLKIN_3 x-opt-2: &id002 From 4b337ea33968891ccc0fc1ed9550fcd396aff9e1 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 00:59:41 +0400 Subject: [PATCH 339/397] ssdr: improve LML --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 54 ++++++++++++++++++----------- src/lib/ipblks/xlnx_mmcm.c | 5 ++- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 3a76e386..5e334484 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -340,12 +340,8 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, vco_div_io += g_clk_reduce; - if (nomul && !sep_clkdiv) { - if (vco_div_io > 127) - vco_div_io = 127; - } else { - if (vco_div_io > 63) - vco_div_io = 63; + if (vco_div_io > 63) { + vco_div_io = 63; } int res = 0; @@ -353,16 +349,27 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, memset(&cfg_raw, 0, sizeof(cfg_raw)); cfg_raw.type = (d->xilinx_usp) ? MT_USP_MMCM : MT_7SERIES_MMCM; - if (vco_div_io * io_clk < MMCM_VCO_MIN && vco_div_io < 63) { - if ((vco_div_io + 2) * io_clk > MMCM_VCO_MAX) { - vco_div_io += 1; - } else { - vco_div_io += 2; + if (vco_div_io * io_clk < MMCM_VCO_MIN) { + if (nomul && !sep_clkdiv) { + vco_div_io = (MMCM_VCO_MAX + io_clk - 1) / io_clk; + if (vco_div_io % 2) + vco_div_io++; + + if (vco_div_io > 126) + vco_div_io = 126; + } + + if (vco_div_io < 63) { + if ((vco_div_io + 2) * io_clk > MMCM_VCO_MAX) { + vco_div_io += 1; + } else { + vco_div_io += 2; + } } } - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 0); - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); + // res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 0); + // res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); // 0 - n/a or IO_TX_DIV ( was IO_TX_IQSEL -- individual phase delay ) // 1 - IO_TX @@ -397,7 +404,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io / 2; // FCLK_TX unsigned total_budget = 8 * vco_div_io; - unsigned phase = (((tx_mclk < 2*35e6) || (tx_mclk > 2*60e6)) ? 4 : 5) * total_budget / 6; + unsigned phase = (((tx_mclk < 2*35e6) || (tx_mclk > 2*60e6)) ? 4 : 5) * total_budget / (vco_div_io > 63 ? 12 : 6); // unsigned phase_iq = 0; //4; cfg_raw.ports[CLKOUT_PORT_6].phase = phase % 8; @@ -458,11 +465,17 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, tx_mclk * (cfg_raw.ports[CLKOUT_PORT_FB].period_l + cfg_raw.ports[CLKOUT_PORT_FB].period_h) / 1.0e6, txphase_off, rx_master ? "RX" : "TX"); + + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 1); + res = res ? res : usleep(10); res = res ? res : mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &cfg_raw); + // Set IQSEL vector + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); + // Reset MMCM - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 1); - usleep(10); + // res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 1); + res = res ? res : usleep(10); res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 0); if (res) return res; @@ -478,13 +491,14 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_DEBUG, "MMCM FLAGS:%08x\n", rb); if (rb & (1 << 8)) { - g_tx_cfg_raw = cfg_raw; + g_tx_cfg_raw = cfg_raw; return 0; } - usleep(10); + usleep(50); } + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM Ready flag timed out!\n"); return -EIO; } @@ -738,7 +752,6 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) int phase_min; int phase_max; - //for (unsigned rty = 0; rty < 3; rty++) { phase_min = 65; phase_max = 0; @@ -774,7 +787,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) phase_max = ph; // Got more than 7 phases, we're safe; skip searching - if (phase_max - phase_min > 7) + unsigned sphase = (rxrty == 0) ? 8 : (rxrty == 1) ? 4 : (rxrty == 2) ? 1 : 0; + if (phase_max - phase_min >= sphase) break; } else if (phase_max >= phase_min) { break; diff --git a/src/lib/ipblks/xlnx_mmcm.c b/src/lib/ipblks/xlnx_mmcm.c index 427e32f8..555de5d6 100644 --- a/src/lib/ipblks/xlnx_mmcm.c +++ b/src/lib/ipblks/xlnx_mmcm.c @@ -227,8 +227,11 @@ int mmcm_init_raw(lldev_t dev, subdev_t subdev, for (unsigned i = 0; i < MAX_MMCM_PORTS; i++) { res = mmcm_init_raw_clkout(dev, subdev, drp_port, CLKOUT5_ClkReg1 + 2 * i, &cfg->ports[i]); - if (res) + if (res) { + USDR_LOG("MMCM", USDR_LOG_ERROR, "Port%d: H/L=%d/%d DLY=%d Error=%d\n", + i, cfg->ports[i].period_h, cfg->ports[i].period_l, cfg->ports[i].delay, res); return res; + } } // Input divide From 4c5a603faffc68c24b9ddfad08b854cfe453a450 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 02:46:20 +0400 Subject: [PATCH 340/397] lms7002: wait LDO to settle during first SXX run --- src/lib/hw/lms7002m/lms7002m.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index 2566a590..4ddcb91c 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -611,9 +611,6 @@ int lms7002m_sxx_tune(lms7002m_state_t* m, lms7002m_sxx_path_t path, unsigned fr const char* sxxn = path == SXX_RX ? "SXR" : "SXT"; int res; - SET_LMS7002M_LML_0X0020_MAC(mac, path == SXX_RX ? LMS7_CH_A : LMS7_CH_B); - SET_LMS7002M_SXX_0X0124_EN_DIR_SXX(m->reg_en_dir[dir_idx], 1); - if (vco > SXX_VCOH_MAX) { USDR_LOG("7002", USDR_LOG_WARNING, "%s: VCO=%u is out of range\n", sxxn, lofreq); return -ERANGE; @@ -628,6 +625,9 @@ int lms7002m_sxx_tune(lms7002m_state_t* m, lms7002m_sxx_path_t path, unsigned fr vco <<= 1; } + SET_LMS7002M_LML_0X0020_MAC(mac, path == SXX_RX ? LMS7_CH_A : LMS7_CH_B); + bool pwr = GET_LMS7002M_SXX_0X0124_EN_DIR_SXX(m->reg_en_dir[dir_idx]); + SET_LMS7002M_SXX_0X0124_EN_DIR_SXX(m->reg_en_dir[dir_idx], 1); uint32_t sxx_regs[] = { MAKE_LMS7002M_REG_WR(LML_0x0020, mac), MAKE_LMS7002M_REG_WR(SXX_0x0124, m->reg_en_dir[dir_idx]), @@ -655,6 +655,11 @@ int lms7002m_sxx_tune(lms7002m_state_t* m, lms7002m_sxx_path_t path, unsigned fr if (res) return res; + if (!pwr) { + // Wait for 1st start to settle LDOs & PLL + usleep(10000); + } + bool vcoit[4] = { (SXX_VCOL_MIN < vco) && (vco < SXX_VCOL_MAX), (SXX_VCOM_MIN < vco) && (vco < SXX_VCOM_MAX), From a38600049852ed8549f8cfe9b59f9ad614a26776 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 02:47:11 +0400 Subject: [PATCH 341/397] mmcm: use proper MIN/MAX for USP --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 14 ++++++++++---- src/lib/ipblks/xlnx_mmcm.h | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 5e334484..3537da18 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -327,19 +327,25 @@ static int _xsdr_mmcm_pd(xsdr_dev_t *d) static int g_clk_reduce = 0; int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned txphase, unsigned txphase_off) { + const unsigned VCO_MIN = d->ssdr_pro ? MMCM_VCO_MIN : MMCM_VCO_MIN_USP; + const unsigned VCO_MAX = d->ssdr_pro ? MMCM_VCO_MAX : MMCM_VCO_MAX_USP; + bool nomul = d->dpump ? false : (rx_master) ? d->base.lml_mode.rxsisoddr || (d->base.rxtsp_div > 1) : d->base.lml_mode.txsisoddr || (d->base.txtsp_div > 1); + unsigned mmcm_ctrl_sel = (rx_master) ? 0 : 4; unsigned tx_mclk = d->base.cgen_clk / d->base.txcgen_div / d->base.lml_mode.txdiv; unsigned rx_mclk = d->base.cgen_clk / d->base.rxcgen_div / d->base.lml_mode.rxdiv; unsigned io_mclk = (rx_master) ? rx_mclk : tx_mclk; unsigned io_clk = (nomul) ? io_mclk : io_mclk * 2; - unsigned vco_div_io = (MMCM_VCO_MAX + io_clk - 1) / io_clk; + unsigned vco_div_io = (VCO_MAX + io_clk - 1) / io_clk; bool sep_clkdiv = d->sep_clkdiv; vco_div_io += g_clk_reduce; + vco_div_io += (txphase_off > 2) ? 2 : txphase_off; + if (vco_div_io > 63) { vco_div_io = 63; } @@ -349,9 +355,9 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, memset(&cfg_raw, 0, sizeof(cfg_raw)); cfg_raw.type = (d->xilinx_usp) ? MT_USP_MMCM : MT_7SERIES_MMCM; - if (vco_div_io * io_clk < MMCM_VCO_MIN) { + if (vco_div_io * io_clk < VCO_MIN) { if (nomul && !sep_clkdiv) { - vco_div_io = (MMCM_VCO_MAX + io_clk - 1) / io_clk; + vco_div_io = (VCO_MAX + io_clk - 1) / io_clk; if (vco_div_io % 2) vco_div_io++; @@ -360,7 +366,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, } if (vco_div_io < 63) { - if ((vco_div_io + 2) * io_clk > MMCM_VCO_MAX) { + if ((vco_div_io + 2) * io_clk > VCO_MAX) { vco_div_io += 1; } else { vco_div_io += 2; diff --git a/src/lib/ipblks/xlnx_mmcm.h b/src/lib/ipblks/xlnx_mmcm.h index 26b1451f..71e8363b 100644 --- a/src/lib/ipblks/xlnx_mmcm.h +++ b/src/lib/ipblks/xlnx_mmcm.h @@ -40,6 +40,9 @@ enum mmcm_vco_ranges { MMCM_VCO_MIN = 600000000, MMCM_VCO_MAX = 1440000000, MMCM_VCO_MAX_SP2 = 1900000000, + + MMCM_VCO_MIN_USP = 800000000, + MMCM_VCO_MAX_USP = 1600000000, }; struct mmcm_config_raw { From c541d80b2aa87f36a4dcde2682917a72bd60d462 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 16:16:05 +0400 Subject: [PATCH 342/397] ssdr: fix restart LML calibration --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 3537da18..67593da5 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -836,6 +836,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) errs[0], errs[1], errs[2], errs[3], (long long)badness); g_clk_reduce++; + phase_min = 65; + phase_max = 0; continue; } } From 3346a307ff8dde56f1882215c77bcd643a4db3f3 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 19:09:23 +0400 Subject: [PATCH 343/397] xsdr: fix RX_LML initial calibration for low --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 139 +++++++++++++++------------- 1 file changed, 74 insertions(+), 65 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 67593da5..5df68814 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -695,6 +695,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) uint64_t tx_badness = UINT64_MAX; unsigned tx_iqerrs = UINT_MAX; unsigned iqserrs2 = -1; + const unsigned MAX_RTY = 5; g_clk_reduce = 0; @@ -747,79 +748,88 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) int ph_ty_m = 0; unsigned iqserrs; unsigned errs[4] = { UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX }; + bool last_noerrs = false; + for (unsigned rxrty = 0; rxrty < MAX_RTY; rxrty++) { + uint64_t badness_m = UINT64_MAX; - for (unsigned rxrty = 0; rxrty < 4; rxrty++) { - uint64_t badness_m = UINT64_MAX; + phase_m = 0; + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); - phase_m = 0; - res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); + int phase_min; + int phase_max; + int phase_last = -1; - int phase_min; - int phase_max; + phase_min = 65; + phase_max = 0; - phase_min = 65; - phase_max = 0; + badness_m = UINT64_MAX; - badness_m = UINT64_MAX; + for (unsigned ph = 1; ph < 65; ph++) { + unsigned w; + uint64_t badness = UINT64_MAX; - for (unsigned ph = 1; ph < 65; ph++) { - unsigned w; - uint64_t badness = UINT64_MAX; + res = res ? res : usleep(10); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, ph, 0, 0); + res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : _xsdr_rxserdes_reset(d); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); - res = res ? res : usleep(10); - res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, ph, 0, 0); - res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); - res = res ? res : _xsdr_rxserdes_reset(d); - res = res ? res : usleep(10); - res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); + for (w = 0; w < check_to; w++) { + res = res ? res : usleep(100); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { + break; + } + } - for (w = 0; w < check_to; w++) { - res = res ? res : usleep(100); - res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { + badness *= 1.0 * check_to / (w + 1); // Rescale + phase_last = ph; + last_noerrs = false; + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_RX/%d=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", rxrty, ph - 1, w, + errs[0], errs[1], errs[2], errs[3], (long long)badness); + if (res) { + break; + } else if ((last_noerrs = (d->dpump ? noerrors_v2(errs, &badness) : noerrors_v4(errs, &badness)))) { + phase_m = ph; + if (ph < phase_min) + phase_min = ph; + if (ph > phase_max) + phase_max = ph; + + // Got more than 7 phases, we're safe; skip searching + unsigned sphase = (rxrty == 0) ? 8 : (rxrty == 1) ? 4 : (rxrty == 2) ? 1 : 0; + if (phase_max - phase_min >= sphase) + break; + } else if (phase_max >= phase_min) { break; } - } - badness *= 1.0 * check_to / (w + 1); // Rescale - USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", ph - 1, w, - errs[0], errs[1], errs[2], errs[3], (long long)badness); - if (res || (d->dpump ? noerrors_v2(errs, &badness) : noerrors_v4(errs, &badness))) { - phase_m = ph; - if (ph < phase_min) - phase_min = ph; - if (ph > phase_max) - phase_max = ph; - - // Got more than 7 phases, we're safe; skip searching - unsigned sphase = (rxrty == 0) ? 8 : (rxrty == 1) ? 4 : (rxrty == 2) ? 1 : 0; - if (phase_max - phase_min >= sphase) - break; - } else if (phase_max >= phase_min) { - break; + if (badness_m > badness) { + badness_m = badness; + phase_m = ph; + } } - if (badness_m > badness) { - badness_m = badness; - phase_m = ph; + if (phase_max >= phase_min) { + phase_m = (phase_max + phase_min) / 2; } - } - if (phase_max > phase_min) { - phase_m = (phase_max + phase_min) / 2; - } + if (phase_last == phase_m && last_noerrs) { + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "Took PHASE_RX=%2d [%6d/%6d/%6d/%6d] BD=0\n", phase_m - 1, + errs[0], errs[1], errs[2], errs[3]); + rx_badness = 0; + break; + } - USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Restoring RX phase to %d (bandness=%" PRId64 ") PH_MIN=%d PH_MAX=%d\n", - phase_m - 1, badness_m, phase_min, phase_max); + // Try our best at least + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, phase_m, 0, 0); + res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); + res = res ? res : _xsdr_rxserdes_reset(d); + res = res ? res : usleep(10); + res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); - // Try our best at least - res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcm_rx_only_path, phase_m, 0, 0); - res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); - res = res ? res : _xsdr_rxserdes_reset(d); - res = res ? res : usleep(10); - res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); - { uint64_t badness = UINT64_MAX; unsigned w; for (w = 0; w < check_to; w++) { @@ -829,20 +839,19 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) break; } } + badness *= 1.0 * check_to / (w + 1); // Rescale rx_badness = badness; - if (badness > 100 /*badness_m * 2*/) { - USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, - errs[0], errs[1], errs[2], errs[3], (long long)badness); - g_clk_reduce++; - phase_min = 65; - phase_max = 0; - continue; - } - } + bool warn_badness = (rxrty == MAX_RTY - 1); + USDR_LL_LOG(dev, "XDEV", warn_badness ? USDR_LOG_WARNING : USDR_LOG_INFO, "RePHASE_RX=%2d I=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", phase_m - 1, w, + errs[0], errs[1], errs[2], errs[3], (long long)badness); - break; + if (badness == 0) + break; + + if (g_clk_reduce < 2) + g_clk_reduce++; } d->lmlcal_rx_phase = phase_m; From 1b47e1e834e8af3c44f6a6bf274b52c71740558f Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 19:10:18 +0400 Subject: [PATCH 344/397] lms8001: retry with different VCO divider --- src/lib/hw/lms8001/lms8001.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index 0cb5a75d..d80728ca 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -563,6 +563,10 @@ static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32 } USDR_LOG("8001", USDR_LOG_NOTE, "VCO Calibration finished, VCO:%d CAP:%d\n", VCO_final, freq_final); + USDR_LOG("8001", USDR_LOG_INFO, "VCO Calibration finished, VCO:%d CAP:%d\n", VCO_final, freq_final); + + if (freq_final == 0 || freq_final == 255) + return -ERANGE; if (actual) *actual = actual_freq; return res; @@ -1032,6 +1036,7 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, 3); SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, 1); +restart: // Sets FF-DIV Modulus (former setFFDIV) SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FF_MOD_n(curr->FF_CFG, pll_s.divi); SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FFCORE_MOD_n(curr->FF_CFG, pll_s.divi); @@ -1056,10 +1061,18 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, _lms80001_tune_settings_def(m, &vco_settings); USDR_LOG("8001", USDR_LOG_NOTE, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); + USDR_LOG("8001", USDR_LOG_INFO, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); // Step 1 - Tune PLL to generate F_LO frequency at LODIST outputs that should be manualy enabled // outside this method res = _lms8001_vco_tune(m, fvco, fref, tune_flags, &vco_settings, &actual_vco); + + if (res == -ERANGE) { + pll_s.divi ++; + pll_s.fvco *= 2; + goto restart; + } + if (res) { USDR_LOG("8001", USDR_LOG_WARNING, "PLL Tuning to F_LO=%.3f GHz failed!\n", flo / 1.0e9); return res; From a17b37d1512a02a9b7707e94e9dc4fd42dd7ac59 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 23:38:54 +0400 Subject: [PATCH 345/397] lms8001: make automatic recalibration after fail more robust --- src/lib/hw/lms8001/lms8001.c | 109 ++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 33 deletions(-) diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index d80728ca..94e069fd 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -451,6 +451,11 @@ static uint32_t _mk_pav(lms8001_state_t* m, unsigned addr, uint16_t val) return MAKE_LMS8001_REG_WR((PLL_PROFILE_1_PLL_ENABLE_n - PLL_PROFILE_0_PLL_ENABLE_n) * m->act_profile + addr, val); } +enum { + VCO_TUNE_TOO_LOW = 1, + VCO_TUNE_TOO_HIGH = 2, +}; + static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32_t flags, const lms80001_tune_settings_t* s, double *actual) { lms8001_pll_settings_t pll = _lms8001_calc_pll(fvco, fref, flags); @@ -562,13 +567,20 @@ static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32 res = -ERANGE; } - USDR_LOG("8001", USDR_LOG_NOTE, "VCO Calibration finished, VCO:%d CAP:%d\n", VCO_final, freq_final); + bool too_low = (freq_final < 2); + bool too_high = (freq_final > 253); + + USDR_LOG("8001", (too_low || too_high) ? USDR_LOG_INFO : USDR_LOG_NOTE, "VCO Calibration finished: %s VCO:%d CAP:%d\n", + (too_low || too_high) ? "FAIL" : "OK", VCO_final, freq_final); USDR_LOG("8001", USDR_LOG_INFO, "VCO Calibration finished, VCO:%d CAP:%d\n", VCO_final, freq_final); - if (freq_final == 0 || freq_final == 255) - return -ERANGE; + if (actual) + *actual = actual_freq; - if (actual) *actual = actual_freq; + if (too_low) + return VCO_TUNE_TOO_LOW; + if (too_high) + return VCO_TUNE_TOO_HIGH; return res; } @@ -1019,7 +1031,8 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, bool iq_gen = (tune_flags & LMS8001_IQ_GEN) == LMS8001_IQ_GEN; lms8001_pll_state_t* curr = &m->pll_profiles[m->act_profile]; lms8001_vco_settings_t pll_s; - double actual_vco; + double actual_vco = 0; + uint64_t fvco; // Calculate Loop - Crossover frequency double fc = loopBW / 1.65; @@ -1036,41 +1049,59 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, 3); SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, 1); -restart: - // Sets FF-DIV Modulus (former setFFDIV) - SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FF_MOD_n(curr->FF_CFG, pll_s.divi); - SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FFCORE_MOD_n(curr->FF_CFG, pll_s.divi); - SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FFDIV_SEL_n(curr->FF_CFG, pll_s.divi > 0 ? 1 : 0); + for (unsigned r = 0; r < 3; r++) { + // Sets FF-DIV Modulus (former setFFDIV) + SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FF_MOD_n(curr->FF_CFG, pll_s.divi); + SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FFCORE_MOD_n(curr->FF_CFG, pll_s.divi); + SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FFDIV_SEL_n(curr->FF_CFG, pll_s.divi > 0 ? 1 : 0); - SET_LMS8001_PLL_PROFILE_0_PLL_ENABLE_N_PLL_EN_FFCORE_n(curr->ENABLE, pll_s.divi > 0 ? 1 : 0); + SET_LMS8001_PLL_PROFILE_0_PLL_ENABLE_N_PLL_EN_FFCORE_n(curr->ENABLE, pll_s.divi > 0 ? 1 : 0); - uint32_t lms_init[] = { - _mk_pav(m, PLL_PROFILE_0_PLL_VCO_CFG_n, curr->VCO_CFG), - _mk_pav(m, PLL_PROFILE_0_PLL_FF_CFG_n, curr->FF_CFG), + uint32_t lms_init[] = { + _mk_pav(m, PLL_PROFILE_0_PLL_VCO_CFG_n, curr->VCO_CFG), + _mk_pav(m, PLL_PROFILE_0_PLL_FF_CFG_n, curr->FF_CFG), - // Enable register is going to be update late anyway, so skip this - // _mk_pav(m, PLL_PROFILE_0_PLL_ENABLE_n, curr->ENABLE), - }; - res = lms8001_spi_post(m, lms_init, SIZEOF_ARRAY(lms_init)); - if (res) - return res; + // Enable register is going to be update late anyway, so skip this + // _mk_pav(m, PLL_PROFILE_0_PLL_ENABLE_n, curr->ENABLE), + }; + res = lms8001_spi_post(m, lms_init, SIZEOF_ARRAY(lms_init)); + if (res) + return res; - // Calculate actual VCO frequency - uint64_t fvco = (iq_gen) ? (flo << (pll_s.divi + 1)) : (flo << pll_s.divi); - lms80001_tune_settings_t vco_settings; - _lms80001_tune_settings_def(m, &vco_settings); + // Calculate actual VCO frequency + fvco = (iq_gen) ? (flo << (pll_s.divi + 1)) : (flo << pll_s.divi); + lms80001_tune_settings_t vco_settings; + _lms80001_tune_settings_def(m, &vco_settings); - USDR_LOG("8001", USDR_LOG_NOTE, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); - USDR_LOG("8001", USDR_LOG_INFO, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); + USDR_LOG("8001", USDR_LOG_NOTE, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); + USDR_LOG("8001", USDR_LOG_INFO, "PLL Tuning to F_VCO=%.3f GHz DIV=%d\n", fvco / 1.0e9, pll_s.divi); - // Step 1 - Tune PLL to generate F_LO frequency at LODIST outputs that should be manualy enabled - // outside this method - res = _lms8001_vco_tune(m, fvco, fref, tune_flags, &vco_settings, &actual_vco); + // Step 1 - Tune PLL to generate F_LO frequency at LODIST outputs that should be manualy enabled + // outside this method + res = _lms8001_vco_tune(m, fvco, fref, tune_flags, &vco_settings, &actual_vco); - if (res == -ERANGE) { - pll_s.divi ++; - pll_s.fvco *= 2; - goto restart; + // Try another divider and recalibrate + if (res == VCO_TUNE_TOO_LOW) { + if (pll_s.divi == 3) { + res = (m->stepping == LMS8_MPW2015) ? 0 : -ERANGE; + break; + } + + pll_s.divi++; + pll_s.fvco *= 2; + } else if (res == VCO_TUNE_TOO_HIGH) { + if (pll_s.divi == 0) { + res = (m->stepping == LMS8_MPW2015) ? 0 : -ERANGE; + break; + } + + pll_s.divi--; + pll_s.fvco /= 2; + } else if (res) { + return res; + } else { + break; + } } if (res) { @@ -1078,6 +1109,18 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, return res; } + int vtune_high, vtune_low, pll_lock; + res = _lms8001_lock_status(m, &vtune_high, &vtune_low, &pll_lock); + if (res) + return res; + + if ((m->stepping == LMS8_MPW2024) && (vtune_high || vtune_low)) { + USDR_LOG("8001", USDR_LOG_WARNING, "PLL didn't lock [%d/%d/%d] F_LO=%.3f Ghz F_VCO=%.3f DIV=%d!\n", + vtune_low, vtune_high, pll_lock, + flo / 1.0e9, pll_s.fvco / 1.0e9, 1 << pll_s.divi); + return -ERANGE; + } + // Step 2 - Center VCO Tuning Voltage if needed only for MPW2015 res = (m->stepping == LMS8_MPW2024) ? res : _lms8001_center_vtune(m, fvco, fref, tune_flags); if (res) { From 2a991641458df8a673931b65d327615821b621ca Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 3 Mar 2026 23:40:53 +0400 Subject: [PATCH 346/397] ssdr: do not retune LMS7 if it's the same LO --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 17 +++++++++ src/lib/device/m2_lm7_1/xsdr_ctrl.c | 58 ++++++++++++++++++++++------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 2 + 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 8fff8333..bd90abb6 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -265,6 +265,7 @@ static int dev_m2_lm7_1_sdr_rx_phase_ovr_set(pdevice_t ud, pusdr_vfs_obj_t obj, static int dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_lnb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -287,6 +288,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/vio", { dev_m2_lm7_1_sdr_vio_set, NULL }}, + { "/dm/sdr/0/lnb", { dev_m2_lm7_1_lnb_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr", { dev_m2_lm7_1_sdr_tx_phase_ovr_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr_iq", { dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr_rc", { dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set, NULL }}, @@ -544,6 +546,17 @@ int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return xsdr_set_vio(&d->xdev, value); } +int dev_m2_lm7_1_lnb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + if (value < 300e6 || value > 3800e6) { + return -ERANGE; + } + + d->xdev.lms7_lob = value; + return 0; +} + int dev_m2_lm7_1_debug_lms7002m_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; @@ -1448,11 +1461,15 @@ int usdr_device_m2_lm7_1_unregister_stream(device_t* dev, stream_handle_t* strea d->tx->ops->destroy(d->tx); d->tx = NULL; + + d->xdev.lms7_txlo_last = 0; } else if (stream == d->rx) { xsdr_rfic_streaming_down(&d->xdev, RFIC_LMS7_RX); d->rx->ops->destroy(d->rx); d->rx = NULL; + + d->xdev.lms7_rxlo_last = 0; } else { return -EINVAL; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 5df68814..8ce21066 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1417,16 +1417,29 @@ int xsdr_rfic_set_gain(xsdr_dev_t *d, return lms7002m_set_gain(&d->base, channel, gain_type, gain, actualgain); } +enum { + LMS8_TXA_CHIDX = 0, + LMS8_TXB_CHIDX = 1, + LMS8_RXA_CHIDX = 2, + LMS8_RXB_CHIDX = 3, +}; + int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, unsigned channel, unsigned type, double freq, double *actualfreq) { + int res = 0; + if (d->ssdr && freq > 3.0e9) { float bwef = d->lms8st_bwef_1000 / 1000.0; - int res = 0; - d->lms7_lob = 2.01e9; + unsigned lob = (d->lms7_lob == 0) ? 2.01e9 : d->lms7_lob; + unsigned pwr_msk = + (d->base.tx_run[0] ? 1 << LMS8_TXA_CHIDX : 0) | + (d->base.tx_run[1] ? 1 << LMS8_TXB_CHIDX : 0) | + (d->base.rx_run[0] ? 1 << LMS8_RXA_CHIDX : 0) | + (d->base.rx_run[1] ? 1 << LMS8_RXB_CHIDX : 0); res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); @@ -1434,29 +1447,37 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 2, 0); res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 3, 0); #else - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 0, 0, 0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 1, 0, 0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 2, 0, 0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, 3, 0, 0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXA_CHIDX, d->base.tx_run[0] ? 0 : ~0, d->base.tx_run[0] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXB_CHIDX, d->base.tx_run[1] ? 0 : ~0, d->base.tx_run[1] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXA_CHIDX, d->base.rx_run[0] ? 0 : ~0, d->base.rx_run[0] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXB_CHIDX, d->base.rx_run[1] ? 0 : ~0, d->base.rx_run[1] ? 0 : ~0); #endif res = res ? res : lms8001_core_enable(&d->lms8, 1); - res = res ? res : lms8001_ch_enable(&d->lms8, 0xf); + res = res ? res : lms8001_ch_enable(&d->lms8, pwr_msk); - //res = res ? res : lms8001_tune(&d->lms8, d->base.fref, freq - d->lms7_lob); - res = res ? res : lms8001_smart_tune(&d->lms8, 0, freq - d->lms7_lob, d->base.fref, + res = res ? res : lms8001_smart_tune(&d->lms8, 0, freq - lob, d->base.fref, d->lms8st_loopbw, d->lms8st_phasemargin, bwef, d->lms8st_flock_n); res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x80); if (res) return res; - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "Setting FREQ %.3f Mhz, LNB %.3f Mhz\n", freq / 1.0e6, d->lms7_lob / 1.0e6); - freq = d->lms7_lob; - } else { - d->lms7_lob = 0; + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "Setting FREQ %.3f Mhz, LNB %.3f Mhz\n", freq / 1.0e6, lob / 1.0e6); + freq = lob; } - return lms7002m_fe_set_freq(&d->base, channel, type, freq, actualfreq); + if (type == RFIC_LMS7_TUNE_RX_FDD && d->lms7_rxlo_last == freq) + return 0; + if (type == RFIC_LMS7_TUNE_TX_FDD && d->lms7_txlo_last == freq) + return 0; + + res = lms7002m_fe_set_freq(&d->base, channel, type, freq, actualfreq); + if (type == RFIC_LMS7_TUNE_RX_FDD) { + d->lms7_rxlo_last = (res == 0) ? freq : 0; + } else if (type == RFIC_LMS7_TUNE_TX_FDD) { + d->lms7_txlo_last = (res == 0) ? freq : 0; + } + return res; } @@ -2096,6 +2117,15 @@ int xsdr_dtor(xsdr_dev_t *d) res = (res) ? res : xsdr_rfic_streaming_down(d, RFIC_LMS7_RX | RFIC_LMS7_TX); res = (res) ? res : lms7002m_destroy(&d->base.lmsstate); } + + if (d->ssdr) { + // Turn off LMS8 + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); + res = res ? res : lms8001_core_enable(&d->lms8, 0); + res = res ? res : lms8001_ch_enable(&d->lms8, 0); + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x80); + } + res = (res) ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0); res = (res) ? res : dev_gpo_set(dev, IGPO_LDOLMS_EN, 0); res = (res) ? res : dev_gpo_set(dev, IGPO_LED, 0); diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index df8e4d1d..da2eacfe 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -57,6 +57,8 @@ struct xsdr_dev unsigned s_flags; unsigned lms7_lob; + unsigned lms7_rxlo_last; + unsigned lms7_txlo_last; int tx_override_phase; int tx_override_phase_iq; From be791af3635c50939eea7444bbfe61aa1016fd35 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 02:38:31 +0400 Subject: [PATCH 347/397] xsdr: reset TSP after samplerate change --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 8ce21066..dd8ca37e 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -996,6 +996,9 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, false, false); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, false); res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); + + // Sometimes TxTSP can get off by 1TSP clock, we need to preventevly reset the path + res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); } } else { From cfe90e12f4031754a8987bdce3ee974b56d6ffd9 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 14:35:43 +0400 Subject: [PATCH 348/397] improve calibration --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 124 +++++++--------------------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 3 - 2 files changed, 32 insertions(+), 95 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index dd8ca37e..5681a466 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -295,24 +295,6 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, static struct mmcm_config_raw g_tx_cfg_raw; -int xsdr_upd_phase(xsdr_dev_t *d) -{ - if (d->tx_override_phase) { - unsigned raw = d->tx_override_phase - 1; - g_tx_cfg_raw.ports[CLKOUT_PORT_0].phase = raw & 7; - g_tx_cfg_raw.ports[CLKOUT_PORT_0].delay = (raw >> 3); - } - - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM_TX set phase to %d.%d\n", g_tx_cfg_raw.ports[CLKOUT_PORT_0].delay, g_tx_cfg_raw.ports[CLKOUT_PORT_0].phase); - mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &g_tx_cfg_raw); - - // Reset MMCM - xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 1); - usleep(1); - xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, 0); - return 0; -} - int xsdr_phy_tx_iqsel(xsdr_dev_t *d, uint8_t iqsel) { return xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, iqsel); @@ -386,11 +368,11 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, // 6 - FCLK_TX if (!sep_clkdiv) { - cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; // IO_TX_IQSEL or unused - cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; // IO_TX_IQSEL or unused + cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; // unused + cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; // unused } else { - cfg_raw.ports[CLKOUT_PORT_0].period_l = vco_div_io; // IO_TX CLKDIV - cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io; // IO_TX CLKDIV + cfg_raw.ports[CLKOUT_PORT_0].period_l = vco_div_io; // IO_TX dedicated CLKDIV + cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io; // IO_TX dedicated CLKDIV } cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; // IO_TX cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; // IO_TX @@ -404,44 +386,31 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, cfg_raw.ports[CLKOUT_PORT_4].period_l = (vco_div_io + 1) / 2; // not used cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io / 2; // not used - cfg_raw.ports[CLKOUT_PORT_5].period_l = (vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io / 2; - cfg_raw.ports[CLKOUT_PORT_6].period_l = (vco_div_io + 1) / 2; + cfg_raw.ports[CLKOUT_PORT_5].period_l = (vco_div_io + 1) / 2; // FCLK_RX + cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io / 2; // FCLK_RX + cfg_raw.ports[CLKOUT_PORT_6].period_l = (vco_div_io + 1) / 2; // FCLK_TX cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io / 2; // FCLK_TX unsigned total_budget = 8 * vco_div_io; - unsigned phase = (((tx_mclk < 2*35e6) || (tx_mclk > 2*60e6)) ? 4 : 5) * total_budget / (vco_div_io > 63 ? 12 : 6); - // unsigned phase_iq = 0; //4; - + unsigned phase = total_budget / 2; + // Default 90deg F_CLK related to clocks cfg_raw.ports[CLKOUT_PORT_6].phase = phase % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = phase / 8; - if (!sep_clkdiv) { -#if 0 + // Old logic calibration (doesn't really work) + if (sep_clkdiv) { + unsigned phase_iq = 0; cfg_raw.ports[CLKOUT_PORT_0].phase = phase_iq % 8; cfg_raw.ports[CLKOUT_PORT_0].delay = phase_iq / 8; if (d->tx_override_phase_iq || txphase || txphase_off) { - //unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase_iq - 1; - unsigned raw = (txphase != 0) ? txphase_off : d->tx_override_phase_iq - 1; cfg_raw.ports[CLKOUT_PORT_0].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_0].delay = raw / 8; } -#endif - } else { - cfg_raw.ports[CLKOUT_PORT_0].phase = 0; - cfg_raw.ports[CLKOUT_PORT_0].delay = 0; } - // if (d->tx_override_phase || txphase) { - // unsigned raw = (txphase != 0) ? txphase - 1 : d->tx_override_phase - 1; - // cfg_raw.ports[CLKOUT_PORT_1].phase = raw % 8; - // cfg_raw.ports[CLKOUT_PORT_1].delay = raw / 8; - // } - - if (d->tx_override_phase || txphase || txphase_off) { - //unsigned raw = (txphase != 0) ? ((txphase - 1 + txphase_off) % 64) : d->tx_override_phase - 1; + if (d->tx_override_phase || txphase) { unsigned raw = (txphase != 0) ? (txphase - 1) : d->tx_override_phase - 1; cfg_raw.ports[CLKOUT_PORT_6].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_6].delay = raw / 8; @@ -451,9 +420,6 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned raw = (rxphase != 0) ? rxphase - 1 : d->rx_override_phase - 1; cfg_raw.ports[CLKOUT_PORT_2].phase = raw % 8; cfg_raw.ports[CLKOUT_PORT_2].delay = raw / 8; - -// cfg_raw.ports[CLKOUT_PORT_FB].phase = raw % 8; -// cfg_raw.ports[CLKOUT_PORT_FB].delay = raw / 8; } if (nomul) { @@ -504,7 +470,6 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, usleep(50); } - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM Ready flag timed out!\n"); return -EIO; } @@ -724,8 +689,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_set_lms125vdd(d, 1360); } } else { - bool boost_vio = (!d->siso_sdr_active_rx) && (d->s_rxrate > 85e6 || d->s_txrate > 85e6); - res = res ? res : xsdr_set_vio(d, boost_vio ? 1850 : 1800); + bool boost_vio = (!d->siso_sdr_active_rx) && (d->s_rxrate > 80e6 || d->s_txrate > 80e6); + res = res ? res : xsdr_set_vio(d, boost_vio ? 1875 : 1800); } if (!(d->base.rx_run[0] || d->base.rx_run[1])) { @@ -741,6 +706,9 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (res) return res; + unsigned recal_rx = 0; +recalibrate_rx: + // Autocallibration if RX phase wasn't set if (d->rx_override_phase == 0) { const unsigned check_to = 10; @@ -765,7 +733,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) badness_m = UINT64_MAX; - for (unsigned ph = 1; ph < 65; ph++) { + for (unsigned ph = 1; ph < 4*63 + 1; ph++) { unsigned w; uint64_t badness = UINT64_MAX; @@ -873,7 +841,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) const unsigned iq_phases[8] = { 0, 1, 2, 62, 63, 2, 1, 0}; unsigned iq_ph = iq_phases[rty]; - for (unsigned ph = 1; ph < 65; ph++) { + for (unsigned ph = 1; ph < 4*63 + 1; ph++) { //unsigned w; uint64_t badness = UINT64_MAX; res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph, iq_ph); @@ -889,11 +857,18 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "FAIL_PHASE_RX=%2d PH=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", d->lmlcal_rx_phase, ph - 1, errs[0], errs[1], errs[2], errs[3], (long long)badness); if (badness > 20) { + failed_rxcnt++; if (failed_rxcnt < 6) { ph--; - failed_rxcnt++; continue; } + if (failed_rxcnt > 30) { + if (recal_rx < 3) { + recal_rx++; + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "GLOBAL_RESYNC\n"); + goto recalibrate_rx; + } + } } } res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_DIGLOOPBACK); @@ -918,8 +893,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if ((rty == 0 && iqserrs != 0) || iqserrs > 40) { USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX[%d]=%2d ABIQ=%d\n", g, ph - 1, iqserrs); - unsigned msk[12] = { 0b1100, 0b0110, 0b0011, 0b1001, 0b1000, 0b0100, 0b0010, 0b0001, 0b1100, 0b0110, 0b1001, 0b1100 }; - + unsigned msk[12] = { 0b1100, 0b0110, 0b0011, 0b1001, 0b1100, 0b0110, 0b0011, 0b1001, 0b1100, 0b0110, 0b1001, 0b1100 }; res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : msk[g + 1]); //res = res ? res : _xsdr_txserdes_reset(d); res = res ? res : usleep(10); @@ -998,6 +972,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); // Sometimes TxTSP can get off by 1TSP clock, we need to preventevly reset the path + res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); } } else { @@ -1075,49 +1050,14 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, } if (rxrate) { -#if 0 - if (d->mmcm_rx) { - res = res ? res : xsdr_configure_lml_mmcm_rx(d); - } -#endif -#if 0 - sisosdrflag = d->dpump ? 16 : d->base.lml_mode.rxsisoddr ? 8 : 0; - res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); - usleep(100); - res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); -#endif -#if 0 - if (d->mmcm_rx) { - // Configure PHY (reset) - // TODO phase search - - for (unsigned h = 0; h < 16; h++) { - res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); - usleep(100); - res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); - - - USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE=%d\n", h); - res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x00000000); - unsigned tmp; //, tmp2; - for (unsigned k = 0; k < 100; k++) { - res = res ? res : lowlevel_reg_rd32(dev, subdev, REG_CFG_PHY_0, &tmp); - } - - res = res ? res : mmcm_set_digdelay_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_RX, CLKOUT_PORT_0, h); - } - } -#endif if (!d->ssdr_pro) { - // Switch to clock meas - res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); + // Switch to clock meas + res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); } } if (txrate || d->ssdr_pro) { res = res ? res : _xsdr_calibrate_lml(d); - - //TODO check tsp/rsp states } return res; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index da2eacfe..cff1d39e 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -219,9 +219,6 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, size_t meminsz, void* pin, size_t memoutsz, const void* pout); - -int xsdr_upd_phase(xsdr_dev_t *d); - int xsdr_config_rcvdly(xsdr_dev_t *d, unsigned type, unsigned val); enum { From a8998ef6d931de9a71b52f04d7ceac22e1b23329 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 14:39:49 +0400 Subject: [PATCH 349/397] xsdr: reduce calibration time --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 5681a466..a3e10444 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -467,7 +467,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, return 0; } - usleep(50); + usleep(10); } USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM Ready flag timed out!\n"); @@ -728,7 +728,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) int phase_max; int phase_last = -1; - phase_min = 65; + phase_min = 4*63 + 1; phase_max = 0; badness_m = UINT64_MAX; From a66a74a4870c7a45f24368d1c84fda2251bae922 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 15:18:42 +0400 Subject: [PATCH 350/397] xsdr: LML calibration fixup --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index a3e10444..e8580431 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -840,11 +840,12 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) for (unsigned rty = 0; rty < 8; rty++) { const unsigned iq_phases[8] = { 0, 1, 2, 62, 63, 2, 1, 0}; unsigned iq_ph = iq_phases[rty]; + // Once we change VCO frequency RX calibration becomes invalid and we need to adjust it for (unsigned ph = 1; ph < 4*63 + 1; ph++) { //unsigned w; uint64_t badness = UINT64_MAX; - res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph, iq_ph); + res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph, 0 /*iq_ph*/); if (check_rx) { res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_LFSR); res = res ? res : lms7002m_limelight_fifo_reset(&d->base.lmsstate, true, true); @@ -881,7 +882,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (res || (noerrors_v4(errs, &badness) /* && (iqserrs == 0)*/) || (rty > 1 && badness < 20)) { phase_m = ph; - for (int g = 0; g < 12/*50*/; g++) { + for (int g = 0; g < 24; g++) { // Check A/B & I/Q aligment is ok res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); res = res ? res : usleep(10); @@ -893,13 +894,22 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if ((rty == 0 && iqserrs != 0) || iqserrs > 40) { USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX[%d]=%2d ABIQ=%d\n", g, ph - 1, iqserrs); - unsigned msk[12] = { 0b1100, 0b0110, 0b0011, 0b1001, 0b1100, 0b0110, 0b0011, 0b1001, 0b1100, 0b0110, 0b1001, 0b1100 }; - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : msk[g + 1]); + unsigned msk[4] = { 0b1100, 0b0110, 0b0011, 0b1001 }; + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : msk[(g + 1) % 4]); //res = res ? res : _xsdr_txserdes_reset(d); res = res ? res : usleep(10); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); res = res ? res : usleep(10); + // REMOVE ME: fixup for now + // On spectrum analyzer signal looks intact but we get phase off in digital loopback + // looks like known LML 1-cycle off problem on LMS7002 chip, need to add + // reclocking, but leave it as is for now + if (g == 20) { + iqserrs = 0; + break; + } + } else if (g > 0) { // sometimes IQ err reports 0 while it's out of sync, check if LFSR still intact @@ -917,6 +927,10 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } else { break; } + + // REMOVE ME: fixup for now + if (g > 18 && badness < 100 && d->s_txrate > 80e6) + break; } } From b60528840f361b8f6eb56aaae9319cee81c4e818 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 16:41:07 +0400 Subject: [PATCH 351/397] ssdr: use integer lms8 --- src/lib/device/m2_dsdr/dsdr_hiper.c | 2 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 39 ++++++++++++++++++----------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 1 + src/lib/hw/lms8001/lms8001.c | 10 ++++---- src/lib/hw/lms8001/lms8001.h | 2 +- 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/lib/device/m2_dsdr/dsdr_hiper.c b/src/lib/device/m2_dsdr/dsdr_hiper.c index 4499ee96..db252680 100644 --- a/src/lib/device/m2_dsdr/dsdr_hiper.c +++ b/src/lib/device/m2_dsdr/dsdr_hiper.c @@ -1780,7 +1780,7 @@ int dsdr_hiper_fe_txlo_upd(dsdr_hiper_fe_t* def, unsigned chno, bool* p_swap_txi (def->ucfg[chno].tx_en << 3) | (def->ucfg[chno - 1].tx_en << 2) : (def->ucfg[chno + 1].tx_en << 3) | (def->ucfg[chno].tx_en << 2); - res = res ? res : lms8001_core_enable(&def->lms8[idx], high_path); + res = res ? res : lms8001_core_enable(&def->lms8[idx], high_path, high_path, high_path); res = res ? res : lms8001_ch_enable(&def->lms8[idx], high_path ? chmsk : 0); if (fLO > 0) { if (def->lms8_lo[idx].set && def->lms8_lo[idx].value == fLO) { diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index e8580431..60879db1 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1398,26 +1398,35 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, (d->base.rx_run[0] ? 1 << LMS8_RXA_CHIDX : 0) | (d->base.rx_run[1] ? 1 << LMS8_RXB_CHIDX : 0); - res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); + int64_t lms8_freq = (freq - lob + d->base.fref / 2) / d->base.fref; + lms8_freq *= d->base.fref; + lob = freq - lms8_freq; + if (d->lms8_lo_freq != lms8_freq) { + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); #if 0 - res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 2, 0); - res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 3, 0); + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 2, 0); + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 3, 0); #else - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXA_CHIDX, d->base.tx_run[0] ? 0 : ~0, d->base.tx_run[0] ? 0 : ~0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXB_CHIDX, d->base.tx_run[1] ? 0 : ~0, d->base.tx_run[1] ? 0 : ~0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXA_CHIDX, d->base.rx_run[0] ? 0 : ~0, d->base.rx_run[0] ? 0 : ~0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXB_CHIDX, d->base.rx_run[1] ? 0 : ~0, d->base.rx_run[1] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXA_CHIDX, d->base.tx_run[0] ? 0 : ~0, d->base.tx_run[0] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXB_CHIDX, d->base.tx_run[1] ? 0 : ~0, d->base.tx_run[1] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXA_CHIDX, d->base.rx_run[0] ? 0 : ~0, d->base.rx_run[0] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXB_CHIDX, d->base.rx_run[1] ? 0 : ~0, d->base.rx_run[1] ? 0 : ~0); #endif - res = res ? res : lms8001_core_enable(&d->lms8, 1); - res = res ? res : lms8001_ch_enable(&d->lms8, pwr_msk); + if (!d->ssdr_pro) { + res = res ? res : lms8001_core_enable(&d->lms8, 0, 0, 1); + } + res = res ? res : lms8001_ch_enable(&d->lms8, pwr_msk); - res = res ? res : lms8001_smart_tune(&d->lms8, 0, freq - lob, d->base.fref, - d->lms8st_loopbw, d->lms8st_phasemargin, bwef, d->lms8st_flock_n); + res = res ? res : lms8001_smart_tune(&d->lms8, 0, freq - lob, d->base.fref, + d->lms8st_loopbw, d->lms8st_phasemargin, bwef, d->lms8st_flock_n); - res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x80); - if (res) - return res; + res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x80); + if (res) + return res; + + d->lms8_lo_freq = freq - lob; + } USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "Setting FREQ %.3f Mhz, LNB %.3f Mhz\n", freq / 1.0e6, lob / 1.0e6); freq = lob; @@ -2078,7 +2087,7 @@ int xsdr_dtor(xsdr_dev_t *d) if (d->ssdr) { // Turn off LMS8 res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); - res = res ? res : lms8001_core_enable(&d->lms8, 0); + res = res ? res : lms8001_core_enable(&d->lms8, 0, 0, 0); res = res ? res : lms8001_ch_enable(&d->lms8, 0); res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x80); } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index cff1d39e..8dd7c337 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -56,6 +56,7 @@ struct xsdr_dev unsigned s_dacclk; unsigned s_flags; + int64_t lms8_lo_freq; unsigned lms7_lob; unsigned lms7_rxlo_last; unsigned lms7_txlo_last; diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index 94e069fd..f0c9b2cc 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -335,14 +335,14 @@ int lms8001b_hlmix_loss_set(lms8001_state_t* state, unsigned chan, unsigned loss return lms8001_spi_post(state, en_regs, SIZEOF_ARRAY(en_regs)); } -int lms8001_core_enable(lms8001_state_t* out, bool en) +int lms8001_core_enable(lms8001_state_t* state, bool enbuf, bool endiv, bool encp) { uint32_t lms_init[] = { - MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, en ? 1 : 0, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CLKBUF : LMS_LDO_1P25), - MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, en ? 1 : 0, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_DIV : LMS_LDO_1P25), - MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, en ? 1 : 0, out->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CP : LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_CLK_BUF_LDO_Config(0, 0, enbuf ? 1 : 0, state->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CLKBUF : LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_PLL_DIV_LDO_Config(0, 0, endiv ? 1 : 0, state->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_DIV : LMS_LDO_1P25), + MAKE_LMS8001_BIASLDOCONFIG_PLL_CP_LDO_Config(0, 0, encp ? 1 : 0, state->stepping == LMS8_MPW2024 ? LMS_LDO_VDD_PLL_CP : LMS_LDO_1P25), }; - return lms8001_spi_post(out, lms_init, SIZEOF_ARRAY(lms_init)); + return lms8001_spi_post(state, lms_init, SIZEOF_ARRAY(lms_init)); } int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned int stepping, lms8001_state_t *out) diff --git a/src/lib/hw/lms8001/lms8001.h b/src/lib/hw/lms8001/lms8001.h index af657b07..da1abf21 100644 --- a/src/lib/hw/lms8001/lms8001.h +++ b/src/lib/hw/lms8001/lms8001.h @@ -89,7 +89,7 @@ typedef struct lms8001_state lms8001_state_t; int lms8001_create(lldev_t dev, unsigned subdev, unsigned lsaddr, unsigned stepping, lms8001_state_t *out); int lms8001_destroy(lms8001_state_t* m); -int lms8001_core_enable(lms8001_state_t* state, bool enable); +int lms8001_core_enable(lms8001_state_t* state, bool enbuf, bool endiv, bool encp); int lms8001_tune(lms8001_state_t* state, unsigned fref, uint64_t out); int lms8001_ch_enable(lms8001_state_t* state, unsigned mask); From 5267fd149a33f33adc60c2e91cd8efb00c367de2 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 19:39:29 +0400 Subject: [PATCH 352/397] ssdr: improve lms8 smart tune --- src/lib/hw/lms8001/lms8001.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/lib/hw/lms8001/lms8001.c b/src/lib/hw/lms8001/lms8001.c index f0c9b2cc..34cc0306 100644 --- a/src/lib/hw/lms8001/lms8001.c +++ b/src/lib/hw/lms8001/lms8001.c @@ -441,8 +441,8 @@ static void _lms80001_tune_settings_def(lms8001_state_t* m, lms80001_tune_settin s->freq_init = 0; s->freq_settling_N = 4; s->vtune_wait_N = 128; - s->vco_sel_freq_max = 255; - s->vco_sel_freq_min = 0; + s->vco_sel_freq_max = 254; + s->vco_sel_freq_min = 1; } @@ -456,7 +456,7 @@ enum { VCO_TUNE_TOO_HIGH = 2, }; -static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32_t flags, const lms80001_tune_settings_t* s, double *actual) +static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32_t flags, const lms80001_tune_settings_t* s, double *actual, unsigned erange) { lms8001_pll_settings_t pll = _lms8001_calc_pll(fvco, fref, flags); bool xbuf_slfben = (flags & LMS8001_SELF_BIAS_XBUF) == LMS8001_SELF_BIAS_XBUF; @@ -467,6 +467,9 @@ static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32 double actual_freq = (double)fref * pll.nfix * (pll.nint + pll.nfrac / (double)(1 << 20)); lms8001_pll_state_t* curr = &m->pll_profiles[m->act_profile]; + if (pll.nfrac == 0) { + int_mode = true; + } // ======================= enablePLL part ======================= // Enable VCO Biasing Block @@ -506,7 +509,7 @@ static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32 m->pll.PLL_CAL_AUTO1 = MAKE_LMS8001_PLL_CONFIGURATION_PLL_CAL_AUTO1(s->vco_sel_force, s->vco_sel_init, s->freq_init_pos, s->freq_init); m->pll.PLL_CAL_AUTO2 = MAKE_LMS8001_PLL_CONFIGURATION_PLL_CAL_AUTO2(s->freq_settling_N, s->vtune_wait_N); - m->pll.PLL_CAL_AUTO3 = MAKE_LMS8001_PLL_CONFIGURATION_PLL_CAL_AUTO3(s->vco_sel_freq_max, s->vco_sel_freq_min); + m->pll.PLL_CAL_AUTO3 = MAKE_LMS8001_PLL_CONFIGURATION_PLL_CAL_AUTO3(s->vco_sel_freq_max - erange, s->vco_sel_freq_min + erange); uint32_t lms_init[] = { MAKE_LMS8001_REG_WR(PLL_CONFIGURATION_PLL_VREG, m->pll.PLL_VREG), @@ -567,8 +570,8 @@ static int _lms8001_vco_tune(lms8001_state_t* m, uint64_t fvco, int fref, uint32 res = -ERANGE; } - bool too_low = (freq_final < 2); - bool too_high = (freq_final > 253); + bool too_low = (freq_final < erange); + bool too_high = (freq_final > 255 - erange); USDR_LOG("8001", (too_low || too_high) ? USDR_LOG_INFO : USDR_LOG_NOTE, "VCO Calibration finished: %s VCO:%d CAP:%d\n", (too_low || too_high) ? "FAIL" : "OK", VCO_final, freq_final); @@ -598,7 +601,7 @@ static int _lms8001_lock_status(lms8001_state_t* m, int* vtune_high, int* vtune_ return 0; } -static int _lms8001_change_pll_vco_cfg(lms8001_state_t* m, uint64_t fvco, int fref, uint32_t flags, lms80001_tune_settings_t* vco_settings) +static int _lms8001_change_pll_vco_cfg(lms8001_state_t* m, uint64_t fvco, int fref, uint32_t flags, lms80001_tune_settings_t* vco_settings, unsigned erange) { int res = 0, vtune_high, vtune_low, pll_lock; lms8001_pll_state_t* curr = &m->pll_profiles[m->act_profile]; @@ -606,7 +609,7 @@ static int _lms8001_change_pll_vco_cfg(lms8001_state_t* m, uint64_t fvco, int fr _mk_pav(m, PLL_PROFILE_0_PLL_VCO_CFG_n, curr->VCO_CFG), }; res = res ? res : lms8001_spi_post(m, lms_init, SIZEOF_ARRAY(lms_init)); - res = res ? res : _lms8001_vco_tune(m, fvco, fref, flags, vco_settings, NULL); + res = res ? res : _lms8001_vco_tune(m, fvco, fref, flags, vco_settings, NULL, erange); res = res ? res : usleep(30000); res = res ? res : _lms8001_lock_status(m, &vtune_high, &vtune_low, &pll_lock); if (res) @@ -677,7 +680,7 @@ static int _lms8001_center_vtune(lms8001_state_t* m, uint64_t fvco, int fref, ui int vdiv_swvdd = swvdd_list[i]; if (vdiv_swvdd_init != vdiv_swvdd) { SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VDIV_SWVDD_n(curr->VCO_CFG, vdiv_swvdd); - res = _lms8001_change_pll_vco_cfg(m, fvco, fref, flags, &vco_settings); + res = _lms8001_change_pll_vco_cfg(m, fvco, fref, flags, &vco_settings, 0); if (res == 1) { USDR_LOG("8001", USDR_LOG_INFO, "VTUNE voltage centered successfuly by changing VDIV_SWVDD value = %d\n", vdiv_swvdd); continue_vtune = false; @@ -706,7 +709,7 @@ static int _lms8001_center_vtune(lms8001_state_t* m, uint64_t fvco, int fref, ui if (amp_init != amp) { SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, amp); SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, 1); - res = _lms8001_change_pll_vco_cfg(m, fvco, fref, flags, &vco_settings); + res = _lms8001_change_pll_vco_cfg(m, fvco, fref, flags, &vco_settings, 0); if (res == 1) { USDR_LOG("8001", USDR_LOG_INFO, "VTUNE voltage centered successfuly by changing VCO_AMP value = %d\n", amp); continue_vtune = false; @@ -1049,7 +1052,7 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AMP_n(curr->VCO_CFG, 3); SET_LMS8001_PLL_PROFILE_0_PLL_VCO_CFG_N_VCO_AAC_EN_n(curr->VCO_CFG, 1); - for (unsigned r = 0; r < 3; r++) { + for (unsigned r = 0; r < 6; r++) { // Sets FF-DIV Modulus (former setFFDIV) SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FF_MOD_n(curr->FF_CFG, pll_s.divi); SET_LMS8001_PLL_PROFILE_0_PLL_FF_CFG_N_FFCORE_MOD_n(curr->FF_CFG, pll_s.divi); @@ -1078,7 +1081,7 @@ int lms8001_config_pll(lms8001_state_t* m, uint64_t flo, int fref, // Step 1 - Tune PLL to generate F_LO frequency at LODIST outputs that should be manualy enabled // outside this method - res = _lms8001_vco_tune(m, fvco, fref, tune_flags, &vco_settings, &actual_vco); + res = _lms8001_vco_tune(m, fvco, fref, tune_flags, &vco_settings, &actual_vco, 3 - (r / 2)); // Try another divider and recalibrate if (res == VCO_TUNE_TOO_LOW) { From a0e9b94d90b68ffd3d597f3c4bfb75de1b2e9253 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 20:34:32 +0400 Subject: [PATCH 353/397] ssdr: add interface to switch LMS8 int/frac mode --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 48 +++++++++++++++++++++++++++-- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 18 ++++++++--- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 4 ++- 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index bd90abb6..c1722718 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -266,6 +266,11 @@ static int dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set(pdevice_t ud, pusdr_vfs_obj_t ob static int dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_lnb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_lnb_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm7_1_lms8_intmode_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_lms8_intmode_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm7_1_lms8_switchover_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_lms8_switchover_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); static int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -287,8 +292,11 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/refclk/path", {dev_m2_lm7_1_sdr_refclk_path_set, NULL}}, - { "/dm/sdr/0/vio", { dev_m2_lm7_1_sdr_vio_set, NULL }}, - { "/dm/sdr/0/lnb", { dev_m2_lm7_1_lnb_set, NULL }}, + { "/dm/sdr/0/vio", { dev_m2_lm7_1_sdr_vio_set, NULL }}, + { "/dm/sdr/0/lnb", { dev_m2_lm7_1_lnb_set, dev_m2_lm7_1_lnb_get }}, + { "/dm/sdr/0/lms8_intmode", { dev_m2_lm7_1_lms8_intmode_set, dev_m2_lm7_1_lms8_intmode_get }}, + { "/dm/sdr/0/lms8_switchover", { dev_m2_lm7_1_lms8_switchover_set, dev_m2_lm7_1_lms8_switchover_get }}, + { "/dm/sdr/0/tx/phase_ovr", { dev_m2_lm7_1_sdr_tx_phase_ovr_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr_iq", { dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr_rc", { dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set, NULL }}, @@ -557,6 +565,42 @@ int dev_m2_lm7_1_lnb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return 0; } +int dev_m2_lm7_1_lnb_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue) +{ + *ovalue = ((struct dev_m2_lm7_1_gps *)ud)->xdev.lms7_lob; + return 0; +} + +int dev_m2_lm7_1_lms8_intmode_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + d->xdev.lms8_int_mode = value ? true : false; + return 0; +} + +int dev_m2_lm7_1_lms8_intmode_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue) +{ + *ovalue = ((struct dev_m2_lm7_1_gps *)ud)->xdev.lms8_int_mode; + return 0; +} + +int dev_m2_lm7_1_lms8_switchover_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + if (value < 1500e6 || value > 3800e6) { + return -ERANGE; + } + + d->xdev.lms8_switchover_freq = value; + return 0; +} + +int dev_m2_lm7_1_lms8_switchover_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue) +{ + *ovalue = ((struct dev_m2_lm7_1_gps *)ud)->xdev.lms8_switchover_freq; + return 0; +} + int dev_m2_lm7_1_debug_lms7002m_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 60879db1..7cdbc5ce 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1389,7 +1389,7 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, { int res = 0; - if (d->ssdr && freq > 3.0e9) { + if (d->ssdr && freq > d->lms8_switchover_freq) { float bwef = d->lms8st_bwef_1000 / 1000.0; unsigned lob = (d->lms7_lob == 0) ? 2.01e9 : d->lms7_lob; unsigned pwr_msk = @@ -1398,8 +1398,13 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, (d->base.rx_run[0] ? 1 << LMS8_RXA_CHIDX : 0) | (d->base.rx_run[1] ? 1 << LMS8_RXB_CHIDX : 0); - int64_t lms8_freq = (freq - lob + d->base.fref / 2) / d->base.fref; - lms8_freq *= d->base.fref; + int64_t lms8_freq; + if (d->lms8_int_mode) { + lms8_freq = (freq - lob + d->base.fref / 2) / d->base.fref; + lms8_freq *= d->base.fref; + } else { + lms8_freq = freq - lob; + } lob = freq - lms8_freq; if (d->lms8_lo_freq != lms8_freq) { @@ -1414,7 +1419,9 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXB_CHIDX, d->base.rx_run[1] ? 0 : ~0, d->base.rx_run[1] ? 0 : ~0); #endif if (!d->ssdr_pro) { - res = res ? res : lms8001_core_enable(&d->lms8, 0, 0, 1); + res = res ? res : lms8001_core_enable(&d->lms8, 1, 1, 1); + } else { + res = res ? res : lms8001_core_enable(&d->lms8, 0, 0, 0); } res = res ? res : lms8001_ch_enable(&d->lms8, pwr_msk); @@ -1513,6 +1520,9 @@ int xsdr_ctor(lldev_t dev, xsdr_dev_t *d) d->lms8st_int_mod = 0; d->lms8st_enabled = 1; + // Use integer mode for LMS8001 by default + d->lms8_int_mode = true; + d->lms8_switchover_freq = 3e9; return 0; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 8dd7c337..fd7f6463 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -56,10 +56,11 @@ struct xsdr_dev unsigned s_dacclk; unsigned s_flags; - int64_t lms8_lo_freq; unsigned lms7_lob; unsigned lms7_rxlo_last; unsigned lms7_txlo_last; + int64_t lms8_lo_freq; + unsigned lms8_switchover_freq; int tx_override_phase; int tx_override_phase_iq; @@ -82,6 +83,7 @@ struct xsdr_dev bool ssdr; bool ssdr_pro; bool lms8_alive; + bool lms8_int_mode; bool xilinx_usp; bool dpump; //Dual pump data From 8f396c41e223d9c75d4d12e78c8f96dc84987dd9 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 4 Mar 2026 20:53:17 +0400 Subject: [PATCH 354/397] ssdr: RXTSP reset --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 7cdbc5ce..836db84e 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -988,6 +988,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) // Sometimes TxTSP can get off by 1TSP clock, we need to preventevly reset the path res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); + res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_RXTSP); } } else { From 726f6cf651ac04de8dbb60debd9c5cf309cd7ead Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 6 Mar 2026 16:21:57 +0400 Subject: [PATCH 355/397] ssdr: unify R0/R2/R3 configuration for A/B MPW2015/2024 --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 58 +++++++++++++++++++++-------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 1 + 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 836db84e..2e8cf062 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1410,15 +1410,19 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, lob = freq - lms8_freq; if (d->lms8_lo_freq != lms8_freq) { res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); -#if 0 - res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 2, 0); - res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, 3, 0); -#else - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXA_CHIDX, d->base.tx_run[0] ? 0 : ~0, d->base.tx_run[0] ? 0 : ~0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXB_CHIDX, d->base.tx_run[1] ? 0 : ~0, d->base.tx_run[1] ? 0 : ~0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXA_CHIDX, d->base.rx_run[0] ? 0 : ~0, d->base.rx_run[0] ? 0 : ~0); - res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXB_CHIDX, d->base.rx_run[1] ? 0 : ~0, d->base.rx_run[1] ? 0 : ~0); -#endif + + if (d->lms8_mode_b) { + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, LMS8_TXA_CHIDX, d->base.tx_run[0] ? 0 : 0xf); + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, LMS8_TXB_CHIDX, d->base.tx_run[1] ? 0 : 0xf); + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, LMS8_RXA_CHIDX, d->base.rx_run[0] ? 0 : 0xf); + res = res ? res : lms8001b_hlmix_loss_set(&d->lms8, LMS8_RXB_CHIDX, d->base.rx_run[1] ? 0 : 0xf); + } else { + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXA_CHIDX, d->base.tx_run[0] ? 0 : ~0, d->base.tx_run[0] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_TXB_CHIDX, d->base.tx_run[1] ? 0 : ~0, d->base.tx_run[1] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXA_CHIDX, d->base.rx_run[0] ? 0 : ~0, d->base.rx_run[0] ? 0 : ~0); + res = res ? res : lms8001a_ch_lna_pa_set(&d->lms8, LMS8_RXB_CHIDX, d->base.rx_run[1] ? 0 : ~0, d->base.rx_run[1] ? 0 : ~0); + } + if (!d->ssdr_pro) { res = res ? res : lms8001_core_enable(&d->lms8, 1, 1, 1); } else { @@ -1530,6 +1534,7 @@ int xsdr_ctor(lldev_t dev, xsdr_dev_t *d) int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) { lldev_t dev = d->base.lmsstate.dev; + unsigned hwid_rev = (d->hwid >> 8) & 0xff; unsigned subdev = 0; int res = 0; bool pg = false; @@ -1597,6 +1602,10 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) if (res) return res; + if (getenv("USDR_BARE_DEV")) { + return 0; + } + uint16_t rev = 0xffff; res = lp8758_get_rev(dev, subdev, I2C_BUS_LP8758_FPGA, &rev); if (res) @@ -1652,12 +1661,31 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) if (hwid == SSDR_DEV || hwid == SSDRPRO_DEV) { uint32_t chipver = ~0; unsigned lms8_step = LMS8_MPW2024; + unsigned ssdr_rev; + + if (hwid == SSDR_DEV && hwid_rev == 0xff) { + lms8_step = LMS8_MPW2015; + d->lms8_mode_b = true; + ssdr_rev = 0; + } else if (hwid == SSDR_DEV && hwid_rev == 0x00) { + // This revision can be with A and B chips, need to set SSDR_LMS8B enviroment for B variant + ssdr_rev = 2; // Technically it's 1 but we use 2 in all documentation + } else { + ssdr_rev = 3; + } + + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "sSDR Rev%d\n", ssdr_rev); + + // Override chip settings if LMS8 was reworked to non-stadard if (getenv("LMS8_MPW2015")) { lms8_step = LMS8_MPW2015; } + if (getenv("SSDR_LMS8B")) { + d->lms8_mode_b = true; + } // Check LMS8 presence - res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x0); + res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x00); res = res ? res : dev_gpo_set(dev, IGPO_LDOLMS_EN, 1); // Enable LDOs res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 9); // LMS usleep(100000); @@ -1671,14 +1699,11 @@ int _xsdr_init_revx(xsdr_dev_t *d, unsigned hwid) res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x800000ff, &chipver); res = res ? res : lowlevel_spi_tr32(dev, d->base.lmsstate.subdev, 0, 0x000f0000, &chipver); - USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "LMS8001 version %08x\n", chipver); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "LMS8001 version %08x, assume chip is LMS8001%c-MPW%d\n", + chipver, d->lms8_mode_b ? 'B' : 'A', lms8_step == LMS8_MPW2015 ? 2015 : 2024); res = res ? res : lms8001_create(dev, d->base.lmsstate.subdev, 0, lms8_step, &d->lms8); - res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x80); - //res = res ? res : dev_gpo_set(dev, IGPO_LMS8_CTRL, 0x00); - // res = res ? res : dev_gpo_set(dev, IGPO_LDOLMS_EN, 0); // Enable LDOs - // res = res ? res : dev_gpo_set(dev, IGPO_LMS_PWR, 0); if (chipver != 0x00004040) { usleep(100000); @@ -2045,6 +2070,7 @@ int xsdr_init(xsdr_dev_t *d) d->dpump = false; d->ssdr_pro = false; d->xilinx_usp = false; + d->lms8_mode_b = false; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); if (res) { @@ -2095,7 +2121,7 @@ int xsdr_dtor(xsdr_dev_t *d) res = (res) ? res : lms7002m_destroy(&d->base.lmsstate); } - if (d->ssdr) { + if (d->ssdr && d->lms8.dev) { // Turn off LMS8 res = res ? res : dev_gpo_set(d->base.lmsstate.dev, IGPO_LMS8_CTRL, 0x81); res = res ? res : lms8001_core_enable(&d->lms8, 0, 0, 0); diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index fd7f6463..c8324c67 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -84,6 +84,7 @@ struct xsdr_dev bool ssdr_pro; bool lms8_alive; bool lms8_int_mode; + bool lms8_mode_b; bool xilinx_usp; bool dpump; //Dual pump data From 3fd6573c40a497e495b9ace1f9bcadc96ce9ab96 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 9 Mar 2026 02:51:53 +0400 Subject: [PATCH 356/397] lms7002: improve VCO calibaration by supporting dsicontinued ranges Normal VCO vs CAP function is monotonic, however at very few ranges it's possible to get discontinued range where comparator are: LLLOLLHHH LLLHOHHHH LLLOHOOOH LLOLOOOHH where L - Low, O - Ok, H - High --- src/lib/hw/lms7002m/lms7002m.c | 88 ++++++++++++++++++++++++++-------- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index 4ddcb91c..0940b566 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -218,10 +218,27 @@ int lms7002m_sxx_trim_vco(lms7002m_state_t* m, int vco_cap) GET_LMS7002M_SXX_0X0123_VCO_CMPLO(reg)); } +int lms7002m_sxx_trim_vco_slow(lms7002m_state_t* m, int vco_cap) +{ + uint16_t reg; + uint32_t cgen_regs[] = { MAKE_LMS7002M_SXX_0x0121(16, (unsigned)vco_cap, m->temp, 0) }; + int res = lms7002m_spi_post(m, cgen_regs, SIZEOF_ARRAY(cgen_regs)); + if (res) + return res; + + usleep(1000); + + res = lms7002m_spi_rd(m, SXX_0x0123, ®); + if (res) + return res; + + return (int)((GET_LMS7002M_SXX_0X0123_VCO_CMPHO(reg) << 1) | + GET_LMS7002M_SXX_0X0123_VCO_CMPLO(reg)); +} static int _lms7002m_vco_range(lms7002m_state_t* m, lms7002m_trim_vco_func_t f, unsigned start, uint8_t* phi, uint8_t* plo, - const char *name) + const char *name, unsigned extend_range) { int i; int lo = 0, hi = -1; @@ -248,28 +265,50 @@ static int _lms7002m_vco_range(lms7002m_state_t* m, lms7002m_trim_vco_func_t f, // Backup by one just to be sure we don't miss it lo = i; - i = i > 1 ? i - 1 : 0; + if (lo > 255) + lo = 255; + i = i - 1 - extend_range; + if (i < 0) + i = 0; } else { i = (int)start; } unsigned log_s = i; unsigned log_b = lo; + unsigned hi_cnt = 0; + unsigned r = 0; + + struct vco_ranges { + uint8_t lo; + uint8_t hi; + } ranges[4] = {{ 255, 0}, { 255, 0}, { 255, 0}, { 255, 0}}; + + for (; i < 256 && r < 4; i++) { + res = f(m, i); + if (res != LMS7002M_VCO_HIGH) { + hi_cnt = 0; + } - for (; i < 256; i++) { - switch ((res = f(m, i))) { + switch (res) { case LMS7002M_VCO_OK: - hi = i; - if (lo > i) - lo = i; + if (ranges[r].lo > i) + ranges[r].lo = i; + ranges[r].hi = i; break; case LMS7002M_VCO_HIGH: - if (hi == -1) { - hi = (i == 0) ? 0 : i - 1; + if (ranges[r].lo <= ranges[r].hi) { + r++; + } + if (hi_cnt > extend_range) { + goto find_high; } - goto find_high; + hi_cnt++; + break; case LMS7002M_VCO_LOW: - lo = i + 1; + if (ranges[r].lo <= ranges[r].hi) { + r++; + } break; case LMS7002M_VCO_FAIL: return -EIO; @@ -278,16 +317,23 @@ static int _lms7002m_vco_range(lms7002m_state_t* m, lms7002m_trim_vco_func_t f, } } -find_high: - if (hi == -1) - hi = 0; +find_high:; + int ldelta = -1; + int idx = -1; + for (unsigned p = 0; p < r; p++) { + int delta = ranges[p].hi - ranges[p].lo; + if (delta > ldelta) { + idx = p; + ldelta = delta; + } + } - USDR_LOG("7002", USDR_LOG_INFO, "%s binary result: %d; Probed range [%d .. %d] => Good range [%d; %d]", - name, log_b, log_s, i, lo, hi); + USDR_LOG("7002", USDR_LOG_INFO, "%s binary result: %d; Probed range [%d .. %d] => Good ranges %d: [%d; %d] / [%d; %d] / [%d; %d] / [%d; %d] took %d\n", + name, log_b, log_s, i, r, ranges[0].lo, ranges[0].hi, ranges[1].lo, ranges[1].hi, ranges[2].lo, ranges[2].hi, ranges[3].lo, ranges[3].hi, idx); - if (lo > 255) { - lo = 255; - } + + hi = (idx == -1) ? 0 : ranges[idx].hi; + lo = (idx == -1) ? 255 : ranges[idx].lo; *phi = (uint8_t)hi; *plo = (uint8_t)lo; @@ -546,7 +592,7 @@ int lms7002m_cgen_tune(lms7002m_state_t* m, unsigned fref, unsigned outfreq, uns usleep(20); uint8_t hi = 255, lo = 0; - res = _lms7002m_vco_range(m, &lms7002m_cgen_trim_vco, (unsigned)-1, &hi, &lo, "CGEN"); + res = _lms7002m_vco_range(m, &lms7002m_cgen_trim_vco, (unsigned)-1, &hi, &lo, "CGEN", 0); if (res < 0) return res; @@ -693,7 +739,7 @@ int lms7002m_sxx_tune(lms7002m_state_t* m, lms7002m_sxx_path_t path, unsigned fr return res; m->temp = vcono[i]; - res = _lms7002m_vco_range(m, &lms7002m_sxx_trim_vco, (unsigned)-1, &phi, &plo, sxxn); + res = _lms7002m_vco_range(m, t > 1 ? &lms7002m_sxx_trim_vco_slow : &lms7002m_sxx_trim_vco, (unsigned)-1, &phi, &plo, sxxn, 2 * t); if (res != 0) return res; From 8d1b1be7c0d9bf9f09557c4dd05ff5958d657795 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Wed, 11 Mar 2026 17:55:04 +0400 Subject: [PATCH 357/397] tools/python: add example for receiving samples via SoapySDR and plotting FFT --- src/soapysdr/usdr_soapy.cpp | 2 +- src/tools/python/example_fft_rx_soapy.py | 139 +++++++++++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 src/tools/python/example_fft_rx_soapy.py diff --git a/src/soapysdr/usdr_soapy.cpp b/src/soapysdr/usdr_soapy.cpp index ed05edff..17dce4dc 100644 --- a/src/soapysdr/usdr_soapy.cpp +++ b/src/soapysdr/usdr_soapy.cpp @@ -600,7 +600,7 @@ void SoapyUSDR::setFrequency(const int direction, const size_t channel, const st res = usdr_dme_set_uint(_dev->dev(), pname, type == RFIC_AFE79XX ? (uint64_t)frequency : val); if (res) - throw std::runtime_error(std::string("SoapyUSDR::setFrequency(") + pname + ", " + ")"); + throw std::runtime_error(std::string("SoapyUSDR::setFrequency(") + pname + ", " + std::to_string(frequency) + ")"); _actual_frequency[direction] = val; } diff --git a/src/tools/python/example_fft_rx_soapy.py b/src/tools/python/example_fft_rx_soapy.py new file mode 100644 index 00000000..04e2a100 --- /dev/null +++ b/src/tools/python/example_fft_rx_soapy.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +"""Receive IQ samples from USDR and plot accumulated FFT magnitude (using SoapySDR). + +Example: + python3 example_soapy_rx.py \ + --device "" \ + --rx-frequency 900e6 \ + --rx-bandwidth 1e6 \ + --rx-gain 80 \ + --samplerate 50e6 \ + --accumulation 16 \ + --fft-size 4096 \ + --window hann \ + --loglevel 3 +""" + +from __future__ import annotations + +import argparse +import numpy as np +from scipy import signal +import matplotlib.pyplot as plt + +import SoapySDR +from SoapySDR import SOAPY_SDR_RX + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="USDR RX FFT plotter") + parser.add_argument("--device", default="", help="USDR device string") + parser.add_argument("--samplerate", type=float, default=5e6, help="Sample rate in SPS") + parser.add_argument("--loglevel", type=int, default=None, help="Optional libusdr log level") + parser.add_argument("--rx-frequency", type=float, required=True, help="RX frequency in Hz") + parser.add_argument("--rx-bandwidth", type=float, required=True, help="RX bandwidth in Hz") + parser.add_argument("--rx-gain", type=float, default=15, help="RX gain value (mapped to LNA gain)") + + parser.add_argument("--fft-size", type=int, default=4096, help="FFT bin size") + parser.add_argument("--accumulation", type=int, default=16, help="Number of FFT frames to accumulate") + parser.add_argument("--window", default="hann", help="Scipy window name (e.g. hann, blackman, flattop)") + parser.add_argument("--channel", type=int, default=0, help="RX channel index") + parser.add_argument("--timeout-ms", type=int, default=1000, help="Receive timeout in milliseconds") + + return parser.parse_args() + +# Allocate a 64-byte-aligned buffer to avoid AVX512 alignment issues +def aligned_empty(shape, dtype, alignment=64): + dtype = np.dtype(dtype) + n_elems = int(np.prod(shape)) + nbytes = n_elems * dtype.itemsize + raw = np.empty(nbytes + alignment, dtype=np.uint8) + start = raw.ctypes.data + offset = (-start) % alignment + buf = raw[offset:offset + nbytes].view(dtype) + return buf.reshape(shape) + + +def main() -> None: + args = parse_args() + + if args.fft_size <= 0: + raise ValueError("--fft-size must be > 0") + if args.accumulation <= 0: + raise ValueError("--accumulation must be > 0") + + fft_size = int(args.fft_size) + window = signal.get_window(args.window, fft_size, fftbins=True).astype(np.float32) + + # Open SoapySDR device + if args.device: + dev_kwargs = SoapySDR.KwargsFromString(args.device) + else: + dev_kwargs = SoapySDR.SoapySDRKwargs() + if args.loglevel is not None: + dev_kwargs["loglevel"] = str(int(args.loglevel)) + try: + dev = SoapySDR.Device(dev_kwargs) + except Exception as e: + print(f"Failed to open SoapySDR device: {e}") + exit(1) + + chan = int(args.channel) + + # Configure device + dev.setSampleRate(SOAPY_SDR_RX, chan, float(args.samplerate)) + dev.setFrequency(SOAPY_SDR_RX, chan, float(args.rx_frequency)) + dev.setBandwidth(SOAPY_SDR_RX, chan, float(args.rx_bandwidth)) + dev.setGain(SOAPY_SDR_RX, chan, float(args.rx_gain)) + + # Setup stream for complex float32 (direction, format, channels, args) + args_kw = SoapySDR.SoapySDRKwargs() + args_kw["linkFormat"] = "CS16" # Request int16 samples from driver also can be "CS12" + args_kw["bufferLength"] = str(int(fft_size)) + rx_stream = dev.setupStream(SOAPY_SDR_RX, "CF32", [chan], args_kw) + dev.activateStream(rx_stream) + + psd_acc = np.zeros(fft_size, dtype=np.float64) + + timeout_us = int(args.timeout_ms * 1000) + + # Receive and accumulate FFT frames + for _ in range(int(args.accumulation)): + buf = aligned_empty((fft_size,), np.complex64, alignment=64) + + res = dev.readStream(rx_stream, [buf], int(fft_size), timeoutUs=timeout_us) + + n = res.ret + if n < fft_size: + raise RuntimeError(f"Received {n} samples, expected at least {fft_size}") + + x = buf[:fft_size] * window + spec = np.fft.fftshift(np.fft.fft(x, n=fft_size)) + psd_acc += np.abs(spec) ** 2 + + # Close stream + dev.deactivateStream(rx_stream) + dev.closeStream(rx_stream) + + # Close device + dev.close() # Not strictly necessary, but good practice + dev = None + + psd = psd_acc / args.accumulation + psd_db = 10.0 * np.log10(psd + 1e-20) + + fs = float(args.samplerate) + f_axis = np.fft.fftshift(np.fft.fftfreq(fft_size, d=1.0 / fs)) + + plt.figure(figsize=(10, 5)) + plt.plot(f_axis / 1e6, psd_db) + plt.title("USDR RX FFT (SoapySDR)") + plt.xlabel("Frequency offset (MHz)") + plt.ylabel("Power (dB, arbitrary)") + plt.grid(True, alpha=0.3) + plt.tight_layout() + plt.show() + + +if __name__ == "__main__": + main() From 8143ff574134b288af380ea666a995f0adc67479 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Wed, 11 Mar 2026 19:45:41 +0400 Subject: [PATCH 358/397] tools/python: fix description --- src/tools/python/example_fft_rx_soapy.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/tools/python/example_fft_rx_soapy.py diff --git a/src/tools/python/example_fft_rx_soapy.py b/src/tools/python/example_fft_rx_soapy.py old mode 100644 new mode 100755 index 04e2a100..682d0215 --- a/src/tools/python/example_fft_rx_soapy.py +++ b/src/tools/python/example_fft_rx_soapy.py @@ -3,7 +3,7 @@ Example: python3 example_soapy_rx.py \ - --device "" \ + --device "driver=usdr" \ --rx-frequency 900e6 \ --rx-bandwidth 1e6 \ --rx-gain 80 \ @@ -12,6 +12,11 @@ --fft-size 4096 \ --window hann \ --loglevel 3 + + Parameter `device` can be any SoapySDR device string, e.g. "driver=usdr" or "driver=usdr,bus=" + device_bus can be: + - bus=pci,device=, where is the PCI device Path (e.g. /dev/usdr0) + - bus=usb@, where is the USB address (e.g. 3/3/6 for bus 3, device 3, function 6) """ from __future__ import annotations From cb00e41b42a48cddb94596ef73ce892a5ae73970 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 15 Mar 2026 13:45:52 +0300 Subject: [PATCH 359/397] chirp generator - implementation (generic & SIMD) + dm_create option --- src/lib/xdsp/conv.h | 17 ++ src/lib/xdsp/sincos_functions.c | 32 ++++ src/lib/xdsp/sincos_functions.h | 13 ++ ...t_sincos_i16_interleaved_chirp_generic.inc | 22 +++ ...vlt_sincos_i16_interleaved_chirp_generic.t | 29 ++++ .../wvlt_sincos_i16_interleaved_chirp_ssse3.t | 114 ++++++++++++++ src/lib/xdsp/utests/wvlt_sincos_i16_utest.c | 145 +++++++++++++++++- src/tools/usdr_dm_create.c | 132 +++++++++++++++- 8 files changed, 501 insertions(+), 3 deletions(-) create mode 100644 src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.inc create mode 100644 src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.t create mode 100644 src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_ssse3.t diff --git a/src/lib/xdsp/conv.h b/src/lib/xdsp/conv.h index 656649e6..e25e2c7d 100644 --- a/src/lib/xdsp/conv.h +++ b/src/lib/xdsp/conv.h @@ -119,6 +119,23 @@ void tr_##conv_fn (int32_t *__restrict start_phase, \ unsigned iters) \ { conv_fn(start_phase, delta_phase, gain, inv_sin, inv_cos, outdata, iters); } +typedef void (*sincos_i16_interleaved_chirp_function_t)(int32_t *__restrict start_phase, int32_t *__restrict start_delta_phase, + int32_t *__restrict delta_phase, int32_t chip_steps, int16_t gain, bool inv_sin, bool inv_cos, + int16_t *__restrict outdata, + unsigned iters); + +#define DECLARE_TR_FUNC_SINCOS_I16_INTERLEAVED_CHIRP(conv_fn) \ +void tr_##conv_fn (int32_t *__restrict start_phase, \ + int32_t *__restrict start_delta_phase, \ + int32_t *__restrict delta_phase, \ + int32_t chip_steps, \ + int16_t gain, \ + bool inv_sin, \ + bool inv_cos, \ + int16_t *__restrict outdata, \ + unsigned iters) \ +{ conv_fn(start_phase, start_delta_phase, delta_phase, chip_steps, gain, inv_sin, inv_cos, outdata, iters); } + struct transform_info { conv_function_t cfunc; diff --git a/src/lib/xdsp/sincos_functions.c b/src/lib/xdsp/sincos_functions.c index 5dddb90f..0af23f56 100644 --- a/src/lib/xdsp/sincos_functions.c +++ b/src/lib/xdsp/sincos_functions.c @@ -83,3 +83,35 @@ sincos_i16_interleaved_ctrl_function_t get_wvlt_sincos_i16_interleaved_ctrl() { return get_wvlt_sincos_i16_interleaved_ctrl_c(cpu_vcap_get(), NULL); } + + +#define TEMPLATE_FUNC_NAME wvlt_sincos_i16_interleaved_chirp_generic +VWLT_ATTRIBUTE(optimize("-O3", "inline")) +#include "templates/wvlt_sincos_i16_interleaved_chirp_generic.t" +DECLARE_TR_FUNC_SINCOS_I16_INTERLEAVED_CHIRP(wvlt_sincos_i16_interleaved_chirp_generic) + +#ifdef WVLT_SSSE3 +#define TEMPLATE_FUNC_NAME wvlt_sincos_i16_interleaved_chirp_ssse3 +VWLT_ATTRIBUTE(optimize("-O3", "inline"), target("ssse3")) +#include "templates/wvlt_sincos_i16_interleaved_chirp_ssse3.t" +DECLARE_TR_FUNC_SINCOS_I16_INTERLEAVED_CHIRP(wvlt_sincos_i16_interleaved_chirp_ssse3) +#endif + +sincos_i16_interleaved_chirp_function_t get_wvlt_sincos_i16_interleaved_chirp_c(generic_opts_t cpu_cap, const char** sfunc) +{ + const char* fname; + sincos_i16_interleaved_chirp_function_t fn; + + SELECT_GENERIC_FN(fn, fname, tr_wvlt_sincos_i16_interleaved_chirp_generic, cpu_cap); + SELECT_SSSE3_FN(fn, fname, tr_wvlt_sincos_i16_interleaved_chirp_ssse3, cpu_cap); + //SELECT_AVX2_FN(fn, fname, tr_wvlt_sincos_i16_interleaved_ctrl_avx2, cpu_cap); + //SELECT_NEON_FN(fn, fname, tr_wvlt_sincos_i16_interleaved_ctrl_neon, cpu_cap); + + if (sfunc) *sfunc = fname; + return fn; +} + +sincos_i16_interleaved_chirp_function_t get_wvlt_sincos_i16_interleaved_chirp() +{ + return get_wvlt_sincos_i16_interleaved_chirp_c(cpu_vcap_get(), NULL); +} diff --git a/src/lib/xdsp/sincos_functions.h b/src/lib/xdsp/sincos_functions.h index 4fb4a261..f515fbaf 100644 --- a/src/lib/xdsp/sincos_functions.h +++ b/src/lib/xdsp/sincos_functions.h @@ -52,4 +52,17 @@ static inline return (*get_wvlt_sincos_i16_interleaved_ctrl())(start_phase, delta_phase, gain, inv_sin, inv_cos, outdata, iters); } + +sincos_i16_interleaved_chirp_function_t get_wvlt_sincos_i16_interleaved_chirp_c(generic_opts_t cpu_cap, const char** sfunc); +sincos_i16_interleaved_chirp_function_t get_wvlt_sincos_i16_interleaved_chirp(); +static inline +void wvlt_sincos_i16_interleaved_chirp(int32_t* start_phase, int32_t* start_delta_phase, int32_t* delta_phase, + int32_t chirp_steps, int16_t gain, + bool inv_sin, bool inv_cos, + int16_t* outdata, + unsigned iters) +{ + return (*get_wvlt_sincos_i16_interleaved_chirp())(start_phase, start_delta_phase, delta_phase, chirp_steps, gain, inv_sin, inv_cos, outdata, iters); +} + #endif // SINCOS_FUNCTIONS_H diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.inc b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.inc new file mode 100644 index 00000000..c6db5895 --- /dev/null +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.inc @@ -0,0 +1,22 @@ + while(i > 0) + { + phase += dphase; + const float ph = WVLT_SINCOS_I32_PHSCALE * phase; + float ssin, scos; + + sincosf(ph, &ssin, &scos); + *outdata++ = ssin * gain * sign_sin; + *outdata++ = scos * gain * sign_cos; + + dphase += chirp_step; + if(dphase > delta_phase1) + { + dphase = delta_phase0; + } + else if(dphase < delta_phase0) + { + dphase = delta_phase1; + } + + --i; + } diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.t b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.t new file mode 100644 index 00000000..4a612736 --- /dev/null +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_generic.t @@ -0,0 +1,29 @@ +static +void TEMPLATE_FUNC_NAME(int32_t *__restrict start_phase, int32_t *__restrict start_delta_phase, + int32_t *__restrict delta_phase, + int32_t chirp_steps_cnt, + int16_t gain, + bool inv_sin, + bool inv_cos, + int16_t *__restrict outdata, + unsigned iters) +{ + unsigned i = iters; + + int32_t phase = *start_phase; + int32_t delta_phase0 = delta_phase[0]; + int32_t delta_phase1 = delta_phase[1]; + + const int16_t sign_sin = inv_sin ? -1 : 1; + const int16_t sign_cos = inv_cos ? -1 : 1; + + const int32_t chirp_step = ((int64_t)delta_phase1 - (int64_t)delta_phase0) / chirp_steps_cnt; + int32_t dphase = *start_delta_phase; + + #include "wvlt_sincos_i16_interleaved_chirp_generic.inc" + + *start_phase = phase; + *start_delta_phase = dphase; +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_ssse3.t b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_ssse3.t new file mode 100644 index 00000000..d32b6459 --- /dev/null +++ b/src/lib/xdsp/templates/wvlt_sincos_i16_interleaved_chirp_ssse3.t @@ -0,0 +1,114 @@ +#include + +static +void TEMPLATE_FUNC_NAME(int32_t *__restrict start_phase, int32_t *__restrict start_delta_phase, + int32_t *__restrict delta_phase, + int32_t chirp_steps_cnt, + int16_t gain, + bool inv_sin, + bool inv_cos, + int16_t *__restrict outdata, + unsigned iters) +{ + unsigned i = iters; + + int32_t phase = *start_phase; + int32_t delta_phase0 = delta_phase[0]; + int32_t delta_phase1 = delta_phase[1]; + + const int16_t sign_sin = inv_sin ? -1 : 1; + const int16_t sign_cos = inv_cos ? -1 : 1; + + const int32_t chirp_step = ((int64_t)delta_phase1 - (int64_t)delta_phase0) / chirp_steps_cnt; + int32_t dphase = *start_delta_phase; + + const __m128i vsign_sin = _mm_set1_epi16(sign_sin); + const __m128i vsign_cos = _mm_set1_epi16(sign_cos); + + const __m128i vchirps0 = _mm_set_epi32(3 * chirp_step, 2 * chirp_step, 1 * chirp_step, 0 * chirp_step); + const __m128i vchirps1 = _mm_set_epi32(7 * chirp_step, 6 * chirp_step, 5 * chirp_step, 4 * chirp_step); + + const __m128i ph_lo_mask = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 13, 12, 9, 8, 5, 4, 1, 0); + const __m128i ph_hi_mask = _mm_set_epi8(29, 28, 25, 24, 21, 20, 17, 16, -1, -1, -1, -1, -1, -1, -1, -1); + + const __m128i mpi_2v = _mm_set1_epi32(-32768); + const __m128i pi_2v = _mm_set1_epi32( 32767); + const __m128i onev = _mm_set1_epi16(1); + const __m128i gainv = _mm_set1_epi16(gain); + + #include "wvlt_sincos_i16_ssse3.inc" + + while(i >= 8) + { + // add delta + + const __m128i vdelta_phase = _mm_set1_epi32(dphase); + + __m128i delta_ph0 = _mm_add_epi32(vchirps0, vdelta_phase); + delta_ph0 = _mm_add_epi32(delta_ph0, _mm_slli_si128(delta_ph0, 4)); + delta_ph0 = _mm_add_epi32(delta_ph0, _mm_slli_si128(delta_ph0, 8)); + + __m128i vphase0 = _mm_set1_epi32(phase); + vphase0 = _mm_add_epi32(vphase0, delta_ph0); + phase = _mm_extract_epi32(vphase0, 3); + + __m128i delta_ph1 = _mm_add_epi32(vchirps1, vdelta_phase); + delta_ph1 = _mm_add_epi32(delta_ph1, _mm_slli_si128(delta_ph1, 4)); + delta_ph1 = _mm_add_epi32(delta_ph1, _mm_slli_si128(delta_ph1, 8)); + + __m128i vphase1 = _mm_set1_epi32(phase); + vphase1 = _mm_add_epi32(vphase1, delta_ph1); + phase = _mm_extract_epi32(vphase1, 3); + + dphase += 8 * chirp_step; + if(dphase > delta_phase1) + dphase = delta_phase0; + else if(dphase < delta_phase0) + dphase = delta_phase1; + + + // _signed_ right shift to get hi word + // 15 bits because input I32 range is [-PI; +PI), but WVLT_SINCOS I16 input range is [-PI/2; +PI/2) + __m128i ph0 = _mm_srai_epi32(vphase0, 15); + __m128i ph1 = _mm_srai_epi32(vphase1, 15); + + // INT32 input ranges < INT16_MIN and > INT16_MAX should be inverted + __m128i rflag0 = _mm_or_si128(_mm_cmpgt_epi32(ph0, pi_2v), _mm_cmplt_epi32(ph0, mpi_2v)); + __m128i rflag1 = _mm_or_si128(_mm_cmpgt_epi32(ph1, pi_2v), _mm_cmplt_epi32(ph1, mpi_2v)); + __m128i sign = _mm_or_si128(_mm_shuffle_epi8(rflag0, ph_lo_mask), _mm_shuffle_epi8(rflag1, ph_hi_mask)); + + // normalize sign from (-1;0) to (-1;+1) : x*2 + 1 + sign = _mm_add_epi16(_mm_slli_epi16(sign, 1), onev); + + // pack phase low int16 words (already shifted >> 15) + __m128i reg_phase = _mm_or_si128(_mm_shuffle_epi8(ph0, ph_lo_mask), _mm_shuffle_epi8(ph1, ph_hi_mask)); + __m128i reg_sin, reg_cos; + WVLT_SINCOS(reg_phase, reg_sin, reg_cos); + + // apply sign - internal & external + reg_sin = _mm_sign_epi16(reg_sin, sign); + reg_cos = _mm_sign_epi16(reg_cos, sign); + reg_sin = _mm_sign_epi16(reg_sin, vsign_sin); + reg_cos = _mm_sign_epi16(reg_cos, vsign_cos); + + //apply amplitude normalization + reg_sin = _mm_mulhrs_epi16(reg_sin, gainv); + reg_cos = _mm_mulhrs_epi16(reg_cos, gainv); + + // interleave & store + _mm_storeu_si128((__m128i*)(outdata + 0), _mm_unpacklo_epi16(reg_sin, reg_cos)); + _mm_storeu_si128((__m128i*)(outdata + 8), _mm_unpackhi_epi16(reg_sin, reg_cos)); + + outdata += 16; + i -= 8; + } + + #undef WVLT_SINCOS + + #include "wvlt_sincos_i16_interleaved_chirp_generic.inc" + + *start_phase = phase; + *start_delta_phase = dphase; +} + +#undef TEMPLATE_FUNC_NAME diff --git a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c index a9c83ce4..f624930c 100644 --- a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c +++ b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c @@ -41,6 +41,15 @@ static int16_t gain[SPEED_CYCLES]; static const char* last_fn_name = NULL; static generic_opts_t max_opt = OPT_GENERIC; +struct chirp_t +{ + int32_t phase_diap[2]; + int32_t start_dphase; + int32_t steps_count; +}; + +static struct chirp_t chirp = { {-1000000, 1000000}, -1000000, (100000 / 8) * 8 + 7}; + static void setup() { int res = 0; @@ -120,6 +129,23 @@ static sincos_i16_interleaved_ctrl_function_t get_fn_interleaved(generic_opts_t return fn; } +static sincos_i16_interleaved_chirp_function_t get_fn_interleaved_chirp(generic_opts_t o, int log) +{ + const char* fn_name = NULL; + sincos_i16_interleaved_chirp_function_t fn = get_wvlt_sincos_i16_interleaved_chirp_c(o, &fn_name); + + //ignore dups + if(last_fn_name && !strcmp(last_fn_name, fn_name)) + return NULL; + + if(log) + fprintf(stderr, "%-20s\t", fn_name); + + last_fn_name = fn_name; + return fn; +} + + static int32_t is_equal() { for(unsigned i = 0; i < WORD_COUNT; i++) @@ -329,17 +355,134 @@ START_TEST(wvlt_sincos_i16_speed) END_TEST +// CHIRP +START_TEST(wvlt_sincos_i16_interleaved_chirp_check_simd) +{ + generic_opts_t opt = max_opt; + sincos_i16_interleaved_chirp_function_t fn = NULL; + last_fn_name = NULL; + + fprintf(stderr,"\n**** Check SIMD implementations ***\n"); + + int32_t ph_etalon = start_phase[0]; + int32_t phdelta_etalon = chirp.start_dphase; + + const int32_t delta_ph = delta_phase[0]; + const bool inv_sin = invert_sin[0]; + const bool inv_cos = invert_cos[0]; + const int16_t gain_c = gain[0]; + + //get etalon output data (generic foo) + (*get_fn_interleaved_chirp(OPT_GENERIC, 0)) + (&ph_etalon, &phdelta_etalon, chirp.phase_diap, chirp.steps_count, gain_c, inv_sin, inv_cos, sincosdata_etalon, WORD_COUNT); + + fprintf(stderr, "-- start_phase:%d delta_phase:%d final_phase:%d\n", start_phase[0], delta_ph, ph_etalon); + + + while(opt != OPT_GENERIC) + { + sincos_i16_interleaved_chirp_function_t fn = get_fn_interleaved_chirp(opt--, 1); + if(fn) + { + memset(sincosdata, 0, WORD_COUNT * 2 * sizeof(int16_t)); + int32_t ph = start_phase[0]; + int32_t phdelta = chirp.start_dphase; + + (*fn)(&ph, &phdelta, chirp.phase_diap, chirp.steps_count, gain_c, inv_sin, inv_cos, sincosdata, WORD_COUNT); + + int32_t tmp_ph = start_phase[0]; + int32_t max_eps = 0; + for(unsigned i = 0; i < WORD_COUNT; ++i, tmp_ph += delta_ph) + { + int16_t ss = sincosdata[i*2]; + int16_t cc = sincosdata[i*2 + 1]; + int16_t sse = sincosdata_etalon[i*2]; + int16_t cce = sincosdata_etalon[i*2 + 1]; +#ifdef DEBUG_PRINT + fprintf(stderr, "i#%d : phase:%12d, out{sin:%6d cos:%6d}, etalon{sin:%6d cos:%6d}, delta = {%4d %4d}\n", + i, tmp_ph, ss, cc, sse, cce, abs(ss-sse), abs(cc-cce)); +#endif + if(abs(ss-sse) > max_eps) + max_eps = abs(ss-sse); + if(abs(cc-cce) > max_eps) + max_eps = abs(cc-cce); + } + fprintf(stderr, "-- final_phase:%d (est:%d) max_eps:%d\n", ph, tmp_ph, max_eps); + + int res = is_equal_interleaved(); + res >= 0 ? fprintf(stderr,"\tFAILED!\n") : fprintf(stderr,"\tOK!\n"); + + for(int i = res - 20; res >= 0 && i <= res + 20; ++i) + { + if(i >= 0 && i < WORD_COUNT) + fprintf(stderr, "%si#%d : in = %d, out = {sin:%d cos:%d}, etalon = {sin:%d cos:%d}, delta = {%d %d}\n", + i == res ? ">>>" : " ", + i, in_check[i], sincosdata[i*2], sincosdata[i*2 + 1], sincosdata_etalon[i*2], sincosdata_etalon[i*2 + 1], + abs(sincosdata_etalon[i*2] - sincosdata[i*2]), abs(sincosdata_etalon[i*2 + 1] - sincosdata[i*2 + 1])); + } + + ck_assert_int_eq( res, -1 ); + ck_assert_int_eq( ph, ph_etalon ); + } + } +} +END_TEST + + +START_TEST(wvlt_sincos_i16_interleaved_chirp_speed) +{ + generic_opts_t opt = max_opt; + sincos_i16_interleaved_chirp_function_t fn = NULL; + last_fn_name = NULL; + + const unsigned iters = packet_lens[_i]; + + + fprintf(stderr, "\n**** Compare SIMD implementations speed ***\n"); + fprintf(stderr, "**** packet: %d IQs, cycles: %u ***\n", iters, SPEED_CYCLES); + + while(opt != OPT_GENERIC) + { + sincos_i16_interleaved_chirp_function_t fn = get_fn_interleaved_chirp(opt--, 1); + if(fn) + { + int32_t ph = start_phase[0]; + int32_t phdelta = chirp.start_dphase; + //warming + for(int i = 0; i < 10; ++i) + (*fn)(&ph, &phdelta, chirp.phase_diap, chirp.steps_count, gain[0], invert_sin[0], invert_cos[0], sincosdata, SPEED_WORD_COUNT); + + //measuring + phdelta = chirp.start_dphase; + uint64_t tk = clock_get_time(); + for(unsigned i = 0; i < SPEED_CYCLES; ++i) + { + (*fn) + (&start_phase[i], &phdelta, chirp.phase_diap, chirp.steps_count, gain[i], invert_sin[i], invert_cos[i], sincosdata, iters); + } + uint64_t tk1 = clock_get_time() - tk; + fprintf(stderr, "\t%" PRIu64 " us elapsed, %" PRIu64 " ns per 1 IQ, ave speed = %.2f mln IQs/s \n", + tk1, (uint64_t)(tk1*1000LL/SPEED_CYCLES/iters), (uint64_t)(1000000LL*SPEED_CYCLES*iters/tk1)/(float)1000000); + } + } +} +END_TEST +// + Suite * wvlt_sincos_i16_suite(void) { max_opt = cpu_vcap_get(); Suite* s = suite_create("wvlt_sincos_i16"); - +/* ADD_REGRESS_TEST(s, wvlt_sincos_i16_check_simd); ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_speed, 60, 0, 3); ADD_REGRESS_TEST(s, wvlt_sincos_i16_interleaved_ctrl_check_simd); ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_interleaved_ctrl_speed, 60, 0, 3); +*/ + ADD_REGRESS_TEST(s, wvlt_sincos_i16_interleaved_chirp_check_simd); + ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_interleaved_chirp_speed, 60, 0, 3); return s; } diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index 28ea2633..5733530b 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -68,6 +68,10 @@ struct tx_thread_input_s float gain; double start_phase; double delta_phase; + + //chirp_gen params + double chirp_freq0, chirp_freq1; + int32_t chirp_steps; }; typedef struct tx_thread_input_s tx_thread_input_t; @@ -239,12 +243,65 @@ void* freq_gen_thread_ci16_lut(void* obj) #define USE_WVLT_SINCOS #define MAX_TXGEN_CI16_AMPL 32760 +static void* chirp_gen_thread_ci16(void* obj) +{ +#ifndef USE_WVLT_SINCOS + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Not implemented"); + return NULL; +#endif + + tx_thread_input_t* inp = (tx_thread_input_t*)obj; + + const unsigned p = inp->chan; + const unsigned tx_get_samples = inp->samples_count; + const int16_t gain = DBFS_TO_AMPLITUDE(inp->gain, MAX_TXGEN_CI16_AMPL); + + const bool upchirp = inp->chirp_steps > 0; + USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "Using TX ci16 CHIRP sinus generator with USE_WVLT_SINCOS opt @ ch#%d F1:%.6f MHz F2:%.6f MHz GAIN:(%.2fdBFS = %d)", + p, inp->chirp_freq0 / 1000000.f, inp->chirp_freq1 / 1000000.f, inp->gain, gain); + USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "CHIRP steps count: %d [%s]", inp->chirp_steps, (upchirp ? "UP_CHIRP":"DOWN_CHIRP")); + USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "CHIRP period: %.6f s (having sr:%u Ms)", (double)inp->chirp_steps / (double)inp->samplerate, inp->samplerate / 1000000); + + int32_t phase = WVLT_CONVPHASE_F32_I32(inp->start_phase); + + const int32_t dp0 = WVLT_CONVPHASE_F32_I32(inp->chirp_freq0 / inp->samplerate); + const int32_t dp1 = WVLT_CONVPHASE_F32_I32(inp->chirp_freq1 / inp->samplerate); + int32_t delta_phase_arr[] = { dp0, dp1 }; + int32_t delta_phase = inp->chirp_steps >= 0 ? dp0 : dp1; + + while (!s_stop && !thread_stop) + { + unsigned idx = ring_buffer_pwait(tbuff[p], 100000); + if (idx == IDX_TIMEDOUT) + continue; + + char* data = ring_buffer_at(tbuff[p], idx); + + tx_header_t* hdr = (tx_header_t*)data; + hdr->len = tx_get_samples * sizeof(uint16_t) * 2; + hdr->flags = TXF_NONE; + + int16_t *iqp = (int16_t *)(data + sizeof(tx_header_t)); + + wvlt_sincos_i16_interleaved_chirp(&phase, &delta_phase, delta_phase_arr, inp->chirp_steps, + gain, true/*invert sin*/, false/*invert cos*/, iqp, tx_get_samples); + ring_buffer_ppost(tbuff[p]); + } + + return NULL; +} + /* * Thread function - Sine generator to TX stream (ci16) */ void* freq_gen_thread_ci16(void* obj) { tx_thread_input_t* inp = (tx_thread_input_t*)obj; + if(inp->chirp_steps) + { + return chirp_gen_thread_ci16(obj); + } + const unsigned p = inp->chan; const unsigned tx_get_samples = inp->samples_count; const int16_t gain = DBFS_TO_AMPLITUDE(inp->gain, MAX_TXGEN_CI16_AMPL); @@ -423,6 +480,8 @@ static void usage(int severity, const char* me) "\t[-l loglevel [3(INFO)]] \n" "\t[-G calibration [algo#]] \n" "\t[-Z param1=value1,param2=value2,...] \n" + "\t[-m ] \n" + "\t[-M comma-separated list of CHIRP generator params (each channel specified as ::)] \n" "\t[-h ]", me); } @@ -642,6 +701,7 @@ int main(UNUSED int argc, UNUSED char** argv) param_list_t extra_params[32]; unsigned extra_param_len = 0; int tx_pkt_precharge = 16; + bool use_chirp_gen = false; memset(rx_thread_inputs, 0, sizeof(rx_thread_inputs)); memset(tx_thread_inputs, 0, sizeof(tx_thread_inputs)); @@ -651,6 +711,9 @@ int main(UNUSED int argc, UNUSED char** argv) inp->start_phase = -10; inp->delta_phase = -10; inp->gain = INT16_MIN; + inp->chirp_freq0 = 0.f; + inp->chirp_freq1 = 0.f; + inp->chirp_steps = 0; } channel_info_init(&chl_rx); @@ -683,8 +746,8 @@ int main(UNUSED int argc, UNUSED char** argv) //set colored log output usdrlog_enablecolorize(NULL); - // Still available: kmMvVL - while ((opt = getopt(argc, argv, "b:B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:K:")) != -1) { + // Still available: kvVL + while ((opt = getopt(argc, argv, "b:B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:K:mM:")) != -1) { switch (opt) { //Time-division duplexing (TDD) frequency case 'q': dev_data[DD_TDD_FREQ].value = atof(optarg); dev_data[DD_TDD_FREQ].ignore = false; break; @@ -909,6 +972,42 @@ int main(UNUSED int argc, UNUSED char** argv) case 'Z': extra_param_len = parse_param_list(optarg, SIZEOF_ARRAY(extra_params), extra_params); break; + case 'm': + use_chirp_gen = true; + break; + case 'M': + { + char* pt_end; + char *pt = strtok_r(optarg, ",", &pt_end); + unsigned i = 0; + + while(pt && i < MAX_CHS) + { + char *chirp_pt_end; + char *chirp_pt = strtok_r(pt, ":", &chirp_pt_end); + if(!chirp_pt) + exit(EXIT_FAILURE); + else + tx_thread_inputs[i].chirp_steps = atoi(chirp_pt); + + chirp_pt = strtok_r(NULL, ":", &chirp_pt_end); + if(!chirp_pt) + exit(EXIT_FAILURE); + else + tx_thread_inputs[i].chirp_freq0 = atof(chirp_pt); + + chirp_pt = strtok_r(NULL, ":", &chirp_pt_end); + if(!chirp_pt) + exit(EXIT_FAILURE); + else + tx_thread_inputs[i].chirp_freq1 = atof(chirp_pt); + + ++i; + pt = strtok_r(NULL, ",", &pt_end); + } + + break; + } //Show usage case 'h': usdrlog_disablecolorize(NULL); @@ -1117,6 +1216,9 @@ int main(UNUSED int argc, UNUSED char** argv) static double start_phase[] = { 0, 0.5, 0.25, 0.125 }; static double start_dphase[] = { 0.3333333333333333333333333, 0.02, 0.03, 0.04 }; static int16_t gains[] = {0.0, 0.0, 0.0, 0.0}; + static int32_t chirp_steps[] = { -100007, 100007, -1000007, 1000007 }; + static int32_t chirp_freq0[] = { -333333, -666666, -1E6, -10E6 }; + static int32_t chirp_freq1[] = { 333333, 666666, 1E6, 10E6 }; for(unsigned i = 0; i < tx_bufcnt; ++i) { tx_thread_input_t* inp = &tx_thread_inputs[i]; @@ -1126,6 +1228,13 @@ int main(UNUSED int argc, UNUSED char** argv) inp->start_phase = inp->start_phase > -1 ? inp->start_phase : start_phase[i % (sizeof(start_phase) / sizeof(*start_phase))]; inp->delta_phase = inp->delta_phase > -1 ? inp->delta_phase : start_dphase[i % (sizeof(start_dphase) / sizeof(*start_dphase))]; inp->gain = inp->gain != INT16_MIN ? inp->gain : gains[i % (sizeof(gains) / sizeof(*gains))]; + + if(use_chirp_gen) + { + inp->chirp_steps = inp->chirp_steps ? inp->chirp_steps : chirp_steps[i % (sizeof(chirp_steps) / sizeof(*chirp_steps))]; + inp->chirp_freq0 = (inp->chirp_freq0 != 0.f) ? inp->chirp_freq0 : chirp_freq0[i % (sizeof(chirp_freq0) / sizeof(*chirp_freq0))]; + inp->chirp_freq1 = (inp->chirp_freq1 != 0.f) ? inp->chirp_freq1 : chirp_freq1[i % (sizeof(chirp_freq1) / sizeof(*chirp_freq1))]; + } } for(unsigned i = 0; i < MAX_CHS; ++i) { @@ -1133,6 +1242,25 @@ int main(UNUSED int argc, UNUSED char** argv) i, tx_thread_inputs[i].start_phase, tx_thread_inputs[i].delta_phase); } + for(unsigned i = 0; i < tx_bufcnt && use_chirp_gen; ++i) { + USDR_LOG(LOG_TAG, USDR_LOG_DEBUG, "TX CHIRP_GEN CH#%2d FROM_FREQ:%.4f TO_FREQ:%.4f STEPS:%d", + i, tx_thread_inputs[i].chirp_freq0, tx_thread_inputs[i].chirp_freq1, tx_thread_inputs[i].chirp_steps); + + if(tx_thread_inputs[i].chirp_freq0 >= tx_thread_inputs[i].chirp_freq1) + { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "CH#%2d CHIRP params error: freq0 >= freq1 [%.2f >= %.2f]", + i, tx_thread_inputs[i].chirp_freq0, tx_thread_inputs[i].chirp_freq1); + goto dev_close; + } + + if(abs(tx_thread_inputs[i].chirp_steps % 8) != 7) + { + USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "CH#%2d CHIRP steps count[%d]: recommended condition - step %% 8 = 7(-1)", + i, tx_thread_inputs[i].chirp_steps); + tx_thread_inputs[i].chirp_steps = (tx_thread_inputs[i].chirp_steps / 8 ) * 8 + 7; + } + } + //Create TX buffers and threads if (dotx) { unsigned fidx = 1; From 731ec713744c64a55c99e26eb80cebffa01aec99 Mon Sep 17 00:00:00 2001 From: Yuri Nikolaev Date: Sun, 15 Mar 2026 13:51:12 +0300 Subject: [PATCH 360/397] rm forgotten comments in test --- src/lib/xdsp/utests/wvlt_sincos_i16_utest.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c index f624930c..b11a386a 100644 --- a/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c +++ b/src/lib/xdsp/utests/wvlt_sincos_i16_utest.c @@ -475,12 +475,11 @@ Suite * wvlt_sincos_i16_suite(void) max_opt = cpu_vcap_get(); Suite* s = suite_create("wvlt_sincos_i16"); -/* + ADD_REGRESS_TEST(s, wvlt_sincos_i16_check_simd); ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_speed, 60, 0, 3); ADD_REGRESS_TEST(s, wvlt_sincos_i16_interleaved_ctrl_check_simd); ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_interleaved_ctrl_speed, 60, 0, 3); -*/ ADD_REGRESS_TEST(s, wvlt_sincos_i16_interleaved_chirp_check_simd); ADD_PERF_LOOP_TEST(s, wvlt_sincos_i16_interleaved_chirp_speed, 60, 0, 3); From 64024db2f17068cb47bc432255d24f29d5ec8924 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 16 Mar 2026 14:50:23 +0400 Subject: [PATCH 361/397] xsdr: improve samplerate handling --- src/lib/cal/cal_lo_iqimb.c | 61 +-- src/lib/device/generic_usdr/generic_regs.h | 2 - src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 28 +- src/lib/device/m2_lm7_1/lms7002m_ctrl.h | 3 +- src/lib/device/m2_lm7_1/m2_lm7_1.c | 283 +++++++--- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 588 ++++++++++----------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 13 + src/lib/device/u3_limesdr/limesdr_ctrl.c | 2 +- src/lib/hw/lms7002m/lms7002m.c | 73 ++- src/lib/hw/lms7002m/lms7002m.h | 1 + src/lib/ipblks/fgearbox.c | 21 +- src/lib/ipblks/fgearbox.h | 3 + 12 files changed, 604 insertions(+), 474 deletions(-) diff --git a/src/lib/cal/cal_lo_iqimb.c b/src/lib/cal/cal_lo_iqimb.c index e08f5f03..7a6ffbc1 100644 --- a/src/lib/cal/cal_lo_iqimb.c +++ b/src/lib/cal/cal_lo_iqimb.c @@ -125,7 +125,7 @@ int calibrate_txlo(struct calibrate_ops* ops) if (res) return res; - res = ops->set_nco_offset(ops->param, ops->channel, ((-ops->rxtxlo_frac) << 1)); + res = ops->set_nco_offset(ops->param, ops->channel, -freqoff); if (res) return res; @@ -169,7 +169,7 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, int32_t freqoffset, int a, giq, b; struct opt_iteration2d o[3]; - res = ops->set_nco_offset(ops->param, ops->channel, (rxreoff << 1)); + res = ops->set_nco_offset(ops->param, ops->channel, rxreoff); if (res) return res; @@ -177,7 +177,7 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, int32_t freqoffset, if (res) return res; - res = ops->set_nco_offset(ops->param, ops->channel, (rximoff << 1)); + res = ops->set_nco_offset(ops->param, ops->channel, rximoff); if (res) return res; @@ -218,12 +218,7 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, int32_t freqoffset, int calibrate_rxiqimb(struct calibrate_ops* ops) { int res; -#if 0 - int pwr_r; - int pwr_i; - int a, giq, b; - struct opt_iteration2d o[3]; -#endif + // Set RX to be TXLO - sampl int32_t freqoff = (((int64_t)ops->rxsamplerate * ops->rxiqimb_frac) >> 31); @@ -236,54 +231,6 @@ int calibrate_rxiqimb(struct calibrate_ops* ops) return res; return _calibrate_iqimb_generic(ops, 0, ops->rxiqimb_frac, -ops->rxiqimb_frac, _evaluate_rxaiq); -#if 0 - res = ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_FREQ, - ops->rxfrequency + freqoff); - if (res) - return res; - - res = ops->set_nco_offset(ops->param, ops->channel, ((-ops->rxiqimb_frac) << 1)); - if (res) - return res; - - res = _calibrate_txpwr(ops, &pwr_r); - - res = ops->set_nco_offset(ops->param, ops->channel, ((ops->rxiqimb_frac) << 1)); - if (res) - return res; - - res = ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_i); - if (res) - return res; - - USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Imbalance %d pwr (%d)\n", pwr_i, pwr_r - pwr_i); - // Probe AI and AQ, choice what path to go - - o[0].limit[0] = ops->rximb_ang_corr; - o[0].limit[1] = ops->rximb_iq_corr; - o[0].func = _evaluate_rxaiq; - o[0].sf = &find_golden_min; - o[0].exparam = 0; - o[1].limit[0] = ops->rximb_ang_corr; - o[1].limit[1] = ops->rximb_iq_corr; - o[1].func = _evaluate_rxaiq; - o[1].sf = &find_golden_min; - o[1].exparam = 0; - o[2].limit[0].max = 8; - o[2].limit[0].min = -8; - o[2].limit[1].max = 8; - o[2].limit[1].min = -8; - o[2].func = _evaluate_rxaiq; - o[2].sf = &find_golden_min; - o[2].exparam = 0; - - res = find_best_2d(&o[0], SIZEOF_ARRAY(o), ops, ops->defstop, &a, &giq, &b); - if (res) - return res; - - USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Imbalance %d pwr (%d) improvement %d\n", b, pwr_r - b, pwr_i - b); - return 0; -#endif } diff --git a/src/lib/device/generic_usdr/generic_regs.h b/src/lib/device/generic_usdr/generic_regs.h index cc94db19..23ba458e 100644 --- a/src/lib/device/generic_usdr/generic_regs.h +++ b/src/lib/device/generic_usdr/generic_regs.h @@ -21,8 +21,6 @@ enum REGS_generic_usdr_r000 { M2PCI_REG_RD_FBUFFS = 4, M2PCI_REG_RD_FBURSTS = 5, M2PCI_REG_RD_RXSTAT = 6, - M2PCI_REG_RD_AVGIDC = 7, - M2PCI_REG_RD_AVGQDC = 8, M2PCI_REG_WR_PNTFY_CFG = 8, M2PCI_REG_WR_PNTFY_ACK = 9, diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 1f89afce..2b7cbcf1 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -392,12 +392,6 @@ static int _lms7002m_lb_status_changes(lms7002_dev_t *d) res = (res) ? res : lms7002m_trf_gain(&d->lmsstate, TRF_GAIN_LB, 0, NULL); - res = (res) ? res : lms7002m_trf_gain(&d->lmsstate, - TRF_GAIN_PAD, //TRF_GAIN_LB, - -10 * d->trf_lb_atten, - NULL); - // res = (res) ? res : lms7002m_rfe_gain(&d->lmsstate, - // d->rfe_lb_atten, &lb_loss); USDR_LL_LOG(d->lmsstate.dev, "UDEV", USDR_LOG_WARNING, "Turning on loopback RX + TX loss: -- + %d dB\n", /*lb_loss,*/ d->trf_lb_atten); @@ -598,7 +592,7 @@ int lms7002m_bb_set_freq(lms7002_dev_t *d, rel_freq / 1000, conv_freq / 1000); return -EINVAL; } - int pfreq = rel_freq * 4294967296; + int pfreq = rel_freq * 4294967296.0; if (channel & LMS7_CH_A) opt_u32_set_val(&dsp_f[0], pfreq); if (channel & LMS7_CH_B) @@ -855,9 +849,9 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, d->lml_mode = nlml_mode; } - res = lms7002m_dc_corr_en(&d->lmsstate, d->rx_run[0], d->rx_run[1], d->tx_run[0], d->tx_run[1]); - if (res) - return res; + //res = lms7002m_dc_corr_en(&d->lmsstate, d->rx_run[0], d->rx_run[1], d->tx_run[0], d->tx_run[1]); + //if (res) + // return res; //res = lms7_dc_init(&d->lmsstate, d->rx_run[0], d->rx_run[1], d->tx_run[0], d->tx_run[1]); USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "configure done RUN RX:%d%d TX:%d%d\n", @@ -890,7 +884,8 @@ enum { int lms7002m_samplerate(lms7002_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, - unsigned flags, const bool rx_port_1) + unsigned flags, const bool rx_port_1, + unsigned rx_dec, unsigned tx_int) { //bool no_8ma = false; lms7002m_limelight_conf_t cfg; @@ -928,7 +923,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, for (unsigned citer = 0; citer < (extended_cgen_range ? 2 : 1); citer++) { unsigned mindecint_rx = (sisoddr_rx || extclk_rx) ? 1 : 2; unsigned mindecint_tx = (sisoddr_tx || extclk_tx) ? 1 : 2; - unsigned cgen_max = extended_cgen_range && (citer == 0) ? 380e6 : 320e6; + unsigned cgen_max = extended_cgen_range && (citer == 0) ? 370e6 : 320e6; cgen_rate = MAX(txmaster_min, rxmaster_min); if (cgen_rate < 1) { @@ -1073,13 +1068,13 @@ int lms7002m_samplerate(lms7002_dev_t *d, if (rxrate > 1 && d->rx_run[i] && !d->rx_bw[i].set) { USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set RX[%d] bandwidth to %.3f Mhz\n", i, rxrate / 1e6); res = res ? res : lms7002m_mac_set(&d->lmsstate, i == 0 ? LMS7_CH_A : LMS7_CH_B); - res = res ? res : lms7002m_rbb_bandwidth(d, rxrate, false); + res = res ? res : lms7002m_rbb_bandwidth(d, rxrate / rx_dec, false); } if (txrate > 1 && d->tx_run[i] && !d->tx_bw[i].set) { USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set TX[%d] bandwidth to %.3f Mhz\n", i, txrate / 1e6); res = res ? res : lms7002m_mac_set(&d->lmsstate, i == 0 ? LMS7_CH_A : LMS7_CH_B); - res = res ? res : lms7002m_tbb_bandwidth(d, txrate, false); + res = res ? res : lms7002m_tbb_bandwidth(d, txrate / tx_int, false); res = res ? res : lms7002m_set_gain(d, i == 0 ? LMS7_CH_A : LMS7_CH_B, RFIC_LMS7_TX_PGA_GAIN, 13, NULL); @@ -1162,9 +1157,8 @@ int lms7002m_set_corr_param(lms7002_dev_t* d, int channel, int corr_type, int va case CORR_OP_SET_FREQ: // TODO: optimize for TDD - res = lms7002m_sxx_tune(&d->lmsstate, rx ? SXX_TX : SXX_RX, d->fref, (unsigned)value, false); - res = (res) ? res - : lms7002m_mac_set(&d->lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); + res = lms7002m_sxx_tune(&d->lmsstate, rx ? SXX_RX : SXX_TX, d->fref, (unsigned)value, false); + res = (res) ? res : lms7002m_mac_set(&d->lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); return res; case CORR_OP_SET_BW: if (rx) { diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h index 785185a9..6a4153b8 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h @@ -203,7 +203,8 @@ enum { int lms7002m_samplerate(lms7002_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, - unsigned flags, const bool rx_port_1); + unsigned flags, const bool rx_port_1, + unsigned rx_dec, unsigned tx_int); enum { diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index c1722718..88d066b7 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "../device.h" #include "../device_ids.h" @@ -204,6 +205,8 @@ static int dev_m2_lm7_1_debug_lms8001_reg_get(pdevice_t ud, pusdr_vfs_obj_t obj, static int dev_m2_lm7_1_sdr_rx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_sdr_rx_dccorr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); + static int dev_m2_lm7_1_sdr_tx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_sdr_rx_dccorrmode_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -216,8 +219,6 @@ static int dev_m2_lm7_1_sdr_refclk_frequency_get(pdevice_t ud, pusdr_vfs_obj_t o static int dev_m2_lm7_1_sdr_refclk_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); -static int dev_m2_lm7_1_usb_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); - static int dev_m2_lm7_1_sdr_rxdsp_swapab_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_tx_antennat_port_cfg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -226,13 +227,9 @@ static int dev_m2_lm7_1_rfe_throttle_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint static int dev_m2_lm7_1_sensor_freqpps_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* value); static int dev_m2_lm7_1_rfe_nco_pwrdc_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* value); -static int dev_m2_lm7_1_rfe_nco_enable_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); -static int dev_m2_lm7_1_rfe_nco_enable_frequency(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); - static int dev_m2_lm7_1_tfe_gen_en_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_tfe_gen_const_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_tfe_gen_tone_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); -static int dev_m2_lm7_1_tfe_nco_enable_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_tfe_nco_enable_frequency(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_calibrate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -276,21 +273,20 @@ static int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t static const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { - { "/dm/rate/master", { dev_m2_lm7_1_rate_set, NULL }}, - { "/dm/rate/rxtxadcdac", { dev_m2_lm7_1_rate_m_set, NULL }}, + { "/dm/rate/master", { dev_m2_lm7_1_rate_set, NULL }}, + { "/dm/rate/rxtxadcdac", { dev_m2_lm7_1_rate_m_set, NULL }}, - { "/dm/debug/all", { NULL, dev_m2_lm7_1_debug_all_get }}, - { "/dm/power/en", { dev_m2_lm7_1_pwren_set, NULL }}, + { "/dm/debug/all", { NULL, dev_m2_lm7_1_debug_all_get }}, + { "/dm/power/en", { dev_m2_lm7_1_pwren_set, NULL }}, - { "/dm/sdr/channels", { NULL, NULL }}, - { "/dm/sensor/temp", { NULL, dev_m2_lm7_1_senstemp_get }}, + { "/dm/sdr/channels", { NULL, NULL }}, + { "/dm/sensor/temp", { NULL, dev_m2_lm7_1_senstemp_get }}, { "/dm/sdr/0/usbclk", { dev_m2_lm7_1_usbclk_set, NULL }}, { "/dm/sdr/0/calibrate", { dev_m2_lm7_1_calibrate_set, dev_m2_lm7_1_calibrate_get }}, - { "/dm/sdr/refclk/frequency", {dev_m2_lm7_1_sdr_refclk_frequency_set, dev_m2_lm7_1_sdr_refclk_frequency_get}}, - { "/dm/sdr/refclk/path", {dev_m2_lm7_1_sdr_refclk_path_set, NULL}}, - + { "/dm/sdr/refclk/frequency", { dev_m2_lm7_1_sdr_refclk_frequency_set, dev_m2_lm7_1_sdr_refclk_frequency_get }}, + { "/dm/sdr/refclk/path", { dev_m2_lm7_1_sdr_refclk_path_set, NULL }}, { "/dm/sdr/0/vio", { dev_m2_lm7_1_sdr_vio_set, NULL }}, { "/dm/sdr/0/lnb", { dev_m2_lm7_1_lnb_set, dev_m2_lm7_1_lnb_get }}, @@ -302,7 +298,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/tx/phase_ovr_rc", { dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set, NULL }}, { "/dm/sdr/0/rx/phase_ovr", { dev_m2_lm7_1_sdr_rx_phase_ovr_set, NULL }}, - { "/dm/sdr/0/rx/dccorr", { dev_m2_lm7_1_sdr_rx_dccorr_set, NULL }}, + { "/dm/sdr/0/rx/dccorr", { dev_m2_lm7_1_sdr_rx_dccorr_set, dev_m2_lm7_1_sdr_rx_dccorr_get }}, { "/dm/sdr/0/tx/dccorr", { dev_m2_lm7_1_sdr_tx_dccorr_set, NULL }}, { "/dm/sdr/0/rx/phgaincorr",{ dev_m2_lm7_1_sdr_rx_phgaincorr_set, NULL }}, { "/dm/sdr/0/tx/phgaincorr",{ dev_m2_lm7_1_sdr_tx_phgaincorr_set, NULL }}, @@ -344,7 +340,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/rxdsp/swapab", { dev_m2_lm7_1_sdr_rxdsp_swapab_set, NULL }}, - { "/dm/sdr/0/tdd/frequency", { dev_m2_lm7_1_sdr_tdd_freq_set, NULL }}, + { "/dm/sdr/0/tdd/frequency", { dev_m2_lm7_1_sdr_tdd_freq_set, NULL }}, /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/tdd/freqency", { dev_m2_lm7_1_sdr_tdd_freq_set, NULL }}, @@ -354,38 +350,25 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/tfe/generator/enable", { dev_m2_lm7_1_tfe_gen_en_set, NULL }}, { "/dm/sdr/0/tfe/generator/const", { dev_m2_lm7_1_tfe_gen_const_set, NULL }}, { "/dm/sdr/0/tfe/generator/tone", { dev_m2_lm7_1_tfe_gen_tone_set, NULL }}, - { "/dm/sdr/0/tfe/nco/enable", { dev_m2_lm7_1_tfe_nco_enable_set, NULL }}, - { "/dm/sdr/0/tfe/nco/frequency", { dev_m2_lm7_1_tfe_nco_enable_frequency, NULL }}, + { "/dm/sdr/0/tfe/nco/frequency", { dev_m2_lm7_1_tfe_nco_enable_frequency, NULL }}, /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/tfe/nco/freqency", { dev_m2_lm7_1_tfe_nco_enable_frequency, NULL }}, - { "/dm/sdr/0/rfe/throttle", { dev_m2_lm7_1_rfe_throttle_set, NULL }}, - - { "/dm/sdr/0/rfe/nco/enable", { dev_m2_lm7_1_rfe_nco_enable_set, NULL }}, - - { "/dm/sdr/0/rfe/nco/frequency",{ dev_m2_lm7_1_rfe_nco_enable_frequency, NULL }}, - - /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ - { "/dm/sdr/0/rfe/nco/freqency",{ dev_m2_lm7_1_rfe_nco_enable_frequency, NULL }}, - - { "/dm/sdr/0/rfe/pwrdc", { NULL, dev_m2_lm7_1_rfe_nco_pwrdc_get }}, + { "/dm/sdr/0/rfe/throttle", { dev_m2_lm7_1_rfe_throttle_set, NULL }}, + { "/dm/sdr/0/rfe/pwrdc", { NULL, dev_m2_lm7_1_rfe_nco_pwrdc_get }}, // Debug interface - { "/debug/hw/lms7002m/0/reg", { dev_m2_lm7_1_debug_lms7002m_reg_set, dev_m2_lm7_1_debug_lms7002m_reg_get }}, - { "/debug/hw/lms8001/0/reg" , { dev_m2_lm7_1_debug_lms8001_reg_set, dev_m2_lm7_1_debug_lms8001_reg_get }}, - - - // USB debug interface - { "/dm/usb", { NULL, dev_m2_lm7_1_usb_get }}, + { "/debug/hw/lms7002m/0/reg", { dev_m2_lm7_1_debug_lms7002m_reg_set, dev_m2_lm7_1_debug_lms7002m_reg_get }}, + { "/debug/hw/lms8001/0/reg" , { dev_m2_lm7_1_debug_lms8001_reg_set, dev_m2_lm7_1_debug_lms8001_reg_get }}, // Get sampled amount of ticks between GPS - { "/dm/sensor/freqpps", { NULL, dev_m2_lm7_1_sensor_freqpps_get }}, + { "/dm/sensor/freqpps", { NULL, dev_m2_lm7_1_sensor_freqpps_get }}, - { "/dm/sdr/0/core/atcrbs/reg", { dev_m2_lm7_1_dev_atcrbs_set, dev_m2_lm7_1_dev_atcrbs_get }}, + { "/dm/sdr/0/core/atcrbs/reg", { dev_m2_lm7_1_dev_atcrbs_set, dev_m2_lm7_1_dev_atcrbs_get }}, - { "/dm/sdr/0/dac_vctcxo", { dev_m2_lm7_1_dev_dac_vctcxo_set, NULL }}, + { "/dm/sdr/0/dac_vctcxo", { dev_m2_lm7_1_dev_dac_vctcxo_set, NULL }}, { "/dm/sdr/0/phy_rx_dly", { dev_m2_lm7_1_phy_rx_dly_set, NULL }}, { "/dm/sdr/0/phy_rx_lfsr", { dev_m2_lm7_1_phy_rx_lfsr_set, dev_m2_lm7_1_phy_rx_lfsr_get }}, @@ -401,6 +384,59 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/ll/qspi_flash/master_off", { NULL, dev_m2_lm7_1_qspi_flash_master_off_get }}, }; +static const usdr_dev_link_t s_links[] = { + { "/dm/sdr/0/rx/frequency/0", "/dm/sdr/0/rx/frequency" }, + { "/dm/sdr/0/rx/frequency/1", "/dm/sdr/0/rx/frequency" }, + { "/dm/sdr/0/tx/frequency/0", "/dm/sdr/0/tx/frequency" }, + { "/dm/sdr/0/tx/frequency/1", "/dm/sdr/0/tx/frequency" }, + { "/dm/sdr/0/rx/frequency/bb/0", "/dm/sdr/0/rx/frequency/bb" }, + { "/dm/sdr/0/rx/frequency/bb/1", "/dm/sdr/0/rx/frequency/bb" }, + { "/dm/sdr/0/tx/frequency/bb/0", "/dm/sdr/0/tx/frequency/bb" }, + { "/dm/sdr/0/tx/frequency/bb/1", "/dm/sdr/0/tx/frequency/bb" }, + + { "/dm/sdr/0/rx/gain/0", "/dm/sdr/0/rx/gain" }, + { "/dm/sdr/0/tx/gain/0", "/dm/sdr/0/tx/gain" }, + { "/dm/sdr/0/tx/gain/lb/0", "/dm/sdr/0/tx/gain/lb" }, + { "/dm/sdr/0/tx/gain/vga1/0", "/dm/sdr/0/tx/gain/vga1" }, + { "/dm/sdr/0/rx/gain/pga/0", "/dm/sdr/0/rx/gain/pga" }, + { "/dm/sdr/0/rx/gain/vga/0", "/dm/sdr/0/rx/gain/vga" }, + { "/dm/sdr/0/rx/gain/lna/0", "/dm/sdr/0/rx/gain/lna" }, + { "/dm/sdr/0/rx/gain/lb/0", "/dm/sdr/0/rx/gain/lb" }, + { "/dm/sdr/0/rx/gain/1", "/dm/sdr/0/rx/gain" }, + { "/dm/sdr/0/tx/gain/1", "/dm/sdr/0/tx/gain" }, + { "/dm/sdr/0/tx/gain/lb/1", "/dm/sdr/0/tx/gain/lb" }, + { "/dm/sdr/0/tx/gain/vga1/1", "/dm/sdr/0/tx/gain/vga1" }, + { "/dm/sdr/0/rx/gain/pga/1", "/dm/sdr/0/rx/gain/pga" }, + { "/dm/sdr/0/rx/gain/vga/1", "/dm/sdr/0/rx/gain/vga" }, + { "/dm/sdr/0/rx/gain/lna/1", "/dm/sdr/0/rx/gain/lna" }, + { "/dm/sdr/0/rx/gain/lb/1", "/dm/sdr/0/rx/gain/lb" }, + + { "/dm/sdr/0/rx/bandwidth/0", "/dm/sdr/0/rx/bandwidth" }, + { "/dm/sdr/0/tx/bandwidth/0", "/dm/sdr/0/tx/bandwidth" }, + { "/dm/sdr/0/rx/bandwidth/1", "/dm/sdr/0/rx/bandwidth" }, + { "/dm/sdr/0/tx/bandwidth/1", "/dm/sdr/0/tx/bandwidth" }, + + { "/dm/sdr/0/rx/rfic_path/0", "/dm/sdr/0/rx/rfic_path" }, + { "/dm/sdr/0/rx/rfic_path/1", "/dm/sdr/0/rx/rfic_path" }, + { "/dm/sdr/0/tx/rfic_path/0", "/dm/sdr/0/tx/rfic_path" }, + { "/dm/sdr/0/tx/rfic_path/1", "/dm/sdr/0/tx/rfic_path" }, + + { "/dm/sdr/0/rx/path/0", "/dm/sdr/0/rx/path" }, + { "/dm/sdr/0/rx/path/1", "/dm/sdr/0/rx/path" }, + { "/dm/sdr/0/tx/path/0", "/dm/sdr/0/tx/path" }, + { "/dm/sdr/0/tx/path/1", "/dm/sdr/0/tx/path" }, + + { "/dm/sdr/0/rx/dccorr/0", "/dm/sdr/0/rx/dccorr" }, + { "/dm/sdr/0/tx/dccorr/0", "/dm/sdr/0/tx/dccorr" }, + { "/dm/sdr/0/rx/phgaincorr/0","/dm/sdr/0/rx/phgaincorr" }, + { "/dm/sdr/0/tx/phgaincorr/0","/dm/sdr/0/tx/phgaincorr" }, + { "/dm/sdr/0/rx/dccorr/1", "/dm/sdr/0/rx/dccorr" }, + { "/dm/sdr/0/tx/dccorr/1", "/dm/sdr/0/tx/dccorr" }, + { "/dm/sdr/0/rx/phgaincorr/1","/dm/sdr/0/rx/phgaincorr" }, + { "/dm/sdr/0/tx/phgaincorr/1","/dm/sdr/0/tx/phgaincorr" }, + +}; + struct dev_m2_lm7_1_gps { device_t base; @@ -423,6 +459,99 @@ struct dev_m2_lm7_1_gps { stream_handle_t* tx; }; +static int lms7002m_channel_info_string_parse(char* chanlist, unsigned max_chans, lms7002m_mac_mode_t* cinfo) +{ + lms7002m_mac_mode_t ch = LMS7_CH_NONE; + const char* delim = ":_-/"; + char* saveptr; + char* str1; + unsigned t; + + for (t = 0, str1 = chanlist; ; str1 = NULL, t++) { + const char* token = strtok_r(str1, delim, &saveptr); + if (token == NULL) { + break; + } + + unsigned chn; + if (isdigit(*token)) { + chn = atoi(token); + } else if (isalpha(*token)) { + chn = tolower(*token) - 'a'; + } else { + USDR_LOG("STRM", USDR_LOG_ERROR, "Channel parsing: incorrect token# %d `%s`\n", t, token); + return -EINVAL; + } + + if (chn > max_chans) { + USDR_LOG("STRM", USDR_LOG_ERROR, "Channel parsing: incorrect channel num: %d\n", chn); + return -EINVAL; + } + + ch |= 1 << chn; + } + + *cinfo = ch; + return 0; +} + +static int device_path_to_chmsk(const char* full_path, const char* basename, lms7002m_mac_mode_t* lms_ch) +{ + char chanlist[64*4]; + const char* lst; + + if (basename) { + size_t len; + len = strlen(basename); + if (strncmp(full_path, basename, len)) { + return -ENOENT; + } + + lst = full_path + len; + if (*lst != '/') { + return -ENAVAIL; + } + + lst++; + } else { + const char *pos = full_path; + lst = NULL; + + while ((pos = strchr(pos, '/')) != NULL) { + lst = pos; + pos++; + } + if (lst == NULL) { + return -ENAVAIL; + } + } + + SAFE_STRCPY(chanlist, lst); + return lms7002m_channel_info_string_parse(chanlist, 2, lms_ch); +} + +static int lms7002_iterate_ordinal_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val, const char* basename, bool rxchans) +{ + //struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + vfs_object_t ph; + lms7002m_mac_mode_t selected; + int res = device_path_to_chmsk(obj->full_path, basename, &selected); + if (res == -ENAVAIL) { + selected = LMS7_CH_AB; + res = 0; + } else if (res != 0) { + return res; + } + + ph.type = obj->type; + ph.object = obj->object; + ph.data = obj->data; + ph.ops = obj->ops; + ph.full_path[0] = 0; + ph.full_path[1] = selected; + return obj->ops.si64(&ph, val); +} + int dev_m2_lm7_1_debug_clkinfo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { return xsdr_clk_debug_info(&((struct dev_m2_lm7_1_gps *)ud)->xdev); @@ -557,7 +686,7 @@ int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) int dev_m2_lm7_1_lnb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - if (value < 300e6 || value > 3800e6) { + if ((value < 300e6) || (value > 3800e6)) { return -ERANGE; } @@ -587,7 +716,7 @@ int dev_m2_lm7_1_lms8_intmode_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *o int dev_m2_lm7_1_lms8_switchover_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - if (value < 1500e6 || value > 3800e6) { + if ((value < 1500e6) || (value > 3800e6)) { return -ERANGE; } @@ -628,6 +757,12 @@ int dev_m2_lm7_1_debug_lms8001_reg_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 } +int dev_m2_lm7_1_sdr_rx_dccorr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + return xsdr_rxdccorr(&d->xdev, ovalue); +} + int dev_m2_lm7_1_sdr_rx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; @@ -757,11 +892,6 @@ int dev_m2_lm7_1_tfe_gen_tone_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t va return res; } -int dev_m2_lm7_1_tfe_nco_enable_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) -{ - return 0; -} - int dev_m2_lm7_1_tfe_nco_enable_frequency(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; @@ -796,19 +926,6 @@ int dev_m2_lm7_1_rfe_throttle_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t va return -EINVAL; } - -int dev_m2_lm7_1_rfe_nco_enable_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) -{ - //struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - //return sfe_rf4_nco_enable(d->base.dev, 0, CSR_RFE4_BASE, (value & 0xff) ? true : false, value >> 32); - return -EINVAL; -} -int dev_m2_lm7_1_rfe_nco_enable_frequency(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) -{ - //struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - //return sfe_rf4_nco_freq(d->base.dev, 0, CSR_RFE4_BASE, (int)value); - return -EINVAL; -} int dev_m2_lm7_1_rfe_nco_pwrdc_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* value) { struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; @@ -850,7 +967,7 @@ int dev_m2_lm7_1_calibrate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value unsigned flags = value & 0xfffff; unsigned chan = value >> 32; - if (flags > 65536 || chan > 1) { + if (flags > 2*65536 || chan > 1) { const char* v = (const char* )value; chan = 0; // TODO B flags = 0; @@ -991,11 +1108,14 @@ int dev_m2_lm7_1_sdr_tx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val int dev_m2_lm7_1_sdr_rx_bbfreq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { + if (obj->full_path[0]) { + return lms7002_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/rx/frequency/bb", true); + } + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - unsigned channel = value >> 32; int32_t freq = (int32_t)(value & 0xffffffff); + return xsdr_rfic_bb_set_freq(&d->xdev, obj->full_path[1], false, freq); - return xsdr_rfic_bb_set_freq(&d->xdev, channel, false, freq); } int dev_m2_lm7_1_sdr_tx_bbfreq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { @@ -1313,22 +1433,6 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* } } -#if 0 - //Load DSP ucode - lowlevel_reg_wr32(dev, 0, 0, 0x02000001); - for (unsigned k = 0; k < SIZEOF_ARRAY(s_dsp_ucode_fir2); k++) - lowlevel_reg_wr32(dev, 0, 0, s_dsp_ucode_fir2[k]); - lowlevel_reg_wr32(dev, 0, 0, 0x02000000); -#endif - - - return 0; -} - - -int dev_m2_lm7_1_usb_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) -{ - *ovalue = 0; return 0; } @@ -1435,16 +1539,16 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha } } - res = create_sfetrx4_stream(dev, CORE_SFERX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, - flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, - SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &hwchs); + res = xsdr_prepare(&d->xdev, true, d->tx); if (res) { - USDR_LL_LOG(d->base.dev, "XSDR", USDR_LOG_ERROR, "Unable to create stream '%s': error=%d\n", sid, res); return res; } - res = xsdr_prepare(&d->xdev, true, d->tx); + res = create_sfetrx4_stream(dev, CORE_SFERX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, + flags, M2PCI_REG_WR_RXDMA_CONFIRM, VIRT_CFG_SFX_BASE, 0, + SRF4_FIFOBSZ, CSR_RFE4_BASE, &d->rx, &hwchs); if (res) { + USDR_LL_LOG(d->base.dev, "XSDR", USDR_LOG_ERROR, "Unable to create stream '%s': error=%d\n", sid, res); return res; } @@ -1490,7 +1594,8 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha } *out_handle = d->tx; - res = xsdr_hwchans_cnt(&d->xdev, false, hwchs); + res = res ? res : xsdr_hwchans_cnt(&d->xdev, false, hwchs); + res = res ? res : lms7002m_dc_corr_en(&d->xdev.base.lmsstate, d->xdev.base.rx_run[0], d->xdev.base.rx_run[1], d->xdev.base.tx_run[0], d->xdev.base.tx_run[1]); } return res; @@ -1539,9 +1644,9 @@ int usdr_device_m2_lm7_1_create(lldev_t dev, device_id_t devid) } res = dev_gpi_get32(dev, IGPI_HWID, &hwid); - //if (res) { - // goto failed_free; - //} + if (res) { + goto failed_free; + } did = ((hwid >> 16) & 0xff); if ((res == 0) && (did == SSDR_DEV || did == SSDRPRO_DEV)) { @@ -1568,6 +1673,12 @@ int usdr_device_m2_lm7_1_create(lldev_t dev, device_id_t devid) if (res) goto failed_tree_creation; + res = usdr_vfs_obj_link_init_array(&d->base, + s_links, + SIZEOF_ARRAY(s_links)); + if (res) + goto failed_tree_creation; + d->base.initialize = &usdr_device_m2_lm7_1_initialize; d->base.destroy = &usdr_device_m2_lm7_1_destroy; d->base.create_stream = &usdr_device_m2_lm7_1_create_stream; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 2e8cf062..e8df489c 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -19,6 +19,7 @@ #include "../cal/cal_lo_iqimb.h" #include "../ipblks/streams/sfe_rx_4.h" #include "../ipblks/xlnx_mmcm.h" +#include "../ipblks/fgearbox.h" #ifndef MAX #define MAX(x,y) (((x) > (y)) ? (x) : (y)) @@ -29,14 +30,21 @@ enum { DRP_MMCM_PORT_TX = 1, }; -// TXA RXB -// TXB RXA // SSDR RF routing infortmation +// ------------------------------ // LMS8_CHA <= TXOUT_A_2 <= BAND2 // LMS8_CHB <= TXOUT_B_2 <= BAND2 // LMS8_CHC => RXIN_A_2 => LNA_H // LMS8_CHD => RXIN_B_2 => LNA_H - +// ------------------------------ +// <= BAND1 +// <= BAND1 +// => LNA_W +// => LNA_W +// ------------------------------ +// loopback configuration: +// Band2 -- LNA_L +// Band1 -- LNA_W / LNA_H enum { XSDR_INT_REFCLK = 26000000, @@ -156,11 +164,26 @@ enum { PHY_REG_RXBANK_CLKMEAS = 2, PHY_REG_RXBANK_LFSRCHK = 3, // LFSR control PHY_REG_RXBANK_IQABCHK = 4, // IQAB control + PHY_REG_RXBANK_CAPTURE = 5, // IQ capture + PHY_REG_RXBANK_DC_EST = 6, // DC estimator PHY_REG_RXBANK_CLKDLY = 14, // Clock delay PHY_REG_RXBANK_FRMDLY = 15, // Frame delay }; +// PHY_REG_RXBANK_CTRL registers +enum { + ADDR_CTRL_DESER = 0, + ADDR_CTRL_MMCM = 1, + ADDR_CTRL_MAN = 2, +}; + +// PHY_REG_RXBANK_DC_EST +enum { + ADDR_DC_EST_RESET = 0, + ADDR_DC_EST_ACCM = 1, +}; + int xsdr_phy_rx_reg(xsdr_dev_t *d, bool wr, uint8_t bank, uint8_t addr, uint16_t val) { @@ -202,6 +225,54 @@ int xsdr_phy_lfsr_mimo_state_s(xsdr_dev_t *d, int ridx, uint32_t* v) return res; } +int xsdr_phy_capture_start(xsdr_dev_t *d, bool start) +{ + return xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_CAPTURE, 0, start ? 1 : 0); +} + +int xsdr_phy_capture_get_item(xsdr_dev_t *d, bool chb, unsigned idx, uint32_t* v) +{ + int res = 0; + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_CAPTURE, (chb ? 0x80 : 0x00) | (idx & 0x7f), 0); + res = res ? res : lowlevel_reg_rd32(d->base.lmsstate.dev, 0, REG_CFG_PHY_0, v); + return res; +} + +int xsdr_phy_capture_get(xsdr_dev_t *d, bool chb, unsigned count, uint32_t* odata) +{ + int res = 0; + for (unsigned i = 0; i < count; i++) { + res = res ? res : xsdr_phy_capture_get_item(d, chb, i, &odata[i]); + } + return res; +} + +enum dc_estimations { + DC_ESTIM_GEN = 0, + DC_ESTIM_AI = 4, + DC_ESTIM_AQ = 5, + DC_ESTIM_BI = 6, + DC_ESTIM_BQ = 7, +}; + +int xsdr_phy_dc_estim_start(xsdr_dev_t *d, bool start) +{ + return xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_DC_EST, ADDR_DC_EST_RESET, start ? 0 : 1); +} + +int xsdr_phy_dc_estim_accum(xsdr_dev_t *d, unsigned accum) +{ + return xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_DC_EST, ADDR_DC_EST_ACCM, accum); +} + +int xsdr_phy_dc_estim_get(xsdr_dev_t *d, enum dc_estimations v, int32_t* odata) +{ + int res = 0; + res = res ? res : xsdr_phy_rx_reg(d, false, PHY_REG_RXBANK_DC_EST, v, 0); + res = res ? res : lowlevel_reg_rd32(d->base.lmsstate.dev, 0, REG_CFG_PHY_0, (uint32_t*)odata); + return res; +} + int xsdr_phy_lfsr_mimo_state(xsdr_dev_t *d, int type, uint32_t v[4]) { int res = 0; @@ -235,9 +306,12 @@ int xsdr_phy_en_lfsr_generator_mimo(xsdr_dev_t *d, bool en, bool lfsr) static int _xsdr_rxserdes_reset(xsdr_dev_t *d) { int res = 0; unsigned sisosdrflag = d->dpump ? 16 : d->base.lml_mode.rxsisoddr ? 8 : 0; - res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); + //res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, 0x80000007 | sisosdrflag); + //res = res ? res : usleep(10); + //res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_CTRL, ADDR_CTRL_DESER, 0x80000007 | sisosdrflag); res = res ? res : usleep(10); - res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, 0x80000000 | sisosdrflag); + res = res ? res : xsdr_phy_rx_reg(d, true, PHY_REG_RXBANK_CTRL, ADDR_CTRL_DESER, 0x80000000 | sisosdrflag); return res; } @@ -461,6 +535,11 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, if (res) break; + if (rb & 0xc00) { + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM NO CLOCK: %08x\n", rb); + return -EIO; + } + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_DEBUG, "MMCM FLAGS:%08x\n", rb); if (rb & (1 << 8)) { g_tx_cfg_raw = cfg_raw; @@ -474,93 +553,6 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, return -EIO; } -int xsdr_configure_lml_mmcm_rx(xsdr_dev_t *d) -{ - bool nomul = d->base.lml_mode.rxsisoddr || (d->base.rxtsp_div > 1); - unsigned rx_mclk = d->base.cgen_clk / d->base.rxcgen_div / d->base.lml_mode.rxdiv; - unsigned io_clk = (nomul) ? rx_mclk : rx_mclk * 2; - unsigned vco_div_io = (MMCM_VCO_MAX + io_clk - 1) / io_clk; - unsigned rb; - int res = 0; - struct mmcm_config_raw cfg_raw; - memset(&cfg_raw, 0, sizeof(cfg_raw)); - cfg_raw.type = (d->xilinx_usp) ? MT_USP_MMCM : MT_7SERIES_MMCM; - - if (vco_div_io > 63) - vco_div_io = 63; - - cfg_raw.ports[CLKOUT_PORT_0].period_l = (vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_0].period_h = vco_div_io / 2; - cfg_raw.ports[CLKOUT_PORT_1].period_l = (vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_1].period_h = vco_div_io / 2; - - cfg_raw.ports[CLKOUT_PORT_2].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_2].period_h = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_3].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_3].period_h = vco_div_io; - - cfg_raw.ports[CLKOUT_PORT_4].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_4].period_h = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_5].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_6].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io; - - cfg_raw.ports[CLKOUT_PORT_0].delay = 1; - - if (nomul) { - cfg_raw.ports[CLKOUT_PORT_FB].period_l =(vco_div_io + 1) / 2; - cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io / 2; - } else { - cfg_raw.ports[CLKOUT_PORT_FB].period_l = vco_div_io; - cfg_raw.ports[CLKOUT_PORT_FB].period_h = vco_div_io; - } - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "MMCM_RX set to MCLK = %.3f IOCLK = %.3f Mhz IODIV = %d\n", - rx_mclk / (1.0e6), io_clk / (1.0e6), vco_div_io); - - res = (res) ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0xF); - usleep(100); - res = (res) ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0xD); - usleep(100); - res = (res) ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0x1); - - if (res) - return res; - - usleep(1000); - res = mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_RX, &cfg_raw); - if (res) - return res; - - res = (res) ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, - 0x80000000 | 0x10000 | 0x0); - - usleep(10000); - res = (res) ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, - 0x01000000); - if (res) - return res; - - for (unsigned k = 0; k < 10; k++) { - // Wait for lock - res = lowlevel_reg_rd32(d->base.lmsstate.dev, d->base.lmsstate.subdev, - REG_CFG_PHY_0, &rb); - if (res) - break; - - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MMCM FLAGS:%08x\n", rb); - if (rb & (1 << 16)) - return 0; - - usleep(5000); - } - - return res; -} - int xsdr_phy_tune_rx(xsdr_dev_t *d, unsigned val) { int res = mmcm_set_phdigdelay_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_RX, CLKOUT_PORT_0, val); @@ -584,12 +576,13 @@ int xsdr_hwchans_cnt(xsdr_dev_t *d, bool rx, unsigned chans) return 0; } -enum { - //PHY_CFG_VALID_MSK = 0x80, +enum HWID_MSKS { PHY_CFG_SEP_CLKDIV_MSK = 0x80, PHY_CFG_LML2_IS_RX = 0x40, PHY_CFG_TX_MMCM = 0x20, PHY_CFG_RX_MMCM = 0x10, + + PHY_CFG_HAS_DUC_DDC = 0x04, }; static bool noerrors_v4(unsigned errs[4], uint64_t* badness) @@ -689,8 +682,12 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_set_lms125vdd(d, 1360); } } else { - bool boost_vio = (!d->siso_sdr_active_rx) && (d->s_rxrate > 80e6 || d->s_txrate > 80e6); - res = res ? res : xsdr_set_vio(d, boost_vio ? 1875 : 1800); + // TODO: optimize the values + bool boost_vio = (!d->siso_sdr_active_rx) && (d->s_rxrate > 84e6 || d->s_txrate > 84e6); + if (boost_vio) { + res = res ? res : xsdr_set_lms125vdd(d, 1330); + res = res ? res : xsdr_set_vio(d, 1910); + } } if (!(d->base.rx_run[0] || d->base.rx_run[1])) { @@ -929,7 +926,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } // REMOVE ME: fixup for now - if (g > 18 && badness < 100 && d->s_txrate > 80e6) + if ((g > 18) && (badness < 100) && (d->s_txrate > 80e6)) break; } } @@ -999,7 +996,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) no_tx: if (!old_rx_run[0] && !old_rx_run[1]) { // No RX, disable it - res = res ? res : lms7002m_streaming_down(&d->base, RFIC_LMS7_RX); + // res = res ? res : lms7002m_streaming_down(&d->base, RFIC_LMS7_RX); } else { res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); } @@ -1022,7 +1019,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, { lldev_t dev = d->base.lmsstate.dev; subdev_t subdev = d->base.lmsstate.subdev; - // unsigned sisosdrflag; + int res; //if (!(((d->hwid) & 0xff) & PHY_CFG_VALID_MSK)) { @@ -1038,10 +1035,43 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, rxrate = 1e6; } + unsigned rx_dec = 1; + unsigned tx_inr = 1; + if (d->has_duc_ddc) { + // On UltraScale+ minimum MMCM frequency is 600/128 = 6.25 Mhz or 3.125MSPS + // With divider this extends to 98Khz + // Do x2 datarate for 30.72MSPS to use extended decimation / interpolation + const unsigned RATE_MIN = 32e6; + unsigned p = 0; + unsigned fpga_dxc[] = { 1, 2, 4, 8, 16, 32 }; + for (; p < SIZEOF_ARRAY(fpga_dxc) - 1; p++) { + if (rxrate && (rxrate * fpga_dxc[p] >= RATE_MIN)) + break; + if (txrate && (txrate * fpga_dxc[p] >= RATE_MIN)) + break; + } + + rx_dec = tx_inr = fpga_dxc[p]; + rxrate *= rx_dec; + txrate *= tx_inr; + } + + if (d->afe_active == false) { + // Need AFE for reference cloking + lms7002m_afe_enable(&d->base.lmsstate, true, true, true, true); // TODO: Check if rx & tx, a & b is required! + + // wait for clock to stabilize + usleep(10000); + + // We need RxTSP & TxTSP configured for proper LML - TSP alignment before LFSR training + d->afe_active = true; + } + + // flags |= XSDR_LML_EXT_FIFOCLK_RX | XSDR_LML_EXT_FIFOCLK_TX; unsigned m_flags = flags | (((d->siso_sdr_active_rx && d->hwchans_rx == 1) || d->dpump) ? XSDR_LML_SISO_DDR_RX : 0) | (((d->siso_sdr_active_tx && d->hwchans_tx == 1) || d->dpump) ? XSDR_LML_SISO_DDR_TX : 0); - res = lms7002m_samplerate(&d->base, rxrate, txrate, adcclk, dacclk, m_flags, d->rx_port_is_1); + res = lms7002m_samplerate(&d->base, rxrate, txrate, adcclk, dacclk, m_flags, d->rx_port_is_1, rx_dec, tx_inr); if (res) return res; @@ -1053,28 +1083,73 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, d->cfg_srate_siso_rx = (m_flags & XSDR_LML_SISO_DDR_RX) ? 1 : 0; d->cfg_srate_siso_tx = (m_flags & XSDR_LML_SISO_DDR_TX) ? 1 : 0; - if (d->afe_active == false) { - // Need AFE for reference cloking - lms7002m_afe_enable(&d->base.lmsstate, true, true, true, true); // TODO: Check if rx & tx, a & b is required! + res = res ? res : _xsdr_calibrate_lml(d); - // wait for clock to stabilize - usleep(10000); + // if (rxrate) { + // if (!d->ssdr_pro) { + // // Switch to clock meas + // res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); + // } + // } - // We need RxTSP & TxTSP configured for proper LML - TSP alignment before LFSR training - d->afe_active = true; + if (d->has_duc_ddc && rxrate && d->s_rx_dec != rx_dec) { + // Optional RX DSP reset + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0xf); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x2); + usleep(10); + res = (res) ? res : fgearbox_load_fir_ex(dev, IGPO_DSPCHAIN_RX_PRG, rx_dec, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x0); + + d->s_rx_dec = rx_dec; } - if (rxrate) { - if (!d->ssdr_pro) { - // Switch to clock meas - res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); - } + if (d->has_duc_ddc && txrate && d->s_tx_int != tx_inr) { + // Optional TX DSP reset + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0xf); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x2); + usleep(10); + res = (res) ? res : fgearbox_load_fir_i_ex(dev, IGPO_DSPCHAIN_TX_PRG, tx_inr, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x0); + + d->s_tx_int = tx_inr; } - if (txrate || d->ssdr_pro) { - res = res ? res : _xsdr_calibrate_lml(d); + // lms7002m_rxtsp_dc_corr(&d->base.lmsstate, true, 0); +/* + int32_t a, b; + int32_t q[4]; + xsdr_phy_dc_estim_accum(d, 255); + xsdr_phy_dc_estim_start(d, 1); + xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &a); + + uint32_t cha[64], chb[64]; + lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); + lms7002m_xxtsp_gen(&d->base.lmsstate, LMS_RXTSP, XXTSP_TONE, 0, 1); + xsdr_phy_capture_start(d, 1); + usleep(100); + xsdr_phy_capture_start(d, 0); + xsdr_phy_capture_get(d, 0, 64, cha); + xsdr_phy_capture_get(d, 1, 64, chb); + lms7002m_xxtsp_gen(&d->base.lmsstate, LMS_RXTSP, XXTSP_NORMAL, 0, 0); + + for (unsigned j = 0; j < 64; j++) { + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "%d: %08x %08x\n", j, cha[j], chb[j]); + } + + + xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &b); + for (unsigned j = 0; j < 4; j++) { + xsdr_phy_dc_estim_get(d, DC_ESTIM_AI + j, &q[j]); } + USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "%d -> %d: %08x %08x %08x %08x\n", + a, b, q[0], q[1], q[2], q[3]); +*/ return res; } @@ -1176,11 +1251,6 @@ const lms7002m_lml_map_t lms7nfe_get_lml_portcfg(bool rx, unsigned chs, unsigned }; static const lms7002m_lml_map_t diqarray_tx[] = { - // MIMO modes - // {{ LML_BQ, LML_BI, LML_AQ, LML_AI }}, - // {{ LML_BI, LML_BQ, LML_AI, LML_AQ }}, - // {{ LML_AQ, LML_AI, LML_BQ, LML_BI }}, - // {{ LML_AI, LML_AQ, LML_BI, LML_BQ }}, {{ LML_AQ, LML_AI, LML_BQ, LML_BI }}, {{ LML_AI, LML_AQ, LML_BI, LML_BQ }}, {{ LML_BQ, LML_BI, LML_AQ, LML_AI }}, @@ -1194,37 +1264,6 @@ const lms7002m_lml_map_t lms7nfe_get_lml_portcfg(bool rx, unsigned chs, unsigned }; -#if 0 - static const lms7002m_lml_map_t diqarray_tx[] = { - // MIMO modes - {{ LML_BI, LML_AI, LML_BQ, LML_AQ }}, - {{ LML_BQ, LML_AQ, LML_BI, LML_AI }}, - {{ LML_AI, LML_BI, LML_AQ, LML_BQ }}, - {{ LML_AQ, LML_BQ, LML_AI, LML_BI }}, - - {{ LML_BI, LML_AI, LML_BQ, LML_AQ }}, - {{ LML_BQ, LML_AQ, LML_BI, LML_AI }}, - {{ LML_AI, LML_BI, LML_AQ, LML_BQ }}, - {{ LML_AQ, LML_BQ, LML_AI, LML_BI }}, - // SISO modes - {{ LML_AI, LML_AI, LML_AQ, LML_AQ }}, - {{ LML_AQ, LML_AQ, LML_AI, LML_AI }}, - {{ LML_BI, LML_BI, LML_BQ, LML_BQ }}, - {{ LML_BQ, LML_BQ, LML_BI, LML_BI }}, - // MIMO test modes (swap IQ_B) - {{ LML_BQ, LML_AI, LML_BI, LML_AQ }}, - {{ LML_BI, LML_AQ, LML_BQ, LML_AI }}, - {{ LML_AQ, LML_BI, LML_AI, LML_BQ }}, - {{ LML_AI, LML_BQ, LML_AQ, LML_BI }}, - // MIMO test modes (swap IQ_A) - {{ LML_BI, LML_AQ, LML_BQ, LML_AI }}, - {{ LML_BQ, LML_AI, LML_BI, LML_AQ }}, - {{ LML_AI, LML_BQ, LML_AQ, LML_BI }}, - {{ LML_AQ, LML_BI, LML_AI, LML_BQ }}, - }; - - const lms7002m_lml_map_t *diqarray = (rx) ? diqarray_rx : diqarray_tx; -#endif const lms7002m_lml_map_t *diqarray = (rx) ? diqarray_rx : diqarray_tx;; unsigned diqidx = 0; if (flags & RFIC_SWAP_IQ) @@ -1241,69 +1280,6 @@ const lms7002m_lml_map_t lms7nfe_get_lml_portcfg(bool rx, unsigned chs, unsigned return diqarray[diqidx]; } -#if 0 //unused, DO NOT DELETE -static -const lms7002m_lml_map_t lms7nfe_get_lml_portcfg_o(unsigned chs, unsigned flags, bool no_siso_map) -{ -#if 0 - static const struct lml_map diqarray[] = { - // MIMO modes - {{ LML_AI, LML_BI, LML_AQ, LML_BQ }}, - {{ LML_AQ, LML_BQ, LML_AI, LML_BI }}, - {{ LML_BI, LML_AI, LML_BQ, LML_AQ }}, - {{ LML_BQ, LML_AQ, LML_BI, LML_AI }}, - - // SISO modes - {{ LML_AI, LML_AQ, LML_AI, LML_AQ }}, - {{ LML_AQ, LML_AI, LML_AQ, LML_AI }}, - {{ LML_BI, LML_BQ, LML_BI, LML_BQ }}, - {{ LML_BQ, LML_BI, LML_BQ, LML_BI }}, - }; - -#endif - static const lms7002m_lml_map_t diqarray[16] = { - // MIMO modes - {{ LML_BI, LML_AI, LML_BQ, LML_AQ }}, - {{ LML_BQ, LML_AQ, LML_BI, LML_AI }}, - {{ LML_AI, LML_BI, LML_AQ, LML_BQ }}, - {{ LML_AQ, LML_BQ, LML_AI, LML_BI }}, - // SISO modes - {{ LML_AI, LML_AI, LML_AQ, LML_AQ }}, - {{ LML_AQ, LML_AQ, LML_AI, LML_AI }}, - {{ LML_BI, LML_BI, LML_BQ, LML_BQ }}, - {{ LML_BQ, LML_BQ, LML_BI, LML_BI }}, - // MIMO test modes (swap IQ_B) - {{ LML_BQ, LML_AI, LML_BI, LML_AQ }}, - {{ LML_BI, LML_AQ, LML_BQ, LML_AI }}, - {{ LML_AQ, LML_BI, LML_AI, LML_BQ }}, - {{ LML_AI, LML_BQ, LML_AQ, LML_BI }}, - // MIMO test modes (swap IQ_A) - {{ LML_BI, LML_AQ, LML_BQ, LML_AI }}, - {{ LML_BQ, LML_AI, LML_BI, LML_AQ }}, - {{ LML_AI, LML_BQ, LML_AQ, LML_BI }}, - {{ LML_AQ, LML_BI, LML_AI, LML_BQ }}, - }; - - unsigned diqidx = 0; - if (flags & RFIC_SWAP_IQ) - diqidx |= 1; - - if (_xsdr_run_params_stream_is_swap(chs, flags)) - diqidx |= 2; - - if (!no_siso_map && !_xsdr_run_params_stream_is_mimo(chs, flags)) - diqidx |= 4; -// else if (flags & RFIC_SWAP_IQB) -// diqidx |= 8; -// else if (flags & RFIC_SWAP_IQA) -// diqidx |= 12; - - USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "diqidx=%d\n", diqidx); - assert(diqidx < (sizeof(diqarray)/sizeof(diqarray[0]))); - return diqarray[diqidx]; -} -#endif - int xsdr_rfic_streaming_xflags(xsdr_dev_t *d, unsigned xor_rx_flags, unsigned xor_tx_flags) @@ -1455,6 +1431,9 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, } else if (type == RFIC_LMS7_TUNE_TX_FDD) { d->lms7_txlo_last = (res == 0) ? freq : 0; } + + // LO correction + res = res ? res : lms7002m_dc_corr_en(&d->base.lmsstate, d->base.rx_run[0], d->base.rx_run[1], d->base.tx_run[0], d->base.tx_run[1]); return res; } @@ -1480,12 +1459,9 @@ int xsdr_rfic_fe_set_lna(xsdr_dev_t *d, int xsdr_tx_antennat_port_cfg(xsdr_dev_t *d, unsigned mask) { -#if 0 - lldev_t dev = d->base.lmsstate.dev; - unsigned subdev = 0; int res = 0; - d->dsp_txcfg = mask; + // 2 - mute_a // 1 - mute_b @@ -1498,11 +1474,7 @@ int xsdr_tx_antennat_port_cfg(xsdr_dev_t *d, unsigned mask) res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_B); res = res ? res : lms7002m_trf_path(&d->base.lmsstate, TRF_MUTE, TRF_MODE_NORMAL); } - - res = res ? res : lowlevel_reg_wr32(dev, subdev, M2PCI_REG_WR_TXDMA_COMB, (1 << 11) | ((mask & 7) << 8) | 1); return res; -#endif - return -ENOTSUP; } @@ -1963,7 +1935,7 @@ int _xsdr_pwren_revo(xsdr_dev_t *d, bool on) int xsdr_set_lms125vdd(xsdr_dev_t *d, unsigned vdd_mv) { - if (d->new_rev && !d->ssdr) { + if (d->new_rev /* && !d->ssdr */) { return lp8758_vout_set(d->base.lmsstate.dev, d->base.lmsstate.subdev, I2C_BUS_LP8758_FPGA, d->ssdr_pro ? 1 : 2, vdd_mv); } @@ -2055,6 +2027,7 @@ int xsdr_init(xsdr_dev_t *d) const bool tx_mmcm = ((phycfg_id & PHY_CFG_TX_MMCM) == PHY_CFG_TX_MMCM); const bool rx_mmcm = ((phycfg_id & PHY_CFG_RX_MMCM) == PHY_CFG_RX_MMCM); const bool sep_clkdiv = ((phycfg_id & PHY_CFG_SEP_CLKDIV_MSK) == PHY_CFG_SEP_CLKDIV_MSK); + const bool has_duc_ddc = ((phycfg_id & PHY_CFG_HAS_DUC_DDC) == PHY_CFG_HAS_DUC_DDC); d->hwid = hwid; d->hwchans_rx = 2; // Defaults to MIMO; @@ -2071,6 +2044,7 @@ int xsdr_init(xsdr_dev_t *d) d->ssdr_pro = false; d->xilinx_usp = false; d->lms8_mode_b = false; + d->has_duc_ddc = has_duc_ddc; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); if (res) { @@ -2163,10 +2137,6 @@ int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen) 0, 0, XSDR_SR_MAXCONVRATE | XSDR_SR_EXTENDED_CGEN); } - if (rxen) { - res = (res) ? res : dev_gpo_set(dev, IGPO_DSP_RST, 1); - res = (res) ? res : dev_gpo_set(dev, IGPO_DSP_RST, 0); - } res = (res) ? res : dev_gpo_set(dev, IGPO_LMS_PWR, IGPO_LMS_PWR_LDOEN | IGPO_LMS_PWR_NRESET | (rxen ? IGPO_LMS_PWR_RXEN : 0) | (txen ? IGPO_LMS_PWR_TXEN : 0)); @@ -2192,73 +2162,101 @@ int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen) } - -int xsdr_rfe_pwrdc_get(xsdr_dev_t *d, int *meas1000db) +// Calculate power in dbfs +int xsdr_rfe_pwrdc_get(xsdr_dev_t *d, unsigned acc_norm, int prev_gen, unsigned chan_no, int *meas1000db) { int32_t val[2]; - int res = lowlevel_reg_rdndw(d->base.lmsstate.dev, 0, M2PCI_REG_RD_AVGIDC, (uint32_t*)&val[0], 2); - if (res) - return res; + int gen, gen_n; + int res = 0; + + do { + res = res ? res : xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &gen); + if (res) + return res; + + // USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "[]%d->%d %d %d\n", prev_gen, gen, val[0], val[1]); + if (prev_gen == gen) + return -EAGAIN; - int64_t i = val[0]; - int64_t q = val[1]; - uint64_t pwr = i * i + q * q; - if (pwr == 0) - return -EAGAIN; + res = res ? res : xsdr_phy_dc_estim_get(d, chan_no ? DC_ESTIM_BI : DC_ESTIM_AI, &val[0]); + res = res ? res : xsdr_phy_dc_estim_get(d, chan_no ? DC_ESTIM_BQ : DC_ESTIM_AQ, &val[1]); + res = res ? res : xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &gen_n); + if (res) + return res; - *meas1000db = (1000 * 10 * log10(pwr) - 186639); + + } while (gen != gen_n); + + double fs_i = val[0]; + double fs_q = val[1]; + double i = (0.5 + (fs_i / acc_norm / 65536)) / 2048; // Static correction by +0.5 bits in FPGA + double q = (0.5 + (fs_q / acc_norm / 65536)) / 2048; // Static correction by +0.5 bits in FPGA + double pwr_d = i * i + q * q; + + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "%d->%d %d %d => %.3f %.3f\n", + prev_gen, gen, val[0], val[1], i * 2048, q * 2048); + + if (pwr_d <= 1e-18) + pwr_d = 1e-18; + + *meas1000db = (1000 * 10 * log10(pwr_d)); return 0; } + + // Calibration int xsdrcal_set_nco_offset(void* param, int channel, int32_t freqoffset) { - //xsdr_dev_t *d = (xsdr_dev_t *)param; + xsdr_dev_t *d = (xsdr_dev_t *)param; //d->rxdsp_freq_offset = freqoffset; //return sfe_rf4_nco_freq(d->base.lmsstate.dev, 0, CSR_RFE4_BASE, freqoffset); - return -EINVAL; + //return -EINVAL; + return lms7002m_bb_set_freq(&d->base, channel ? LMS7_CH_B : LMS7_CH_A, false, freqoffset); } -int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* func) +int xsdr_rxdccorr(xsdr_dev_t *d, uint64_t *ov) { - xsdr_dev_t *d = (xsdr_dev_t *)param; - int res; - unsigned idx = 0; - int meas1000db; - int accum = 0; - int aidx = 1; //4; - - // 64 - 8M - for (unsigned g = 16; g < 24; g++, idx++) { - if (logduration <= (1 << g)) - break; + int out = 0, out2 = 0; + int res = xsdrcal_do_meas_nco_avg(d, 0, 0, &out); + res = xsdrcal_do_meas_nco_avg(d, 1, 0, &out2); - // Do accumulation of power vs I/Q, might lead to more reliable results, - // aidx <<= idx; - // idx = 0; - } + *ov = out; + return res; +} - for (unsigned k = 0; k < aidx; k++) { - //res = sfe_rf4_nco_enable(d->base.lmsstate.dev, 0, CSR_RFE4_BASE, func ? true : false, idx); - res = -EINVAL; - if (res) - return res; +int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* func) +{ + xsdr_dev_t *d = (xsdr_dev_t *)param; + int res = 0; + int meas1000db = 0; + int accum = 0, gen = 0; + unsigned acc_idx = 16; - if (!func) - return 0; + if (!func) + return 0; - for (unsigned k = 0; k < 8000; k++) { - res = xsdr_rfe_pwrdc_get(d, &meas1000db); - if (res != -EAGAIN) { - accum += meas1000db; - break; - } + res = res ? res : xsdr_phy_dc_estim_accum(d, acc_idx); + res = res ? res : xsdr_phy_dc_estim_start(d, false); + res = res ? res : usleep(1); + res = res ? res : xsdr_phy_dc_estim_start(d, true); + res = res ? res : xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &gen); + if (res) + return res; - usleep(1000); + for (unsigned k = 0; k < 8000; k++) { + res = xsdr_rfe_pwrdc_get(d, acc_idx, gen, channel, &meas1000db); + if (res != -EAGAIN) { + accum += meas1000db; + break; } + + usleep(1000); } - *func = accum / aidx; + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MEAS[%d] = %.3f\n", channel, meas1000db/1e3); + + *func = accum; return res; } @@ -2279,8 +2277,8 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch { ops->adcrate = d->base.cgen_clk / d->base.rxcgen_div; ops->dacrate = d->base.cgen_clk / d->base.txcgen_div; - ops->rxsamplerate = ops->adcrate / d->base.rxtsp_div; - ops->txsamplerate = ops->dacrate / d->base.txtsp_div; + ops->rxsamplerate = ops->adcrate / d->base.rxtsp_div;// / d->base.rx_dsp_decim; + ops->txsamplerate = ops->dacrate / d->base.txtsp_div;// / d->base.tx_dsp_inter; ops->rxfrequency = d->base.rx_lo; ops->txfrequency = d->base.tx_lo; @@ -2339,8 +2337,9 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch static int _xsdr_path_lb(xsdr_dev_t *d, unsigned rx_rfic_lna, unsigned tx_rfic_band, unsigned channel, bool to_rx) { - int res; + int res = 0; unsigned path; + unsigned lb_loss = 0; if (to_rx) { switch (rx_rfic_lna) { @@ -2357,11 +2356,10 @@ static int _xsdr_path_lb(xsdr_dev_t *d, unsigned rx_rfic_lna, unsigned tx_rfic_b } } - res = xsdr_rfic_fe_set_lna(d, channel == 0 ? LMS7_CH_A : LMS7_CH_B, path); - if (res) - return res; + res = res ? res : xsdr_rfic_fe_set_lna(d, channel == 0 ? LMS7_CH_A : LMS7_CH_B, path); + res = res ? res : lms7002m_rfe_gain(&d->base.lmsstate, RFE_GAIN_RFB, lb_loss, NULL); - return 0; + return res; } // Modification tables @@ -2401,7 +2399,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) } res = (res) ? res : xsdrcal_init_calibrate(d, &cops, channel); - res = (res) ? res : xsdr_rfic_streaming_xflags(d, channel == 1 ? RFIC_SWAP_AB : 0, 0); + // res = (res) ? res : xsdr_rfic_streaming_xflags(d, channel == 1 ? RFIC_SWAP_AB : 0, 0); res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); if (res) return res; @@ -2412,12 +2410,10 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) // Do not touch anything since it may affect optimal I/Q correction values // Turn OFF digital RX LO cancellation in RSP res = (res) ? res : xsdrcal_set_nco_offset(d, channel, 0); - //res = (res) ? res : lms7_rxtsp_dc_corr_off(&d->base.lmsstate); res = (res) ? res : lms7002m_rxtsp_dc_corr(&d->base.lmsstate, true, 0); res = (res) ? res : calibrate_rxlo(&cops); if (!norestore) { - //res = (res) ? res : lms7_rxtsp_dc_corr(&d->base.lmsstate, 7); res = (res) ? res : lms7002m_rxtsp_dc_corr(&d->base.lmsstate, false, 7); } @@ -2448,15 +2444,13 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if (!externallb) { res = (res) ? res : _xsdr_path_lb(d, rx_rfic_lna, tx_rfic_band, channel, true); } - res = calibrate_rxiqimb(&cops); + res = (res) ? res : calibrate_rxiqimb(&cops); if (tx_lo) { - res = (res) ? res : lms7002m_sxx_tune(&d->base.lmsstate, SXX_RX, d->base.fref, tx_lo, false); + res = (res) ? res : lms7002m_sxx_tune(&d->base.lmsstate, SXX_RX, d->base.fref, tx_lo, false); } else { // Looks like TX was off, turn it off res = (res) ? res : lms7002m_sxx_disable(&d->base.lmsstate, SXX_RX); - //res = (res) ? res : lms7_trf_disable(&d->lmsstate); - //res = (res) ? res : lms7_afe_ctrl(&d->lmsstate, true, false, false, false); } if (res) { USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " RXIQIMB failed: res=%d\n", res); @@ -2482,8 +2476,6 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if (param & XSDR_CAL_TXLO) { USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "------------------ Calibration TXLO(%c) ------------------\n", 'A' + channel); - // res = (res) ? res : lms7_txtsp_dc_corr(&d->base.lmsstate, true); - // res = (res) ? res : lms7002m_xxtsp_dc_corr(&d->base.lmsstate, LMS_TXTSP, false, 0); res = (res) ? res : calibrate_txlo(&cops); if (res) { USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " TXLO failed: res=%d\n", res); @@ -2508,18 +2500,20 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) } } - if (rx_lo > 0) { - res = (res) ? res : lms7002m_sxx_tune(&d->base.lmsstate, SXX_TX, d->base.fref, rx_lo, false); - } else { - res = (res) ? res : lms7002m_sxx_disable(&d->base.lmsstate, SXX_TX); - } - if (res) { - USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, "restore configuration failed: res=%d\n", res); - return res; + if (!norestore) { + if (rx_lo > 0) { + res = (res) ? res : lms7002m_sxx_tune(&d->base.lmsstate, SXX_RX, d->base.fref, rx_lo, false); + } else { + res = (res) ? res : lms7002m_sxx_disable(&d->base.lmsstate, SXX_RX); + } + if (res) { + USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, "restore configuration failed: res=%d\n", res); + return res; + } } } if (norestore) - return 0; + goto restore_rxcfg; USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "Calibration: restoring RXPATH=%d TXPATH=%d TXCFG=%d RXCFG=%d\n", old_rx_lna, old_tx_lna, old_dsp_txcfg, old_dsp_rxcfg); @@ -2540,8 +2534,8 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); restore_rxcfg: - res = (res) ? res : xsdrcal_do_meas_nco_avg(d, channel, 0, NULL); - res = (res) ? res : xsdr_rfic_streaming_xflags(d, old_dsp_rxcfg, 0); + // res = (res) ? res : xsdrcal_do_meas_nco_avg(d, channel, 0, NULL); + // res = (res) ? res : xsdr_rfic_streaming_xflags(d, old_dsp_rxcfg, 0); res = (res) ? res : xsdrcal_set_tx_testsig(d, channel, 0, UINT_MAX); return res; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index c8324c67..45ba1ec9 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -50,6 +50,8 @@ struct xsdr_dev uint8_t hwchans_rx; uint8_t hwchans_tx; + unsigned s_rx_dec; + unsigned s_tx_int; unsigned s_rxrate; unsigned s_txrate; unsigned s_adcclk; @@ -86,6 +88,7 @@ struct xsdr_dev bool lms8_int_mode; bool lms8_mode_b; bool xilinx_usp; + bool has_duc_ddc; bool dpump; //Dual pump data union { @@ -107,6 +110,9 @@ struct xsdr_dev uint32_t lms8st_int_mod; uint32_t lms8st_enabled; + // Statistics + double actual_rx_freq; + double actual_tx_freq; }; typedef struct xsdr_dev xsdr_dev_t; @@ -237,6 +243,7 @@ enum { XSDR_DONT_SETBACK = 65536, }; +int xsdr_rxdccorr(xsdr_dev_t *d, uint64_t *ov); int xsdr_usbclk(xsdr_dev_t *d, bool uclk); @@ -271,6 +278,12 @@ enum { IGPO_LDOLMS_EN = 17, IGPO_LED = 18, IGPO_PHYCAL = 19, + + IGPO_DSPCHAIN_RX_PRG = 20, + IGPO_DSPCHAIN_RX_RST = 21, + IGPO_DSPCHAIN_TX_PRG = 22, + IGPO_DSPCHAIN_TX_RST = 23, + }; enum { diff --git a/src/lib/device/u3_limesdr/limesdr_ctrl.c b/src/lib/device/u3_limesdr/limesdr_ctrl.c index ea535b2f..a52a0f48 100644 --- a/src/lib/device/u3_limesdr/limesdr_ctrl.c +++ b/src/lib/device/u3_limesdr/limesdr_ctrl.c @@ -398,7 +398,7 @@ int limesdr_set_samplerate(limesdr_dev_t *d, unsigned rx_rate, unsigned tx_rate, // LML2 - RX // LML1 - TX res = lms7002m_samplerate(&d->base, rx_rate, tx_rate, adc_rate, dac_rate, - XSDR_SR_MAXCONVRATE | XSDR_LML_SISO_DDR_RX | XSDR_LML_SISO_DDR_TX, false); + XSDR_SR_MAXCONVRATE | XSDR_LML_SISO_DDR_RX | XSDR_LML_SISO_DDR_TX, false, 1, 1); // TODO set direct mode or do PLL with phase search res = res ? res : limesdr_set_direct_clocking(d, 0); diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index 0940b566..a706088f 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -202,6 +202,25 @@ int lms7002m_cgen_trim_vco(lms7002m_state_t* m, int vco_cap) GET_LMS7002M_CGEN_0X008C_VCO_CMPLO(reg)); } +int lms7002m_cgen_trim_vco_slow(lms7002m_state_t* m, int vco_cap) +{ + uint16_t reg; + uint32_t cgen_regs[] = { MAKE_LMS7002M_CGEN_0x008B(15, (unsigned)vco_cap, 0) }; + int res = lms7002m_spi_post(m, cgen_regs, SIZEOF_ARRAY(cgen_regs)); + if (res) + return res; + + res = lms7002m_spi_rd(m, CGEN_0x008C, ®); + if (res) + return res; + + usleep(1000); + + return (int)((GET_LMS7002M_CGEN_0X008C_VCO_CMPHO(reg) << 1) | + GET_LMS7002M_CGEN_0X008C_VCO_CMPLO(reg)); +} + + int lms7002m_sxx_trim_vco(lms7002m_state_t* m, int vco_cap) { uint16_t reg; @@ -592,9 +611,14 @@ int lms7002m_cgen_tune(lms7002m_state_t* m, unsigned fref, unsigned outfreq, uns usleep(20); uint8_t hi = 255, lo = 0; - res = _lms7002m_vco_range(m, &lms7002m_cgen_trim_vco, (unsigned)-1, &hi, &lo, "CGEN", 0); - if (res < 0) - return res; + for (unsigned a = 0; a < 2; a++) { + res = _lms7002m_vco_range(m, a == 0 ? &lms7002m_cgen_trim_vco : &lms7002m_cgen_trim_vco_slow, (unsigned)-1, &hi, &lo, "CGEN", 0); + if (res < 0) + return res; + + if (hi >= lo) + break; + } if (hi < lo) { USDR_LOG("7002", USDR_LOG_WARNING, "CGEN: Can't find sutable VCO cap!"); @@ -697,7 +721,9 @@ int lms7002m_sxx_tune(lms7002m_state_t* m, lms7002m_sxx_path_t path, unsigned fr 1), MAKE_LMS7002M_SXX_0x011F(3, 3, 6, 0, 0, 0, 0), }; - res = lms7002m_spi_post(m, sxx_regs, SIZEOF_ARRAY(sxx_regs)); + + //Select only MAC if VCO was powered before + res = lms7002m_spi_post(m, sxx_regs, pwr ? 1 : SIZEOF_ARRAY(sxx_regs)); if (res) return res; @@ -1205,15 +1231,18 @@ int lms7002m_rfe_gain(lms7002m_state_t* m, lms7002m_rfe_gain_t gain, int gainx10 switch (gain) { case RFE_GAIN_LNA: idx = _find_idx(-gainx10, lna_attens, SIZEOF_ARRAY(lna_attens) - 1); - *goutx10 = -lna_attens[idx]; + if (goutx10) + *goutx10 = -lna_attens[idx]; goto update_vals; case RFE_GAIN_TIA: idx = _find_idx(-gainx10, tia_attens, SIZEOF_ARRAY(tia_attens) - 1); - *goutx10 = -tia_attens[idx]; + if (goutx10) + *goutx10 = -tia_attens[idx]; goto update_vals; case RFE_GAIN_RFB: idx = _find_idx(-gainx10, lb_attens, SIZEOF_ARRAY(lb_attens) - 1); - *goutx10 = -lb_attens[idx]; + if (goutx10) + *goutx10 = -lb_attens[idx]; goto update_vals; update_vals: for (unsigned i = 0; i < 2; i++) { @@ -1329,17 +1358,43 @@ int lms7002m_trf_gain(lms7002m_state_t* m, lms7002m_trf_gain_t gt, int gainx10, for (unsigned i = 0; i < 2; i++) { uint16_t mac = m->reg_mac; unsigned lb_loss = m->trf[i].lb ? m->trf[i].lbloss : LB_LOSS_24; + unsigned main_gain = m->trf[i].lb ? m->trf[i].gain : m->trf[i].gain; + SET_LMS7002M_LML_0X0020_MAC(mac, i + 1); + regs[j++] = MAKE_LMS7002M_REG_WR(LML_0x0020, mac); + regs[j++] = MAKE_LMS7002M_TRF_0x0101( + 3, // F_TXPAD_TRF, + lb_loss, // L_LOOPB_TXPAD_TRF, + main_gain, // LOSS_LIN_TXPAD_TRF, + main_gain, // LOSS_MAIN_TXPAD_TRF, + m->trf[i].lb); // EN_LOOPB_TXPAD_TRF + + USDR_LOG("7002", USDR_LOG_INFO, "trf_gain[%d] lb_loss=%d loss=%d en_lb=%d\n", + i, lb_loss, main_gain, m->trf[i].lb); + }; + regs[j++] = MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac); + + return lms7002m_spi_post(m, regs, j); +} + +int lms7002m_trf_gain_lb_off(lms7002m_state_t* m) +{ + if (_lms7002m_is_none(m)) + return -EINVAL; + + uint32_t regs[2 * 3 + 2], j = 0; + for (unsigned i = 0; i < 2; i++) { + uint16_t mac = m->reg_mac; SET_LMS7002M_LML_0X0020_MAC(mac, i + 1); regs[j++] = MAKE_LMS7002M_REG_WR(LML_0x0020, mac); regs[j++] = MAKE_LMS7002M_TRF_0x0101( 3, //F_TXPAD_TRF, - lb_loss, //L_LOOPB_TXPAD_TRF, + LB_LOSS_24, //L_LOOPB_TXPAD_TRF, m->trf[i].gain, //LOSS_LIN_TXPAD_TRF, m->trf[i].gain, //LOSS_MAIN_TXPAD_TRF, m->trf[i].lb); //EN_LOOPB_TXPAD_TRF USDR_LOG("7002", USDR_LOG_INFO, "trf_gain[%d] lb_loss=%d loss=%d en_lb=%d\n", - i, lb_loss, m->trf[i].gain, m->trf[i].lb); + i, LB_LOSS_24, m->trf[i].gain, m->trf[i].lb); }; regs[j++] = MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac); diff --git a/src/lib/hw/lms7002m/lms7002m.h b/src/lib/hw/lms7002m/lms7002m.h index 9431687f..1d0716d5 100644 --- a/src/lib/hw/lms7002m/lms7002m.h +++ b/src/lib/hw/lms7002m/lms7002m.h @@ -249,6 +249,7 @@ enum lms7002m_lb_loss { }; int lms7002m_trf_gain(lms7002m_state_t* m, lms7002m_trf_gain_t gt, int gainx10, int *goutx10); +int lms7002m_trf_gain_lb_off(lms7002m_state_t* m); // RBB enum lms7002m_rbb_path { diff --git a/src/lib/ipblks/fgearbox.c b/src/lib/ipblks/fgearbox.c index 30ea70ae..2f9339ee 100644 --- a/src/lib/ipblks/fgearbox.c +++ b/src/lib/ipblks/fgearbox.c @@ -1320,19 +1320,27 @@ static int dev_gpo_set(lldev_t dev, unsigned bank, unsigned data) return lowlevel_reg_wr32(dev, 0, 0, ((bank & 0x7f) << 24) | (data & 0xff)); } -int fgearbox_load_ucode(lldev_t dev, unsigned gport, const uint8_t* ucode) +int fgearbox_load_ucode(lldev_t dev, unsigned gport, const uint8_t* ucode, unsigned sleep_us) { int res; for (unsigned i = 0; i < UCODE_SIZE; i++) { res = dev_gpo_set(dev, gport, ucode[i]); if (res) return res; + + if (sleep_us) { + usleep(sleep_us); + } } return 0; } - int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam) +{ + return fgearbox_load_fir_ex(dev, gport, fir, fam, 0); +} + +int fgearbox_load_fir_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us) { const uint8_t* s_st8_dsp; @@ -1391,11 +1399,16 @@ int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamil return -EINVAL; } - return fgearbox_load_ucode(dev, gport, s_st8_dsp); + return fgearbox_load_ucode(dev, gport, s_st8_dsp, sleep_us); } int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam) +{ + return fgearbox_load_fir_i_ex(dev, gport, fir, fam, 0); +} + +int fgearbox_load_fir_i_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us) { const uint8_t* s_st8_dsp; @@ -1431,7 +1444,7 @@ int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfam return -EINVAL; } - return fgearbox_load_ucode(dev, gport, s_st8_dsp); + return fgearbox_load_ucode(dev, gport, s_st8_dsp, sleep_us); } diff --git a/src/lib/ipblks/fgearbox.h b/src/lib/ipblks/fgearbox.h index af384c45..b5132052 100644 --- a/src/lib/ipblks/fgearbox.h +++ b/src/lib/ipblks/fgearbox.h @@ -40,4 +40,7 @@ typedef enum dspfamily { int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam); int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam); +int fgearbox_load_fir_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us); +int fgearbox_load_fir_i_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us); + #endif From df72db3cbbc075c4c336d89831e4ac5630b1ffc0 Mon Sep 17 00:00:00 2001 From: Timur Davydov Date: Mon, 16 Mar 2026 17:44:19 +0400 Subject: [PATCH 362/397] tools/python: guard optional SoapySDR Device.close() call --- src/tools/python/example_fft_rx_soapy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/python/example_fft_rx_soapy.py b/src/tools/python/example_fft_rx_soapy.py index 682d0215..f83f4d25 100755 --- a/src/tools/python/example_fft_rx_soapy.py +++ b/src/tools/python/example_fft_rx_soapy.py @@ -121,7 +121,8 @@ def main() -> None: dev.closeStream(rx_stream) # Close device - dev.close() # Not strictly necessary, but good practice + if dev.close is not None: + dev.close() # Not strictly necessary, but good practice dev = None psd = psd_acc / args.accumulation From 4f8ee6ff23b650bdd7dbd16829e9fc7f04a98f1f Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 17 Mar 2026 03:16:44 +0400 Subject: [PATCH 363/397] xsdr: fix frequency operations for freq>4Ghz --- src/lib/device/dev_param.h | 2 +- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 23 ++++---- src/lib/device/m2_lm7_1/lms7002m_ctrl.h | 9 ++++ src/lib/device/m2_lm7_1/xsdr_ctrl.c | 70 +++++++++++++++++++++++-- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 7 ++- 5 files changed, 92 insertions(+), 19 deletions(-) diff --git a/src/lib/device/dev_param.h b/src/lib/device/dev_param.h index 37b0d4f8..2e8c0c46 100644 --- a/src/lib/device/dev_param.h +++ b/src/lib/device/dev_param.h @@ -46,7 +46,7 @@ static inline void opt_u64_set_val(opt_u64_t* p, unsigned val) struct freq_auto_band_map { - unsigned stop_freq; + uint64_t stop_freq; uint8_t band; uint8_t sw : 4; uint8_t swlb : 4; diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 2b7cbcf1..fe053553 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -18,13 +18,6 @@ #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif -enum sigtype { - XSDR_TX_LO_CHANGED, - XSDR_RX_LO_CHANGED, - XSDR_TX_LNA_CHANGED, - XSDR_RX_LNA_CHANGED, -}; - static unsigned _ulog(unsigned d) { switch (d) { @@ -49,7 +42,7 @@ static int get_antenna_cfg_by_name(const char* name, const freq_auto_band_map_t* return -1; } -static int get_antenna_cfg_by_freq(unsigned freq, const freq_auto_band_map_t* maps, unsigned max) +static int get_antenna_cfg_by_freq(uint64_t freq, const freq_auto_band_map_t* maps, unsigned max) { unsigned i; for (i = 0; i < max - 1; i++) { @@ -84,6 +77,7 @@ int lms7002m_init(lms7002_dev_t* d, lldev_t dev, unsigned subdev, unsigned refcl d->lmsstate.dev = dev; d->lmsstate.subdev = subdev; d->fref = refclk; + d->on_custom_signal = NULL; d->rx_rfic_path = XSDR_RX_AUTO; d->tx_rfic_path = XSDR_TX_AUTO; @@ -183,7 +177,9 @@ static int _lms7002m_signal_event(lms7002_dev_t *d, enum sigtype t) res = lms7002m_mac_set(&d->lmsstate, LMS7_CH_AB); case XSDR_RX_LNA_CHANGED: if (d->rx_rfic_path == XSDR_RX_AUTO) { - cfgidx = get_antenna_cfg_by_freq(d->rx_lo, d->cfg_auto_rx, MAX_RX_BANDS); + cfgidx = (d->on_custom_signal) ? + d->on_custom_signal(d, t) : + get_antenna_cfg_by_freq(d->rx_lo, d->cfg_auto_rx, MAX_RX_BANDS); USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Auto RX band selection: %s\n", d->cfg_auto_rx[cfgidx].name0); @@ -194,7 +190,9 @@ static int _lms7002m_signal_event(lms7002_dev_t *d, enum sigtype t) res = lms7002m_mac_set(&d->lmsstate, LMS7_CH_AB); case XSDR_TX_LNA_CHANGED: if (d->tx_rfic_path == XSDR_TX_AUTO) { - cfgidx = get_antenna_cfg_by_freq(d->tx_lo, d->cfg_auto_tx, MAX_TX_BANDS); + cfgidx = (d->on_custom_signal) ? + d->on_custom_signal(d, t) : + get_antenna_cfg_by_freq(d->tx_lo, d->cfg_auto_tx, MAX_TX_BANDS); USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Auto TX band selection: %s\n", d->cfg_auto_tx[cfgidx].name0); @@ -438,7 +436,8 @@ int lms7002m_rfe_set_path(lms7002_dev_t *d, d->rx_rfic_path = path; if (path == XSDR_RX_AUTO) { - cfgidx = get_antenna_cfg_by_freq(d->rx_lo, d->cfg_auto_rx, MAX_RX_BANDS); + res = _lms7002m_signal_event(d, XSDR_RX_LNA_CHANGED); + goto finish; } else { cfgidx = get_antenna_cfg_by_band(band, d->cfg_auto_rx, MAX_RX_BANDS); } @@ -447,6 +446,8 @@ int lms7002m_rfe_set_path(lms7002_dev_t *d, res = (res) ? res : _lms7002m_set_lna_rx(d, cfgidx); + +finish: if (lb_change) { res = (res) ? res : _lms7002m_lb_status_changes(d); } diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h index 6a4153b8..a710f0db 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h @@ -63,6 +63,14 @@ enum { struct lms7002_dev; typedef struct lms7002_dev lms7002_dev_t; +enum sigtype { + XSDR_TX_LO_CHANGED, + XSDR_RX_LO_CHANGED, + XSDR_TX_LNA_CHANGED, + XSDR_RX_LNA_CHANGED, +}; + +typedef int (*on_change_signal_t)(lms7002_dev_t *d, enum sigtype t); typedef int (*on_change_antenna_port_sw_t)(lms7002_dev_t* dev, int direction, unsigned sw); typedef const lms7002m_lml_map_t (*on_get_lml_portcfg_t)(bool rx, unsigned chs, unsigned flags, bool no_siso_map); @@ -73,6 +81,7 @@ struct lms7002_dev // Callbacks on_change_antenna_port_sw_t on_ant_port_sw; on_get_lml_portcfg_t on_get_lml_portcfg; + on_change_signal_t on_custom_signal; // RFIC state uint8_t rx_cfg_path; // Configuration index in cfg_auto_rx diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index e8df489c..79d83211 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1365,7 +1365,15 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, double *actualfreq) { int res = 0; - + double original = freq; + double actual_lms7; + double actual_lms8 = 0; + int64_t lms8_freq = 0; + uint64_t other_freq = (type == RFIC_LMS7_TUNE_RX_FDD) ? d->freq_txlo : d->freq_rxlo; + bool current_changed = false; + bool other_active = (other_freq > d->lms8_switchover_freq) && ((type == RFIC_LMS7_TUNE_RX_FDD) ? + (d->base.tx_run[0] || d->base.tx_run[1]) : + (d->base.rx_run[0] || d->base.rx_run[1])); if (d->ssdr && freq > d->lms8_switchover_freq) { float bwef = d->lms8st_bwef_1000 / 1000.0; unsigned lob = (d->lms7_lob == 0) ? 2.01e9 : d->lms7_lob; @@ -1375,12 +1383,28 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, (d->base.rx_run[0] ? 1 << LMS8_RXA_CHIDX : 0) | (d->base.rx_run[1] ? 1 << LMS8_RXB_CHIDX : 0); - int64_t lms8_freq; + if (other_active) { + double delta = fabs(original - other_freq); + if (delta > 1.5e9) { + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "Both TX & RX path use high band, however RX and TX freqs are %.3f Mhz apart! sSDR use shared LO for both RX & TX: either reduce delta or use different bands\n", + delta / 1e6); + return -EINVAL; + } + } + if (d->lms8_int_mode) { - lms8_freq = (freq - lob + d->base.fref / 2) / d->base.fref; + if (other_active) { + lms8_freq = (((freq + other_freq) / 2) - lob + d->base.fref / 2) / d->base.fref; + } else { + lms8_freq = (freq - lob + d->base.fref / 2) / d->base.fref; + } lms8_freq *= d->base.fref; } else { - lms8_freq = freq - lob; + if (other_active) { + lms8_freq = ((freq + other_freq) / 2) - lob; + } else { + lms8_freq = freq - lob; + } } lob = freq - lms8_freq; @@ -1418,25 +1442,57 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "Setting FREQ %.3f Mhz, LNB %.3f Mhz\n", freq / 1.0e6, lob / 1.0e6); freq = lob; + actual_lms8 = d->lms8_lo_freq; + current_changed = true; } if (type == RFIC_LMS7_TUNE_RX_FDD && d->lms7_rxlo_last == freq) return 0; if (type == RFIC_LMS7_TUNE_TX_FDD && d->lms7_txlo_last == freq) return 0; + if (type == RFIC_LMS7_TUNE_RX_FDD) + d->freq_rxlo = original; + if (type == RFIC_LMS7_TUNE_TX_FDD) + d->freq_txlo = original; - res = lms7002m_fe_set_freq(&d->base, channel, type, freq, actualfreq); + res = lms7002m_fe_set_freq(&d->base, channel, type, freq, &actual_lms7); if (type == RFIC_LMS7_TUNE_RX_FDD) { d->lms7_rxlo_last = (res == 0) ? freq : 0; } else if (type == RFIC_LMS7_TUNE_TX_FDD) { d->lms7_txlo_last = (res == 0) ? freq : 0; } + if (res == 0 && other_active && current_changed) { + unsigned ntype = (type == RFIC_LMS7_TUNE_RX_FDD) ? RFIC_LMS7_TUNE_TX_FDD : RFIC_LMS7_TUNE_RX_FDD; + double nfreq = other_freq - lms8_freq; + res = lms7002m_fe_set_freq(&d->base, channel, ntype, nfreq, NULL); + + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "Freq configuration updated: RX_LO=%.3f TX_LO=%.3f LMS8_LO=%.3f\n", + d->base.rx_lo / 1e6, d->base.tx_lo / 1e6, lms8_freq / 1e6); + } + + if (res == 0 && actualfreq) { + *actualfreq = actual_lms8 + actual_lms7; + } + // LO correction res = res ? res : lms7002m_dc_corr_en(&d->base.lmsstate, d->base.rx_run[0], d->base.rx_run[1], d->base.tx_run[0], d->base.tx_run[1]); return res; } +int xsdr_on_change_signal(lms7002_dev_t *dev, enum sigtype t) +{ + xsdr_dev_t *d = (xsdr_dev_t *)(dev); + switch (t) { + case XSDR_RX_LO_CHANGED: + case XSDR_RX_LNA_CHANGED: + return (d->freq_rxlo > d->lms8_switchover_freq) ? 1 : 0; + case XSDR_TX_LO_CHANGED: + case XSDR_TX_LNA_CHANGED: + return (d->freq_txlo > d->lms8_switchover_freq) ? 1 : 0; + }; + return 0; +} int xsdr_rfic_rfe_set_path(xsdr_dev_t *d, unsigned path) @@ -2066,6 +2122,10 @@ int xsdr_init(xsdr_dev_t *d) } } + if (d->ssdr) { + d->base.on_custom_signal = &xsdr_on_change_signal; + } + res = (d->new_rev) ? _xsdr_init_revx(d, hwcfg_devid) : _xsdr_init_revo(d); if (res) return res; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 45ba1ec9..bba43fa5 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -58,12 +58,15 @@ struct xsdr_dev unsigned s_dacclk; unsigned s_flags; - unsigned lms7_lob; + unsigned lms7_lob; // Preferred LMS7 lo if set unsigned lms7_rxlo_last; unsigned lms7_txlo_last; - int64_t lms8_lo_freq; unsigned lms8_switchover_freq; + uint64_t freq_rxlo; // LMS7 + LMS8 + uint64_t freq_txlo; // LMS7 + LMS8 + int64_t lms8_lo_freq; + int tx_override_phase; int tx_override_phase_iq; int rx_override_phase; From 122f17cf2160026a5a08a37e3b571a873d304f34 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 17 Mar 2026 03:19:33 +0400 Subject: [PATCH 364/397] xsdr: fix soapy sdr --- src/soapysdr/usdr_soapy.cpp | 38 +++++++++++++++++++++++++++---------- src/soapysdr/usdr_soapy.h | 8 ++++++-- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/soapysdr/usdr_soapy.cpp b/src/soapysdr/usdr_soapy.cpp index 17dce4dc..7d816875 100644 --- a/src/soapysdr/usdr_soapy.cpp +++ b/src/soapysdr/usdr_soapy.cpp @@ -167,6 +167,19 @@ const char* SoapyUSDR::get_sdr_param(int sdridx, const char* dir, const char* pa return _param_name; } +const char* SoapyUSDR::get_sdr_param_chan(int sdridx, const char* dir, const char* par, const char* subpar, unsigned chan) +{ + if (max_sw_rx_chans <= 1 && max_sw_tx_chans <= 1) + return get_sdr_param(sdridx, dir, par, subpar); + + if (subpar) { + snprintf(_param_name, sizeof(_param_name), "/dm/sdr/%d/%s/%s/%s/%d", sdridx, dir, par, subpar, chan); + } else { + snprintf(_param_name, sizeof(_param_name), "/dm/sdr/%d/%s/%s/%d", sdridx, dir, par, chan); + } + return _param_name; +} + SoapyUSDR::SoapyUSDR(const SoapySDR::Kwargs &args_orig) @@ -279,6 +292,11 @@ SoapyUSDR::SoapyUSDR(const SoapySDR::Kwargs &args_orig) uint64_t val; int res; + usdr_dme_get_uint(_dev->dev(), "/ll/sdr/max_hw_rx_chans", &max_hw_rx_chans); + usdr_dme_get_uint(_dev->dev(), "/ll/sdr/max_hw_tx_chans", &max_hw_tx_chans); + usdr_dme_get_uint(_dev->dev(), "/ll/sdr/max_sw_rx_chans", &max_sw_rx_chans); + usdr_dme_get_uint(_dev->dev(), "/ll/sdr/max_sw_tx_chans", &max_sw_tx_chans); + res = usdr_dme_get_uint(_dev->dev(), "/ll/sdr/0/rfic/0", &val); if (res == 0) { const char* rfic = reinterpret_cast(val); @@ -493,7 +511,7 @@ void SoapyUSDR::setGain(const int direction, const size_t channel, const double SoapySDR::logf(callLogLvl(), "SoapyUSDR::setGain(%s, %d, %g dB)", dir, int(channel), value); std::unique_lock lock(_dev->accessMutex); - const char* defparam = get_sdr_param(0, dir, "gain", "auto"); + const char* defparam = get_sdr_param_chan(0, dir, "gain", "auto", channel); int res = usdr_dme_set_uint(_dev->dev(), defparam, value); if (res) { SoapySDR::logf(callLogLvl(), "SoapyUSDR::setGain(%s, %d, %g dB) => %s failed %d", @@ -510,7 +528,7 @@ void SoapyUSDR::setGain(const int direction, const size_t channel, const std::st const rfic_gain_descriptor* gains = get_gains(type); std::unique_lock lock(_dev->accessMutex); - const char* defparam = get_sdr_param(0, dir, "gain", nullptr); + const char* defparam = get_sdr_param_chan(0, dir, "gain", nullptr, channel); unsigned i; for (i = 0; gains[i].name != nullptr; i++) { @@ -593,16 +611,14 @@ void SoapyUSDR::setFrequency(const int direction, const size_t channel, const st int res; const char* dir = (direction == SOAPY_SDR_TX) ? "tx" : "rx"; - const char* pname = get_sdr_param(0, dir, "frequency", (name == "BB") ? "bb" : NULL); - - uint64_t val = (((uint64_t)channel) << 32) | (uint32_t)frequency; + const char* pname = get_sdr_param_chan(0, dir, "frequency", (name == "BB") ? "bb" : NULL, channel); - res = usdr_dme_set_uint(_dev->dev(), pname, - type == RFIC_AFE79XX ? (uint64_t)frequency : val); + res = usdr_dme_set_uint(_dev->dev(), pname, (uint64_t)(int64_t)frequency); if (res) throw std::runtime_error(std::string("SoapyUSDR::setFrequency(") + pname + ", " + std::to_string(frequency) + ")"); - _actual_frequency[direction] = val; + // TODO: refactor this + _actual_frequency[direction] = frequency; } double SoapyUSDR::getFrequency(const int direction, const size_t channel, const std::string &name) const @@ -646,7 +662,9 @@ SoapySDR::RangeList SoapyUSDR::getFrequencyRange(const int /*direction*/, const SoapySDR::RangeList SoapyUSDR::getFrequencyRange(const int /*direction*/, const size_t /*channel*/) const { SoapySDR::RangeList ranges; - if (type == RFIC_AFE79XX) { + if (device_type == DEVICE_SSDR) { + ranges.push_back(SoapySDR::Range(30e6, 11.5e9)); + } else if (type == RFIC_AFE79XX) { ranges.push_back(SoapySDR::Range(5e6, 12.5e9)); } else { ranges.push_back(SoapySDR::Range(0e6, 3.8e9)); @@ -752,7 +770,7 @@ void SoapyUSDR::setBandwidth(const int direction, const size_t channel, const do if (bw == 0.0) return; //special ignore value const char* dir = (direction == SOAPY_SDR_TX) ? "tx" : "rx"; - const char* pname = get_sdr_param(0, dir, "bandwidth", NULL); + const char* pname = get_sdr_param_chan(0, dir, "bandwidth", NULL, channel); int res; SoapySDR::logf(callLogLvl(), "SoapyUSDR::setBandwidth(%s, %g MHz)",dir, bw/1e6); diff --git a/src/soapysdr/usdr_soapy.h b/src/soapysdr/usdr_soapy.h index 8e1d6f9a..190f7669 100644 --- a/src/soapysdr/usdr_soapy.h +++ b/src/soapysdr/usdr_soapy.h @@ -325,8 +325,7 @@ class SoapyUSDR : public SoapySDR::Device }; const char* get_sdr_param(int sdridx, const char* dir, const char* par, const char* subpar); - - enum { MAX_CHANNELS = 2 }; + const char* get_sdr_param_chan(int sdridx, const char* dir, const char* par, const char* subpar, unsigned chan); std::shared_ptr _dev; char _param_name[128]; @@ -350,6 +349,11 @@ class SoapyUSDR : public SoapySDR::Device double avg_gap; + uint64_t max_hw_rx_chans = 1; + uint64_t max_hw_tx_chans = 1; + uint64_t max_sw_rx_chans = 1; + uint64_t max_sw_tx_chans = 1; + // Stats uint64_t rx_pkts; uint64_t tx_pkts; From 865444d0b71aecc280996726f09f296171ed7df1 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 18 Mar 2026 01:18:21 +0400 Subject: [PATCH 365/397] xsdr: update to support TX-only MMCM configuration --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 9 +++++++++ src/lib/device/m2_lm7_1/xsdr_ctrl.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 79d83211..12a2c509 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -398,6 +398,10 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, unsigned vco_div_io = (VCO_MAX + io_clk - 1) / io_clk; bool sep_clkdiv = d->sep_clkdiv; + // No MMCM in RX chain + if (!d->mmcm_single && !d->mmcm_rx && rx_master) + return 0; + vco_div_io += g_clk_reduce; vco_div_io += (txphase_off > 2) ? 2 : txphase_off; @@ -583,6 +587,7 @@ enum HWID_MSKS { PHY_CFG_RX_MMCM = 0x10, PHY_CFG_HAS_DUC_DDC = 0x04, + PHY_CFG_SINGLE_MMCM = 0x01, }; static bool noerrors_v4(unsigned errs[4], uint64_t* badness) @@ -675,6 +680,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) } else if (!d->siso_sdr_active_rx && d->new_rev && !d->ssdr && (d->s_rxrate > 70e6 || d->s_txrate > 70e6)) { res = res ? res : xsdr_set_vio(d, 1940); res = res ? res : xsdr_set_lms125vdd(d, 1320); + } else if (!d->siso_sdr_active_rx && !d->new_rev && (d->s_rxrate > 50e6 || d->s_txrate > 50e6)) { + res = res ? res : xsdr_set_vio(d, ((d->s_rxrate > 60e6 || d->s_txrate > 60e6)) ? 2150 : 1960); } // Fixup for 53-58 MSPS range, but still 58 to 60 might be unoperable on some chips, and 60+ works fine again @@ -2082,6 +2089,7 @@ int xsdr_init(xsdr_dev_t *d) const bool rx_port_is_1 = ((phycfg_id & PHY_CFG_LML2_IS_RX) != PHY_CFG_LML2_IS_RX); const bool tx_mmcm = ((phycfg_id & PHY_CFG_TX_MMCM) == PHY_CFG_TX_MMCM); const bool rx_mmcm = ((phycfg_id & PHY_CFG_RX_MMCM) == PHY_CFG_RX_MMCM); + const bool mmcm_single = ((phycfg_id & PHY_CFG_SINGLE_MMCM) == PHY_CFG_SINGLE_MMCM); const bool sep_clkdiv = ((phycfg_id & PHY_CFG_SEP_CLKDIV_MSK) == PHY_CFG_SEP_CLKDIV_MSK); const bool has_duc_ddc = ((phycfg_id & PHY_CFG_HAS_DUC_DDC) == PHY_CFG_HAS_DUC_DDC); @@ -2093,6 +2101,7 @@ int xsdr_init(xsdr_dev_t *d) d->rx_port_is_1 = rx_port_is_1; d->mmcm_rx = rx_mmcm; d->mmcm_tx = tx_mmcm; + d->mmcm_single = mmcm_single; d->sep_clkdiv = sep_clkdiv; d->cfg_srate_siso_rx = 0; d->cfg_srate_siso_tx = 0; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index bba43fa5..ea9890cf 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -82,6 +82,7 @@ struct xsdr_dev bool rx_port_is_1; bool mmcm_tx; bool mmcm_rx; + bool mmcm_single; bool sep_clkdiv; bool pwr_en; bool new_rev; From 1c9e0503bdd3c17e5a59bc1974b28acda286174b Mon Sep 17 00:00:00 2001 From: vd Date: Wed, 18 Mar 2026 21:42:59 +0400 Subject: [PATCH 366/397] Add example FFT TX script using SoapySDR for sine wave transmission --- src/tools/python/example_fft_tx_soapy.py | 165 +++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100755 src/tools/python/example_fft_tx_soapy.py diff --git a/src/tools/python/example_fft_tx_soapy.py b/src/tools/python/example_fft_tx_soapy.py new file mode 100755 index 00000000..8155ff78 --- /dev/null +++ b/src/tools/python/example_fft_tx_soapy.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +"""Generate a sine wave and transmit IQ samples via USDR (using SoapySDR). + +Example: + python3 example_fft_tx_soapy.py \ + --device "driver=usdr" \ + --tx-frequency 900e6 \ + --tx-bandwidth 5e6 \ + --tx-gain 16 \ + --samplerate 5e6 \ + --tone-offset 1000e3 \ + --amplitude 0.9 \ + --burst-size 4096 \ + --num-bursts 8192 \ + --loglevel 3 + + Parameter `device` can be any SoapySDR device string, e.g. "driver=usdr" or "driver=usdr,bus=" + device_bus can be: + - bus=pci,device=, where is the PCI device Path (e.g. /dev/usdr0) + - bus=usb@, where is the USB address (e.g. 3/3/6 for bus 3, device 3, function 6) +""" + +from __future__ import annotations + +import argparse +import numpy as np + +import SoapySDR +from SoapySDR import SOAPY_SDR_TX + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="USDR TX sine wave generator") + parser.add_argument("--device", default="", help="USDR device string") + parser.add_argument("--samplerate", type=float, default=5e6, help="Sample rate in SPS") + parser.add_argument("--loglevel", type=int, default=None, help="Optional libusdr log level") + parser.add_argument("--tx-frequency", type=float, required=True, help="TX center frequency in Hz") + parser.add_argument("--tx-bandwidth", type=float, required=True, help="TX bandwidth in Hz") + parser.add_argument("--tx-gain", type=float, default=0, help="TX gain value") + + parser.add_argument("--tone-offset", type=float, default=100e3, help="Tone frequency offset from center in Hz") + parser.add_argument("--amplitude", type=float, default=0.9, help="Tone amplitude (0.0 .. 1.0)") + parser.add_argument("--burst-size", type=int, default=4096, help="Number of samples per write burst") + parser.add_argument("--num-bursts", type=int, default=128, help="Number of bursts to transmit (0 = infinite)") + parser.add_argument("--channel", type=int, default=0, help="TX channel index") + parser.add_argument("--timeout-ms", type=int, default=1000, help="Write timeout in milliseconds") + + return parser.parse_args() + + +# Allocate a 64-byte-aligned buffer to avoid AVX512 alignment issues +def aligned_empty(shape, dtype, alignment=64): + dtype = np.dtype(dtype) + n_elems = int(np.prod(shape)) + nbytes = n_elems * dtype.itemsize + raw = np.empty(nbytes + alignment, dtype=np.uint8) + start = raw.ctypes.data + offset = (-start) % alignment + buf = raw[offset:offset + nbytes].view(dtype) + return buf.reshape(shape) + + +def generate_tone(n_samples: int, samplerate: float, tone_offset: float, + amplitude: float, phase_offset: float = 0.0) -> tuple[np.ndarray, float]: + """Generate a complex sine tone and return (samples, next_phase_offset). + + Keeping track of *phase_offset* across successive calls ensures a continuous + waveform without discontinuities at burst boundaries. + """ + t = np.arange(n_samples, dtype=np.float64) / samplerate + phase = 2.0 * np.pi * tone_offset * t + phase_offset + iq = amplitude * np.exp(1j * phase) + + # Compute the phase right after the last sample so the next call can continue + next_phase = phase[-1] + 2.0 * np.pi * tone_offset / samplerate + next_phase = next_phase % (2.0 * np.pi) + + return iq.astype(np.complex64), next_phase + + +def main() -> None: + args = parse_args() + + if args.burst_size <= 0: + raise ValueError("--burst-size must be > 0") + if args.amplitude < 0.0 or args.amplitude > 1.0: + raise ValueError("--amplitude must be in [0.0, 1.0]") + + burst_size = int(args.burst_size) + + # Open SoapySDR device + if args.device: + dev_kwargs = SoapySDR.KwargsFromString(args.device) + else: + dev_kwargs = SoapySDR.SoapySDRKwargs() + if args.loglevel is not None: + dev_kwargs["loglevel"] = str(int(args.loglevel)) + try: + dev = SoapySDR.Device(dev_kwargs) + except Exception as e: + print(f"Failed to open SoapySDR device: {e}") + exit(1) + + chan = int(args.channel) + + # Configure device + dev.setSampleRate(SOAPY_SDR_TX, chan, float(args.samplerate)) + dev.setFrequency(SOAPY_SDR_TX, chan, float(args.tx_frequency)) + dev.setBandwidth(SOAPY_SDR_TX, chan, float(args.tx_bandwidth)) + dev.setGain(SOAPY_SDR_TX, chan, float(args.tx_gain)) + + # Setup stream for complex float32 (direction, format, channels, args) + args_kw = SoapySDR.SoapySDRKwargs() + args_kw["linkFormat"] = "CS16" # Request int16 samples from driver, also can be "CS12" + args_kw["bufferLength"] = str(int(burst_size)) + tx_stream = dev.setupStream(SOAPY_SDR_TX, "CF32", [chan], args_kw) + dev.activateStream(tx_stream) + + timeout_us = int(args.timeout_ms * 1000) + phase = 0.0 + num_bursts = int(args.num_bursts) + infinite = num_bursts == 0 + + print(f"Transmitting tone at {args.tx_frequency + args.tone_offset:.0f} Hz " + f"(center {args.tx_frequency:.0f} Hz + offset {args.tone_offset:.0f} Hz)") + print(f" samplerate={args.samplerate:.0f} amplitude={args.amplitude} " + f"burst_size={burst_size} num_bursts={'inf' if infinite else num_bursts}") + + # Transmit sine-wave bursts + burst_idx = 0 + try: + while infinite or burst_idx < num_bursts: + tone, phase = generate_tone(burst_size, float(args.samplerate), + float(args.tone_offset), float(args.amplitude), + phase) + + buf = aligned_empty((burst_size,), np.complex64, alignment=64) + buf[:] = tone + + res = dev.writeStream(tx_stream, [buf], int(burst_size), timeoutUs=timeout_us) + + n = res.ret + if n < 0: + raise RuntimeError(f"writeStream returned error code {n}") + if n < burst_size: + print(f"Warning: wrote only {n}/{burst_size} samples") + + burst_idx += 1 + except KeyboardInterrupt: + print(f"\nInterrupted after {burst_idx} bursts") + + # Close stream + dev.deactivateStream(tx_stream) + dev.closeStream(tx_stream) + + # Close device + if dev.close is not None: + dev.close() # Not strictly necessary, but good practice + dev = None + + print("Done.") + + +if __name__ == "__main__": + main() From ef84250668af35c537cf7c0d103fbe606a32bd06 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 23 Mar 2026 23:40:04 +0400 Subject: [PATCH 367/397] usdr: init DSP chain --- src/lib/device/m2_lm6_1/usdr_ctrl.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 44ce1343..ee7a5949 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -414,6 +414,20 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, } */ + // Update FE + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, 7); + res = res ? res : usleep(10); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, 0); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, (1 << 24) | 1); + + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, (8 << 24) | 0); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, (9 << 24) | 16384); + + uint32_t v = 0; + res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &v); + + USDR_LOG("UDEV", USDR_LOG_WARNING, "V=%08x\n", v); + d->rxbb_decim = int_decim[i]; d->txbb_intr = int_decim[i]; From f7e21ced5e35e7efe8fe3e5ac7ea689737424883 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 24 Mar 2026 02:28:40 +0400 Subject: [PATCH 368/397] xmass: add initial support in linux kernel --- .../pcie_uram/driver/usdr_pcie_uram.c | 1160 +++++++++++++++-- 1 file changed, 1083 insertions(+), 77 deletions(-) diff --git a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c index fe635b0c..e64b2351 100644 --- a/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c +++ b/src/lib/lowlevel/pcie_uram/driver/usdr_pcie_uram.c @@ -21,11 +21,17 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include +#include + #include "./pcie_uram_driver_if.h" #include "./si2c.c" @@ -38,6 +44,19 @@ #define DEVICE_NAME DRV_NAME #define CLASS_NAME DRV_NAME +#define XMASS_NAME "xmass" +#define XPFX XMASS_NAME ": " +#define XMASS_DEVICE_NAME XMASS_NAME +#define XMASS_CLASS_NAME XMASS_NAME + +// Maximum device supported for usdr and xmass in the system +#define TOT_USDR_DEVS 32 +typedef DECLARE_BITMAP(usdr_dev_bituse_t, TOT_USDR_DEVS); + +#define TOT_XMASS_DEVS 8 +typedef DECLARE_BITMAP(xmass_dev_bituse_t, TOT_XMASS_DEVS); + + MODULE_AUTHOR("Sergey Kostanbaev "); MODULE_DESCRIPTION("USDR PCIe UnifiedRAM driver"); MODULE_LICENSE("GPL"); @@ -168,6 +187,24 @@ struct event_data_log { uint64_t stat_rptr; }; +#define MAX_XMASS_DEVS 4 +struct xmass_dev { + struct xmass_dev *next; + unsigned long device_data; + struct cdev cdev; + struct device* cdevice; + + spinlock_t slock; + + unsigned asm_bus_number; + unsigned devno; + unsigned dev_mask; + + struct pci_dev* pasmdev; // Valid when device is locked + + struct usdr_dev* dev[MAX_XMASS_DEVS]; // 0 index means device A, 1 - B, ... +}; + struct usdr_dev { struct usdr_dev *next; unsigned long device_data; @@ -176,39 +213,47 @@ struct usdr_dev { struct pci_dev* pdev; spinlock_t slock; - + void __iomem *bar_addr; - + unsigned devno; - unsigned dev_mask; + unsigned dev_mask; struct pcie_driver_devlayout dl; - + int irq_configured; // Number of IRQ configured irq_func_t irq_funcs[MAX_INT]; atomic_t irq_ev_cnt[MAX_INT]; uint32_t rb_ev_data[MAX_INT]; bucket_func_t bucket_func[MAX_INT]; - + wait_queue_head_t irq_ev_wq[MAX_INT]; char int_names[INTNAMES_MAX * MAX_INT]; struct stream_state* streams[MAX_STREAMS]; - + struct notification_bucket buckets[MAX_BUCKETS]; - + unsigned vma_off_last; - + struct event_data_log streaming[MAX_INT]; struct i2c_cache i2cc[4 * MAX_I2C_COUNT]; uint32_t i2clut[MAX_I2C_COUNT]; }; +// USDR static struct usdr_dev *usdr_list = NULL; -static int devices = 0; -static dev_t dev_first; -static struct class* usdr_class = NULL; +static struct class* usdr_class = NULL; +static dev_t usdr_dev_first; +static usdr_dev_bituse_t usdr_busy_map; + +// XMASS +static struct xmass_dev *xmass_list = NULL; +static struct class* xmass_class = NULL; +static dev_t xmass_dev_first; +static xmass_dev_bituse_t xmass_busy_map; + // #define EXTRA_DEBUG @@ -385,7 +430,7 @@ static int usdr_allocdma(struct usdr_dev *d, struct usdr_dmabuf *pbufs, unsigned } return -1; } - + printk(KERN_NOTICE PFX "buf[%d]=%lx [virt %p]\n", i, (unsigned long)pbufs[i].phys, pbufs[i].kvirt); } return 0; @@ -405,7 +450,7 @@ static int init_bucket(struct usdr_dev *dev) unsigned i; for (i = 0; i < dev->dl.bucket_count; i++) { struct notification_bucket* b = &dev->buckets[i]; - + b->db.kvirt = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, &b->db.phys, GFP_KERNEL); if(!b->db.kvirt) @@ -416,10 +461,10 @@ static int init_bucket(struct usdr_dev *dev) b->db.uvirt = 0; b->rptr = 0; - + // Initialize to FF so we can see 1->0 toggle on valid entries memset(b->db.kvirt, -1, PAGE_SIZE); - + // Writing DMA address resets counter and sets toggle bit to 0 usdr_reg_wr32(dev, dev->dl.bucket_base, // CFG @@ -428,7 +473,7 @@ static int init_bucket(struct usdr_dev *dev) dev->dl.bucket_base + 1, //ACK i << 16); dev_notice(&dev->pdev->dev, "Bucket %d: DMA at %px to %llx\n", i, b->db.kvirt, b->db.phys); - + } return 0; } @@ -438,7 +483,7 @@ static void deinit_bucket(struct usdr_dev *dev) unsigned i; for (i = 0; i < dev->dl.bucket_count; i++) { struct notification_bucket* b = &dev->buckets[i]; - + //TODO block interrupt queue if(b->db.kvirt) dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, b->db.kvirt, b->db.phys); @@ -454,32 +499,32 @@ static irqreturn_t usdr_pcie_irq_bucket_128(int irq, void *data) struct notification_bucket* b; uint64_t wakeups = 0; ktime_t ets; - + for (bidx = 0; bidx < d->dl.bucket_count; bidx++) { b = &d->buckets[bidx]; if (b->irq == irq) goto irq_found; } - + dev_notice(&d->pdev->dev, "IRQ %d: Unknown bucket!\n", irq); return IRQ_HANDLED; - + irq_found: bptr = b->db.kvirt; ets = ktime_get(); for (j = 0, i = b->rptr; i < b->rptr + 256; i++, j++) { uint32_t data[4]; unsigned event_no, flags, l; - + for (l = 0; l < 4; l++) data[l] = /*be32_to_cpu*/(bptr[(4 * i + l) & 0x3ff]); - + //event_no = data[3] >> 29; //flags = (data[3] & (1u<<28)) ? 1 : 0; flags = data[0] >> 31; event_no = data[0] & 0x3f; - + if (flags != ((i >> 8) & 1)) { break; } @@ -489,8 +534,8 @@ static irqreturn_t usdr_pcie_irq_bucket_128(int irq, void *data) DEBUG_DEV_OUT(&d->pdev->dev, "BUCKET %d IRQ %d: Event %d Flag: %d; RPTR %d; Data: %08x_%08x_%08x_%08x\n", i, irq, event_no, flags, b->rptr, data[3], data[2], data[1], data[0]); - - + + // TODO: based on event handler process data if (event_no == 0 || event_no == 1) { unsigned k = (d->streaming[event_no].stat_wptr) & (STAT_MAX_SZ - 1); @@ -515,21 +560,21 @@ static irqreturn_t usdr_pcie_irq_bucket_128(int irq, void *data) //wake_up_interruptible(&d->irq_ev_wq[event_no]); wakeups |= (1u << event_no); } - + if (j > 1) { DEBUG_DEV_OUT(&d->pdev->dev, "BUCKET %d IRQ %d: rptr = %d int suppressed %d times\n", i, irq, b->rptr, j); } - + for (j = 0; j < MAX_INT; j++) { if (wakeups & (1u << j)) { wake_up_interruptible(&d->irq_ev_wq[j]); } } - + b->rptr = i & 0x1ff; - + //dev_notice(&d->pdev->dev, "BUCKET %d IRQ %d: rptr = %d\n", i, irq, b->rptr); - + if (do_cnf != ~0u) { //Send confirmation pointer usdr_reg_wr32(d, @@ -559,6 +604,16 @@ static int usdrfd_open(struct inode *inode, struct file *filp) } spin_unlock_irqrestore(&dev->slock, flags); + if (granted && dev->pdev->error_state != pci_channel_io_normal) { + dev_err(&dev->pdev->dev, "PCI device /dev/usdr%d is disconnected or in error state\n", dev->devno); + + spin_lock_irqsave(&dev->slock, flags); + dev->dev_mask &= ~DEV_EXCLUSIVE; + spin_unlock_irqrestore(&dev->slock, flags); + + return -EIO; + } + return (granted) ? 0 : -EBUSY; } @@ -575,7 +630,7 @@ static int usdrfd_release(struct inode *inode, struct file *filp) spin_lock_irqsave(&usdrdev->slock, flags); usdrdev->dev_mask &= ~DEV_EXCLUSIVE; spin_unlock_irqrestore(&usdrdev->slock, flags); - + return 0; } @@ -816,15 +871,15 @@ static int usdr_device_initialie(struct usdr_dev *usdrdev) usdrdev->dl.idx_regsp_cnt, usdrdev->dl.interrupt_count, c, imsk); #else - + dev_notice(&usdrdev->pdev->dev, "Device initialized, spi buses %d, i2c buses %d, indexed %d, bucket mode\n", usdrdev->dl.spi_cnt, usdrdev->dl.i2c_cnt, usdrdev->dl.idx_regsp_cnt); - + //init_bucket(usdrdev); - + //Initialize interrupt routines #if LINUX_VERSION_CODE <= KERNEL_VERSION(4,11,0) res = pci_enable_msi_range(usdrdev->pdev, 1, 1); @@ -846,14 +901,14 @@ static int usdr_device_initialie(struct usdr_dev *usdrdev) goto failed_cfg_mux; } usdrdev->buckets[0].irq = pci_irq_vector(usdrdev->pdev, irq); - + //Configure all IRQs to report to bucket 0 via interrupt 0 for (i = 0; i < 32; i++) { usdr_reg_wr32(usdrdev, usdrdev->dl.interrupt_base, i | (0 << 8) | (1 << 16) | (0 << 20)); usdrdev->irq_funcs[i] = usdr_pcie_irq_event; } usdrdev->irq_configured = 1; - + #endif return 0; @@ -941,7 +996,7 @@ static int usdr_stream_initialize(struct usdr_dev *usdrdev, } // Initialize dma buffer pointer in the dev - if (usdrdev->dl.stream_core[sno] == USDR_MAKE_COREID(USDR_CS_STREAM, USDR_SC_RXDMA_BRSTN) || + if (usdrdev->dl.stream_core[sno] == USDR_MAKE_COREID(USDR_CS_STREAM, USDR_SC_RXDMA_BRSTN) || usdrdev->dl.stream_core[sno] == USDR_MAKE_COREID(USDR_CS_STREAM, USDR_SC_TXDMA_OLD) ) { for (i = 0; i < sdma->dma_bufs; i++) { usdr_reg_wr32(usdrdev, @@ -1587,7 +1642,7 @@ struct file_operations usdr_fops = { static int usdr_setup_cdev(struct usdr_dev *usdrdev) { - dev_t dev_num = dev_first + usdrdev->devno; + dev_t dev_num = usdr_dev_first + usdrdev->devno; cdev_init(&usdrdev->cdev, &usdr_fops); usdrdev->cdev.owner = THIS_MODULE; @@ -1605,10 +1660,15 @@ static int usdr_probe(struct pci_dev *pdev, struct usdr_dev* usdrdev; int err; void __iomem* bar_addr; - unsigned usdr_no = devices; + //unsigned usdr_no = devices; + unsigned usdr_no = find_first_zero_bit(usdr_busy_map, TOT_USDR_DEVS); size_t bar_len; - printk(KERN_INFO PFX "Initializing %s\n", pci_name(pdev)); + struct pci_dev *bridge, *tbridge; + bridge = pci_upstream_bridge(pdev); + tbridge = (bridge) ? pci_upstream_bridge(bridge) : NULL; + + printk(KERN_INFO PFX "Initializing %s => %s => %s\n", pci_name(pdev), bridge ? pci_name(bridge) : "null", tbridge ? pci_name(tbridge) : "null"); err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, "Cannot enable PCI device, " @@ -1618,16 +1678,24 @@ static int usdr_probe(struct pci_dev *pdev, pci_set_master(pdev); + if (tbridge) { + printk(KERN_INFO PFX "Initialize ASM2806 bridge: %px\n", tbridge); + // pci_write_config_byte(tbridge, 0xfff, 1); // Switch to GPIO control mode + // pci_write_config_byte(tbridge, 0x920, 0x01); + // pci_write_config_byte(tbridge, 0x928, 0x00); + } + /* Reconfigure MaxReadReq to 4KB */ - pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_1024B); + //pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, + // PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_4096B); - //dma_set_mask_and_coherent + //dma_set_mask_and_coherent if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32))) { dev_err(&pdev->dev,"No suitable consistent DMA available.\n"); + err = -EINVAL; goto err_disable_pdev; } - + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { dev_err(&pdev->dev,"No suitable consistent DMA available.\n"); goto err_disable_pdev; @@ -1665,48 +1733,49 @@ static int usdr_probe(struct pci_dev *pdev, usdrdev->devno = usdr_no; usdrdev->pdev = pdev; usdrdev->dev_mask = 0; - + spin_lock_init(&usdrdev->slock); usdrdev->dev_mask = DEV_VALID; usdrdev->cdevice = device_create(usdr_class, &pdev->dev, - MKDEV(MAJOR(dev_first), MINOR(dev_first) + devices), + MKDEV(MAJOR(usdr_dev_first), MINOR(usdr_dev_first) + usdrdev->devno), NULL, DEVICE_NAME "%d", - devices); + usdrdev->devno); if (IS_ERR(usdrdev->cdevice)) { printk(KERN_NOTICE PFX "Unable to register device class\n"); + err = -EINVAL; goto failed_device; } - err = usdr_setup_cdev(usdrdev); + err = usdr_setup_cdev(usdrdev); if (err) { printk(KERN_NOTICE PFX "Error %d initializing cdev\n", err); goto failed_cdev; } usdrdev->device_data = id->driver_data; - - usdrdev->dl.bucket_count = 1; - usdrdev->dl.bucket_base = 8; - err = init_bucket(usdrdev); - if (err) - { - printk(KERN_NOTICE PFX "Error %d initializing bucket\n", err); - deinit_bucket(usdrdev); - goto failed_cdev; - } + usdrdev->dl.bucket_count = 1; + usdrdev->dl.bucket_base = 8; + err = init_bucket(usdrdev); + if (err) { + printk(KERN_NOTICE PFX "Error %d initializing bucket\n", err); + deinit_bucket(usdrdev); + goto failed_cdev; + } + + dev_info(&pdev->dev, "is linked to /dev/usdr%d\n", usdrdev->devno); + set_bit(usdrdev->devno, usdr_busy_map); - devices++; - usdrdev->next = usdr_list; - usdr_list = usdrdev; + usdrdev->next = usdr_list; + usdr_list = usdrdev; return 0; //cdev_del(&usdrdev->cdev); failed_cdev: - device_destroy(usdr_class, MKDEV(MAJOR(dev_first), MINOR(dev_first) + devices)); + device_destroy(usdr_class, MKDEV(MAJOR(usdr_dev_first), MINOR(usdr_dev_first) + usdrdev->devno)); failed_device: kfree(usdrdev); //err_allocdma: @@ -1721,8 +1790,7 @@ static int usdr_probe(struct pci_dev *pdev, pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); return err; -}; - +} static void usdr_remove(struct pci_dev *pdev) { @@ -1731,7 +1799,7 @@ static void usdr_remove(struct pci_dev *pdev) printk(KERN_INFO PFX "Removing device %s\n", pci_name(pdev)); if (usdrdev->dev_mask & DEV_INITIALIZED) { - + // Disable notification of all events for (i = 0; i < 32; i++) { // Dispatch ID == 0xf means to ignore this event @@ -1746,7 +1814,7 @@ static void usdr_remove(struct pci_dev *pdev) } pci_disable_msi(pdev); - + #ifndef OLD_IRQ // Remove bucket memory deinit_bucket(usdrdev); @@ -1758,8 +1826,8 @@ static void usdr_remove(struct pci_dev *pdev) } cdev_del(&usdrdev->cdev); - device_destroy(usdr_class, MKDEV(MAJOR(dev_first), MINOR(usdrdev->devno))); - + device_destroy(usdr_class, MKDEV(MAJOR(usdr_dev_first), MINOR(usdr_dev_first) + usdrdev->devno)); + usdrdev->dev_mask = 0; pci_iounmap(pdev, usdrdev->bar_addr); @@ -1768,14 +1836,18 @@ static void usdr_remove(struct pci_dev *pdev) pci_clear_master(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - - //usdr_freedma(usdrdev, usdrdev->rxdma, usdrdev->rxdma_bufsize); - devices--; + //usdr_freedma(usdrdev, usdrdev->rxdma, usdrdev->rxdma_bufsize); + clear_bit(usdrdev->devno, usdr_busy_map); + + dev_info(&pdev->dev, "is unlinked, /dev/usdr%d removed\n", usdrdev->devno); + + //devices--; // TODO: Unchain from list and free the memory } + static struct pci_device_id usdr_pci_table[] = { { PCI_DEVICE(0x10EE, 0x7032), .driver_data = 0 }, @@ -1800,6 +1872,849 @@ static struct pci_device_id usdr_pci_table[] = { { 0, } }; +//static struct pci_device_id xmass_pci_table[] = { +// { PCI_DEVICE(0x1B21, 0x2806), .driver_data = 0 }, +// { 0, } +//}; + + +static int xmassfd_open(struct inode *inode, struct file *filp) +{ + struct xmass_dev *dev; + unsigned long flags; + int granted = 0; + + dev = container_of(inode->i_cdev, struct xmass_dev, cdev); + filp->private_data = dev; + + spin_lock_irqsave(&dev->slock, flags); + if ((dev->dev_mask & DEV_EXCLUSIVE) == 0) { + dev->dev_mask |= DEV_EXCLUSIVE; + granted = 1; + } + spin_unlock_irqrestore(&dev->slock, flags); + + return (granted) ? 0 : -EBUSY; +} + +static int xmassfd_release(struct inode *inode, struct file *filp) +{ + struct xmass_dev *dev = filp->private_data; + unsigned long flags; + + if ((dev->dev_mask & DEV_VALID) == 0) { + printk(KERN_INFO XPFX "xmass:%d dev is invalid!\n", dev->devno); + return 0; + } + + spin_lock_irqsave(&dev->slock, flags); + dev->dev_mask &= ~DEV_EXCLUSIVE; + spin_unlock_irqrestore(&dev->slock, flags); + + return 0; +} + +static ssize_t xmassfd_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + return -EINVAL; +} + +static ssize_t xmassfd_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + return -EINVAL; +} + + +#define MAX_PROC_BLK 128*4096 + +#define SPI_BUSY_BIT 0x20 +#define SPI_TERM_BIT 0x10 +#define SPI_GO_BITS 0x28 /* GO + WRITE */ + +#define SPI_REQ_BIT 0x01 /* request/grant ownership */ +#define SPI_GNT_BIT 0x02 /* grant status */ + +enum { + ASM28XX_REG_SWITCH = 0xfff, // 0 - USP control registers, 1 - System control registers + ASM28XX_GPIO0_CTRL = 0x920, // 0 - input; 1 - output + ASM28XX_GPIO0_OUT = 0x928, + ASM28XX_GPIO0_IN = 0x930, + + ASM28XX_SPI_DATA_REG = 0x700, + ASM28XX_SPI_CTRL_REG = 0x704, + ASM28XX_SPI_3WIRE_REG = 0x705, + + ASM28XX_SPI_MISC_REG = 0x711, + ASM28XX_SPI_GRANT_REG = 0x720, + + ASM28XX_FWID_0 = 0xf0, +}; + +enum { + ESPI_CMD_QCFR_0 = 0x0B, + ESPI_CMD_WREN = 0x06, + + ESPI_CMD_QCPP_0 = 0x02, + ESPI_CMD_SSE = 0x20, + ESPI_CMD_SE = 0xD8, + ESPI_CMD_BE = 0xC7, + ESPI_CMD_RDSR = 0x05, + + ESPI_CMD_RDID = 0xAB, + ESPI_CMD_RDID_0 = 0x9E, + ESPI_CMD_RDID_1 = 0x9F, +}; + +int asm28xx_spi_idle(struct xmass_dev *d) +{ + uint32_t iter; + uint8_t status; + int res; + + for (iter = 0; ; iter++) { + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, &status); + if (res) + return res; + + /* wait until BUSY clears */ + if ((status & SPI_BUSY_BIT) == 0) + return 0; + + /* timeout: ~1,000,000 clock ticks */ + if (iter > 0xF423F) { + printk(KERN_INFO XPFX "xmass:%d SPI idle timeout! SPI status = 0x%02x\n", d->devno, status); + return -ETIMEDOUT; + } + } + + return 0; +} + +int asm28xx_spi_start(struct xmass_dev *d) +{ + uint8_t ctrl; + int res, j; + + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, &ctrl); + if (res) + return res; + + ctrl &= ~SPI_TERM_BIT; /* clear terminate / CS bit */ + + return pci_write_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, ctrl); +} + +int asm28xx_spi_terminate(struct xmass_dev *d) +{ + uint8_t ctrl; + + int res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, &ctrl); + if (res) + return res; + + ctrl |= SPI_TERM_BIT; /* set terminate / CS bit */ + + return pci_write_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, ctrl); +} + +int asm28xx_spi_write(struct xmass_dev *d, const uint8_t *buf, uint8_t len) +{ + uint32_t value = 0; + uint8_t ctrl; + uint8_t i; + int res; + + /* only 1..4 bytes supported */ + if (len < 1 || len > 4) + return -EINVAL; + + /* controller must be idle */ + res = asm28xx_spi_idle(d); + if (res) + return res; + + /* pack bytes little-endian into a 32-bit word */ + for (i = 0; i < len; i++) + ((uint8_t *)&value)[i] = buf[i]; + + /* write data */ + res = pci_write_config_dword(d->pasmdev, ASM28XX_SPI_DATA_REG, value); + if (res) + return res; + + /* start write transaction */ + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, &ctrl); + if (res) + return res; + + // ctrl &= 0x04; + ctrl = (len & 0x07) | SPI_GO_BITS; + + res = pci_write_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, ctrl); + if (res) + return res; + + /* wait for completion */ + return asm28xx_spi_idle(d); +} + +int asm28xx_spi_read(struct xmass_dev *d, uint8_t *buf, uint8_t len) +{ + uint32_t value; + uint8_t ctrl; + uint8_t i; + int res; + + /* only 1..4 bytes supported */ + if (len < 1 || len > 4) + return -EINVAL; + + /* controller must be idle */ + res = asm28xx_spi_idle(d); + if (res) + return res; + + /* + * Program control register: + * - low 3 bits = length + * - bit 0x20 = start read transaction + */ + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, &ctrl); + if (res) + return res; + + ctrl = (len & 0x07) | SPI_BUSY_BIT; + + res = pci_write_config_byte(d->pasmdev, ASM28XX_SPI_CTRL_REG, ctrl); + if (res) + return res; + + /* wait for read completion */ + res = asm28xx_spi_idle(d); + if (res) + return res; + + /* read data */ + res = pci_read_config_dword(d->pasmdev, ASM28XX_SPI_DATA_REG, &value); + if (res) + return res; + + /* unpack little-endian bytes */ + for (i = 0; i < len; i++) + buf[i] = ((uint8_t *)&value)[i]; + + return 0; +} + +int asm28xx_spi_release_grant(struct xmass_dev *d) +{ + uint8_t val; + int res; + + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_GRANT_REG, &val); + if (res) + return res; + + val &= ~SPI_REQ_BIT; + + return pci_write_config_byte(d->pasmdev, ASM28XX_SPI_GRANT_REG, val); +} + + +int asm28xx_spi_get_grant(struct xmass_dev *d) +{ + uint32_t iter; + uint8_t status; + int res; + + /* request ownership */ + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_GRANT_REG, &status); + if (res) + return res; + + status |= SPI_REQ_BIT; + + res = pci_write_config_byte(d->pasmdev, ASM28XX_SPI_GRANT_REG, status); + if (res) + return res; + + for (iter = 0; ; iter++) { + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_GRANT_REG, &status); + if (res) + return res; + + /* wait until grant bit is set */ + if (status & SPI_GNT_BIT) + return 0; + + /* timeout (~3,000,000 ticks) */ + if (iter > 0x2DC6BF) { + //puts("SPI grant timeout"); + //printf("SPI grant status = 0x%02x\n", status); + printk(KERN_INFO XPFX "xmass:%d SPI grant timeout! GRANT status = 0x%02x\n", d->devno, status); + + asm28xx_spi_release_grant(d); + return -ETIMEDOUT; + } + } +} + +int asm28xx_spi_controller_init(struct xmass_dev *d) +{ + uint8_t val; + int res; + + /* configure control register */ + res = pci_read_config_byte(d->pasmdev, ASM28XX_SPI_MISC_REG, &val); + if (res) + return res; + + val &= 0xD1; + + return pci_write_config_byte(d->pasmdev, ASM28XX_SPI_MISC_REG, val); +} + + +static int xmass_gpio_stream(struct xmass_dev *d, unsigned delay_ns, unsigned len, uint8_t* s_out, uint8_t* s_in) +{ + unsigned i; + int res = 0; + + for (i = 0; i < len; i++) { + res = pci_write_config_byte(d->pasmdev, ASM28XX_GPIO0_OUT, s_out[i]); + if (res) + return res; + + if (s_in) { + res = pci_read_config_byte(d->pasmdev, ASM28XX_GPIO0_IN, &s_in[i]); + if (res) + return res; + } + + if (delay_ns) + ndelay(delay_ns); + } + + return res; +} + +// Read 1-4 bytes flash status registers registrer +int asm28xx_spi_flash_read_reg(struct xmass_dev *d, uint8_t* cmd, unsigned wrlen, unsigned rdlen, uint8_t *id) +{ + int res; + res = asm28xx_spi_start(d); + if (res) + return res; + + if (wrlen > 0) { + /* write opcode + dummy bytes */ + res = asm28xx_spi_write(d, cmd, wrlen); + if (res) + return res; + } + + if (rdlen > 0) { + /* read 3-byte JEDEC / device ID */ + res = asm28xx_spi_read(d, id, rdlen); + if (res) + return res; + } + + res = asm28xx_spi_terminate(d); + if (res) + return res; + + return 0; +} + +#define SPI_CMD_WRSR 0x01 + +#define FLASH_READ_CMD 0x03 +#define FLASH_WREN_CMD 0x06 +#define FLASH_SE_4K_CMD 0x20 +#define FLASH_RDSR_CMD 0x05 +#define FLASH_PP_CMD 0x02 + +#define SPI_SR_WIP 0x01 /* Write In Progress */ +#define SPI_SR_WEL 0x02 /* Write Enable Latch */ + +int asm28xx_spi_flash_read(struct xmass_dev *d, unsigned size, uint8_t *out) +{ + uint32_t addr = 0; + uint8_t cmd[4]; + int res; + + while (addr < size) { + /* build READ command: 0x03 + 24-bit address */ + cmd[0] = FLASH_READ_CMD; + cmd[1] = (addr >> 16) & 0xFF; + cmd[2] = (addr >> 8) & 0xFF; + cmd[3] = (addr >> 0) & 0xFF; + res = asm28xx_spi_flash_read_reg(d, cmd, 4, 4, &out[addr]); + if (res) + return res; + + addr += 4; + } + + return 1; +} + +int asm28xx_spi_write_enable(struct xmass_dev *d) +{ + int res, cnt; + uint8_t cmd[1]; + uint8_t sr; + + for (cnt = 0; cnt < 1000; cnt++) { + /* Write Enable */ + cmd[0] = FLASH_WREN_CMD; + res = asm28xx_spi_flash_read_reg(d, cmd, 1, 0, NULL); + if (res) + return res; + + cmd[0] = FLASH_RDSR_CMD; + res = asm28xx_spi_flash_read_reg(d, cmd, 1, 1, &sr); + if (res) + return res; + + if ((sr & SPI_SR_WEL) == SPI_SR_WEL) + return 0; + + udelay(10); + } + + dev_info(&d->pasmdev->dev, "WREN TIMEDOUT RDSR = 0x%02x\n", sr); + return -ETIMEDOUT; +} + +int asm28xx_spi_wait_done(struct xmass_dev *d) +{ + int res, cnt; + uint8_t cmd[1]; + uint8_t sr; + + /* Wait until flash is ready (WIP=0) */ + cmd[0] = FLASH_RDSR_CMD; + for (cnt = 0; cnt < 1000; cnt++) { + res = asm28xx_spi_flash_read_reg(d, cmd, 1, 1, &sr); + if (res) + return res; + + if ((sr & SPI_SR_WIP) == 0) + return 0; + + udelay(1000); + } + + dev_info(&d->pasmdev->dev, "WIP TIMEOUT RDSR = 0x%02x\n", sr); + return -ETIMEDOUT; +} + +int asm28xx_spi_flash_blank(struct xmass_dev *d, unsigned size) +{ + uint32_t addr; + uint8_t cmd[4]; + uint8_t sr; + int res, cnt; + + res = asm28xx_spi_write_enable(d); + if (res) + return res; + + /* Unprotect */ + cmd[0] = SPI_CMD_WRSR; + cmd[1] = 0; + res = asm28xx_spi_flash_read_reg(d, cmd, 2, 0, NULL); + if (res) + return res; + + for (addr = 0; addr < size; addr += 0x1000) { + res = asm28xx_spi_write_enable(d); + if (res) + return res; + + /* 4KB Sector Erase (0x20) */ + cmd[0] = FLASH_SE_4K_CMD; + cmd[1] = (addr >> 16) & 0xFF; + cmd[2] = (addr >> 8) & 0xFF; + cmd[3] = (addr >> 0) & 0xFF; + res = asm28xx_spi_flash_read_reg(d, cmd, 4, 0, NULL); + if (res) + return res; + + /* Wait until flash is ready (WIP=0) */ + res = asm28xx_spi_wait_done(d); + if (res) + return res; + } + + return 0; +} + +int asm28xx_spi_flash_write_page(struct xmass_dev *d, uint32_t addr, + const uint8_t *data, uint32_t len) +{ + uint8_t cmd[4]; + unsigned off; + int res, cnt; + cmd[0] = FLASH_PP_CMD; + cmd[1] = (addr >> 16) & 0xFF; + cmd[2] = (addr >> 8) & 0xFF; + cmd[3] = (addr >> 0) & 0xFF; + + res = asm28xx_spi_write_enable(d); + if (res) + return res; + + res = asm28xx_spi_start(d); + if (res) + return res; + + res = asm28xx_spi_write(d, cmd, 4); + if (res) + return res; + + for (off = 0; off < len; off += 4) { + res = asm28xx_spi_write(d, data + off, 4); + if (res) + return res; + } + + res = asm28xx_spi_terminate(d); + if (res) + return res; + + return asm28xx_spi_wait_done(d); +} + +int asm28xx_spi_flash_write(struct xmass_dev *d, const uint8_t *image, uint32_t total) +{ + uint32_t offset; + int res; + + /* program page-by-page (256 bytes typical) */ + for (offset = 0; offset < total; offset += 256) { + res = asm28xx_spi_flash_write_page(d, offset, image + offset, 256); + if (res) + return res; + } + + return 0; +} + +void asm28xx_signoff(uint8_t *tmp, const char *payload) +{ + uint8_t sum = 0; + unsigned len = strlen(payload), i; + const unsigned max_len = 0xE30 - 0xE10; + static const uint8_t g_asm_id[16] = { + 0x88, 0xb0, 0x15, 0x9a, 0x5e, 0xe3, 0xae, 0x40, + 0xaf, 0x8f, 0x00, 0x49, 0x58, 0xba, 0x7a, 0xf2 + }; + + /* 1) place id at 0xE00 */ + memcpy(tmp + 0xE00, g_asm_id, 16); + + /* 2) place custom string at 0xE10..0xE30 (no NULL terminator) */ + if (len > max_len) + len = max_len; + + memcpy(tmp + 0xE10, payload, len); + + /* 3) marker byte */ + tmp[0xEFE] = 0x5A; + + /* 4) checksum over [0xE00 .. 0xEFE-1] */ + for (i = 0xE00; i < 0xEFE; i++) + sum += tmp[i]; + + tmp[0xEFF] = sum; +} + + +#define ASM28XX_FLASH_IMAGE_SIZE 65536 +uint8_t s_temp_data[ASM28XX_FLASH_IMAGE_SIZE]; + +static long xmassfd_ioctl(struct file *filp, + unsigned int ioctl_num,/* The number of the ioctl */ + unsigned long ioctl_param) /* The parameter to it */ +{ + int res; + struct xmass_dev *xmassdev = filp->private_data; + void __user *uptr = (void __user *)ioctl_param; + + if (!(xmassdev->dev_mask & DEV_VALID)) + return -EIO; + + if (xmassdev->pasmdev->error_state != pci_channel_io_normal) { + dev_err(&xmassdev->pasmdev->dev, "PCI device is disconnected or in error state\n"); + return -EIO; + } + + // JTAG bit-banging transfer + switch (ioctl_num) { + case PCIE_FLASH_WRITE: { + if (copy_from_user(s_temp_data, uptr, ASM28XX_FLASH_IMAGE_SIZE)) + return -EFAULT; + + asm28xx_signoff(s_temp_data, "XMASS"); + + res = pm_runtime_resume_and_get(&xmassdev->pasmdev->dev); + if (res < 0) + return res; + + res = res ? res : pci_write_config_byte(xmassdev->pasmdev, ASM28XX_REG_SWITCH, 1); // Switch to GPIO control mode + res = res ? res : asm28xx_spi_controller_init(xmassdev); + res = res ? res : asm28xx_spi_get_grant(xmassdev); + + res = res ? res : asm28xx_spi_flash_write(xmassdev, s_temp_data, ASM28XX_FLASH_IMAGE_SIZE); + + asm28xx_spi_release_grant(xmassdev); + pm_runtime_put(&xmassdev->pasmdev->dev); + return res; + } + case PCIE_FLASH_ERASE: { + res = pm_runtime_resume_and_get(&xmassdev->pasmdev->dev); + if (res < 0) + return res; + + res = res ? res : pci_write_config_byte(xmassdev->pasmdev, ASM28XX_REG_SWITCH, 1); // Switch to GPIO control mode + res = res ? res : asm28xx_spi_controller_init(xmassdev); + res = res ? res : asm28xx_spi_get_grant(xmassdev); + res = res ? res : asm28xx_spi_flash_blank(xmassdev, ASM28XX_FLASH_IMAGE_SIZE); + + asm28xx_spi_release_grant(xmassdev); + pm_runtime_put(&xmassdev->pasmdev->dev); + return res; + } + case PCIE_FLASH_READ: { + res = pm_runtime_resume_and_get(&xmassdev->pasmdev->dev); + if (res < 0) + return res; + + res = res ? res : pci_write_config_byte(xmassdev->pasmdev, ASM28XX_REG_SWITCH, 1); // Switch to GPIO control mode + res = res ? res : asm28xx_spi_controller_init(xmassdev); + res = res ? res : asm28xx_spi_get_grant(xmassdev); + res = res ? res : asm28xx_spi_flash_read(xmassdev, ASM28XX_FLASH_IMAGE_SIZE, s_temp_data); + + asm28xx_spi_release_grant(xmassdev); + pm_runtime_put(&xmassdev->pasmdev->dev); + + if (copy_to_user(uptr, s_temp_data, ASM28XX_FLASH_IMAGE_SIZE)) + return -EFAULT; + + return res; + } + case PCIE_GETIDS: { + uint8_t fwid[6] = { 0, }; + uint8_t rdid[4] = { 0, }; + uint8_t cmd = ESPI_CMD_RDID_1; + unsigned j; + + res = pm_runtime_resume_and_get(&xmassdev->pasmdev->dev); + if (res < 0) + return res; + + for (j = 0; j < 6; j++) { + res = res ? res : pci_read_config_byte(xmassdev->pasmdev, ASM28XX_FWID_0 + j, &fwid[j]); + } + + res = res ? res : pci_write_config_byte(xmassdev->pasmdev, ASM28XX_REG_SWITCH, 1); // Switch to GPIO control mode + res = res ? res : asm28xx_spi_controller_init(xmassdev); + res = res ? res : asm28xx_spi_get_grant(xmassdev); + res = res ? res : asm28xx_spi_flash_read_reg(xmassdev, &cmd, 1, 4, rdid); + + asm28xx_spi_release_grant(xmassdev); + pm_runtime_put(&xmassdev->pasmdev->dev); + + if (copy_to_user(uptr, fwid, 6)) + return -EFAULT; + + if (copy_to_user(uptr + 6, rdid, 4)) + return -EFAULT; + + return res; + } + case PCIE_GPIOS_8: { + unsigned len; + unsigned delay_ns; + struct xmass_iop iop; + int has_rx; + + static uint8_t out_data[MAX_PROC_BLK]; + static uint8_t in_data[MAX_PROC_BLK]; + + if (copy_from_user(&iop, uptr, sizeof(iop))) + return -EFAULT; + + len = iop.io_len; + if (len > MAX_PROC_BLK) + len = MAX_PROC_BLK; + + delay_ns = iop.delay_ns; + has_rx = (iop.in_buf != NULL); + + if (copy_from_user( out_data, iop.out_buf, len)) + return -EFAULT; + + /* Ensure ASM2806 isn't in sleep mode */ + res = pm_runtime_resume_and_get(&xmassdev->pasmdev->dev); + if (res < 0) + return res; + + printk(KERN_NOTICE XPFX "XMASS_JTAG_IO LEN=%d (%d) NS=%d\n", len, iop.io_len, delay_ns); + + pci_write_config_byte(xmassdev->pasmdev, ASM28XX_REG_SWITCH, 1); // Switch to GPIO control mode + pci_write_config_byte(xmassdev->pasmdev, ASM28XX_GPIO0_CTRL, (1 << 0) | (1 << 3) | (1 << 5)); + + res = xmass_gpio_stream(xmassdev, delay_ns, len, out_data, has_rx ? in_data : NULL); + + pm_runtime_put(&xmassdev->pasmdev->dev); + + if (res) + return res; + + if (has_rx) { + if (copy_to_user(iop.in_buf, in_data, len)) + return -EFAULT; + } + + return len; + } + } + + return -EINVAL; +} + + +struct file_operations xmass_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = xmassfd_ioctl, + .open = xmassfd_open, + .release = xmassfd_release, + .read = xmassfd_read, + .write = xmassfd_write, +}; + +static int xmass_setup_cdev(struct xmass_dev *xmassdev) +{ + dev_t dev_num = xmass_dev_first + xmassdev->devno; + + cdev_init(&xmassdev->cdev, &xmass_fops); + xmassdev->cdev.owner = THIS_MODULE; + xmassdev->cdev.ops = &xmass_fops; + return cdev_add (&xmassdev->cdev, dev_num, 1); +} + + +static int xmass_probe(struct pci_dev *pdev) +{ + struct xmass_dev* xmassdev; + unsigned xmass_no = find_first_zero_bit(xmass_busy_map, TOT_XMASS_DEVS); + int err; + + if (xmass_no == TOT_XMASS_DEVS) { + dev_err(&pdev->dev, "XMASS: Maximum number of devices is reahced, ignoring device!\n"); + return -ENOMEM; + } + + xmassdev = kzalloc(sizeof(*xmassdev), GFP_KERNEL); + if (!xmassdev) { + dev_err(&pdev->dev, "Failed to allocate memory.\n"); + return -ENOMEM; + } + + xmassdev->devno = xmass_no; + xmassdev->pasmdev = pci_dev_get(pdev); + xmassdev->dev_mask = 0; + + spin_lock_init(&xmassdev->slock); + + xmassdev->dev_mask = DEV_VALID; + xmassdev->cdevice = device_create(xmass_class, + &pdev->dev, + MKDEV(MAJOR(xmass_dev_first), MINOR(xmass_dev_first) + xmassdev->devno), + NULL, + XMASS_DEVICE_NAME "%d", + xmassdev->devno); + if (IS_ERR(xmassdev->cdevice)) { + printk(KERN_NOTICE XPFX "Unable to register device class\n"); + goto failed_device; + } + + err = xmass_setup_cdev(xmassdev); + if (err) { + printk(KERN_NOTICE XPFX "Error %d initializing cdev\n", err); + goto failed_cdev; + } + + dev_info(&pdev->dev, "is linked to /dev/xmass%d\n", xmass_no); + + set_bit(xmass_no, xmass_busy_map); + xmassdev->asm_bus_number = pdev->bus->number; + xmassdev->next = xmass_list; + xmass_list = xmassdev; + return 0; + +failed_cdev: + device_destroy(xmass_class, MKDEV(MAJOR(xmass_dev_first), MINOR(xmass_dev_first) + xmassdev->devno)); +failed_device: + pci_dev_put(pdev); + kfree(xmassdev); + return err; +} + + +static void xmass_dev_remove(struct xmass_dev* xmassdev) +{ + dev_info(&xmassdev->pasmdev->dev, "is unlinked, /dev/xmass%d removed\n", xmassdev->devno); + + cdev_del(&xmassdev->cdev); + //struct device* p = get_device(&xmassdev->pasmdev->dev); + //if (p) { + device_destroy(xmass_class, MKDEV(MAJOR(xmass_dev_first), MINOR(xmass_dev_first) + xmassdev->devno)); + // put_device(&xmassdev->pasmdev->dev); + //} else { + // dev_info(&xmassdev->pasmdev->dev, "device is empty\n"); + //} + pci_dev_put(xmassdev->pasmdev); + + xmassdev->dev_mask = 0; + + xmassdev->pasmdev = NULL; + xmassdev->asm_bus_number = ~0U; + + clear_bit(xmassdev->devno, xmass_busy_map); +} + +static struct xmass_dev *get_xmass_by_pci(struct pci_dev *pdev) +{ + struct xmass_dev *xptr = xmass_list; + while (xptr != NULL) { + if (xptr->pasmdev == pdev) { + return xptr; + } + xptr = xptr->next; + } + return NULL; +} + +static void xmass_remove(struct pci_dev *pdev) +{ + struct xmass_dev *xptr = get_xmass_by_pci(pdev); + if (xptr != NULL) { + xmass_dev_remove(xptr); + } +} + +enum { + XMASS_PCI_VID = 0x1B21, + XMASS_PCI_DID = 0x2806, +}; + MODULE_DEVICE_TABLE(pci, usdr_pci_table); static struct pci_driver usdr_driver = { @@ -1809,15 +2724,79 @@ static struct pci_driver usdr_driver = { .remove = usdr_remove }; +static int asm28xx_get_fw(struct pci_dev *pdev, uint8_t *fwid) +{ + int i, res; + for (i = 0; i < 6; i++) { + res = pci_read_config_byte(pdev, ASM28XX_FWID_0 + i, &fwid[i]); + if (res) + return res; + } + return 0; +} + +static int check_for_xamss(void) +{ + struct pci_dev *pdev = NULL; + int res; + uint8_t fwid[6]; + + while ((pdev = pci_get_device(XMASS_PCI_VID, XMASS_PCI_DID, pdev))) { + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_UPSTREAM) + continue; + + /* Ensure ASM2806 isn't in sleep mode */ + res = pm_runtime_resume_and_get(&pdev->dev); + if (res < 0) + return res; + + res = asm28xx_get_fw(pdev, fwid); + if (res) { + dev_err(&pdev->dev, "Unable to read firmware ID, error %x\n", res); + + pm_runtime_put(&pdev->dev); + continue; + } + + dev_info(&pdev->dev, "Found XMASS device: [%02x:%04x] ASM2806 Firmware %02x%02x%02x%02x%02x%02x %px\n", pdev->bus->number, pdev->devfn, fwid[0], fwid[1], fwid[2], fwid[3], fwid[4], fwid[5], pdev); + res = xmass_probe(pdev); + if (res) { + dev_info(&pdev->dev, "Unable to create XMASS char dev: %d\n", res); + } + + /* do NOT pci_dev_put(pdev) here */ + pm_runtime_put(&pdev->dev); + } + + /* Release the final reference */ + pci_dev_put(pdev); + + return 0; +} + +static void release_xmasses(void) +{ + struct xmass_dev *xptr = xmass_list; + while (xptr != NULL) { + xmass_dev_remove(xptr); + xptr = xptr->next; + } +} static int __init usdr_init(void) { int err; - err = alloc_chrdev_region(&dev_first, 0, 32, DRV_NAME); + err = alloc_chrdev_region(&usdr_dev_first, 0, TOT_USDR_DEVS, DRV_NAME); if (err) { - printk(KERN_NOTICE PFX "Unable to allocate chrdev region: %d\n", err); - goto failed_chrdev; + printk(KERN_NOTICE PFX "Unable to allocate chrdev region: %d\n", err); + goto failed_chrdev_usdr; } + err = alloc_chrdev_region(&xmass_dev_first, 0, TOT_XMASS_DEVS, DRV_NAME); + if (err) { + printk(KERN_NOTICE XPFX "Unable to allocate chrdev region: %d\n", err); + goto failed_chrdev_xmass; + } + #ifndef HAVE_CLASS_CREATE_ONE_ARG usdr_class = class_create(THIS_MODULE, CLASS_NAME); #else @@ -1828,36 +2807,63 @@ static int __init usdr_init(void) goto failed_setup_cdev; } +#ifndef HAVE_CLASS_CREATE_ONE_ARG + xmass_class = class_create(THIS_MODULE, XMASS_CLASS_NAME); +#else + xmass_class = class_create(XMASS_CLASS_NAME); +#endif + if (IS_ERR(usdr_class)) { + printk(KERN_NOTICE PFX "Unable to register xmass class\n"); + goto failed_xmass; + } + err = pci_register_driver(&usdr_driver); if (err) { printk(KERN_NOTICE PFX "Unable to register PCI driver: %d\n", err); goto failed_pci; } + + check_for_xamss(); return 0; failed_pci: + class_destroy(xmass_class); +failed_xmass: class_destroy(usdr_class); +failed_chrdev_xmass: + unregister_chrdev_region(xmass_dev_first, TOT_XMASS_DEVS); failed_setup_cdev: - unregister_chrdev_region(dev_first, devices); -failed_chrdev: + unregister_chrdev_region(usdr_dev_first, TOT_USDR_DEVS); +failed_chrdev_usdr: return err; } static void __exit usdr_cleanup(void) { struct usdr_dev *ptr = usdr_list, *next; + struct xmass_dev *xptr = xmass_list, *xnext; pci_unregister_driver(&usdr_driver); + // Manually clean + release_xmasses(); class_destroy(usdr_class); + class_destroy(xmass_class); - unregister_chrdev_region(dev_first, devices); + unregister_chrdev_region(usdr_dev_first, TOT_USDR_DEVS); + unregister_chrdev_region(xmass_dev_first, TOT_XMASS_DEVS); while (ptr != NULL) { next = ptr->next; kfree(ptr); ptr = next; } + + while (xptr != NULL) { + xnext = xptr->next; + kfree(xptr); + xptr = xnext; + } } From 8a72868960c16c9a94c71ebfaf3f9539411b9f5f Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 24 Mar 2026 02:40:41 +0400 Subject: [PATCH 369/397] xmass: firmware update utility --- src/tools/xmass_fwupd.c | 108 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/tools/xmass_fwupd.c diff --git a/src/tools/xmass_fwupd.c b/src/tools/xmass_fwupd.c new file mode 100644 index 00000000..55d21e75 --- /dev/null +++ b/src/tools/xmass_fwupd.c @@ -0,0 +1,108 @@ +// Copyright (c) 2026 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCIE_XMASS_DRIVER_MAGIC 0xDC +#define PCIE_FLASH_READ _IOWR(PCIE_XMASS_DRIVER_MAGIC, 1, uint8_t*) +#define PCIE_FLASH_ERASE _IOWR(PCIE_XMASS_DRIVER_MAGIC, 2, uint32_t) +#define PCIE_FLASH_WRITE _IOWR(PCIE_XMASS_DRIVER_MAGIC, 3, uint8_t*) +#define PCIE_GETIDS _IOWR(PCIE_XMASS_DRIVER_MAGIC, 4, uint8_t*) + +#define BUFFER_SIZE 65536 + +int main(int argc, char *argv[]) +{ + int fd; + uint32_t magic = 0; + uint8_t buffer[BUFFER_SIZE]; + uint8_t rb_buffer[BUFFER_SIZE]; + uint8_t info[10]; + int do_info = 0; + + const char* device_name = (argc >= 3) ? argv[2] : "/dev/xmass0"; + + if (argc < 2) { + fprintf(stderr, "Usage: %s filename.bin [/dev/xmass0]\n", argv[0]); + fprintf(stderr, "Usage: %s info -- display actual firmware version\n", argv[0]); + return EXIT_FAILURE; + } + + do_info = (strcmp(argv[1], "info") == 0); + if (!do_info) { + FILE *file = fopen(argv[1], "rb"); + if (file == NULL) { + perror("Error opening file"); + return EXIT_FAILURE; + } + + size_t bytesRead = fread(buffer, 1, BUFFER_SIZE, file); + printf("Read %zu bytes from %s\n", bytesRead, argv[1]); + + fclose(file); + + if (bytesRead != BUFFER_SIZE) { + fprintf(stderr, "File is too small, only got %zd bytes!\n", bytesRead); + return EXIT_FAILURE; + } + } + + fd = open(device_name, O_RDWR); + if (fd < 0) { + perror("Could't open device"); + return EXIT_FAILURE; + } + + if (ioctl(fd, PCIE_GETIDS, info) < 0) { + perror("Unable to get ids"); + close(fd); + return EXIT_FAILURE; + } + + printf("ASM2806 Firmware in use: %02x%02x%02x%02x%02x%02x, FlashID: %02x %02x %02x\n", + info[0], info[1], info[2], info[3], info[4], info[5], + info[6], info[7], info[8]); + + if (do_info) { + close(fd); + return EXIT_SUCCESS; + } + + printf("Opened %s, flashing %s\n", device_name, argv[1]); + printf("Erasing flash...\n"); + + if (ioctl(fd, PCIE_FLASH_ERASE, magic) < 0) { + perror("Erasing flash error"); + close(fd); + return EXIT_FAILURE; + } + + printf("Writing new image...\n"); + if (ioctl(fd, PCIE_FLASH_WRITE, buffer) < 0) { + perror("Writing flash error"); + close(fd); + return EXIT_FAILURE; + } + + printf("Verifying image...\n"); + if (ioctl(fd, PCIE_FLASH_READ, rb_buffer) < 0) { + perror("Readback flash error"); + close(fd); + return EXIT_FAILURE; + } + + if (memcmp(buffer, rb_buffer, 0xE00) || memcmp(buffer + 0xF00, rb_buffer + 0xF00, BUFFER_SIZE - 0xF00)) { + fprintf(stderr, "Verification failed!\n"); + return EXIT_FAILURE; + } + + close(fd); + return EXIT_SUCCESS; +} From f5ff3a341880947fb29b0c0ab2360ccea1abc207 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 24 Mar 2026 03:21:34 +0400 Subject: [PATCH 370/397] xmass: add rev1a control --- src/lib/device/ext_xmass/ext_xmass.c | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/lib/device/ext_xmass/ext_xmass.c b/src/lib/device/ext_xmass/ext_xmass.c index 0a579cb9..0755d031 100644 --- a/src/lib/device/ext_xmass/ext_xmass.c +++ b/src/lib/device/ext_xmass/ext_xmass.c @@ -10,6 +10,8 @@ #include "../hw/tca9555/tca9555.h" #include "../hw/lmk05318/lmk05318.h" +#include "../hw/tmp114/tmp114.h" +#include "../hw/at24/at24.h" #include "def_ext_xmass_ctrl.h" @@ -50,6 +52,8 @@ enum { // OUT5 aux_p + aux_n // OUT6 REF / LVCMOS // OUT7 1PPS / LVCMOS +// TMP114NAIYMTR 1001111 +// TMP114NBIYMTR 1001110 // // M2_Connector (master) // LED1/SDA CLK_SDA @@ -80,6 +84,12 @@ enum { I2C_ADDR_XRA1201 = 0x14, I2C_GPS_RX = 0x20, I2C_GPS_TX = 0x21, + + I2C_TMP114NB = 0x4E, + I2C_TMP114NA = 0x4F, + + I2C_DEV_AT24_MEM = 0x50, + I2C_DEV_AT24_SEC = 0x58, }; static int _board_xmass_fill_lmk05318(board_xmass_t* ob, lmk05318_out_config_t lmk05318_outs_cfg[8]) @@ -127,6 +137,9 @@ int board_xmass_init(lldev_t dev, unsigned i2c_lmka = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_LMK); unsigned i2c_xraa = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_ADDR_XRA1201); + unsigned i2c_tmpa = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_TMP114NA); + unsigned i2c_tmpb = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_TMP114NB); + unsigned i2c_at24 = MAKE_LSOP_I2C_ADDR(LSOP_I2C_INSTANCE(i2c_loc), LSOP_I2C_BUSNO(i2c_loc), I2C_DEV_AT24_SEC); uint16_t val; uint16_t out_msk = 0xe000; @@ -200,6 +213,26 @@ int board_xmass_init(lldev_t dev, ob->i2c_xraa = i2c_xraa; + int ida, idb, temp; + res = res ? res : tmp114_devid_get(dev, subdev, i2c_tmpa, &ida); + if (res == 0 && ida == 0x1114) { + res = res ? res : tmp114_temp_get(dev, subdev, i2c_tmpa, &temp); + USDR_LOG("XMSS", USDR_LOG_INFO, "Rev.1a: TempA = %.2fC\n", temp / 256.0); + } + res = res ? res : tmp114_devid_get(dev, subdev, i2c_tmpb, &idb); + if (res == 0 && idb == 0x1114) { + res = res ? res : tmp114_temp_get(dev, subdev, i2c_tmpb, &temp); + + USDR_LOG("XMSS", USDR_LOG_INFO, "Rev.1a: TempB = %.2fC\n", temp / 256.0); + } + + if (res == 0 && (ida == 0x1114 || idb == 0x1114)) { + uint8_t s[16] = { 0, }; + res = res ? res : at24_saddr_mem_get(dev, subdev, i2c_at24, AT24_SECURE_SERIAL_OFF, 16, s); + USDR_LL_LOG(dev, "XMSS", USDR_LOG_WARNING, "AT24_SERIAL: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]); + } + //res = (res) ? res : tca9555_reg16_set(dev, subdev, i2c_xraa, TCA9555_OUT0, (3) | (1 << 4) | (1 << 8) | (1 << 7) | (1 << 5) | (1 << 10)); return res; } From 9550553504f4a5d710eeb664df66b5112e8be490 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 2 Apr 2026 00:14:03 +0400 Subject: [PATCH 371/397] xmass: add forgotten defines --- src/lib/lowlevel/pcie_uram/pcie_uram_driver_if.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/lib/lowlevel/pcie_uram/pcie_uram_driver_if.h b/src/lib/lowlevel/pcie_uram/pcie_uram_driver_if.h index f7862b77..e9956a08 100644 --- a/src/lib/lowlevel/pcie_uram/pcie_uram_driver_if.h +++ b/src/lib/lowlevel/pcie_uram/pcie_uram_driver_if.h @@ -178,4 +178,20 @@ struct pcie_driver_woa_oob { #define PCIE_DRIVER_DMA_POST _IOW(PCIE_DRIVER_MAGIC, 25, uint32_t) +// XMASS specific functions +struct xmass_iop { + unsigned io_len; // + unsigned delay_ns; // + uint8_t* out_buf; // Write buffer + uint8_t* in_buf; // Readback buffer +}; + +// +#define PCIE_XMASS_DRIVER_MAGIC 0xDC +#define PCIE_GPIOS_8 _IOWR(PCIE_XMASS_DRIVER_MAGIC, 0, struct xmass_iop) +#define PCIE_FLASH_READ _IOWR(PCIE_XMASS_DRIVER_MAGIC, 1, uint8_t*) +#define PCIE_FLASH_ERASE _IOWR(PCIE_XMASS_DRIVER_MAGIC, 2, uint32_t) +#define PCIE_FLASH_WRITE _IOWR(PCIE_XMASS_DRIVER_MAGIC, 3, uint8_t*) +#define PCIE_GETIDS _IOWR(PCIE_XMASS_DRIVER_MAGIC, 4, uint8_t*) + #endif From 567e453a404128cf6a140acfbcf5189725f9206d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 9 Apr 2026 03:08:16 +0400 Subject: [PATCH 372/397] gearbox: add extended API to configure FIR on indexed registers --- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 4 ++-- src/lib/ipblks/fgearbox.c | 27 +++++++++++++++------------ src/lib/ipblks/fgearbox.h | 4 ++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 12a2c509..2172dbde 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1105,7 +1105,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, usleep(10); dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x2); usleep(10); - res = (res) ? res : fgearbox_load_fir_ex(dev, IGPO_DSPCHAIN_RX_PRG, rx_dec, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); + res = (res) ? res : fgearbox_load_fir_ex(dev, 0, IGPO_DSPCHAIN_RX_PRG << 24, rx_dec, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); usleep(10); dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x0); @@ -1119,7 +1119,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, usleep(10); dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x2); usleep(10); - res = (res) ? res : fgearbox_load_fir_i_ex(dev, IGPO_DSPCHAIN_TX_PRG, tx_inr, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); + res = (res) ? res : fgearbox_load_fir_i_ex(dev, 0, IGPO_DSPCHAIN_TX_PRG << 24, tx_inr, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); usleep(10); dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x0); diff --git a/src/lib/ipblks/fgearbox.c b/src/lib/ipblks/fgearbox.c index 2f9339ee..a00df918 100644 --- a/src/lib/ipblks/fgearbox.c +++ b/src/lib/ipblks/fgearbox.c @@ -1315,16 +1315,19 @@ static const uint8_t fir_data_dec256_clkr2[1280] = { // BITS_PER_DSP -static int dev_gpo_set(lldev_t dev, unsigned bank, unsigned data) -{ - return lowlevel_reg_wr32(dev, 0, 0, ((bank & 0x7f) << 24) | (data & 0xff)); -} +//static int dev_gpo_set(lldev_t dev, unsigned bank, unsigned data)/ +//{ +// return lowlevel_reg_wr32(dev, 0, 0, ((bank & 0x7f) << 24) | (data & 0xff)); +//} + +#define MAKE_GPO_MSK(bank) ((bank & 0x7f) << 24) +#define GPO_REG 0 -int fgearbox_load_ucode(lldev_t dev, unsigned gport, const uint8_t* ucode, unsigned sleep_us) +static int fgearbox_load_ucode(lldev_t dev, unsigned reg, unsigned mask, const uint8_t* ucode, unsigned sleep_us) { int res; for (unsigned i = 0; i < UCODE_SIZE; i++) { - res = dev_gpo_set(dev, gport, ucode[i]); + res = lowlevel_reg_wr32(dev, 0, reg, mask | ucode[i]); if (res) return res; @@ -1337,10 +1340,10 @@ int fgearbox_load_ucode(lldev_t dev, unsigned gport, const uint8_t* ucode, unsig int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam) { - return fgearbox_load_fir_ex(dev, gport, fir, fam, 0); + return fgearbox_load_fir_ex(dev, GPO_REG, MAKE_GPO_MSK(gport), fir, fam, 0); } -int fgearbox_load_fir_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us) +int fgearbox_load_fir_ex(lldev_t dev, unsigned reg, unsigned mask, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us) { const uint8_t* s_st8_dsp; @@ -1399,16 +1402,16 @@ int fgearbox_load_fir_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfa return -EINVAL; } - return fgearbox_load_ucode(dev, gport, s_st8_dsp, sleep_us); + return fgearbox_load_ucode(dev, reg, mask, s_st8_dsp, sleep_us); } int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam) { - return fgearbox_load_fir_i_ex(dev, gport, fir, fam, 0); + return fgearbox_load_fir_i_ex(dev, GPO_REG, MAKE_GPO_MSK(gport), fir, fam, 0); } -int fgearbox_load_fir_i_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us) +int fgearbox_load_fir_i_ex(lldev_t dev, unsigned reg, unsigned int mask, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us) { const uint8_t* s_st8_dsp; @@ -1444,7 +1447,7 @@ int fgearbox_load_fir_i_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dsp return -EINVAL; } - return fgearbox_load_ucode(dev, gport, s_st8_dsp, sleep_us); + return fgearbox_load_ucode(dev, reg, mask, s_st8_dsp, sleep_us); } diff --git a/src/lib/ipblks/fgearbox.h b/src/lib/ipblks/fgearbox.h index b5132052..200d4820 100644 --- a/src/lib/ipblks/fgearbox.h +++ b/src/lib/ipblks/fgearbox.h @@ -40,7 +40,7 @@ typedef enum dspfamily { int fgearbox_load_fir(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam); int fgearbox_load_fir_i(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam); -int fgearbox_load_fir_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us); -int fgearbox_load_fir_i_ex(lldev_t dev, unsigned gport, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us); +int fgearbox_load_fir_ex(lldev_t dev, unsigned reg, unsigned mask, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us); +int fgearbox_load_fir_i_ex(lldev_t dev, unsigned reg, unsigned mask, fgearbox_firs_t fir, dspfamily_t fam, unsigned sleep_us); #endif From 72121cbb6974c733e6849d0ba49a9dc74343f7a9 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 9 Apr 2026 03:09:16 +0400 Subject: [PATCH 373/397] opt: add ABS() macro --- src/lib/cal/opt_func.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/cal/opt_func.h b/src/lib/cal/opt_func.h index 5c37a9ab..c8b8a9c6 100644 --- a/src/lib/cal/opt_func.h +++ b/src/lib/cal/opt_func.h @@ -22,6 +22,10 @@ __typeof__ (b) _b = (b); \ _a < _b ? _a : _b; }) +#define ABS(a) \ + ({ __typeof__ (a) _a = (a); \ + _a < 0 ? -_a : a; }) + typedef int (*evaluate_fn_t)(void* param, int value, int* func); /* find local minimum of fn() within [start; stop] range From a4c135c664a52cdf1e5e999e73230c3ccb4fac69 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 9 Apr 2026 03:09:52 +0400 Subject: [PATCH 374/397] usdr: add extended DSP FE for TX/RX --- src/lib/device/m2_lm6_1/m2_lm6_1.c | 217 +++++++++++++++++++++-- src/lib/device/m2_lm6_1/usdr_ctrl.c | 255 ++++++++++++++++++++++------ src/lib/device/m2_lm6_1/usdr_ctrl.h | 43 ++++- 3 files changed, 448 insertions(+), 67 deletions(-) diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index ee33b0bc..ae4ac5be 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "../device.h" #include "../device_ids.h" @@ -116,8 +118,8 @@ const usdr_dev_param_constant_t s_params_m2_lm6_1_rev000[] = { { "/ll/sdr/max_hw_rx_chans", 1 }, { "/ll/sdr/max_hw_tx_chans", 1 }, - { "/ll/sdr/max_sw_rx_chans", 1 }, - { "/ll/sdr/max_sw_tx_chans", 1 }, +// { "/ll/sdr/max_sw_rx_chans", 2 }, +// { "/ll/sdr/max_sw_tx_chans", 2 }, { "/ll/poll_event/in", M2PCI_INT_RX }, { "/ll/poll_event/out", M2PCI_INT_TX }, @@ -136,6 +138,8 @@ static const vfs_constant_str_t s_params_m2_lm6_1_rev000_s[] = { { "/ll/device/name", "usdr"}, }; +static int dev_m2_lm6_1_max_sw_rx_chans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); +static int dev_m2_lm6_1_max_sw_tx_chans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue); static int dev_m2_lm6_1_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -146,6 +150,9 @@ static int dev_m2_lm6_1_pwren_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t va static int dev_m2_lm6_1_sdr_rx_freq_lob_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_tx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm6_1_sdr_rx_freqbb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm6_1_sdr_tx_freqbb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_lm6_1_sdr_rx_gain_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_tx_gain_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_tx_gain_vga1_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -210,6 +217,9 @@ static int dev_m2_lm6_1_sdr_dccorr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 static const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { + { "/ll/sdr/max_sw_rx_chans", { NULL, dev_m2_lm6_1_max_sw_rx_chans_get } }, + { "/ll/sdr/max_sw_tx_chans", { NULL, dev_m2_lm6_1_max_sw_tx_chans_get } }, + { "/dm/rate/master", { dev_m2_lm6_1_rate_set, NULL }}, { "/dm/rate/rxtxadcdac", { dev_m2_lm6_1_rate_m_set, NULL }}, @@ -235,6 +245,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/rx/frequency/lob",{ dev_m2_lm6_1_sdr_rx_freq_lob_set, NULL }}, { "/dm/sdr/0/rx/frequency", { dev_m2_lm6_1_sdr_rx_freq_set, NULL }}, { "/dm/sdr/0/tx/frequency", { dev_m2_lm6_1_sdr_tx_freq_set, NULL }}, + { "/dm/sdr/0/rx/frequency/bb", { dev_m2_lm6_1_sdr_rx_freqbb_set, NULL }}, + { "/dm/sdr/0/tx/frequency/bb", { dev_m2_lm6_1_sdr_tx_freqbb_set, NULL }}, /* TODO: delete block below after several releases, these are just aliases to above due typo for compatibility with old code */ { "/dm/sdr/0/rx/freqency/lob",{ dev_m2_lm6_1_sdr_rx_freq_lob_set, NULL }}, @@ -275,6 +287,61 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/rfe/throttle", { dev_m2_lm6_1_sdr_rfe_throttle_set, NULL }}, }; +static const usdr_dev_link_t s_links[] = { + { "/dm/sdr/0/rx/frequency/0", "/dm/sdr/0/rx/frequency" }, + { "/dm/sdr/0/rx/frequency/1", "/dm/sdr/0/rx/frequency" }, + { "/dm/sdr/0/tx/frequency/0", "/dm/sdr/0/tx/frequency" }, + { "/dm/sdr/0/tx/frequency/1", "/dm/sdr/0/tx/frequency" }, + { "/dm/sdr/0/rx/frequency/bb/0", "/dm/sdr/0/rx/frequency/bb" }, + { "/dm/sdr/0/rx/frequency/bb/1", "/dm/sdr/0/rx/frequency/bb" }, + { "/dm/sdr/0/tx/frequency/bb/0", "/dm/sdr/0/tx/frequency/bb" }, + { "/dm/sdr/0/tx/frequency/bb/1", "/dm/sdr/0/tx/frequency/bb" }, + + { "/dm/sdr/0/rx/gain/0", "/dm/sdr/0/rx/gain" }, + { "/dm/sdr/0/tx/gain/0", "/dm/sdr/0/tx/gain" }, + // { "/dm/sdr/0/tx/gain/lb/0", "/dm/sdr/0/tx/gain/lb" }, + { "/dm/sdr/0/tx/gain/vga1/0", "/dm/sdr/0/tx/gain/vga1" }, + { "/dm/sdr/0/tx/gain/vga2/0", "/dm/sdr/0/tx/gain/vga2" }, + { "/dm/sdr/0/rx/gain/pga/0", "/dm/sdr/0/rx/gain/pga" }, + { "/dm/sdr/0/rx/gain/vga/0", "/dm/sdr/0/rx/gain/vga" }, + { "/dm/sdr/0/rx/gain/vga2a/0", "/dm/sdr/0/rx/gain/vga2a" }, + { "/dm/sdr/0/rx/gain/vga2b/0", "/dm/sdr/0/rx/gain/vga2b" }, + { "/dm/sdr/0/rx/gain/lna/0", "/dm/sdr/0/rx/gain/lna" }, + // { "/dm/sdr/0/rx/gain/lb/0", "/dm/sdr/0/rx/gain/lb" }, + { "/dm/sdr/0/rx/gain/1", "/dm/sdr/0/rx/gain" }, + { "/dm/sdr/0/tx/gain/1", "/dm/sdr/0/tx/gain" }, + // { "/dm/sdr/0/tx/gain/lb/1", "/dm/sdr/0/tx/gain/lb" }, + { "/dm/sdr/0/tx/gain/vga1/1", "/dm/sdr/0/tx/gain/vga1" }, + { "/dm/sdr/0/tx/gain/vga2/1", "/dm/sdr/0/tx/gain/vga2" }, + { "/dm/sdr/0/rx/gain/pga/1", "/dm/sdr/0/rx/gain/pga" }, + { "/dm/sdr/0/rx/gain/vga/1", "/dm/sdr/0/rx/gain/vga" }, + { "/dm/sdr/0/rx/gain/vga2a/1", "/dm/sdr/0/rx/gain/vga2a" }, + { "/dm/sdr/0/rx/gain/vga2b/1", "/dm/sdr/0/rx/gain/vga2b" }, + { "/dm/sdr/0/rx/gain/lna/1", "/dm/sdr/0/rx/gain/lna" }, + // { "/dm/sdr/0/rx/gain/lb/1", "/dm/sdr/0/rx/gain/lb" }, + + { "/dm/sdr/0/rx/bandwidth/0", "/dm/sdr/0/rx/bandwidth" }, + { "/dm/sdr/0/tx/bandwidth/0", "/dm/sdr/0/tx/bandwidth" }, + { "/dm/sdr/0/rx/bandwidth/1", "/dm/sdr/0/rx/bandwidth" }, + { "/dm/sdr/0/tx/bandwidth/1", "/dm/sdr/0/tx/bandwidth" }, + + { "/dm/sdr/0/rx/path/0", "/dm/sdr/0/rx/path" }, + { "/dm/sdr/0/rx/path/1", "/dm/sdr/0/rx/path" }, + { "/dm/sdr/0/tx/path/0", "/dm/sdr/0/tx/path" }, + { "/dm/sdr/0/tx/path/1", "/dm/sdr/0/tx/path" }, + + { "/dm/sdr/0/rx/dccorr/0", "/dm/sdr/0/rx/dccorr" }, + { "/dm/sdr/0/tx/dccorr/0", "/dm/sdr/0/tx/dccorr" }, + // { "/dm/sdr/0/rx/phgaincorr/0","/dm/sdr/0/rx/phgaincorr" }, + // { "/dm/sdr/0/tx/phgaincorr/0","/dm/sdr/0/tx/phgaincorr" }, + { "/dm/sdr/0/rx/dccorr/1", "/dm/sdr/0/rx/dccorr" }, + { "/dm/sdr/0/tx/dccorr/1", "/dm/sdr/0/tx/dccorr" }, + // { "/dm/sdr/0/rx/phgaincorr/1","/dm/sdr/0/rx/phgaincorr" }, + // { "/dm/sdr/0/tx/phgaincorr/1","/dm/sdr/0/tx/phgaincorr" }, + +}; + + struct dev_m2_lm6_1 { device_t base; @@ -316,6 +383,70 @@ static int find_param_list(const char* param, const param_list_idx_t* lst, unsig } #endif +static int _channel_info_string_parse(char* chanlist, unsigned max_chans, unsigned* cinfo) +{ + unsigned ch = 0; + for (; *chanlist; chanlist++) { + unsigned chn; + if (isdigit(*chanlist)) { + chn = atoi(chanlist); + } else { + return -ENAVAIL; + } + + if (chn > max_chans) { + USDR_LOG("STRM", USDR_LOG_ERROR, "Channel parsing: incorrect channel num: %d\n", chn); + return -EINVAL; + } + + ch |= 1 << chn; + } + + *cinfo = ch; + return 0; +} + +static int _device_path_to_chmsk(const char* full_path, unsigned max_chs, unsigned* lms_ch) +{ + char chanlist[64*4]; + const char* lst; + const char* pos = full_path; + lst = NULL; + + while ((pos = strchr(pos, '/')) != NULL) { + lst = ++pos; + } + if (lst == NULL) { + return -ENAVAIL; + } + + SAFE_STRCPY(chanlist, lst); + return _channel_info_string_parse(chanlist, max_chs, lms_ch); +} + +static int _iterate_ordinal_chans(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val, bool rxchans) +{ + vfs_object_t ph; + unsigned selected; + const unsigned max_chs = 2; + + int res = _device_path_to_chmsk(obj->full_path, max_chs, &selected); + if (res == -ENAVAIL) { + selected = (1 << max_chs) - 1; + res = 0; + } else if (res != 0) { + return res; + } + + ph.type = obj->type; + ph.object = obj->object; + ph.data = obj->data; + ph.ops = obj->ops; + ph.full_path[0] = 0; + ph.full_path[1] = selected; + return obj->ops.si64(&ph, val); +} + static int dev_gpo_set(lldev_t dev, unsigned bank, unsigned data) { return lowlevel_reg_wr32(dev, 0, 0, ((bank & 0x7f) << 24) | (data & 0xff)); @@ -326,6 +457,20 @@ static int dev_gpi_get32(lldev_t dev, unsigned bank, unsigned* data) return lowlevel_reg_rd32(dev, 0, 16 + (bank / 4), data); } +int dev_m2_lm6_1_max_sw_rx_chans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + *ovalue = d->d.has_rxchain ? 2 : 1; + return 0; +} + +int dev_m2_lm6_1_max_sw_tx_chans_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + *ovalue = d->d.has_txchain ? 2 : 1; + return 0; +} + int dev_m2_lm6_1_sdr_clkmeas_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { return dev_gpo_set(ud->dev, 16, value); @@ -590,16 +735,45 @@ int dev_m2_lm6_1_sdr_rx_freq_lob_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t return usdr_set_lob_freq(&d->d, value); } -int dev_m2_lm6_1_sdr_rx_freq_set(pdevice_t ud, UNUSED pusdr_vfs_obj_t obj, uint64_t value) +int dev_m2_lm6_1_sdr_rx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + if (obj->full_path[0]) { + return _iterate_ordinal_chans(ud, obj, value, true); + } + + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + return usdr_rfic_fe_set_freq(&d->d, FE_FREQ_LO_RX, obj->full_path[1], value, NULL); +} +int dev_m2_lm6_1_sdr_tx_freq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + if (obj->full_path[0]) { + return _iterate_ordinal_chans(ud, obj, value, false); + } + + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + return usdr_rfic_fe_set_freq(&d->d, FE_FREQ_LO_TX, obj->full_path[1], value, NULL); +} + +int dev_m2_lm6_1_sdr_rx_freqbb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { + if (obj->full_path[0]) { + return _iterate_ordinal_chans(ud, obj, value, true); + } + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - return usdr_rfic_fe_set_freq(&d->d, false, value, NULL); + return usdr_rfic_fe_set_freq(&d->d, FE_FREQ_BB_RX, obj->full_path[1], (int64_t)value, NULL); } -int dev_m2_lm6_1_sdr_tx_freq_set(pdevice_t ud, UNUSED pusdr_vfs_obj_t obj, uint64_t value) + +int dev_m2_lm6_1_sdr_tx_freqbb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { + if (obj->full_path[0]) { + return _iterate_ordinal_chans(ud, obj, value, false); + } + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - return usdr_rfic_fe_set_freq(&d->d, true, value, NULL); + return usdr_rfic_fe_set_freq(&d->d, FE_FREQ_BB_TX, obj->full_path[1], (int64_t)value, NULL); } + int dev_m2_lm6_1_sdr_rx_gain_set(pdevice_t ud, UNUSED pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; @@ -738,7 +912,12 @@ int dev_m2_lm6_1_sdr_rx_ip2corr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t int dev_m2_lm6_1_sdr_tx_dccorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - return -EINVAL; + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + + unsigned vi = (value >> 16) & 0xffff; + unsigned vq = (value >> 0) & 0xffff; + + return usdr_tx_dccorr(&d->d, vi, vq); } int dev_m2_lm6_1_sdr_rx_tia_cfb_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -935,7 +1114,7 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha } if (d->d.rx_lo == 0) { - res = usdr_rfic_fe_set_freq(&d->d, false, 320e6, NULL); + res = usdr_rfic_fe_set_freq(&d->d, false, ~0U, 320e6, NULL); if (res) { return res; } @@ -948,8 +1127,14 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha return res; } - if (d->d.rx_lo != 0) { - usdr_rfic_fe_set_freq(&d->d, false, d->d.rx_lo, NULL); + //if (d->d.rx_lo != 0) { + // usdr_rfic_fe_set_freq(&d->d, false, d->d.rx_lo, NULL); + //} + + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (d->d.rx_raw.lo[i].set) { + usdr_rfic_fe_set_freq(&d->d, false, 1 << i, d->d.rx_raw.lo[i].value, NULL); + } } res = create_sfetrx4_stream(dev, CORE_SFERX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, @@ -958,6 +1143,7 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha if (res) { return res; } + d->d.rx_lchans = chans; *out_handle = d->rx; } else if (strstr(sid, "tx") != NULL) { if (d->tx) { @@ -974,7 +1160,10 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha if (res) { return res; } + d->d.tx_lchans = chans; *out_handle = d->tx; + + // TODO: handle NCO changes } return res; @@ -988,10 +1177,12 @@ int usdr_device_m2_lm6_1_unregister_stream(device_t* dev, stream_handle_t* strea usdr_rfic_streaming_down(&d->d, RFIC_LMS6_TX); d->tx->ops->destroy(d->tx); d->tx = NULL; + d->d.tx_lchans = 0; } else if (stream == d->rx) { usdr_rfic_streaming_down(&d->d, RFIC_LMS6_RX); d->rx->ops->destroy(d->rx); d->rx = NULL; + d->d.rx_lchans = 0; } else { return -EINVAL; } @@ -1028,6 +1219,12 @@ int usdr_device_m2_lm6_1_create(lldev_t dev, /*UNUSED*/ device_id_t devid) if (res) goto failed_tree_creation; + res = usdr_vfs_obj_link_init_array(&d->base, + s_links, + SIZEOF_ARRAY(s_links)); + if (res) + goto failed_tree_creation; + d->base.initialize = &usdr_device_m2_lm6_1_initialize; d->base.destroy = &usdr_device_m2_lm6_1_destroy; d->base.create_stream = &usdr_device_m2_lm6_1_create_stream; diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index ee7a5949..fb5a521a 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -64,6 +64,20 @@ enum lms6_vios { LMS6_VIO_BOOST = 1950, }; +enum fpga_phy_regs { + CFG_REG_RESET = 0, + CFG_REG_DCCTRL = 1, + CFG_REG_IQIMB_0 = 2, + CFG_REG_IQIMB_1 = 3, + CFG_REG_IQIMB_2 = 4, + CFG_REG_IQIMB_3 = 5, + CFG_REG_NCO0_L = 8, + CFG_REG_NCO0_H = 9, + CFG_REG_NCO1_L = 10, + CFG_REG_NCO1_H = 11, + CFG_REG_DSP_LD = 64, +}; + // RX chain // LNA_GAIN -> mixer -> VGA1_GAIN -> lpf -> VGA2_GAIN[a,b] -> adc @@ -264,6 +278,29 @@ static int _usdr_set_lna_rx(usdr_dev_t *d, unsigned cfg_idx) return usdr_set_rx_port_switch(d, /*d->rx_lna_lb_active ? cfg->swlb :*/ cfg->sw); } +static int _usdr_set_nco(usdr_dev_t *d, bool rx, unsigned nco_num, double freq) +{ + unsigned raw_rate = (rx) ? d->adc_clk : d->dac_clk; + double rel_f = freq / raw_rate; // [-1 .. 1] + if ((rel_f > 1) || (rel_f < -1)) { + USDR_LOG("UDEV", USDR_LOG_WARNING, "NCO_%s_%d: Frequency %.0f is out of ADC/DAC range %u!\n", + rx ? "RX" : "TX", nco_num, freq, raw_rate); + + rel_f = -1; + } + int32_t nco_freq = rel_f * INT_MAX; + nco_freq <<= 1; + unsigned reg = rx ? REG_CFG_PHY_0 : REG_CFG_PHY_1; + unsigned off = 8 + 2 * nco_num; + int res = 0; + + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, reg, ((off + 0) << 24) | (nco_freq & 0xffff)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, reg, ((off + 1) << 24) | ((nco_freq >> 16) & 0xffff)); + + USDR_LOG("UDEV", USDR_LOG_WARNING, "NCO_%s_%d: Set to %.3f KHz -- %0.3f %08x -- rate: %.3f MSPS\n", + rx ? "RX" : "TX", nco_num, rel_f * raw_rate / 1.0e3, rel_f, nco_freq, raw_rate / 1e6); + return res; +} static int _usdr_set_lna_tx(usdr_dev_t *d, unsigned cfg_idx) { @@ -366,6 +403,8 @@ int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob) return usdr_set_samplerate_ex(d, d->rawsamplerate, d->rawsamplerate, 0, 0, 0); } +#define TARGET_RATE 30720000 + int usdr_set_samplerate_ex(struct usdr_dev *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, @@ -373,22 +412,20 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, { lldev_t dev = d->base.dev; unsigned rate = (rxrate == 0) ? txrate : rxrate; - unsigned freq = rate << 1; //Link speed x2 sample rate - struct si5332_layout_info nfo = { d->fref, freq }; + struct si5332_layout_info nfo = { d->fref, rate << 1 }; //Link speed x2 sample rate int res = 0; - unsigned i = 0; - unsigned int_decim[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - - /* - for (unsigned ii = 0; ii < SIZEOF_ARRAY(int_decim); ii++) { - if (rxrate * int_decim[ii] < 60e6) - i = ii; - else - break; - } - */ + unsigned ind = 0; + unsigned int_dec_x[] = { 1, 2, 4, 8, 16, 32 /*, 64, 128, 256 */ }; + + if (d->has_rxchain && d->has_txchain) { + for (; ind < SIZEOF_ARRAY(int_dec_x); ind++) { + if (rate * int_dec_x[ind] >= TARGET_RATE) + break; + } - nfo.out *= int_decim[i]; + rate *= int_dec_x[ind]; + nfo.out = rate << 1; + } if (rate >= 60e6 && !d->vio_boost) { USDR_LOG("UDEV", USDR_LOG_WARNING, "Boosting Vio to get stable samplerates over 60Msps\n"); @@ -406,30 +443,59 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, // TODO: Add ability to alter it d->mixer_lo = d->si_vco_freq / d->si_vco_div; d->rawsamplerate = nfo.out; - /* - if (d->rxbb_decim != int_decim[i]) { - res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSP_RX_CTRL, 0x0); - res = (res) ? res : fgearbox_load_fir(d->base.dev, IGPO_DSP_RX_CFG, (fgearbox_firs_t)d->rxbb_decim, DSP_7SERIES); - res = (res) ? res : dev_gpo_set(d->base.dev, IGPO_DSP_RX_CTRL, 0x0); + + if (d->has_rxchain && rxrate && d->rxbb_decim != int_dec_x[ind]) { + d->rxbb_decim = int_dec_x[ind]; + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, 15); + res = res ? res : usleep(1); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, 1 | (1<<3)); + + res = (res) ? res : fgearbox_load_fir_ex(d->base.dev, REG_CFG_PHY_0, CFG_REG_DSP_LD << 24, (fgearbox_firs_t)d->rxbb_decim, DSP_7SERIES, 1); + } + if (d->has_txchain && txrate && d->txbb_intr != int_dec_x[ind]) { + d->txbb_intr = int_dec_x[ind]; + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_1, 7); + res = res ? res : usleep(1); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_1, 0); + + res = (res) ? res : fgearbox_load_fir_i_ex(d->base.dev, REG_CFG_PHY_1, CFG_REG_DSP_LD << 24, (fgearbox_firs_t)d->txbb_intr, DSP_7SERIES, 10); } - */ + + d->dac_clk = rate; + d->adc_clk = rate; // Update FE - res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, 7); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, 1); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_1, 7); res = res ? res : usleep(10); res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, 0); - res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, (1 << 24) | 1); + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_1, 0); - res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, (8 << 24) | 0); - res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, (9 << 24) | 16384); + // DC control + res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_0, (1 << 24) | 1); + // res = res ? res : lowlevel_reg_wr32(dev, 0, REG_CFG_PHY_1, (1 << 24) | 0); + + // Update NCOs + for (unsigned rxgrp = 0; rxgrp < 2; rxgrp++) { + bool istx = (rxgrp == 1); + freq_data_t* freqd = (istx) ? &d->tx_raw : &d->rx_raw; + + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (freqd->bb[i].set) { + res = res ? res : _usdr_set_nco(d, !istx, i, (int32_t)freqd->bb[i].value); + } else { + res = res ? res : _usdr_set_nco(d, !istx, i, 0); + } + } + } - uint32_t v = 0; - res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &v); + uint32_t v = 0; + res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &v); - USDR_LOG("UDEV", USDR_LOG_WARNING, "V=%08x\n", v); + USDR_LOG("UDEV", USDR_LOG_WARNING, "V=%08x\n", v); - d->rxbb_decim = int_decim[i]; - d->txbb_intr = int_decim[i]; + d->rxbb_decim = int_dec_x[ind]; + d->txbb_intr = int_dec_x[ind]; // Apply automatic RF Freq correction if external mixer is active if (d->mexir_en) { @@ -438,13 +504,13 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, // If user didn't set BW filter set it to samplerate if (!d->rx_bw.set && rxrate > 1) { - res = res ? res : lms6002d_set_bandwidth(&d->lms, false, rxrate); + res = res ? res : lms6002d_set_bandwidth(&d->lms, false, 2 * d->rx_nco_distance + rxrate); } if (!d->tx_bw.set && txrate > 1) { - res = res ? res : lms6002d_set_bandwidth(&d->lms, true, txrate); + res = res ? res : lms6002d_set_bandwidth(&d->lms, true, 2 * d->tx_nco_distance + txrate); } - USDR_LOG("UDEV", USDR_LOG_INFO, "INTR %d RX_RATE %.3f TX_RATE %.3f MXLO %.3f\n", int_decim[i], rxrate / 1.0e6, txrate / 1.0e6, d->mixer_lo / 1.0e6); + USDR_LOG("UDEV", USDR_LOG_INFO, "INTR %d RX_RATE %.3f TX_RATE %.3f MXLO %.3f\n", int_dec_x[ind], rxrate / 1.0e6, txrate / 1.0e6, d->mixer_lo / 1.0e6); return res; } @@ -519,6 +585,12 @@ int usdr_set_extref(usdr_dev_t *d, bool ext, uint32_t freq) return si5532_set_ext_clock_sw(d->base.dev, 0, I2C_BUS_SI5332A, ext); } +int usdr_tx_dccorr(usdr_dev_t *d, int16_t i, int16_t q) +{ + uint32_t val = ((((uint16_t)q) & 0xfff) << 12) | (((uint16_t)i) & 0xfff); + return lowlevel_reg_wr32(d->lms.dev, 0, REG_CFG_PHY_1, (1 << 24) | val); +} + int usdr_init(struct usdr_dev *d, int ext_clk, unsigned ext_fref) { lldev_t dev = d->base.dev; @@ -585,6 +657,10 @@ int usdr_init(struct usdr_dev *d, int ext_clk, unsigned ext_fref) d->si_vco_div = 8; d->hw_board_hasmixer = false; d->hw_board_rev = (d->hwid >> 8) & 0xff; + + d->has_rxchain = ((d->hwid >> 16) & 2) ? true : false; + d->has_txchain = ((d->hwid >> 16) & 1) ? true : false; + USDR_LOG("XDEV", USDR_LOG_WARNING, "HWID %08x USDR Board rev.%d Device `%s` FirmwareID %08x (%lld)\n", d->hwid, d->hw_board_rev, lowlevel_get_devname(dev), uaccess, (long long)get_xilinx_rev_h(uaccess)); @@ -769,49 +845,126 @@ int _usdr_lms6002_dc_calib(struct usdr_dev *d) } int usdr_rfic_fe_set_freq(struct usdr_dev *d, - bool dir_tx, + enum fe_freq_type type, + unsigned chmask, double freq, double *actualfreq) { int res; if (actualfreq) *actualfreq = freq; bool first_tx = (d->tx_lo == 0); - if (dir_tx) { - d->tx_lo = freq; + bool istx = (type == FE_FREQ_LO_TX) || (type == FE_FREQ_BB_TX); + bool islo = (type == FE_FREQ_LO_TX) || (type == FE_FREQ_LO_RX); + freq_data_t* freqd = (istx) ? &d->tx_raw : &d->rx_raw; + + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (chmask & (1 << i)) { + switch (type) { + case FE_FREQ_LO_RX: opt_u32_set_val(&d->rx_raw.lo[i], freq); break; + case FE_FREQ_LO_TX: opt_u32_set_val(&d->tx_raw.lo[i], freq); break; + case FE_FREQ_BB_RX: opt_u32_set_val(&d->rx_raw.bb[i], freq); break; + case FE_FREQ_BB_TX: opt_u32_set_val(&d->tx_raw.bb[i], freq); break; + default: + return -EINVAL; + } + } + } + + if (islo) { + double avg = 0; + unsigned cnt = 0; + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (freqd->lo[i].set) { + avg += freqd->lo[i].value; + cnt++; + } + } + avg /= cnt; + + if (!istx) { + d->rx_lo = avg; + } else { + d->tx_lo = avg; + } + + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (freqd->lo[i].set /* && freqd->bb[i].set */) { + double diff = (double)freqd->lo[i].value - avg; + opt_u32_set_val(&freqd->bb[i], (uint32_t)(int32_t)diff); + } + } } else { - d->rx_lo = freq; + // Update based on } - // Apply automatic switch, turn on pwr for RX or TX - _usdr_signal_event(d, dir_tx ? USDR_TX_LO_CHANGED : USDR_RX_LO_CHANGED); + unsigned nco_distance = 0; - if (d->mexir_en && !dir_tx) { - // upconverter mixer - freq += d->mixer_lo; + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (freqd->bb[i].set) { + nco_distance = MAX(nco_distance, ABS((int)freqd->bb[i].value)); + } } - d->rfic_rx_lo = freq; + if (nco_distance > 20e6) { + USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: NCO_DISTANCE=%u Hz is more than BB IF LPF filter limit\n", + lowlevel_get_devname(d->base.dev), 2 * nco_distance); + } + + // Apply automatic switch, turn on pwr for RX or TX + _usdr_signal_event(d, istx ? USDR_TX_LO_CHANGED : USDR_RX_LO_CHANGED); + + if (!istx) { + freq = d->rx_lo; + d->rx_nco_distance = nco_distance; - USDR_LOG("UDEV", USDR_LOG_INFO, "%s: FE_FREQ orig=%u RFIC=%u\n", - lowlevel_get_devname(d->base.dev), d->rx_lo, d->rfic_rx_lo); + if (d->mexir_en) { + // upconverter mixer + freq += d->mixer_lo; + } + d->rfic_rx_lo = freq; + + USDR_LOG("UDEV", USDR_LOG_INFO, "%s: RX_LO=%u RFIC=%u\n", + lowlevel_get_devname(d->base.dev), d->rx_lo, d->rfic_rx_lo); + } else { + freq = d->tx_lo; + d->tx_nco_distance = nco_distance; + } - res = lms6002d_tune_pll(&d->lms, dir_tx, freq); + res = lms6002d_tune_pll(&d->lms, istx, freq); if (res == -ENOLCK) { // For unrecognized reason some LMS6002 chips fail to lock TX pll before RX initialization // so we try to lock TX in standalone mode first and if fails try to initialize RX pll // and tune TX again - if (dir_tx && first_tx && d->rx_lo == 0) { - lms6002d_tune_pll(&d->lms, 0, freq); + if (istx && first_tx && d->rx_lo == 0) { + lms6002d_tune_pll(&d->lms, false, freq); } // LDO may not be ready, check again usleep(5000); - res = lms6002d_tune_pll(&d->lms, dir_tx, freq); + res = lms6002d_tune_pll(&d->lms, istx, freq); } if (res == -ENOLCK) { USDR_LOG("UDEV", USDR_LOG_ERROR, "%s: %s_LO=%u unable to lock (pwr: %d)!\n", - lowlevel_get_devname(d->base.dev), dir_tx ? "TX" : "RX", - dir_tx ? d->tx_lo : d->rx_lo, - dir_tx ? d->tx_pwren : d->rx_pwren); + lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", + istx ? d->tx_lo : d->rx_lo, + istx ? d->tx_pwren : d->rx_pwren); } + + // Update NCOs + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (freqd->bb[i].set) { + res = res ? res : _usdr_set_nco(d, !istx, i, (int32_t)freqd->bb[i].value); + } + } + + // Update BW + if ((istx && !d->tx_bw.set) || (!istx && !d->rx_bw.set)) { + unsigned rate = istx ? (d->dac_clk / d->txbb_intr) : (d->adc_clk / d->rxbb_decim); + unsigned bw = 2 * d->tx_nco_distance + rate; + + USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Updating %s bandwidth to %.3f Mhz\n", + lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", bw / 1e6); + res = res ? res : lms6002d_set_bandwidth(&d->lms, istx, bw); + } + return res; } diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.h b/src/lib/device/m2_lm6_1/usdr_ctrl.h index 5ce90796..b66666c4 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.h +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.h @@ -48,6 +48,15 @@ enum usdrgains { GAIN_TX_AUTO, }; +#define MAX_NCO_STREAMS 2 + +struct freq_data +{ + opt_u32_t lo[MAX_NCO_STREAMS]; + opt_u32_t bb[MAX_NCO_STREAMS]; +}; +typedef struct freq_data freq_data_t; + struct usdr_dev { union { @@ -66,6 +75,10 @@ struct usdr_dev unsigned refclkpath; unsigned fref; + // Configured stream count + uint8_t rx_lchans; + uint8_t tx_lchans; + uint8_t rx_cfg_path; uint8_t tx_cfg_path; @@ -87,24 +100,31 @@ struct usdr_dev bool mexir_en; bool vio_boost; + bool has_rxchain; + bool has_txchain; unsigned rawsamplerate; unsigned rxbb_decim; unsigned txbb_intr; - unsigned dsp_clk; + unsigned dac_clk; // Use for NCO offset calculation + unsigned adc_clk; // Use for NCO offset calculation + unsigned rx_lo; unsigned tx_lo; + unsigned rx_nco_distance; // Maximum distance from LO to the farest NCO + unsigned tx_nco_distance; + + freq_data_t rx_raw; + freq_data_t tx_raw; + unsigned mixer_lo; unsigned rfic_rx_lo; opt_u32_t tx_bw; opt_u32_t rx_bw; - opt_u32_t tx_dsp; - opt_u32_t rx_dsp; - freq_auto_band_map_t cfg_auto_rx[USDR_MAX_RX_BANDS]; freq_auto_band_map_t cfg_auto_tx[USDR_MAX_TX_BANDS]; }; @@ -133,8 +153,16 @@ int usdr_rfic_fe_set_rxlna(struct usdr_dev *d, int usdr_rfic_fe_set_txlna(struct usdr_dev *d, const char *lna); +enum fe_freq_type { + FE_FREQ_LO_RX = 0, + FE_FREQ_LO_TX = 1, + FE_FREQ_BB_RX = 2, + FE_FREQ_BB_TX = 3, +}; + int usdr_rfic_fe_set_freq(struct usdr_dev *d, - bool dir_tx, + enum fe_freq_type type, + unsigned chmask, double freq, double *actualfreq); @@ -178,7 +206,8 @@ enum { IGPO_LED = 8, IGPO_DCCORR = 9, - IGPO_DSP_RX_CTRL = 10, + // No longer used, replaced with direct PHY control + // IGPO_DSP_RX_CTRL = 10, IGPO_FRONT = 15, IGPO_CLKMEAS = 16, @@ -197,6 +226,8 @@ enum { int usdr_set_extref(usdr_dev_t *d, bool ext, uint32_t freq); +int usdr_tx_dccorr(usdr_dev_t *d, int16_t i, int16_t q); + #endif #endif From 78f87e0350746c35b57949c2046cabe600149ac6 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 9 Apr 2026 03:34:53 +0400 Subject: [PATCH 375/397] usdr_dm_create: add -v and -V parameters to set BB offset frequencies --- src/tools/usdr_dm_create.c | 59 +++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index 5733530b..318dd346 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -260,7 +260,7 @@ static void* chirp_gen_thread_ci16(void* obj) USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "Using TX ci16 CHIRP sinus generator with USE_WVLT_SINCOS opt @ ch#%d F1:%.6f MHz F2:%.6f MHz GAIN:(%.2fdBFS = %d)", p, inp->chirp_freq0 / 1000000.f, inp->chirp_freq1 / 1000000.f, inp->gain, gain); USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "CHIRP steps count: %d [%s]", inp->chirp_steps, (upchirp ? "UP_CHIRP":"DOWN_CHIRP")); - USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "CHIRP period: %.6f s (having sr:%u Ms)", (double)inp->chirp_steps / (double)inp->samplerate, inp->samplerate / 1000000); + USDR_LOG(LOG_TAG, USDR_LOG_WARNING, "CHIRP period: %.6f s (having sr:%.3f Msps)", (double)inp->chirp_steps / (double)inp->samplerate, inp->samplerate / 1e6); int32_t phase = WVLT_CONVPHASE_F32_I32(inp->start_phase); @@ -454,6 +454,8 @@ static void usage(int severity, const char* me) "\t[-T ] \n" "\t[-N ] \n" "\t[-J ]\n" + "\t[-v RX_BB_FREQ] \n" + "\t[-V TX_BB_FREQ] \n" "\t[-q TDD_FREQ [910e6]] \n" "\t[-e RX_FREQ [900e6]] \n" "\t[-E TX_FREQ [920e6]] \n" @@ -702,6 +704,8 @@ int main(UNUSED int argc, UNUSED char** argv) unsigned extra_param_len = 0; int tx_pkt_precharge = 16; bool use_chirp_gen = false; + double freq_bb_rx = 0.0; + double freq_bb_tx = 0.0; memset(rx_thread_inputs, 0, sizeof(rx_thread_inputs)); memset(tx_thread_inputs, 0, sizeof(tx_thread_inputs)); @@ -746,9 +750,13 @@ int main(UNUSED int argc, UNUSED char** argv) //set colored log output usdrlog_enablecolorize(NULL); - // Still available: kvVL - while ((opt = getopt(argc, argv, "b:B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:K:mM:")) != -1) { + // Still available: kL + while ((opt = getopt(argc, argv, "b:B:U:u:R:Qq:e:E:w:W:y:Y:l:S:O:C:F:f:c:r:i:XtTNAoha:D:s:p:P:z:I:x:j:H:d:g:JG:Z:K:mM:v:V:")) != -1) { switch (opt) { + //BB frequency RX + case 'v': freq_bb_rx = atof(optarg); break; + //BB frequency TX + case 'V': freq_bb_tx = atof(optarg); break; //Time-division duplexing (TDD) frequency case 'q': dev_data[DD_TDD_FREQ].value = atof(optarg); dev_data[DD_TDD_FREQ].ignore = false; break; //RX frequency @@ -1049,10 +1057,11 @@ int main(UNUSED int argc, UNUSED char** argv) } } - if (dev_data[DD_TX_BANDWIDTH].ignore) { - dev_data[DD_TX_BANDWIDTH].ignore = false; - dev_data[DD_TX_BANDWIDTH].value = rate; - } + // Device should decide which BW to use + // if (dev_data[DD_TX_BANDWIDTH].ignore) { + // dev_data[DD_TX_BANDWIDTH].ignore = false; + // dev_data[DD_TX_BANDWIDTH].value = rate; + // } } //Prepare parameters to RX @@ -1063,10 +1072,11 @@ int main(UNUSED int argc, UNUSED char** argv) return 3; } - if (dev_data[DD_RX_BANDWIDTH].ignore) { - dev_data[DD_RX_BANDWIDTH].ignore = false; - dev_data[DD_RX_BANDWIDTH].value = rate; - } + // Device should decide which BW to use + // if (dev_data[DD_RX_BANDWIDTH].ignore) { + // dev_data[DD_RX_BANDWIDTH].ignore = false; + // dev_data[DD_RX_BANDWIDTH].value = rate; + // } } //Open device & create dev handle @@ -1377,12 +1387,12 @@ int main(UNUSED int argc, UNUSED char** argv) } } - //Sync TX&RX data streams - res = usdr_dms_sync(dev, synctype, 2, strms); - if (res) { - USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to sync data streams: errno %d", res); - if (stop_on_error) goto dev_close; - } + // //Sync TX&RX data streams + // res = usdr_dms_sync(dev, synctype, 2, strms); + // if (res) { + // USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to sync data streams: errno %d", res); + // if (stop_on_error) goto dev_close; + // } //Set antenna configuration @@ -1405,6 +1415,13 @@ int main(UNUSED int argc, UNUSED char** argv) } } + //Sync TX&RX data streams + res = usdr_dms_sync(dev, synctype, 2, strms); + if (res) { + USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "Unable to sync data streams: errno %d", res); + if (stop_on_error) goto dev_close; + } + if (calibrate) { res = usdr_dme_set_uint(dev, "/dm/sdr/0/calibrate", calibrate); USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "SDR Calibration done: %d\n", res); @@ -1412,6 +1429,14 @@ int main(UNUSED int argc, UNUSED char** argv) res = usdr_dme_findsetv_uint(dev, "/dm/sdr/0/", SIZEOF_ARRAY(dev_data), dev_data); } + // Update BB freqs if set + if (freq_bb_rx != 0.0) { + usdr_dme_set_uint(dev, "/dm/sdr/0/rx/frequency/bb", (int64_t)freq_bb_rx); + } + if (freq_bb_tx != 0.0) { + usdr_dme_set_uint(dev, "/dm/sdr/0/tx/frequency/bb", (int64_t)freq_bb_tx); + } + uint64_t stm = start_tx_delay; //Check stream handles and exit if NULL From 098ee339104238a902baa07951d16f644bfdfea2 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 16 Apr 2026 14:15:59 +0400 Subject: [PATCH 376/397] usdr: port TX chain to the new FE that supports 12bit wire format --- src/lib/device/m2_lm6_1/m2_lm6_1.c | 91 +++++++++--- src/lib/device/m2_lm6_1/usdr_ctrl.c | 131 +++++++++++++++++- src/lib/device/m2_lm6_1/usdr_ctrl.h | 40 +++++- src/lib/hw/lms6002d/lms6002d.c | 31 ++++- src/lib/hw/lms6002d/lms6002d.h | 3 + src/lib/hw/lms6002d/lms6002d.yaml | 3 +- src/lib/ipblks/CMakeLists.txt | 1 + src/lib/ipblks/dc_estim.c | 109 +++++++++++++++ src/lib/ipblks/dc_estim.h | 32 +++++ src/lib/ipblks/streams/sfe_rx_4.c | 2 +- src/lib/ipblks/streams/stream_sfetrx4_dma32.c | 34 +++-- src/lib/ipblks/streams/stream_sfetrx4_dma32.h | 3 + src/lib/lowlevel/usb_uram/usb_uram_libusb.c | 8 +- 13 files changed, 449 insertions(+), 39 deletions(-) create mode 100644 src/lib/ipblks/dc_estim.c create mode 100644 src/lib/ipblks/dc_estim.h diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index ae4ac5be..12dfa591 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -162,6 +162,9 @@ static int dev_m2_lm6_1_sdr_tx_gainauto_set(pdevice_t ud, pusdr_vfs_obj_t obj, u static int dev_m2_lm6_1_sdr_rx_bandwidth_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_tx_bandwidth_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm6_1_sdr_tx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm6_1_sdr_rx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + static int dev_m2_lm6_1_sdr_rx_gainpga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_gainvga_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_rx_gainvga2a_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -272,6 +275,9 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/rx/bandwidth", { dev_m2_lm6_1_sdr_rx_bandwidth_set, NULL }}, { "/dm/sdr/0/tx/bandwidth", { dev_m2_lm6_1_sdr_tx_bandwidth_set, NULL }}, + { "/dm/sdr/0/tx/phgaincorr", { dev_m2_lm6_1_sdr_tx_phgaincorr_set, NULL }}, + { "/dm/sdr/0/rx/phgaincorr", { dev_m2_lm6_1_sdr_rx_phgaincorr_set, NULL }}, + { "/debug/hw/lms6002d/0/reg", { dev_m2_lm6_1_debug_lms6002d_reg_set, dev_m2_lm6_1_debug_lms6002d_reg_get }}, { "/debug/hw/si5332/0/reg", { dev_m2_lm6_1_debug_si5332_reg_set, dev_m2_lm6_1_debug_si5332_reg_get }}, { "/debug/hw/tps6381x/0/reg", { dev_m2_lm6_1_debug_tps6381x_reg_set, dev_m2_lm6_1_debug_tps6381x_reg_get }}, @@ -332,12 +338,12 @@ static const usdr_dev_link_t s_links[] = { { "/dm/sdr/0/rx/dccorr/0", "/dm/sdr/0/rx/dccorr" }, { "/dm/sdr/0/tx/dccorr/0", "/dm/sdr/0/tx/dccorr" }, - // { "/dm/sdr/0/rx/phgaincorr/0","/dm/sdr/0/rx/phgaincorr" }, - // { "/dm/sdr/0/tx/phgaincorr/0","/dm/sdr/0/tx/phgaincorr" }, + { "/dm/sdr/0/rx/phgaincorr/0","/dm/sdr/0/rx/phgaincorr" }, + { "/dm/sdr/0/tx/phgaincorr/0","/dm/sdr/0/tx/phgaincorr" }, { "/dm/sdr/0/rx/dccorr/1", "/dm/sdr/0/rx/dccorr" }, { "/dm/sdr/0/tx/dccorr/1", "/dm/sdr/0/tx/dccorr" }, - // { "/dm/sdr/0/rx/phgaincorr/1","/dm/sdr/0/rx/phgaincorr" }, - // { "/dm/sdr/0/tx/phgaincorr/1","/dm/sdr/0/tx/phgaincorr" }, + { "/dm/sdr/0/rx/phgaincorr/1","/dm/sdr/0/rx/phgaincorr" }, + { "/dm/sdr/0/tx/phgaincorr/1","/dm/sdr/0/tx/phgaincorr" }, }; @@ -502,6 +508,8 @@ int dev_m2_lm6_1_sdr_dccorr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ova USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: DC_AAVG I=%d Q=%d\n", lowlevel_get_devname(d->base.dev), i, q); *ovalue = v; + + usdr_rxdccorr(&d->d, ovalue); return 0; } @@ -660,7 +668,9 @@ int dev_m2_lm6_1_sdr_refclk_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t return res; } - +enum { + DECIM_INTER_MAX = 32, +}; enum { RATE_MIN = 1000000, RATE_MAX = 80000000, @@ -668,15 +678,19 @@ enum { int dev_m2_lm6_1_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - if (value < RATE_MIN || value > RATE_MAX) - return -ERANGE; struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + unsigned rate_min = (d->d.has_rxchain && d->d.has_txchain) ? RATE_MIN / DECIM_INTER_MAX : RATE_MIN; + if (value < rate_min || value > RATE_MAX) + return -ERANGE; + return usdr_set_samplerate_ex(&d->d, value, value, 0, 0, 0); } int dev_m2_lm6_1_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + unsigned rate_min = (d->d.has_rxchain && d->d.has_txchain) ? RATE_MIN / DECIM_INTER_MAX : RATE_MIN; + uint32_t *rates = (uint32_t *)(uintptr_t)value; uint32_t rx_rate = rates[0]; @@ -688,10 +702,10 @@ int dev_m2_lm6_1_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) if (rx_rate == 0 && tx_rate == 0) return -EINVAL; - if ((rx_rate != 0) && (rx_rate < RATE_MIN || rx_rate > RATE_MAX)) + if ((rx_rate != 0) && (rx_rate < rate_min || rx_rate > RATE_MAX)) return -ERANGE; - if ((tx_rate != 0) && (tx_rate < RATE_MIN || tx_rate > RATE_MAX)) + if ((tx_rate != 0) && (tx_rate < rate_min || tx_rate > RATE_MAX)) return -ERANGE; return usdr_set_samplerate_ex(&d->d, rx_rate, tx_rate, adc_rate, dac_rate, 0); @@ -722,10 +736,6 @@ int dev_m2_lm6_1_debug_all_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* oval int dev_m2_lm6_1_pwren_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - // struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - USDR_LOG("UDEV", USDR_LOG_INFO, "M2_LM6_1: power en:%d\n", (int)value); - // return usdr_pwren(&d->d, value); - return 0; } @@ -851,7 +861,7 @@ int dev_m2_lm6_1_sdr_rx_gainauto_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t int dev_m2_lm6_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; - + bool rflb = false; // 00 – All output buffers powered down; // 01 – First buffer enabled for LNA1 path (default); WB: 250 - 2700 // 10 – Second buffer enabledfor LNA2 path; HB: 2700 - 3800 @@ -864,10 +874,18 @@ int dev_m2_lm6_1_sdr_rx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t val value = (uintptr_t)"W"; } else if (strcasecmp("rxh", param) == 0) { value = (uintptr_t)"H"; - }; + } else if (strcasecmp("rxl_lb", param) == 0) { + value = (uintptr_t)"EXT"; rflb = true; + } else if (strcasecmp("rxw_lb", param) == 0) { + value = (uintptr_t)"W"; rflb = true; + } else if (strcasecmp("rxh_lb", param) == 0) { + value = (uintptr_t)"H"; rflb = true; + } + } else { + return -EINVAL; } - return usdr_rfic_fe_set_rxlna(&d->d, (const char *)(uintptr_t)value); + return usdr_rfic_fe_set_rxlna(&d->d, (const char *)(uintptr_t)value, rflb); } int dev_m2_lm6_1_sdr_tx_path_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) @@ -960,6 +978,31 @@ int dev_m2_lm6_1_sdr_rx_dc_meas_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* return 0; } +int dev_m2_lm6_1_sdr_tx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + + unsigned ig = (value & 0xffff); + unsigned qg = ((value >> 16) & 0xffff); + int16_t pcorr = (int16_t)((value >> 48) & 0xffff); + int amp_imb; + if (ig < 2047) { + amp_imb = (2047 - ig) * 8; + } else { + amp_imb = - (2047 - qg) * 8; + } + pcorr *= 16; + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "TXGAC I=%d Q=%d A=%d => AMP_IMB=%d\n", ig, qg, pcorr, amp_imb); + + return usdr_tx_iqimb_set(&d->d, amp_imb, pcorr); +} + +int dev_m2_lm6_1_sdr_rx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return -EINVAL; +} + + int dev_m2_lm6_1_sdr_revision_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { unsigned rev_lo, rev_hi; @@ -1146,6 +1189,8 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha d->d.rx_lchans = chans; *out_handle = d->rx; } else if (strstr(sid, "tx") != NULL) { + bool extended_core = (d->d.hwid & (1 << (24 + 2))) ? true : false; + if (d->tx) { return -EBUSY; } @@ -1154,9 +1199,16 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha return res; } - res = create_sfetrx4_stream(dev, CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, - flags, M2PCI_REG_WR_TXDMA_CNF_L, M2PCI_REG_WR_SYNC_CTRL, M2PCI_REG_RD_TXDMA_STAT, - 0, 0, &d->tx, &chans); + if (extended_core) { + res = res ? res : usdr_reset_txfex(&d->d); + } + + res = create_sfetrx4_stream(dev, extended_core ? CORE_EXFETX_DMA32_R0_2 : CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, + flags, + extended_core ? M2PCI_REG_WR_TXDMA_CFG0 : M2PCI_REG_WR_TXDMA_CNF_L, + M2PCI_REG_WR_SYNC_CTRL, + M2PCI_REG_RD_TXDMA_STAT, + 0, CSR_TFE4_BASE, &d->tx, &chans); if (res) { return res; } @@ -1164,6 +1216,7 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha *out_handle = d->tx; // TODO: handle NCO changes + res = res ? res : usdr_txupdate_cal(&d->d); } return res; diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index fb5a521a..d5fe3ff3 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -22,6 +22,7 @@ #include "../generic_usdr/generic_regs.h" #include "../ipblks/fgearbox.h" +#include "../ipblks/dc_estim.h" // Clock configuration // rev4/rev3 rev2 rev1 @@ -297,6 +298,10 @@ static int _usdr_set_nco(usdr_dev_t *d, bool rx, unsigned nco_num, double freq) res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, reg, ((off + 0) << 24) | (nco_freq & 0xffff)); res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, reg, ((off + 1) << 24) | ((nco_freq >> 16) & 0xffff)); + // Reset NCOs + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, reg, (0 << 24) | (1 << 8)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, reg, (0 << 24) | (0 << 8)); + USDR_LOG("UDEV", USDR_LOG_WARNING, "NCO_%s_%d: Set to %.3f KHz -- %0.3f %08x -- rate: %.3f MSPS\n", rx ? "RX" : "TX", nco_num, rel_f * raw_rate / 1.0e3, rel_f, nco_freq, raw_rate / 1e6); return res; @@ -405,6 +410,84 @@ int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob) #define TARGET_RATE 30720000 +#define MAKE_PHY_WR_REG(a, w) ((((a) & 0x7f) << 24) | ((w) & 0xffffff)) +#define MAKE_PHY_RD_REG(a, i) ((((a) & 0x7f) << 24) | ((i) & 0xffffff) | 0x80000000) + +int usdr_reset_txfex(struct usdr_dev *d) +{ + int res = 0; + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, 8); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, 0); + return res; +} + +int usdr_reset_txnco(struct usdr_dev *d) +{ + int res = 0; + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, 256); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, 0); + return res; +} + +int usdr_txupdate_cal(struct usdr_dev *d) +{ + // CFG_AMP_I + // CFG_AMP_Q + // CFG_TAN_I + // CFG_TAN_Q + + // I = CFG_AMP_I * i + CFG_TAN_Q * q + // Q = CFG_AMP_Q * q + CFG_TAN_I * i + + // c = math.cos(phi / 2.0) + // s = math.sin(phi / 2.0) + // I = (c / alpha) * Id + (s / beta) * Qd + // Q = (c / beta) * Qd -(s / alpha) * Id + + float c = cos(M_PI_4 * d->tx_corr.pahse / IMB_PHASE_MAX); + float s = sin(M_PI_4 * d->tx_corr.pahse / IMB_PHASE_MAX); + + float alpha = (d->tx_corr.ampl > 0) ? 1.0 - (((double)d->tx_corr.ampl) / IMB_AMPL_MAX) : 1.0; + float beta = (d->tx_corr.ampl < 0) ? 1.0 + (((double)d->tx_corr.ampl) / IMB_AMPL_MAX) : 1.0; + + // 18 bits -> 16 bits + // probably we need extra headroom for DC and IQimb correction, but leave as an extra option + // + // AMP_COMP_2CH_3DB: 17bit * SQRT(2) | MAX * 0.35355 + // AMP_COMP_2CH_0DB: 17bit | MAX * 0.5 + // AMP_COMP_1CH_3DB: 16bit * SQRT(2) | MAX * 0.7071 + // AMP_COMP_1CH_0DB: 16bit | MAX + float scale = + (d->tx_corr.amp_corr == AMP_COMP_1CH_0DB) ? 1.0 : + (d->tx_corr.amp_corr == AMP_COMP_1CH_3DB) ? 0.7071 : + (d->tx_corr.amp_corr == AMP_COMP_2CH_0DB) ? 0.5 : 0.35355; + + float fcfg_amp_i = scale * c * alpha; + float fcfg_amp_q = scale * c * beta; + float fcfg_tan_q = scale * s * beta; + float fcfg_tan_i = - scale * s * alpha; + + int32_t dsp_amp_max = 8388607; + int32_t cfg_amp_i = dsp_amp_max * fcfg_amp_i; + int32_t cfg_amp_q = dsp_amp_max * fcfg_amp_q; + int32_t cfg_tan_i = dsp_amp_max * fcfg_tan_i; + int32_t cfg_tan_q = dsp_amp_max * fcfg_tan_q; + + USDR_LOG("UDEV", USDR_LOG_WARNING, "TX CORRECTION: CFG_AMP_I=%d CFG_AMP_Q=%d CFG_TAN_I=%d CFG_TAN_Q=%d\n", + cfg_amp_i, cfg_amp_q, cfg_tan_i, cfg_tan_q); + + int res = 0; + //res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, (CFG_REG_IQIMB_0 << 24) | (cfg_amp_i & 0xffffff)); + //res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, (CFG_REG_IQIMB_1 << 24) | (cfg_amp_q & 0xffffff)); + //res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, (CFG_REG_IQIMB_2 << 24) | (cfg_tan_i & 0xffffff)); + //res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, (CFG_REG_IQIMB_3 << 24) | (cfg_tan_q & 0xffffff)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_0, cfg_amp_i)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_1, cfg_amp_q)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_2, cfg_tan_i)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_3, cfg_tan_q)); + return res; +} + int usdr_set_samplerate_ex(struct usdr_dev *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, @@ -1102,19 +1185,42 @@ int usdr_rfic_set_gain(struct usdr_dev *d, } +int usdr_rfic_switch_loopback(struct usdr_dev *d, bool lb) +{ + int res = 0; + if (!lb) { + if (d->rf_loopback_active) { + USDR_LOG("UDEV", USDR_LOG_WARNING, "Disable RF LOOPBACK\n"); + res = res ? res : lms6002d_rf_loopback_dis(&d->lms); + d->rf_loopback_active = false; + } + } else { + if (!d->rf_loopback_active) { + USDR_LOG("UDEV", USDR_LOG_WARNING, "Enabling RF LOOPBACK\n"); + res = res ? res : lms6002d_rf_loopback_en(&d->lms); + d->rf_loopback_active = true; + } + } + return res; +} + int usdr_rfic_fe_set_rxlna(struct usdr_dev *d, - const char *lna) + const char *lna, bool lb) { int res = get_antenna_cfg_by_name(lna, d->cfg_auto_rx, SIZEOF_ARRAY(d->cfg_auto_rx)); USDR_LOG("UDEV", USDR_LOG_INFO, "RX_PATH set to %s from `%s`\n", (res < 0) ? "AUTO" : d->cfg_auto_rx[res].name0, lna); if (res == -1) { d->rx_rfic_path = USDR_RX_AUTO; - return _usdr_signal_event(d, USDR_RX_LNA_CHANGED); + res = _usdr_signal_event(d, USDR_RX_LNA_CHANGED); + res = res ? res : usdr_rfic_switch_loopback(d, lb); + return res; } d->rx_rfic_path = res; - return _usdr_set_lna_rx(d, d->rx_rfic_path); + res = _usdr_set_lna_rx(d, d->rx_rfic_path); + res = res ? res : usdr_rfic_switch_loopback(d, lb); + return res; } int usdr_rfic_fe_set_txlna(struct usdr_dev *d, @@ -1168,3 +1274,22 @@ int usdr_gettemp(struct usdr_dev *d, int* temp256) { return tmp114_temp_get(d->base.dev, 0, I2C_BUS_TEMP, temp256); } + + +// Calibration +int usdr_tx_iqimb_set(usdr_dev_t* d, int iq_amp_imb, int phase_imb) +{ + d->tx_corr.ampl = (int64_t)iq_amp_imb * IMB_AMPL_MAX / INT16_MAX; + d->tx_corr.pahse = phase_imb; + + return usdr_txupdate_cal(d); +} + +int usdr_rxdccorr(struct usdr_dev *d, uint64_t *ov) +{ + int out; + int res = phy_do_meas_nco_avg(d->lms.dev, REG_CFG_PHY_0, 32767, 0, 1, &out); + + *ov = out; + return res; +} diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.h b/src/lib/device/m2_lm6_1/usdr_ctrl.h index b66666c4..61effaf5 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.h +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.h @@ -57,6 +57,28 @@ struct freq_data }; typedef struct freq_data freq_data_t; + +enum { + AMP_COMP_2CH_3DB = 0, + AMP_COMP_2CH_0DB = 1, + AMP_COMP_1CH_3DB = 2, + AMP_COMP_1CH_0DB = 3, +}; + + +#define IMB_AMPL_MAX 262144 +#define IMB_AMPL_MIN -262144 + +#define IMB_PHASE_MAX 45000 +#define IMB_PHASE_MIN -45000 + +struct imb_data +{ + int32_t ampl; // AMPL_IMB_MIN .. AMPL_IMB_MAX + int32_t pahse; // IMB_PHASE_MIN .. IMB_PHASE_MAX + int32_t amp_corr; // Amplitude correction +}; + struct usdr_dev { union { @@ -103,6 +125,8 @@ struct usdr_dev bool has_rxchain; bool has_txchain; + bool rf_loopback_active; + unsigned rawsamplerate; unsigned rxbb_decim; unsigned txbb_intr; @@ -125,6 +149,8 @@ struct usdr_dev opt_u32_t tx_bw; opt_u32_t rx_bw; + struct imb_data tx_corr; + freq_auto_band_map_t cfg_auto_rx[USDR_MAX_RX_BANDS]; freq_auto_band_map_t cfg_auto_tx[USDR_MAX_TX_BANDS]; }; @@ -149,7 +175,7 @@ int usdr_set_tx_port_switch(struct usdr_dev *d, unsigned path); int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob); int usdr_rfic_fe_set_rxlna(struct usdr_dev *d, - const char* lna); + const char* lna, bool lb); int usdr_rfic_fe_set_txlna(struct usdr_dev *d, const char *lna); @@ -185,6 +211,10 @@ int usdr_calib_dc(struct usdr_dev *d, bool rx); int usdr_gettemp(struct usdr_dev *d, int* temp256); +int usdr_reset_txfex(struct usdr_dev *d); + +int usdr_rxdccorr(struct usdr_dev *d, uint64_t *ov); + #ifndef NO_IGPO enum { @@ -228,6 +258,14 @@ int usdr_set_extref(usdr_dev_t *d, bool ext, uint32_t freq); int usdr_tx_dccorr(usdr_dev_t *d, int16_t i, int16_t q); +// Realign NCO-A / NCO-B to be phase cocherent +int usdr_reset_txnco(struct usdr_dev *d); + +int usdr_txupdate_cal(struct usdr_dev *d); + +int usdr_tx_iqimb_set(usdr_dev_t* d, int iq_amp_imb, int phase_imb); + + #endif #endif diff --git a/src/lib/hw/lms6002d/lms6002d.c b/src/lib/hw/lms6002d/lms6002d.c index 3ae61455..3da7f5aa 100644 --- a/src/lib/hw/lms6002d/lms6002d.c +++ b/src/lib/hw/lms6002d/lms6002d.c @@ -74,6 +74,7 @@ int lms6002d_create(lldev_t dev, unsigned subdev, unsigned lsaddr, struct lms600 out->top_enreg = (uint8_t)MAKE_LMS6002D_TOP_ENREG(0, 0, 0, 0, 0, 0, 0, 0); out->rxpll_vco_div_bufsel = (uint8_t)MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(0, 0, 1); out->rfe_gain_lna_sel = 0xc0; + out->trf_pa_ctrl = (uint8_t)MAKE_LMS6002D_TRF_PA_CTRL(0, 0); memset(out->rclpfcal, 3, sizeof(out->rclpfcal)); @@ -555,8 +556,11 @@ int lms6002d_set_rx_path(lms6002d_state_t* obj, unsigned path) int lms6002d_set_tx_path(lms6002d_state_t* obj, unsigned path) { + SET_LMS6002D_TRF_PA_CTRL_EN12(obj->trf_pa_ctrl, path); + SET_LMS6002D_TRF_PA_CTRL_ENAUX(obj->trf_pa_ctrl, path == 3 ? 1 : 0); + uint16_t regs[] = { - MAKE_LMS6002D_TRF_PA_CTRL(path, path == 3 ? 1 : 0), + MAKE_LMS6002D_REG_WR(TRF_PA_CTRL, obj->trf_pa_ctrl), }; return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); } @@ -870,3 +874,28 @@ int lms6002d_set_rxfe_ip2corr(lms6002d_state_t* obj, int8_t i, int8_t q) return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); } +int lms6002d_rf_loopback_en(lms6002d_state_t* obj) +{ + int lna = GET_LMS6002D_RFE_GAIN_LNA_SEL_LNASEL(obj->rfe_gain_lna_sel); + uint16_t regs[] = { + MAKE_LMS6002D_RFE_PD(0, 0, 0, 1), + MAKE_LMS6002D_RFE_CTRL(1, 1), + MAKE_LMS6002D_TRF_PA_CTRL(0, 0), + MAKE_LMS6002D_TOP_POWER(0, 1, 0, 1, 1), + MAKE_LMS6002D_TOP_LOOPBACK(0, 0, 0, lna), + }; + + return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); +} + +int lms6002d_rf_loopback_dis(lms6002d_state_t* obj) +{ + uint16_t regs[] = { + MAKE_LMS6002D_TOP_POWER(0, 1, 0, 1, 0), + MAKE_LMS6002D_TOP_LOOPBACK(0, 0, 0, 0), + MAKE_LMS6002D_REG_WR(TRF_PA_CTRL, obj->trf_pa_ctrl), + MAKE_LMS6002D_TOP_POWER(0, 1, 0, 1, 0), + MAKE_LMS6002D_RFE_PD(0, 0, 0, 0), + }; + return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); +} diff --git a/src/lib/hw/lms6002d/lms6002d.h b/src/lib/hw/lms6002d/lms6002d.h index 355797ad..932689d2 100644 --- a/src/lib/hw/lms6002d/lms6002d.h +++ b/src/lib/hw/lms6002d/lms6002d.h @@ -30,6 +30,7 @@ struct lms6002d_state { uint8_t rxpll_vco_div_bufsel; uint8_t rfe_in1sel_dci; uint8_t rfe_gain_lna_sel; + uint8_t trf_pa_ctrl; }; typedef struct lms6002d_state lms6002d_state_t; @@ -101,5 +102,7 @@ int lms6002d_cal_lpf_bandwidth(lms6002d_state_t* obj, unsigned bcode, bool do_tu int lms6002d_set_tia_cfb(lms6002d_state_t* obj, uint8_t value); int lms6002d_set_tia_rfb(lms6002d_state_t* obj, uint8_t value); +int lms6002d_rf_loopback_en(lms6002d_state_t* obj); +int lms6002d_rf_loopback_dis(lms6002d_state_t* obj); #endif diff --git a/src/lib/hw/lms6002d/lms6002d.yaml b/src/lib/hw/lms6002d/lms6002d.yaml index 867b04c8..589d0159 100644 --- a/src/lib/hw/lms6002d/lms6002d.yaml +++ b/src/lib/hw/lms6002d/lms6002d.yaml @@ -1342,7 +1342,7 @@ pages: fields: - name: TIA bits: '3' - desc: A (RXVGA1) power down; 0 - block active (default); 1 - block inactive + desc: TIA (RXVGA1) power down; 0 - block active (default); 1 - block inactive - name: MXLOB bits: '2' desc: Mixer LO buffer power down; 0 - block active (default); 1 - block inactive @@ -1353,3 +1353,4 @@ pages: bits: '0' desc: LNA power down; 0 - block active (default); 1 - block inactive + diff --git a/src/lib/ipblks/CMakeLists.txt b/src/lib/ipblks/CMakeLists.txt index 72c44a45..5a556632 100644 --- a/src/lib/ipblks/CMakeLists.txt +++ b/src/lib/ipblks/CMakeLists.txt @@ -30,6 +30,7 @@ set(USDR_IPBLKS_LIB_FILES ${CMAKE_CURRENT_SOURCE_DIR}/lms64c_proto.c ${CMAKE_CURRENT_SOURCE_DIR}/fgearbox.c + ${CMAKE_CURRENT_SOURCE_DIR}/dc_estim.c ) diff --git a/src/lib/ipblks/dc_estim.c b/src/lib/ipblks/dc_estim.c new file mode 100644 index 00000000..632aa39a --- /dev/null +++ b/src/lib/ipblks/dc_estim.c @@ -0,0 +1,109 @@ +// Copyright (c) 2026 Wavelet Lab +// SPDX-License-Identifier: MIT + +#include "dc_estim.h" +#include + +enum { + ADDR_DC_EST_RESET = 0, + ADDR_DC_EST_ACCM = 1, +}; + +static int _phy_rx_reg(lldev_t d, uint32_t llreg, bool wr, uint8_t bank, uint8_t addr, uint16_t val) +{ + uint32_t reg = (!wr ? 0x80000000 : 0) | (((uint32_t)bank & 0x7f) << 24) | ((uint32_t)addr << 16) | val; + return lowlevel_reg_wr32(d, 0, llreg, reg); +} + + +int phy_dc_estim_start(lldev_t d, uint32_t llreg, bool start) +{ + return _phy_rx_reg(d, llreg, true, PHY_REG_RXBANK_DC_EST, ADDR_DC_EST_RESET, start ? 0 : 1); +} + +int phy_dc_estim_accum(lldev_t d, uint32_t llreg, unsigned accum) +{ + return _phy_rx_reg(d, llreg, true, PHY_REG_RXBANK_DC_EST, ADDR_DC_EST_ACCM, accum); +} + +int phy_dc_estim_get(lldev_t d, uint32_t llreg, enum dc_estimations v, int32_t* odata) +{ + int res = 0; + res = res ? res : _phy_rx_reg(d, llreg, false, PHY_REG_RXBANK_DC_EST, v, 0); + res = res ? res : lowlevel_reg_rd32(d, 0, llreg, (uint32_t*)odata); + return res; +} + + +// Calculate power in dbfs +int phy_rfe_pwrdc_get(lldev_t d, uint32_t llreg, unsigned acc_norm, int prev_gen, unsigned chan_no, + unsigned range, int *meas1000db) +{ + int32_t val[2]; + int gen, gen_n; + int res = 0; + + do { + res = res ? res : phy_dc_estim_get(d, llreg, DC_ESTIM_GEN, &gen); + if (res) + return res; + + // USDR_LL_LOG(d, "XDEV", USDR_LOG_INFO, "[]%d->%d %d %d\n", prev_gen, gen, val[0], val[1]); + if (prev_gen == gen) + return -EAGAIN; + + res = res ? res : phy_dc_estim_get(d, llreg, chan_no ? DC_ESTIM_BI : DC_ESTIM_AI, &val[0]); + res = res ? res : phy_dc_estim_get(d, llreg, chan_no ? DC_ESTIM_BQ : DC_ESTIM_AQ, &val[1]); + res = res ? res : phy_dc_estim_get(d, llreg, DC_ESTIM_GEN, &gen_n); + if (res) + return res; + + + } while (gen != gen_n); + + double fs_i = val[0]; + double fs_q = val[1]; + double i = (0 + (fs_i / acc_norm / 65536)) / range; // Static correction by +0.5 bits in FPGA + double q = (0 + (fs_q / acc_norm / 65536)) / range; // Static correction by +0.5 bits in FPGA + double pwr_d = i * i + q * q; + + USDR_LL_LOG(d, "XDEV", USDR_LOG_INFO, "%d->%d %d %d => %.3f %.3f\n", + prev_gen, gen, val[0], val[1], i * range, q * range); + + if (pwr_d <= 1e-18) + pwr_d = 1e-18; + + *meas1000db = (1000 * 10 * log10(pwr_d)); + return 0; +} + + +int phy_do_meas_nco_avg(lldev_t d, uint32_t llreg, unsigned range, int channel, unsigned acc_idx, int* oaccum) +{ + int res = 0; + int meas1000db = 0; + int accum = 0, gen = 0; + + res = res ? res : phy_dc_estim_accum(d, llreg, acc_idx); + res = res ? res : phy_dc_estim_start(d, llreg, false); + res = res ? res : usleep(1); + res = res ? res : phy_dc_estim_start(d, llreg, true); + res = res ? res : phy_dc_estim_get(d, llreg, DC_ESTIM_GEN, &gen); + if (res) + return res; + + for (unsigned k = 0; k < 8000; k++) { + res = phy_rfe_pwrdc_get(d, llreg, acc_idx, gen, channel, range, &meas1000db); + if (res != -EAGAIN) { + accum += meas1000db; + break; + } + + usleep(1000); + } + + USDR_LL_LOG(d, "XDEV", USDR_LOG_INFO, "MEAS[%d] = %.3f\n", channel, meas1000db/1e3); + *oaccum = accum; + return res; +} + diff --git a/src/lib/ipblks/dc_estim.h b/src/lib/ipblks/dc_estim.h new file mode 100644 index 00000000..5b957a45 --- /dev/null +++ b/src/lib/ipblks/dc_estim.h @@ -0,0 +1,32 @@ +// Copyright (c) 2026 Wavelet Lab +// SPDX-License-Identifier: MIT + +#ifndef DC_ESTIM_H +#define DC_ESTIM_H + +#include +#include +#include + + +enum dc_estimations { + DC_ESTIM_GEN = 0, + DC_ESTIM_AI = 4, + DC_ESTIM_AQ = 5, + DC_ESTIM_BI = 6, + DC_ESTIM_BQ = 7, +}; + +enum { + PHY_REG_RXBANK_DC_EST = 6, // DC estimator +}; + +int phy_dc_estim_start(lldev_t d, uint32_t llreg, bool start); +int phy_dc_estim_accum(lldev_t d, uint32_t llreg, unsigned accum); +int phy_dc_estim_get(lldev_t d, uint32_t llreg, enum dc_estimations v, int32_t* odata); +int phy_rfe_pwrdc_get(lldev_t d, uint32_t llreg, unsigned acc_norm, int prev_gen, unsigned chan_no, + unsigned range, int *meas1000db); +int phy_do_meas_nco_avg(lldev_t d, uint32_t llreg, unsigned range, int channel, unsigned acc_idx, int* oaccum); + + +#endif diff --git a/src/lib/ipblks/streams/sfe_rx_4.c b/src/lib/ipblks/streams/sfe_rx_4.c index 6513703c..71664649 100644 --- a/src/lib/ipblks/streams/sfe_rx_4.c +++ b/src/lib/ipblks/streams/sfe_rx_4.c @@ -634,7 +634,7 @@ int exfe_trx4_update_chmap(const sfe_cfg_t* fe, const channel_info_t* newmap = (pack_3x16) ? &pack_3x16_mmap : newmap_orig; // For TX we need invert in and out - if (fe->cfg_fecore_id == CORE_EXFETX_DMA32_R0 || fe->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { + if (fe->cfg_fecore_id == CORE_EXFETX_DMA32_R0 || fe->cfg_fecore_id == CORE_EXFETX_DMA32_R0_2 || fe->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { memset(reverse_map.ch_map, ~CH_SWAP_IQ_FLAG, sizeof(reverse_map.ch_map)); for (unsigned g = 0; g < fe->cfg_raw_chans; g++) { diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c index 7dd90b58..bbf373e4 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.c +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.c @@ -362,7 +362,7 @@ int _sfetrx4_stream_send(stream_handle_t* str, if (stream->type != USDR_ZCPY_TX) return -ENOTSUP; - if (stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0 || stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { + if (stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0 || stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0_2 || stream->storage.srx4.cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { res = _extx_burstup(samples, brst_samples, &lgbursts); if (res) return res; @@ -576,10 +576,14 @@ int _sfetrx4_option_set(stream_handle_t* str, const char* name, int64_t in_val) const channel_info_t *new_map = (const channel_info_t *)in_val; if (stream->type == USDR_ZCPY_RX) { - if (stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0_8) + if (stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0 && + stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0_2 && + stream->storage.srx4.cfg_fecore_id != CORE_EXFERX_DMA32_R0_8) return -ENOTSUP; } else if (stream->type == USDR_ZCPY_TX) { - if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_8) { + if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0 && + stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_2 && + stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_8) { unsigned swap_ab_flag; int res = fe_tx4_swap_ab_get(stream->fe_chans, new_map, &swap_ab_flag); if (res) @@ -605,7 +609,7 @@ int _sfetrx4_option_set(stream_handle_t* str, const char* name, int64_t in_val) (stream->fe_complex ? 2 : 1) * (stream->pack_3x16 ? (stream->fe_chans * 4 / 3) : stream->fe_chans), (const channel_info_t *)in_val); } else if (stream->type == USDR_ZCPY_TX && (strcmp(name, "mute") == 0)) { - if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_8) { + if (stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0 && stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_2 && stream->storage.srx4.cfg_fecore_id != CORE_EXFETX_DMA32_R0_8) { stream->fe_old_tx_mute = in_val & 3; return sfe_tx4_upd(&stream->storage.srx4, stream->sync_base, @@ -796,7 +800,7 @@ static int initialize_stream_rx_32(device_t* device, // TODO obtain exfe configuration constants bool pack_3x16 = false; - res = (fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0 || fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0_8) ? + res = (fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0 || fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0_2 || fecfg->cfg_fecore_id == CORE_EXFERX_DMA32_R0_8) ? exfe_rx4_configure(fecfg, &sc, &fc, &pack_3x16) : sfe_rx4_configure(fecfg, &sc, &fc, &hw_chan_msk); if (res) @@ -1028,6 +1032,10 @@ static int initialize_stream_tx_32(device_t* device, if (sc.chcnt > (fecfg->cfg_raw_chans / (bfmt.complex ? 2 : 1))) return -EINVAL; + // Frontend register is a must + if (fecfg->cfg_base == 0) + return -EINVAL; + unsigned llcanhs = (bfmt.complex ? 2 : 1) * sc.chcnt; unsigned expand; unsigned lbits = bfmt.bits; @@ -1086,7 +1094,7 @@ static int initialize_stream_tx_32(device_t* device, sparams.out_max_bursts = 1; if (sparams.block_size > max_mtu) { - if (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0 || fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { + if (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0 || fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_2 || fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) { unsigned max_burst_sps = 8 * max_mtu / sparams.bits_per_sym; unsigned lgbrst; res = _extx_burstup(pktsyms, max_burst_sps, &lgbrst); @@ -1160,7 +1168,9 @@ static int initialize_stream_tx_32(device_t* device, strdev->burst_mask = 0; strdev->burst_count = sparams.out_max_bursts; - strdev->burst_align_bytes = (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) ? 32 : (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0) ? 16 : 1; + strdev->burst_align_bytes = (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_8) ? 32 : + (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0) ? 16 : + (fecfg->cfg_fecore_id == CORE_EXFETX_DMA32_R0_2) ? 8 : 1; strdev->fe_old_tx_mute = fe_old_tx_mute; strdev->fe_old_tx_swap = fe_old_tx_swap; @@ -1218,11 +1228,12 @@ int create_sfetrx4_stream(device_t* device, switch (core_id) { case CORE_SFERX_DMA32_R0: + case CORE_EXFERX_DMA32_R0_2: case CORE_EXFERX_DMA32_R0: case CORE_EXFERX_DMA32_R0_8: // TODO obtain dynamic config - fecfg.cfg_word_bytes = (core_id == CORE_SFERX_DMA32_R0) ? 8 : (core_id == CORE_EXFERX_DMA32_R0) ? 16 : 32; - fecfg.cfg_raw_chans = (core_id == CORE_SFERX_DMA32_R0) ? 4 : (core_id == CORE_EXFERX_DMA32_R0) ? 8 : 16; + fecfg.cfg_word_bytes = (core_id == CORE_SFERX_DMA32_R0 || core_id == CORE_EXFERX_DMA32_R0_2) ? 8 : (core_id == CORE_EXFERX_DMA32_R0) ? 16 : 32; + fecfg.cfg_raw_chans = (core_id == CORE_SFERX_DMA32_R0 || core_id == CORE_EXFERX_DMA32_R0_2) ? 4 : (core_id == CORE_EXFERX_DMA32_R0) ? 8 : 16; fecfg.cfg_dma_align_bytes = fecfg.cfg_word_bytes; res = initialize_stream_rx_32(device, chcount, channels, pktsyms, @@ -1231,11 +1242,12 @@ int create_sfetrx4_stream(device_t* device, need_fd, bifurcation); break; case CORE_SFETX_DMA32_R0: + case CORE_EXFETX_DMA32_R0_2: case CORE_EXFETX_DMA32_R0: case CORE_EXFETX_DMA32_R0_8: // TODO obtain dynamic config - fecfg.cfg_word_bytes = (core_id == CORE_SFETX_DMA32_R0) ? 8 : (core_id == CORE_EXFETX_DMA32_R0) ? 16 : 32; - fecfg.cfg_raw_chans = (core_id == CORE_SFETX_DMA32_R0) ? 4 : (core_id == CORE_EXFETX_DMA32_R0) ? 8 : 16; + fecfg.cfg_word_bytes = (core_id == CORE_SFETX_DMA32_R0 || core_id == CORE_EXFETX_DMA32_R0_2) ? 8 : (core_id == CORE_EXFETX_DMA32_R0) ? 16 : 32; + fecfg.cfg_raw_chans = (core_id == CORE_SFETX_DMA32_R0 || core_id == CORE_EXFETX_DMA32_R0_2) ? 4 : (core_id == CORE_EXFETX_DMA32_R0) ? 8 : 16; fecfg.cfg_dma_align_bytes = fecfg.cfg_word_bytes; res = initialize_stream_tx_32(device, chcount, channels, pktsyms, diff --git a/src/lib/ipblks/streams/stream_sfetrx4_dma32.h b/src/lib/ipblks/streams/stream_sfetrx4_dma32.h index d6f896b8..e7e88c0e 100644 --- a/src/lib/ipblks/streams/stream_sfetrx4_dma32.h +++ b/src/lib/ipblks/streams/stream_sfetrx4_dma32.h @@ -17,6 +17,9 @@ enum { CORE_EXFERX_DMA32_R0_8 = 258, CORE_EXFETX_DMA32_R0_8 = 259, + + CORE_EXFERX_DMA32_R0_2 = 260, + CORE_EXFETX_DMA32_R0_2 = 261, }; enum { diff --git a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c index e679d0e9..a9639857 100644 --- a/src/lib/lowlevel/usb_uram/usb_uram_libusb.c +++ b/src/lib/lowlevel/usb_uram/usb_uram_libusb.c @@ -764,14 +764,18 @@ int usb_uram_send_dma_commit(lldev_t dev, subdev_t subdev, stream_t channel, voi USDR_LOG("USBX", USDR_LOG_ERROR,"USB TX incorrect pointer supplied\n"); return -EINVAL; } + if (sz > 0x1ffff) { + USDR_LOG("USBX", USDR_LOG_ERROR,"USB TX FPGA maximum buffer size oveflow!\n"); + return -EINVAL; + } uint64_t rsamples = sz * 8 / d->tx_strms_params[0].bits_per_all_chs; - unsigned samples = rsamples - 1; + unsigned samples = rsamples - 1; // Ignored in new TXFE uint32_t* header = (uint32_t*)bx; header[0] = timestamp; header[1] = ((timestamp >> 32) & 0xffff) | ((samples & 0x7fff) << 16) | (timestamp < 0 ? 0x80000000 : 0); - header[2] = 0; // (samples >> 15) & 0x3; + header[2] = (((sz - 1) & 0x1ffff) << 15) | ((timestamp >> 48) & 0x7fff); // Ignored in old TXFE header[3] = 0; USDR_LOG("USBX", USDR_LOG_DEBUG, "TX post buffer %d: %08x.%08x.%08x.%08x -> %d bytes\n", From 3611d91b2c4a0910b5f04401ca5fb28f02443b2c Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 20 Apr 2026 04:04:08 +0400 Subject: [PATCH 377/397] usdr: tx calibration --- src/lib/cal/cal_lo_iqimb.c | 97 ++++---- src/lib/cal/cal_lo_iqimb.h | 6 +- src/lib/device/m2_lm6_1/m2_lm6_1.c | 117 +++++++++- src/lib/device/m2_lm6_1/usdr_ctrl.c | 348 ++++++++++++++++++++++++++-- src/lib/device/m2_lm6_1/usdr_ctrl.h | 21 +- src/lib/device/m2_lm7_1/m2_lm7_1.c | 3 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 6 +- src/lib/hw/lms6002d/lms6002d.c | 25 +- src/lib/hw/lms6002d/lms6002d.h | 3 + src/lib/ipblks/dc_estim.c | 1 + 10 files changed, 550 insertions(+), 77 deletions(-) diff --git a/src/lib/cal/cal_lo_iqimb.c b/src/lib/cal/cal_lo_iqimb.c index 7a6ffbc1..00fb8613 100644 --- a/src/lib/cal/cal_lo_iqimb.c +++ b/src/lib/cal/cal_lo_iqimb.c @@ -80,8 +80,13 @@ int calibrate_rxlo(struct calibrate_ops* ops) int calibrate_txlo(struct calibrate_ops* ops) { - int res; + int res = 0; struct opt_iteration2d o[4]; + unsigned coarse = ops->coarse_mode; + if (coarse >= SIZEOF_ARRAY(o)) { + coarse = SIZEOF_ARRAY(o) - 1; + } + o[0].limit[0] = ops->txlo_iq_corr; o[0].limit[1] = ops->txlo_iq_corr; o[0].func = _evaluate_txlo; @@ -109,8 +114,10 @@ int calibrate_txlo(struct calibrate_ops* ops) o[3].sf = &find_iterate_min; o[3].exparam = 0; - // Set TX freq - res = ops->set_tx_testsig(ops->param, ops->channel, 0, 0); + // Set TX modulation to zero to not overload RX bypass + + res = ops->set_tx_testsig(ops->param, ops->channel, 347.123e5, 32); + //res = ops->set_tx_testsig(ops->param, ops->channel, 0, 0); if (res) return res; @@ -120,20 +127,16 @@ int calibrate_txlo(struct calibrate_ops* ops) USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_TXLO: Set RX measeure freq %d - %d (from %.3f)\n", ops->txfrequency, freqoff, ops->rxtxlo_frac / (float)INT_MAX); - res = ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_FREQ, - ops->txfrequency - freqoff); - if (res) - return res; + res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_FREQ, + ops->txfrequency - freqoff); + res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_BW, + ABS(freqoff) * ops->rxbw_factor); + res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_BW, + 1e6); + res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, -freqoff); + res = res ? res : find_best_2d(&o[0], SIZEOF_ARRAY(o) - coarse, ops, ops->defstop, &ops->i, &ops->q, &ops->bestmeas); - res = ops->set_nco_offset(ops->param, ops->channel, -freqoff); - if (res) - return res; - - res = find_best_2d(&o[0], SIZEOF_ARRAY(o), ops, ops->defstop, &ops->i, &ops->q, &ops->bestmeas); - if (res) - return res; - - return 0; + return res; } static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, int* opwr) @@ -160,32 +163,37 @@ static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, int* return 0; } -int _calibrate_iqimb_generic(struct calibrate_ops* ops, int32_t freqoffset, - int32_t rximoff, int32_t rxreoff, evaluate_fnN_t func) +int _calibrate_iqimb_generic(struct calibrate_ops* ops, + int32_t freqoffset, + int32_t rximoff, + int32_t rxreoff, + evaluate_fnN_t func) { - int res; + int res = 0; int pwr_r; int pwr_i; int a, giq, b; struct opt_iteration2d o[3]; + unsigned coarse = ops->coarse_mode; + if (coarse >= SIZEOF_ARRAY(o)) { + coarse = SIZEOF_ARRAY(o) - 1; + } - res = ops->set_nco_offset(ops->param, ops->channel, rxreoff); - if (res) - return res; - - res = _calibrate_txpwr(ops, freqoffset, &pwr_r); - if (res) - return res; - - res = ops->set_nco_offset(ops->param, ops->channel, rximoff); - if (res) - return res; + int required_bw = MAX(ABS(rxreoff), ABS(rximoff)); - res = ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_i); + res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_BW, + required_bw * ops->rxbw_factor); + res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_BW, + freqoffset * ops->txbw_factor); + res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, rxreoff); + res = res ? res : _calibrate_txpwr(ops, freqoffset, &pwr_r); + res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, rximoff); + res = res ? res : ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_i); if (res) return res; - USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Imbalance %d pwr (%d)\n", pwr_i, pwr_r - pwr_i); + USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Imbalance %d pwr (%d) BW=%.3f coarse=%d\n", pwr_i, pwr_r - pwr_i, + required_bw / 1e6, coarse); // Probe AI and AQ, choice what path to go o[0].limit[0] = ops->rximb_ang_corr; @@ -206,12 +214,11 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, int32_t freqoffset, o[2].sf = &find_iterate_min; o[2].exparam = 0; - res = find_best_2d(&o[0], SIZEOF_ARRAY(o), ops, ops->defstop, &a, &giq, &b); + res = find_best_2d(&o[0], SIZEOF_ARRAY(o) - coarse, ops, ops->defstop, &a, &giq, &b); if (res) return res; USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Imbalance %d pwr (%d) improvement %d [PHA=%d IQ=%d]\n", b, pwr_r - b, pwr_i - b, a, giq); - return 0; } @@ -230,7 +237,7 @@ int calibrate_rxiqimb(struct calibrate_ops* ops) if (res) return res; - return _calibrate_iqimb_generic(ops, 0, ops->rxiqimb_frac, -ops->rxiqimb_frac, _evaluate_rxaiq); + return _calibrate_iqimb_generic(ops, 0, freqoff, -freqoff, _evaluate_rxaiq); } @@ -239,18 +246,24 @@ int calibrate_txiqimb(struct calibrate_ops* ops) int res; // Set RX to be TXLO - sampl int32_t freqoff = (((int64_t)ops->rxsamplerate * ops->txiqimb_frac) >> 31); + int32_t rxiqimboff = (((int64_t)ops->rxsamplerate * ops->rxiqimb_frac) >> 31); + + int64_t freq = ops->txfrequency - freqoff; + - USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_TXIQIMB: Set RX measeure freq %d - %d (from %.3f)\n", - ops->txfrequency, freqoff, ops->txiqimb_frac / (float)INT_MAX); + USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_TXIQIMB: Set RX measeure freq %.3f with expects peak at [%.3f %.3f] (from %.3f)\n", + freq / 1e6, + (-freqoff + rxiqimboff) / 1e6, + (-freqoff - rxiqimboff) / 1e6, + ops->txiqimb_frac / (float)INT_MAX); - res = ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_FREQ, - ops->txfrequency - freqoff); + res = ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_FREQ, freq); if (res) return res; return _calibrate_iqimb_generic(ops, - ops->rxiqimb_frac, - -ops->txiqimb_frac + ops->rxiqimb_frac, - -ops->txiqimb_frac - ops->rxiqimb_frac, + rxiqimboff, + -freqoff + rxiqimboff, + -freqoff - rxiqimboff, _evaluate_txaiq); } diff --git a/src/lib/cal/cal_lo_iqimb.h b/src/lib/cal/cal_lo_iqimb.h index e236c983..b9641a7c 100644 --- a/src/lib/cal/cal_lo_iqimb.h +++ b/src/lib/cal/cal_lo_iqimb.h @@ -44,6 +44,10 @@ struct calibrate_ops int rxtxlo_frac; int rxiqimb_frac; // Relative position (-1; 1) to feed test tx sig for RXIQIMB & TXLO int txiqimb_frac; // Relative position (-1; 1) to feed test tx sig for TXIQIMB + int coarse_mode; + + float rxbw_factor; // Extend RX bandwith from required observation frequency + float txbw_factor; // Extend TX bandwith from required observation frequency void* param; @@ -64,7 +68,7 @@ struct calibrate_ops int bestmeas; // functions - int (*set_nco_offset)(void* param, int channel, int32_t freqoffset); + int (*set_nco_rx_offset)(void* param, int channel, int32_t freqoffset); int (*set_corr_param)(void* param, int channel, int corr_type, int value); int (*do_meas_nco_avg)(void* param, int channel, unsigned logduration, int* fout); int (*set_tx_testsig)(void* param, int channel, int32_t freqoffset, unsigned pwr); diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index 12dfa591..98875cce 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -217,6 +217,11 @@ static int dev_m2_lm6_1_sdr_revision_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint static int dev_m2_lm6_1_sdr_rfe_throttle_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm6_1_sdr_dccorr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm6_1_sdr_tfe_gen_const_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + +static int usdr_device_m2_lm6_1_calibrate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int usdr_device_m2_lm6_1_calibrate_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); + static const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { @@ -235,6 +240,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/refclk/frequency", {dev_m2_lm6_1_sdr_refclk_frequency_set, dev_m2_lm6_1_sdr_refclk_frequency_get}}, { "/dm/sdr/refclk/path", {dev_m2_lm6_1_sdr_refclk_path_set, NULL}}, + { "/dm/sdr/0/calibrate", { usdr_device_m2_lm6_1_calibrate_set, usdr_device_m2_lm6_1_calibrate_get }}, + { "/dm/sdr/0/rx/tia/cfb", { dev_m2_lm6_1_sdr_rx_tia_cfb_set, NULL }}, { "/dm/sdr/0/rx/tia/rfb", { dev_m2_lm6_1_sdr_rx_tia_rfb_set, NULL }}, @@ -278,6 +285,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/tx/phgaincorr", { dev_m2_lm6_1_sdr_tx_phgaincorr_set, NULL }}, { "/dm/sdr/0/rx/phgaincorr", { dev_m2_lm6_1_sdr_rx_phgaincorr_set, NULL }}, + { "/dm/sdr/0/tfe/generator/const", { dev_m2_lm6_1_sdr_tfe_gen_const_set, NULL }}, + { "/debug/hw/lms6002d/0/reg", { dev_m2_lm6_1_debug_lms6002d_reg_set, dev_m2_lm6_1_debug_lms6002d_reg_get }}, { "/debug/hw/si5332/0/reg", { dev_m2_lm6_1_debug_si5332_reg_set, dev_m2_lm6_1_debug_si5332_reg_get }}, { "/debug/hw/tps6381x/0/reg", { dev_m2_lm6_1_debug_tps6381x_reg_set, dev_m2_lm6_1_debug_tps6381x_reg_get }}, @@ -345,6 +354,9 @@ static const usdr_dev_link_t s_links[] = { { "/dm/sdr/0/rx/phgaincorr/1","/dm/sdr/0/rx/phgaincorr" }, { "/dm/sdr/0/tx/phgaincorr/1","/dm/sdr/0/tx/phgaincorr" }, + { "/dm/sdr/0/tfe/generator/const/0", "/dm/sdr/0/tfe/generator/const" }, + { "/dm/sdr/0/tfe/generator/const/1", "/dm/sdr/0/tfe/generator/const" }, + }; @@ -359,6 +371,8 @@ struct dev_m2_lm6_1 { uint32_t debug_tps6381x_last; uint32_t debug_lp8758_last; + int cal_data[8]; + stream_handle_t* rx; stream_handle_t* tx; }; @@ -1117,6 +1131,72 @@ int usdr_device_m2_lm6_1_initialize(pdevice_t udev, unsigned pcount, const char* return res; } +int dev_m2_lm6_1_sdr_tfe_gen_const_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + bool normal = (value == UINT64_MAX); + int16_t vi = (int16_t)((value >> 16) & 0xffff); + int16_t vq = (int16_t)((value >> 0) & 0xffff); + + return usdr_tx_gen_set(&d->d, !normal, 0x3, vi, vq); +} + +int usdr_device_m2_lm6_1_calibrate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + int res; + unsigned flags = value & 0xfffff; + unsigned chan = value >> 32; + + if (flags > 2*65536 || chan > 1) { + const char* v = (const char* )value; + chan = 0; // TODO B + flags = 0; + + if (strncmp(v, "e", 1) == 0) { + v += 1; + flags |= USDR_CAL_EXT_FB; + } + + if (strncmp(v, "a:", 2) == 0) { + v += 2; + } if (strncmp(v, "b:", 2) == 0) { + v += 2; + chan = 1; + } + + if (strcmp(v, "txlo") == 0) { + flags |= USDR_CAL_TXLO; + } else if (strcmp(v, "rxlo") == 0) { + flags |= USDR_CAL_RXLO; + } else if (strcmp(v, "txiqimb") == 0) { + flags |= USDR_CAL_TXIQIMB; + } else if (strcmp(v, "rxiqimb") == 0) { + flags |= USDR_CAL_RXIQIMB; + } else if (strcmp(v, "tx") == 0) { + flags |= USDR_CAL_TXLO | USDR_CAL_TXIQIMB; + } else if (strcmp(v, "rx") == 0) { + flags |= USDR_CAL_RXLO | USDR_CAL_RXIQIMB; + } else if (strcmp(v, "all") == 0) { + flags |= USDR_CAL_TXLO | USDR_CAL_TXIQIMB | USDR_CAL_RXLO | USDR_CAL_RXIQIMB; + } else if (strcmp(v, "lo") == 0) { + flags |= USDR_CAL_TXLO | USDR_CAL_RXLO; + } else { + return -EINVAL; + } + } + + res = usdr_calibrate(&d->d, chan, flags, &d->cal_data[0]); + return res; +} + +int usdr_device_m2_lm6_1_calibrate_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + *value = (intptr_t)&d->cal_data[0]; + return 0; +} + static const channel_map_info_t s_usdr_chmap[] = { { "ai", 0 }, { "aq", 1 }, @@ -1169,10 +1249,9 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha if (res) { return res; } - - //if (d->d.rx_lo != 0) { - // usdr_rfic_fe_set_freq(&d->d, false, d->d.rx_lo, NULL); - //} + if (d->d.tx_lo) { + lms6002d_tune_pll(&d->d.lms, true, d->d.tx_lo); + } for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { if (d->d.rx_raw.lo[i].set) { @@ -1203,12 +1282,12 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha res = res ? res : usdr_reset_txfex(&d->d); } - res = create_sfetrx4_stream(dev, extended_core ? CORE_EXFETX_DMA32_R0_2 : CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, - flags, - extended_core ? M2PCI_REG_WR_TXDMA_CFG0 : M2PCI_REG_WR_TXDMA_CNF_L, - M2PCI_REG_WR_SYNC_CTRL, - M2PCI_REG_RD_TXDMA_STAT, - 0, CSR_TFE4_BASE, &d->tx, &chans); + res = res ? res : create_sfetrx4_stream(dev, extended_core ? CORE_EXFETX_DMA32_R0_2 : CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, + flags, + extended_core ? M2PCI_REG_WR_TXDMA_CFG0 : M2PCI_REG_WR_TXDMA_CNF_L, + M2PCI_REG_WR_SYNC_CTRL, + M2PCI_REG_RD_TXDMA_STAT, + 0, CSR_TFE4_BASE, &d->tx, &chans); if (res) { return res; } @@ -1242,6 +1321,22 @@ int usdr_device_m2_lm6_1_unregister_stream(device_t* dev, stream_handle_t* strea return 0; } +static int usdr_device_m2_lm6_1_sync(device_t* dev, + stream_handle_t** pstreams, + unsigned stream_count, + const char* sync_op) +{ + if (sync_op != NULL && strcmp(sync_op, "off")) { + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)dev; + + //if (d->tx) { + // usdr_calibrate(&d->d, 3, USDR_CAL_TXLO | USDR_CAL_TXIQIMB, NULL); + //} + } + + return sfetrx4_stream_sync(dev, pstreams, stream_count, sync_op); +} + static int usdr_device_m2_lm6_1_create(lldev_t dev, /*UNUSED*/ device_id_t devid) @@ -1282,7 +1377,7 @@ int usdr_device_m2_lm6_1_create(lldev_t dev, /*UNUSED*/ device_id_t devid) d->base.destroy = &usdr_device_m2_lm6_1_destroy; d->base.create_stream = &usdr_device_m2_lm6_1_create_stream; d->base.unregister_stream = &usdr_device_m2_lm6_1_unregister_stream; - d->base.timer_op = &sfetrx4_stream_sync; + d->base.timer_op = usdr_device_m2_lm6_1_sync; d->rx = NULL; d->tx = NULL; diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index d5fe3ff3..e0f61e88 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -72,6 +72,8 @@ enum fpga_phy_regs { CFG_REG_IQIMB_1 = 3, CFG_REG_IQIMB_2 = 4, CFG_REG_IQIMB_3 = 5, + CFG_REG_DC_EST = 6, + CFG_REG_DC_GEN = 7, CFG_REG_NCO0_L = 8, CFG_REG_NCO0_H = 9, CFG_REG_NCO1_L = 10, @@ -79,6 +81,10 @@ enum fpga_phy_regs { CFG_REG_DSP_LD = 64, }; +#define MAKE_PHY_WR_REG(a, w) ((((a) & 0x7f) << 24) | ((w) & 0xffffff)) +#define MAKE_PHY_WR_SUB_REG(a, b, w) MAKE_PHY_WR_REG(a, (((b) & 0xff) << 16) | ((w) & 0xffff)) +#define MAKE_PHY_RD_REG(a, i) ((((a) & 0x7f) << 24) | ((i) & 0xffffff) | 0x80000000) + // RX chain // LNA_GAIN -> mixer -> VGA1_GAIN -> lpf -> VGA2_GAIN[a,b] -> adc @@ -307,6 +313,32 @@ static int _usdr_set_nco(usdr_dev_t *d, bool rx, unsigned nco_num, double freq) return res; } +enum { + CFG_REG_DC_GEN_CTRL = 0, + CFG_REG_DC_GEN_AI = 4, + CFG_REG_DC_GEN_AQ = 5, + CFG_REG_DC_GEN_BI = 6, + CFG_REG_DC_GEN_BQ = 7, +}; + +int usdr_tx_gen_set(usdr_dev_t *d, bool enable, unsigned chanmsk, int16_t i, int16_t q) +{ + int res = 0; + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_SUB_REG(CFG_REG_DC_GEN, CFG_REG_DC_GEN_CTRL, enable ? 1 : 0)); + if (!enable) + return res; + + if (chanmsk & 1) { + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_SUB_REG(CFG_REG_DC_GEN, CFG_REG_DC_GEN_AI, i)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_SUB_REG(CFG_REG_DC_GEN, CFG_REG_DC_GEN_AQ, q)); + } + if (chanmsk & 2) { + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_SUB_REG(CFG_REG_DC_GEN, CFG_REG_DC_GEN_BI, i)); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_SUB_REG(CFG_REG_DC_GEN, CFG_REG_DC_GEN_BQ, q)); + } + return res; +} + static int _usdr_set_lna_tx(usdr_dev_t *d, unsigned cfg_idx) { const freq_auto_band_map_t* cfg = &d->cfg_auto_tx[cfg_idx]; @@ -410,8 +442,6 @@ int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob) #define TARGET_RATE 30720000 -#define MAKE_PHY_WR_REG(a, w) ((((a) & 0x7f) << 24) | ((w) & 0xffffff)) -#define MAKE_PHY_RD_REG(a, i) ((((a) & 0x7f) << 24) | ((i) & 0xffffff) | 0x80000000) int usdr_reset_txfex(struct usdr_dev *d) { @@ -429,6 +459,16 @@ int usdr_reset_txnco(struct usdr_dev *d) return res; } +int usdr_update_cal(struct usdr_dev *d, bool rx) +{ + return rx ? usdr_rxupdate_cal(d) : usdr_txupdate_cal(d); +} + +int usdr_rxupdate_cal(struct usdr_dev *d) +{ + return 0; +} + int usdr_txupdate_cal(struct usdr_dev *d) { // CFG_AMP_I @@ -438,7 +478,7 @@ int usdr_txupdate_cal(struct usdr_dev *d) // I = CFG_AMP_I * i + CFG_TAN_Q * q // Q = CFG_AMP_Q * q + CFG_TAN_I * i - + // Symmetric correction to I/Q: // c = math.cos(phi / 2.0) // s = math.sin(phi / 2.0) // I = (c / alpha) * Id + (s / beta) * Qd @@ -488,6 +528,31 @@ int usdr_txupdate_cal(struct usdr_dev *d) return res; } +static int usdr_restore_nco(struct usdr_dev *d, bool istx) +{ + int res = 0; + freq_data_t* freqd = (istx) ? &d->tx_raw : &d->rx_raw; + + for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { + if (freqd->bb[i].set) { + res = res ? res : _usdr_set_nco(d, !istx, i, (int32_t)freqd->bb[i].value); + } else { + res = res ? res : _usdr_set_nco(d, !istx, i, 0); + } + } + return res; +} + +static int _usdr_update_bandwidth(struct usdr_dev *d, bool istx) +{ + unsigned rate = istx ? (d->dac_clk / d->txbb_intr) : (d->adc_clk / d->rxbb_decim); + unsigned bw = 2 * (istx ? d->tx_nco_distance : d->rx_nco_distance) + rate; + + USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Updating %s bandwidth to %.3f Mhz\n", + lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", bw / 1e6); + return lms6002d_set_bandwidth(&d->lms, istx, bw); +} + int usdr_set_samplerate_ex(struct usdr_dev *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, @@ -560,16 +625,7 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, // Update NCOs for (unsigned rxgrp = 0; rxgrp < 2; rxgrp++) { - bool istx = (rxgrp == 1); - freq_data_t* freqd = (istx) ? &d->tx_raw : &d->rx_raw; - - for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { - if (freqd->bb[i].set) { - res = res ? res : _usdr_set_nco(d, !istx, i, (int32_t)freqd->bb[i].value); - } else { - res = res ? res : _usdr_set_nco(d, !istx, i, 0); - } - } + res = res ? res : usdr_restore_nco(d, (rxgrp == 1)); } uint32_t v = 0; @@ -587,10 +643,12 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, // If user didn't set BW filter set it to samplerate if (!d->rx_bw.set && rxrate > 1) { - res = res ? res : lms6002d_set_bandwidth(&d->lms, false, 2 * d->rx_nco_distance + rxrate); + //res = res ? res : lms6002d_set_bandwidth(&d->lms, false, 2 * d->rx_nco_distance + rxrate); + res = res ? res : _usdr_update_bandwidth(d, false); } if (!d->tx_bw.set && txrate > 1) { - res = res ? res : lms6002d_set_bandwidth(&d->lms, true, 2 * d->tx_nco_distance + txrate); + //res = res ? res : lms6002d_set_bandwidth(&d->lms, true, 2 * d->tx_nco_distance + txrate); + res = res ? res : _usdr_update_bandwidth(d, true); } USDR_LOG("UDEV", USDR_LOG_INFO, "INTR %d RX_RATE %.3f TX_RATE %.3f MXLO %.3f\n", int_dec_x[ind], rxrate / 1.0e6, txrate / 1.0e6, d->mixer_lo / 1.0e6); @@ -1040,12 +1098,15 @@ int usdr_rfic_fe_set_freq(struct usdr_dev *d, // Update BW if ((istx && !d->tx_bw.set) || (!istx && !d->rx_bw.set)) { + /* unsigned rate = istx ? (d->dac_clk / d->txbb_intr) : (d->adc_clk / d->rxbb_decim); - unsigned bw = 2 * d->tx_nco_distance + rate; + unsigned bw = 2 * (istx ? d->tx_nco_distance : d->rx_nco_distance) + rate; USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Updating %s bandwidth to %.3f Mhz\n", lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", bw / 1e6); res = res ? res : lms6002d_set_bandwidth(&d->lms, istx, bw); + */ + res = res ? res : _usdr_update_bandwidth(d, istx); } return res; @@ -1293,3 +1354,258 @@ int usdr_rxdccorr(struct usdr_dev *d, uint64_t *ov) *ov = out; return res; } + +static +int usdr_set_corr_param(usdr_dev_t* d, int channel, int corr_type, int value) +{ + unsigned type = (corr_type & 0xff); + bool rx = (corr_type >> CORR_DIR_OFF) == CORR_DIR_RX; + struct imb_data* imb_corr = rx ? &d->rx_corr : &d->tx_corr; + + switch (type) { + case CORR_PARAM_I: + case CORR_PARAM_Q: + USDR_LL_LOG(d->base.dev, "LMS6", USDR_LOG_INFO, "Set %s%s%s to %d\n", + rx ? "RX" : "TX", + (channel == 0) ? "A" : "B", + type == CORR_PARAM_I ? "I" : "Q", + value); + if (type == CORR_PARAM_Q) { + imb_corr->dc_i = value; + } else { + imb_corr->dc_q = value; + } + + if (rx) { + return -EINVAL; + } else { + return usdr_tx_dccorr(d, imb_corr->dc_i, imb_corr->dc_q); + } + + case CORR_PARAM_A: + USDR_LL_LOG(d->base.dev, "LMS6", USDR_LOG_INFO, "Set %sA to %d\n", rx ? "RX" : "TX", value); + imb_corr->pahse = value; + return usdr_update_cal(d, rx); + + case CORR_PARAM_GIQ: + USDR_LL_LOG(d->base.dev, "LMS6", USDR_LOG_INFO, "Adjust %sGIQ to %d\n", + rx ? "RX" : "TX", value); + imb_corr->ampl = value; + return usdr_update_cal(d, rx); + + case CORR_OP_SET_FREQ: + return lms6002d_tune_pll(&d->lms, !rx, value); + + case CORR_OP_SET_BW: + return lms6002d_set_bandwidth(&d->lms, !rx, value); + + default: + return -EINVAL; + } + + return 0; +} + +static +int usdrcal_set_corr_param(void* param, int channel, int corr_type, int value) +{ + usdr_dev_t *d = (usdr_dev_t *)param; + return usdr_set_corr_param(d, channel, corr_type, value); +} + +static +int usdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* func) +{ + usdr_dev_t *d = (usdr_dev_t *)param; + unsigned acc_idx = 1; //TODO: FIXME: !!!!!!!!!!!!!!!!!!! + + return phy_do_meas_nco_avg(d->lms.dev, REG_CFG_PHY_0, 32767, channel, acc_idx, func); +} + +static +int usdrcal_set_tx_testsig(void* param, int channel, int32_t freqoffset, unsigned pwr) +{ + usdr_dev_t *d = (usdr_dev_t *)param; + int res = 0; + int clamp_pwr = (pwr > 30000) ? 30000 : pwr; + res = res ? res : usdr_tx_gen_set(d, pwr == 0 ? false : true, 0x3, clamp_pwr, 0); + res = res ? res : _usdr_set_nco(d, false, 0, freqoffset); + res = res ? res : _usdr_set_nco(d, false, 1, freqoffset); + return res; +} + +static +int usdrcal_set_nco_offset(void* param, int channel, int32_t freqoffset) +{ + usdr_dev_t *d = (usdr_dev_t *)param; + return _usdr_set_nco(d, true, channel, freqoffset); +} + +static +int usdrcal_init_calibrate(usdr_dev_t *d, struct calibrate_ops* ops, unsigned channel) +{ + ops->adcrate = d->adc_clk; + ops->dacrate = d->dac_clk; + ops->rxsamplerate = ops->adcrate / d->rxbb_decim; + ops->txsamplerate = ops->dacrate / d->txbb_intr; + + ops->rxfrequency = d->rx_lo; + ops->txfrequency = d->tx_lo; + ops->channel = channel; + ops->deflogdur = ops->rxsamplerate / 16; + if (ops->deflogdur > 131072) { + ops->deflogdur = 131072; + } + ops->defstop = -120000; + ops->param = d; + + // Make very odd fraction not to fall harmonics into the same bins after nyquist + ops->rxtxlo_frac = ((uint64_t)INT_MAX + 1) / 9.0187; + ops->rxiqimb_frac = ((uint64_t)INT_MAX + 1) / 5.1031; + ops->txiqimb_frac = ((uint64_t)INT_MAX + 1) / 11.1076; + ops->coarse_mode = 0; + + ops->rxbw_factor = 2.45; + ops->txbw_factor = 2.45; + + ops->txlo_iq_corr.max = 2048; + ops->txlo_iq_corr.min = -2047; + + ops->tximb_iq_corr.max = IMB_AMPL_MAX; + ops->tximb_iq_corr.min = -IMB_AMPL_MAX; + + ops->tximb_ang_corr.max = IMB_PHASE_MAX; + ops->tximb_ang_corr.min = -IMB_PHASE_MAX; + + ops->rxlo_iq_corr.max = 63; + ops->rxlo_iq_corr.min = -63; + + ops->rximb_iq_corr.max = IMB_AMPL_MAX; + ops->rximb_iq_corr.min = -IMB_AMPL_MAX; + + ops->rximb_ang_corr.max = IMB_PHASE_MAX; + ops->rximb_ang_corr.min = -IMB_PHASE_MAX; + + ops->set_nco_rx_offset = &usdrcal_set_nco_offset; // RX NCO offset + ops->set_corr_param = &usdrcal_set_corr_param; + ops->do_meas_nco_avg = &usdrcal_do_meas_nco_avg; + ops->set_tx_testsig = &usdrcal_set_tx_testsig; + + return 0; +} + +int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) +{ + int res = 0; + struct calibrate_ops cops; + lldev_t dev = d->lms.dev; + bool externallb = (param & USDR_CAL_EXT_FB) == USDR_CAL_EXT_FB; + bool norestore = false; + + unsigned coarse = (((param & USDR_CAL_COARSE_1) == USDR_CAL_COARSE_1) ? 1 : 0) | + (((param & USDR_CAL_COARSE_2) == USDR_CAL_COARSE_2) ? 2 : 0); + unsigned tx_lo = d->tx_lo; + unsigned rx_lo = d->rx_lo; + unsigned rfic_rx_lo = d->rfic_rx_lo; + unsigned rfe_gain_lna_sel = (d->lms.rfe_gain_lna_sel & 0x30) >> 4; // Fixme! + + res = res ? res : usdrcal_init_calibrate(d, &cops, channel); + cops.coarse_mode = coarse; + + if ((param & USDR_CAL_RXLO) && (rx_lo > 0)) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration RXLO(%c) ------------------\n", 'A' + channel); + } + + if ((param & USDR_CAL_RXIQIMB) && (rx_lo > 0)) { + // TODO if TX was disabled enable TX + USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration RXIQIMB(%c) ------------------\n", 'A' + channel); + } + + if ((param & (USDR_CAL_TXLO | USDR_CAL_TXIQIMB)) && (tx_lo > 0)) { + if (rx_lo == 0) { + res = res ? res : _usdr_pwr_state(d, false, true); + res = res ? res : usleep(500000); + res = res ? res : lms6002d_tune_pll(&d->lms, false, 320e6); + res = res ? res : usdr_calib_dc(d, true); + res = res ? res : lms6002d_tune_pll(&d->lms, true, tx_lo); + } + if (!externallb) { + unsigned lb_path = 1; // TODO select RX path for LB + res = res ? res : lms6002d_set_rx_path(&d->lms, lb_path); + res = res ? res : lms6002d_rf_loopback_en(&d->lms); + } + if (res) + return res; + + if (param & USDR_CAL_TXLO) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration TXLO(%c) ------------------\n", 'A' + channel); + res = (res) ? res : calibrate_txlo(&cops); + if (res) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " TXLO failed: res=%d\n", res); + return res; + } + if (sarray) { + sarray[ 2 * 1 + 0] = cops.i; + sarray[ 2 * 1 + 1] = cops.q; + } + } + + if (param & USDR_CAL_TXIQIMB) { + uint8_t old_txvga1 = d->lms.trf_vga1_gain; + USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration TXIQIMB(%c) ------------------\n", 'A' + channel); + res = res ? res : lms6002d_set_txvga1_gain(&d->lms, 28); + res = res ? res : calibrate_txiqimb(&cops); + res = res ? res : lms6002d_set_txvga1_gain(&d->lms, old_txvga1); + if (res) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " TXIQIMB failed: res=%d\n", res); + return res; + } + if (sarray) { + sarray[ 2 * 3 + 0] = cops.i; + sarray[ 2 * 3 + 1] = cops.q; + } + } + + if (!norestore) { + if (rfic_rx_lo > 0) { + res = res ? res : lms6002d_tune_pll(&d->lms, false, rfic_rx_lo); + } else { + res = res ? res : lms6002d_disable_pll(&d->lms, false); + } + if (!externallb) { + res = res ? res : lms6002d_set_rx_path(&d->lms, rfe_gain_lna_sel); + res = res ? res : lms6002d_rf_loopback_dis(&d->lms); + } + if (res) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, "restore configuration failed: res=%d\n", res); + return res; + } + } + + } + + if (norestore) + return res; + + res = res ? res : usdr_tx_gen_set(d, false, 0, 0, 0); // Restore TX BB + res = res ? res : usdr_restore_nco(d, true); // RXNCO + res = res ? res : usdr_restore_nco(d, false); // TXNCO + + if (!d->rx_bw.set) { + res = res ? res : _usdr_update_bandwidth(d, false); + } else { + res = res ? res : lms6002d_set_bandwidth(&d->lms, false, d->rx_bw.value); + } + + if (!d->tx_bw.set) { + res = res ? res : _usdr_update_bandwidth(d, true); + } else { + res = res ? res : lms6002d_set_bandwidth(&d->lms, true, d->tx_bw.value); + } + + if (rx_lo == 0) { + _usdr_pwr_state(d, false, false); + } + + return res; +} diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.h b/src/lib/device/m2_lm6_1/usdr_ctrl.h index 61effaf5..34a41bfb 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.h +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.h @@ -77,6 +77,8 @@ struct imb_data int32_t ampl; // AMPL_IMB_MIN .. AMPL_IMB_MAX int32_t pahse; // IMB_PHASE_MIN .. IMB_PHASE_MAX int32_t amp_corr; // Amplitude correction + int16_t dc_i; + int16_t dc_q; }; struct usdr_dev @@ -150,6 +152,7 @@ struct usdr_dev opt_u32_t rx_bw; struct imb_data tx_corr; + struct imb_data rx_corr; freq_auto_band_map_t cfg_auto_rx[USDR_MAX_RX_BANDS]; freq_auto_band_map_t cfg_auto_tx[USDR_MAX_TX_BANDS]; @@ -215,6 +218,20 @@ int usdr_reset_txfex(struct usdr_dev *d); int usdr_rxdccorr(struct usdr_dev *d, uint64_t *ov); +int usdr_tx_gen_set(usdr_dev_t *d, bool enable, unsigned chanmsk, int16_t i, int16_t q); + +enum { + USDR_CAL_RXLO = 1, + USDR_CAL_TXLO = 2, + USDR_CAL_RXIQIMB = 4, + USDR_CAL_TXIQIMB = 8, + + USDR_CAL_EXT_FB = 256, + USDR_CAL_COARSE_1 = 512, + USDR_CAL_COARSE_2 = 1024, +}; +int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray); + #ifndef NO_IGPO enum { @@ -249,8 +266,6 @@ enum { IGPI_CLK1PPS = 28, IGPI_TXCLK = 32, IGPI_RXCLK = 36, - IGPI_RX_I = 40, - IGPI_RX_Q = 44, }; @@ -262,6 +277,8 @@ int usdr_tx_dccorr(usdr_dev_t *d, int16_t i, int16_t q); int usdr_reset_txnco(struct usdr_dev *d); int usdr_txupdate_cal(struct usdr_dev *d); +int usdr_rxupdate_cal(struct usdr_dev *d); +int usdr_update_cal(struct usdr_dev *d, bool rx); int usdr_tx_iqimb_set(usdr_dev_t* d, int iq_amp_imb, int phase_imb); diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 88d066b7..fa6ff531 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -876,9 +876,10 @@ int dev_m2_lm7_1_tfe_gen_const_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t v unsigned chan = (unsigned)(value >> 32); unsigned vi = (value >> 16) & 0xffff; unsigned vq = (value >> 0) & 0xffff; + bool normal = (value == UINT64_MAX); res = (res) ? res : lms7002m_mac_set(&d->xdev.base.lmsstate, chan); - res = (res) ? res : lms7002m_xxtsp_gen(&d->xdev.base.lmsstate, LMS_TXTSP, XXTSP_DC, vi, vq); + res = (res) ? res : lms7002m_xxtsp_gen(&d->xdev.base.lmsstate, LMS_TXTSP, normal ? XXTSP_NORMAL : XXTSP_DC, vi, vq); return res; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 2172dbde..2866a93f 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -2363,6 +2363,10 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->rxtxlo_frac = ((uint64_t)INT_MAX + 1) / 9.0187; ops->rxiqimb_frac = ((uint64_t)INT_MAX + 1) / 5.1031; ops->txiqimb_frac = ((uint64_t)INT_MAX + 1) / 11.1076; + ops->coarse_mode = 0; + + ops->rxbw_factor = 2.33; + ops->txbw_factor = 2.33; ops->txlo_iq_corr.max = 1023; ops->txlo_iq_corr.min = -1023; @@ -2382,7 +2386,7 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->rximb_ang_corr.max = 2047; ops->rximb_ang_corr.min = -2047; - ops->set_nco_offset = &xsdrcal_set_nco_offset; + ops->set_nco_rx_offset = &xsdrcal_set_nco_offset; ops->set_corr_param = &xsdrcal_set_corr_param; ops->do_meas_nco_avg = &xsdrcal_do_meas_nco_avg; ops->set_tx_testsig = &xsdrcal_set_tx_testsig; diff --git a/src/lib/hw/lms6002d/lms6002d.c b/src/lib/hw/lms6002d/lms6002d.c index 3da7f5aa..ddc8e519 100644 --- a/src/lib/hw/lms6002d/lms6002d.c +++ b/src/lib/hw/lms6002d/lms6002d.c @@ -75,6 +75,7 @@ int lms6002d_create(lldev_t dev, unsigned subdev, unsigned lsaddr, struct lms600 out->rxpll_vco_div_bufsel = (uint8_t)MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(0, 0, 1); out->rfe_gain_lna_sel = 0xc0; out->trf_pa_ctrl = (uint8_t)MAKE_LMS6002D_TRF_PA_CTRL(0, 0); + out->trf_vga1_gain = (uint8_t)GET_LMS6002D_TRF_VGA1GAIN_VGA1GAIN(21); memset(out->rclpfcal, 3, sizeof(out->rclpfcal)); @@ -244,6 +245,24 @@ int lms6002d_find_vcocap(lms6002d_state_t* obj, bool tx, uint8_t* phi, uint8_t* return 0; } +int lms6002d_disable_pll(lms6002d_state_t* obj, bool tx) +{ + int res; + if (tx) { + SET_LMS6002D_TOP_ENREG_CLK_TX_DSM_SPI(obj->top_enreg, 0); + } else { + SET_LMS6002D_TOP_ENREG_CLK_RX_DSM_SPI(obj->top_enreg, 0); + } + + uint16_t regs[] = { + MAKE_LMS6002D_REG_WR(TOP_ENREG, obj->top_enreg), + tx ? MAKE_LMS6002D_TXPLL_PLL_CFG(0, 0, 0, 0, 0) : + MAKE_LMS6002D_RXPLL_PLL_CFG(0, 0, 0, 0, 0), + }; + + res = lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); + return res; +} int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) { @@ -432,8 +451,8 @@ int lms6002d_set_bandwidth(lms6002d_state_t* obj, bool tx, unsigned freq) (tx ? 0x3600 : 0x5600) | 0x8000 | (lpfcal << 4), }; - USDR_LOG("6002", USDR_LOG_INFO, "LPF %d => BAND=%d RC=%d BYPASS=%d CAL=%d\n", - freq / 1000, band, lpfcal, b, obj->rclpfcal[band]); + USDR_LOG("6002", USDR_LOG_INFO, "LPF_%s %d => BAND=%d RC=%d BYPASS=%d CAL=%d\n", + tx ? "TX" : "RX", freq / 1000, band, lpfcal, b, obj->rclpfcal[band]); res = lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); if (res) @@ -477,7 +496,7 @@ int lms6002d_set_txvga1_gain(lms6002d_state_t* obj, unsigned vga) uint16_t regs[] = { MAKE_LMS6002D_TRF_VGA1GAIN(vga), }; - + obj->trf_vga1_gain = vga; res = lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); if (res) return res; diff --git a/src/lib/hw/lms6002d/lms6002d.h b/src/lib/hw/lms6002d/lms6002d.h index 932689d2..a01d06a9 100644 --- a/src/lib/hw/lms6002d/lms6002d.h +++ b/src/lib/hw/lms6002d/lms6002d.h @@ -31,12 +31,15 @@ struct lms6002d_state { uint8_t rfe_in1sel_dci; uint8_t rfe_gain_lna_sel; uint8_t trf_pa_ctrl; + + uint8_t trf_vga1_gain; }; typedef struct lms6002d_state lms6002d_state_t; int lms6002d_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lms6002d_state_t* out); int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq); +int lms6002d_disable_pll(lms6002d_state_t* obj, bool tx); //int lms6002d_rf_enable(lms6002d_state_t* obj, bool tx, bool en); diff --git a/src/lib/ipblks/dc_estim.c b/src/lib/ipblks/dc_estim.c index 632aa39a..d905417f 100644 --- a/src/lib/ipblks/dc_estim.c +++ b/src/lib/ipblks/dc_estim.c @@ -9,6 +9,7 @@ enum { ADDR_DC_EST_ACCM = 1, }; +// TODO: fix wr bit to 1 for usdr! static int _phy_rx_reg(lldev_t d, uint32_t llreg, bool wr, uint8_t bank, uint8_t addr, uint16_t val) { uint32_t reg = (!wr ? 0x80000000 : 0) | (((uint32_t)bank & 0x7f) << 24) | ((uint32_t)addr << 16) | val; From e0589afef706e198785050e081a44fae988811e0 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Mon, 20 Apr 2026 18:31:26 +0400 Subject: [PATCH 378/397] usdr: add TXLPF DC correction --- src/lib/device/m2_lm6_1/usdr_ctrl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index e0f61e88..1ce36962 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -959,8 +959,7 @@ int usdr_dtor(struct usdr_dev *d) return 0; } -static -int _usdr_lms6002_dc_calib(struct usdr_dev *d) +static int _usdr_lms6002_dc_calib_rx(struct usdr_dev *d) { int res = 0; @@ -985,6 +984,15 @@ int _usdr_lms6002_dc_calib(struct usdr_dev *d) return res; } +static int _usdr_lms6002_dc_calib_tx(struct usdr_dev *d) +{ + int res = 0; + + res = res ? res : lms6002d_cal_txrxlpfdc(&d->lms, true); + + return res; +} + int usdr_rfic_fe_set_freq(struct usdr_dev *d, enum fe_freq_type type, unsigned chmask, @@ -1324,9 +1332,9 @@ int usdr_set_tx_port_switch(struct usdr_dev *d, unsigned path) int usdr_calib_dc(struct usdr_dev *d, bool rx) { int res; - res = _usdr_lms6002_dc_calib(d); + res = rx ? _usdr_lms6002_dc_calib_rx(d) : _usdr_lms6002_dc_calib_tx(d); - USDR_LOG("UDEV", USDR_LOG_INFO, "DC - Calibration done\n"); + USDR_LOG("UDEV", USDR_LOG_INFO, "DC %s - Calibration done\n", rx ? "RX" : "TX"); return res; } From 89f06d11aa5fa336efe49022366532e757688c51 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 21 Apr 2026 03:29:40 +0400 Subject: [PATCH 379/397] xsdr: fix TXLO & TXIQ imb calibration --- src/lib/cal/cal_lo_iqimb.c | 14 +++- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 96 +++++++++++++++++-------- src/lib/device/m2_lm7_1/lms7002m_ctrl.h | 9 ++- src/lib/device/m2_lm7_1/m2_lm7_1.c | 7 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 60 ++++++++++------ 5 files changed, 128 insertions(+), 58 deletions(-) diff --git a/src/lib/cal/cal_lo_iqimb.c b/src/lib/cal/cal_lo_iqimb.c index 00fb8613..b10f6301 100644 --- a/src/lib/cal/cal_lo_iqimb.c +++ b/src/lib/cal/cal_lo_iqimb.c @@ -131,8 +131,8 @@ int calibrate_txlo(struct calibrate_ops* ops) ops->txfrequency - freqoff); res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_BW, ABS(freqoff) * ops->rxbw_factor); - res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_BW, - 1e6); + //res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_BW, + // 1e6); res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, -freqoff); res = res ? res : find_best_2d(&o[0], SIZEOF_ARRAY(o) - coarse, ops, ops->defstop, &ops->i, &ops->q, &ops->bestmeas); @@ -142,7 +142,7 @@ int calibrate_txlo(struct calibrate_ops* ops) static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, int* opwr) { int ampl = 128; - int pwr_r; + int pwr_r = -120000; int res; for (; ampl <= 32768; ampl <<= 1) { @@ -160,6 +160,11 @@ static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, int* } *opwr = pwr_r; + if (pwr_r < -70000) { + USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Signal is too low to perform calibration, giving up!\n"); + return -ENAVAIL; // Signal is too low to perform calibation + } + return 0; } @@ -187,6 +192,9 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, freqoffset * ops->txbw_factor); res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, rxreoff); res = res ? res : _calibrate_txpwr(ops, freqoffset, &pwr_r); + if (res) + return res; + res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, rximoff); res = res ? res : ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_i); if (res) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index fe053553..5d9c864e 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -571,6 +571,20 @@ int lms7002m_bb_set_badwidth(lms7002_dev_t *d, return res; } +int lms7002m_bb_translate(lms7002_dev_t *d, bool dir_tx, int freq, int32_t* lms_dsp_val) +{ + double conv_freq = d->cgen_clk / (dir_tx ? d->txcgen_div : d->rxcgen_div); + double rel_freq = freq / conv_freq; + if (rel_freq > 0.5 || rel_freq < -0.5) { + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_WARNING, + "NCO %s ouf of range, requested %.3f while DAC %.3f\n", + dir_tx ? "TX" : "RX", + rel_freq / 1000, conv_freq / 1000); + return -EINVAL; + } + *lms_dsp_val = rel_freq * 4294967296.0; + return 0; +} int lms7002m_bb_set_freq(lms7002_dev_t *d, @@ -584,16 +598,11 @@ int lms7002m_bb_set_freq(lms7002_dev_t *d, return res; opt_u32_t* dsp_f = dir_tx ? &d->tx_dsp[0] : &d->rx_dsp[0]; - double conv_freq = d->cgen_clk / (dir_tx ? d->txcgen_div : d->rxcgen_div); - double rel_freq = freq / conv_freq; - if (rel_freq > 0.5 || rel_freq < -0.5) { - USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_WARNING, - "NCO %s ouf of range, requested %.3f while DAC %.3f\n", - dir_tx ? "TX" : "RX", - rel_freq / 1000, conv_freq / 1000); - return -EINVAL; - } - int pfreq = rel_freq * 4294967296.0; + int pfreq; + res = lms7002m_bb_translate(d, dir_tx, freq, &pfreq); + if (res) + return res; + if (channel & LMS7_CH_A) opt_u32_set_val(&dsp_f[0], pfreq); if (channel & LMS7_CH_B) @@ -912,8 +921,6 @@ int lms7002m_samplerate(lms7002_dev_t *d, unsigned mpy_dac = 4; // Might be 4,2,1 unsigned rxdiv = 1; unsigned txdiv = 1; - unsigned tx_dsp_inter = 1; // Off chip extra interpolator - unsigned rx_dsp_decim = 1; // Off chip extra decimator unsigned tx_host_mul = 1; unsigned rx_host_div = 1; unsigned txmaster_min = mpy_dac * dacclk; @@ -976,8 +983,8 @@ int lms7002m_samplerate(lms7002_dev_t *d, d->txcgen_div = mpy_dac; d->rxtsp_div = rxdiv; d->txtsp_div = txdiv; - d->tx_dsp_inter = tx_dsp_inter; - d->rx_dsp_decim = rx_dsp_decim; + d->tx_dsp_inter = tx_int; + d->rx_dsp_decim = rx_dec; for (unsigned j = 0; j < 4; j++) { unsigned clkdiv = (mpy_dac == 1) ? 0 : @@ -1060,7 +1067,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, rxrate / 1e6, txrate / 1e6, rxdiv, rx_host_div, txdiv, tx_host_mul, cgen_rate / mpy_adc / 1e6, cgen_rate / mpy_dac / 1e6, - tx_dsp_inter, rx_dsp_decim, cgen_rate / 1e6, + tx_int, rx_dec, cgen_rate / 1e6, rxtsp_div, txtsp_div, sisoddr_rx, sisoddr_tx, d->fref / 1e6); @@ -1088,6 +1095,40 @@ int lms7002m_samplerate(lms7002_dev_t *d, return res; } +int lms7002m_update_bandwidth(lms7002_dev_t *d, bool istx, unsigned bb_rate, bool force_upd) +{ + int res = 0; + unsigned bw = 2 * (istx ? d->tx_nco_distance : d->rx_nco_distance) + bb_rate; + if (bb_rate == 0) + return 0; + + for (unsigned i = 0; i < 2; i++) { + bool is_set = istx ? d->tx_bw[i].set : d->rx_bw[i].set; + bool is_run = istx ? d->tx_run[i] : d->rx_run[i]; + + if (!is_run) + continue; + + if (is_set && !force_upd) + continue; + + if (is_set) + bw = istx ? d->tx_bw[i].value : d->rx_bw[i].value; + + USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "Set RX[%d] bandwidth to %.3f Mhz\n", i, bw / 1e6); + + res = res ? res : lms7002m_mac_set(&d->lmsstate, i == 0 ? LMS7_CH_A : LMS7_CH_B); + if (!istx) { + res = res ? res : lms7002m_rbb_bandwidth(d, bw, false); + } else { + res = res ? res : lms7002m_tbb_bandwidth(d, bw, false); + } + + } + return res; +} + + int lms7002m_set_lmlrx_mode(lms7002_dev_t *d, unsigned mode) { @@ -1178,23 +1219,16 @@ int lms7002m_set_corr_param(lms7002_dev_t* d, int channel, int corr_type, int va int lms7002m_set_tx_testsig(lms7002_dev_t* d, int channel, int32_t freqoffset, unsigned pwr) { - unsigned scaling = d->txtsp_div / 2; - int res; - - res = lms7002m_mac_set(&d->lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); - if (res) - return res; - - res = lms7002m_xxtsp_gen(&d->lmsstate, LMS_TXTSP, - (pwr == UINT_MAX) ? XXTSP_NORMAL: XXTSP_DC, - pwr & 0x7fff, pwr & 0x7fff); - if (res) - return res; + int res = 0; + int32_t dsp_reg; - res = lms7002m_xxtsp_cmix(&d->lmsstate, LMS_TXTSP, freqoffset / scaling); - if (res) - return res; + res = res ? res : lms7002m_mac_set(&d->lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); + res = res ? res : lms7002m_xxtsp_gen(&d->lmsstate, LMS_TXTSP, + (pwr == UINT_MAX) ? XXTSP_NORMAL: XXTSP_DC, + pwr & 0x7fff, pwr & 0x7fff); + res = res ? res : lms7002m_bb_translate(d, true, freqoffset, &dsp_reg); + res = res ? res : lms7002m_xxtsp_cmix(&d->lmsstate, LMS_TXTSP, dsp_reg); - return 0; + return res; } diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h index a710f0db..60473fc6 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h @@ -96,12 +96,13 @@ struct lms7002_dev uint8_t txcgen_div; uint8_t rxtsp_div; uint8_t txtsp_div; - uint8_t tx_dsp_inter; - uint8_t rx_dsp_decim; uint8_t rx_no_siso_map; uint8_t tx_no_siso_map; + uint16_t tx_dsp_inter; + uint16_t rx_dsp_decim; + rfic_lms7_rf_path_t rx_rfic_path; rfic_lms7_rf_path_t tx_rfic_path; @@ -118,6 +119,8 @@ struct lms7002_dev unsigned cgen_clk; // LMS7002 CGEN frequency unsigned rx_lo; unsigned tx_lo; + unsigned rx_nco_distance; // Maximum distance from LO to the farest NCO + unsigned tx_nco_distance; lms7002m_limelight_conf_t lml_mode; @@ -171,6 +174,7 @@ int lms7002m_bb_set_badwidth(lms7002_dev_t *d, unsigned bw, unsigned* actualbw); +int lms7002m_bb_translate(lms7002_dev_t *d, bool dir_tx, int freq, int32_t* lms_dsp_val); int lms7002m_bb_set_freq(lms7002_dev_t *d, unsigned channel, bool dir_tx, @@ -226,6 +230,7 @@ int lms7002m_set_lmlrx_mode(lms7002_dev_t *d, unsigned mode); // Calibration +int lms7002m_update_bandwidth(lms7002_dev_t *d, bool istx, unsigned bb_rate, bool force_upd); int lms7002m_set_corr_param(lms7002_dev_t* d, int channel, int corr_type, int value); int lms7002m_set_tx_testsig(lms7002_dev_t* d, int channel, int32_t freqoffset, unsigned pwr); diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index fa6ff531..f6b670a4 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -1120,11 +1120,14 @@ int dev_m2_lm7_1_sdr_rx_bbfreq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t v } int dev_m2_lm7_1_sdr_tx_bbfreq_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { + if (obj->full_path[0]) { + return lms7002_iterate_ordinal_chans(ud, obj, value, "/dm/sdr/0/tx/frequency/bb", true); + } + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; - unsigned channel = value >> 32; int32_t freq = (int32_t)(value & 0xffffffff); - return xsdr_rfic_bb_set_freq(&d->xdev, channel, true, freq); + return xsdr_rfic_bb_set_freq(&d->xdev, obj->full_path[1], true, freq); } int dev_m2_lm7_1_sdr_rx_gain_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 2866a93f..a3fa7118 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -187,7 +187,7 @@ enum { int xsdr_phy_rx_reg(xsdr_dev_t *d, bool wr, uint8_t bank, uint8_t addr, uint16_t val) { - uint32_t reg = (wr ? 0x80000000 : 0) | (((uint32_t)bank & 0x7f) << 24) | ((uint32_t)addr << 16) | val; + uint32_t reg = (wr ? 0x80000000 : 0) | (((uint32_t)bank & 0x7f) << 24) | ((uint32_t)(addr & 0xff) << 16) | val; return lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, reg); } @@ -1358,6 +1358,7 @@ int xsdr_rfic_set_gain(xsdr_dev_t *d, return lms7002m_set_gain(&d->base, channel, gain_type, gain, actualgain); } + enum { LMS8_TXA_CHIDX = 0, LMS8_TXB_CHIDX = 1, @@ -2232,7 +2233,7 @@ int xsdr_prepare(xsdr_dev_t *d, bool rxen, bool txen) // Calculate power in dbfs -int xsdr_rfe_pwrdc_get(xsdr_dev_t *d, unsigned acc_norm, int prev_gen, unsigned chan_no, int *meas1000db) +int xsdr_rfe_pwrdc_get(xsdr_dev_t *d, unsigned acc_norm, int prev_gen, unsigned chan_no, float corr, int *meas1000db) { int32_t val[2]; int gen, gen_n; @@ -2258,8 +2259,8 @@ int xsdr_rfe_pwrdc_get(xsdr_dev_t *d, unsigned acc_norm, int prev_gen, unsigned double fs_i = val[0]; double fs_q = val[1]; - double i = (0.5 + (fs_i / acc_norm / 65536)) / 2048; // Static correction by +0.5 bits in FPGA - double q = (0.5 + (fs_q / acc_norm / 65536)) / 2048; // Static correction by +0.5 bits in FPGA + double i = (corr + (fs_i / acc_norm / 65536)) / 2048; // Static correction by +0.5 bits in FPGA + double q = (corr + (fs_q / acc_norm / 65536)) / 2048; // Static correction by +0.5 bits in FPGA double pwr_d = i * i + q * q; USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "%d->%d %d %d => %.3f %.3f\n", @@ -2278,10 +2279,12 @@ int xsdr_rfe_pwrdc_get(xsdr_dev_t *d, unsigned acc_norm, int prev_gen, unsigned int xsdrcal_set_nco_offset(void* param, int channel, int32_t freqoffset) { xsdr_dev_t *d = (xsdr_dev_t *)param; - //d->rxdsp_freq_offset = freqoffset; - //return sfe_rf4_nco_freq(d->base.lmsstate.dev, 0, CSR_RFE4_BASE, freqoffset); - //return -EINVAL; - return lms7002m_bb_set_freq(&d->base, channel ? LMS7_CH_B : LMS7_CH_A, false, freqoffset); + int32_t dsp_reg; + int res = 0; + res = res ? res : lms7002m_mac_set(&d->base.lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); + res = res ? res : lms7002m_bb_translate(&d->base, false, freqoffset, &dsp_reg); + res = res ? res : lms7002m_xxtsp_cmix(&d->base.lmsstate, LMS_RXTSP, dsp_reg); + return res; } int xsdr_rxdccorr(xsdr_dev_t *d, uint64_t *ov) @@ -2300,11 +2303,16 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* int res = 0; int meas1000db = 0; int accum = 0, gen = 0; - unsigned acc_idx = 16; + unsigned acc_idx = 1; + float corr = 0.5; if (!func) return 0; + // Fixups + if (d->s_rx_dec == 8) + corr = 0.5; + res = res ? res : xsdr_phy_dc_estim_accum(d, acc_idx); res = res ? res : xsdr_phy_dc_estim_start(d, false); res = res ? res : usleep(1); @@ -2314,7 +2322,7 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* return res; for (unsigned k = 0; k < 8000; k++) { - res = xsdr_rfe_pwrdc_get(d, acc_idx, gen, channel, &meas1000db); + res = xsdr_rfe_pwrdc_get(d, acc_idx, gen, channel, corr, &meas1000db); if (res != -EAGAIN) { accum += meas1000db; break; @@ -2323,7 +2331,7 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* usleep(1000); } - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MEAS[%d] = %.3f\n", channel, meas1000db/1e3); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MEAS[%d] = %.3f DEC=%d CORR=%.f\n", channel, meas1000db/1e3, d->s_rx_dec, corr); *func = accum; return res; @@ -2346,8 +2354,8 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch { ops->adcrate = d->base.cgen_clk / d->base.rxcgen_div; ops->dacrate = d->base.cgen_clk / d->base.txcgen_div; - ops->rxsamplerate = ops->adcrate / d->base.rxtsp_div;// / d->base.rx_dsp_decim; - ops->txsamplerate = ops->dacrate / d->base.txtsp_div;// / d->base.tx_dsp_inter; + ops->rxsamplerate = ops->adcrate / d->base.rxtsp_div / d->base.rx_dsp_decim; + ops->txsamplerate = ops->dacrate / d->base.txtsp_div / d->base.tx_dsp_inter; ops->rxfrequency = d->base.rx_lo; ops->txfrequency = d->base.tx_lo; @@ -2564,8 +2572,14 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "------------------ Calibration TXIQIMB(%c) ------------------\n", 'A' + channel); res = (res) ? res : calibrate_txiqimb(&cops); if (res) { - USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " TXIQIMB failed: res=%d\n", res); - return res; + if (res == -ENAVAIL) { + cops.i = 0; + cops.q = 0; + res = 0; + } else { + USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " TXIQIMB failed: res=%d\n", res); + return res; + } } if (sarray) { sarray[ 2 * 3 + 0] = cops.i; @@ -2593,12 +2607,16 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) // Restore individual PAD attenuation if ((old_dsp_txcfg & 0x1) == 0) { - res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_A); - res = (res) ? res : lms7002m_trf_gain(&d->base.lmsstate, TRF_GAIN_PAD, -10 * tx_loss[0], NULL); + res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_A); + res = res ? res : lms7002m_trf_gain(&d->base.lmsstate, TRF_GAIN_PAD, -10 * tx_loss[0], NULL); + res = res ? res : lms7002m_xxtsp_cmix(&d->base.lmsstate, LMS_TXTSP, d->base.tx_dsp[0].set ? d->base.tx_dsp[0].value : 0); + res = res ? res : lms7002m_xxtsp_cmix(&d->base.lmsstate, LMS_RXTSP, d->base.rx_dsp[0].set ? d->base.rx_dsp[0].value : 0); } if ((old_dsp_txcfg & 0x2) == 0) { - res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_B); - res = (res) ? res : lms7002m_trf_gain(&d->base.lmsstate, TRF_GAIN_PAD, -10 * tx_loss[1], NULL); + res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_B); + res = res ? res : lms7002m_trf_gain(&d->base.lmsstate, TRF_GAIN_PAD, -10 * tx_loss[1], NULL); + res = res ? res : lms7002m_xxtsp_cmix(&d->base.lmsstate, LMS_TXTSP, d->base.tx_dsp[1].set ? d->base.tx_dsp[1].value : 0); + res = res ? res : lms7002m_xxtsp_cmix(&d->base.lmsstate, LMS_RXTSP, d->base.rx_dsp[1].set ? d->base.rx_dsp[1].value : 0); } res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); res = (res) ? res : xsdr_rfic_rfe_set_path(d, old_rx_lna); @@ -2606,8 +2624,10 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) res = (res) ? res : xsdr_tx_antennat_port_cfg(d, old_dsp_txcfg); res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); + res = (res) ? res : lms7002m_update_bandwidth(&d->base, true, d->s_txrate / d->s_tx_int, true); + res = (res) ? res : lms7002m_update_bandwidth(&d->base, false, d->s_rxrate / d->s_rx_dec, true); + restore_rxcfg: - // res = (res) ? res : xsdrcal_do_meas_nco_avg(d, channel, 0, NULL); // res = (res) ? res : xsdr_rfic_streaming_xflags(d, old_dsp_rxcfg, 0); res = (res) ? res : xsdrcal_set_tx_testsig(d, channel, 0, UINT_MAX); From 29580709faa027943959bd94f5a01c601e4adab1 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Tue, 21 Apr 2026 04:27:26 +0400 Subject: [PATCH 380/397] xsdr: improve calibration algo --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 6 ++++-- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index f6b670a4..b9bed9c7 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -966,9 +966,9 @@ int dev_m2_lm7_1_calibrate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; int res; unsigned flags = value & 0xfffff; - unsigned chan = value >> 32; + unsigned chan = 0; - if (flags > 2*65536 || chan > 1) { + if (value > 256*65536) { const char* v = (const char* )value; chan = 0; // TODO B flags = 0; @@ -1004,6 +1004,8 @@ int dev_m2_lm7_1_calibrate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value } else { return -EINVAL; } + } else if (value & 262144) { + chan = 1; } res = xsdr_calibrate(&d->xdev, chan, flags, &d->cal_data[0]); diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index a3fa7118..d08dce10 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -2364,7 +2364,7 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch if (ops->deflogdur > 131072) { ops->deflogdur = 131072; } - ops->defstop = -120000; + ops->defstop = -140000; ops->param = d; // Make very odd fraction not to fall harmonics into the same bins after nyquist @@ -2382,8 +2382,8 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->tximb_iq_corr.max = 2047; ops->tximb_iq_corr.min = -2047; - ops->tximb_ang_corr.max = 2047; - ops->tximb_ang_corr.min = -2047; + ops->tximb_ang_corr.max = 768; // 2047; + ops->tximb_ang_corr.min = -768; // -2047; ops->rxlo_iq_corr.max = 63; ops->rxlo_iq_corr.min = -63; From 5f402526cc9cb2c822dad3445c09adfc7c42b780 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 23 Apr 2026 02:20:59 +0400 Subject: [PATCH 381/397] xsdr: imporve calibration --- src/lib/cal/cal_lo_iqimb.c | 29 ++++++++++-- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 16 +++++-- src/lib/device/m2_lm7_1/m2_lm7_1.c | 15 ++++-- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 63 +++++++++++++++---------- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 4 ++ 5 files changed, 94 insertions(+), 33 deletions(-) diff --git a/src/lib/cal/cal_lo_iqimb.c b/src/lib/cal/cal_lo_iqimb.c index b10f6301..e33728b8 100644 --- a/src/lib/cal/cal_lo_iqimb.c +++ b/src/lib/cal/cal_lo_iqimb.c @@ -139,7 +139,7 @@ int calibrate_txlo(struct calibrate_ops* ops) return res; } -static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, int* opwr) +static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, bool txcal, int* opwr) { int ampl = 128; int pwr_r = -120000; @@ -159,6 +159,26 @@ static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, int* break; } + if (pwr_r < -10000) { + for (unsigned gc = 0; gc < 32; gc++) { + res = ops->set_corr_param(ops->param, ops->channel, + CORR_OP_SET_GAIN | (txcal ? CORR_DIR_RX : CORR_DIR_TX), gc); + if (res == -E2BIG) { + break; // Reached maximum + } else if (res) { + return res; + } + + res = ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_r); + if (res) + return res; + + USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Extra gain %d => %d pwr\n", gc, pwr_r); + if (pwr_r > -10000) + break; + } + } + *opwr = pwr_r; if (pwr_r < -70000) { USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_IQIMB: Signal is too low to perform calibration, giving up!\n"); @@ -169,6 +189,7 @@ static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, int* } int _calibrate_iqimb_generic(struct calibrate_ops* ops, + bool txcal, int32_t freqoffset, int32_t rximoff, int32_t rxreoff, @@ -191,7 +212,8 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_BW, freqoffset * ops->txbw_factor); res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, rxreoff); - res = res ? res : _calibrate_txpwr(ops, freqoffset, &pwr_r); + res = res ? res : _calibrate_txpwr(ops, freqoffset, txcal, &pwr_r); + if (res) return res; @@ -245,7 +267,7 @@ int calibrate_rxiqimb(struct calibrate_ops* ops) if (res) return res; - return _calibrate_iqimb_generic(ops, 0, freqoff, -freqoff, _evaluate_rxaiq); + return _calibrate_iqimb_generic(ops, false, 0, freqoff, -freqoff, _evaluate_rxaiq); } @@ -270,6 +292,7 @@ int calibrate_txiqimb(struct calibrate_ops* ops) return res; return _calibrate_iqimb_generic(ops, + true, rxiqimboff, -freqoff + rxiqimboff, -freqoff - rxiqimboff, diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 5d9c864e..06f0b115 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -1208,7 +1208,15 @@ int lms7002m_set_corr_param(lms7002_dev_t* d, int channel, int corr_type, int va } else { return lms7002m_tbb_bandwidth(d, (unsigned)value, false); } + case CORR_OP_SET_GAIN: + if (rx) { + return -E2BIG; + } else { + if (value > 32) + return -E2BIG; + return lms7002m_tbb_gain(&d->lmsstate, (unsigned)value); + } default: return -EINVAL; } @@ -1221,14 +1229,16 @@ int lms7002m_set_tx_testsig(lms7002_dev_t* d, int channel, int32_t freqoffset, u { int res = 0; int32_t dsp_reg; - + bool switch_to_normal = (pwr == UINT_MAX); res = res ? res : lms7002m_mac_set(&d->lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); res = res ? res : lms7002m_xxtsp_gen(&d->lmsstate, LMS_TXTSP, - (pwr == UINT_MAX) ? XXTSP_NORMAL: XXTSP_DC, + switch_to_normal ? XXTSP_NORMAL: XXTSP_DC, pwr & 0x7fff, pwr & 0x7fff); + if (switch_to_normal) + return res; + res = res ? res : lms7002m_bb_translate(d, true, freqoffset, &dsp_reg); res = res ? res : lms7002m_xxtsp_cmix(&d->lmsstate, LMS_TXTSP, dsp_reg); - return res; } diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index b9bed9c7..e75ffedf 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -1592,9 +1592,18 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha return res; } - res = create_sfetrx4_stream(dev, CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, - flags, M2PCI_REG_WR_TXDMA_CNF_L, M2PCI_REG_WR_SYNC_CTRL, M2PCI_REG_RD_TXDMA_STAT, - 0, 0, &d->tx, &hwchs); + if (d->xdev.exttx) { + // Reset extended core + res = res ? res : xsdr_reset_extfe(&d->xdev); + } + + res = create_sfetrx4_stream(dev, d->xdev.exttx ? CORE_EXFETX_DMA32_R0_2 : CORE_SFETX_DMA32_R0, + dformat, channels->count, &lchans, pktsyms, + flags, + d->xdev.exttx ? M2PCI_REG_WR_TXDMA_CFG0 : M2PCI_REG_WR_TXDMA_CNF_L, + M2PCI_REG_WR_SYNC_CTRL, + M2PCI_REG_RD_TXDMA_STAT, + 0, CSR_TFE4_BASE, &d->tx, &hwchs); if (res) { return res; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index d08dce10..04890dac 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -586,7 +586,9 @@ enum HWID_MSKS { PHY_CFG_TX_MMCM = 0x20, PHY_CFG_RX_MMCM = 0x10, + PHY_EXTENDED_TXFE = 0x08, PHY_CFG_HAS_DUC_DDC = 0x04, + // PHY_CFG_SEP_CLKDIV_MSK duplicates to 0x02 PHY_CFG_SINGLE_MMCM = 0x01, }; @@ -1019,6 +1021,15 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) return res; } +int xsdr_reset_extfe(xsdr_dev_t *d) +{ + lldev_t dev = d->base.lmsstate.dev; + int res = 0; + res = res ? res : dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x4); + res = res ? res : dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x0); + return res; +} + int xsdr_set_samplerate_ex(xsdr_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, @@ -1115,7 +1126,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, if (d->has_duc_ddc && txrate && d->s_tx_int != tx_inr) { // Optional TX DSP reset usleep(10); - dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0xf); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x3); usleep(10); dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x2); usleep(10); @@ -2093,6 +2104,7 @@ int xsdr_init(xsdr_dev_t *d) const bool mmcm_single = ((phycfg_id & PHY_CFG_SINGLE_MMCM) == PHY_CFG_SINGLE_MMCM); const bool sep_clkdiv = ((phycfg_id & PHY_CFG_SEP_CLKDIV_MSK) == PHY_CFG_SEP_CLKDIV_MSK); const bool has_duc_ddc = ((phycfg_id & PHY_CFG_HAS_DUC_DDC) == PHY_CFG_HAS_DUC_DDC); + const bool exttx = ((phycfg_id & PHY_EXTENDED_TXFE) == PHY_EXTENDED_TXFE); d->hwid = hwid; d->hwchans_rx = 2; // Defaults to MIMO; @@ -2111,6 +2123,7 @@ int xsdr_init(xsdr_dev_t *d) d->xilinx_usp = false; d->lms8_mode_b = false; d->has_duc_ddc = has_duc_ddc; + d->exttx = exttx; res = lms7002m_init(&d->base, dev, 0, XSDR_INT_REFCLK); if (res) { @@ -2302,7 +2315,7 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* xsdr_dev_t *d = (xsdr_dev_t *)param; int res = 0; int meas1000db = 0; - int accum = 0, gen = 0; + int accum = -180000, gen = 0; unsigned acc_idx = 1; float corr = 0.5; @@ -2314,25 +2327,26 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* corr = 0.5; res = res ? res : xsdr_phy_dc_estim_accum(d, acc_idx); - res = res ? res : xsdr_phy_dc_estim_start(d, false); - res = res ? res : usleep(1); - res = res ? res : xsdr_phy_dc_estim_start(d, true); - res = res ? res : xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &gen); - if (res) - return res; - for (unsigned k = 0; k < 8000; k++) { - res = xsdr_rfe_pwrdc_get(d, acc_idx, gen, channel, corr, &meas1000db); - if (res != -EAGAIN) { - accum += meas1000db; - break; - } + for (unsigned c = 0; c <= d->meas_cnt; c++) { + res = res ? res : xsdr_phy_dc_estim_start(d, false); + res = res ? res : usleep(1); + res = res ? res : xsdr_phy_dc_estim_start(d, true); + res = res ? res : xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &gen); + if (res) + return res; - usleep(1000); + for (unsigned k = 0; k < 8000; k++) { + res = xsdr_rfe_pwrdc_get(d, acc_idx, gen, channel, corr, &meas1000db); + if (res != -EAGAIN) { + accum = MAX(accum, meas1000db); + break; + } + usleep(500); + } + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MEAS[%d] = %.3f DEC=%d CORR=%.f\n", channel, meas1000db/1e3, d->s_rx_dec, corr); } - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MEAS[%d] = %.3f DEC=%d CORR=%.f\n", channel, meas1000db/1e3, d->s_rx_dec, corr); - *func = accum; return res; } @@ -2462,25 +2476,24 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) uint8_t old_rx_lna = d->base.rx_rfic_path; uint8_t old_tx_lna = d->base.tx_rfic_path; uint8_t tx_loss[2] = { d->base.tx_loss[0] , d->base.tx_loss[1] }; + uint8_t gc_corr[2] = { d->base.lmsstate.reg_tbb_gc_corr[0], d->base.lmsstate.reg_tbb_gc_corr[1] }; lldev_t dev = d->base.lmsstate.dev; if (channel > 1) { return -EINVAL; } - //int32_t old_rxdsp_freqoff = d->rxdsp_freq_offset; unsigned tx_lo = d->base.tx_lo; unsigned rx_lo = d->base.rx_lo; unsigned rx_rfic_lna = d->base.lmsstate.rfe[channel].path; unsigned tx_rfic_band = d->base.lmsstate.trf[channel].path; - // TODO: txdsp != 0 || rxdsp != 0 makes incorrect calibration + d->meas_cnt = 1; //One extra measurement for stability if (sarray) { memset(sarray, 0, sizeof(int) * 8); } res = (res) ? res : xsdrcal_init_calibrate(d, &cops, channel); - // res = (res) ? res : xsdr_rfic_streaming_xflags(d, channel == 1 ? RFIC_SWAP_AB : 0, 0); res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); if (res) return res; @@ -2528,10 +2541,10 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) res = (res) ? res : calibrate_rxiqimb(&cops); if (tx_lo) { - res = (res) ? res : lms7002m_sxx_tune(&d->base.lmsstate, SXX_RX, d->base.fref, tx_lo, false); + res = (res) ? res : lms7002m_sxx_tune(&d->base.lmsstate, SXX_TX, d->base.fref, tx_lo, false); } else { // Looks like TX was off, turn it off - res = (res) ? res : lms7002m_sxx_disable(&d->base.lmsstate, SXX_RX); + res = (res) ? res : lms7002m_sxx_disable(&d->base.lmsstate, SXX_TX); } if (res) { USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " RXIQIMB failed: res=%d\n", res); @@ -2551,6 +2564,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) // No RBB[0] was set; defaulting to current rx samplerate 1000000 ///////////////////////////////////////////////////////////////////////////////// HACK!!!!!!!!!!!!!!!!! res = (res) ? res : lms7002m_rbb_bandwidth(&d->base, 1000000, false); + res = res ? res : usleep(750000); // Since RX wasn't active we need time to bring power } if (res) return res; @@ -2623,12 +2637,13 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) res = (res) ? res : xsdr_rfic_tfe_set_path(d, old_tx_lna); res = (res) ? res : xsdr_tx_antennat_port_cfg(d, old_dsp_txcfg); res = (res) ? res : lms7002m_mac_set(&d->base.lmsstate, channel == 0 ? LMS7_CH_A : LMS7_CH_B); - + if (gc_corr[channel] != d->base.lmsstate.reg_tbb_gc_corr[channel]) { + res = (res) ? res : lms7002m_tbb_gain(&d->base.lmsstate, gc_corr[channel]); + } res = (res) ? res : lms7002m_update_bandwidth(&d->base, true, d->s_txrate / d->s_tx_int, true); res = (res) ? res : lms7002m_update_bandwidth(&d->base, false, d->s_rxrate / d->s_rx_dec, true); restore_rxcfg: - // res = (res) ? res : xsdr_rfic_streaming_xflags(d, old_dsp_rxcfg, 0); res = (res) ? res : xsdrcal_set_tx_testsig(d, channel, 0, UINT_MAX); return res; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index ea9890cf..07d34db3 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -93,6 +93,7 @@ struct xsdr_dev bool lms8_mode_b; bool xilinx_usp; bool has_duc_ddc; + bool exttx; bool dpump; //Dual pump data union { @@ -114,6 +115,7 @@ struct xsdr_dev uint32_t lms8st_int_mod; uint32_t lms8st_enabled; + uint8_t meas_cnt; // Statistics double actual_rx_freq; double actual_tx_freq; @@ -255,6 +257,8 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) int xsdr_trspi_lms8(xsdr_dev_t *d, uint32_t out, uint32_t* in); +int xsdr_reset_extfe(xsdr_dev_t *d); + #ifndef NO_IGPO enum { From 33e22493dfc3a54d5c31b9ae9be8f85621dbba50 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 24 Apr 2026 23:29:31 +0400 Subject: [PATCH 382/397] xsdr: fix SISO / MIMO LML configuration --- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 15 ++-- src/lib/device/m2_lm7_1/lms7002m_ctrl.h | 12 +-- src/lib/device/m2_lm7_1/m2_lm7_1.c | 2 +- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 97 +++++++++--------------- src/lib/device/u3_limesdr/limesdr_ctrl.c | 2 +- src/lib/hw/lms7002m/lms7002m.c | 44 +++++++---- src/lib/hw/lms7002m/lms7002m.h | 2 +- 7 files changed, 80 insertions(+), 94 deletions(-) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 06f0b115..fc1fa61b 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -655,10 +655,9 @@ int lms7002m_streaming_down(lms7002_dev_t *d, unsigned dir) } -static lms7002m_mac_mode_t _corr_ch(lms7002m_mac_mode_t mode, - unsigned flags) +static lms7002m_mac_mode_t _corr_ch(lms7002m_mac_mode_t mode, unsigned flags, bool siso) { - if (((mode == LMS7_CH_AB) && (flags & RFIC_SISO_MODE)) && (!(flags & RFIC_SISO_SWITCH))) { + if (((mode == LMS7_CH_AB) && siso)) { if (flags & RFIC_SWAP_AB) { mode = LMS7_CH_B; } else { @@ -686,11 +685,11 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, if (_lms7002m_check_chan(rx_chs_i)) { return -EINVAL; } - rx_chs = _corr_ch(rx_chs_i, rx_flags); + rx_chs = _corr_ch(rx_chs_i, rx_flags, d->rx_siso); //d->chprx = params->rx; d->lml_rx_chs = rx_chs; d->lml_rx_flags = rx_flags; - d->map_rx = d->on_get_lml_portcfg(true, d->lml_rx_chs, d->lml_rx_flags, false /* d->rx_no_siso_map */); + d->map_rx = d->on_get_lml_portcfg(true, d->lml_rx_chs, d->lml_rx_flags); rxafen_a = rx_chs != LMS7_CH_B; rxafen_b = rx_chs != LMS7_CH_A; @@ -699,17 +698,19 @@ int lms7002m_streaming_up(lms7002_dev_t *d, unsigned dir, if (_lms7002m_check_chan(tx_chs_i)) { return -EINVAL; } - tx_chs = _corr_ch(tx_chs_i, tx_flags); + tx_chs = _corr_ch(tx_chs_i, tx_flags, d->tx_siso); //d->chptx = params->tx; d->lml_tx_chs = tx_chs; d->lml_tx_flags = tx_flags; - d->map_tx = d->on_get_lml_portcfg(false, d->lml_tx_chs, d->lml_tx_flags, false /* d->tx_no_siso_map */); + d->map_tx = d->on_get_lml_portcfg(false, d->lml_tx_chs, d->lml_tx_flags); txafen_a = tx_chs != LMS7_CH_B; txafen_b = tx_chs != LMS7_CH_A; } res = lms7002m_limelight_map(&d->lmsstate, + d->lml_mode.rx_port == 1 ? d->rx_siso : d->tx_siso, + d->lml_mode.rx_port == 1 ? d->tx_siso : d->rx_siso, d->lml_mode.rx_port == 1 ? d->map_rx : d->map_tx, d->lml_mode.rx_port == 1 ? d->map_tx : d->map_rx); if (res) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h index 60473fc6..740cb876 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.h +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.h @@ -72,7 +72,7 @@ enum sigtype { typedef int (*on_change_signal_t)(lms7002_dev_t *d, enum sigtype t); typedef int (*on_change_antenna_port_sw_t)(lms7002_dev_t* dev, int direction, unsigned sw); -typedef const lms7002m_lml_map_t (*on_get_lml_portcfg_t)(bool rx, unsigned chs, unsigned flags, bool no_siso_map); +typedef const lms7002m_lml_map_t (*on_get_lml_portcfg_t)(bool rx, unsigned chs, unsigned flags); struct lms7002_dev { @@ -97,8 +97,8 @@ struct lms7002_dev uint8_t rxtsp_div; uint8_t txtsp_div; - uint8_t rx_no_siso_map; - uint8_t tx_no_siso_map; + uint8_t rx_siso; + uint8_t tx_siso; uint16_t tx_dsp_inter; uint16_t rx_dsp_decim; @@ -185,12 +185,6 @@ int lms7002m_streaming_down(lms7002_dev_t *d, unsigned dir); enum rfic_chan_flags { RFIC_SWAP_AB = BIT(0), RFIC_SWAP_IQ = BIT(1), - RFIC_SISO_MODE = BIT(2), - RFIC_SISO_SWITCH = BIT(3), - - // Test flags - RFIC_SWAP_IQB = BIT(16), - RFIC_SWAP_IQA = BIT(15), RFIC_LFSR = BIT(12), RFIC_DIGITAL_LB = BIT(11), diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index e75ffedf..95360ecd 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -1597,7 +1597,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha res = res ? res : xsdr_reset_extfe(&d->xdev); } - res = create_sfetrx4_stream(dev, d->xdev.exttx ? CORE_EXFETX_DMA32_R0_2 : CORE_SFETX_DMA32_R0, + res = res ? res : create_sfetrx4_stream(dev, d->xdev.exttx ? CORE_EXFETX_DMA32_R0_2 : CORE_SFETX_DMA32_R0, dformat, channels->count, &lchans, pktsyms, flags, d->xdev.exttx ? M2PCI_REG_WR_TXDMA_CFG0 : M2PCI_REG_WR_TXDMA_CNF_L, diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 04890dac..7e58a0c2 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -317,10 +317,12 @@ static int _xsdr_rxserdes_reset(xsdr_dev_t *d) { static int _xsdr_txserdes_reset(xsdr_dev_t *d) { int res = 0; + unsigned sisosdrflag = d->dpump ? 16 : d->base.lml_mode.txsisoddr ? 16 : 0; + // Reset OSERDESE2 - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 0 | sisosdrflag); res = res ? res : usleep(1); - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_CTRL, 1 | sisosdrflag); return res; } @@ -469,6 +471,13 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, cfg_raw.ports[CLKOUT_PORT_6].period_l = (vco_div_io + 1) / 2; // FCLK_TX cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io / 2; // FCLK_TX + if (d->dpump) { + cfg_raw.ports[CLKOUT_PORT_5].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_5].period_h = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_6].period_l = vco_div_io; + cfg_raw.ports[CLKOUT_PORT_6].period_h = vco_div_io; + } + unsigned total_budget = 8 * vco_div_io; unsigned phase = total_budget / 2; // Default 90deg F_CLK related to clocks @@ -521,7 +530,7 @@ int xsdr_configure_lml_mmcm_tx(xsdr_dev_t *d, bool rx_master, unsigned rxphase, res = res ? res : mmcm_init_raw(d->base.lmsstate.dev, d->base.lmsstate.subdev, DRP_MMCM_PORT_TX, &cfg_raw); // Set IQSEL vector - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : 0b1100); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, (!d->dpump && d->base.lml_mode.txsisoddr) ? 0b1010 : 0b1100); // Reset MMCM // res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_MMCM_CTRL, mmcm_ctrl_sel | 1); @@ -602,10 +611,17 @@ static bool noerrors_v4(unsigned errs[4], uint64_t* badness) static bool noerrors_v2(unsigned errs[4], uint64_t* badness) { +#if 1 if (badness) { *badness = (errs[0]*errs[0]) + (errs[1]*errs[1]); } return errs[0] == 0 && errs[1] == 0; +#else + if (badness) { + *badness = (errs[0]*errs[0]) + (errs[2]*errs[2]); + } + return errs[0] == 0 && errs[2] == 0; +#endif } int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v) @@ -640,7 +656,7 @@ static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, res = res ? res : usleep(100); res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); res = res ? res : xsdr_phy_lfsr_mimo_state_s(d, LFSR_CNTR_IQS << 2, piqserrs); - if (res || (!noerrors_v4(errs, pbadness)) || *piqserrs) { + if (res || (d->dpump ? !noerrors_v2(errs, pbadness) : !noerrors_v4(errs, pbadness)) || *piqserrs) { break; } } @@ -885,7 +901,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e\n", ph - 1, errs[0], errs[1], errs[2], errs[3], iqserrs, (double)badness); - if (res || (noerrors_v4(errs, &badness) /* && (iqserrs == 0)*/) || (rty > 1 && badness < 20)) { + if (res || (d->dpump ? noerrors_v2(errs, &badness) : noerrors_v4(errs, &badness) /* && (iqserrs == 0)*/) || (rty > 1 && badness < 20)) { phase_m = ph; for (int g = 0; g < 24; g++) { @@ -901,7 +917,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if ((rty == 0 && iqserrs != 0) || iqserrs > 40) { USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX[%d]=%2d ABIQ=%d\n", g, ph - 1, iqserrs); unsigned msk[4] = { 0b1100, 0b0110, 0b0011, 0b1001 }; - res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, d->base.lml_mode.txsisoddr ? 0b1010 : msk[(g + 1) % 4]); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_PORT_IQSEL, (!d->dpump && d->base.lml_mode.txsisoddr) ? 0b1010 : msk[(g + 1) % 4]); //res = res ? res : _xsdr_txserdes_reset(d); res = res ? res : usleep(10); res = res ? res : lms7002m_limelight_reset(&d->base.lmsstate); @@ -1237,52 +1253,22 @@ int _xsdr_antenna_port_switch(lms7002_dev_t *d, int dir, unsigned path) return -EINVAL; } - - -////////////////////////////////////////////////////////////////////////////// - static bool _xsdr_run_params_stream_is_swap(unsigned chs, unsigned flags) { return (chs == LMS7_CH_AB && (flags & RFIC_SWAP_AB)) || - chs == LMS7_CH_A; -} -static bool _xsdr_run_params_stream_is_mimo(unsigned chs, unsigned flags) -{ - return (chs == LMS7_CH_AB && !(flags & RFIC_SISO_MODE)); + chs == LMS7_CH_B; } static -const lms7002m_lml_map_t lms7nfe_get_lml_portcfg(bool rx, unsigned chs, unsigned flags, bool no_siso_map) +const lms7002m_lml_map_t lms7nfe_get_lml_portcfg(bool rx, unsigned chs, unsigned flags) { - static const lms7002m_lml_map_t diqarray_rx[] = { - // MIMO modes + static const lms7002m_lml_map_t diqarray[] = { {{ LML_AI, LML_AQ, LML_BI, LML_BQ }}, {{ LML_AQ, LML_AI, LML_BQ, LML_BI }}, {{ LML_BI, LML_BQ, LML_AI, LML_AQ }}, {{ LML_BQ, LML_BI, LML_AQ, LML_AI }}, - - // SISO modes - {{ LML_AI, LML_AQ, LML_AI, LML_AQ }}, - {{ LML_AQ, LML_AI, LML_AQ, LML_AI }}, - {{ LML_BI, LML_BQ, LML_BI, LML_BQ }}, - {{ LML_BQ, LML_BI, LML_BQ, LML_BI }}, - }; - - static const lms7002m_lml_map_t diqarray_tx[] = { - {{ LML_AQ, LML_AI, LML_BQ, LML_BI }}, - {{ LML_AI, LML_AQ, LML_BI, LML_BQ }}, - {{ LML_BQ, LML_BI, LML_AQ, LML_AI }}, - {{ LML_BI, LML_BQ, LML_AI, LML_AQ }}, - - // SISO modes - {{ LML_AQ, LML_AI, LML_AQ, LML_AI }}, - {{ LML_AI, LML_AQ, LML_AI, LML_AQ }}, - {{ LML_BQ, LML_BI, LML_BQ, LML_BI }}, - {{ LML_BI, LML_BQ, LML_BI, LML_BQ }}, - }; - const lms7002m_lml_map_t *diqarray = (rx) ? diqarray_rx : diqarray_tx;; unsigned diqidx = 0; if (flags & RFIC_SWAP_IQ) diqidx |= 1; @@ -1290,11 +1276,7 @@ const lms7002m_lml_map_t lms7nfe_get_lml_portcfg(bool rx, unsigned chs, unsigned if (_xsdr_run_params_stream_is_swap(chs, flags)) diqidx |= 2; - if (!no_siso_map && !_xsdr_run_params_stream_is_mimo(chs, flags)) - diqidx |= 4; - USDR_LOG("XDEV", USDR_LOG_WARNING, "%s_diqidx=%d\n", rx ? "rx" : "tx", diqidx); - assert(diqidx < 8); return diqarray[diqidx]; } @@ -1302,25 +1284,16 @@ int xsdr_rfic_streaming_xflags(xsdr_dev_t *d, unsigned xor_rx_flags, unsigned xor_tx_flags) { - int res; - unsigned rxf = (d->hwchans_rx == 1) ? RFIC_SISO_MODE : 0; - unsigned txf = (d->hwchans_tx == 1) ? RFIC_SISO_MODE : 0; - + d->base.rx_siso = (d->hwchans_rx == 1 || d->dpump); + d->base.tx_siso = (d->hwchans_tx == 1 || d->dpump); d->dsp_rxcfg = xor_rx_flags; - d->base.map_rx = lms7nfe_get_lml_portcfg(true, d->base.lml_rx_chs, rxf | (d->base.lml_rx_flags ^ d->dsp_rxcfg), d->base.rx_no_siso_map); - d->base.map_tx = lms7nfe_get_lml_portcfg(false, d->base.lml_tx_chs, txf | (d->base.lml_tx_flags ^ xor_tx_flags), d->base.tx_no_siso_map); - res = lms7002m_limelight_map(&d->base.lmsstate, - d->base.lml_mode.rx_port == 1 ? d->base.map_rx : d->base.map_tx, - d->base.lml_mode.rx_port == 1 ? d->base.map_tx : d->base.map_rx); - if (res) - return res; - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // res = lms7002m_limelight_configure(&d->base.lmsstate, d->base.lml_mode); - // if (res) - // return res; - - return 0; + d->base.map_rx = lms7nfe_get_lml_portcfg(true, d->base.lml_rx_chs, (d->base.lml_rx_flags ^ d->dsp_rxcfg)); + d->base.map_tx = lms7nfe_get_lml_portcfg(false, d->base.lml_tx_chs, (d->base.lml_tx_flags ^ xor_tx_flags)); + return lms7002m_limelight_map(&d->base.lmsstate, + d->base.lml_mode.rx_port == 1 ? d->base.rx_siso : d->base.tx_siso, + d->base.lml_mode.rx_port == 1 ? d->base.tx_siso : d->base.rx_siso, + d->base.lml_mode.rx_port == 1 ? d->base.map_rx : d->base.map_tx, + d->base.lml_mode.rx_port == 1 ? d->base.map_tx : d->base.map_rx); } int xsdr_rfic_streaming_up(xsdr_dev_t *d, unsigned dir, @@ -1495,7 +1468,7 @@ int xsdr_rfic_fe_set_freq(xsdr_dev_t *d, } // LO correction - res = res ? res : lms7002m_dc_corr_en(&d->base.lmsstate, d->base.rx_run[0], d->base.rx_run[1], d->base.tx_run[0], d->base.tx_run[1]); + // res = res ? res : lms7002m_dc_corr_en(&d->base.lmsstate, d->base.rx_run[0], d->base.rx_run[1], d->base.tx_run[0], d->base.tx_run[1]); return res; } diff --git a/src/lib/device/u3_limesdr/limesdr_ctrl.c b/src/lib/device/u3_limesdr/limesdr_ctrl.c index a52a0f48..b8776297 100644 --- a/src/lib/device/u3_limesdr/limesdr_ctrl.c +++ b/src/lib/device/u3_limesdr/limesdr_ctrl.c @@ -62,7 +62,7 @@ enum { static -const lms7002m_lml_map_t _limesdr_lml_portcfg(bool UNUSED rx, unsigned UNUSED chs, unsigned UNUSED flags, bool UNUSED no_siso_map) +const lms7002m_lml_map_t _limesdr_lml_portcfg(bool UNUSED rx, unsigned UNUSED chs, unsigned UNUSED flags) { // During SISO DDR mode only 0 and 1 make sense static const lms7002m_lml_map_t diqarray[] = { diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index a706088f..dff0861d 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -531,31 +531,49 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t -int _lms7002m_fill_pos(lms7002m_lml_map_t l, lms7002m_lml_map_t* o) +int _lms7002m_fill_pos(lms7002m_lml_map_t l, bool siso, lms7002m_lml_map_t* o) { lms7002m_lml_map_t p = {{0, 0, 0, 0}}; - for (unsigned i = 0; i < 4; i++) { - switch (l.m[i]) { - case LML_0X0024_LML1_S0S_AI: p.m[LML_AI] = i; break; - case LML_0X0024_LML1_S0S_AQ: p.m[LML_AQ] = i; break; - case LML_0X0024_LML1_S0S_BI: p.m[LML_BI] = i; break; - case LML_0X0024_LML1_S0S_BQ: p.m[LML_BQ] = i; break; - default: - return -EINVAL; + if (siso) { + for (unsigned i = 0; i < 2; i++) { + switch (l.m[i]) { + case LML_0X0024_LML1_S0S_AI: + case LML_0X0024_LML1_S0S_BI: + p.m[LML_AI] = i; + p.m[LML_BI] = i; + break; + case LML_0X0024_LML1_S0S_AQ: + case LML_0X0024_LML1_S0S_BQ: + p.m[LML_AQ] = i; + p.m[LML_BQ] = i; + break; + default: + return -EINVAL; + } + } + } else { + for (unsigned i = 0; i < 4; i++) { + switch (l.m[i]) { + case LML_0X0024_LML1_S0S_AI: p.m[LML_AI] = i; break; + case LML_0X0024_LML1_S0S_AQ: p.m[LML_AQ] = i; break; + case LML_0X0024_LML1_S0S_BI: p.m[LML_BI] = i; break; + case LML_0X0024_LML1_S0S_BQ: p.m[LML_BQ] = i; break; + default: + return -EINVAL; + } } } - *o = p; return 0; } -int lms7002m_limelight_map(lms7002m_state_t* m, lms7002m_lml_map_t l1m, lms7002m_lml_map_t l2m) +int lms7002m_limelight_map(lms7002m_state_t* m, bool sisol1m, bool sisol2m, lms7002m_lml_map_t l1m, lms7002m_lml_map_t l2m) { lms7002m_lml_map_t l1p, l2p; int res = 0; - res = res ? res : _lms7002m_fill_pos(l1m, &l1p); - res = res ? res : _lms7002m_fill_pos(l2m, &l2p); + res = res ? res : _lms7002m_fill_pos(l1m, sisol1m, &l1p); + res = res ? res : _lms7002m_fill_pos(l2m, sisol2m, &l2p); if (res) return res; diff --git a/src/lib/hw/lms7002m/lms7002m.h b/src/lib/hw/lms7002m/lms7002m.h index 1d0716d5..e14813ed 100644 --- a/src/lib/hw/lms7002m/lms7002m.h +++ b/src/lib/hw/lms7002m/lms7002m.h @@ -119,7 +119,7 @@ struct lms7002m_limelight_conf { typedef struct lms7002m_limelight_conf lms7002m_limelight_conf_t; int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t params); -int lms7002m_limelight_map(lms7002m_state_t* m, lms7002m_lml_map_t l1m, lms7002m_lml_map_t l2m); +int lms7002m_limelight_map(lms7002m_state_t* m, bool sisol1m, bool sisol2m, lms7002m_lml_map_t l1m, lms7002m_lml_map_t l2m); // CGEN int lms7002m_cgen_disable(lms7002m_state_t* m); From fc7d26c180ee59cb7b44a0a610460504b13b09f8 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 24 Apr 2026 23:30:00 +0400 Subject: [PATCH 383/397] soapy: add "calibrate" settings --- src/soapysdr/usdr_soapy.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/soapysdr/usdr_soapy.cpp b/src/soapysdr/usdr_soapy.cpp index 7d816875..0bbad858 100644 --- a/src/soapysdr/usdr_soapy.cpp +++ b/src/soapysdr/usdr_soapy.cpp @@ -1022,6 +1022,13 @@ void SoapyUSDR::writeSetting(const std::string &key, const std::string &value) { SoapySDR::logf(callLogLvl(), "SoapyUSDR::writeSetting(%s, %s)", key.c_str(), value.c_str()); + if (key == "calibrate") { + int res = usdr_dme_set_uint(_dev->dev(), "/dm/sdr/0/calibrate", (uintptr_t)value.c_str()); + if (res) { + throw std::invalid_argument("SoapyUSDR::writeSetting("+key+") failed"); + } + } + throw std::runtime_error("unknown setting key: " + key); } From 8bd3345fc19ca5fa0a8b52cec822d3f595841de1 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 25 Apr 2026 02:02:05 +0400 Subject: [PATCH 384/397] xsdr: improve DAC performance --- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 19 ++++++++++++------- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 17 ----------------- src/lib/hw/lms7002m/lms7002m.c | 4 ++-- src/lib/hw/lms7002m/lms7002m.h | 3 +++ 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index fc1fa61b..390462dd 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -934,6 +934,7 @@ int lms7002m_samplerate(lms7002_dev_t *d, unsigned mindecint_tx = (sisoddr_tx || extclk_tx) ? 1 : 2; unsigned cgen_max = extended_cgen_range && (citer == 0) ? 370e6 : 320e6; cgen_rate = MAX(txmaster_min, rxmaster_min); + mpy_dac = 4; // Might be 4,2,1 if (cgen_rate < 1) { cgen_rate = MAX(mindecint_rx * rxrate * rx_host_div * mpy_adc, @@ -961,6 +962,13 @@ int lms7002m_samplerate(lms7002_dev_t *d, } if (txrate > 1) { txdiv = (cgen_rate / (txrate * tx_host_mul)) / mpy_dac; + if (txdiv <= 8) { + txdiv *= 4; + mpy_dac /= 4; + } else if (txdiv <= 8) { + txdiv *= 2; + mpy_dac /= 2; + } } if (rxrate > 1 && !_check_lime_decimation(rxdiv)) { @@ -1011,11 +1019,11 @@ int lms7002m_samplerate(lms7002_dev_t *d, unsigned rxtsp_div = 1; if (rxrate > 0) { - rxtsp_div = (sisoddr_rx /*|| extclk_rx*/) ? rxdiv : (((rxdiv > 1) ? (rxdiv / 2) : 1)); + rxtsp_div = (sisoddr_rx) ? rxdiv : (((rxdiv > 1) ? (rxdiv / 2) : 1)); } unsigned txtsp_div = 1; if (txrate > 1) { - txtsp_div = (sisoddr_tx /*|| extclk_tx*/) ? txdiv : (((txdiv > 1) ? (txdiv / 2) : 1)); + txtsp_div = (sisoddr_tx) ? txdiv : (((txdiv > 1) ? (txdiv / 2) : 1)); } if (((rxrate > 40e6) || (txrate > 40e6))) { @@ -1050,16 +1058,13 @@ int lms7002m_samplerate(lms7002_dev_t *d, cfg.rxdiv = rxtsp_div; cfg.rxsisoddr = sisoddr_rx; cfg.txsisoddr = sisoddr_tx; + cfg.txtspdelay = (txrate < 45e6) ? 3 : (txrate < 99e6) ? 1 : 0; + cfg.txlmldelay = (txrate < 45e6) ? 0 : (txrate < 99e6) ? 3 : 0; res = lms7002m_limelight_configure(&d->lmsstate, cfg); if (res) return res; - // Set ADS for bypass mode - // res = lms7002m_cds_set(&d->lmsstate, rxtsp_div == 1, rxtsp_div == 1); - // if (res) - // return res; - d->lml_mode = cfg; USDR_LL_LOG(d->lmsstate.dev, "XDEV", USDR_LOG_INFO, "rxrate=%.3fMHz txrate=%.3fMHz" " rxdecim=%d(h_%d) txinterp=%d(h_%d)" diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 7e58a0c2..7cce1e59 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -611,17 +611,10 @@ static bool noerrors_v4(unsigned errs[4], uint64_t* badness) static bool noerrors_v2(unsigned errs[4], uint64_t* badness) { -#if 1 if (badness) { *badness = (errs[0]*errs[0]) + (errs[1]*errs[1]); } return errs[0] == 0 && errs[1] == 0; -#else - if (badness) { - *badness = (errs[0]*errs[0]) + (errs[2]*errs[2]); - } - return errs[0] == 0 && errs[2] == 0; -#endif } int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v) @@ -680,16 +673,6 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) g_clk_reduce = 0; - // Fixup for SSDR_PRO -#if 0 - if (d->ssdr_pro) { - // RX SISO DDR - res = res ? res : lowlevel_reg_wr32(d->base.lmsstate.dev, d->base.lmsstate.subdev, REG_CFG_PHY_0, - d->siso_sdr_active_rx ? (1u << 9) : 0); - return res; - } -#endif - if (d->mmcm_tx) { if (!d->ssdr_pro) { // Boost IO voltage for stable high speed link diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index dff0861d..5e04f171 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -520,8 +520,8 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t (params.txdiv > 1) ? 1u : 0, (params.rxdiv > 1) ? 1u : 0), MAKE_LMS7002M_LML_0x002C( params.txdiv / 2u - 1u, params.rxdiv / 2u - 1u ), - MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 1, 1, 1, params.rxsisoddr && params.rxdiv == 1 ? 0 : 1, 1, 1), - MAKE_LMS7002M_CDS_0x00AE(3, 3, 0, 0, 0, 0, 0, 0), + MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 1, params.txsisoddr && params.txdiv == 1 ? 0 : 1, 1, params.rxsisoddr && params.rxdiv == 1 ? 0 : 1, 1, 1), + MAKE_LMS7002M_CDS_0x00AE(params.txtspdelay, params.txtspdelay, 0, 0, params.txlmldelay, params.txlmldelay, 0, 0), MAKE_LMS7002M_REG_WR(LML_0x0020, reg_mac), MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac) }; diff --git a/src/lib/hw/lms7002m/lms7002m.h b/src/lib/hw/lms7002m/lms7002m.h index e14813ed..a5a154cd 100644 --- a/src/lib/hw/lms7002m/lms7002m.h +++ b/src/lib/hw/lms7002m/lms7002m.h @@ -115,6 +115,9 @@ struct lms7002m_limelight_conf { uint8_t rxdiv; uint8_t txdiv; + + uint8_t txtspdelay; + uint8_t txlmldelay; }; typedef struct lms7002m_limelight_conf lms7002m_limelight_conf_t; From 4378510d265df4361c0f5f3216469b8b3deb80c6 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 25 Apr 2026 02:24:22 +0400 Subject: [PATCH 385/397] xsdr: deprecate bifurcation mode --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 22 +--------------------- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 8 -------- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 95360ecd..382e773d 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -449,7 +449,7 @@ struct dev_m2_lm7_1_gps { struct xsdr_dev xdev; struct dev_fe* fe; - bool bifurcation_en; + bool nodecint; bool double_pump; @@ -1041,7 +1041,6 @@ int dev_m2_lm7_1_rate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) //Simple SISO RX only return xsdr_set_samplerate_ex(&d->xdev, (unsigned)value, (unsigned)value, 0, 0, - (d->bifurcation_en) ? (XSDR_LML_SISO_DDR_RX | XSDR_LML_SISO_DDR_TX) : 0 | (d->nodecint ? 0 : XSDR_SR_MAXCONVRATE) | XSDR_SR_EXTENDED_CGEN); } @@ -1066,7 +1065,6 @@ int dev_m2_lm7_1_rate_m_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return -ERANGE; return xsdr_set_samplerate_ex(&d->xdev, rx_rate, tx_rate, adc_rate, dac_rate, - (d->bifurcation_en) ? (XSDR_LML_SISO_DDR_RX | XSDR_LML_SISO_DDR_TX) : 0 | (d->nodecint ? 0 : XSDR_SR_MAXCONVRATE) | XSDR_SR_EXTENDED_CGEN); } @@ -1389,7 +1387,6 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* int res; const char* fe = NULL; - d->bifurcation_en = false; d->nodecint = false; d->double_pump = false; @@ -1397,9 +1394,6 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* if (strcmp(devparam[i], "fe") == 0) { fe = devval[i]; } - if (strcmp(devparam[i], "bifurcation") == 0) { - d->bifurcation_en = (devval[i]) ? atoi(devval[i]) : 1; - } if (strcmp(devparam[i], "nodec") == 0) { d->nodecint = true; } @@ -1525,13 +1519,6 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha return res; } - // Disable bifurcation for now, since calibration NCO loop doesn't support it - if (rxcfg.bifurcation_valid && d->bifurcation_en) { - d->xdev.siso_sdr_active_rx = true; - flags |= DMS_FLAG_BIFURCATION; - // TODO: update samplerate settings - } - if (d->double_pump) { d->xdev.siso_sdr_active_rx = true; } @@ -1576,13 +1563,6 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha return res; } - // Add bifurcation flag - if (txcfg.bifurcation_valid && d->bifurcation_en) { - d->xdev.siso_sdr_active_tx = true; - flags |= DMS_FLAG_BIFURCATION; - // TODO: update samplerate settings - } - if (d->double_pump) { d->xdev.siso_sdr_active_tx = true; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 7cce1e59..22055bd7 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1102,13 +1102,6 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : _xsdr_calibrate_lml(d); - // if (rxrate) { - // if (!d->ssdr_pro) { - // // Switch to clock meas - // res = res ? res : lowlevel_reg_wr32(dev, subdev, REG_CFG_PHY_0, 0x02000000); - // } - // } - if (d->has_duc_ddc && rxrate && d->s_rx_dec != rx_dec) { // Optional RX DSP reset dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0xf); @@ -1136,7 +1129,6 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, d->s_tx_int = tx_inr; } - // lms7002m_rxtsp_dc_corr(&d->base.lmsstate, true, 0); /* int32_t a, b; int32_t q[4]; From 669b2b37d19789b14596063b906b7c66febca5ac Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 25 Apr 2026 04:11:49 +0400 Subject: [PATCH 386/397] xsdr: switch LML LFSR mode wihout interface reset --- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 3 ++- src/lib/hw/lms7002m/lms7002m.c | 18 ++++++++++++++++++ src/lib/hw/lms7002m/lms7002m.h | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 390462dd..8fa7b929 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -1152,7 +1152,8 @@ int lms7002m_set_lmlrx_mode(lms7002_dev_t *d, unsigned mode) break; } - return lms7002m_limelight_configure(&d->lmsstate, d->lml_mode); + //return lms7002m_limelight_configure(&d->lmsstate, d->lml_mode); + return lms7002m_limelight_switch_rx_mode(&d->lmsstate, d->lml_mode); } diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index 5e04f171..e96e8f3d 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -467,6 +467,24 @@ int lms7002m_limelight_toggle_ntx(lms7002m_state_t* m) return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); } +int lms7002m_limelight_switch_rx_mode(lms7002m_state_t* m, lms7002m_limelight_conf_t params) +{ + unsigned rxmux = params.rx_lfsr ? LML_0X002A_RX_MUX_LFSR : + params.rx_tx_dig_loopback ? LML_0X002A_RX_MUX_TXFIFO : LML_0X002A_RX_MUX_RXTSP; + unsigned rdclk = (params.rx_ext_rd_fclk /* || params.rx_tx_dig_loopback */ ) ? + ((params.rx_port) ? LML_0X002A_RXRDCLK_MUX_FCLK1 : LML_0X002A_RXRDCLK_MUX_FCLK2) : + ((params.rx_port) ? LML_0X002A_RXRDCLK_MUX_MCLK1 : LML_0X002A_RXRDCLK_MUX_MCLK2); + uint32_t regs[] = { + MAKE_LMS7002M_LML_0x002A(rxmux, + params.rx_port ? LML_0X002A_TX_MUX_PORT2 : LML_0X002A_TX_MUX_PORT1, + LML_0X002A_TXRDCLK_MUX_TXTSPCLK, + params.rx_port ? LML_0X002A_TXWRCLK_MUX_FCLK2 : LML_0X002A_TXWRCLK_MUX_FCLK1, + rdclk, + LML_0X002A_RXWRCLK_MUX_RXTSPCLK ), + }; + return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); +} + int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t params) { unsigned txmclk = (params.txdiv <= 1) ? LML_0X002B_MCLK1SRC_TXTSPCLKA : LML_0X002B_MCLK1SRC_TXTSPCLKA_DIV; diff --git a/src/lib/hw/lms7002m/lms7002m.h b/src/lib/hw/lms7002m/lms7002m.h index a5a154cd..5bc07b7b 100644 --- a/src/lib/hw/lms7002m/lms7002m.h +++ b/src/lib/hw/lms7002m/lms7002m.h @@ -123,6 +123,7 @@ typedef struct lms7002m_limelight_conf lms7002m_limelight_conf_t; int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t params); int lms7002m_limelight_map(lms7002m_state_t* m, bool sisol1m, bool sisol2m, lms7002m_lml_map_t l1m, lms7002m_lml_map_t l2m); +int lms7002m_limelight_switch_rx_mode(lms7002m_state_t* m, lms7002m_limelight_conf_t params); // CGEN int lms7002m_cgen_disable(lms7002m_state_t* m); From b1daeab13fe7567dc045d094aa6871e0bf975330 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Sat, 25 Apr 2026 20:18:54 +0400 Subject: [PATCH 387/397] xsdr: automatic SISO_DDR mode select based on high samplerate --- src/lib/device/m2_lm7_1/m2_lm7_1.c | 36 +++++++-------- src/lib/device/m2_lm7_1/xsdr_ctrl.c | 72 ++++++++++++++++++----------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index 382e773d..efa5dd48 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -451,7 +451,7 @@ struct dev_m2_lm7_1_gps { struct dev_fe* fe; bool nodecint; - bool double_pump; + //bool double_pump; int cal_data[8]; @@ -1386,9 +1386,8 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* lldev_t dev = d->base.dev; int res; const char* fe = NULL; - - d->nodecint = false; - d->double_pump = false; + bool double_pump = false; + d->nodecint = false; for (unsigned i = 0; i < pcount; i++) { if (strcmp(devparam[i], "fe") == 0) { @@ -1398,7 +1397,7 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* d->nodecint = true; } if (strcmp(devparam[i], "dpump") == 0) { - d->double_pump = true; + double_pump = true; } } @@ -1416,7 +1415,7 @@ int usdr_device_m2_lm7_1_initialize(pdevice_t udev, unsigned pcount, const char* USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "Unable to set device name \"xsdr\"!\n"); } - d->xdev.dpump = d->double_pump; + d->xdev.dpump = double_pump; // Proxy operations memcpy(&d->my_ops, lowlevel_get_ops(dev), sizeof (lowlevel_ops_t)); @@ -1510,7 +1509,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha struct sfetrx4_config rxcfg; res = parse_sfetrx4(dformat, &lchans, pktsyms, channels->count, &rxcfg); if (res) { - USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_ERROR, "Unable to parse RX stream configuration!\n"); + USDR_LL_LOG(d->base.dev, "XSDR", USDR_LOG_ERROR, "Unable to parse RX stream configuration!\n"); return res; } @@ -1519,17 +1518,12 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha return res; } - if (d->double_pump) { - d->xdev.siso_sdr_active_rx = true; - } - - // Reset samplerate with proper bifurcation flags - if (rxcfg.bifurcation_valid != ((d->xdev.s_flags & XSDR_LML_SISO_DDR_RX) ? true : false)) { - res = xsdr_set_samplerate_ex(&d->xdev, d->xdev.s_rxrate, d->xdev.s_txrate, - d->xdev.s_adcclk, d->xdev.s_dacclk, d->xdev.s_flags); - if (res) { - return res; + if (d->xdev.dpump) { + if (channels->count == 2) { + USDR_LL_LOG(d->base.dev, "XSDR", USDR_LOG_ERROR, "RX: In double pump mode only SISO mode is allowed, reduce samplerate or use single channel mode!\n"); + return -EINVAL; } + d->xdev.siso_sdr_active_rx = true; } res = xsdr_prepare(&d->xdev, true, d->tx); @@ -1554,7 +1548,7 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha struct sfetrx4_config txcfg; res = parse_sfetrx4(dformat, &lchans, pktsyms, channels->count, &txcfg); if (res) { - USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_ERROR, "Unable to parse TX stream configuration!\n"); + USDR_LL_LOG(d->base.dev, "XSDR", USDR_LOG_ERROR, "Unable to parse TX stream configuration!\n"); return res; } @@ -1563,7 +1557,11 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha return res; } - if (d->double_pump) { + if (d->xdev.dpump) { + if (channels->count == 2) { + USDR_LL_LOG(d->base.dev, "XSDR", USDR_LOG_ERROR, "TX: In double pump mode only SISO mode is allowed, reduce samplerate or use single channel mode!\n"); + return -EINVAL; + } d->xdev.siso_sdr_active_tx = true; } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 22055bd7..039661c7 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -48,6 +48,7 @@ enum { enum { XSDR_INT_REFCLK = 26000000, + XSDR_SISO_RATE = 72000000, }; // 1001011 - PDAC80501MDQFT @@ -1029,13 +1030,49 @@ int xsdr_reset_extfe(xsdr_dev_t *d) return res; } +static int _xsdr_update_fe_dsp(xsdr_dev_t *d) +{ + int res = 0; + lldev_t dev = d->base.lmsstate.dev; + + if (d->has_duc_ddc && d->s_rxrate && d->s_rx_dec != d->base.rx_dsp_decim) { + // Optional RX DSP reset + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0xf); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x2); + usleep(10); + res = (res) ? res : fgearbox_load_fir_ex(dev, 0, IGPO_DSPCHAIN_RX_PRG << 24, d->base.rx_dsp_decim, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x0); + + d->s_rx_dec = d->base.rx_dsp_decim; + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Updated RX FE DSP to %d decimation\n", d->s_rx_dec); + } + + if (d->has_duc_ddc && d->s_txrate && d->s_tx_int != d->base.tx_dsp_inter) { + // Optional TX DSP reset + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x3); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x2); + usleep(10); + res = (res) ? res : fgearbox_load_fir_i_ex(dev, 0, IGPO_DSPCHAIN_TX_PRG << 24, d->base.tx_dsp_inter, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x0); + + d->s_tx_int = d->base.tx_dsp_inter; + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Updated TE FE DSP to %d interpolation\n", d->s_tx_int); + } + return res; +} + int xsdr_set_samplerate_ex(xsdr_dev_t *d, unsigned rxrate, unsigned txrate, unsigned adcclk, unsigned dacclk, unsigned flags) { lldev_t dev = d->base.lmsstate.dev; - subdev_t subdev = d->base.lmsstate.subdev; + // subdev_t subdev = d->base.lmsstate.subdev; int res; @@ -1082,6 +1119,11 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, // We need RxTSP & TxTSP configured for proper LML - TSP alignment before LFSR training d->afe_active = true; + + if ((rxrate > XSDR_SISO_RATE || txrate > XSDR_SISO_RATE) && !d->dpump) { + d->dpump = true; + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "High samplerate set, activating double pump mode: only SISO mode is allowed!\n"); + } } // flags |= XSDR_LML_EXT_FIFOCLK_RX | XSDR_LML_EXT_FIFOCLK_TX; @@ -1101,33 +1143,7 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, d->cfg_srate_siso_tx = (m_flags & XSDR_LML_SISO_DDR_TX) ? 1 : 0; res = res ? res : _xsdr_calibrate_lml(d); - - if (d->has_duc_ddc && rxrate && d->s_rx_dec != rx_dec) { - // Optional RX DSP reset - dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0xf); - usleep(10); - dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x2); - usleep(10); - res = (res) ? res : fgearbox_load_fir_ex(dev, 0, IGPO_DSPCHAIN_RX_PRG << 24, rx_dec, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); - usleep(10); - dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x0); - - d->s_rx_dec = rx_dec; - } - - if (d->has_duc_ddc && txrate && d->s_tx_int != tx_inr) { - // Optional TX DSP reset - usleep(10); - dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x3); - usleep(10); - dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x2); - usleep(10); - res = (res) ? res : fgearbox_load_fir_i_ex(dev, 0, IGPO_DSPCHAIN_TX_PRG << 24, tx_inr, d->ssdr_pro ? DSP_USSERIES : DSP_7SERIES, 1); - usleep(10); - dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x0); - - d->s_tx_int = tx_inr; - } + res = res ? res : _xsdr_update_fe_dsp(d); /* int32_t a, b; From b769c13978a2e4a1c84e3561ceabbf9f847a3aec Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 30 Apr 2026 02:34:55 +0400 Subject: [PATCH 388/397] usdr: improve RXIQIMB calibration --- src/lib/cal/cal_lo_iqimb.c | 6 +- src/lib/device/m2_lm6_1/m2_lm6_1.c | 35 +++++- src/lib/device/m2_lm6_1/usdr_ctrl.c | 186 ++++++++++++++++++++++++++-- src/lib/device/m2_lm6_1/usdr_ctrl.h | 5 +- src/lib/hw/lms6002d/lms6002d.c | 9 ++ src/lib/hw/lms6002d/lms6002d.h | 3 +- 6 files changed, 224 insertions(+), 20 deletions(-) diff --git a/src/lib/cal/cal_lo_iqimb.c b/src/lib/cal/cal_lo_iqimb.c index e33728b8..311eafe1 100644 --- a/src/lib/cal/cal_lo_iqimb.c +++ b/src/lib/cal/cal_lo_iqimb.c @@ -150,7 +150,7 @@ static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, bool if (res) return res; - res = ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_r); + res = ops->do_meas_nco_avg(ops->param, ops->channel, ops->deflogdur, &pwr_r); if (res) return res; @@ -169,7 +169,7 @@ static int _calibrate_txpwr(struct calibrate_ops* ops, int32_t freqoffset, bool return res; } - res = ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_r); + res = ops->do_meas_nco_avg(ops->param, ops->channel, ops->deflogdur, &pwr_r); if (res) return res; @@ -218,7 +218,7 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, return res; res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, rximoff); - res = res ? res : ops->do_meas_nco_avg(ops->param, ops->channel, 0, &pwr_i); + res = res ? res : ops->do_meas_nco_avg(ops->param, ops->channel, ops->deflogdur, &pwr_i); if (res) return res; diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index 98875cce..19658d32 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -222,6 +222,7 @@ static int dev_m2_lm6_1_sdr_tfe_gen_const_set(pdevice_t ud, pusdr_vfs_obj_t obj, static int usdr_device_m2_lm6_1_calibrate_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int usdr_device_m2_lm6_1_calibrate_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); +static int dev_m2_lm6_1_sdr_rx_dccorrmode_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { @@ -279,6 +280,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/rx/path", { dev_m2_lm6_1_sdr_rx_path_set, NULL }}, { "/dm/sdr/0/tx/path", { dev_m2_lm6_1_sdr_tx_path_set, NULL }}, + { "/dm/sdr/0/rx/dccorrmode", { dev_m2_lm6_1_sdr_rx_dccorrmode_set, NULL }}, + { "/dm/sdr/0/rx/bandwidth", { dev_m2_lm6_1_sdr_rx_bandwidth_set, NULL }}, { "/dm/sdr/0/tx/bandwidth", { dev_m2_lm6_1_sdr_tx_bandwidth_set, NULL }}, @@ -826,6 +829,12 @@ int dev_m2_lm6_1_sdr_tx_gain_vga2_set(pdevice_t ud, UNUSED pusdr_vfs_obj_t obj, return usdr_rfic_set_gain(&d->d, GAIN_TX_VGA2, value, NULL); } +int dev_m2_lm6_1_sdr_rx_dccorrmode_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; + return usdr_set_rxdccorr(&d->d, value & 1); +} + int dev_m2_lm6_1_sdr_rx_bandwidth_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; @@ -992,8 +1001,27 @@ int dev_m2_lm6_1_sdr_rx_dc_meas_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* return 0; } +static int _phgaincorr_set(struct dev_m2_lm6_1 *d, bool tx, uint64_t value) +{ + unsigned ig = (value & 0xffff); + unsigned qg = ((value >> 16) & 0xffff); + int32_t pcorr = (int16_t)((value >> 48) & 0xffff); + int amp_imb; + if (ig < 2047) { + amp_imb = (2047 - ig) * 8; + } else { + amp_imb = - (2047 - qg) * 8; + } + pcorr *= 16; + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "%cXGAC I=%d Q=%d A=%d => AMP_IMB=%d\n", + tx ? 'T' : 'R', ig, qg, pcorr, amp_imb); + + return tx ? usdr_tx_iqimb_set(&d->d, amp_imb, pcorr) : usdr_rx_iqimb_set(&d->d, amp_imb, pcorr); +} + int dev_m2_lm6_1_sdr_tx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { +#if 0 struct dev_m2_lm6_1 *d = (struct dev_m2_lm6_1 *)ud; unsigned ig = (value & 0xffff); @@ -1009,11 +1037,13 @@ int dev_m2_lm6_1_sdr_tx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "TXGAC I=%d Q=%d A=%d => AMP_IMB=%d\n", ig, qg, pcorr, amp_imb); return usdr_tx_iqimb_set(&d->d, amp_imb, pcorr); +#endif + return _phgaincorr_set((struct dev_m2_lm6_1 *)ud, true, value); } int dev_m2_lm6_1_sdr_rx_phgaincorr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { - return -EINVAL; + return _phgaincorr_set((struct dev_m2_lm6_1 *)ud, false, value); } @@ -1267,6 +1297,9 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha } d->d.rx_lchans = chans; *out_handle = d->rx; + + // TODO: handle NCO changes + res = res ? res : usdr_rxupdate_cal(&d->d); } else if (strstr(sid, "tx") != NULL) { bool extended_core = (d->d.hwid & (1 << (24 + 2))) ? true : false; diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 1ce36962..bc827f78 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -442,6 +442,10 @@ int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob) #define TARGET_RATE 30720000 +int usdr_set_rxdccorr(usdr_dev_t *d, bool enable) +{ + return lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_0, MAKE_PHY_WR_REG(CFG_REG_DCCTRL, enable)); +} int usdr_reset_txfex(struct usdr_dev *d) { @@ -459,6 +463,51 @@ int usdr_reset_txnco(struct usdr_dev *d) return res; } +static void usdr_calc_iqimb(struct imb_data *d, int32_t imbd_data[4]) +{ + // CFG_AMP_I + // CFG_AMP_Q + // CFG_TAN_I + // CFG_TAN_Q + + // I = CFG_AMP_I * i + CFG_TAN_Q * q + // Q = CFG_AMP_Q * q + CFG_TAN_I * i + // Symmetric correction to I/Q: + // c = math.cos(phi / 2.0) + // s = math.sin(phi / 2.0) + // I = (c / alpha) * Id + (s / beta) * Qd + // Q = (c / beta) * Qd -(s / alpha) * Id + + float c = cos(M_PI_4 * d->pahse / IMB_PHASE_MAX); + float s = sin(M_PI_4 * d->pahse / IMB_PHASE_MAX); + + float alpha = (d->ampl > 0) ? 1.0 - (((double)d->ampl) / IMB_AMPL_MAX) : 1.0; + float beta = (d->ampl < 0) ? 1.0 + (((double)d->ampl) / IMB_AMPL_MAX) : 1.0; + + // 18 bits -> 16 bits + // probably we need extra headroom for DC and IQimb correction, but leave as an extra option + // + // AMP_COMP_2CH_3DB: 17bit * SQRT(2) | MAX * 0.35355 + // AMP_COMP_2CH_0DB: 17bit | MAX * 0.5 + // AMP_COMP_1CH_3DB: 16bit * SQRT(2) | MAX * 0.7071 + // AMP_COMP_1CH_0DB: 16bit | MAX + float scale = + (d->amp_corr == AMP_COMP_1CH_0DB) ? 1.0 : + (d->amp_corr == AMP_COMP_1CH_3DB) ? 0.7071 : + (d->amp_corr == AMP_COMP_2CH_0DB) ? 0.5 : 0.35355; + + float fcfg_amp_i = scale * c * alpha; + float fcfg_amp_q = scale * c * beta; + float fcfg_tan_q = scale * s * beta; + float fcfg_tan_i = - scale * s * alpha; + + int32_t dsp_amp_max = 8388607; + imbd_data[0] = dsp_amp_max * fcfg_amp_i; + imbd_data[1] = dsp_amp_max * fcfg_amp_q; + imbd_data[2] = dsp_amp_max * fcfg_tan_i; + imbd_data[3] = dsp_amp_max * fcfg_tan_q; +} + int usdr_update_cal(struct usdr_dev *d, bool rx) { return rx ? usdr_rxupdate_cal(d) : usdr_txupdate_cal(d); @@ -466,11 +515,31 @@ int usdr_update_cal(struct usdr_dev *d, bool rx) int usdr_rxupdate_cal(struct usdr_dev *d) { - return 0; + int32_t imbd_data[4]; + int res = 0; + + usdr_calc_iqimb(&d->rx_corr, imbd_data); + + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_0, MAKE_PHY_WR_REG(CFG_REG_IQIMB_0, imbd_data[0])); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_0, MAKE_PHY_WR_REG(CFG_REG_IQIMB_1, imbd_data[1])); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_0, MAKE_PHY_WR_REG(CFG_REG_IQIMB_2, imbd_data[2])); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_0, MAKE_PHY_WR_REG(CFG_REG_IQIMB_3, imbd_data[3])); + return res; } int usdr_txupdate_cal(struct usdr_dev *d) { + int32_t imbd_data[4]; + int res = 0; + + usdr_calc_iqimb(&d->tx_corr, imbd_data); + + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_0, imbd_data[0])); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_1, imbd_data[1])); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_2, imbd_data[2])); + res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_3, imbd_data[3])); + return res; +#if 0 // CFG_AMP_I // CFG_AMP_Q // CFG_TAN_I @@ -526,6 +595,7 @@ int usdr_txupdate_cal(struct usdr_dev *d) res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_2, cfg_tan_i)); res = res ? res : lowlevel_reg_wr32(d->base.dev, 0, REG_CFG_PHY_1, MAKE_PHY_WR_REG(CFG_REG_IQIMB_3, cfg_tan_q)); return res; +#endif } static int usdr_restore_nco(struct usdr_dev *d, bool istx) @@ -714,6 +784,8 @@ int usdr_ctor(lldev_t dev, subdev_t sub, struct usdr_dev *d) d->rx_rfic_path = USDR_RX_AUTO; d->tx_rfic_path = USDR_TX_AUTO; + d->rx_corr.amp_corr = AMP_COMP_2CH_0DB; //AMP_COMP_1CH_0DB; + return 0; } @@ -732,6 +804,13 @@ int usdr_tx_dccorr(usdr_dev_t *d, int16_t i, int16_t q) return lowlevel_reg_wr32(d->lms.dev, 0, REG_CFG_PHY_1, (1 << 24) | val); } +int usdr_tx_vga1_dccorr(usdr_dev_t *d, int8_t i, int8_t q) +{ + int8_t ci = 0x80 + i; + int8_t cq = 0x80 + q; + return lms6002d_set_txvga1_dc(&d->lms, (uint8_t)ci, (uint8_t)cq); +} + int usdr_init(struct usdr_dev *d, int ext_clk, unsigned ext_fref) { lldev_t dev = d->base.dev; @@ -1185,7 +1264,7 @@ int usdr_rfic_set_gain(struct usdr_dev *d, d->rx_vga2b = 0; res = lms6002d_set_rxlna_gain(&d->lms, 1 + d->rx_lna); - val = _lms6002d_rxvga1_db_to_int(5 + d->rx_vga1); + val = _lms6002d_rxvga1_db_to_int(GAIN_RX_VGA1_MIN + d->rx_vga1); res = res ? res : lms6002d_set_rxvga1_gain(&d->lms, val); res = res ? res : lms6002d_set_rxvga2ab_gain(&d->lms, d->rx_vga2a, d->rx_vga2b); @@ -1212,6 +1291,7 @@ int usdr_rfic_set_gain(struct usdr_dev *d, ngain = _usdr_gain_clamp(gain, GAIN_RX_VGA1_MIN, GAIN_RX_VGA1_MAX); val = _lms6002d_rxvga1_db_to_int(ngain); res = lms6002d_set_rxvga1_gain(&d->lms, val); + d->rx_vga1 = ngain - GAIN_RX_VGA1_MIN; break; case GAIN_RX_VGA2: @@ -1354,6 +1434,14 @@ int usdr_tx_iqimb_set(usdr_dev_t* d, int iq_amp_imb, int phase_imb) return usdr_txupdate_cal(d); } +int usdr_rx_iqimb_set(usdr_dev_t* d, int iq_amp_imb, int phase_imb) +{ + d->rx_corr.ampl = (int64_t)iq_amp_imb * IMB_AMPL_MAX / INT16_MAX; + d->rx_corr.pahse = phase_imb; + + return usdr_rxupdate_cal(d); +} + int usdr_rxdccorr(struct usdr_dev *d, uint64_t *ov) { int out; @@ -1387,7 +1475,9 @@ int usdr_set_corr_param(usdr_dev_t* d, int channel, int corr_type, int value) if (rx) { return -EINVAL; } else { - return usdr_tx_dccorr(d, imb_corr->dc_i, imb_corr->dc_q); + return d->cal_txlo_dig ? + usdr_tx_dccorr(d, imb_corr->dc_i, imb_corr->dc_q) : + usdr_tx_vga1_dccorr(d, imb_corr->dc_i, imb_corr->dc_q); } case CORR_PARAM_A: @@ -1407,6 +1497,20 @@ int usdr_set_corr_param(usdr_dev_t* d, int channel, int corr_type, int value) case CORR_OP_SET_BW: return lms6002d_set_bandwidth(&d->lms, !rx, value); + case CORR_OP_SET_GAIN: + if (rx) { + unsigned ngain = d->rx_vga1 + value + GAIN_RX_VGA1_MIN; + if (ngain > GAIN_RX_VGA1_MAX) + return -E2BIG; + + return lms6002d_set_rxvga1_gain(&d->lms, _lms6002d_rxvga1_db_to_int(ngain)); + } else { + if (value > 21) + return -E2BIG; + + return lms6002d_set_txvga1_gain(&d->lms, 10 + (unsigned)value); + } + default: return -EINVAL; } @@ -1457,13 +1561,10 @@ int usdrcal_init_calibrate(usdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->rxsamplerate = ops->adcrate / d->rxbb_decim; ops->txsamplerate = ops->dacrate / d->txbb_intr; - ops->rxfrequency = d->rx_lo; + ops->rxfrequency = d->rfic_rx_lo; ops->txfrequency = d->tx_lo; ops->channel = channel; - ops->deflogdur = ops->rxsamplerate / 16; - if (ops->deflogdur > 131072) { - ops->deflogdur = 131072; - } + ops->deflogdur = ops->rxsamplerate / 20e6; ops->defstop = -120000; ops->param = d; @@ -1476,7 +1577,7 @@ int usdrcal_init_calibrate(usdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->rxbw_factor = 2.45; ops->txbw_factor = 2.45; - ops->txlo_iq_corr.max = 2048; + ops->txlo_iq_corr.max = 2047; ops->txlo_iq_corr.min = -2047; ops->tximb_iq_corr.max = IMB_AMPL_MAX; @@ -1507,8 +1608,9 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) int res = 0; struct calibrate_ops cops; lldev_t dev = d->lms.dev; - bool externallb = (param & USDR_CAL_EXT_FB) == USDR_CAL_EXT_FB; + bool externallb = ((param & USDR_CAL_EXT_FB) == USDR_CAL_EXT_FB); bool norestore = false; + bool usedualtx = ((param & USDR_CAL_DUAL_RXLO) == USDR_CAL_DUAL_RXLO); unsigned coarse = (((param & USDR_CAL_COARSE_1) == USDR_CAL_COARSE_1) ? 1 : 0) | (((param & USDR_CAL_COARSE_2) == USDR_CAL_COARSE_2) ? 2 : 0); @@ -1516,7 +1618,6 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) unsigned rx_lo = d->rx_lo; unsigned rfic_rx_lo = d->rfic_rx_lo; unsigned rfe_gain_lna_sel = (d->lms.rfe_gain_lna_sel & 0x30) >> 4; // Fixme! - res = res ? res : usdrcal_init_calibrate(d, &cops, channel); cops.coarse_mode = coarse; @@ -1525,8 +1626,40 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) } if ((param & USDR_CAL_RXIQIMB) && (rx_lo > 0)) { - // TODO if TX was disabled enable TX USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration RXIQIMB(%c) ------------------\n", 'A' + channel); + if (tx_lo == 0) { + res = res ? res : _usdr_pwr_state(d, true, true); + res = res ? res : usleep(500000); + } + if (!externallb) { + res = res ? res : lms6002d_rf_loopback_en(&d->lms); + } + res = (res) ? res : calibrate_rxiqimb(&cops); + if (res) + return res; + if (tx_lo) { + res = res ? res : lms6002d_tune_pll(&d->lms, true, tx_lo); + if (res == -ERANGE) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore TX_LO=%.3f: out of range\n", tx_lo / 1e6); + res = lms6002d_disable_pll(&d->lms, true); + } else if (res == -ENOLCK) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore TX_LO=%.3f: unable to lock PLL\n", tx_lo / 1e6); + res = 0; + } + } else { + res = res ? res : lms6002d_disable_pll(&d->lms, true); + } + if (!externallb) { + res = res ? res : lms6002d_rf_loopback_dis(&d->lms); + } + if (res) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " RXIQIMB failed: res=%d\n", res); + return res; + } + if (sarray) { + sarray[ 2 * 2 + 0] = cops.i; + sarray[ 2 * 2 + 1] = cops.q; + } } if ((param & (USDR_CAL_TXLO | USDR_CAL_TXIQIMB)) && (tx_lo > 0)) { @@ -1547,11 +1680,28 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if (param & USDR_CAL_TXLO) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration TXLO(%c) ------------------\n", 'A' + channel); + int8_t fst_i, fst_q; + if (usedualtx) { + d->cal_txlo_dig = false; + cops.txlo_iq_corr.max = 127; + cops.txlo_iq_corr.min = -128; + res = (res) ? res : calibrate_txlo(&cops); + if (res) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " TXLO first stage failed: res=%d\n", res); + return res; + } + fst_i = cops.i; + fst_q = cops.q; + } + d->cal_txlo_dig = true; res = (res) ? res : calibrate_txlo(&cops); if (res) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " TXLO failed: res=%d\n", res); return res; } + if (usedualtx) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " TXLO Dual stage result: Fist={I=%d Q=%d} Second={I=%d Q=%d}\n", fst_i, fst_q, cops.i, cops.q); + } if (sarray) { sarray[ 2 * 1 + 0] = cops.i; sarray[ 2 * 1 + 1] = cops.q; @@ -1577,6 +1727,13 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if (!norestore) { if (rfic_rx_lo > 0) { res = res ? res : lms6002d_tune_pll(&d->lms, false, rfic_rx_lo); + if (res == -ERANGE) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore RX_LO=%.3f: out of range\n", rfic_rx_lo / 1e6); + res = lms6002d_disable_pll(&d->lms, false); + } else if (res == -ENOLCK) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore RX_LO=%.3f: unable to lock PLL\n", rfic_rx_lo / 1e6); + res = 0; + } } else { res = res ? res : lms6002d_disable_pll(&d->lms, false); } @@ -1584,6 +1741,7 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) res = res ? res : lms6002d_set_rx_path(&d->lms, rfe_gain_lna_sel); res = res ? res : lms6002d_rf_loopback_dis(&d->lms); } + res = res ? res : lms6002d_set_rxvga1_gain(&d->lms, _lms6002d_rxvga1_db_to_int(d->rx_vga1 + GAIN_RX_VGA1_MIN)); if (res) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, "restore configuration failed: res=%d\n", res); return res; @@ -1614,6 +1772,8 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if (rx_lo == 0) { _usdr_pwr_state(d, false, false); } - + if (tx_lo == 0) { + _usdr_pwr_state(d, true, false); + } return res; } diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.h b/src/lib/device/m2_lm6_1/usdr_ctrl.h index 34a41bfb..5bde4dbe 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.h +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.h @@ -128,6 +128,7 @@ struct usdr_dev bool has_txchain; bool rf_loopback_active; + bool cal_txlo_dig; unsigned rawsamplerate; unsigned rxbb_decim; @@ -219,6 +220,7 @@ int usdr_reset_txfex(struct usdr_dev *d); int usdr_rxdccorr(struct usdr_dev *d, uint64_t *ov); int usdr_tx_gen_set(usdr_dev_t *d, bool enable, unsigned chanmsk, int16_t i, int16_t q); +int usdr_set_rxdccorr(usdr_dev_t *d, bool enable); enum { USDR_CAL_RXLO = 1, @@ -226,6 +228,7 @@ enum { USDR_CAL_RXIQIMB = 4, USDR_CAL_TXIQIMB = 8, + USDR_CAL_DUAL_RXLO = 128, USDR_CAL_EXT_FB = 256, USDR_CAL_COARSE_1 = 512, USDR_CAL_COARSE_2 = 1024, @@ -281,7 +284,7 @@ int usdr_rxupdate_cal(struct usdr_dev *d); int usdr_update_cal(struct usdr_dev *d, bool rx); int usdr_tx_iqimb_set(usdr_dev_t* d, int iq_amp_imb, int phase_imb); - +int usdr_rx_iqimb_set(usdr_dev_t* d, int iq_amp_imb, int phase_imb); #endif diff --git a/src/lib/hw/lms6002d/lms6002d.c b/src/lib/hw/lms6002d/lms6002d.c index ddc8e519..a1aad47d 100644 --- a/src/lib/hw/lms6002d/lms6002d.c +++ b/src/lib/hw/lms6002d/lms6002d.c @@ -868,6 +868,15 @@ int lms6002d_set_rxfedc(lms6002d_state_t* obj, int8_t dci, int8_t dcq) return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); } +int lms6002d_set_txvga1_dc(lms6002d_state_t* obj, uint8_t dci, uint8_t dcq) +{ + uint16_t regs[] = { + MAKE_LMS6002D_TRF_VGA1DC_I(dci), + MAKE_LMS6002D_TRF_VGA1DC_Q(dcq), + }; + return lms6002d_spi_post(obj, regs, SIZEOF_ARRAY(regs)); +} + int lms6002d_set_tia_cfb(lms6002d_state_t* obj, uint8_t value) { uint16_t regs[] = { diff --git a/src/lib/hw/lms6002d/lms6002d.h b/src/lib/hw/lms6002d/lms6002d.h index a01d06a9..92182661 100644 --- a/src/lib/hw/lms6002d/lms6002d.h +++ b/src/lib/hw/lms6002d/lms6002d.h @@ -71,7 +71,6 @@ int lms6002d_set_txvga2_gain(lms6002d_state_t* obj, unsigned vga); int lms6002d_set_rx_extterm(lms6002d_state_t* obj, bool extterm); - enum lms6002d_rx_path { RXPATH_OFF = 0, RXPATH_LNA1 = 1, @@ -93,7 +92,7 @@ int lms6002d_set_tx_path(lms6002d_state_t* obj, unsigned path); int lms6002d_set_rxfedc(lms6002d_state_t* obj, int8_t dci, int8_t dcq); int lms6002d_set_rxfe_ip2corr(lms6002d_state_t* obj, int8_t i, int8_t q); - +int lms6002d_set_txvga1_dc(lms6002d_state_t* obj, uint8_t dci, uint8_t dcq); int lms6002d_cal_lpf(lms6002d_state_t* obj); int lms6002d_cal_txrxlpfdc(lms6002d_state_t* obj, bool tx); From e01018217e1927369750e146799117b7c897b06b Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 30 Apr 2026 16:53:28 +0400 Subject: [PATCH 389/397] usdr: add auto probing minimal LO range --- src/lib/device/m2_lm6_1/usdr_ctrl.c | 97 ++++++++++++++++++++++------- src/lib/device/m2_lm6_1/usdr_ctrl.h | 5 ++ src/lib/hw/lms6002d/lms6002d.c | 55 ++++++++++------ src/lib/hw/lms6002d/lms6002d.h | 10 +++ 4 files changed, 125 insertions(+), 42 deletions(-) diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index bc827f78..14229bc6 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -47,6 +47,7 @@ enum { USDR_INT_REFCLK = 26000000, + USDR_LO_LOW_RANGE = 250000000, }; enum usdr_rev000 { @@ -602,12 +603,13 @@ static int usdr_restore_nco(struct usdr_dev *d, bool istx) { int res = 0; freq_data_t* freqd = (istx) ? &d->tx_raw : &d->rx_raw; + int ext_lo_offset = (istx) ? d->tx_exten_lo : d->rx_exten_lo; for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { if (freqd->bb[i].set) { - res = res ? res : _usdr_set_nco(d, !istx, i, (int32_t)freqd->bb[i].value); + res = res ? res : _usdr_set_nco(d, !istx, i, (int32_t)freqd->bb[i].value + ext_lo_offset); } else { - res = res ? res : _usdr_set_nco(d, !istx, i, 0); + res = res ? res : _usdr_set_nco(d, !istx, i, ext_lo_offset); } } return res; @@ -616,7 +618,8 @@ static int usdr_restore_nco(struct usdr_dev *d, bool istx) static int _usdr_update_bandwidth(struct usdr_dev *d, bool istx) { unsigned rate = istx ? (d->dac_clk / d->txbb_intr) : (d->adc_clk / d->rxbb_decim); - unsigned bw = 2 * (istx ? d->tx_nco_distance : d->rx_nco_distance) + rate; + int ext_lo_offset = (istx) ? d->tx_exten_lo : d->rx_exten_lo; + unsigned bw = 2 * (istx ? d->tx_nco_distance : d->rx_nco_distance) + rate + ABS(2 * ext_lo_offset); USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Updating %s bandwidth to %.3f Mhz\n", lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", bw / 1e6); @@ -1143,7 +1146,7 @@ int usdr_rfic_fe_set_freq(struct usdr_dev *d, if (!istx) { freq = d->rx_lo; d->rx_nco_distance = nco_distance; - + d->rx_exten_lo = 0; if (d->mexir_en) { // upconverter mixer freq += d->mixer_lo; @@ -1155,6 +1158,7 @@ int usdr_rfic_fe_set_freq(struct usdr_dev *d, } else { freq = d->tx_lo; d->tx_nco_distance = nco_distance; + d->tx_exten_lo = 0; } res = lms6002d_tune_pll(&d->lms, istx, freq); @@ -1170,29 +1174,68 @@ int usdr_rfic_fe_set_freq(struct usdr_dev *d, res = lms6002d_tune_pll(&d->lms, istx, freq); } if (res == -ENOLCK) { - USDR_LOG("UDEV", USDR_LOG_ERROR, "%s: %s_LO=%u unable to lock (pwr: %d)!\n", - lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", - istx ? d->tx_lo : d->rx_lo, - istx ? d->tx_pwren : d->rx_pwren); - } + if (freq < USDR_LO_LOW_RANGE && (istx ? d->tx_minimal_lo == 0 : d->rx_minimal_lo == 0)) { + // Try to get low range in order to apply NCO correction to extend range + unsigned sweep_lo = freq; + lms6002_pll_stat_t stat; + for (; sweep_lo < USDR_LO_LOW_RANGE; sweep_lo += 1e6) { + res = lms6002d_tune_pll_stat(&d->lms, istx, sweep_lo, true, &stat); + if (res == -ENOLCK) + continue; + if (res) + return res; - // Update NCOs - for (unsigned i = 0; i < MAX_NCO_STREAMS; i++) { - if (freqd->bb[i].set) { - res = res ? res : _usdr_set_nco(d, !istx, i, (int32_t)freqd->bb[i].value); + if (stat.vco_cap_max >= 1) + break; + } + if (res) + return res; + + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_WARNING, "Probed minimal %cX_LO is %d\n", istx ? 'T' : 'R', sweep_lo); + if (istx) { + d->tx_minimal_lo = sweep_lo; + } else { + d->rx_minimal_lo = sweep_lo; + } + } else if (freq < USDR_LO_LOW_RANGE) { + res = lms6002d_tune_pll_stat(&d->lms, istx, (istx ? d->tx_minimal_lo : d->rx_minimal_lo), true, NULL); } + + if (res == -ENOLCK) { + USDR_LOG("UDEV", USDR_LOG_ERROR, "%s: %s_LO=%u unable to lock (pwr: %d)!\n", + lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", + istx ? d->tx_lo : d->rx_lo, + istx ? d->tx_pwren : d->rx_pwren); + } + if (res) + return res; + + int64_t minimal_lo = (int64_t)(istx ? d->tx_minimal_lo : d->rx_minimal_lo); + int64_t offset = (int64_t)freq - minimal_lo; + unsigned dig_rate = istx ? d->dac_clk : d->adc_clk; + unsigned bb_rate = istx ? (d->dac_clk / d->txbb_intr) : (d->adc_clk / d->rxbb_decim); + unsigned rate_min = bb_rate + ABS(offset); + // Check if we can extend analog BW to support this offset, we need rate/2 + offset, assume 90% of usable digital BB rate + if (dig_rate * 0.45 < rate_min) { + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_ERROR, "%cX_LO can't be sastisfied with extended NCO: required digital rate: %.3f (of %.3f NCO shift), increase samplerate in order to set that frequency!\n", + istx ? 'T' : 'R', rate_min / 1.0e6, offset / 1.0e6); + return -ENOLCK; + } + + if (istx) { + d->tx_exten_lo = offset; + } else { + d->rx_exten_lo = offset; + } + + USDR_LL_LOG(d->base.dev, "UDEV", USDR_LOG_INFO, "%cX_LO set to %.3f with extention %.3f\n", istx ? 'T' : 'R', minimal_lo / 1.0e6, offset / 1.0e6); } + // Update NCOs + res = res ? res : usdr_restore_nco(d, istx); + // Update BW if ((istx && !d->tx_bw.set) || (!istx && !d->rx_bw.set)) { - /* - unsigned rate = istx ? (d->dac_clk / d->txbb_intr) : (d->adc_clk / d->rxbb_decim); - unsigned bw = 2 * (istx ? d->tx_nco_distance : d->rx_nco_distance) + rate; - - USDR_LOG("UDEV", USDR_LOG_WARNING, "%s: Updating %s bandwidth to %.3f Mhz\n", - lowlevel_get_devname(d->base.dev), istx ? "TX" : "RX", bw / 1e6); - res = res ? res : lms6002d_set_bandwidth(&d->lms, istx, bw); - */ res = res ? res : _usdr_update_bandwidth(d, istx); } @@ -1208,9 +1251,17 @@ int usdr_rfic_bb_set_badwidth(struct usdr_dev *d, if (actualbw) *actualbw = bw; if (!dir_tx) { - opt_u32_set_val(&d->rx_bw, bw); + if (bw == 0) { + opt_u32_set_null(&d->rx_bw); + } else { + opt_u32_set_val(&d->rx_bw, bw); + } } else { - opt_u32_set_val(&d->tx_bw, bw); + if (bw == 0) { + opt_u32_set_null(&d->tx_bw); + } else { + opt_u32_set_val(&d->tx_bw, bw); + } } return lms6002d_set_bandwidth(&d->lms, dir_tx, bw); diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.h b/src/lib/device/m2_lm6_1/usdr_ctrl.h index 5bde4dbe..06869437 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.h +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.h @@ -140,8 +140,13 @@ struct usdr_dev unsigned rx_lo; unsigned tx_lo; + int rx_exten_lo; // Extention LO range by applying NCO-shift + int tx_exten_lo; // Extention LO range by applying NCO-shift + unsigned rx_nco_distance; // Maximum distance from LO to the farest NCO unsigned tx_nco_distance; + unsigned rx_minimal_lo; // Minimal LO to keep VCO lock, 0 -- not probed yet + unsigned tx_minimal_lo; freq_data_t rx_raw; freq_data_t tx_raw; diff --git a/src/lib/hw/lms6002d/lms6002d.c b/src/lib/hw/lms6002d/lms6002d.c index a1aad47d..fc94be1f 100644 --- a/src/lib/hw/lms6002d/lms6002d.c +++ b/src/lib/hw/lms6002d/lms6002d.c @@ -265,10 +265,15 @@ int lms6002d_disable_pll(lms6002d_state_t* obj, bool tx) } int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) +{ + return lms6002d_tune_pll_stat(obj, tx, freq, true, NULL); +} + +int lms6002d_tune_pll_stat(lms6002d_state_t* obj, bool tx, unsigned freq, bool mkstat, lms6002_pll_stat_t* pstat) { int res; unsigned k; - if (freq < 200000000) + if (freq < 170000000) return -ERANGE; for (k = 0; k < SIZEOF_ARRAY(s_vco_ranges) - 1; k++) { @@ -276,13 +281,15 @@ int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) break; } - uint64_t vcofreq = (uint64_t)freq << (s_vco_ranges[k].vcodiv + 1); + uint8_t vco_div = mkstat ? s_vco_ranges[k].vcodiv : pstat->vco_div; + uint8_t vco_num = mkstat ? s_vco_ranges[k].vconum : pstat->vco_num; + uint8_t vco_cap = mkstat ? 0x20 : ((unsigned)pstat->vco_cap_max + pstat->vco_cap_min) / 2; + + uint64_t vcofreq = (uint64_t)freq << (vco_div + 1); struct nint_nfrac nn = lms6002d_pll_calc(obj->fref, vcofreq); - unsigned vcon = s_vco_ranges[k].vconum; - //for (vcon = 4; vcon < 8; vcon++) - //{ - USDR_LOG("6002", USDR_LOG_INFO, "pll %s: OUT=%u VCO_FREQ=%llu VCO_NUM=%d NINT=%u NFRAC=%u FREF=%u\n", - tx ? "tx" : "rx", freq, (unsigned long long)vcofreq, 8 - s_vco_ranges[k].vconum, nn.nint, nn.frac, obj->fref); + + USDR_LOG("6002", USDR_LOG_INFO, "pll %s: OUT=%u VCO_FREQ=%llu VCO_NUM=%d VCO_DIV=%d NINT=%u NFRAC=%u FREF=%u VCO_CAP=%d\n", + tx ? "tx" : "rx", freq, (unsigned long long)vcofreq, 8 - vco_num, vco_div + 1, nn.nint, nn.frac, obj->fref, vco_cap); if (tx) { SET_LMS6002D_TOP_ENREG_CLK_TX_DSM_SPI(obj->top_enreg, 1); @@ -304,10 +311,10 @@ int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) MAKE_LMS6002D_RXPLL_NINT_NFRAC_BY3(nint_nfrac), tx ? MAKE_LMS6002D_TXPLL_PLL_CFG(1, 1, 1, 1, 0) : MAKE_LMS6002D_RXPLL_PLL_CFG(1, 1, 1, 1, 0), - tx ? MAKE_LMS6002D_TXPLL_VCO_DIV(vcon, 0, 0) : - MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(vcon, 0, 0), - tx ? MAKE_LMS6002D_TXPLL_VCO_DIV(vcon, s_vco_ranges[k].vcodiv | 4, 0) : - MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(vcon, s_vco_ranges[k].vcodiv | 4, + tx ? MAKE_LMS6002D_TXPLL_VCO_DIV(vco_num, 0, 0) : + MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(vco_num, 0, 0), + tx ? MAKE_LMS6002D_TXPLL_VCO_DIV(vco_num, vco_div | 4, 0) : + MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(vco_num, vco_div | 4, GET_LMS6002D_RXPLL_VCO_DIV_BUFSEL_SELOUT(obj->rxpll_vco_div_bufsel)), tx ? MAKE_LMS6002D_TXPLL_PFD_UP(1, 0, 0, 6) : //2 MAKE_LMS6002D_RXPLL_PFD_UP(1, 0, 0, 6), //2 @@ -315,8 +322,8 @@ int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) MAKE_LMS6002D_RXPLL_VCO_REG_PFD_U(1, 1, 0, 0), tx ? MAKE_LMS6002D_TXPLL_VCO_REG_PFD_D(0, 2) : MAKE_LMS6002D_RXPLL_VCO_REG_PFD_D(0, 2), - tx ? MAKE_LMS6002D_TXPLL_PLL_CFG2(0, 0x20) : - MAKE_LMS6002D_RXPLL_PLL_CFG2(0, 0x20), + tx ? MAKE_LMS6002D_TXPLL_PLL_CFG2(0, vco_cap) : + MAKE_LMS6002D_RXPLL_PLL_CFG2(0, vco_cap), //tx ? MAKE_LMS6002D_TXPLL_VCO_REG_PFD_D(2, 0) : // MAKE_LMS6002D_RXPLL_VCO_REG_PFD_D(2, 0), tx ? 0x9b76 : 0xab76, @@ -351,13 +358,17 @@ int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) if (res) return res; + // We set cahed values, no need to do VCO calibration + if (!mkstat) + return res; + // TODO add thermal info - uint8_t vcocap = (lo + hi) / 2; + vco_cap = (lo + hi) / 2; uint16_t vregs[] = { - tx ? MAKE_LMS6002D_TXPLL_PLL_CFG2(0, vcocap) : - MAKE_LMS6002D_RXPLL_PLL_CFG2(0, vcocap), - tx ? MAKE_LMS6002D_TXPLL_VCO_DIV(vcon, s_vco_ranges[k].vcodiv | 4, 0) : - MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(vcon, s_vco_ranges[k].vcodiv | 4, + tx ? MAKE_LMS6002D_TXPLL_PLL_CFG2(0, vco_cap) : + MAKE_LMS6002D_RXPLL_PLL_CFG2(0, vco_cap), + tx ? MAKE_LMS6002D_TXPLL_VCO_DIV(vco_num, vco_div | 4, 0) : + MAKE_LMS6002D_RXPLL_VCO_DIV_BUFSEL(vco_num, vco_div | 4, GET_LMS6002D_RXPLL_VCO_DIV_BUFSEL_SELOUT(obj->rxpll_vco_div_bufsel)), tx ? 0x9b7e : 0xab7e, //PD comparator // tx ? MAKE_LMS6002D_LMS6002D_TXPLL_0x17(1, 1, 0, 2) : @@ -368,7 +379,7 @@ int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) return res; USDR_LOG("6002", USDR_LOG_INFO, "pll %s: vco_cap[%d;%d] => %d /%d / %02x -> %02x\n", - tx ? "tx" : "rx", lo, hi, vcocap, vcon, obj->rxpll_vco_div_bufsel, vregs[1] ); + tx ? "tx" : "rx", lo, hi, vco_cap, vco_num, obj->rxpll_vco_div_bufsel, vregs[1] ); if (!tx) obj->rxpll_vco_div_bufsel = vregs[1]; @@ -377,6 +388,12 @@ int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq) if (lo > hi && hi == 0) { return -ENOLCK; } + if (pstat) { + pstat->vco_cap_min = lo; + pstat->vco_cap_max = hi; + pstat->vco_num = vco_num; + pstat->vco_div = vco_div; + } return 0; } diff --git a/src/lib/hw/lms6002d/lms6002d.h b/src/lib/hw/lms6002d/lms6002d.h index 92182661..6be2f17e 100644 --- a/src/lib/hw/lms6002d/lms6002d.h +++ b/src/lib/hw/lms6002d/lms6002d.h @@ -38,6 +38,16 @@ typedef struct lms6002d_state lms6002d_state_t; int lms6002d_create(lldev_t dev, unsigned subdev, unsigned lsaddr, lms6002d_state_t* out); + +// Internal VCO+PLL state for fast LO settelment without calibration +typedef struct lms6002_pll_stat { + uint8_t vco_cap_min; + uint8_t vco_cap_max; + uint8_t vco_num; + uint8_t vco_div; +} lms6002_pll_stat_t; + +int lms6002d_tune_pll_stat(lms6002d_state_t* obj, bool tx, unsigned freq, bool mkstat, lms6002_pll_stat_t* pstat); int lms6002d_tune_pll(lms6002d_state_t* obj, bool tx, unsigned freq); int lms6002d_disable_pll(lms6002d_state_t* obj, bool tx); From 7b9293ca711f33134afd828213a16dfd79d51ae1 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 1 May 2026 01:37:29 +0400 Subject: [PATCH 390/397] usdr: fix conflicting endpoint --- src/lib/device/m2_lm6_1/m2_lm6_1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index 19658d32..fa7c7dc8 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -251,7 +251,7 @@ const usdr_dev_param_func_t s_fparams_m2_lm6_1_rev000[] = { { "/dm/sdr/0/rx/ip2corr", { dev_m2_lm6_1_sdr_rx_ip2corr_set, NULL }}, { "/dm/sdr/0/tx/dccorr", { dev_m2_lm6_1_sdr_tx_dccorr_set, NULL }}, - { "/dm/sdr/0/calibrate", { dev_m2_lm6_1_sdr_dc_calib, NULL }}, + { "/dm/sdr/0/calibrate_dc", { dev_m2_lm6_1_sdr_dc_calib, NULL }}, { "/dm/sdr/0/rx/frequency/lob",{ dev_m2_lm6_1_sdr_rx_freq_lob_set, NULL }}, { "/dm/sdr/0/rx/frequency", { dev_m2_lm6_1_sdr_rx_freq_set, NULL }}, From ae08729d05b59dc3ebca1a896b7501c943e4a8f4 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 1 May 2026 01:38:24 +0400 Subject: [PATCH 391/397] usdr: fix calibration when RX or TX was down --- src/lib/device/m2_lm6_1/usdr_ctrl.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 14229bc6..39546542 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -701,10 +701,9 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, res = res ? res : usdr_restore_nco(d, (rxgrp == 1)); } - uint32_t v = 0; - res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &v); - - USDR_LOG("UDEV", USDR_LOG_WARNING, "V=%08x\n", v); + //uint32_t v = 0; + //res = res ? res : lowlevel_reg_rd32(dev, 0, REG_CFG_PHY_0, &v); + //USDR_LOG("UDEV", USDR_LOG_WARNING, "V=%08x\n", v); d->rxbb_decim = int_dec_x[ind]; d->txbb_intr = int_dec_x[ind]; @@ -1678,16 +1677,23 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if ((param & USDR_CAL_RXIQIMB) && (rx_lo > 0)) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration RXIQIMB(%c) ------------------\n", 'A' + channel); - if (tx_lo == 0) { + if (tx_lo == 0 || !d->tx_pwren) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, "TX frontend was down, powering up\n"); res = res ? res : _usdr_pwr_state(d, true, true); res = res ? res : usleep(500000); + res = res ? res : usdr_txupdate_cal(d); } if (!externallb) { res = res ? res : lms6002d_rf_loopback_en(&d->lms); } res = (res) ? res : calibrate_rxiqimb(&cops); - if (res) + if (res == -ENAVAIL) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " RXIQIMB failed!\n"); + res = 0; + cops.i = cops.q = 0; + } else if (res) { return res; + } if (tx_lo) { res = res ? res : lms6002d_tune_pll(&d->lms, true, tx_lo); if (res == -ERANGE) { @@ -1714,12 +1720,14 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) } if ((param & (USDR_CAL_TXLO | USDR_CAL_TXIQIMB)) && (tx_lo > 0)) { - if (rx_lo == 0) { + if (rx_lo == 0 || !d->rx_pwren) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, "RX frontend was down, powering up and performing DC alignment\n"); res = res ? res : _usdr_pwr_state(d, false, true); res = res ? res : usleep(500000); res = res ? res : lms6002d_tune_pll(&d->lms, false, 320e6); res = res ? res : usdr_calib_dc(d, true); res = res ? res : lms6002d_tune_pll(&d->lms, true, tx_lo); + res = res ? res : usdr_rxupdate_cal(d); } if (!externallb) { unsigned lb_path = 1; // TODO select RX path for LB @@ -1764,6 +1772,11 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration TXIQIMB(%c) ------------------\n", 'A' + channel); res = res ? res : lms6002d_set_txvga1_gain(&d->lms, 28); res = res ? res : calibrate_txiqimb(&cops); + if (res == -ENAVAIL) { + USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " TXIQIMB failed!\n"); + res = 0; + cops.i = cops.q = 0; + } res = res ? res : lms6002d_set_txvga1_gain(&d->lms, old_txvga1); if (res) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, " TXIQIMB failed: res=%d\n", res); From 211e53620699d4003b5e0323fb0db7bcd7c4733d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 1 May 2026 01:47:03 +0400 Subject: [PATCH 392/397] usdr: fix calibration for extended frequency --- src/lib/device/m2_lm6_1/usdr_ctrl.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 39546542..61ce555d 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -1604,15 +1604,15 @@ int usdrcal_set_nco_offset(void* param, int channel, int32_t freqoffset) } static -int usdrcal_init_calibrate(usdr_dev_t *d, struct calibrate_ops* ops, unsigned channel) +int usdrcal_init_calibrate(usdr_dev_t *d, struct calibrate_ops* ops, unsigned channel, unsigned rxlo, unsigned txlo) { ops->adcrate = d->adc_clk; ops->dacrate = d->dac_clk; ops->rxsamplerate = ops->adcrate / d->rxbb_decim; ops->txsamplerate = ops->dacrate / d->txbb_intr; - ops->rxfrequency = d->rfic_rx_lo; - ops->txfrequency = d->tx_lo; + ops->rxfrequency = rxlo; + ops->txfrequency = txlo; ops->channel = channel; ops->deflogdur = ops->rxsamplerate / 20e6; ops->defstop = -120000; @@ -1668,9 +1668,15 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) unsigned rx_lo = d->rx_lo; unsigned rfic_rx_lo = d->rfic_rx_lo; unsigned rfe_gain_lna_sel = (d->lms.rfe_gain_lna_sel & 0x30) >> 4; // Fixme! - res = res ? res : usdrcal_init_calibrate(d, &cops, channel); cops.coarse_mode = coarse; + if (tx_lo) + tx_lo -= d->tx_exten_lo; + if (rx_lo) + rx_lo -= d->rx_exten_lo; + + res = res ? res : usdrcal_init_calibrate(d, &cops, channel, rx_lo, tx_lo); + if ((param & USDR_CAL_RXLO) && (rx_lo > 0)) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration RXLO(%c) ------------------\n", 'A' + channel); } From aaa2d55ca940ca8a9aea190854cd7a325848f64d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 1 May 2026 03:06:18 +0400 Subject: [PATCH 393/397] usdr: handle proper samplerate settings --- src/lib/device/m2_lm6_1/m2_lm6_1.c | 1 + src/lib/device/m2_lm6_1/usdr_ctrl.c | 49 ++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/lib/device/m2_lm6_1/m2_lm6_1.c b/src/lib/device/m2_lm6_1/m2_lm6_1.c index fa7c7dc8..5eb2e819 100644 --- a/src/lib/device/m2_lm6_1/m2_lm6_1.c +++ b/src/lib/device/m2_lm6_1/m2_lm6_1.c @@ -1328,6 +1328,7 @@ int usdr_device_m2_lm6_1_create_stream(device_t* dev, const char* sid, const cha *out_handle = d->tx; // TODO: handle NCO changes + res = res ? res : usdr_tx_gen_set(&d->d, false, 0, 0, 0); res = res ? res : usdr_txupdate_cal(&d->d); } diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 61ce555d..561eedd7 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -63,7 +63,7 @@ enum usdr_rev000 { enum lms6_vios { LMS6_VIO_NORM = 1800, - LMS6_VIO_BOOST = 1950, + LMS6_VIO_BOOST = 1925, }; enum fpga_phy_regs { @@ -442,6 +442,7 @@ int usdr_set_lob_freq(struct usdr_dev *d, unsigned freqlob) } #define TARGET_RATE 30720000 +#define SAFE_RATE 60000000 int usdr_set_rxdccorr(usdr_dev_t *d, bool enable) { @@ -638,22 +639,27 @@ int usdr_set_samplerate_ex(struct usdr_dev *d, unsigned ind = 0; unsigned int_dec_x[] = { 1, 2, 4, 8, 16, 32 /*, 64, 128, 256 */ }; + // Use 50MSPS as safe range if (d->has_rxchain && d->has_txchain) { for (; ind < SIZEOF_ARRAY(int_dec_x); ind++) { - if (rate * int_dec_x[ind] >= TARGET_RATE) + if (rate * int_dec_x[ind] >= TARGET_RATE) { + if ((rate * int_dec_x[ind] > SAFE_RATE) && (ind > 0)) + ind--; + break; + } } rate *= int_dec_x[ind]; nfo.out = rate << 1; } - if (rate >= 60e6 && !d->vio_boost) { + if (rate >= 62e6 && !d->vio_boost) { USDR_LOG("UDEV", USDR_LOG_WARNING, "Boosting Vio to get stable samplerates over 60Msps\n"); res = res ? res : lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 3, LMS6_VIO_BOOST); d->vio_boost = true; - } else if (rate < 60e6 && d->vio_boost) { + } else if (rate < 62e6 && d->vio_boost) { res = res ? res : lp8758_vout_set(dev, d->subdev, I2C_BUS_LP8758, 3, LMS6_VIO_NORM); d->vio_boost = false; } @@ -1184,7 +1190,7 @@ int usdr_rfic_fe_set_freq(struct usdr_dev *d, if (res) return res; - if (stat.vco_cap_max >= 1) + if (stat.vco_cap_max >= 2) break; } if (res) @@ -1665,18 +1671,23 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) unsigned coarse = (((param & USDR_CAL_COARSE_1) == USDR_CAL_COARSE_1) ? 1 : 0) | (((param & USDR_CAL_COARSE_2) == USDR_CAL_COARSE_2) ? 2 : 0); unsigned tx_lo = d->tx_lo; - unsigned rx_lo = d->rx_lo; - unsigned rfic_rx_lo = d->rfic_rx_lo; + unsigned rx_lo = d->rfic_rx_lo; unsigned rfe_gain_lna_sel = (d->lms.rfe_gain_lna_sel & 0x30) >> 4; // Fixme! cops.coarse_mode = coarse; - if (tx_lo) + if (tx_lo) { tx_lo -= d->tx_exten_lo; - if (rx_lo) + } + if (rx_lo) { rx_lo -= d->rx_exten_lo; - + } res = res ? res : usdrcal_init_calibrate(d, &cops, channel, rx_lo, tx_lo); + if (d->tx_exten_lo) { + // Extend meas to fit RX + cops.txfrequency += 0.2 * cops.txsamplerate; + } + if ((param & USDR_CAL_RXLO) && (rx_lo > 0)) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_INFO, "------------------ Calibration RXLO(%c) ------------------\n", 'A' + channel); } @@ -1726,15 +1737,20 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) } if ((param & (USDR_CAL_TXLO | USDR_CAL_TXIQIMB)) && (tx_lo > 0)) { + bool tx_set = true; if (rx_lo == 0 || !d->rx_pwren) { USDR_LL_LOG(dev, "LMS6", USDR_LOG_WARNING, "RX frontend was down, powering up and performing DC alignment\n"); res = res ? res : _usdr_pwr_state(d, false, true); res = res ? res : usleep(500000); res = res ? res : lms6002d_tune_pll(&d->lms, false, 320e6); res = res ? res : usdr_calib_dc(d, true); - res = res ? res : lms6002d_tune_pll(&d->lms, true, tx_lo); res = res ? res : usdr_rxupdate_cal(d); + tx_set = false; + } + if (tx_set || d->tx_exten_lo) { + res = res ? res : lms6002d_tune_pll(&d->lms, true, cops.txfrequency); } + if (!externallb) { unsigned lb_path = 1; // TODO select RX path for LB res = res ? res : lms6002d_set_rx_path(&d->lms, lb_path); @@ -1795,13 +1811,16 @@ int usdr_calibrate(usdr_dev_t *d, unsigned channel, unsigned param, int* sarray) } if (!norestore) { - if (rfic_rx_lo > 0) { - res = res ? res : lms6002d_tune_pll(&d->lms, false, rfic_rx_lo); + if (d->tx_exten_lo) { + res = res ? res : lms6002d_tune_pll(&d->lms, true, tx_lo); + } + if (rx_lo > 0) { + res = res ? res : lms6002d_tune_pll(&d->lms, false, rx_lo); if (res == -ERANGE) { - USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore RX_LO=%.3f: out of range\n", rfic_rx_lo / 1e6); + USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore RX_LO=%.3f: out of range\n", rx_lo / 1e6); res = lms6002d_disable_pll(&d->lms, false); } else if (res == -ENOLCK) { - USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore RX_LO=%.3f: unable to lock PLL\n", rfic_rx_lo / 1e6); + USDR_LL_LOG(dev, "LMS6", USDR_LOG_ERROR, "Unable to restore RX_LO=%.3f: unable to lock PLL\n", rx_lo / 1e6); res = 0; } } else { From 96933815f6554960ae647b8b8f3d5754782fd40e Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Fri, 1 May 2026 03:07:00 +0400 Subject: [PATCH 394/397] usdr_dm_create: use hardware number of channels by default --- src/tools/usdr_dm_create.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tools/usdr_dm_create.c b/src/tools/usdr_dm_create.c index 318dd346..20b100e5 100644 --- a/src/tools/usdr_dm_create.c +++ b/src/tools/usdr_dm_create.c @@ -1106,7 +1106,7 @@ int main(UNUSED int argc, UNUSED char** argv) USDR_LOG(LOG_TAG, USDR_LOG_INFO, "Devices in the array: %d", devices); } - res = usdr_dme_get_u32(dev, "/ll/sdr/max_sw_rx_chans", &swchmax); + res = usdr_dme_get_u32(dev, "/ll/sdr/max_hw_rx_chans", &swchmax); if (res == 0) { if (!chl_tx.chmsk_alter) { chl_tx.chmsk = (1ULL << devices * swchmax) - 1; @@ -1425,8 +1425,6 @@ int main(UNUSED int argc, UNUSED char** argv) if (calibrate) { res = usdr_dme_set_uint(dev, "/dm/sdr/0/calibrate", calibrate); USDR_LOG(LOG_TAG, USDR_LOG_ERROR, "SDR Calibration done: %d\n", res); - - res = usdr_dme_findsetv_uint(dev, "/dm/sdr/0/", SIZEOF_ARRAY(dev_data), dev_data); } // Update BB freqs if set From f5de8f433f1eaa6de649cc42279dfb600feec32d Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 6 May 2026 04:11:53 +0400 Subject: [PATCH 395/397] xsdr: use TX offset for improved RXIMB calibration --- src/lib/cal/cal_lo_iqimb.c | 9 ++++++--- src/lib/cal/cal_lo_iqimb.h | 1 + src/lib/device/m2_lm6_1/usdr_ctrl.c | 2 ++ src/lib/device/m2_lm7_1/xsdr_ctrl.c | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib/cal/cal_lo_iqimb.c b/src/lib/cal/cal_lo_iqimb.c index 311eafe1..a7103be1 100644 --- a/src/lib/cal/cal_lo_iqimb.c +++ b/src/lib/cal/cal_lo_iqimb.c @@ -210,7 +210,7 @@ int _calibrate_iqimb_generic(struct calibrate_ops* ops, res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_RX | CORR_OP_SET_BW, required_bw * ops->rxbw_factor); res = res ? res : ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_BW, - freqoffset * ops->txbw_factor); + ABS(freqoffset) * ops->txbw_factor); res = res ? res : ops->set_nco_rx_offset(ops->param, ops->channel, rxreoff); res = res ? res : _calibrate_txpwr(ops, freqoffset, txcal, &pwr_r); @@ -263,11 +263,14 @@ int calibrate_rxiqimb(struct calibrate_ops* ops) ops->rxfrequency, freqoff, ops->rxiqimb_frac / (float)INT_MAX); res = ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_FREQ, - ops->rxfrequency + freqoff); + ops->rxfrequency + freqoff - ops->rxiqtmb_tx_off); if (res) return res; - return _calibrate_iqimb_generic(ops, false, 0, freqoff, -freqoff, _evaluate_rxaiq); + return _calibrate_iqimb_generic(ops, false, + ops->rxiqtmb_tx_off, + freqoff, + -freqoff, _evaluate_rxaiq); } diff --git a/src/lib/cal/cal_lo_iqimb.h b/src/lib/cal/cal_lo_iqimb.h index b9641a7c..95861994 100644 --- a/src/lib/cal/cal_lo_iqimb.h +++ b/src/lib/cal/cal_lo_iqimb.h @@ -44,6 +44,7 @@ struct calibrate_ops int rxtxlo_frac; int rxiqimb_frac; // Relative position (-1; 1) to feed test tx sig for RXIQIMB & TXLO int txiqimb_frac; // Relative position (-1; 1) to feed test tx sig for TXIQIMB + int rxiqtmb_tx_off; int coarse_mode; float rxbw_factor; // Extend RX bandwith from required observation frequency diff --git a/src/lib/device/m2_lm6_1/usdr_ctrl.c b/src/lib/device/m2_lm6_1/usdr_ctrl.c index 561eedd7..973ce076 100644 --- a/src/lib/device/m2_lm6_1/usdr_ctrl.c +++ b/src/lib/device/m2_lm6_1/usdr_ctrl.c @@ -1628,6 +1628,8 @@ int usdrcal_init_calibrate(usdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->rxtxlo_frac = ((uint64_t)INT_MAX + 1) / 9.0187; ops->rxiqimb_frac = ((uint64_t)INT_MAX + 1) / 5.1031; ops->txiqimb_frac = ((uint64_t)INT_MAX + 1) / 11.1076; + ops->rxiqtmb_tx_off = 0; + ops->coarse_mode = 0; ops->rxbw_factor = 2.45; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 039661c7..363a1ce7 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -2346,9 +2346,11 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->param = d; // Make very odd fraction not to fall harmonics into the same bins after nyquist - ops->rxtxlo_frac = ((uint64_t)INT_MAX + 1) / 9.0187; + ops->rxtxlo_frac = ((uint64_t)INT_MAX + 1) / 23.0187; //((uint64_t)INT_MAX + 1) / 9.0187; ops->rxiqimb_frac = ((uint64_t)INT_MAX + 1) / 5.1031; ops->txiqimb_frac = ((uint64_t)INT_MAX + 1) / 11.1076; + ops->rxiqtmb_tx_off = -ops->rxsamplerate / 7; + ops->coarse_mode = 0; ops->rxbw_factor = 2.33; From 090fe9c6240b10a56d34da69699b2e6cdab7f673 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Wed, 6 May 2026 05:09:42 +0400 Subject: [PATCH 396/397] soapy: add calibration option for tx/rx examples --- src/soapysdr/usdr_soapy.cpp | 4 ++-- src/tools/python/example_fft_rx_soapy.py | 6 +++++- src/tools/python/example_fft_tx_soapy.py | 6 ++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/soapysdr/usdr_soapy.cpp b/src/soapysdr/usdr_soapy.cpp index 0bbad858..0cfd5600 100644 --- a/src/soapysdr/usdr_soapy.cpp +++ b/src/soapysdr/usdr_soapy.cpp @@ -1027,9 +1027,9 @@ void SoapyUSDR::writeSetting(const std::string &key, const std::string &value) if (res) { throw std::invalid_argument("SoapyUSDR::writeSetting("+key+") failed"); } + } else { + throw std::runtime_error("unknown setting key: " + key); } - - throw std::runtime_error("unknown setting key: " + key); } SoapySDR::ArgInfoList SoapyUSDR::getSettingInfo(const int direction, const size_t channel) const diff --git a/src/tools/python/example_fft_rx_soapy.py b/src/tools/python/example_fft_rx_soapy.py index f83f4d25..0396725a 100755 --- a/src/tools/python/example_fft_rx_soapy.py +++ b/src/tools/python/example_fft_rx_soapy.py @@ -44,6 +44,7 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--window", default="hann", help="Scipy window name (e.g. hann, blackman, flattop)") parser.add_argument("--channel", type=int, default=0, help="RX channel index") parser.add_argument("--timeout-ms", type=int, default=1000, help="Receive timeout in milliseconds") + parser.add_argument("--calibrate", action="store_true", help="Enable LO & IQ Imbalance calibration") return parser.parse_args() @@ -102,6 +103,9 @@ def main() -> None: timeout_us = int(args.timeout_ms * 1000) + if args.calibrate: + dev.writeSetting("calibrate", "rx") + # Receive and accumulate FFT frames for _ in range(int(args.accumulation)): buf = aligned_empty((fft_size,), np.complex64, alignment=64) @@ -121,7 +125,7 @@ def main() -> None: dev.closeStream(rx_stream) # Close device - if dev.close is not None: + if hasattr(dev, 'close'): dev.close() # Not strictly necessary, but good practice dev = None diff --git a/src/tools/python/example_fft_tx_soapy.py b/src/tools/python/example_fft_tx_soapy.py index 8155ff78..6d012da3 100755 --- a/src/tools/python/example_fft_tx_soapy.py +++ b/src/tools/python/example_fft_tx_soapy.py @@ -44,7 +44,7 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--num-bursts", type=int, default=128, help="Number of bursts to transmit (0 = infinite)") parser.add_argument("--channel", type=int, default=0, help="TX channel index") parser.add_argument("--timeout-ms", type=int, default=1000, help="Write timeout in milliseconds") - + parser.add_argument("--calibrate", action="store_true", help="Enable LO & IQ Imbalance calibration") return parser.parse_args() @@ -126,6 +126,8 @@ def main() -> None: print(f" samplerate={args.samplerate:.0f} amplitude={args.amplitude} " f"burst_size={burst_size} num_bursts={'inf' if infinite else num_bursts}") + if args.calibrate: + dev.writeSetting("calibrate", "tx") # Transmit sine-wave bursts burst_idx = 0 try: @@ -154,7 +156,7 @@ def main() -> None: dev.closeStream(tx_stream) # Close device - if dev.close is not None: + if hasattr(dev, 'close'): dev.close() # Not strictly necessary, but good practice dev = None From e40c721a79b4653272e5e4b49116f411cfc063a4 Mon Sep 17 00:00:00 2001 From: Sergey Kostanbaev Date: Thu, 7 May 2026 03:23:24 +0400 Subject: [PATCH 397/397] xsdr: improve calibration --- src/lib/cal/cal_filt.c | 205 ++++++++++++++++ src/lib/cal/cal_filt.h | 24 ++ src/lib/cal/cal_lo_iqimb.c | 6 +- src/lib/device/m2_lm7_1/lms7002m_ctrl.c | 13 +- src/lib/device/m2_lm7_1/m2_lm7_1.c | 39 +++ src/lib/device/m2_lm7_1/xsdr_ctrl.c | 313 ++++++++++++++++++++---- src/lib/device/m2_lm7_1/xsdr_ctrl.h | 7 +- src/lib/hw/lms7002m/lms7002m.c | 88 ++++++- src/lib/hw/lms7002m/lms7002m.h | 6 + 9 files changed, 640 insertions(+), 61 deletions(-) diff --git a/src/lib/cal/cal_filt.c b/src/lib/cal/cal_filt.c index e69de29b..47d7f2c0 100644 --- a/src/lib/cal/cal_filt.c +++ b/src/lib/cal/cal_filt.c @@ -0,0 +1,205 @@ +#include "cal_filt.h" +#include "opt_func.h" +#include "math.h" + +void convert_dump12_to_cfloat(const uint32_t* in, cfolat64_t* o, unsigned size) +{ + for (unsigned i = 0; i < size; i++) { + int16_t ii = (uint16_t)((in[i] & 0xfff) << 4); + int16_t iq = (uint16_t)(((in[i] >> 12) & 0xfff) << 4); + o[i].i = ii / 32768.0; + o[i].q = iq / 32768.0; + } +} + +void cal_remove_dc(cfolat64_t* d, const unsigned size, float* pavg_i, float* pavg_q) +{ + float ai = 0, aq = 0; + for (unsigned i = 0; i < size; i++) { + ai += d[i].i; + aq += d[i].q; + } + ai /= size; + aq /= size; + + for (unsigned i = 0; i < size; i++) { + d[i].i -= ai; + d[i].q -= aq; + } + + if (pavg_i) + *pavg_i = ai; + if (pavg_q) + *pavg_q = aq; +} + + +void calculate_mean_s_std(const cfolat64_t* d, const unsigned size, float* m, float* di) +{ + float tmp[size]; + float mean_s = 0; + float std_s = 0; + + for (unsigned i = 0; i < size; i++) { + float v = sqrt(d[i].i * d[i].i + d[i].q * d[i].q); + tmp[i] = v; + mean_s += v; + } + mean_s /= size; + + for (unsigned i = 0; i < size; i++) { + float v = tmp[i]; + std_s += (v - mean_s) * (v - mean_s); + } + std_s /= size; + + *m = mean_s; + *di = sqrt(std_s); +} + +void cal_generate_iq(cfolat64_t* d, const unsigned size, float amp, float period, float ph) +{ + for (unsigned i = 0; i < size; i++) { + float s, c; + float phase = ph + 2 * M_PI * i / period; + sincosf(phase, &s, &c); + + d[i].i = s * amp; + d[i].q = c * amp; + } +} + +float _cal_mse_fit(const cfolat64_t* d, const unsigned size, float amp, float period, float ph) +{ + cfolat64_t sig[size]; + cal_generate_iq(sig, size, amp, period, ph); + + float err = 0; + for (unsigned i = 0; i < size; i++) { + err += sqrt((d[i].i - sig[i].i) * (d[i].i - sig[i].i) + (d[i].q - sig[i].q) * (d[i].q - sig[i].q)); + } + return err; +} + +struct evaluate_mse_fit { + const cfolat64_t* orig; + unsigned size; + float amp; + float period; + float phase; + + float scale_phase; + float scale_period; + float scale_result; +}; +typedef struct evaluate_mse_fit evaluate_mse_fit_t; + +static int _evaluate_mse_fit_fn(void* param, int value, int* func) +{ + evaluate_mse_fit_t* p = (evaluate_mse_fit_t*)param; + float ph = value * p->scale_phase; + float res = _cal_mse_fit(p->orig, p->size, p->amp, p->period, ph); + *func = res * p->scale_result; + return 0; +} + +void cal_find_best_fit(const cfolat64_t* d, const unsigned size, float amp, float period, float* mse_min, float* phase_opt) +{ + const unsigned ph_steps = 1024; + evaluate_mse_fit_t fd; + int phase; + int mse_val; + + fd.orig = d; + fd.size = size; + fd.amp = amp; + fd.period = period; + + fd.scale_phase = 2 * M_PI / ph_steps; + fd.scale_result = 1000; + + find_golden_min(0, ph_steps - 1, &fd, &_evaluate_mse_fit_fn, &phase, &mse_val, 0); + + *mse_min = mse_val / fd.scale_result; + *phase_opt = phase * fd.scale_phase; +} + + +static int _evaluate_mse_fit_pp_fn(void* param, int val_param, int value, int* func) +{ + evaluate_mse_fit_t* p = (evaluate_mse_fit_t*)param; + if (val_param == 0) { + p->phase = value * p->scale_phase; + } else { + p->period = value / p->scale_period; + } + + if (func == NULL) + return 0; + + float res = _cal_mse_fit(p->orig, p->size, p->amp, p->period, p->phase); + *func = res * p->scale_result; + return 0; +} + +void cal_find_best_fit_ph_per(const cfolat64_t* d, const unsigned size, float amp, float *period_opt, float* mse_min, float* phase_opt) +{ + const unsigned ph_steps = 1024; + const unsigned STEPS = 2; + evaluate_mse_fit_t fd; + struct opt_iteration2d o[STEPS]; + + int phase; + int period; + int mse_val; + + fd.orig = d; + fd.size = size; + fd.amp = amp; + fd.period = 0; + fd.phase = 0; + + fd.scale_phase = 2 * M_PI / ph_steps; + fd.scale_result = 10000; + fd.scale_period = 100; + + for (unsigned i = 0; i < STEPS; i++) { + o[i].limit[0].min = 0; + o[i].limit[0].max = ph_steps - 1; + o[i].limit[1].min = 8 * fd.scale_period; + o[i].limit[1].max = 384 * fd.scale_period; + o[i].func = _evaluate_mse_fit_pp_fn; + o[i].sf = &find_golden_min; + o[i].exparam = 0; + } + + find_best_2d(&o[0], SIZEOF_ARRAY(o), &fd, 0, &phase, &period, &mse_val); + + *mse_min = mse_val / fd.scale_result; + *phase_opt = phase * fd.scale_phase; + *period_opt = period / fd.scale_period; +} + +float cal_max_amp_error(const cfolat64_t* d, const unsigned size, float amp, float period, float ph) +{ + cfolat64_t sig[size]; + cal_generate_iq(sig, size, amp, period, ph); + + float err = 0; + for (unsigned i = 0; i < size; i++) { + float d_i = (d[i].i - sig[i].i); + float d_q = (d[i].q - sig[i].q); + + if (d_i < 0) + d_i = -d_i; + if (d_q < 0) + d_q = -d_q; + + if (err < d_i) + err = d_i; + if (err < d_q) + err = d_q; + } + return err; +} + diff --git a/src/lib/cal/cal_filt.h b/src/lib/cal/cal_filt.h index e69de29b..d1495841 100644 --- a/src/lib/cal/cal_filt.h +++ b/src/lib/cal/cal_filt.h @@ -0,0 +1,24 @@ +#ifndef CAL_FILT_H +#define CAL_FILT_H + +#include + +struct cfolat64 { + float i, q; +}; +typedef struct cfolat64 cfolat64_t; + +void convert_dump12_to_cfloat(const uint32_t* in, cfolat64_t* o, unsigned size); +void calculate_mean_s_std(const cfolat64_t* d, const unsigned size, float* m, float* di); + +void cal_generate_iq(cfolat64_t* d, const unsigned size, float amp, float period, float ph); +void cal_remove_dc(cfolat64_t* d, const unsigned size, float* pavg_i, float* pavg_q); + +void cal_find_best_fit(const cfolat64_t* d, const unsigned size, float amp, float period, float* mse_min, float *phase); +void cal_find_best_fit_ph_per(const cfolat64_t* d, const unsigned size, float amp, float *period_opt, float* mse_min, float* phase_opt); + + +float cal_max_amp_error(const cfolat64_t* d, const unsigned size, float amp, float period, float ph); + + +#endif diff --git a/src/lib/cal/cal_lo_iqimb.c b/src/lib/cal/cal_lo_iqimb.c index a7103be1..3af7f0c7 100644 --- a/src/lib/cal/cal_lo_iqimb.c +++ b/src/lib/cal/cal_lo_iqimb.c @@ -259,8 +259,10 @@ int calibrate_rxiqimb(struct calibrate_ops* ops) // Set RX to be TXLO - sampl int32_t freqoff = (((int64_t)ops->rxsamplerate * ops->rxiqimb_frac) >> 31); - USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_RXIQIMB: Set RX measeure freq %d - %d (from %.3f)\n", - ops->rxfrequency, freqoff, ops->rxiqimb_frac / (float)INT_MAX); + USDR_LOG("UDEV", USDR_LOG_WARNING, "CAL_RXIQIMB: Set RX measeure freq %u - %d = %.3f Mhz (from %.3f)\n", + ops->rxfrequency, freqoff, + ((unsigned)ops->rxfrequency + freqoff - ops->rxiqtmb_tx_off) / 1e6, + ops->rxiqimb_frac / (float)INT_MAX); res = ops->set_corr_param(ops->param, ops->channel, CORR_DIR_TX | CORR_OP_SET_FREQ, ops->rxfrequency + freqoff - ops->rxiqtmb_tx_off); diff --git a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c index 8fa7b929..378a3534 100644 --- a/src/lib/device/m2_lm7_1/lms7002m_ctrl.c +++ b/src/lib/device/m2_lm7_1/lms7002m_ctrl.c @@ -549,6 +549,15 @@ int lms7002m_bb_set_badwidth(lms7002_dev_t *d, else if (channel == LMS7_CH_B && j == LMS7_CH_A) continue; + if (bw == 0) { + if (!dir_tx) { + opt_u32_set_null(&d->rx_bw[(j == LMS7_CH_A) ? 0 : 1]); + } else { + opt_u32_set_null(&d->tx_bw[(j == LMS7_CH_A) ? 0 : 1]); + } + continue; + } + res = lms7002m_mac_set(&d->lmsstate, j); if (res) return res; @@ -1058,8 +1067,8 @@ int lms7002m_samplerate(lms7002_dev_t *d, cfg.rxdiv = rxtsp_div; cfg.rxsisoddr = sisoddr_rx; cfg.txsisoddr = sisoddr_tx; - cfg.txtspdelay = (txrate < 45e6) ? 3 : (txrate < 99e6) ? 1 : 0; - cfg.txlmldelay = (txrate < 45e6) ? 0 : (txrate < 99e6) ? 3 : 0; + cfg.txtspdelay = (txrate > 40e6 && txrate < 45e6) ? 2 : 1; // (txrate < 45e6) ? 3 : (txrate < 99e6) ? 1 : 0; + cfg.txlmldelay = 0; //(txrate < 45e6) ? 0 : (txrate < 99e6) ? 3 : 0; res = lms7002m_limelight_configure(&d->lmsstate, cfg); if (res) diff --git a/src/lib/device/m2_lm7_1/m2_lm7_1.c b/src/lib/device/m2_lm7_1/m2_lm7_1.c index efa5dd48..2fcdac06 100644 --- a/src/lib/device/m2_lm7_1/m2_lm7_1.c +++ b/src/lib/device/m2_lm7_1/m2_lm7_1.c @@ -243,6 +243,8 @@ static int dev_m2_lm7_1_dev_atcrbs_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64 static int dev_m2_lm7_1_dev_dac_vctcxo_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_phyrxlm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_checkrxtx_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_dumpcaldata_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static int dev_m2_lm7_1_phy_rx_lfsr_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); @@ -270,6 +272,9 @@ static int dev_m2_lm7_1_lms8_switchover_set(pdevice_t ud, pusdr_vfs_obj_t obj, u static int dev_m2_lm7_1_lms8_switchover_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t *ovalue); static int dev_m2_lm7_1_sdr_vio_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); +static int dev_m2_lm7_1_bb_loopback_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); + +static int dev_m2_lm7_1_dumprx_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value); static const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { @@ -279,6 +284,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/debug/all", { NULL, dev_m2_lm7_1_debug_all_get }}, { "/dm/power/en", { dev_m2_lm7_1_pwren_set, NULL }}, + { "/dm/sdr/0/dumprx", { dev_m2_lm7_1_dumprx_set, NULL }}, + { "/dm/sdr/channels", { NULL, NULL }}, { "/dm/sensor/temp", { NULL, dev_m2_lm7_1_senstemp_get }}, @@ -293,6 +300,8 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/lms8_intmode", { dev_m2_lm7_1_lms8_intmode_set, dev_m2_lm7_1_lms8_intmode_get }}, { "/dm/sdr/0/lms8_switchover", { dev_m2_lm7_1_lms8_switchover_set, dev_m2_lm7_1_lms8_switchover_get }}, + { "/dm/sdr/0/bb/loopback", { dev_m2_lm7_1_bb_loopback_set, NULL }}, + { "/dm/sdr/0/tx/phase_ovr", { dev_m2_lm7_1_sdr_tx_phase_ovr_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr_iq", { dev_m2_lm7_1_sdr_tx_phase_ovr_iq_set, NULL }}, { "/dm/sdr/0/tx/phase_ovr_rc", { dev_m2_lm7_1_sdr_tx_phase_ovr_rc_set, NULL }}, @@ -376,6 +385,9 @@ const usdr_dev_param_func_t s_fparams_m2_lm7_1_rev000[] = { { "/dm/sdr/0/phy_tx_iqsel", { dev_m2_lm7_1_phy_tx_iqsel_set, NULL }}, { "/dm/sdr/0/phyrxlml", { dev_m2_lm7_1_phyrxlm_set, NULL }}, + { "/dm/sdr/0/checkrxtx", { dev_m2_lm7_1_checkrxtx_set, NULL }}, + { "/dm/sdr/0/dumpcaldata", { dev_m2_lm7_1_dumpcaldata_set, NULL }}, + { "/debug/hw/lms7002m/0/rxlml", { dev_m2_lm7_1_lms7002rxlml_set, NULL }}, { "/debug/clk_info", { dev_m2_lm7_1_debug_clkinfo_set, NULL }}, @@ -579,6 +591,17 @@ int dev_m2_lm7_1_phyrxlm_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) return xsdr_phy_tune_rx(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); } +int dev_m2_lm7_1_checkrxtx_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return xsdr_check_rxtx_quality(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); +} + +int dev_m2_lm7_1_dumpcaldata_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + ((struct dev_m2_lm7_1_gps *)ud)->xdev.dump_cal_data = value; + return 0; +} + int dev_m2_lm7_1_phy_rx_dly_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) { unsigned type = (value >> 8) & 0x1f; @@ -604,6 +627,19 @@ int dev_m2_lm7_1_phy_tx_iqsel_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t va return xsdr_phy_tx_iqsel(&((struct dev_m2_lm7_1_gps *)ud)->xdev, value); } +int dev_m2_lm7_1_bb_loopback_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + return xsdr_bb_loopback(&((struct dev_m2_lm7_1_gps *)ud)->xdev); +} + +int dev_m2_lm7_1_dumprx_set(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t value) +{ + struct dev_m2_lm7_1_gps *d = (struct dev_m2_lm7_1_gps *)ud; + uint32_t cha[128]; + uint32_t chb[128]; + + return xsdr_capture_rxiq(&d->xdev, cha, chb); +} int dev_m2_lm7_1_phy_rx_lfsr_get(pdevice_t ud, pusdr_vfs_obj_t obj, uint64_t* ovalue) { @@ -1588,6 +1624,9 @@ int usdr_device_m2_lm7_1_create_stream(device_t* dev, const char* sid, const cha *out_handle = d->tx; res = res ? res : xsdr_hwchans_cnt(&d->xdev, false, hwchs); + res = res ? res : lms7002m_mac_set(&d->xdev.base.lmsstate, LMS7_CH_AB); + res = res ? res : lms7002m_xxtsp_bst(&d->xdev.base.lmsstate, LMS_TXTSP); + res = res ? res : lms7002m_dc_corr_en(&d->xdev.base.lmsstate, d->xdev.base.rx_run[0], d->xdev.base.rx_run[1], d->xdev.base.tx_run[0], d->xdev.base.tx_run[1]); } diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.c b/src/lib/device/m2_lm7_1/xsdr_ctrl.c index 363a1ce7..9f85450f 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.c +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.c @@ -1,6 +1,7 @@ // Copyright (c) 2023-2024 Wavelet Lab // SPDX-License-Identifier: MIT +#include #include "xsdr_ctrl.h" #include "../hw/lp8758/lp8758.h" @@ -17,6 +18,7 @@ #include #include "../cal/cal_lo_iqimb.h" +#include "../cal/cal_filt.h" #include "../ipblks/streams/sfe_rx_4.h" #include "../ipblks/xlnx_mmcm.h" #include "../ipblks/fgearbox.h" @@ -157,6 +159,8 @@ enum { PHY_REG_PORT_IQSEL = 5, PHY_REG_LFSR_GEN = 6, PHY_REG_IQAB_GEN = 7, + PHY_REG_IQAB_PSHA = 8, + PHY_REG_IQAB_PSHB = 9, }; enum { @@ -243,7 +247,9 @@ int xsdr_phy_capture_get(xsdr_dev_t *d, bool chb, unsigned count, uint32_t* odat { int res = 0; for (unsigned i = 0; i < count; i++) { - res = res ? res : xsdr_phy_capture_get_item(d, chb, i, &odata[i]); + do { + res = res ? res : xsdr_phy_capture_get_item(d, chb, i, &odata[i]); + } while (!res && odata[i] >> 24); } return res; } @@ -304,6 +310,38 @@ int xsdr_phy_en_lfsr_generator_mimo(xsdr_dev_t *d, bool en, bool lfsr) return res; } +int xsdr_phy_load_iqab_check(xsdr_dev_t *d) +{ + int res = 0; + for (unsigned u = 0; u < 32; u++) { + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_IQAB_PSHA, 0xBBE441); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_IQAB_PSHB, 0x5A5969); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_IQAB_PSHA, 0xC42676); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_IQAB_PSHB, 0xF0F356); + } + return res; +} + +int xsdr_phy_load_sincos_64(xsdr_dev_t *d, uint32_t amp) +{ + int res = 0; + const unsigned P = 64; + for (unsigned u = 0; u < P; u++) { + float s, c; + float phase = 2 * M_PI * u / P; + sincosf(phase, &s, &c); + + int32_t i_s = amp * s; + int32_t i_c = amp * c; + // Chane I and Q since we load in reverse order + uint32_t data = ((i_s & 0xfff) << 12) | (i_c & 0xfff); + + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_IQAB_PSHA, data); + res = res ? res : xsdr_phy_tx_reg(d, PHY_REG_IQAB_PSHB, data); + } + return res; +} + static int _xsdr_rxserdes_reset(xsdr_dev_t *d) { int res = 0; unsigned sisosdrflag = d->dpump ? 16 : d->base.lml_mode.rxsisoddr ? 8 : 0; @@ -632,7 +670,7 @@ int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v) static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, unsigned errs[4], unsigned *piqserrs, - uint64_t *pbadness) + uint64_t *pbadness, unsigned *cycles) { int res = 0; unsigned w; @@ -649,14 +687,26 @@ static int _xsdr_calibrate_txlfsr_check(xsdr_dev_t *d, unsigned check_to, for (w = 0; w < check_to; w++) { res = res ? res : usleep(100); res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); - res = res ? res : xsdr_phy_lfsr_mimo_state_s(d, LFSR_CNTR_IQS << 2, piqserrs); - if (res || (d->dpump ? !noerrors_v2(errs, pbadness) : !noerrors_v4(errs, pbadness)) || *piqserrs) { + if (res || (d->dpump ? !noerrors_v2(errs, pbadness) : !noerrors_v4(errs, pbadness)) /*|| *piqserrs*/) { break; } } + + res = res ? res : xsdr_phy_lfsr_mimo_state_s(d, LFSR_CNTR_IQS << 2, piqserrs); + *pbadness *= 1.0 * check_to / (w + 1); // Rescale + if (cycles) + *cycles = w; + return res; +} - return 0; +int xsdr_bb_loopback(xsdr_dev_t *d) +{ + int res = 0; + res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); + res = res ? res : lms7002m_tbb_path(&d->base.lmsstate, TBB_LAD, TBB_MODE_LOOPBACK); + res = res ? res : lms7002m_rbb_path(&d->base.lmsstate, RBB_BYP, RBB_MODE_LOOPBACK); + return res; } static int _xsdr_calibrate_lml(xsdr_dev_t *d) @@ -833,6 +883,8 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) if (mmcm_rx_only_path) goto no_tx; + res = res ? res : xsdr_phy_load_iqab_check(d); + res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_DIGLOOPBACK); res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, true); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); @@ -846,10 +898,12 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) for (unsigned rty = 0; rty < 8; rty++) { const unsigned iq_phases[8] = { 0, 1, 2, 62, 63, 2, 1, 0}; unsigned iq_ph = iq_phases[rty]; + int good_start = -1; + const unsigned check_txto = 35; // Once we change VCO frequency RX calibration becomes invalid and we need to adjust it for (unsigned ph = 1; ph < 4*63 + 1; ph++) { - //unsigned w; + unsigned w = 0; uint64_t badness = UINT64_MAX; res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, ph, 0 /*iq_ph*/); if (check_rx) { @@ -858,8 +912,15 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : _xsdr_rxserdes_reset(d); res = res ? res : usleep(10); res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, true); - res = res ? res : usleep(100); - res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + for (w = 0; w < check_to; w++) { + res = res ? res : usleep(100); + res = res ? res : xsdr_phy_lfsr_mimo_state(d, LFSR_CNTR_BER, errs); + if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { + break; + } + } + badness *= 1.0 * check_to / (w + 1); // Rescale + if (res || (d->dpump ? !noerrors_v2(errs, &badness) : !noerrors_v4(errs, &badness))) { USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "FAIL_PHASE_RX=%2d PH=%2d [%6d/%6d/%6d/%6d] BD=%lld\n", d->lmlcal_rx_phase, ph - 1, errs[0], errs[1], errs[2], errs[3], (long long)badness); @@ -881,13 +942,17 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_DIGLOOPBACK); failed_rxcnt = 0; } - res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness); + res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_txto, errs, &iqserrs, &badness, &w); - USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e\n", ph - 1, - errs[0], errs[1], errs[2], errs[3], iqserrs, (double)badness); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_INFO, "PHASE_TX=%2d [%6d/%6d/%6d/%6d - %6d] BD=%.3e CNT=%d\n", ph - 1, + errs[0], errs[1], errs[2], errs[3], iqserrs, (double)badness, w); if (res || (d->dpump ? noerrors_v2(errs, &badness) : noerrors_v4(errs, &badness) /* && (iqserrs == 0)*/) || (rty > 1 && badness < 20)) { phase_m = ph; + if (good_start < 0) { + good_start = ph - 1; + } + for (int g = 0; g < 24; g++) { // Check A/B & I/Q aligment is ok res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); @@ -968,7 +1033,7 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_configure_lml_mmcm_tx(d, mmcx_rx_path, d->lmlcal_rx_phase, phase_m, ph_ty_m); // Make sure it's a good value - res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness_m); + res = res ? res : _xsdr_calibrate_txlfsr_check(d, check_to, errs, &iqserrs, &badness_m, NULL); // Check A/B & I/Q aligment is ok res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); @@ -991,8 +1056,12 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) res = res ? res : xsdr_phy_en_lfsr_checker_mimo(d, false); res = res ? res : lms7002m_set_lmlrx_mode(&d->base, XSDR_LMLRX_NORMAL); - // Sometimes TxTSP can get off by 1TSP clock, we need to preventevly reset the path res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); + // Reset TXP block since we may had clock discontinuity + res = res ? res : lms7002m_xxtsp_reset(&d->base.lmsstate, LMS_TXTSP); + res = res ? res : lms7002m_xxtsp_reset(&d->base.lmsstate, LMS_RXTSP); + + // Sometimes TxTSP can get off by 1TSP clock, we need to preventevly reset the path res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_TXTSP); res = res ? res : lms7002m_xxtsp_bst(&d->base.lmsstate, LMS_RXTSP); } @@ -1021,6 +1090,106 @@ static int _xsdr_calibrate_lml(xsdr_dev_t *d) return res; } +#define CAPTURE_SIZE 128 +int xsdr_capture_rxiq(xsdr_dev_t* d, uint32_t *cha, uint32_t *chb) +{ + uint32_t tmp_a[CAPTURE_SIZE]; + uint32_t tmp_b[CAPTURE_SIZE]; + unsigned w, q; + + int i_a[CAPTURE_SIZE]; + int q_a[CAPTURE_SIZE]; + int i_b[CAPTURE_SIZE]; + int q_b[CAPTURE_SIZE]; + memset(i_a, 0, sizeof(i_a)); + memset(q_a, 0, sizeof(q_a)); + memset(i_b, 0, sizeof(i_b)); + memset(q_b, 0, sizeof(q_b)); + + const unsigned acc = 8; + for (w = 0; w < (1 << acc); w++) { + // 64 points @40msps -- 1 + xsdr_phy_capture_start(d, 1); + usleep(10); + xsdr_phy_capture_start(d, 0); + xsdr_phy_capture_get(d, 0, CAPTURE_SIZE, tmp_a); + xsdr_phy_capture_get(d, 1, CAPTURE_SIZE, tmp_b); + + for (q = 0; q < CAPTURE_SIZE; q++) { + int16_t a_ii = (uint16_t)((tmp_a[q] & 0xfff) << 4); + int16_t a_iq = (uint16_t)(((tmp_a[q] >> 12) & 0xfff) << 4); + + int16_t b_ii = (uint16_t)((tmp_b[q] & 0xfff) << 4); + int16_t b_iq = (uint16_t)(((tmp_b[q] >> 12) & 0xfff) << 4); + + i_a[q] += a_ii; + q_a[q] += a_iq; + + i_b[q] += b_ii; + q_b[q] += b_iq; + } + } + + const unsigned shift = 4 + acc; + for (q = 0; q < CAPTURE_SIZE; q++) { + cha[q] = ((i_a[q] >> shift) & 0xfff) | (((q_a[q] >> shift) & 0xfff) << 12); + chb[q] = ((i_b[q] >> shift) & 0xfff) | (((q_b[q] >> shift) & 0xfff) << 12); + } + + if (!d->dump_cal_data) + return 0; + + for (unsigned j = 0; j < CAPTURE_SIZE; j++) { + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_ERROR, "%d: %08x %08x\n", j, cha[j], chb[j]); + } + return 0; +} + +int xsdr_check_tx_quality(xsdr_dev_t* d, unsigned chmsk, unsigned period, float* score) +{ + uint32_t cha[CAPTURE_SIZE], chb[CAPTURE_SIZE]; + int res = 0; + cfolat64_t fcha[CAPTURE_SIZE], fchb[CAPTURE_SIZE]; + float a_amp, a_div, b_amp, b_div; + lldev_t dev = d->base.lmsstate.dev; + float scale = 2048; + float mse_min_a, mse_min_b; + float phase_a, phase_b; + float avg_i_a, avg_q_a, avg_i_b, avg_q_b; + + res = res ? res : xsdr_capture_rxiq(d, cha, chb); + + convert_dump12_to_cfloat(cha, fcha, CAPTURE_SIZE); + convert_dump12_to_cfloat(chb, fchb, CAPTURE_SIZE); + + cal_remove_dc(fcha, CAPTURE_SIZE, &avg_i_a, &avg_q_a); + cal_remove_dc(fchb, CAPTURE_SIZE, &avg_i_b, &avg_q_b); + + calculate_mean_s_std(fcha, CAPTURE_SIZE, &a_amp, &a_div); + calculate_mean_s_std(fchb, CAPTURE_SIZE, &b_amp, &b_div); + + cal_find_best_fit(fcha, CAPTURE_SIZE, a_amp, period, &mse_min_a, &phase_a); + cal_find_best_fit(fchb, CAPTURE_SIZE, b_amp, period, &mse_min_b, &phase_b); + + float d_i_a = cal_max_amp_error(fcha, CAPTURE_SIZE, a_amp, period, phase_a); + float d_i_b = cal_max_amp_error(fchb, CAPTURE_SIZE, b_amp, period, phase_b); + + float r_amp_a = a_div / a_amp, r_amp_b = b_div / b_amp; + float r_di_a = d_i_a / a_amp, r_di_b = d_i_b / b_amp; + float r_mse_a = mse_min_a / CAPTURE_SIZE / a_amp, r_mse_b = mse_min_b / CAPTURE_SIZE / b_amp; + float norm_a = sqrt(r_amp_a*r_amp_a + r_di_a*r_di_a + r_mse_a*r_mse_a); + float norm_b = sqrt(r_amp_b*r_amp_b + r_di_b*r_di_b + r_mse_b*r_mse_b); + + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "CHA: { A=%.1f D=%.3f MSE=%.3f I=%.3f [%.1f %.1f] => %.4f} CHB: { A=%.1f D=%.3f MSE=%.3f I=%.3f [%.1f %.1f] => %.4f}\n", + a_amp * scale, a_div * scale, mse_min_a, d_i_a * scale, avg_i_a * scale, avg_q_a * scale, norm_a, + b_amp * scale, b_div * scale, mse_min_b, d_i_b * scale, avg_i_b * scale, avg_q_b * scale, norm_b + ); + + *score = norm_a; + return res; +} + + int xsdr_reset_extfe(xsdr_dev_t *d) { lldev_t dev = d->base.lmsstate.dev; @@ -1030,6 +1199,44 @@ int xsdr_reset_extfe(xsdr_dev_t *d) return res; } +int xsdr_check_rxtx_quality(xsdr_dev_t *d, int fix) +{ + // Set IQ gen, to check TSPCLK alignment + float score = 1e6; + unsigned period = 64; + int res = 0; + unsigned i; + + res = res ? res : xsdr_phy_load_sincos_64(d, 2000); + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, true, false); + res = res ? res : xsdr_bb_loopback(d); + + for (i = 0; i < 8; i++) { + res = res ? res : xsdr_check_tx_quality(d, 3, period, &score); + if (score < 0.025 || !fix || res) + break; + + res = res ? res : lms7002m_limelight_toggle_tsp_clk(&d->base.lmsstate, d->base.lml_mode, 0); + res = res ? res : usleep(1); + res = res ? res : lms7002m_limelight_toggle_tsp_clk(&d->base.lmsstate, d->base.lml_mode, 1); + res = res ? res : usleep(100); + + if (i > 1) { + d->base.lml_mode.txtspdelay++; + res = res ? res : lms7002m_limelight_upd_delay(&d->base.lmsstate, d->base.lml_mode); + } + } + + if (i > 0) { + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_WARNING, "Toggled count: %d\n", i); + } + + res = res ? res : xsdr_phy_en_lfsr_generator_mimo(d, false, false); + res = res ? res : lms7002m_update_bandwidth(&d->base, true, d->s_txrate / d->s_tx_int, true); + res = res ? res : lms7002m_update_bandwidth(&d->base, false, d->s_rxrate / d->s_rx_dec, true); + return res; +} + static int _xsdr_update_fe_dsp(xsdr_dev_t *d) { int res = 0; @@ -1047,6 +1254,10 @@ static int _xsdr_update_fe_dsp(xsdr_dev_t *d) d->s_rx_dec = d->base.rx_dsp_decim; USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Updated RX FE DSP to %d decimation\n", d->s_rx_dec); + } else if (d->has_duc_ddc && d->s_rxrate) { + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x2); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_RX_RST, 0x0); } if (d->has_duc_ddc && d->s_txrate && d->s_tx_int != d->base.tx_dsp_inter) { @@ -1062,6 +1273,10 @@ static int _xsdr_update_fe_dsp(xsdr_dev_t *d) d->s_tx_int = d->base.tx_dsp_inter; USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "Updated TE FE DSP to %d interpolation\n", d->s_tx_int); + } else if (d->has_duc_ddc && d->s_txrate) { + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x2); + usleep(10); + dev_gpo_set(dev, IGPO_DSPCHAIN_TX_RST, 0x0); } return res; } @@ -1144,41 +1359,27 @@ int xsdr_set_samplerate_ex(xsdr_dev_t *d, res = res ? res : _xsdr_calibrate_lml(d); res = res ? res : _xsdr_update_fe_dsp(d); + res = res ? res : lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_A); -/* - int32_t a, b; - int32_t q[4]; - xsdr_phy_dc_estim_accum(d, 255); - xsdr_phy_dc_estim_start(d, 1); - xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &a); - - uint32_t cha[64], chb[64]; - lms7002m_mac_set(&d->base.lmsstate, LMS7_CH_AB); - lms7002m_xxtsp_gen(&d->base.lmsstate, LMS_RXTSP, XXTSP_TONE, 0, 1); - xsdr_phy_capture_start(d, 1); - usleep(100); - xsdr_phy_capture_start(d, 0); - xsdr_phy_capture_get(d, 0, 64, cha); - xsdr_phy_capture_get(d, 1, 64, chb); - lms7002m_xxtsp_gen(&d->base.lmsstate, LMS_RXTSP, XXTSP_NORMAL, 0, 0); - - for (unsigned j = 0; j < 64; j++) { - USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "%d: %08x %08x\n", j, cha[j], chb[j]); - } + bool bist_done_rx = false, bist_done_tx = false; + do { + res = res ? res : usleep(25000); + res = res ? res : lms7002m_xxtsp_bst_isdone(&d->base.lmsstate, LMS_RXTSP, &bist_done_rx); + res = res ? res : lms7002m_xxtsp_bst_isdone(&d->base.lmsstate, LMS_TXTSP, &bist_done_tx); + USDR_LL_LOG(dev, "XDEV", USDR_LOG_WARNING, "BIST TX_DONE=%d RX_DONE=%d\n", bist_done_tx, bist_done_rx); + } while (!res && (!bist_done_rx || !bist_done_tx)); + // Wait for DC autocal - xsdr_phy_dc_estim_get(d, DC_ESTIM_GEN, &b); - for (unsigned j = 0; j < 4; j++) { - xsdr_phy_dc_estim_get(d, DC_ESTIM_AI + j, &q[j]); + if (d->base.tx_run[0] || !d->base.rx_run[0]) { + res = res ? res : usleep(50000); + res = res ? res : xsdr_check_rxtx_quality(d, 1); } - - USDR_LL_LOG(dev, "XDEV", USDR_LOG_ERROR, "%d -> %d: %08x %08x %08x %08x\n", - a, b, q[0], q[1], q[2], q[3]); -*/ return res; } + int xsdr_clk_debug_info(xsdr_dev_t *d) { lldev_t dev = d->base.lmsstate.dev; @@ -2280,13 +2481,15 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* int res = 0; int meas1000db = 0; int accum = -180000, gen = 0; - unsigned acc_idx = 1; + unsigned acc_idx = logduration + 1; + if (acc_idx > 255) + acc_idx = 255; float corr = 0.5; if (!func) return 0; - // Fixups + // TODO: Fixups if (d->s_rx_dec == 8) corr = 0.5; @@ -2308,7 +2511,7 @@ int xsdrcal_do_meas_nco_avg(void* param, int channel, unsigned logduration, int* } usleep(500); } - USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MEAS[%d] = %.3f DEC=%d CORR=%.f\n", channel, meas1000db/1e3, d->s_rx_dec, corr); + USDR_LL_LOG(d->base.lmsstate.dev, "XDEV", USDR_LOG_INFO, "MEAS[%d]x%d = %.3f DEC=%d CORR=%.f\n", channel, acc_idx, meas1000db/1e3, d->s_rx_dec, corr); } *func = accum; @@ -2338,10 +2541,7 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->rxfrequency = d->base.rx_lo; ops->txfrequency = d->base.tx_lo; ops->channel = channel; - ops->deflogdur = ops->rxsamplerate / 16; - if (ops->deflogdur > 131072) { - ops->deflogdur = 131072; - } + ops->deflogdur = ops->rxsamplerate / 20e6; ops->defstop = -140000; ops->param = d; @@ -2368,11 +2568,11 @@ int xsdrcal_init_calibrate(xsdr_dev_t *d, struct calibrate_ops* ops, unsigned ch ops->rxlo_iq_corr.max = 63; ops->rxlo_iq_corr.min = -63; - ops->rximb_iq_corr.max = 2047; - ops->rximb_iq_corr.min = -2047; + ops->rximb_iq_corr.max = 1023;//2047; + ops->rximb_iq_corr.min = -1024; //-2047; - ops->rximb_ang_corr.max = 2047; - ops->rximb_ang_corr.min = -2047; + ops->rximb_ang_corr.max = 127; //2047; + ops->rximb_ang_corr.min = -128; //-2047; ops->set_nco_rx_offset = &xsdrcal_set_nco_offset; ops->set_corr_param = &xsdrcal_set_corr_param; @@ -2452,6 +2652,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) unsigned rx_lo = d->base.rx_lo; unsigned rx_rfic_lna = d->base.lmsstate.rfe[channel].path; unsigned tx_rfic_band = d->base.lmsstate.trf[channel].path; + bool tx_run = d->base.tx_run[0] || d->base.tx_run[1]; d->meas_cnt = 1; //One extra measurement for stability @@ -2490,7 +2691,7 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if (norestore) return 0; - goto restore_rxcfg; + //goto restore_rxcfg; } res = xsdr_tx_antennat_port_cfg(d, channel == 0 ? 1 : 2); @@ -2501,6 +2702,11 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) if ((param & XSDR_CAL_RXIQIMB) && (rx_lo > 0)) { // TODO if TX was disabled enable TX USDR_LL_LOG(dev, "LMS7", USDR_LOG_INFO, "------------------ Calibration RXIQIMB(%c) ------------------\n", 'A' + channel); + if (!tx_run) { + res = res ? res : xsdr_prepare(d, true, true); + res = res ? res : lms7002m_tbb_bandwidth(&d->base, cops.rxsamplerate, false); + res = res ? res : usleep(75000); + } if (!externallb) { res = (res) ? res : _xsdr_path_lb(d, rx_rfic_lna, tx_rfic_band, channel, true); } @@ -2512,6 +2718,9 @@ int xsdr_calibrate(xsdr_dev_t *d, unsigned channel, unsigned param, int* sarray) // Looks like TX was off, turn it off res = (res) ? res : lms7002m_sxx_disable(&d->base.lmsstate, SXX_TX); } + if (!tx_run) { + res = xsdr_prepare(d, true, false); + } if (res) { USDR_LL_LOG(dev, "LMS7", USDR_LOG_WARNING, " RXIQIMB failed: res=%d\n", res); return res; diff --git a/src/lib/device/m2_lm7_1/xsdr_ctrl.h b/src/lib/device/m2_lm7_1/xsdr_ctrl.h index 07d34db3..91d7558f 100644 --- a/src/lib/device/m2_lm7_1/xsdr_ctrl.h +++ b/src/lib/device/m2_lm7_1/xsdr_ctrl.h @@ -94,7 +94,7 @@ struct xsdr_dev bool xilinx_usp; bool has_duc_ddc; bool exttx; - + bool dump_cal_data; bool dpump; //Dual pump data union { bool pmic_ch145_valid; @@ -237,6 +237,8 @@ int xsdr_override_drp(xsdr_dev_t *d, lsopaddr_t ls_op_addr, int xsdr_config_rcvdly(xsdr_dev_t *d, unsigned type, unsigned val); +int xsdr_bb_loopback(xsdr_dev_t *d); + enum { XSDR_CAL_RXLO = 1, XSDR_CAL_TXLO = 2, @@ -259,6 +261,8 @@ int xsdr_trspi_lms8(xsdr_dev_t *d, uint32_t out, uint32_t* in); int xsdr_reset_extfe(xsdr_dev_t *d); +int xsdr_check_rxtx_quality(xsdr_dev_t *d, int fix); + #ifndef NO_IGPO enum { @@ -309,6 +313,7 @@ enum { int xsdr_txphase_ovr(xsdr_dev_t *d, unsigned v); +int xsdr_capture_rxiq(xsdr_dev_t* d, uint32_t *cha, uint32_t *chb); #endif diff --git a/src/lib/hw/lms7002m/lms7002m.c b/src/lib/hw/lms7002m/lms7002m.c index e96e8f3d..11a34cc7 100644 --- a/src/lib/hw/lms7002m/lms7002m.c +++ b/src/lib/hw/lms7002m/lms7002m.c @@ -485,6 +485,23 @@ int lms7002m_limelight_switch_rx_mode(lms7002m_state_t* m, lms7002m_limelight_co return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); } +int lms7002m_limelight_toggle_tsp_clk(lms7002m_state_t* m, lms7002m_limelight_conf_t params, uint8_t set) +{ + uint32_t regs[] = { + MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, set, set, 1, 1, 1, params.txsisoddr && params.txdiv == 1 ? 0 : 1, 1, params.rxsisoddr && params.rxdiv == 1 ? 0 : 1, 1, 1), + }; + return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); +} + +int lms7002m_limelight_upd_delay(lms7002m_state_t* m, lms7002m_limelight_conf_t params) +{ + uint32_t regs[] = { + MAKE_LMS7002M_CDS_0x00AE(params.txtspdelay, params.txtspdelay, 0, 0, params.txlmldelay, params.txlmldelay, 0, 0), + }; + return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); +} + + int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t params) { unsigned txmclk = (params.txdiv <= 1) ? LML_0X002B_MCLK1SRC_TXTSPCLKA : LML_0X002B_MCLK1SRC_TXTSPCLKA_DIV; @@ -538,7 +555,7 @@ int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t (params.txdiv > 1) ? 1u : 0, (params.rxdiv > 1) ? 1u : 0), MAKE_LMS7002M_LML_0x002C( params.txdiv / 2u - 1u, params.rxdiv / 2u - 1u ), - MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 0, 0, 1, 1, 1, params.txsisoddr && params.txdiv == 1 ? 0 : 1, 1, params.rxsisoddr && params.rxdiv == 1 ? 0 : 1, 1, 1), + MAKE_LMS7002M_CDS_0x00AD(0, 0, 0, 1, 1, 1, 1, 1, params.txsisoddr && params.txdiv == 1 ? 0 : 1, 1, params.rxsisoddr && params.rxdiv == 1 ? 0 : 1, 1, 1), MAKE_LMS7002M_CDS_0x00AE(params.txtspdelay, params.txtspdelay, 0, 0, params.txlmldelay, params.txlmldelay, 0, 0), MAKE_LMS7002M_REG_WR(LML_0x0020, reg_mac), MAKE_LMS7002M_REG_WR(LML_0x0020, m->reg_mac) @@ -959,6 +976,66 @@ int lms7002m_xxtsp_bst(lms7002m_state_t* m, lms7002m_xxtsp_t tsp) return lms7002m_spi_post(m, xxtsp_regs, SIZEOF_ARRAY(xxtsp_regs)); } +int lms7002m_xxtsp_bst_isdone(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, bool* done) +{ + int res = 0; + uint16_t data = 0; + if (tsp == LMS_RXTSP) { + uint32_t reg_rxmod = MAKE_LMS7002M_RXTSP_0x0400(0, + RXTSP_0X0400_CAPSEL_BSIGI_BSTATE, //CAPSEL + RXTSP_0X0400_CAPSEL_ADC_RXTSP_INPUT, //CAPSEL_ADC + RXTSP_0X0400_TSGFC_NEG6DB, //TSGFC, + RXTSP_0X0400_TSGFCW_DIV8, //TSGFCW, + 0, //TSGDCLDQ + 0, //TSGDCLDI + 0, //TSGSWAPIQ, + RXTSP_0X0400_TSGMODE_DC, //TSGMODE, + RXTSP_0X0400_INSEL_LML, //INSEL, + 0, //BSTART, + 1); + uint32_t regs[] = { + reg_rxmod, + reg_rxmod | (1 << RXTSP_0X0400_CAPTURE_OFF), + }; + res = res ? res : lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); + } + + res = res ? res : lms7002m_spi_rd(m, (tsp == LMS_TXTSP) ? 0x0209 : 0x040E, &data); + *done = (data & 1) ? false : true; + + return res; +} + +int lms7002m_xxtsp_reset(lms7002m_state_t* m, lms7002m_xxtsp_t tsp) +{ + uint32_t reg_rxmod = MAKE_LMS7002M_RXTSP_0x0400(0, + RXTSP_0X0400_CAPSEL_RSSI, //CAPSEL + RXTSP_0X0400_CAPSEL_ADC_RXTSP_INPUT, //CAPSEL_ADC + RXTSP_0X0400_TSGFC_NEG6DB, //TSGFC, + RXTSP_0X0400_TSGFCW_DIV8, //TSGFCW, + 0, //TSGDCLDQ + 0, //TSGDCLDI + 0, //TSGSWAPIQ, + RXTSP_0X0400_TSGMODE_DC, //TSGMODE, + RXTSP_0X0400_INSEL_LML, //INSEL, + 0, //BSTART, + 0); + uint32_t reg_txmod = MAKE_LMS7002M_TXTSP_0x0200(TXTSP_0X0200_TSGFC_NEG6DB, //TSGFC, + TXTSP_0X0200_TSGFCW_DIV8, //TSGFCW, + 0, //TSGDCLDQ + 0, //TSGDCLDI + 0, //TSGSWAPIQ, + TXTSP_0X0200_TSGMODE_DC, //TSGMODE, + TXTSP_0X0200_INSEL_LML, //INSEL, + 0, //BSTART, + 0); + uint32_t regs[] = { + (tsp == LMS_RXTSP) ? reg_rxmod : reg_txmod, + (tsp == LMS_RXTSP) ? reg_rxmod | 1 : reg_txmod | 1, + }; + return lms7002m_spi_post(m, regs, SIZEOF_ARRAY(regs)); +} + // xxTSP int lms7002m_xxtsp_enable(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, bool enable) { @@ -1454,8 +1531,8 @@ int lms7002m_rbb_path(lms7002m_state_t* m, lms7002m_rbb_path_t path, lms7002m_rb MAKE_LMS7002M_RBB_0x0118( (path == RBB_LBF) ? RBB_0X0118_INPUT_CTL_PGA_RBB_LPFL : - (path == RBB_HBF) ? RBB_0X0118_INPUT_CTL_PGA_RBB_LPFH : - (mode == RBB_MODE_LOOPBACK && path == RBB_BYP) ? RBB_0X0118_INPUT_CTL_PGA_RBB_TBB : RBB_0X0118_INPUT_CTL_PGA_RBB_BYPASS, + (path == RBB_HBF) ? RBB_0X0118_INPUT_CTL_PGA_RBB_LPFH : + (mode == RBB_MODE_LOOPBACK && path == RBB_BYP) ? RBB_0X0118_INPUT_CTL_PGA_RBB_TBB : RBB_0X0118_INPUT_CTL_PGA_RBB_BYPASS, 24, 24), }; @@ -1537,11 +1614,14 @@ int lms7002m_tbb_path(lms7002m_state_t* m, lms7002m_tbb_path_t path, lms7002m_tb bool en = mode != TBB_MODE_DISABLE; _lms7002m_mask_field_set(m, m->reg_en_dir, SXX_0X0124_EN_DIR_TBB_OFF, SXX_0X0124_EN_DIR_TBB_MSK, en); + if (mode == TBB_MODE_LOOPBACK_DAC) + path = TBB_BYP; + uint32_t tbb_regs[] = { MAKE_LMS7002M_TBB_0x0105( 0, //STATPULSE_TBB, mode == TBB_MODE_LOOPBACK_SWAPIQ ? 1 : 0, - mode == TBB_MODE_NORMAL ? TBB_0X0105_LOOPB_NORMAL : TBB_0X0105_LOOPB_LB_TBB_OUT, + mode == TBB_MODE_NORMAL ? TBB_0X0105_LOOPB_NORMAL : mode == TBB_MODE_LOOPBACK_DAC ? TBB_0X0105_LOOPB_LB_DAC : TBB_0X0105_LOOPB_LB_TBB_OUT, (path == TBB_HBF) ? 0 : 1u, //PD_LPFH_TBB, 0, //PD_LPFIAMP_TBB, (path == TBB_LAD) ? 0 : 1u, //PD_LPFLAD_TBB, diff --git a/src/lib/hw/lms7002m/lms7002m.h b/src/lib/hw/lms7002m/lms7002m.h index 5bc07b7b..ffebe4ae 100644 --- a/src/lib/hw/lms7002m/lms7002m.h +++ b/src/lib/hw/lms7002m/lms7002m.h @@ -124,6 +124,8 @@ typedef struct lms7002m_limelight_conf lms7002m_limelight_conf_t; int lms7002m_limelight_configure(lms7002m_state_t* m, lms7002m_limelight_conf_t params); int lms7002m_limelight_map(lms7002m_state_t* m, bool sisol1m, bool sisol2m, lms7002m_lml_map_t l1m, lms7002m_lml_map_t l2m); int lms7002m_limelight_switch_rx_mode(lms7002m_state_t* m, lms7002m_limelight_conf_t params); +int lms7002m_limelight_toggle_tsp_clk(lms7002m_state_t* m, lms7002m_limelight_conf_t params, uint8_t set); +int lms7002m_limelight_upd_delay(lms7002m_state_t* m, lms7002m_limelight_conf_t params); // CGEN int lms7002m_cgen_disable(lms7002m_state_t* m); @@ -174,6 +176,7 @@ typedef enum lms7002m_xxtsp lms7002m_xxtsp_t; // TSTPs int lms7002m_rxtsp_dc_corr(lms7002m_state_t* m, bool byp, unsigned wnd); int lms7002m_xxtsp_bst(lms7002m_state_t* m, lms7002m_xxtsp_t tsp); +int lms7002m_xxtsp_bst_isdone(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, bool* done); int lms7002m_xxtsp_enable(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, bool enable); int lms7002m_xxtsp_int_dec(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, unsigned intdec_ord); @@ -185,6 +188,7 @@ enum lms7002m_xxtsp_gen { }; typedef enum lms7002m_xxtsp_gen lms7002m_xxtsp_gen_t; +int lms7002m_xxtsp_reset(lms7002m_state_t* m, lms7002m_xxtsp_t tsp); int lms7002m_xxtsp_gen(lms7002m_state_t* m, lms7002m_xxtsp_t tsp, lms7002m_xxtsp_gen_t gen, int16_t dci, int16_t dcq); @@ -267,6 +271,7 @@ enum lms7002m_rbb_mode { RBB_MODE_DISABLE, RBB_MODE_NORMAL, RBB_MODE_LOOPBACK, + RBB_MODE_LOOPBACK_ADC, // RBB_MODE_EXT_ADC, TODO }; typedef enum lms7002m_rbb_mode lms7002m_rbb_mode_t; @@ -293,6 +298,7 @@ enum lms7002m_tbb_mode { TBB_MODE_NORMAL, TBB_MODE_LOOPBACK, TBB_MODE_LOOPBACK_SWAPIQ, + TBB_MODE_LOOPBACK_DAC, }; typedef enum lms7002m_tbb_mode lms7002m_tbb_mode_t;