From 6f1b3afa15dafdac886f86d130ff39b6e001c4af Mon Sep 17 00:00:00 2001
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Date: Sat, 3 Jul 2021 08:59:21 +0200
Subject: [PATCH 059/484] cw1200: xr819 hacks

Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
 drivers/net/wireless/st/cw1200/cw1200.h      |  7 ++-
 drivers/net/wireless/st/cw1200/cw1200_sdio.c | 59 ++++++++++++++++++--
 drivers/net/wireless/st/cw1200/cw1200_spi.c  |  3 +-
 drivers/net/wireless/st/cw1200/fwio.c        | 20 +++++--
 drivers/net/wireless/st/cw1200/fwio.h        |  3 +
 drivers/net/wireless/st/cw1200/main.c        |  9 ++-
 drivers/net/wireless/st/cw1200/queue.h       |  7 ++-
 drivers/net/wireless/st/cw1200/sta.c         | 46 ++++++++-------
 drivers/net/wireless/st/cw1200/wsm.c         |  9 +++
 9 files changed, 128 insertions(+), 35 deletions(-)

diff --git a/drivers/net/wireless/st/cw1200/cw1200.h b/drivers/net/wireless/st/cw1200/cw1200.h
index 48f808cdc1cb..22bf12ea2859 100644
--- a/drivers/net/wireless/st/cw1200/cw1200.h
+++ b/drivers/net/wireless/st/cw1200/cw1200.h
@@ -117,6 +117,10 @@ struct cw1200_common {
 		CW1200_HW_REV_CUT22 = 22,
 		CW1X60_HW_REV       = 40,
 	} hw_revision;
+	enum cw1200_fw_api {
+		CW1200_FW_API_ORIGINAL = 0,
+		CW1200_FW_API_XRADIO,
+	} fw_api;
 	int                             hw_refclk;
 	bool				hw_have_5ghz;
 	const struct firmware		*sdd;
@@ -292,7 +296,8 @@ int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
 		      struct device *pdev,
 		      struct cw1200_common **pself,
 		      int ref_clk, const u8 *macaddr,
-		      const char *sdd_path, bool have_5ghz);
+		      const char *sdd_path, bool have_5ghz,
+		      unsigned int fw_api);
 void cw1200_core_release(struct cw1200_common *self);
 
 #define FWLOAD_BLOCK_SIZE (1024)
diff --git a/drivers/net/wireless/st/cw1200/cw1200_sdio.c b/drivers/net/wireless/st/cw1200/cw1200_sdio.c
index 00c4731d8f8e..b7f8a14e12bc 100644
--- a/drivers/net/wireless/st/cw1200/cw1200_sdio.c
+++ b/drivers/net/wireless/st/cw1200/cw1200_sdio.c
@@ -15,6 +15,9 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_ids.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
 #include <net/mac80211.h>
 
 #include "cw1200.h"
@@ -30,9 +33,7 @@ MODULE_LICENSE("GPL");
 
 /* Default platform data for Sagrad modules */
 static struct cw1200_platform_data_sdio sagrad_109x_evk_platform_data = {
-	.ref_clk = 38400,
-	.have_5ghz = false,
-	.sdd_file = "sdd_sagrad_1091_1098.bin",
+	.ref_clk = 24000,
 };
 
 /* Allow platform data to be overridden */
@@ -50,8 +51,15 @@ struct hwbus_priv {
 };
 
 static const struct sdio_device_id cw1200_sdio_ids[] = {
-	{ SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200) },
-	{ /* end: all zeroes */			},
+	{
+		SDIO_DEVICE(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200),
+		.driver_data = CW1200_FW_API_ORIGINAL
+	},
+	{
+		SDIO_DEVICE(SDIO_VENDOR_ID_STE, 0x2281),
+		.driver_data = CW1200_FW_API_XRADIO
+	},
+	{ /* end: all zeroes */ },
 };
 MODULE_DEVICE_TABLE(sdio, cw1200_sdio_ids);
 
@@ -274,6 +282,41 @@ static const struct hwbus_ops cw1200_sdio_hwbus_ops = {
 	.power_mgmt		= cw1200_sdio_pm,
 };
 
+static const struct of_device_id xradio_sdio_of_match_table[] = {
+	{ .compatible = "xradio,xr819" },
+	{ }
+};
+
+static int cw1200_probe_of(struct sdio_func *func)
+{
+	struct device *dev = &func->dev;
+	struct device_node *np = dev->of_node;
+	const struct of_device_id *of_id;
+	u8 *macaddr;
+	int irq;
+
+	of_id = of_match_node(xradio_sdio_of_match_table, np);
+	if (!of_id)
+		return -ENODEV;
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq) {
+		pr_err("SDIO: No irq in platform data\n");
+		return -EINVAL;
+	}
+
+	global_plat_data->irq = irq;
+
+	macaddr = devm_kmalloc(dev, ETH_ALEN, GFP_KERNEL);
+	if (!macaddr)
+		return -ENOMEM;
+
+	if (!of_get_mac_address(np, macaddr))
+		global_plat_data->macaddr = macaddr;
+
+	return 0;
+}
+
 /* Probe Function to be called by SDIO stack when device is discovered */
 static int cw1200_sdio_probe(struct sdio_func *func,
 			     const struct sdio_device_id *id)
@@ -287,6 +330,8 @@ static int cw1200_sdio_probe(struct sdio_func *func,
 	if (func->num != 0x01)
 		return -ENODEV;
 
+	cw1200_probe_of(func);
+
 	self = kzalloc(sizeof(*self), GFP_KERNEL);
 	if (!self) {
 		pr_err("Can't allocate SDIO hwbus_priv.\n");
@@ -294,6 +339,7 @@ static int cw1200_sdio_probe(struct sdio_func *func,
 	}
 
 	func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+	func->card->quirks |= MMC_QUIRK_BROKEN_BYTE_MODE_512;
 
 	self->pdata = global_plat_data; /* FIXME */
 	self->func = func;
@@ -309,7 +355,8 @@ static int cw1200_sdio_probe(struct sdio_func *func,
 				   self->pdata->ref_clk,
 				   self->pdata->macaddr,
 				   self->pdata->sdd_file,
-				   self->pdata->have_5ghz);
+				   self->pdata->have_5ghz,
+				   id->driver_data);
 	if (status) {
 		cw1200_sdio_irq_unsubscribe(self);
 		sdio_claim_host(func);
diff --git a/drivers/net/wireless/st/cw1200/cw1200_spi.c b/drivers/net/wireless/st/cw1200/cw1200_spi.c
index 52386dfb5f4a..2dcf69ccec99 100644
--- a/drivers/net/wireless/st/cw1200/cw1200_spi.c
+++ b/drivers/net/wireless/st/cw1200/cw1200_spi.c
@@ -421,7 +421,8 @@ static int cw1200_spi_probe(struct spi_device *func)
 				   self->pdata->ref_clk,
 				   self->pdata->macaddr,
 				   self->pdata->sdd_file,
-				   self->pdata->have_5ghz);
+				   self->pdata->have_5ghz,
+				   CW1200_FW_API_ORIGINAL);
 
 	if (status) {
 		cw1200_spi_irq_unsubscribe(self);
diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c
index a71e90fff616..55cd897a9d4d 100644
--- a/drivers/net/wireless/st/cw1200/fwio.c
+++ b/drivers/net/wireless/st/cw1200/fwio.c
@@ -51,10 +51,15 @@ static int cw1200_get_hw_type(u32 config_reg_val, int *major_revision)
 static int cw1200_load_bootloader(struct cw1200_common *priv)
 {
 	const struct firmware *bootloader = NULL;
-	const char *bl_path = BOOTLOADER_CW1X60;
 	u32 *data, i, addr = AHB_MEMORY_ADDRESS;
+	const char *bl_path;
 	int ret;
 
+	if (priv->fw_api == CW1200_FW_API_XRADIO)
+		bl_path = BOOTLOADER_XRADIO;
+	else
+		bl_path = BOOTLOADER_CW1X60;
+
 	ret = request_firmware(&bootloader, bl_path, priv->pdev);
 	if (ret) {
 		pr_err("Can't load bootloader file %s.\n", bl_path);
@@ -145,9 +150,16 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
 			priv->sdd_path = SDD_FILE_22;
 		break;
 	case CW1X60_HW_REV:
-		fw_path = FIRMWARE_CW1X60;
-		if (!priv->sdd_path)
-			priv->sdd_path = SDD_FILE_CW1X60;
+		if (priv->fw_api == CW1200_FW_API_XRADIO)
+			fw_path = FIRMWARE_XRADIO;
+		else
+			fw_path = FIRMWARE_CW1X60;
+		if (!priv->sdd_path) {
+			if (priv->fw_api == CW1200_FW_API_XRADIO)
+				priv->sdd_path = SDD_FILE_XRADIO;
+			else
+				priv->sdd_path = SDD_FILE_CW1X60;
+		}
 		break;
 	default:
 		pr_err("Invalid silicon revision %d.\n", priv->hw_revision);
diff --git a/drivers/net/wireless/st/cw1200/fwio.h b/drivers/net/wireless/st/cw1200/fwio.h
index c287160a492e..e18f7628cf4c 100644
--- a/drivers/net/wireless/st/cw1200/fwio.h
+++ b/drivers/net/wireless/st/cw1200/fwio.h
@@ -15,12 +15,15 @@
 #define FWIO_H_INCLUDED
 
 #define BOOTLOADER_CW1X60       "boot_cw1x60.bin"
+#define BOOTLOADER_XRADIO	"boot_xr819.bin"
 #define FIRMWARE_CW1X60		"wsm_cw1x60.bin"
+#define FIRMWARE_XRADIO		"fw_xr819.bin"
 #define FIRMWARE_CUT22		"wsm_22.bin"
 #define FIRMWARE_CUT20		"wsm_20.bin"
 #define FIRMWARE_CUT11		"wsm_11.bin"
 #define FIRMWARE_CUT10		"wsm_10.bin"
 #define SDD_FILE_CW1X60		"sdd_cw1x60.bin"
+#define SDD_FILE_XRADIO		"sdd_xr819.bin"
 #define SDD_FILE_22		"sdd_22.bin"
 #define SDD_FILE_20		"sdd_20.bin"
 #define SDD_FILE_11		"sdd_11.bin"
diff --git a/drivers/net/wireless/st/cw1200/main.c b/drivers/net/wireless/st/cw1200/main.c
index 5d569eeb353f..465310d5ad42 100644
--- a/drivers/net/wireless/st/cw1200/main.c
+++ b/drivers/net/wireless/st/cw1200/main.c
@@ -255,7 +255,8 @@ static const struct wiphy_wowlan_support cw1200_wowlan_support = {
 
 
 static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
-						const bool have_5ghz)
+					       const bool have_5ghz,
+					       unsigned int fw_api)
 {
 	int i, band;
 	struct ieee80211_hw *hw;
@@ -271,6 +272,7 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
 	priv->mode = NL80211_IFTYPE_UNSPECIFIED;
 	priv->rates = cw1200_rates; /* TODO: fetch from FW */
 	priv->mcs_rates = cw1200_n_rates;
+	priv->fw_api = fw_api;
 	if (cw1200_ba_rx_tids != -1)
 		priv->ba_rx_tid_mask = cw1200_ba_rx_tids;
 	else
@@ -522,7 +524,8 @@ int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
 		      struct device *pdev,
 		      struct cw1200_common **core,
 		      int ref_clk, const u8 *macaddr,
-		      const char *sdd_path, bool have_5ghz)
+		      const char *sdd_path, bool have_5ghz,
+		      unsigned int fw_api)
 {
 	int err = -EINVAL;
 	struct ieee80211_hw *dev;
@@ -532,7 +535,7 @@ int cw1200_core_probe(const struct hwbus_ops *hwbus_ops,
 		.disable_more_flag_usage = true,
 	};
 
-	dev = cw1200_init_common(macaddr, have_5ghz);
+	dev = cw1200_init_common(macaddr, have_5ghz, fw_api);
 	if (!dev)
 		goto err;
 
diff --git a/drivers/net/wireless/st/cw1200/queue.h b/drivers/net/wireless/st/cw1200/queue.h
index d46304b58747..9635fb58f3eb 100644
--- a/drivers/net/wireless/st/cw1200/queue.h
+++ b/drivers/net/wireless/st/cw1200/queue.h
@@ -101,7 +101,12 @@ bool cw1200_queue_stats_is_empty(struct cw1200_queue_stats *stats,
 
 static inline u8 cw1200_queue_get_queue_id(u32 packet_id)
 {
-	return (packet_id >> 16) & 0xFF;
+	return (packet_id >> 16) & 0xF;
+}
+
+static inline u8 cw1200_queue_get_link_id(u32 packet_id)
+{
+	return (packet_id >> 24) & 0xF;
 }
 
 static inline u8 cw1200_queue_get_generation(u32 packet_id)
diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c
index 444272caf124..5ae9591db577 100644
--- a/drivers/net/wireless/st/cw1200/sta.c
+++ b/drivers/net/wireless/st/cw1200/sta.c
@@ -343,28 +343,34 @@ int cw1200_config(struct ieee80211_hw *dev, u32 changed)
 	if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) &&
 	    (priv->channel != conf->chandef.chan)) {
 		struct ieee80211_channel *ch = conf->chandef.chan;
-		struct wsm_switch_channel channel = {
-			.channel_number = ch->hw_value,
-		};
+
 		pr_debug("[STA] Freq %d (wsm ch: %d).\n",
 			 ch->center_freq, ch->hw_value);
 
-		/* __cw1200_flush() implicitly locks tx, if successful */
-		if (!__cw1200_flush(priv, false)) {
-			if (!wsm_switch_channel(priv, &channel)) {
-				ret = wait_event_timeout(priv->channel_switch_done,
-							 !priv->channel_switch_in_progress,
-							 3 * HZ);
-				if (ret) {
-					/* Already unlocks if successful */
-					priv->channel = ch;
-					ret = 0;
+		if (priv->fw_api == CW1200_FW_API_XRADIO) {
+			priv->channel = ch;
+		} else {
+			struct wsm_switch_channel channel = {
+				.channel_number = ch->hw_value,
+			};
+
+			/* __cw1200_flush() implicitly locks tx, if successful */
+			if (!__cw1200_flush(priv, false)) {
+				if (!wsm_switch_channel(priv, &channel)) {
+					ret = wait_event_timeout(priv->channel_switch_done,
+								!priv->channel_switch_in_progress,
+								3 * HZ);
+					if (ret) {
+						/* Already unlocks if successful */
+						priv->channel = ch;
+						ret = 0;
+					} else {
+						ret = -ETIMEDOUT;
+					}
 				} else {
-					ret = -ETIMEDOUT;
+					/* Unlock if switch channel fails */
+					wsm_unlock_tx(priv);
 				}
-			} else {
-				/* Unlock if switch channel fails */
-				wsm_unlock_tx(priv);
 			}
 		}
 	}
@@ -1303,7 +1309,7 @@ static void cw1200_do_join(struct cw1200_common *priv)
 	}
 
 	/* Enable asynchronous join calls */
-	if (!priv->vif->cfg.ibss_joined) {
+	if (priv->fw_api != CW1200_FW_API_XRADIO && !priv->vif->cfg.ibss_joined) {
 		join.flags |= WSM_JOIN_FLAGS_FORCE;
 		join.flags |= WSM_JOIN_FLAGS_FORCE_WITH_COMPLETE_IND;
 	}
@@ -1743,7 +1749,9 @@ void cw1200_set_cts_work(struct work_struct *work)
 
 	wsm_write_mib(priv, WSM_MIB_ID_NON_ERP_PROTECTION,
 		      &use_cts_prot, sizeof(use_cts_prot));
-	wsm_update_ie(priv, &update_ie);
+	if (priv->fw_api != CW1200_FW_API_XRADIO ||
+	    priv->mode != NL80211_IFTYPE_STATION)
+		wsm_update_ie(priv, &update_ie);
 
 	return;
 }
diff --git a/drivers/net/wireless/st/cw1200/wsm.c b/drivers/net/wireless/st/cw1200/wsm.c
index 4a9e4b5d3547..ee378265aee5 100644
--- a/drivers/net/wireless/st/cw1200/wsm.c
+++ b/drivers/net/wireless/st/cw1200/wsm.c
@@ -360,9 +360,18 @@ static int wsm_tx_confirm(struct cw1200_common *priv,
 	tx_confirm.tx_rate = WSM_GET8(buf);
 	tx_confirm.ack_failures = WSM_GET8(buf);
 	tx_confirm.flags = WSM_GET16(buf);
+	if (priv->fw_api == CW1200_FW_API_XRADIO) {
+		/* rate_try[3] */
+		WSM_GET32(buf);
+		WSM_GET32(buf);
+		WSM_GET32(buf);
+	}
 	tx_confirm.media_delay = WSM_GET32(buf);
 	tx_confirm.tx_queue_delay = WSM_GET32(buf);
 
+	if (priv->fw_api == CW1200_FW_API_XRADIO)
+		link_id = cw1200_queue_get_link_id(tx_confirm.packet_id);
+
 	cw1200_tx_confirm_cb(priv, link_id, &tx_confirm);
 	return 0;
 
-- 
2.49.0

