/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2005-2014, 2018-2020 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2021 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016 Intel Deutschland GmbH
  */
 #define UREG_DOORBELL_TO_ISR6_RESUME   BIT(19)
 #define UREG_DOORBELL_TO_ISR6_PNVM     BIT(20)
 
+#define CNVI_MBOX_C                    0xA3400C
+
 #define FSEQ_ERROR_CODE                        0xA340C8
 #define FSEQ_TOP_INIT_VERSION          0xA34038
 #define FSEQ_CNVIO_INIT_VERSION                0xA3403C
 
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2003-2015, 2018-2020 Intel Corporation
+ * Copyright (C) 2003-2015, 2018-2021 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
  * @alloc_page_lock: spinlock for the page allocator
  * @alloc_page: allocated page to still use parts of
  * @alloc_page_used: how much of the allocated page was already used (bytes)
+ * @rf_name: name/version of the CRF, if any
  */
 struct iwl_trans_pcie {
        struct iwl_rxq *rxq;
        bool fw_reset_handshake;
        bool fw_reset_done;
        wait_queue_head_t fw_reset_waitq;
+
+       char rf_name[32];
 };
 
 static inline struct iwl_trans_pcie *
 
        return 0;
 }
 
+static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       char *buf = trans_pcie->rf_name;
+       size_t buflen = sizeof(trans_pcie->rf_name);
+       size_t pos;
+       u32 version;
+
+       if (buf[0])
+               return;
+
+       switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) {
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF):
+               pos = scnprintf(buf, buflen, "JF");
+               break;
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF):
+               pos = scnprintf(buf, buflen, "GF");
+               break;
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4):
+               pos = scnprintf(buf, buflen, "GF4");
+               break;
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR):
+               pos = scnprintf(buf, buflen, "HR");
+               break;
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1):
+               pos = scnprintf(buf, buflen, "HR1");
+               break;
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB):
+               pos = scnprintf(buf, buflen, "HRCDB");
+               break;
+       default:
+               return;
+       }
+
+       switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) {
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR):
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1):
+       case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB):
+               version = iwl_read_prph(trans, CNVI_MBOX_C);
+               switch (version) {
+               case 0x20000:
+                       pos += scnprintf(buf + pos, buflen - pos, " B3");
+                       break;
+               case 0x120000:
+                       pos += scnprintf(buf + pos, buflen - pos, " B5");
+                       break;
+               default:
+                       pos += scnprintf(buf + pos, buflen - pos,
+                                        " (0x%x)", version);
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       pos += scnprintf(buf + pos, buflen - pos, ", rfid=0x%x",
+                        trans->hw_rf_id);
+
+       IWL_INFO(trans, "Detected RF %s\n", buf);
+
+       /*
+        * also add a \n for debugfs - need to do it after printing
+        * since our IWL_INFO machinery wants to see a static \n at
+        * the end of the string
+        */
+       pos += scnprintf(buf + pos, buflen - pos, "\n");
+}
+
 void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        iwl_enable_interrupts(trans);
        mutex_lock(&trans_pcie->mutex);
        iwl_pcie_check_hw_rf_kill(trans);
+
+       iwl_pcie_get_rf_name(trans);
        mutex_unlock(&trans_pcie->mutex);
 }
 
 
        return bytes_copied;
 }
 
+static ssize_t iwl_dbgfs_rf_read(struct file *file,
+                                char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (!trans_pcie->rf_name[0])
+               return -ENODEV;
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      trans_pcie->rf_name,
+                                      strlen(trans_pcie->rf_name));
+}
+
 DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
 DEBUGFS_READ_FILE_OPS(fh_reg);
 DEBUGFS_READ_FILE_OPS(rx_queue);
 DEBUGFS_WRITE_FILE_OPS(csr);
 DEBUGFS_READ_WRITE_FILE_OPS(rfkill);
+DEBUGFS_READ_FILE_OPS(rf);
+
 static const struct file_operations iwl_dbgfs_tx_queue_ops = {
        .owner = THIS_MODULE,
        .open = iwl_dbgfs_tx_queue_open,
        DEBUGFS_ADD_FILE(fh_reg, dir, 0400);
        DEBUGFS_ADD_FILE(rfkill, dir, 0600);
        DEBUGFS_ADD_FILE(monitor_data, dir, 0400);
+       DEBUGFS_ADD_FILE(rf, dir, 0400);
 }
 
 static void iwl_trans_pcie_debugfs_cleanup(struct iwl_trans *trans)