/*
  * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
        }
 }
 
-static int wil_target_reset(struct wil6210_priv *wil)
+static int wil_target_reset(struct wil6210_priv *wil, int no_flash)
 {
        int delay = 0;
        u32 x, x1 = 0;
 
        wil_halt_cpu(wil);
 
-       /* clear all boot loader "ready" bits */
-       wil_w(wil, RGF_USER_BL +
-             offsetof(struct bl_dedicated_registers_v0, boot_loader_ready), 0);
+       if (!no_flash)
+               /* clear all boot loader "ready" bits */
+               wil_w(wil, RGF_USER_BL +
+                     offsetof(struct bl_dedicated_registers_v0,
+                              boot_loader_ready), 0);
        /* Clear Fw Download notification */
        wil_c(wil, RGF_USER_USAGE_6, BIT(0));
 
        wil_w(wil, RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
 
        /* wait until device ready. typical time is 20..80 msec */
-       do {
-               msleep(RST_DELAY);
-               x = wil_r(wil, RGF_USER_BL +
-                         offsetof(struct bl_dedicated_registers_v0,
-                                  boot_loader_ready));
-               if (x1 != x) {
-                       wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n", x1, x);
-                       x1 = x;
-               }
-               if (delay++ > RST_COUNT) {
-                       wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
-                               x);
-                       return -ETIME;
-               }
-       } while (x != BL_READY);
+       if (no_flash)
+               do {
+                       msleep(RST_DELAY);
+                       x = wil_r(wil, USER_EXT_USER_PMU_3);
+                       if (delay++ > RST_COUNT) {
+                               wil_err(wil, "Reset not completed, PMU_3 0x%08x\n",
+                                       x);
+                               return -ETIME;
+                       }
+               } while ((x & BIT_PMU_DEVICE_RDY) == 0);
+       else
+               do {
+                       msleep(RST_DELAY);
+                       x = wil_r(wil, RGF_USER_BL +
+                                 offsetof(struct bl_dedicated_registers_v0,
+                                          boot_loader_ready));
+                       if (x1 != x) {
+                               wil_dbg_misc(wil, "BL.ready 0x%08x => 0x%08x\n",
+                                            x1, x);
+                               x1 = x;
+                       }
+                       if (delay++ > RST_COUNT) {
+                               wil_err(wil, "Reset not completed, bl.ready 0x%08x\n",
+                                       x);
+                               return -ETIME;
+                       }
+               } while (x != BL_READY);
 
        wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
 
        }
 }
 
+static int wil_get_otp_info(struct wil6210_priv *wil)
+{
+       struct net_device *ndev = wil_to_ndev(wil);
+       struct wiphy *wiphy = wil_to_wiphy(wil);
+       u8 mac[8];
+
+       wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(RGF_OTP_MAC),
+                            sizeof(mac));
+       if (!is_valid_ether_addr(mac)) {
+               wil_err(wil, "Invalid MAC %pM\n", mac);
+               return -EINVAL;
+       }
+
+       ether_addr_copy(ndev->perm_addr, mac);
+       ether_addr_copy(wiphy->perm_addr, mac);
+       if (!is_valid_ether_addr(ndev->dev_addr))
+               ether_addr_copy(ndev->dev_addr, mac);
+
+       return 0;
+}
+
 static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
 {
        ulong to = msecs_to_jiffies(1000);
 {
        int rc;
        unsigned long status_flags = BIT(wil_status_resetting);
+       int no_flash;
 
        wil_dbg_misc(wil, "reset\n");
 
        flush_workqueue(wil->wq_service);
        flush_workqueue(wil->wmi_wq);
 
-       wil_bl_crash_info(wil, false);
+       no_flash = test_bit(hw_capa_no_flash, wil->hw_capa);
+       if (!no_flash)
+               wil_bl_crash_info(wil, false);
        wil_disable_irq(wil);
-       rc = wil_target_reset(wil);
+       rc = wil_target_reset(wil, no_flash);
        wil6210_clear_irq(wil);
        wil_enable_irq(wil);
        wil_rx_fini(wil);
        if (rc) {
-               wil_bl_crash_info(wil, true);
+               if (!no_flash)
+                       wil_bl_crash_info(wil, true);
                goto out;
        }
 
-       rc = wil_get_bl_info(wil);
-       if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
-               rc = 0;
+       if (no_flash) {
+               rc = wil_get_otp_info(wil);
+       } else {
+               rc = wil_get_bl_info(wil);
+               if (rc == -EAGAIN && !load_fw)
+                       /* ignore RF error if not going up */
+                       rc = 0;
+       }
        if (rc)
                goto out;
 
 
                            RGF_USER_REVISION_ID_MASK);
        int platform_capa;
 
-       bitmap_zero(wil->hw_capabilities, hw_capability_last);
+       bitmap_zero(wil->hw_capa, hw_capa_last);
        bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
        bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX);
        wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
                memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping));
                wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE;
                wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE;
+               if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) &
+                   BIT_NO_FLASH_INDICATION)
+                       set_bit(hw_capa_no_flash, wil->hw_capa);
                break;
        default:
                wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
                return -EINVAL;
        }
 
-       wil_info(wil, "Board hardware is %s\n", wil->hw_name);
+       wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name,
+                test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : "");
 
        /* Get platform capabilities */
        if (wil->platform_ops.get_capa) {
 
 #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1     (0x880c2c)
 #define RGF_USER_SPARROW_M_4                   (0x880c50) /* Sparrow */
        #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF        BIT(2)
+#define RGF_USER_OTP_HW_RD_MACHINE_1   (0x880ce0)
+       #define BIT_NO_FLASH_INDICATION         BIT(8)
 
 #define RGF_DMA_EP_TX_ICR              (0x881bb4) /* struct RGF_ICR */
        #define BIT_DMA_EP_TX_ICR_TX_DONE       BIT(0)
 #define RGF_CAF_PLL_LOCK_STATUS                (0x88afec)
        #define BIT_CAF_OSC_DIG_XTAL_STABLE     BIT(0)
 
+#define USER_EXT_USER_PMU_3            (0x88d00c)
+       #define BIT_PMU_DEVICE_RDY              BIT(0)
+
 #define RGF_USER_JTAG_DEV_ID   (0x880b34) /* device ID */
        #define JTAG_DEV_ID_SPARROW     (0x2632072f)
        #define JTAG_DEV_ID_TALYN       (0x7e0e1)
        #define REVISION_ID_SPARROW_B0  (0x0)
        #define REVISION_ID_SPARROW_D0  (0x3)
 
+#define RGF_OTP_MAC                    (0x8a0620)
+
 /* crash codes for FW/Ucode stored here */
 
 /* ASSERT RGFs */
 };
 
 enum {
-       hw_capability_last
+       hw_capa_no_flash,
+       hw_capa_last
 };
 
 struct wil_probe_client_req {
        u8 chip_revision;
        const char *hw_name;
        const char *wil_fw_name;
-       DECLARE_BITMAP(hw_capabilities, hw_capability_last);
+       char *board_file;
+       DECLARE_BITMAP(hw_capa, hw_capa_last);
        DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
        DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
        u8 n_mids; /* number of additional MIDs as reported by FW */