laforge has uploaded this change for review.
fw/e1-tracer: Initialize IDT82V2081 from within firmware in e1d mode
Initially it was a good choice to keep the LIU driver in the host
software (easier debugging/changes). However, we never really needed it
to do anything but initialization of the LIU.
So in order to avoid having to teach osmo-e1d or other software the
details about the LIU initialization, let's do this from the firmware
*if* the e1d compatible USB configuration is used.
Closes: OS#5733
Change-Id: Id2217ff4573c4eebd816318128f256e85fb3c3bd
---
M firmware/ice40-riscv/e1-tracer/Makefile
A firmware/ice40-riscv/e1-tracer/idt82v2081.c
A firmware/ice40-riscv/e1-tracer/idt82v2081.h
A firmware/ice40-riscv/e1-tracer/idt82v2081_no2spi.c
A firmware/ice40-riscv/e1-tracer/idt82v2081_regs.h
M firmware/ice40-riscv/e1-tracer/usb_e1.c
6 files changed, 314 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-e1-hardware refs/changes/49/29949/1
diff --git a/firmware/ice40-riscv/e1-tracer/Makefile b/firmware/ice40-riscv/e1-tracer/Makefile
index 030501e..5fa38fa 100644
--- a/firmware/ice40-riscv/e1-tracer/Makefile
+++ b/firmware/ice40-riscv/e1-tracer/Makefile
@@ -47,6 +47,8 @@
HEADERS_app=\
config.h \
e1.h \
+ idt82v2081.h \
+ idt82v2081_regs.h \
misc.h \
usb_str_app.gen.h \
$(NULL)
@@ -54,6 +56,8 @@
SOURCES_app=\
e1.c \
fw_app.c \
+ idt82v2081.c \
+ idt82v2081_no2spi.c \
misc.c \
usb_desc_app.c \
usb_e1.c \
diff --git a/firmware/ice40-riscv/e1-tracer/idt82v2081.c b/firmware/ice40-riscv/e1-tracer/idt82v2081.c
new file mode 100644
index 0000000..9233292
--- /dev/null
+++ b/firmware/ice40-riscv/e1-tracer/idt82v2081.c
@@ -0,0 +1,140 @@
+/* (C) 2019 by Harald Welte <laforge@osmocom.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdint.h>
+
+#include "idt82v2081.h"
+#include "idt82v2081_regs.h"
+
+/*! \brief Set or clear some (masked) bits inside a register
+ * \param[in] e4k reference to the tuner
+ * \param[in] reg number of the register
+ * \param[in] mask bit-mask of the value
+ * \param[in] val data value to be written to register
+ * \returns 0 on success, negative in case of error
+ */
+static int idt82_reg_set_bit_mask(struct idt82 *idt, uint8_t reg,
+ uint8_t mask, uint8_t val)
+{
+ uint8_t tmp = idt82_reg_read(idt, reg);
+
+ if ((tmp & mask) == val)
+ return 0;
+
+ return idt82_reg_write(idt, reg, (tmp & ~mask) | (val & mask));
+}
+
+int idt82_termination(struct idt82 *idt, enum idt82_term term)
+{
+ uint8_t puls, scal;
+
+ idt82_reg_set_bit_mask(idt, IDT_REG_TERM, term | (term << IDT_TERM_T_SHIFT),
+ IDT_TERM_T_MASK | IDT_TERM_R_MASK);
+
+ switch (idt->mode) {
+ case IDT_MODE_E1:
+ if (term == IDT_TERM_INT_75)
+ puls = 0;
+ else
+ puls = 1;
+ scal = 0x21;
+ break;
+ case IDT_MODE_T1:
+ /* FIXME: different length! */
+ puls = 2;
+ scal = 0x36;
+ break;
+ case IDT_MODE_J1:
+ puls = 7;
+ scal = 0x36;
+ break;
+ default:
+ return -1;
+ }
+
+ idt82_reg_set_bit_mask(idt, IDT_REG_TCF1, puls, IDT_TCF1_PULS_MASK);
+ idt82_reg_set_bit_mask(idt, IDT_REG_TCF2, scal, IDT_TCF2_SCAL_MASK);
+
+ idt->term = term;
+
+ return 0;
+}
+
+int idt82_mode(struct idt82 *idt, enum idt82_mode mode)
+{
+ switch (mode) {
+ case IDT_MODE_E1:
+ idt82_reg_set_bit_mask(idt, IDT_REG_GCF, IDT_GCF_T1E1_E1,
+ IDT_GCF_T1E1_MASK);
+ break;
+ case IDT_MODE_T1:
+ case IDT_MODE_J1:
+ idt82_reg_set_bit_mask(idt, IDT_REG_GCF, IDT_GCF_T1E1_T1,
+ IDT_GCF_T1E1_MASK);
+ break;
+ }
+ idt->mode = mode;
+
+ return 0;
+}
+
+int idt82_get_errcount(struct idt82 *idt)
+{
+ uint16_t ret;
+ int rc;
+
+ rc = idt82_reg_read(idt, IDT_REG_CNT0);
+ if (rc < 0)
+ return rc;
+
+ ret = rc;
+
+ rc = idt82_reg_read(idt, IDT_REG_CNT1);
+ if (rc < 0)
+ return rc;
+
+ ret |= (rc << 8);
+
+ return ret;
+}
+
+/* return in dB, range is return value ... (value + 2) */
+int idt82_get_line_att(struct idt82 *idt)
+{
+ int rc;
+
+ rc = idt82_reg_read(idt, IDT_REG_STAT1);
+ if (rc < 0)
+ return rc;
+
+ return (rc & IDT_STAT1_ATT_MASK)*2;
+}
+
+int idt82_init(struct idt82 *idt, bool monitor)
+{
+ idt82_reg_write(idt, IDT_REG_RST, 0x00); /* Reset to defaults */
+
+ idt82_mode(idt, IDT_MODE_E1);
+ idt82_termination(idt, IDT_TERM_INT_120);
+
+ idt82_reg_write(idt, IDT_REG_TCF0, 0x10); /* Disable TX */
+
+ if (monitor)
+ idt82_reg_write(idt, IDT_REG_RCF2, 0x19); /* 22 dB monitor mode */
+
+ return 0;
+}
+
diff --git a/firmware/ice40-riscv/e1-tracer/idt82v2081.h b/firmware/ice40-riscv/e1-tracer/idt82v2081.h
new file mode 100644
index 0000000..1c930b1
--- /dev/null
+++ b/firmware/ice40-riscv/e1-tracer/idt82v2081.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+enum idt82_term {
+ IDT_TERM_INT_75 = 0,
+ IDT_TERM_INT_120,
+ IDT_TERM_INT_100,
+ IDT_TERM_INT_110,
+ IDT_TERM_EXT,
+};
+
+enum idt82_mode {
+ IDT_MODE_E1 = 0,
+ IDT_MODE_T1,
+ IDT_MODE_J1,
+};
+
+struct idt82 {
+ enum idt82_mode mode;
+ enum idt82_term term;
+ void *priv;
+ uint8_t cs;
+};
+
+int idt82_termination(struct idt82 *idt, enum idt82_term term);
+int idt82_mode(struct idt82 *idt, enum idt82_mode mode);
+int idt82_get_errcount(struct idt82 *idt);
+int idt82_get_line_att(struct idt82 *idt);
+int idt82_init(struct idt82 *idt, bool monitor);
+
+/* callbacks into transport */
+int idt82_reg_write(struct idt82 *idt, uint8_t reg, uint8_t val);
+int idt82_reg_read(struct idt82 *idt, uint8_t reg);
diff --git a/firmware/ice40-riscv/e1-tracer/idt82v2081_no2spi.c b/firmware/ice40-riscv/e1-tracer/idt82v2081_no2spi.c
new file mode 100644
index 0000000..66e5c5b
--- /dev/null
+++ b/firmware/ice40-riscv/e1-tracer/idt82v2081_no2spi.c
@@ -0,0 +1,48 @@
+/* (C) 2019 by Harald Welte <laforge@osmocom.org>
+ * All Rights Reserved
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "idt82v2081.h"
+#include "spi.h"
+
+/* Adaption layer between idt82 driver and no2fpga SPI */
+
+/* backend function for core idt82 driver */
+int idt82_reg_read(struct idt82 *idt, uint8_t reg)
+{
+ uint8_t cmd = reg | 0x20;
+ uint8_t rv;
+ struct spi_xfer_chunk xfer[2] = {
+ { .data = (void*)&cmd, .len = 1, .read = false, .write = true, },
+ { .data = (void*)&rv, .len = 1, .read = true, .write = false, },
+ };
+ spi_xfer(SPI_CS_LIU(idt->cs), xfer, 2);
+ return rv;
+}
+
+/* backend function for core idt82 driver */
+int idt82_reg_write(struct idt82 *idt, uint8_t reg, uint8_t val)
+{
+ uint8_t cmd[2] = { reg, val };
+ struct spi_xfer_chunk xfer[2] = {
+ { .data = (void*)cmd, .len = 2, .read = false, .write = true, },
+ };
+ spi_xfer(SPI_CS_LIU(idt->cs), xfer, 1);
+ return 0;
+}
diff --git a/firmware/ice40-riscv/e1-tracer/idt82v2081_regs.h b/firmware/ice40-riscv/e1-tracer/idt82v2081_regs.h
new file mode 100644
index 0000000..679ed90
--- /dev/null
+++ b/firmware/ice40-riscv/e1-tracer/idt82v2081_regs.h
@@ -0,0 +1,81 @@
+#ifndef _IDT82_REGS_H
+#define _IDT82_REGS_H
+
+/* Section 4.1 of Data Sheet */
+enum idt82v2081_reg {
+ IDT_REG_ID, /* control */
+ IDT_REG_RST,
+ IDT_REG_GCF,
+ IDT_REG_TERM,
+ IDT_REG_JACF,
+ IDT_REG_TCF0, /* Tx path control */
+ IDT_REG_TCF1,
+ IDT_REG_TCF2,
+ IDT_REG_TCF3,
+ IDT_REG_TCF4,
+ IDT_REG_RCF0, /* Rx path control */
+ IDT_REG_RCF1,
+ IDT_REG_RCF2,
+ IDT_REG_MAINT0, /* Net Diag Ctrl */
+ IDT_REG_MAINT1,
+ IDT_REG_MAINT2,
+ IDT_REG_MAINT3,
+ IDT_REG_MAINT4,
+ IDT_REG_MAINT5,
+ IDT_REG_MAINT6,
+ IDT_REG_INTM0, /* Interrupt Control */
+ IDT_REG_INTM1,
+ IDT_REG_INTES,
+ IDT_REG_STAT0, /* Line Status */
+ IDT_REG_STAT1,
+ IDT_REG_INTS0, /* Interrupt Status */
+ IDT_REG_INTS1,
+ IDT_REG_CNT0, /* Counter */
+ IDT_REG_CNT1,
+};
+
+#define IDT_GCF_T1E1_E1 (0 << 2)
+#define IDT_GCF_T1E1_T1 (1 << 2)
+#define IDT_GCF_T1E1_MASK (1 << 2)
+
+#define IDT_TERM_T_SHIFT 3
+#define IDT_TERM_T_MASK (7 << IDT_TERM_T_SHIFT)
+#define IDT_TERM_R_SHIFT 0
+#define IDT_TERM_R_MASK (7 << IDT_TERM_R_SHIFT)
+
+#define IDT_TCF1_PULS_MASK 0xF
+
+#define IDT_TCF2_SCAL_MASK 0x3F
+
+#define IDT_RCF2_MG_MASK 3
+#define IDT_RCF2_UPDW_SHIFT 2
+#define IDT_RCF2_UPDW_MASK (3 << IDT_TERM_INT_75)
+#define IDT_RCF2_SLICE_SHIFT 4
+#define IDT_RCF2_SLICE_MASK (3 << IDT_RCF2_SLICE_SHIFT)
+
+#define IDT_INTM0_EQ (1 << 7) /* equalizer out of range */
+#define IDT_INTM0_IBLBA (1 << 6) /* in-band LB act detect */
+#define IDT_INTM0_IBLBD (1 << 5) /* in-band LB deact detect */
+#define IDT_INTM0_PRBS (1 << 4) /* prbs sync signal detect */
+#define IDT_INTM0_TCLK (1 << 3) /* tclk loss */
+#define IDT_INTM0_DF (1 << 2) /* driver failure */
+#define IDT_INTM0_AIS (1 << 1) /* Alarm Indication Signal */
+#define IDT_INTM0_LOS (1 << 0) /* Loss Of Signal */
+
+#define IDT_INTM1_DAC_OV (1 << 7) /* DAC arithmetic overflow */
+#define IDT_INTM1_JA_OV (1 << 6) /* JA overflow */
+#define IDT_INTM1_JA_UD (1 << 5) /* JA underflow */
+#define IDT_INTM1_ERR (1 << 4) /* PRBS/QRBS logic error detect */
+#define IDT_INTM1_EXZ (1 << 3) /* Receive excess zeros */
+#define IDT_INTM1_CV (1 << 2) /* Receive error */
+#define IDT_INTM1_TIMER (1 << 1) /* One second timer expiration */
+#define IDT_INTM1_CNT (1 << 0) /* Counter overflow */
+
+/* STAT0 == INTES == INTS0 == INTM0 */
+
+/* INTS1 == INTM1 */
+
+#define IDT_STAT1_RLP (1 << 5)
+#define IDT_STAT1_ATT_MASK 0x1F
+
+#endif /* _IDT82_REGS_H */
diff --git a/firmware/ice40-riscv/e1-tracer/usb_e1.c b/firmware/ice40-riscv/e1-tracer/usb_e1.c
index 728dc3a..160d2b5 100644
--- a/firmware/ice40-riscv/e1-tracer/usb_e1.c
+++ b/firmware/ice40-riscv/e1-tracer/usb_e1.c
@@ -16,10 +16,12 @@
#include "console.h"
#include "e1.h"
#include "misc.h"
+#include "idt82v2081.h"
struct {
bool running[2];
int in_bdi[2];
+ struct idt82 idt82[2];
} g_usb_e1;
@@ -218,6 +220,7 @@
disable_chan(base->bInterfaceNumber);
break;
case 1:
+ idt82_init(&g_usb_e1.idt82[base->bInterfaceNumber], true);
enable_chan(base->bInterfaceNumber);
break;
default:
@@ -271,6 +274,9 @@
{
/* Clear state */
memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
+ /* make sure we use the right SPI channel for the respective IDT82 */
+ g_usb_e1.idt82[0].cs = 0;
+ g_usb_e1.idt82[1].cs = 1;
/* Install driver */
usb_register_function_driver(&_e1_drv);
To view, visit change 29949. To unsubscribe, or for help writing mail filters, visit settings.