summaryrefslogtreecommitdiff
path: root/snd-alpx/alpx_cards.c
diff options
context:
space:
mode:
authorChristian Pointner <equinox@helsinki.at>2024-05-10 18:26:46 (GMT)
committerChristian Pointner <equinox@helsinki.at>2024-05-10 18:26:46 (GMT)
commit627f7d488817e308d6f3a92fd9a877723ac7ae1d (patch)
tree554a3c53c90b20da5bd0da0c8da67a9b169bd10f /snd-alpx/alpx_cards.c
import snd-alpx V3.4.3
Diffstat (limited to 'snd-alpx/alpx_cards.c')
-rw-r--r--snd-alpx/alpx_cards.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/snd-alpx/alpx_cards.c b/snd-alpx/alpx_cards.c
new file mode 100644
index 0000000..7f9ec3a
--- /dev/null
+++ b/snd-alpx/alpx_cards.c
@@ -0,0 +1,545 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+* Support for Digigram AlpX PCI-e boards
+*
+* Copyright (c) 2024 Digigram Digital (info@digigram.com)
+*/
+
+#include <linux/pci.h>
+
+#include "alpx_cards.h"
+#include "alpx_reg.h"
+#include "alpx_mtd.h"
+#include "alpx_axcmem.h"
+#include "alpx_variants_dante.h"
+
+#include <linux/delay.h>
+
+void alpstereo_print_identity(struct alpx_device *alpx_dev, struct snd_card *card, const unsigned char* label)
+{
+ const unsigned int design_revision = readl(ALPX_REG(alpx_dev, ALP, CONTROL, DESIGN_VERSION));
+
+ //Add Build information, only for design >= 1.8
+ if (design_revision >= ALP222_DESIGN_WITH_BUILD_REGISTER_VERSION) {
+ const unsigned int build_version = alpx_dev->identity.ver_fpga;
+ const unsigned int ctrl_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, CONTROL, VERSION));
+ const unsigned int mxr_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, MIXER, VERSION));
+ const unsigned int ampli_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, AMPLI_IN, VERSION));
+ const unsigned int ampli_out_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, AMPLI_OUT, VERSION));
+ const unsigned int proc_revision = alpx_dev->identity.ver_mcu;
+
+ dev_info( alpx_dev->dev,\
+ "\n************ \n"
+ "%s Alp Stereo %s soundcard[%d]{#%llu} : %s - %s (%s - 0x%04x), \n\t== Revisions ==\n\t* Build: \t\t%u\n\t* Design: \t\t%u.%lu\n\t* Control: \t\t%u.%lu\n\t* Ampli In:\t\t%u.%lu\n\t* Mixer: \t\t%u.%lu\n"
+ "\t* Ampli Out:\t\t%u.%lu\n\t* MCU:\t\t\t%u.%lu\n"
+ "************\n",
+ label,
+ alpx_is_222_mic(alpx_dev) ? "MIC":"",
+ card->number,
+ alpx_dev->identity.serial_number,
+ card->id,
+ card->shortname,
+ card->longname,
+ alpx_dev->identity.sub_system_id,
+ build_version,
+ ALPX_COMMON_VERSION_VERSION(design_revision),
+ ALPX_COMMON_VERSION_REVISION(design_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ctrl_revision),
+ ALPX_COMMON_VERSION_REVISION(ctrl_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ampli_in_revision),
+ ALPX_COMMON_VERSION_REVISION(ampli_in_revision),
+
+ ALPX_COMMON_VERSION_VERSION(mxr_revision),
+ ALPX_COMMON_VERSION_REVISION(mxr_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ampli_out_revision),
+ ALPX_COMMON_VERSION_REVISION(ampli_out_revision),
+
+ ALPX_COMMON_VERSION_VERSION(proc_revision),
+ ALPX_COMMON_VERSION_REVISION(proc_revision)
+ );
+ }
+ else {
+ const unsigned int ctrl_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, CONTROL, VERSION));
+ const unsigned int mxr_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, MIXER, VERSION));
+ const unsigned int ampli_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, AMPLI_IN, VERSION));
+ const unsigned int ampli_out_revision = readl(ALPX_COMMON_REG(alpx_dev, ALP222, AMPLI_OUT, VERSION));
+ const unsigned int proc_revision = readl(ALPX_REG(alpx_dev, ALP, PROC, VERSION));
+dev_info(alpx_dev->dev, "Serial# : %llu\n", alpx_dev->identity.serial_number);
+ dev_info( alpx_dev->dev,\
+ "\n************ \n"
+ "%s Alp222 soundcard[%d] {#%llu} : %s - %s (%s - 0x%04x), \n\t== Revisions ==\n\t* Design: \t\t%u.%lu\n\t* Control: \t\t%u.%lu\n\t* Ampli In:\t\t%u.%lu\n\t* Mixer: \t\t%u.%lu\n"
+ "\t* Ampli Out:\t\t%u.%lu\n\t* MCU:\t\t\t%u.%lu\n"
+ "************\n",
+ label,
+ card->number,
+ alpx_dev->identity.serial_number,
+ card->id,
+ card->shortname,
+ card->longname,
+ alpx_dev->identity.sub_system_id,
+ ALPX_COMMON_VERSION_VERSION(design_revision),
+ ALPX_COMMON_VERSION_REVISION(design_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ctrl_revision),
+ ALPX_COMMON_VERSION_REVISION(ctrl_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ampli_in_revision),
+ ALPX_COMMON_VERSION_REVISION(ampli_in_revision),
+
+ ALPX_COMMON_VERSION_VERSION(mxr_revision),
+ ALPX_COMMON_VERSION_REVISION(mxr_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ampli_out_revision),
+ ALPX_COMMON_VERSION_REVISION(ampli_out_revision),
+
+ ALPX_COMMON_VERSION_VERSION(proc_revision),
+ ALPX_COMMON_VERSION_REVISION(proc_revision)
+ );
+ }
+}
+
+void alpmadi_print_identity(struct alpx_device *alpx_dev, struct snd_card *card, const unsigned char* label)
+{
+
+ const unsigned int ctrl_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, CONTROL, VERSION));
+ const unsigned int mxr_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, MIXER, VERSION));
+ const unsigned int meas_daw_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, MEAS_DAW_IN, VERSION));
+ const unsigned int meas_daw_out_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, MEAS_DAW_OUT, VERSION));
+ const unsigned int meas_madi_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, MEAS_MADI_IN, VERSION));
+ const unsigned int meas_madi_out_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, MEAS_MADI_OUT, VERSION));
+ const unsigned int gain_madi_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, GAIN_MADI_IN, VERSION));
+ const unsigned int gain_madi_out_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, GAIN_MADI_OUT, VERSION));
+ const unsigned int gain_daw_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, GAIN_DAW_IN, VERSION));
+ const unsigned int gain_daw_out_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, GAIN_DAW_OUT, VERSION));
+ const unsigned int router_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMADI, ROUTER_IN, VERSION));
+
+ dev_info( alpx_dev->dev,\
+ "************ \n"
+ "%s AlpMadi soundcard[%d]{#%llu} : %s - %s (%s - 0x%04x), \n\t== Revisions ==\n\t * Control: \t\t%u.%lu\n\t * Mixer: \t\t%u.%lu\n\t * Gain Daw In:\t%u.%lu\n\t * Gain Daw Out:\t%u.%lu\n\t * Gain MADI In:\t\t%u.%lu\n\t * Gain MADI Out:\t%u.%lu\n\t * Meas DAW In:\t%u.%lu\n\t * Meas Daw Out:\t%u.%lu\n\t * Meas MADI In:\t\t%u.%lu\n\t * Meas MADI Out:\t%u.%lu\n\t * Router:\t\t%u.%lu\n"
+ "************\n",
+ label,
+ card->number,
+ alpx_dev->identity.serial_number,
+ card->id,
+ card->shortname,
+ card->longname,
+ alpx_dev->identity.sub_system_id,
+ ALPX_COMMON_VERSION_VERSION(ctrl_revision),
+ ALPX_COMMON_VERSION_REVISION(ctrl_revision),
+
+ ALPX_COMMON_VERSION_VERSION(mxr_revision),
+ ALPX_COMMON_VERSION_REVISION(mxr_revision),
+
+ ALPX_COMMON_VERSION_VERSION(gain_daw_in_revision),
+ ALPX_COMMON_VERSION_REVISION(gain_daw_in_revision),
+ ALPX_COMMON_VERSION_VERSION(gain_daw_out_revision),
+ ALPX_COMMON_VERSION_REVISION(gain_daw_out_revision),
+
+ ALPX_COMMON_VERSION_VERSION(gain_madi_in_revision),
+ ALPX_COMMON_VERSION_REVISION(gain_madi_in_revision),
+ ALPX_COMMON_VERSION_VERSION(gain_madi_out_revision),
+ ALPX_COMMON_VERSION_REVISION(gain_madi_out_revision),
+
+ ALPX_COMMON_VERSION_VERSION(meas_daw_in_revision),
+ ALPX_COMMON_VERSION_REVISION(meas_daw_in_revision),
+ ALPX_COMMON_VERSION_VERSION(meas_daw_out_revision),
+ ALPX_COMMON_VERSION_REVISION(meas_daw_out_revision),
+
+ ALPX_COMMON_VERSION_VERSION(meas_madi_in_revision),
+ ALPX_COMMON_VERSION_REVISION(meas_madi_in_revision),
+ ALPX_COMMON_VERSION_VERSION(meas_madi_out_revision),
+ ALPX_COMMON_VERSION_REVISION(meas_madi_out_revision),
+
+ ALPX_COMMON_VERSION_VERSION(router_in_revision),
+ ALPX_COMMON_VERSION_REVISION(router_in_revision));
+}
+
+void alpmultichan_print_identity(struct alpx_device *alpx_dev, struct snd_card *card, const unsigned char* label)
+{
+ const unsigned int design_revision = readl(ALPX_REG(alpx_dev, ALP, CONTROL, DESIGN_VERSION));
+ const unsigned int build_version = alpx_dev->identity.ver_fpga;
+ const unsigned int ctrl_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMC, CONTROL, VERSION));
+ const unsigned int mxr_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMC, MIXER, VERSION));
+ const unsigned int ampli_in_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMC, AMPLI_IN, VERSION));
+ const unsigned int ampli_out_revision = readl(ALPX_COMMON_REG(alpx_dev, ALPMC, AMPLI_OUT, VERSION));
+ const unsigned int proc_revision = alpx_dev->identity.ver_mcu;
+
+ dev_info( alpx_dev->dev,\
+ "\n************ \n"
+ "%s Alp multi-channels soundcard[%d]{#%llu} : %s - %s (%s - 0x%04x) , \n\t== Revisions ==\n\t* Build: \t\t%u\n\t* Design: \t\t%u.%lu\n\t* Control: \t\t%u.%lu\n\t* Ampli In:\t\t%u.%lu\n\t* Mixer: \t\t%u.%lu\n"
+ "\t* Ampli Out:\t\t%u.%lu\n\t* MCU:\t\t\t%u.%lu\n"
+ "************\n",
+ label,
+ card->number,
+ alpx_dev->identity.serial_number,
+ card->id,
+ card->shortname,
+ card->longname,
+ alpx_dev->identity.sub_system_id,
+ build_version,
+ ALPX_COMMON_VERSION_VERSION(design_revision),
+ ALPX_COMMON_VERSION_REVISION(design_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ctrl_revision),
+ ALPX_COMMON_VERSION_REVISION(ctrl_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ampli_in_revision),
+ ALPX_COMMON_VERSION_REVISION(ampli_in_revision),
+
+ ALPX_COMMON_VERSION_VERSION(mxr_revision),
+ ALPX_COMMON_VERSION_REVISION(mxr_revision),
+
+ ALPX_COMMON_VERSION_VERSION(ampli_out_revision),
+ ALPX_COMMON_VERSION_REVISION(ampli_out_revision),
+
+ ALPX_COMMON_VERSION_VERSION(proc_revision),
+ ALPX_COMMON_VERSION_REVISION(proc_revision));
+}
+
+static int alpx_card_read_serial_number(struct alpx_device* alpx_dev)
+{
+ unsigned char raw_serial[9];
+ int ret = alpx_mtd_read_shared(alpx_dev, ALPX_SERIAL_OFFSET_IN_PRODUCTION,
+ raw_serial,
+ sizeof(raw_serial) - 1);
+
+ raw_serial[sizeof(raw_serial) - 1] = 0;
+
+ if (ret){
+ dev_err(alpx_dev->dev, "Error %d when reading Shared Area\n", ret);
+ /* DEFAULT VALUES */
+ alpx_dev->identity.serial_number = (~ 0);
+ return -EIO;
+ }
+
+ dev_dbg(alpx_dev->dev, " %s() : BEFORE shift %llu // 0x%llx\n", __func__, (uint64_t)raw_serial, (uint64_t)raw_serial);
+
+ //Conversion RAW => Little endian (not use be64_to_cpu() ?? Should be tested later)
+ alpx_dev->identity.serial_number = ((uint64_t)raw_serial[0])<<32 | ((uint64_t)raw_serial[1]) << 24 |
+ ((uint64_t)raw_serial[2]) << 16 |
+ ((uint64_t)raw_serial[3]) << 8 |
+ ((uint64_t)raw_serial[4]);
+
+ return 0;
+}
+
+int alpxxx_finalize_identity(struct alpx_device* alpx_dev)
+{
+ alpx_dev->identity.ver_mcu = readl(ALPX_REG(alpx_dev, ALP, PROC, VERSION));
+ alpx_dev->identity.ver_fpga = readl(ALPX_REG(alpx_dev, ALP, CONTROL, BUILD_VERSION)) & ALP_CONTROL_BUILD_VERSION_MASK;
+ return 0;
+}
+
+int alpstereo_finalize_identity(struct alpx_device* alpx_dev)
+{
+
+ int ret = alpxxx_finalize_identity(alpx_dev);
+ if (ret){
+ dev_err(alpx_dev->dev, "Error %d when finalizing base identity\n", ret);
+ return ret;
+ }
+
+ ret = alpx_mtd_load_shared_from(alpx_dev,
+ alpx_dev->variant->flash_partitions.partitions[ALPX_FLASH_PARTITION_PRODUCTION_ID].offset);
+
+ /* DEFAULT VALUES */
+ alpx_dev->identity.sub_system_id = (~ 0);
+ alpx_dev->identity.sub_system_id = (~ 0);
+
+ if (ret){
+ dev_err(alpx_dev->dev, "Error %d when extracting Production Area\n", ret);
+ return -EIO;
+ }
+
+ alpx_card_read_serial_number(alpx_dev);
+ alpx_dev->identity.sub_system_id = alpx_dev->pci_dev->subsystem_device;
+
+ return 0;
+}
+
+int alpmultichan_finalize_identity(struct alpx_device* alpx_dev)
+{
+ int ret = alpxxx_finalize_identity(alpx_dev);
+ if (ret){
+ dev_err(alpx_dev->dev, "Error %d when finalizing base identity\n", ret);
+ return ret;
+ }
+
+ ret = alpx_mtd_load_shared_from(alpx_dev,
+ alpx_dev->variant->flash_partitions.partitions[ALPX_FLASH_PARTITION_PRODUCTION_ID].offset);
+
+ /* DEFAULT VALUES */
+ alpx_dev->identity.sub_system_id = alpx_dev->pci_dev->subsystem_device;
+
+ if (ret){
+ dev_err(alpx_dev->dev, "Error %d when extracting Production Area\n", ret);
+ return -EIO;
+ }
+
+ alpx_card_read_serial_number(alpx_dev);
+
+ return 0;
+}
+
+int alpdante_finalize_identity(struct alpx_device* alpx_dev)
+{
+ void* fir_reg = NULL;
+ void* csppr_reg = NULL;
+ void* ublaze_version_reg = NULL;
+ void* design_bloc_version_reg = NULL;
+ void* low_serial_reg = NULL;
+ void* high_serial_reg = NULL;
+
+ uint32_t low_serial_raw = 0;
+ uint32_t high_serial_raw = 0;
+
+ dev_info(alpx_dev->dev, "DANTE card detected, finalizing identity\n");
+ /* All this is extracted from AXcMEM registers */
+
+ fir_reg = alpx_axcmem_getRegAddr(alpx_dev, &ALPDANTE_FIR_LOC);
+
+ csppr_reg = alpx_axcmem_getRegAddr(alpx_dev, &ALPDANTE_CSPPR_LOC);
+
+ ublaze_version_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_CSPPR_LOC, &ALPDANTE_UBLAZE_VERSION_LOC);
+
+ design_bloc_version_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_CSPPR_LOC, &ALPDANTE_DESIGN_BLOC_VERSION_LOC);
+
+ low_serial_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_CSPPR_LOC, &ALPDANTE_LOW_SERIAL_NUM_LOC);
+
+ high_serial_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_CSPPR_LOC, &ALPDANTE_HIGH_SERIAL_NUM_LOC);
+
+
+ dev_dbg(alpx_dev->dev, "FIR[0x%lx]=>%d\n", (uint8_t*)fir_reg - (uint8_t*)alpx_dev->base, alpx_axcmem_getRegBEU16Value(fir_reg));
+
+ dev_dbg(alpx_dev->dev, "CSPPR[0x%lx]=> %d\n", (uint8_t*)csppr_reg - (uint8_t*)alpx_dev->base, alpx_axcmem_getRegU8Value(csppr_reg));
+
+ dev_dbg(alpx_dev->dev, "uBlaze Version[0x%lx]=> %d\n", (uint8_t*)ublaze_version_reg - (uint8_t*)alpx_dev->base, alpx_axcmem_getRegU16Value(ublaze_version_reg));
+
+ dev_dbg(alpx_dev->dev, "Design bloc Version[0x%lx]=> %d\n", (uint8_t*)design_bloc_version_reg - (uint8_t*)alpx_dev->base, alpx_axcmem_getRegU16Value(design_bloc_version_reg));
+
+ alpx_dev->identity.ver_mcu = alpx_axcmem_getRegU16Value(ublaze_version_reg);
+ alpx_dev->identity.ver_fpga = alpx_axcmem_getRegBEU16Value(fir_reg);
+
+ low_serial_raw = alpx_axcmem_getRegU32Value(low_serial_reg);
+ high_serial_raw = alpx_axcmem_getRegU32Value(high_serial_reg);
+
+ dev_dbg(alpx_dev->dev, "Low serial number[0x%lx]=> 0x%x\n", (uint8_t*)low_serial_reg - (uint8_t*)alpx_dev->base, low_serial_raw);
+
+ dev_dbg(alpx_dev->dev, "High serial number[0x%lx]=> 0x%x\n", (uint8_t*)high_serial_reg - (uint8_t*)alpx_dev->base, high_serial_raw);
+
+ alpx_dev->identity.serial_number = ((uint64_t)high_serial_raw)<<8 | (((uint64_t)low_serial_raw) >> 24);
+
+ /* DEFAULT VALUES */
+ alpx_dev->identity.sub_system_id = alpx_dev->pci_dev->subsystem_device;
+
+ return 0;
+}
+
+void alpdante_print_identity(struct alpx_device *alpx_dev, struct snd_card *card, const unsigned char* label)
+{
+ void* design_bloc_version_reg = design_bloc_version_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_CSPPR_LOC, &ALPDANTE_DESIGN_BLOC_VERSION_LOC);
+
+ const unsigned int design_bloc_version = alpx_axcmem_getRegU16Value(design_bloc_version_reg);
+ char dante_name[ALPDANTE_NETWORK_NAME_LENGTH];
+
+ dante_name[ALPDANTE_NETWORK_NAME_LENGTH - 1] = 0;
+ alpdante_get_dante_name(alpx_dev, dante_name, ALPDANTE_NETWORK_NAME_LENGTH);
+
+ dev_info( alpx_dev->dev,
+ "\n************ \n"
+ "%s Alp DANTE soundcard[%d]{#%llu / %s }: %s - %s (%s - 0x%04x) , \n\t== Revisions ==\n\t* Build: \t\t%u\n\t* Design: \t\t%u.%lu\n\t* MCU:\t\t\t%u.%lu\n"
+ "************\n",
+ label,
+ card->number,
+ alpx_dev->identity.serial_number,
+ dante_name,
+ card->id,
+ card->shortname,
+ card->longname,
+ alpx_dev->identity.sub_system_id,
+ alpx_dev->identity.ver_fpga,
+ ALPX_DANTE_VERSION_VERSION(design_bloc_version),
+ ALPX_DANTE_VERSION_REVISION(design_bloc_version),
+ ALPX_DANTE_VERSION_VERSION(alpx_dev->identity.ver_mcu),
+ ALPX_DANTE_VERSION_REVISION(alpx_dev->identity.ver_mcu));
+}
+
+int alpdante_get_dante_name(struct alpx_device* alpx_dev, char* name, unsigned int length)
+{
+ if (length < ALPDANTE_NETWORK_NAME_LENGTH) {
+ dev_warn(alpx_dev->dev, "name parameter must be at least %d char long !\n", ALPDANTE_NETWORK_NAME_LENGTH);
+ return -EINVAL;
+ }
+
+ return alpx_acxmem_getByteArrayByRefLoc(alpx_dev, &ALPDANTE_CNAMPR_LOC,
+ &ALPDANTE_NAME_LOC,
+ name,
+ length);
+}
+
+int alpdante_store_config(struct alpx_device* alpx_dev)
+{
+ void* fsdr_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_FPPR_LOC,
+ &ALPDANTE_FSDR_LOC);
+
+ void* fcr_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_FPPR_LOC,
+ &ALPDANTE_FCR_LOC);
+
+ void* fcar_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_FPPR_LOC,
+ &ALPDANTE_FCAR_LOC);
+
+ void* smalar_reg = alpx_axcmem_getRegAddr(alpx_dev, &ALPDANTE_SMALAR_LOC);
+
+
+ unsigned int waitLoopQty = ALPDANTE_FLASH_LOCK_ACCESS_TRY_QTY;
+ u32 cmd_status = 0;
+ int result = 0;
+
+ dev_info(alpx_dev->dev, "Storing configuration ...\n");
+
+ //Wait for availability
+ while ((alpx_axcmem_getRegU8Value(smalar_reg) != ALPDANTE_SMALAR_AVAILABLE) && (--waitLoopQty)) {
+ dev_dbg(alpx_dev->dev," FCR:0x%x : Not yet available, wai a bit...\n", alpx_axcmem_getRegU8Value(smalar_reg));
+ mdelay(ALPDANTE_FLASH_WAIT_STEP_TIME);
+ }
+
+ if (waitLoopQty != 0) {
+ alpx_axcmem_setRegU8Value(smalar_reg, ALPDANTE_SMALAR_IN_USE);
+ dev_dbg(alpx_dev->dev," Semaphore taken\n");
+ }
+ else {
+ dev_err(alpx_dev->dev, "!! Flash memory unavailable !!\n ");
+ return -EBUSY;
+ }
+
+ //Write sequence
+ alpx_axcmem_setRegU8Value(fsdr_reg, 1);
+ alpx_axcmem_setRegU8Value(fcr_reg, ALPDANTE_FPPR_SAVE_REGISTERS_CMD_ID);
+
+ //Wait for completion
+ waitLoopQty = ALPDANTE_FPPR_SAVE_REGS_CMD_COMPLETION_WAIT_STEPS_QTY;
+ while ((alpx_axcmem_getRegU8Value(fcr_reg) != ALPDANTE_FPPR_NOPE_CMD_ID) && (--waitLoopQty)) {
+ dev_dbg(alpx_dev->dev,"FCR: 0x%x : Cmd in progress, wait a bit...\n", alpx_axcmem_getRegU8Value(fcr_reg));
+ mdelay(ALPDANTE_FLASH_WAIT_STEP_TIME);
+ }
+
+ if (waitLoopQty==0) {
+ dev_err(alpx_dev->dev, "!! Flash Command TIMEOUT!!\n");
+ result = -EIO;
+ goto EXIT;
+ }
+
+ cmd_status = ALPDANTE_FPPR_CMD_STATUS(alpx_axcmem_getRegU32Value(fcar_reg));
+
+ dev_info(alpx_dev->dev, "Configuration %s (0x%x)\n", cmd_status ? "NOT STORED !" : "STORED", cmd_status);
+ result = (cmd_status == 0) ? 0 : -EIO;
+
+EXIT:
+ alpx_axcmem_setRegU8Value(smalar_reg, ALPDANTE_SMALAR_AVAILABLE);
+ dev_dbg(alpx_dev->dev," Semaphore released\n");
+ return result;
+}
+
+int alpdante_card_setup(struct alpx_device *alpx_dev, struct snd_card *card, unsigned int configured_fs, bool is_loopback_enabled)
+{
+ unsigned int sr_config_value = 0;
+ void* sr_config_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_CLKPR_LOC,
+ &ALPDANTE_SRConfig_LOC);
+
+ unsigned int fppr_prod_test_value = 0;
+ void* fppr_prod_test_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_ERRTST_LOC,
+ &ALPDANTE_PROD_TEST_LOC);
+
+ dev_dbg(alpx_dev->dev, "Setting AlpDANTE card {S/N: %llu} ...\n", alpx_dev->identity.serial_number);
+
+ switch (configured_fs) {
+ case 44100:
+ sr_config_value = ALPDANTE_CLK_MANAGER_CLK_VALUE_44_1K;
+ alpx_dev->variant->capture_hw->rates=SNDRV_PCM_RATE_44100;
+ alpx_dev->variant->capture_hw->channels_min = 64;
+ alpx_dev->variant->capture_hw->channels_max = 64;
+ alpx_dev->variant->capture_hw->rate_min = configured_fs;
+ alpx_dev->variant->capture_hw->rate_max = configured_fs;
+ break;
+ case 48000:
+ sr_config_value = ALPDANTE_CLK_MANAGER_CLK_VALUE_48K;
+ alpx_dev->variant->capture_hw->rates=SNDRV_PCM_RATE_48000;
+ alpx_dev->variant->capture_hw->channels_min = 64;
+ alpx_dev->variant->capture_hw->channels_max = 64;
+ alpx_dev->variant->capture_hw->rate_min = configured_fs;
+ alpx_dev->variant->capture_hw->rate_max = configured_fs;
+ break;
+ case 88200:
+ sr_config_value = ALPDANTE_CLK_MANAGER_CLK_VALUE_88_2K;
+ alpx_dev->variant->capture_hw->rates=SNDRV_PCM_RATE_88200;
+ alpx_dev->variant->capture_hw->channels_min = 32;
+ alpx_dev->variant->capture_hw->channels_max = 32;
+ alpx_dev->variant->capture_hw->rate_min = configured_fs;
+ alpx_dev->variant->capture_hw->rate_max = configured_fs;
+ break;
+ case 96000:
+ sr_config_value = ALPDANTE_CLK_MANAGER_CLK_VALUE_96K;
+ alpx_dev->variant->capture_hw->rates=SNDRV_PCM_RATE_96000;
+ alpx_dev->variant->capture_hw->channels_min = 32;
+ alpx_dev->variant->capture_hw->channels_max = 32;
+ alpx_dev->variant->capture_hw->rate_min = configured_fs;
+ alpx_dev->variant->capture_hw->rate_max = configured_fs;
+ break;
+ case 176400:
+ sr_config_value = ALPDANTE_CLK_MANAGER_CLK_VALUE_176_4K;
+ alpx_dev->variant->capture_hw->rates=SNDRV_PCM_RATE_176400;
+ alpx_dev->variant->capture_hw->channels_min = 16;
+ alpx_dev->variant->capture_hw->channels_max = 16;
+ alpx_dev->variant->capture_hw->rate_min = configured_fs;
+ alpx_dev->variant->capture_hw->rate_max = configured_fs;
+ break;
+ case 192000:
+ sr_config_value = ALPDANTE_CLK_MANAGER_CLK_VALUE_192K;
+ alpx_dev->variant->capture_hw->rates=SNDRV_PCM_RATE_192000;
+ alpx_dev->variant->capture_hw->channels_min = 16;
+ alpx_dev->variant->capture_hw->channels_max = 16;
+ alpx_dev->variant->capture_hw->rate_min = configured_fs;
+ alpx_dev->variant->capture_hw->rate_max = configured_fs;
+ break;
+ default:
+ dev_err(alpx_dev->dev, "AlpDANTE card {S/N: %llu}; %dHz : unsupported FS, keep default %dHz !\n", alpx_dev->identity.serial_number, configured_fs, alpx_dev->variant->capture_hw->rate_min);
+ };
+
+ dev_dbg(alpx_dev->dev, "Setting AlpDANTE card {S/N: %llu}: FS:%dHz => reg=0x%x\n", alpx_dev->identity.serial_number,
+ alpx_dev->variant->capture_hw->rate_min, sr_config_value);
+
+ alpx_axcmem_setRegU8Value(sr_config_reg, sr_config_value);
+
+
+ dev_info(alpx_dev->dev, "AlpDANTE card {S/N: %llu}: loopback mode %s.\n",
+ alpx_dev->identity.serial_number,
+ is_loopback_enabled ? "ENABLED" : "DISABLED");
+
+ fppr_prod_test_value = alpx_axcmem_getRegU8Value(fppr_prod_test_reg);
+ fppr_prod_test_value = is_loopback_enabled ?
+ (ALPDANTE_PROD_TEST_LOOPBACK | fppr_prod_test_value) :
+ (fppr_prod_test_value & ~ALPDANTE_PROD_TEST_LOOPBACK);
+ alpx_axcmem_setRegU8Value(fppr_prod_test_reg, fppr_prod_test_value);
+
+ dev_dbg(alpx_dev->dev, "fppr_prod_test_value = 0x%x, reg: 0x%x\n", fppr_prod_test_value,
+ alpx_axcmem_getRegU8Value(fppr_prod_test_reg));
+
+ return alpdante_store_config(alpx_dev);
+}
+
+/* Helpers */
+unsigned int
+alpx_get_samples_counter(struct alpx_device *alpx_dev)
+{
+ if (alpx_dev->variant->model != ALPX_VARIANT_MODEL_ALPDANTE) {
+ return readl(ALPX_REG(alpx_dev, ALP, CLK_MANAGER, SAMPLES_COUNT));
+ }
+ else {
+ void* sample_count_reg = alpx_axcmem_getPointedRegAddrByRefLoc(alpx_dev, &ALPDANTE_CSPPR_LOC, &ALPDANTE_SAMPLE_COUNT_LOC);
+ return alpx_axcmem_getRegU32Value(sample_count_reg);
+ }
+ return 0;
+}