All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops
@ 2022-04-21 12:08 Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 01/14] rtw89: pci: add variant IMR/ISR and configure functions Ping-Ke Shih
                   ` (13 more replies)
  0 siblings, 14 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

The PCI code of 8852CE is different from 8852AE. The IMR/ISR addresses are
different, and 8852CE has a special low power mode that uses another set
of addresses. To handle the special mode, we add a special interrupt
threadfn to handle packets, because regular NAPI poll function does many
things that can't access at this mode.

Another special handle is RPP (TX skb completion) prior to TX BD (TX ring
completion). In low mode power, it can be possible, so we extend the code
to handle this case as well as normal mode.

Patch 3/14 is to optimize count of reading IO, and patch 8/14 is to resolve
some warnings happened on 8852ce, because PCI ring registers are power-off
after running power-off function. These registers on 8852ae aren't
power-off.

Patches 9/14-14/14 are to add chip ops of 8852c as description of the
patches individually.

Ping-Ke Shih (14):
  rtw89: pci: add variant IMR/ISR and configure functions
  rtw89: pci: add variant RPWM/CPWM to enter low power mode
  rtw89: pci: reclaim TX BD only if it really need
  rtw89: pci: does RX in interrupt threadfn if low power mode
  rtw89: ser: re-enable interrupt in threadfn if under_recovery
  rtw89: ps: access TX/RX rings via another registers in low power mode
  rtw89: pci: allow to process RPP prior to TX BD
  rtw89: don't flush hci queues and send h2c if power is off
  rtw89: add RF H2C to notify firmware
  rtw89: 8852c: configure default BB TX/RX path
  rtw89: 8852c: implement chip_ops related to TX power
  rtw89: 8852c: implement chip_ops::get_thermal
  rtw89: 8852c: fill freq and band of RX status by PPDU report
  rtw89: 8852c: add chip_ops related to BTC

 drivers/net/wireless/realtek/rtw89/core.c     |  10 +
 drivers/net/wireless/realtek/rtw89/core.h     |  34 +
 drivers/net/wireless/realtek/rtw89/fw.c       |  39 +
 drivers/net/wireless/realtek/rtw89/fw.h       |  12 +
 drivers/net/wireless/realtek/rtw89/mac.c      |   6 +-
 drivers/net/wireless/realtek/rtw89/pci.c      | 339 ++++++--
 drivers/net/wireless/realtek/rtw89/pci.h      | 144 ++++
 drivers/net/wireless/realtek/rtw89/phy.c      |   1 +
 drivers/net/wireless/realtek/rtw89/ps.c       |  34 +-
 drivers/net/wireless/realtek/rtw89/reg.h      |  83 +-
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |   2 +
 .../net/wireless/realtek/rtw89/rtw8852ae.c    |   8 +
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 766 ++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/rtw8852c.h |   1 +
 .../net/wireless/realtek/rtw89/rtw8852ce.c    |  16 +
 15 files changed, 1438 insertions(+), 57 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 01/14] rtw89: pci: add variant IMR/ISR and configure functions
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-24 11:31   ` Kalle Valo
  2022-04-21 12:08 ` [PATCH 02/14] rtw89: pci: add variant RPWM/CPWM to enter low power mode Ping-Ke Shih
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

8852CE uses different but similar IMR/ISR registers, and its masks are also
different in various states, so add config_intr_mask ops to configure masks
according to under_recovery or low_power states.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/pci.c      | 168 +++++++++++++++---
 drivers/net/wireless/realtek/rtw89/pci.h      | 123 +++++++++++++
 .../net/wireless/realtek/rtw89/rtw8852ae.c    |   4 +
 .../net/wireless/realtek/rtw89/rtw8852ce.c    |   4 +
 4 files changed, 270 insertions(+), 29 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index ecb419010f0c2..0d9cd8033c778 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -612,9 +612,9 @@ static void rtw89_pci_isr_rxd_unavail(struct rtw89_dev *rtwdev,
 	}
 }
 
-static void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
-				      struct rtw89_pci *rtwpci,
-				      struct rtw89_pci_isrs *isrs)
+void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
+			       struct rtw89_pci *rtwpci,
+			       struct rtw89_pci_isrs *isrs)
 {
 	isrs->halt_c2h_isrs = rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs;
 	isrs->isrs[0] = rtw89_read32(rtwdev, R_AX_PCIE_HISR00) & rtwpci->intrs[0];
@@ -624,6 +624,28 @@ static void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
 	rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isrs->isrs[0]);
 	rtw89_write32(rtwdev, R_AX_PCIE_HISR10, isrs->isrs[1]);
 }
+EXPORT_SYMBOL(rtw89_pci_recognize_intrs);
+
+void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev,
+				  struct rtw89_pci *rtwpci,
+				  struct rtw89_pci_isrs *isrs)
+{
+	isrs->ind_isrs = rtw89_read32(rtwdev, R_AX_PCIE_HISR00_V1) & rtwpci->ind_intrs;
+	isrs->halt_c2h_isrs = isrs->ind_isrs & B_AX_HS0ISR_IND_INT_EN ?
+			      rtw89_read32(rtwdev, R_AX_HISR0) & rtwpci->halt_c2h_intrs : 0;
+	isrs->isrs[0] = isrs->ind_isrs & B_AX_HCI_AXIDMA_INT_EN ?
+			rtw89_read32(rtwdev, R_AX_HAXI_HISR00) & rtwpci->intrs[0] : 0;
+	isrs->isrs[1] = isrs->ind_isrs & B_AX_HS1ISR_IND_INT_EN ?
+			rtw89_read32(rtwdev, R_AX_HISR1) & rtwpci->intrs[1] : 0;
+
+	if (isrs->halt_c2h_isrs)
+		rtw89_write32(rtwdev, R_AX_HISR0, isrs->halt_c2h_isrs);
+	if (isrs->isrs[0])
+		rtw89_write32(rtwdev, R_AX_HAXI_HISR00, isrs->isrs[0]);
+	if (isrs->isrs[1])
+		rtw89_write32(rtwdev, R_AX_HISR1, isrs->isrs[1]);
+}
+EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1);
 
 static void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00)
 {
@@ -631,21 +653,39 @@ static void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00)
 	rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isr00);
 }
 
-static void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev,
-				  struct rtw89_pci *rtwpci)
+void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
 {
 	rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs);
 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, rtwpci->intrs[0]);
 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, rtwpci->intrs[1]);
 }
+EXPORT_SYMBOL(rtw89_pci_enable_intr);
 
-static void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev,
-				   struct rtw89_pci *rtwpci)
+void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
 {
 	rtw89_write32(rtwdev, R_AX_HIMR0, 0);
 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, 0);
 	rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0);
 }
+EXPORT_SYMBOL(rtw89_pci_disable_intr);
+
+void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
+{
+	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, rtwpci->ind_intrs);
+	rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs);
+	rtw89_write32(rtwdev, R_AX_HAXI_HIMR00, rtwpci->intrs[0]);
+	rtw89_write32(rtwdev, R_AX_HIMR1, rtwpci->intrs[1]);
+}
+EXPORT_SYMBOL(rtw89_pci_enable_intr_v1);
+
+void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
+{
+	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00_V1, 0);
+	rtw89_write32(rtwdev, R_AX_HIMR0, 0);
+	rtw89_write32(rtwdev, R_AX_HAXI_HIMR00, 0);
+	rtw89_write32(rtwdev, R_AX_HIMR1, 0);
+}
+EXPORT_SYMBOL(rtw89_pci_disable_intr_v1);
 
 static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev)
 {
@@ -653,9 +693,9 @@ static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev)
 	unsigned long flags;
 
 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
-	rtwpci->under_recovery = true;
-	rtw89_write32(rtwdev, R_AX_PCIE_HIMR00, 0);
-	rtw89_write32(rtwdev, R_AX_PCIE_HIMR10, 0);
+	rtw89_chip_disable_intr(rtwdev, rtwpci);
+	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_START);
+	rtw89_chip_enable_intr(rtwdev, rtwpci);
 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
 }
 
@@ -665,8 +705,9 @@ static void rtw89_pci_ops_recovery_complete(struct rtw89_dev *rtwdev)
 	unsigned long flags;
 
 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
-	rtwpci->under_recovery = false;
-	rtw89_pci_enable_intr(rtwdev, rtwpci);
+	rtw89_chip_disable_intr(rtwdev, rtwpci);
+	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RECOVERY_COMPLETE);
+	rtw89_chip_enable_intr(rtwdev, rtwpci);
 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
 }
 
@@ -678,7 +719,7 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
 	unsigned long flags;
 
 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
-	rtw89_pci_recognize_intrs(rtwdev, rtwpci, &isrs);
+	rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs);
 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
 
 	if (unlikely(isrs.isrs[0] & B_AX_RDU_INT))
@@ -716,7 +757,7 @@ static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev)
 		goto exit;
 	}
 
-	rtw89_pci_disable_intr(rtwdev, rtwpci);
+	rtw89_chip_disable_intr(rtwdev, rtwpci);
 exit:
 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
 
@@ -1313,32 +1354,42 @@ static void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev)
 	spin_unlock_bh(&rtwpci->trx_lock);
 }
 
-static int rtw89_pci_ops_start(struct rtw89_dev *rtwdev)
+static void rtw89_pci_enable_intr_lock(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
 	unsigned long flags;
 
-	rtw89_core_napi_start(rtwdev);
-
 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
 	rtwpci->running = true;
-	rtw89_pci_enable_intr(rtwdev, rtwpci);
+	rtw89_chip_enable_intr(rtwdev, rtwpci);
 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
-
-	return 0;
 }
 
-static void rtw89_pci_ops_stop(struct rtw89_dev *rtwdev)
+static void rtw89_pci_disable_intr_lock(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
-	struct pci_dev *pdev = rtwpci->pdev;
 	unsigned long flags;
 
 	spin_lock_irqsave(&rtwpci->irq_lock, flags);
 	rtwpci->running = false;
-	rtw89_pci_disable_intr(rtwdev, rtwpci);
+	rtw89_chip_disable_intr(rtwdev, rtwpci);
 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
+}
+
+static int rtw89_pci_ops_start(struct rtw89_dev *rtwdev)
+{
+	rtw89_core_napi_start(rtwdev);
+	rtw89_pci_enable_intr_lock(rtwdev);
+
+	return 0;
+}
 
+static void rtw89_pci_ops_stop(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+	struct pci_dev *pdev = rtwpci->pdev;
+
+	rtw89_pci_disable_intr_lock(rtwdev);
 	synchronize_irq(pdev->irq);
 	rtw89_core_napi_stop(rtwdev);
 }
@@ -2924,22 +2975,81 @@ static void rtw89_pci_clear_resource(struct rtw89_dev *rtwdev,
 				skb_queue_len(&rtwpci->h2c_queue), true);
 }
 
-static void rtw89_pci_default_intr_mask(struct rtw89_dev *rtwdev)
+void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev)
 {
 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
 
 	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | 0;
+
+	if (rtwpci->under_recovery) {
+		rtwpci->intrs[0] = 0;
+		rtwpci->intrs[1] = 0;
+	} else {
+		rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN |
+				   B_AX_RXDMA_INT_EN |
+				   B_AX_RXP1DMA_INT_EN |
+				   B_AX_RPQDMA_INT_EN |
+				   B_AX_RXDMA_STUCK_INT_EN |
+				   B_AX_RDU_INT_EN |
+				   B_AX_RPQBD_FULL_INT_EN |
+				   B_AX_HS0ISR_IND_INT_EN;
+
+		rtwpci->intrs[1] = B_AX_HC10ISR_IND_INT_EN;
+	}
+}
+EXPORT_SYMBOL(rtw89_pci_config_intr_mask);
+
+static void rtw89_pci_recovery_intr_mask_v1(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+	rtwpci->ind_intrs = B_AX_HS0ISR_IND_INT_EN;
+	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
+	rtwpci->intrs[0] = 0;
+	rtwpci->intrs[1] = 0;
+}
+
+static void rtw89_pci_default_intr_mask_v1(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+	rtwpci->ind_intrs = B_AX_HCI_AXIDMA_INT_EN |
+			    B_AX_HS1ISR_IND_INT_EN |
+			    B_AX_HS0ISR_IND_INT_EN;
+	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
 	rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN |
 			   B_AX_RXDMA_INT_EN |
 			   B_AX_RXP1DMA_INT_EN |
 			   B_AX_RPQDMA_INT_EN |
 			   B_AX_RXDMA_STUCK_INT_EN |
 			   B_AX_RDU_INT_EN |
-			   B_AX_RPQBD_FULL_INT_EN |
-			   B_AX_HS0ISR_IND_INT_EN;
+			   B_AX_RPQBD_FULL_INT_EN;
+	rtwpci->intrs[1] = B_AX_GPIO18_INT_EN;
+}
+
+static void rtw89_pci_low_power_intr_mask_v1(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+	rtwpci->ind_intrs = B_AX_HS1ISR_IND_INT_EN |
+			    B_AX_HS0ISR_IND_INT_EN;
+	rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
+	rtwpci->intrs[0] = 0;
+	rtwpci->intrs[1] = B_AX_GPIO18_INT_EN;
+}
 
-	rtwpci->intrs[1] = B_AX_HC10ISR_IND_INT_EN;
+void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+	if (rtwpci->under_recovery)
+		rtw89_pci_recovery_intr_mask_v1(rtwdev);
+	else if (rtwpci->low_power)
+		rtw89_pci_low_power_intr_mask_v1(rtwdev);
+	else
+		rtw89_pci_default_intr_mask_v1(rtwdev);
 }
+EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1);
 
 static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev,
 				 struct pci_dev *pdev)
@@ -2963,7 +3073,7 @@ static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev,
 		goto err_free_vector;
 	}
 
-	rtw89_pci_default_intr_mask(rtwdev);
+	rtw89_chip_config_intr_mask(rtwdev, RTW89_PCI_INTR_MASK_RESET);
 
 	return 0;
 
@@ -3285,7 +3395,7 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget)
 	if (work_done < budget && napi_complete_done(napi, work_done)) {
 		spin_lock_irqsave(&rtwpci->irq_lock, flags);
 		if (likely(rtwpci->running))
-			rtw89_pci_enable_intr(rtwdev, rtwpci);
+			rtw89_chip_enable_intr(rtwdev, rtwpci);
 		spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
 	}
 
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index a085d1f27a120..aa804b577df27 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -97,6 +97,16 @@
 #define B_AX_HALT_C2H_INT_EN BIT(21)
 #define R_AX_HISR0 0x01A4
 
+#define R_AX_HIMR1 0x01A8
+#define B_AX_GPIO18_INT_EN BIT(2)
+#define B_AX_GPIO17_INT_EN BIT(1)
+#define B_AX_GPIO16_INT_EN BIT(0)
+
+#define R_AX_HISR1 0x01AC
+#define B_AX_GPIO18_INT BIT(2)
+#define B_AX_GPIO17_INT BIT(1)
+#define B_AX_GPIO16_INT BIT(0)
+
 #define R_AX_MDIO_CFG			0x10A0
 #define B_AX_MDIO_PHY_ADDR_MASK		GENMASK(13, 12)
 #define B_AX_MDIO_RFLAG			BIT(9)
@@ -104,6 +114,7 @@
 #define B_AX_MDIO_ADDR_MASK		GENMASK(4, 0)
 
 #define R_AX_PCIE_HIMR00	0x10B0
+#define R_AX_HAXI_HIMR00 0x10B0
 #define B_AX_HC00ISR_IND_INT_EN		BIT(27)
 #define B_AX_HD1ISR_IND_INT_EN		BIT(26)
 #define B_AX_HD0ISR_IND_INT_EN		BIT(25)
@@ -132,6 +143,7 @@
 #define B_AX_RXDMA_INT_EN		BIT(0)
 
 #define R_AX_PCIE_HISR00	0x10B4
+#define R_AX_HAXI_HISR00 0x10B4
 #define B_AX_HC00ISR_IND_INT		BIT(27)
 #define B_AX_HD1ISR_IND_INT		BIT(26)
 #define B_AX_HD0ISR_IND_INT		BIT(25)
@@ -159,6 +171,10 @@
 #define B_AX_RXP1DMA_INT		BIT(1)
 #define B_AX_RXDMA_INT			BIT(0)
 
+#define R_AX_HAXI_HIMR10 0x11E0
+#define B_AX_TXDMA_CH11_INT_EN_V1 BIT(1)
+#define B_AX_TXDMA_CH10_INT_EN_V1 BIT(0)
+
 #define R_AX_PCIE_HIMR10	0x13B0
 #define B_AX_HC10ISR_IND_INT_EN		BIT(28)
 #define B_AX_TXDMA_CH11_INT_EN		BIT(12)
@@ -169,6 +185,22 @@
 #define B_AX_TXDMA_CH11_INT		BIT(12)
 #define B_AX_TXDMA_CH10_INT		BIT(11)
 
+#define R_AX_PCIE_HIMR00_V1 0x30B0
+#define B_AX_HCI_AXIDMA_INT_EN BIT(29)
+#define B_AX_HC00ISR_IND_INT_EN_V1 BIT(28)
+#define B_AX_HD1ISR_IND_INT_EN_V1 BIT(27)
+#define B_AX_HD0ISR_IND_INT_EN_V1 BIT(26)
+#define B_AX_HS1ISR_IND_INT_EN BIT(25)
+#define B_AX_PCIE_DBG_STE_INT_EN BIT(13)
+
+#define R_AX_PCIE_HISR00_V1 0x30B4
+#define B_AX_HCI_AXIDMA_INT BIT(29)
+#define B_AX_HC00ISR_IND_INT_V1 BIT(28)
+#define B_AX_HD1ISR_IND_INT_V1 BIT(27)
+#define B_AX_HD0ISR_IND_INT_V1 BIT(26)
+#define B_AX_HS1ISR_IND_INT BIT(25)
+#define B_AX_PCIE_DBG_STE_INT BIT(13)
+
 /* TX/RX */
 #define R_AX_RXQ_RXBD_IDX	0x1050
 #define R_AX_RPQ_RXBD_IDX	0x1054
@@ -612,6 +644,17 @@ enum mac_ax_io_rcy_tmr {
 	MAC_AX_IO_RCY_ANA_TMR_DEF = 0xFE
 };
 
+enum rtw89_pci_intr_mask_cfg {
+	RTW89_PCI_INTR_MASK_RESET,
+	RTW89_PCI_INTR_MASK_NORMAL,
+	RTW89_PCI_INTR_MASK_LOW_POWER,
+	RTW89_PCI_INTR_MASK_RECOVERY_START,
+	RTW89_PCI_INTR_MASK_RECOVERY_COMPLETE,
+};
+
+struct rtw89_pci_isrs;
+struct rtw89_pci;
+
 struct rtw89_pci_ch_dma_addr {
 	u32 num;
 	u32 idx;
@@ -661,6 +704,12 @@ struct rtw89_pci_info {
 	u32 (*fill_txaddr_info)(struct rtw89_dev *rtwdev,
 				void *txaddr_info_addr, u32 total_len,
 				dma_addr_t dma, u8 *add_info_nr);
+	void (*config_intr_mask)(struct rtw89_dev *rtwdev);
+	void (*enable_intr)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+	void (*disable_intr)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+	void (*recognize_intrs)(struct rtw89_dev *rtwdev,
+				struct rtw89_pci *rtwpci,
+				struct rtw89_pci_isrs *isrs);
 };
 
 struct rtw89_pci_bd_ram {
@@ -807,6 +856,7 @@ struct rtw89_pci_rx_ring {
 };
 
 struct rtw89_pci_isrs {
+	u32 ind_isrs;
 	u32 halt_c2h_isrs;
 	u32 isrs[2];
 };
@@ -819,12 +869,14 @@ struct rtw89_pci {
 	/* protect TRX resources (exclude RXQ) */
 	spinlock_t trx_lock;
 	bool running;
+	bool low_power;
 	bool under_recovery;
 	struct rtw89_pci_tx_ring tx_rings[RTW89_TXCH_NUM];
 	struct rtw89_pci_rx_ring rx_rings[RTW89_RXCH_NUM];
 	struct sk_buff_head h2c_queue;
 	struct sk_buff_head h2c_release_queue;
 
+	u32 ind_intrs;
 	u32 halt_c2h_intrs;
 	u32 intrs[2];
 	void __iomem *mmap;
@@ -931,6 +983,18 @@ u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev,
 u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev,
 				  void *txaddr_info_addr, u32 total_len,
 				  dma_addr_t dma, u8 *add_info_nr);
+void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev);
+void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev);
+void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
+			       struct rtw89_pci *rtwpci,
+			       struct rtw89_pci_isrs *isrs);
+void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev,
+				  struct rtw89_pci *rtwpci,
+				  struct rtw89_pci_isrs *isrs);
 
 static inline
 u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev,
@@ -943,4 +1007,63 @@ u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev,
 				      dma, add_info_nr);
 }
 
+static inline void rtw89_chip_config_intr_mask(struct rtw89_dev *rtwdev,
+					       enum rtw89_pci_intr_mask_cfg cfg)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+	const struct rtw89_pci_info *info = rtwdev->pci_info;
+
+	switch (cfg) {
+	default:
+	case RTW89_PCI_INTR_MASK_RESET:
+		rtwpci->low_power = false;
+		rtwpci->under_recovery = false;
+		break;
+	case RTW89_PCI_INTR_MASK_NORMAL:
+		rtwpci->low_power = false;
+		break;
+	case RTW89_PCI_INTR_MASK_LOW_POWER:
+		rtwpci->low_power = true;
+		break;
+	case RTW89_PCI_INTR_MASK_RECOVERY_START:
+		rtwpci->under_recovery = true;
+		break;
+	case RTW89_PCI_INTR_MASK_RECOVERY_COMPLETE:
+		rtwpci->under_recovery = false;
+		break;
+	}
+
+	rtw89_debug(rtwdev, RTW89_DBG_HCI,
+		    "Configure PCI interrupt mask mode low_power=%d under_recovery=%d\n",
+		    rtwpci->low_power, rtwpci->under_recovery);
+
+	info->config_intr_mask(rtwdev);
+}
+
+static inline
+void rtw89_chip_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
+{
+	const struct rtw89_pci_info *info = rtwdev->pci_info;
+
+	info->enable_intr(rtwdev, rtwpci);
+}
+
+static inline
+void rtw89_chip_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
+{
+	const struct rtw89_pci_info *info = rtwdev->pci_info;
+
+	info->disable_intr(rtwdev, rtwpci);
+}
+
+static inline
+void rtw89_chip_recognize_intrs(struct rtw89_dev *rtwdev,
+				struct rtw89_pci *rtwpci,
+				struct rtw89_pci_isrs *isrs)
+{
+	const struct rtw89_pci_info *info = rtwdev->pci_info;
+
+	info->recognize_intrs(rtwdev, rtwpci, isrs);
+}
+
 #endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
index 61a1693535d8a..73b5dd05235aa 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
@@ -42,6 +42,10 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
 
 	.ltr_set		= rtw89_pci_ltr_set,
 	.fill_txaddr_info	= rtw89_pci_fill_txaddr_info,
+	.config_intr_mask	= rtw89_pci_config_intr_mask,
+	.enable_intr		= rtw89_pci_enable_intr,
+	.disable_intr		= rtw89_pci_disable_intr,
+	.recognize_intrs	= rtw89_pci_recognize_intrs,
 };
 
 static const struct rtw89_driver_info rtw89_8852ae_info = {
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
index aeafac553f404..4021a56a82bc5 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
@@ -43,6 +43,10 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
 
 	.ltr_set		= rtw89_pci_ltr_set_v1,
 	.fill_txaddr_info	= rtw89_pci_fill_txaddr_info_v1,
+	.config_intr_mask	= rtw89_pci_config_intr_mask_v1,
+	.enable_intr		= rtw89_pci_enable_intr_v1,
+	.disable_intr		= rtw89_pci_disable_intr_v1,
+	.recognize_intrs	= rtw89_pci_recognize_intrs_v1,
 };
 
 static const struct rtw89_driver_info rtw89_8852ce_info = {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 02/14] rtw89: pci: add variant RPWM/CPWM to enter low power mode
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 01/14] rtw89: pci: add variant IMR/ISR and configure functions Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 03/14] rtw89: pci: reclaim TX BD only if it really need Ping-Ke Shih
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

RPWM/CPWM are registers that can set and check low power mode. Since chips
use different address, add a field to access them in common flow.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/mac.c       |  6 +++---
 drivers/net/wireless/realtek/rtw89/pci.c       | 14 ++++++++------
 drivers/net/wireless/realtek/rtw89/pci.h       |  5 +++++
 drivers/net/wireless/realtek/rtw89/rtw8852ae.c |  3 +++
 drivers/net/wireless/realtek/rtw89/rtw8852ce.c |  2 ++
 5 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index 127d5d74c426b..05b94842fe662 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -1027,7 +1027,7 @@ static int rtw89_mac_check_cpwm_state(struct rtw89_dev *rtwdev,
 		return 0;
 
 	rpwm_req_num = rtwdev->mac.rpwm_seq_num;
-	cpwm_rsp_seq = rtw89_read16_mask(rtwdev, R_AX_CPWM,
+	cpwm_rsp_seq = rtw89_read16_mask(rtwdev, rtwdev->hci.cpwm_addr,
 					 PS_CPWM_RSP_SEQ_NUM);
 
 	if (rpwm_req_num != cpwm_rsp_seq)
@@ -1036,11 +1036,11 @@ static int rtw89_mac_check_cpwm_state(struct rtw89_dev *rtwdev,
 	rtwdev->mac.cpwm_seq_num = (rtwdev->mac.cpwm_seq_num + 1) &
 				    CPWM_SEQ_NUM_MAX;
 
-	cpwm_seq = rtw89_read16_mask(rtwdev, R_AX_CPWM, PS_CPWM_SEQ_NUM);
+	cpwm_seq = rtw89_read16_mask(rtwdev, rtwdev->hci.cpwm_addr, PS_CPWM_SEQ_NUM);
 	if (cpwm_seq != rtwdev->mac.cpwm_seq_num)
 		return -EPERM;
 
-	cpwm_status = rtw89_read16_mask(rtwdev, R_AX_CPWM, PS_CPWM_STATE);
+	cpwm_status = rtw89_read16_mask(rtwdev, rtwdev->hci.cpwm_addr, PS_CPWM_STATE);
 	if (cpwm_status != req_pwr_state)
 		return -EPERM;
 
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 0d9cd8033c778..338a032490e16 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -3486,6 +3486,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	struct ieee80211_hw *hw;
 	struct rtw89_dev *rtwdev;
 	const struct rtw89_driver_info *info;
+	const struct rtw89_pci_info *pci_info;
 	int driver_data_size;
 	int ret;
 
@@ -3496,20 +3497,21 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		return -ENOMEM;
 	}
 
+	info = (const struct rtw89_driver_info *)id->driver_data;
+	pci_info = info->bus.pci;
+
 	rtwdev = hw->priv;
 	rtwdev->hw = hw;
 	rtwdev->dev = &pdev->dev;
+	rtwdev->chip = info->chip;
+	rtwdev->pci_info = info->bus.pci;
 	rtwdev->hci.ops = &rtw89_pci_ops;
 	rtwdev->hci.type = RTW89_HCI_TYPE_PCIE;
-	rtwdev->hci.rpwm_addr = R_AX_PCIE_HRPWM;
-	rtwdev->hci.cpwm_addr = R_AX_CPWM;
+	rtwdev->hci.rpwm_addr = pci_info->rpwm_addr;
+	rtwdev->hci.cpwm_addr = pci_info->cpwm_addr;
 
 	SET_IEEE80211_DEV(rtwdev->hw, &pdev->dev);
 
-	info = (const struct rtw89_driver_info *)id->driver_data;
-	rtwdev->chip = info->chip;
-	rtwdev->pci_info = info->bus.pci;
-
 	ret = rtw89_core_init(rtwdev);
 	if (ret) {
 		rtw89_err(rtwdev, "failed to initialise core\n");
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index aa804b577df27..c203c8cbf1632 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -481,6 +481,9 @@
 #define R_AX_PCIE_RX_PREF_ADV		0x13F4
 #define B_AX_RXDMA_PREF_ADV_EN		BIT(0)
 
+#define R_AX_PCIE_HRPWM_V1		0x30C0
+#define R_AX_PCIE_CRPWM			0x30C4
+
 #define RTW89_PCI_TXBD_NUM_MAX		256
 #define RTW89_PCI_RXBD_NUM_MAX		256
 #define RTW89_PCI_TXWD_NUM_MAX		512
@@ -698,6 +701,8 @@ struct rtw89_pci_info {
 	u32 dma_busy2_reg;
 	u32 dma_busy3_reg;
 
+	u32 rpwm_addr;
+	u32 cpwm_addr;
 	const struct rtw89_pci_ch_dma_addr_set *dma_addr_set;
 
 	int (*ltr_set)(struct rtw89_dev *rtwdev, bool en);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
index 73b5dd05235aa..c6937e5943ea7 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
@@ -6,6 +6,7 @@
 #include <linux/pci.h>
 
 #include "pci.h"
+#include "reg.h"
 #include "rtw8852a.h"
 
 static const struct rtw89_pci_info rtw8852a_pci_info = {
@@ -38,6 +39,8 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
 	.dma_busy2_reg		= R_AX_PCIE_DMA_BUSY2,
 	.dma_busy3_reg		= R_AX_PCIE_DMA_BUSY1,
 
+	.rpwm_addr		= R_AX_PCIE_HRPWM,
+	.cpwm_addr		= R_AX_CPWM,
 	.dma_addr_set		= &rtw89_pci_ch_dma_addr_set,
 
 	.ltr_set		= rtw89_pci_ltr_set,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
index 4021a56a82bc5..4d71cc87f7ba8 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
@@ -39,6 +39,8 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
 	.dma_busy2_reg		= R_AX_HAXI_DMA_BUSY2,
 	.dma_busy3_reg		= R_AX_HAXI_DMA_BUSY3,
 
+	.rpwm_addr		= R_AX_PCIE_HRPWM_V1,
+	.cpwm_addr		= R_AX_PCIE_CRPWM,
 	.dma_addr_set		= &rtw89_pci_ch_dma_addr_set_v1,
 
 	.ltr_set		= rtw89_pci_ltr_set_v1,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 03/14] rtw89: pci: reclaim TX BD only if it really need
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 01/14] rtw89: pci: add variant IMR/ISR and configure functions Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 02/14] rtw89: pci: add variant RPWM/CPWM to enter low power mode Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode Ping-Ke Shih
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

To reclaim TX BD, we need to read hardware reading index to determine if
any DMA is complete. Since this IO spends time, do this thing only if we
really need it when TX BD has no free buffer corresponding to target skb.

The experimental result shows that reading counter decreases from 26,000
to 130 per second.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/pci.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 338a032490e16..c1bb44bcd48e1 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -412,9 +412,12 @@ static void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev,
 	u8 txch = tx_ring->txch;
 
 	if (!list_empty(&txwd->list)) {
-		rtw89_warn(rtwdev, "queue %d txwd %d is not idle\n",
-			   txch, seq);
-		return;
+		rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
+		if (!list_empty(&txwd->list)) {
+			rtw89_warn(rtwdev, "queue %d txwd %d is not idle\n",
+				   txch, seq);
+			return;
+		}
 	}
 
 	/* currently, support for only one frame */
@@ -458,7 +461,6 @@ static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev,
 	}
 
 	tx_ring = &rtwpci->tx_rings[txch];
-	rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
 	wd_ring = &tx_ring->wd_ring;
 	txwd = &wd_ring->pages[seq];
 
@@ -915,6 +917,10 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
 		if (!cnt)
 			goto out_unlock;
 		rtw89_pci_release_tx(rtwdev, rx_ring, cnt);
+
+		bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
+		if (bd_cnt == 0)
+			rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
 	}
 
 	bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (2 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 03/14] rtw89: pci: reclaim TX BD only if it really need Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-23 12:32   ` Kalle Valo
  2022-04-21 12:08 ` [PATCH 05/14] rtw89: ser: re-enable interrupt in threadfn if under_recovery Ping-Ke Shih
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

In lower power mode, there are very low amount of RX, and it must process
in a separated function instead of schedule_napi(), because the existing
napi_poll does many things to optimize performance, but not all registers
can access in low power mode. The simple way is to use threadfn to process
the simple thing.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.c |  3 +++
 drivers/net/wireless/realtek/rtw89/pci.c  | 23 +++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 6e8a65b021ce4..796b205854ac6 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -1420,7 +1420,10 @@ static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev,
 {
 	rtw89_core_hw_to_sband_rate(rx_status);
 	rtw89_core_rx_stats(rtwdev, phy_ppdu, desc_info, skb_ppdu);
+	/* In low power mode, it does RX in thread context. */
+	local_bh_disable();
 	ieee80211_rx_napi(rtwdev->hw, NULL, skb_ppdu, &rtwdev->napi);
+	local_bh_enable();
 	rtwdev->napi_budget_countdown--;
 }
 
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index c1bb44bcd48e1..e8bcecbe77e14 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -713,6 +713,18 @@ static void rtw89_pci_ops_recovery_complete(struct rtw89_dev *rtwdev)
 	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
 }
 
+static void rtw89_pci_low_power_interrupt_handler(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+	int budget = NAPI_POLL_WEIGHT;
+
+	/* To prevent RXQ get stuck due to run out of budget. */
+	rtwdev->napi_budget_countdown = budget;
+
+	rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, budget);
+	rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, budget);
+}
+
 static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
 {
 	struct rtw89_dev *rtwdev = dev;
@@ -733,6 +745,11 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
 	if (unlikely(rtwpci->under_recovery))
 		return IRQ_HANDLED;
 
+	if (unlikely(rtwpci->low_power)) {
+		rtw89_pci_low_power_interrupt_handler(rtwdev);
+		goto enable_intr;
+	}
+
 	if (likely(rtwpci->running)) {
 		local_bh_disable();
 		napi_schedule(&rtwdev->napi);
@@ -740,6 +757,12 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
 	}
 
 	return IRQ_HANDLED;
+
+enable_intr:
+	spin_lock_irqsave(&rtwpci->irq_lock, flags);
+	rtw89_chip_enable_intr(rtwdev, rtwpci);
+	spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
+	return IRQ_HANDLED;
 }
 
 static irqreturn_t rtw89_pci_interrupt_handler(int irq, void *dev)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 05/14] rtw89: ser: re-enable interrupt in threadfn if under_recovery
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (3 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 06/14] rtw89: ps: access TX/RX rings via another registers in low power mode Ping-Ke Shih
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

Normally, we re-enable interrupt by napi_poll, but for this special
situation, we must turn it on immediately because napi_poll isn't
scheduled.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index e8bcecbe77e14..ad3db5aa890c6 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -743,7 +743,7 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
 		rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev));
 
 	if (unlikely(rtwpci->under_recovery))
-		return IRQ_HANDLED;
+		goto enable_intr;
 
 	if (unlikely(rtwpci->low_power)) {
 		rtw89_pci_low_power_interrupt_handler(rtwdev);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 06/14] rtw89: ps: access TX/RX rings via another registers in low power mode
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (4 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 05/14] rtw89: ser: re-enable interrupt in threadfn if under_recovery Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 07/14] rtw89: pci: allow to process RPP prior to TX BD Ping-Ke Shih
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

In low power mode, we need to pause PCI to configure IMR and PCI ring
index registers accordingly, because the regular registers are power-off
in this mode.

In the transition moment named paused in code, we can't touch ring index,
so don't kick off DMA immediately. Instead, queue them into pending queue,
and kick off after the moment.

There are three low power modes, which are RF off/clock gate/power gate,
but PCI enter low power mode in later two modes only. So, add a mask
to achieve this.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.h     |  14 +++
 drivers/net/wireless/realtek/rtw89/pci.c      | 103 +++++++++++++++++-
 drivers/net/wireless/realtek/rtw89/pci.h      |  16 +++
 drivers/net/wireless/realtek/rtw89/ps.c       |  34 +++++-
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |   1 +
 .../net/wireless/realtek/rtw89/rtw8852ae.c    |   1 +
 drivers/net/wireless/realtek/rtw89/rtw8852c.c |   2 +
 .../net/wireless/realtek/rtw89/rtw8852ce.c    |  10 ++
 8 files changed, 177 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index f34aca70908e0..27a3ceda90b90 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2036,6 +2036,8 @@ struct rtw89_hci_ops {
 	void (*reset)(struct rtw89_dev *rtwdev);
 	int (*start)(struct rtw89_dev *rtwdev);
 	void (*stop)(struct rtw89_dev *rtwdev);
+	void (*pause)(struct rtw89_dev *rtwdev, bool pause);
+	void (*switch_mode)(struct rtw89_dev *rtwdev, bool low_power);
 	void (*recalc_int_mit)(struct rtw89_dev *rtwdev);
 
 	u8 (*read8)(struct rtw89_dev *rtwdev, u32 addr);
@@ -2067,6 +2069,7 @@ struct rtw89_hci_info {
 	enum rtw89_hci_type type;
 	u32 rpwm_addr;
 	u32 cpwm_addr;
+	bool paused;
 };
 
 struct rtw89_chip_ops {
@@ -2428,6 +2431,7 @@ struct rtw89_chip_info {
 	u8 rf_para_dlink_num;
 	const struct rtw89_btc_rf_trx_para *rf_para_dlink;
 	u8 ps_mode_supported;
+	u8 low_power_hci_modes;
 
 	u32 h2c_cctl_func_id;
 	u32 hci_func_en_addr;
@@ -3167,6 +3171,16 @@ static inline int rtw89_hci_deinit(struct rtw89_dev *rtwdev)
 	return rtwdev->hci.ops->deinit(rtwdev);
 }
 
+static inline void rtw89_hci_pause(struct rtw89_dev *rtwdev, bool pause)
+{
+	rtwdev->hci.ops->pause(rtwdev, pause);
+}
+
+static inline void rtw89_hci_switch_mode(struct rtw89_dev *rtwdev, bool low_power)
+{
+	rtwdev->hci.ops->switch_mode(rtwdev, low_power);
+}
+
 static inline void rtw89_hci_recalc_int_mit(struct rtw89_dev *rtwdev)
 {
 	rtwdev->hci.ops->recalc_int_mit(rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index ad3db5aa890c6..31c62d116f44f 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -919,6 +919,21 @@ u32 __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(struct rtw89_dev *rtwdev)
 	return cnt;
 }
 
+static
+u32 __rtw89_pci_check_and_reclaim_tx_resource_noio(struct rtw89_dev *rtwdev,
+						   u8 txch)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
+	u32 cnt;
+
+	spin_lock_bh(&rtwpci->trx_lock);
+	cnt = rtw89_pci_get_avail_txbd_num(tx_ring);
+	spin_unlock_bh(&rtwpci->trx_lock);
+
+	return cnt;
+}
+
 static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
 						     u8 txch)
 {
@@ -961,6 +976,9 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
 static u32 rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
 						   u8 txch)
 {
+	if (rtwdev->hci.paused)
+		return __rtw89_pci_check_and_reclaim_tx_resource_noio(rtwdev, txch);
+
 	if (txch == RTW89_TXCH_CH12)
 		return __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(rtwdev);
 
@@ -969,12 +987,17 @@ static u32 rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev,
 
 static void __rtw89_pci_tx_kick_off(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring)
 {
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
 	struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring;
 	u32 host_idx, addr;
 
+	spin_lock_bh(&rtwpci->trx_lock);
+
 	addr = bd_ring->addr.idx;
 	host_idx = bd_ring->wp;
 	rtw89_write16(rtwdev, addr, host_idx);
+
+	spin_unlock_bh(&rtwpci->trx_lock);
 }
 
 static void rtw89_pci_tx_bd_ring_update(struct rtw89_dev *rtwdev, struct rtw89_pci_tx_ring *tx_ring,
@@ -995,9 +1018,27 @@ static void rtw89_pci_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
 	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
 	struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch];
 
-	spin_lock_bh(&rtwpci->trx_lock);
+	if (rtwdev->hci.paused) {
+		set_bit(txch, rtwpci->kick_map);
+		return;
+	}
+
 	__rtw89_pci_tx_kick_off(rtwdev, tx_ring);
-	spin_unlock_bh(&rtwpci->trx_lock);
+}
+
+static void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+	struct rtw89_pci_tx_ring *tx_ring;
+	int txch;
+
+	for (txch = 0; txch < RTW89_TXCH_NUM; txch++) {
+		if (!test_and_clear_bit(txch, rtwpci->kick_map))
+			continue;
+
+		tx_ring = &rtwpci->tx_rings[txch];
+		__rtw89_pci_tx_kick_off(rtwdev, tx_ring);
+	}
 }
 
 static void __pci_flush_txch(struct rtw89_dev *rtwdev, u8 txch, bool drop)
@@ -1423,6 +1464,62 @@ static void rtw89_pci_ops_stop(struct rtw89_dev *rtwdev)
 	rtw89_core_napi_stop(rtwdev);
 }
 
+static void rtw89_pci_ops_pause(struct rtw89_dev *rtwdev, bool pause)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+	struct pci_dev *pdev = rtwpci->pdev;
+
+	if (pause) {
+		rtw89_pci_disable_intr_lock(rtwdev);
+		synchronize_irq(pdev->irq);
+		if (test_bit(RTW89_FLAG_NAPI_RUNNING, rtwdev->flags))
+			napi_synchronize(&rtwdev->napi);
+	} else {
+		rtw89_pci_enable_intr_lock(rtwdev);
+		rtw89_pci_tx_kick_off_pending(rtwdev);
+	}
+}
+
+static
+void rtw89_pci_switch_bd_idx_addr(struct rtw89_dev *rtwdev, bool low_power)
+{
+	struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+	const struct rtw89_pci_info *info = rtwdev->pci_info;
+	const struct rtw89_pci_bd_idx_addr *bd_idx_addr = info->bd_idx_addr_low_power;
+	const struct rtw89_pci_ch_dma_addr_set *dma_addr_set = info->dma_addr_set;
+	struct rtw89_pci_tx_ring *tx_ring;
+	struct rtw89_pci_rx_ring *rx_ring;
+	int i;
+
+	if (WARN(!bd_idx_addr, "only HCI with low power mode needs this\n"))
+		return;
+
+	for (i = 0; i < RTW89_TXCH_NUM; i++) {
+		tx_ring = &rtwpci->tx_rings[i];
+		tx_ring->bd_ring.addr.idx = low_power ?
+					    bd_idx_addr->tx_bd_addrs[i] :
+					    dma_addr_set->tx[i].idx;
+	}
+
+	for (i = 0; i < RTW89_RXCH_NUM; i++) {
+		rx_ring = &rtwpci->rx_rings[i];
+		rx_ring->bd_ring.addr.idx = low_power ?
+					    bd_idx_addr->rx_bd_addrs[i] :
+					    dma_addr_set->rx[i].idx;
+	}
+}
+
+static void rtw89_pci_ops_switch_mode(struct rtw89_dev *rtwdev, bool low_power)
+{
+	enum rtw89_pci_intr_mask_cfg cfg;
+
+	WARN(!rtwdev->hci.paused, "HCI isn't paused\n");
+
+	cfg = low_power ? RTW89_PCI_INTR_MASK_LOW_POWER : RTW89_PCI_INTR_MASK_NORMAL;
+	rtw89_chip_config_intr_mask(rtwdev, cfg);
+	rtw89_pci_switch_bd_idx_addr(rtwdev, low_power);
+}
+
 static void rtw89_pci_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 data);
 
 static u32 rtw89_pci_ops_read32_cmac(struct rtw89_dev *rtwdev, u32 addr)
@@ -3488,6 +3585,8 @@ static const struct rtw89_hci_ops rtw89_pci_ops = {
 	.reset		= rtw89_pci_ops_reset,
 	.start		= rtw89_pci_ops_start,
 	.stop		= rtw89_pci_ops_stop,
+	.pause		= rtw89_pci_ops_pause,
+	.switch_mode	= rtw89_pci_ops_switch_mode,
 	.recalc_int_mit = rtw89_pci_recalc_int_mit,
 
 	.read8		= rtw89_pci_ops_read8,
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index c203c8cbf1632..bb585ed191908 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -202,6 +202,15 @@
 #define B_AX_PCIE_DBG_STE_INT BIT(13)
 
 /* TX/RX */
+#define R_AX_DRV_FW_HSK_0	0x01B0
+#define R_AX_DRV_FW_HSK_1	0x01B4
+#define R_AX_DRV_FW_HSK_2	0x01B8
+#define R_AX_DRV_FW_HSK_3	0x01BC
+#define R_AX_DRV_FW_HSK_4	0x01C0
+#define R_AX_DRV_FW_HSK_5	0x01C4
+#define R_AX_DRV_FW_HSK_6	0x01C8
+#define R_AX_DRV_FW_HSK_7	0x01CC
+
 #define R_AX_RXQ_RXBD_IDX	0x1050
 #define R_AX_RPQ_RXBD_IDX	0x1054
 #define R_AX_ACH0_TXBD_IDX	0x1058
@@ -658,6 +667,11 @@ enum rtw89_pci_intr_mask_cfg {
 struct rtw89_pci_isrs;
 struct rtw89_pci;
 
+struct rtw89_pci_bd_idx_addr {
+	u32 tx_bd_addrs[RTW89_TXCH_NUM];
+	u32 rx_bd_addrs[RTW89_RXCH_NUM];
+};
+
 struct rtw89_pci_ch_dma_addr {
 	u32 num;
 	u32 idx;
@@ -703,6 +717,7 @@ struct rtw89_pci_info {
 
 	u32 rpwm_addr;
 	u32 cpwm_addr;
+	const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power;
 	const struct rtw89_pci_ch_dma_addr_set *dma_addr_set;
 
 	int (*ltr_set)(struct rtw89_dev *rtwdev, bool en);
@@ -880,6 +895,7 @@ struct rtw89_pci {
 	struct rtw89_pci_rx_ring rx_rings[RTW89_RXCH_NUM];
 	struct sk_buff_head h2c_queue;
 	struct sk_buff_head h2c_release_queue;
+	DECLARE_BITMAP(kick_map, RTW89_TXCH_NUM);
 
 	u32 ind_intrs;
 	u32 halt_c2h_intrs;
diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c
index 7eaa01e41ef24..a90b337205885 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.c
+++ b/drivers/net/wireless/realtek/rtw89/ps.c
@@ -29,6 +29,36 @@ static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid)
 	return 0;
 }
 
+static void rtw89_ps_power_mode_change_with_hci(struct rtw89_dev *rtwdev,
+						bool enter)
+{
+	ieee80211_stop_queues(rtwdev->hw);
+	rtwdev->hci.paused = true;
+	flush_work(&rtwdev->txq_work);
+	ieee80211_wake_queues(rtwdev->hw);
+
+	rtw89_hci_pause(rtwdev, true);
+	rtw89_mac_power_mode_change(rtwdev, enter);
+	rtw89_hci_switch_mode(rtwdev, enter);
+	rtw89_hci_pause(rtwdev, false);
+
+	rtwdev->hci.paused = false;
+
+	if (!enter) {
+		local_bh_disable();
+		napi_schedule(&rtwdev->napi);
+		local_bh_enable();
+	}
+}
+
+static void rtw89_ps_power_mode_change(struct rtw89_dev *rtwdev, bool enter)
+{
+	if (rtwdev->chip->low_power_hci_modes & BIT(rtwdev->ps_mode))
+		rtw89_ps_power_mode_change_with_hci(rtwdev, enter);
+	else
+		rtw89_mac_power_mode_change(rtwdev, enter);
+}
+
 static void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev)
 {
 	if (!rtwdev->ps_mode)
@@ -37,7 +67,7 @@ static void __rtw89_enter_ps_mode(struct rtw89_dev *rtwdev)
 	if (test_and_set_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
 		return;
 
-	rtw89_mac_power_mode_change(rtwdev, true);
+	rtw89_ps_power_mode_change(rtwdev, true);
 }
 
 void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
@@ -46,7 +76,7 @@ void __rtw89_leave_ps_mode(struct rtw89_dev *rtwdev)
 		return;
 
 	if (test_and_clear_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags))
-		rtw89_mac_power_mode_change(rtwdev, false);
+		rtw89_ps_power_mode_change(rtwdev, false);
 }
 
 static void __rtw89_enter_lps(struct rtw89_dev *rtwdev, u8 mac_id)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index cb93287d47222..5af618709dedd 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -2150,6 +2150,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
 	.ps_mode_supported	= BIT(RTW89_PS_MODE_RFOFF) |
 				  BIT(RTW89_PS_MODE_CLK_GATED) |
 				  BIT(RTW89_PS_MODE_PWR_GATED),
+	.low_power_hci_modes	= 0,
 	.h2c_cctl_func_id	= H2C_FUNC_MAC_CCTLINFO_UD,
 	.hci_func_en_addr	= R_AX_HCI_FUNC_EN,
 	.h2c_desc_size		= sizeof(struct rtw89_txwd_body),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
index c6937e5943ea7..190c4aefb02e3 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
@@ -41,6 +41,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
 
 	.rpwm_addr		= R_AX_PCIE_HRPWM,
 	.cpwm_addr		= R_AX_CPWM,
+	.bd_idx_addr_low_power	= NULL,
 	.dma_addr_set		= &rtw89_pci_ch_dma_addr_set,
 
 	.ltr_set		= rtw89_pci_ltr_set,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 510614630bfbb..1302d4324473e 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2006,6 +2006,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
 	.dav_log_efuse_size	= 16,
 	.phycap_addr		= 0x590,
 	.phycap_size		= 0x60,
+	.low_power_hci_modes	= BIT(RTW89_PS_MODE_CLK_GATED) |
+				  BIT(RTW89_PS_MODE_PWR_GATED),
 	.h2c_cctl_func_id	= H2C_FUNC_MAC_CCTLINFO_UD_V1,
 	.hci_func_en_addr	= R_AX_HCI_FUNC_EN_V1,
 	.h2c_desc_size		= sizeof(struct rtw89_rxdesc_short),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
index 4d71cc87f7ba8..fc03944940130 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
@@ -9,6 +9,15 @@
 #include "reg.h"
 #include "rtw8852c.h"
 
+static const struct rtw89_pci_bd_idx_addr rtw8852c_bd_idx_addr_low_power = {
+	.tx_bd_addrs = {R_AX_DRV_FW_HSK_0, R_AX_DRV_FW_HSK_1, R_AX_DRV_FW_HSK_2,
+			R_AX_DRV_FW_HSK_3, 0, 0,
+			0, 0, R_AX_DRV_FW_HSK_4,
+			0, 0, 0,
+			R_AX_DRV_FW_HSK_5},
+	.rx_bd_addrs = {R_AX_DRV_FW_HSK_6, R_AX_DRV_FW_HSK_7},
+};
+
 static const struct rtw89_pci_info rtw8852c_pci_info = {
 	.txbd_trunc_mode	= MAC_AX_BD_TRUNC,
 	.rxbd_trunc_mode	= MAC_AX_BD_TRUNC,
@@ -41,6 +50,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
 
 	.rpwm_addr		= R_AX_PCIE_HRPWM_V1,
 	.cpwm_addr		= R_AX_PCIE_CRPWM,
+	.bd_idx_addr_low_power	= &rtw8852c_bd_idx_addr_low_power,
 	.dma_addr_set		= &rtw89_pci_ch_dma_addr_set_v1,
 
 	.ltr_set		= rtw89_pci_ltr_set_v1,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 07/14] rtw89: pci: allow to process RPP prior to TX BD
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (5 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 06/14] rtw89: ps: access TX/RX rings via another registers in low power mode Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 08/14] rtw89: don't flush hci queues and send h2c if power is off Ping-Ke Shih
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

RPP is to report certain skb(s) can be freed, and TX BD indicates which
TX descriptors can be freed. Normally, TX BD is happened before RPP.
In low power mode, RPP can happen ahead, so change flow to handle this
case.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/pci.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 31c62d116f44f..2bdce7024f25b 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -382,6 +382,10 @@ static void rtw89_pci_reclaim_txbd(struct rtw89_dev *rtwdev, struct rtw89_pci_tx
 		}
 
 		list_del_init(&txwd->list);
+
+		/* this skb has been freed by RPP */
+		if (skb_queue_len(&txwd->queue) == 0)
+			rtw89_pci_enqueue_txwd(tx_ring, txwd);
 	}
 }
 
@@ -413,18 +417,12 @@ static void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev,
 
 	if (!list_empty(&txwd->list)) {
 		rtw89_pci_reclaim_txbd(rtwdev, tx_ring);
-		if (!list_empty(&txwd->list)) {
+		/* In low power mode, RPP can receive before updating of TX BD.
+		 * In normal mode, it should not happen so give it a warning.
+		 */
+		if (!rtwpci->low_power && !list_empty(&txwd->list))
 			rtw89_warn(rtwdev, "queue %d txwd %d is not idle\n",
 				   txch, seq);
-			return;
-		}
-	}
-
-	/* currently, support for only one frame */
-	if (skb_queue_len(&txwd->queue) != 1) {
-		rtw89_warn(rtwdev, "empty pending queue %d page %d\n",
-			   txch, seq);
-		return;
 	}
 
 	skb_queue_walk_safe(&txwd->queue, skb, tmp) {
@@ -437,7 +435,8 @@ static void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev,
 		rtw89_pci_tx_status(rtwdev, tx_ring, skb, tx_status);
 	}
 
-	rtw89_pci_enqueue_txwd(tx_ring, txwd);
+	if (list_empty(&txwd->list))
+		rtw89_pci_enqueue_txwd(tx_ring, txwd);
 }
 
 static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 08/14] rtw89: don't flush hci queues and send h2c if power is off
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (6 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 07/14] rtw89: pci: allow to process RPP prior to TX BD Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 09/14] rtw89: add RF H2C to notify firmware Ping-Ke Shih
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

When disconnecting, it warns somethings after power is off, and we can't
do HCI IO. So, add this patch to avoid below messages:

  rtw89_8852ce 0000:03:00.0: timed out to flush pci txch: 11
  rtw89_8852ce 0000:03:00.0: failed to pre-release fwcmd

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.c | 7 +++++++
 drivers/net/wireless/realtek/rtw89/core.h | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 796b205854ac6..e3317deafa1d0 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -856,6 +856,13 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev,
 	u32 cnt;
 	int ret;
 
+	if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) {
+		rtw89_debug(rtwdev, RTW89_DBG_FW,
+			    "ignore h2c due to power is off with firmware state=%d\n",
+			    test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags));
+		return 0;
+	}
+
 	tx_req.skb = skb;
 	tx_req.tx_type = RTW89_CORE_TX_TYPE_FWCMD;
 	if (fwdl)
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 27a3ceda90b90..6ca915cb7a29f 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -3199,6 +3199,9 @@ static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
 static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues,
 					  bool drop)
 {
+	if (!test_bit(RTW89_FLAG_POWERON, rtwdev->flags))
+		return;
+
 	if (rtwdev->hci.ops->flush_queues)
 		return rtwdev->hci.ops->flush_queues(rtwdev, queues, drop);
 }
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 09/14] rtw89: add RF H2C to notify firmware
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (7 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 08/14] rtw89: don't flush hci queues and send h2c if power is off Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:08 ` [PATCH 10/14] rtw89: 8852c: configure default BB TX/RX path Ping-Ke Shih
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

IQK results in hardware has two copies that are used by firmware to switch
these two to support MCC.

This H2C tell firmware the corresponding channel and band of each IQK
results, and currrent one.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.h     |  8 ++++
 drivers/net/wireless/realtek/rtw89/fw.c       | 39 +++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/fw.h       | 12 ++++++
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 14 +++++++
 4 files changed, 73 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 6ca915cb7a29f..9be74d8673cfd 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2634,6 +2634,13 @@ struct rtw89_dack_info {
 
 #define RTW89_IQK_CHS_NR 2
 #define RTW89_IQK_PATH_NR 4
+
+struct rtw89_mcc_info {
+	u8 ch[RTW89_IQK_CHS_NR];
+	u8 band[RTW89_IQK_CHS_NR];
+	u8 table_idx;
+};
+
 struct rtw89_iqk_info {
 	bool lok_cor_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
 	bool lok_fin_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
@@ -3105,6 +3112,7 @@ struct rtw89_dev {
 	struct rtw89_dack_info dack;
 	struct rtw89_iqk_info iqk;
 	struct rtw89_dpk_info dpk;
+	struct rtw89_mcc_info mcc;
 	bool is_tssi_mode[RF_PATH_MAX];
 	bool is_bt_iqk_timeout;
 
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 7bef8b4288f0c..e4be785709d10 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -1785,6 +1785,45 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
 	return -EBUSY;
 }
 
+int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
+	struct rtw89_fw_h2c_rf_get_mccch *mccch;
+	struct sk_buff *skb;
+
+	skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, sizeof(*mccch));
+	if (!skb) {
+		rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n");
+		return -ENOMEM;
+	}
+	skb_put(skb, sizeof(*mccch));
+	mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data;
+
+	mccch->ch_0 = cpu_to_le32(mcc_info->ch[0]);
+	mccch->ch_1 = cpu_to_le32(mcc_info->ch[1]);
+	mccch->band_0 = cpu_to_le32(mcc_info->band[0]);
+	mccch->band_1 = cpu_to_le32(mcc_info->band[1]);
+	mccch->current_channel = cpu_to_le32(rtwdev->hal.current_channel);
+	mccch->current_band_type = cpu_to_le32(rtwdev->hal.current_band_type);
+
+	rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+			      H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY,
+			      H2C_FUNC_OUTSRC_RF_GET_MCCCH, 0, 0,
+			      sizeof(*mccch));
+
+	if (rtw89_h2c_tx(rtwdev, skb, false)) {
+		rtw89_err(rtwdev, "failed to send h2c\n");
+		goto fail;
+	}
+
+	return 0;
+fail:
+	dev_kfree_skb_any(skb);
+
+	return -EBUSY;
+}
+EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc);
+
 int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
 			      u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
 			      bool rack, bool dack)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index aaabfc0dfd713..95a55c4213db3 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2538,6 +2538,17 @@ struct rtw89_fw_h2c_rf_reg_info {
 
 #define H2C_CL_OUTSRC_RF_REG_A		0x8
 #define H2C_CL_OUTSRC_RF_REG_B		0x9
+#define H2C_CL_OUTSRC_RF_FW_NOTIFY	0xa
+#define H2C_FUNC_OUTSRC_RF_GET_MCCCH	0x2
+
+struct rtw89_fw_h2c_rf_get_mccch {
+	__le32 ch_0;
+	__le32 ch_1;
+	__le32 band_0;
+	__le32 band_1;
+	__le32 current_channel;
+	__le32 current_band_type;
+} __packed;
 
 #define RTW89_FW_RSVD_PLE_SIZE 0x800
 
@@ -2602,6 +2613,7 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev,
 int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev,
 			struct rtw89_fw_h2c_rf_reg_info *info,
 			u16 len, u8 page);
+int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev);
 int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev,
 			      u8 h2c_class, u8 h2c_func, u8 *buf, u16 len,
 			      bool rack, bool dack);
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 1302d4324473e..3ee57df0a6396 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -1766,6 +1766,18 @@ static void rtw8852c_set_channel_help(struct rtw89_dev *rtwdev, bool enter,
 	}
 }
 
+static void rtw8852c_rfk_init(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_mcc_info *mcc_info = &rtwdev->mcc;
+
+	memset(mcc_info, 0, sizeof(*mcc_info));
+}
+
+static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev)
+{
+	rtw89_fw_h2c_rf_ntfy_mcc(rtwdev);
+}
+
 static
 void rtw8852c_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
 				     s8 pw_ofst, enum rtw89_mac_idx mac_idx)
@@ -1955,6 +1967,8 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
 	.set_channel_help	= rtw8852c_set_channel_help,
 	.read_efuse		= rtw8852c_read_efuse,
 	.read_phycap		= rtw8852c_read_phycap,
+	.rfk_init		= rtw8852c_rfk_init,
+	.rfk_channel		= rtw8852c_rfk_channel,
 	.power_trim		= rtw8852c_power_trim,
 	.read_rf		= rtw89_phy_read_rf_v1,
 	.write_rf		= rtw89_phy_write_rf_v1,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 10/14] rtw89: 8852c: configure default BB TX/RX path
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (8 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 09/14] rtw89: add RF H2C to notify firmware Ping-Ke Shih
@ 2022-04-21 12:08 ` Ping-Ke Shih
  2022-04-21 12:09 ` [PATCH 11/14] rtw89: 8852c: implement chip_ops related to TX power Ping-Ke Shih
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:08 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

8852c propose new API to configure BB TX/RX path. Without fix patch, it
can't transmit any packet.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/core.h     |   9 +
 drivers/net/wireless/realtek/rtw89/phy.c      |   1 +
 drivers/net/wireless/realtek/rtw89/reg.h      |  76 ++++++-
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |   1 +
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 194 ++++++++++++++++++
 5 files changed, 279 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 9be74d8673cfd..d544cf29e588a 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -2104,6 +2104,7 @@ struct rtw89_chip_ops {
 			   struct rtw89_rx_phy_ppdu *phy_ppdu,
 			   struct ieee80211_rx_status *status);
 	void (*bb_ctrl_btc_preagc)(struct rtw89_dev *rtwdev, bool bt_en);
+	void (*cfg_txrx_path)(struct rtw89_dev *rtwdev);
 	void (*set_txpwr_ul_tb_offset)(struct rtw89_dev *rtwdev,
 				       s8 pw_ofst, enum rtw89_mac_idx mac_idx);
 	int (*pwr_on_func)(struct rtw89_dev *rtwdev);
@@ -3633,6 +3634,14 @@ static inline void rtw89_chip_bb_ctrl_btc_preagc(struct rtw89_dev *rtwdev,
 		chip->ops->bb_ctrl_btc_preagc(rtwdev, bt_en);
 }
 
+static inline void rtw89_chip_cfg_txrx_path(struct rtw89_dev *rtwdev)
+{
+	const struct rtw89_chip_info *chip = rtwdev->chip;
+
+	if (chip->ops->cfg_txrx_path)
+		chip->ops->cfg_txrx_path(rtwdev);
+}
+
 static inline
 void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
 				       struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 7d0593d8fafe9..33494e8451cf3 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3592,6 +3592,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
 	rtw89_load_txpwr_table(rtwdev, chip->byr_table);
 	rtw89_chip_set_txpwr_ctrl(rtwdev);
 	rtw89_chip_power_trim(rtwdev);
+	rtw89_chip_cfg_txrx_path(rtwdev);
 }
 
 void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 0f08b25817976..6dc11e8e2a839 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -2962,6 +2962,45 @@
 #define R_AX_PWR_MACID_LMT_TABLE0 0xD36C
 #define R_AX_PWR_MACID_LMT_TABLE127 0xD568
 
+#define R_AX_PATH_COM0 0xD800
+#define AX_PATH_COM0_DFVAL 0x00000000
+#define AX_PATH_COM0_PATHA 0x08888880
+#define AX_PATH_COM0_PATHB 0x11111100
+#define AX_PATH_COM0_PATHAB 0x19999980
+#define R_AX_PATH_COM1 0xD804
+#define AX_PATH_COM1_DFVAL 0x00000000
+#define AX_PATH_COM1_PATHA 0x11111111
+#define AX_PATH_COM1_PATHB 0x22222222
+#define AX_PATH_COM1_PATHAB 0x33333333
+#define R_AX_PATH_COM2 0xD808
+#define AX_PATH_COM2_DFVAL 0x00000000
+#define AX_PATH_COM2_PATHA 0x01209111
+#define AX_PATH_COM2_PATHB 0x01209222
+#define AX_PATH_COM2_PATHAB 0x01209333
+#define R_AX_PATH_COM3 0xD80C
+#define AX_PATH_COM3_DFVAL 0x49249249
+#define R_AX_PATH_COM4 0xD810
+#define AX_PATH_COM4_DFVAL 0x1C9C9C49
+#define R_AX_PATH_COM5 0xD814
+#define AX_PATH_COM5_DFVAL 0x39393939
+#define R_AX_PATH_COM6 0xD818
+#define AX_PATH_COM6_DFVAL 0x39393939
+#define R_AX_PATH_COM7 0xD81C
+#define AX_PATH_COM7_DFVAL 0x39393939
+#define AX_PATH_COM7_PATHA 0x39393939
+#define AX_PATH_COM7_PATHB 0x39383939
+#define AX_PATH_COM7_PATHAB 0x39393939
+#define R_AX_PATH_COM8 0xD820
+#define AX_PATH_COM8_DFVAL 0x00000000
+#define AX_PATH_COM8_PATHA 0x00003939
+#define AX_PATH_COM8_PATHB 0x00003938
+#define AX_PATH_COM8_PATHAB 0x00003939
+#define R_AX_PATH_COM9 0xD824
+#define AX_PATH_COM9_DFVAL 0x000007C0
+#define R_AX_PATH_COM10 0xD828
+#define AX_PATH_COM10_DFVAL 0xE0000000
+#define R_AX_PATH_COM11 0xD82C
+#define AX_PATH_COM11_DFVAL 0x00000000
 #define R_P80_AT_HIGH_FREQ_BB_WRP 0xD848
 #define B_P80_AT_HIGH_FREQ_BB_WRP BIT(28)
 #define R_AX_TSSI_CTRL_HEAD 0xD908
@@ -3097,6 +3136,9 @@
 #define R_AX_LTE_WDATA 0xDAF4
 #define R_AX_LTE_RDATA 0xDAF8
 
+#define R_AX_MACID_ANT_TABLE 0xDC00
+#define R_AX_MACID_ANT_TABLE_LAST 0xDDFC
+
 #define CMAC1_START_ADDR 0xE000
 #define CMAC1_END_ADDR 0xFFFF
 #define R_AX_CMAC_REG_END 0xFFFF
@@ -3360,9 +3402,10 @@
 #define R_PMAC_RXMOD 0x0994
 #define B_PMAC_RXMOD_MSK GENMASK(7, 4)
 #define R_MAC_SEL 0x09A4
-#define B_MAC_SEL_MOD GENMASK(4, 2)
-#define B_MAC_SEL_DPD_EN BIT(10)
+#define B_MAC_SEL_OFDM_TRI_FILTER BIT(31)
 #define B_MAC_SEL_PWR_EN BIT(16)
+#define B_MAC_SEL_DPD_EN BIT(10)
+#define B_MAC_SEL_MOD GENMASK(4, 2)
 #define R_PMAC_TX_CTRL 0x09C0
 #define B_PMAC_TXEN_DIS BIT(0)
 #define R_PMAC_TX_PRD 0x09C4
@@ -3413,8 +3456,16 @@
 #define B_SNDCCA_A1_EN GENMASK(19, 12)
 #define R_SNDCCA_A2 0x0CA0
 #define B_SNDCCA_A2_VAL GENMASK(19, 12)
+#define R_RXHT_MCS_LIMIT 0x0D18
+#define B_RXHT_MCS_LIMIT GENMASK(9, 8)
+#define R_RXVHT_MCS_LIMIT 0x0D18
+#define B_RXVHT_MCS_LIMIT GENMASK(22, 21)
 #define R_P0_EN_SOUND_WO_NDP 0x0D7C
 #define B_P0_EN_SOUND_WO_NDP BIT(1)
+#define R_RXHE 0x0D80
+#define B_RXHETB_MAX_NSS GENMASK(25, 23)
+#define B_RXHE_MAX_NSS GENMASK(16, 14)
+#define B_RXHE_USER_MAX GENMASK(13, 6)
 #define R_SPOOF_ASYNC_RST 0x0D84
 #define B_SPOOF_ASYNC_RST BIT(15)
 #define R_NDP_BRK0 0xDA0
@@ -3634,6 +3685,8 @@
 #define B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5)
 #define R_PATH0_S20_FOLLOW_BY_PAGCUGC 0x46A4
 #define B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5)
+#define R_PATH0_G_LNA6_OP1DB_V1 0x4688
+#define B_PATH0_G_LNA6_OP1DB_V1 GENMASK(31, 24)
 #define R_PATH0_G_TIA0_LNA6_OP1DB_V1 0x4694
 #define B_PATH0_G_TIA0_LNA6_OP1DB_V1 GENMASK(7, 0)
 #define R_PATH0_G_TIA1_LNA6_OP1DB_V1 0x4694
@@ -3650,6 +3703,9 @@
 #define R_P0_NBIIDX 0x469C
 #define B_P0_NBIIDX_VAL GENMASK(11, 0)
 #define B_P0_NBIIDX_NOTCH_EN BIT(12)
+#define R_P0_BACKOFF_IBADC_V1 0x469C
+#define B_P0_BACKOFF_IBADC_V1 GENMASK(31, 26)
+#define B_P0_NBIIDX_NOTCH_EN_V1 BIT(12)
 #define R_P1_MODE 0x4718
 #define B_P1_MODE_SEL GENMASK(31, 30)
 #define R_PATH1_LNA_INIT 0x473C
@@ -3668,6 +3724,8 @@
 #define B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5)
 #define R_PATH1_G_TIA0_LNA6_OP1DB_V1 0x4778
 #define B_PATH1_G_TIA0_LNA6_OP1DB_V1 GENMASK(7, 0)
+#define R_PATH1_G_TIA1_LNA6_OP1DB_V1 0x4778
+#define B_PATH1_G_TIA1_LNA6_OP1DB_V1 GENMASK(15, 8)
 #define R_PATH1_BAND_SEL_V1 0x4AA4
 #define B_PATH1_BAND_SEL_MSK_V1 BIT(17)
 #define R_PATH1_BT_SHARE_V1 0x4AA4
@@ -3693,15 +3751,29 @@
 #define B_CHBW_MOD_SBW GENMASK(13, 12)
 #define B_CHBW_MOD_PRICH GENMASK(11, 8)
 #define B_ANT_RX_SEG0 GENMASK(3, 0)
+#define R_P1_BACKOFF_IBADC_V1 0x49F0
+#define B_P1_BACKOFF_IBADC_V1 GENMASK(31, 26)
 #define R_BK_FC0_INV_V1 0x4A1C
 #define B_BK_FC0_INV_MSK_V1 GENMASK(18, 0)
 #define R_CCK_FC0_INV_V1 0x4A20
 #define B_CCK_FC0_INV_MSK_V1 GENMASK(18, 0)
+#define R_PATH0_RXBB_V1 0x4AD4
+#define B_PATH0_RXBB_MSK_V1 GENMASK(31, 0)
+#define R_PATH1_RXBB_V1 0x4AE0
+#define B_PATH1_RXBB_MSK_V1 GENMASK(31, 0)
+#define R_PATH0_BT_BACKOFF_V1 0x4AE4
+#define B_PATH0_BT_BACKOFF_V1 GENMASK(23, 0)
+#define R_PATH1_BT_BACKOFF_V1 0x4AEC
+#define B_PATH1_BT_BACKOFF_V1 GENMASK(23, 0)
+#define R_PATH0_FRC_FIR_TYPE_V1 0x4C00
+#define B_PATH0_FRC_FIR_TYPE_MSK_V1 GENMASK(1, 0)
 #define R_PATH0_5MDET 0x4C4C
 #define B_PATH0_5MDET_EN BIT(12)
 #define B_PATH0_5MDET_SB2 BIT(8)
 #define B_PATH0_5MDET_SB0 BIT(6)
 #define B_PATH0_5MDET_TH GENMASK(5, 0)
+#define R_PATH1_FRC_FIR_TYPE_V1 0x4CC4
+#define B_PATH1_FRC_FIR_TYPE_MSK_V1 GENMASK(1, 0)
 #define R_PATH1_5MDET 0x4D10
 #define B_PATH1_5MDET_EN BIT(12)
 #define B_PATH1_5MDET_SB2 BIT(8)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 5af618709dedd..81bd0c4fe21bc 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -2066,6 +2066,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = {
 	.ctrl_btg		= rtw8852a_ctrl_btg,
 	.query_ppdu		= rtw8852a_query_ppdu,
 	.bb_ctrl_btc_preagc	= rtw8852a_bb_ctrl_btc_preagc,
+	.cfg_txrx_path		= NULL,
 	.set_txpwr_ul_tb_offset	= rtw8852a_set_txpwr_ul_tb_offset,
 	.pwr_on_func		= NULL,
 	.pwr_off_func		= NULL,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 3ee57df0a6396..290c453d8c23a 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -1813,6 +1813,199 @@ void rtw8852c_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
 	}
 }
 
+static void rtw8852c_bb_cfg_rx_path(struct rtw89_dev *rtwdev, u8 rx_path)
+{
+	struct rtw89_hal *hal = &rtwdev->hal;
+	u32 rst_mask0 = B_P0_TXPW_RSTB_MANON | B_P0_TXPW_RSTB_TSSI;
+	u32 rst_mask1 = B_P1_TXPW_RSTB_MANON | B_P1_TXPW_RSTB_TSSI;
+
+	if (rtwdev->dbcc_en) {
+		rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD, B_ANT_RX_SEG0, 1);
+		rtw89_phy_write32_idx(rtwdev, R_CHBW_MOD, B_ANT_RX_SEG0, 2,
+				      RTW89_PHY_1);
+
+		rtw89_phy_write32_mask(rtwdev, R_FC0_BW, B_ANT_RX_1RCCA_SEG0,
+				       1);
+		rtw89_phy_write32_mask(rtwdev, R_FC0_BW, B_ANT_RX_1RCCA_SEG1,
+				       1);
+		rtw89_phy_write32_idx(rtwdev, R_FC0_BW, B_ANT_RX_1RCCA_SEG0, 2,
+				      RTW89_PHY_1);
+		rtw89_phy_write32_idx(rtwdev, R_FC0_BW, B_ANT_RX_1RCCA_SEG1, 2,
+				      RTW89_PHY_1);
+
+		rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT,
+				       B_RXHT_MCS_LIMIT, 0);
+		rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT,
+				       B_RXVHT_MCS_LIMIT, 0);
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 8);
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0);
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0);
+
+		rtw89_phy_write32_idx(rtwdev, R_RXHT_MCS_LIMIT,
+				      B_RXHT_MCS_LIMIT, 0, RTW89_PHY_1);
+		rtw89_phy_write32_idx(rtwdev, R_RXVHT_MCS_LIMIT,
+				      B_RXVHT_MCS_LIMIT, 0, RTW89_PHY_1);
+		rtw89_phy_write32_idx(rtwdev, R_RXHE, B_RXHE_USER_MAX, 1,
+				      RTW89_PHY_1);
+		rtw89_phy_write32_idx(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0,
+				      RTW89_PHY_1);
+		rtw89_phy_write32_idx(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0,
+				      RTW89_PHY_1);
+		rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 1);
+		rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB, rst_mask0, 3);
+		rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 1);
+		rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB, rst_mask1, 3);
+	} else {
+		if (rx_path == RF_PATH_A) {
+			rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD,
+					       B_ANT_RX_SEG0, 1);
+			rtw89_phy_write32_mask(rtwdev, R_FC0_BW,
+					       B_ANT_RX_1RCCA_SEG0, 1);
+			rtw89_phy_write32_mask(rtwdev, R_FC0_BW,
+					       B_ANT_RX_1RCCA_SEG1, 1);
+			rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT,
+					       B_RXHT_MCS_LIMIT, 0);
+			rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT,
+					       B_RXVHT_MCS_LIMIT, 0);
+			rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS,
+					       0);
+			rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS,
+					       0);
+			rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB,
+					       rst_mask0, 1);
+			rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB,
+					       rst_mask0, 3);
+		} else if (rx_path == RF_PATH_B) {
+			rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD,
+					       B_ANT_RX_SEG0, 2);
+			rtw89_phy_write32_mask(rtwdev, R_FC0_BW,
+					       B_ANT_RX_1RCCA_SEG0, 2);
+			rtw89_phy_write32_mask(rtwdev, R_FC0_BW,
+					       B_ANT_RX_1RCCA_SEG1, 2);
+			rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT,
+					       B_RXHT_MCS_LIMIT, 0);
+			rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT,
+					       B_RXVHT_MCS_LIMIT, 0);
+			rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS,
+					       0);
+			rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS,
+					       0);
+			rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB,
+					       rst_mask1, 1);
+			rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB,
+					       rst_mask1, 3);
+		} else {
+			rtw89_phy_write32_mask(rtwdev, R_CHBW_MOD,
+					       B_ANT_RX_SEG0, 3);
+			rtw89_phy_write32_mask(rtwdev, R_FC0_BW,
+					       B_ANT_RX_1RCCA_SEG0, 3);
+			rtw89_phy_write32_mask(rtwdev, R_FC0_BW,
+					       B_ANT_RX_1RCCA_SEG1, 3);
+			rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT,
+					       B_RXHT_MCS_LIMIT, 1);
+			rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT,
+					       B_RXVHT_MCS_LIMIT, 1);
+			rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS,
+					       1);
+			rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS,
+					       1);
+			rtw8852c_ctrl_btg(rtwdev, hal->current_band_type == RTW89_BAND_2G);
+			rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB,
+					       rst_mask0, 1);
+			rtw89_phy_write32_mask(rtwdev, R_P0_TXPW_RSTB,
+					       rst_mask0, 3);
+			rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB,
+					       rst_mask1, 1);
+			rtw89_phy_write32_mask(rtwdev, R_P1_TXPW_RSTB,
+					       rst_mask1, 3);
+		}
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_USER_MAX, 8);
+	}
+}
+
+static void rtw8852c_ctrl_tx_path_tmac(struct rtw89_dev *rtwdev, u8 tx_path,
+				       enum rtw89_mac_idx mac_idx)
+{
+	struct rtw89_reg2_def path_com[] = {
+		{R_AX_PATH_COM0, AX_PATH_COM0_DFVAL},
+		{R_AX_PATH_COM1, AX_PATH_COM1_DFVAL},
+		{R_AX_PATH_COM2, AX_PATH_COM2_DFVAL},
+		{R_AX_PATH_COM3, AX_PATH_COM3_DFVAL},
+		{R_AX_PATH_COM4, AX_PATH_COM4_DFVAL},
+		{R_AX_PATH_COM5, AX_PATH_COM5_DFVAL},
+		{R_AX_PATH_COM6, AX_PATH_COM6_DFVAL},
+		{R_AX_PATH_COM7, AX_PATH_COM7_DFVAL},
+		{R_AX_PATH_COM8, AX_PATH_COM8_DFVAL},
+		{R_AX_PATH_COM9, AX_PATH_COM9_DFVAL},
+		{R_AX_PATH_COM10, AX_PATH_COM10_DFVAL},
+		{R_AX_PATH_COM11, AX_PATH_COM11_DFVAL},
+	};
+	u32 addr;
+	u32 reg;
+	u8 cr_size = ARRAY_SIZE(path_com);
+	u8 i = 0;
+
+	rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0, RTW89_PHY_0);
+	rtw89_phy_write32_idx(rtwdev, R_MAC_SEL, B_MAC_SEL_MOD, 0, RTW89_PHY_1);
+
+	for (addr = R_AX_MACID_ANT_TABLE;
+	     addr <= R_AX_MACID_ANT_TABLE_LAST; addr += 4) {
+		reg = rtw89_mac_reg_by_idx(addr, mac_idx);
+		rtw89_write32(rtwdev, reg, 0);
+	}
+
+	if (tx_path == RF_PATH_A) {
+		path_com[0].data = AX_PATH_COM0_PATHA;
+		path_com[1].data = AX_PATH_COM1_PATHA;
+		path_com[2].data = AX_PATH_COM2_PATHA;
+		path_com[7].data = AX_PATH_COM7_PATHA;
+		path_com[8].data = AX_PATH_COM8_PATHA;
+	} else if (tx_path == RF_PATH_B) {
+		path_com[0].data = AX_PATH_COM0_PATHB;
+		path_com[1].data = AX_PATH_COM1_PATHB;
+		path_com[2].data = AX_PATH_COM2_PATHB;
+		path_com[7].data = AX_PATH_COM7_PATHB;
+		path_com[8].data = AX_PATH_COM8_PATHB;
+	} else if (tx_path == RF_PATH_AB) {
+		path_com[0].data = AX_PATH_COM0_PATHAB;
+		path_com[1].data = AX_PATH_COM1_PATHAB;
+		path_com[2].data = AX_PATH_COM2_PATHAB;
+		path_com[7].data = AX_PATH_COM7_PATHAB;
+		path_com[8].data = AX_PATH_COM8_PATHAB;
+	} else {
+		rtw89_warn(rtwdev, "[Invalid Tx Path]Tx Path: %d\n", tx_path);
+		return;
+	}
+
+	for (i = 0; i < cr_size; i++) {
+		rtw89_debug(rtwdev, RTW89_DBG_TSSI, "0x%x = 0x%x\n",
+			    path_com[i].addr, path_com[i].data);
+		reg = rtw89_mac_reg_by_idx(path_com[i].addr, mac_idx);
+		rtw89_write32(rtwdev, reg, path_com[i].data);
+	}
+}
+
+static void rtw8852c_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_hal *hal = &rtwdev->hal;
+
+	rtw8852c_bb_cfg_rx_path(rtwdev, RF_PATH_AB);
+
+	if (hal->rx_nss == 1) {
+		rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 0);
+		rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 0);
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 0);
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 0);
+	} else {
+		rtw89_phy_write32_mask(rtwdev, R_RXHT_MCS_LIMIT, B_RXHT_MCS_LIMIT, 1);
+		rtw89_phy_write32_mask(rtwdev, R_RXVHT_MCS_LIMIT, B_RXVHT_MCS_LIMIT, 1);
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHE_MAX_NSS, 1);
+		rtw89_phy_write32_mask(rtwdev, R_RXHE, B_RXHETB_MAX_NSS, 1);
+	}
+
+	rtw8852c_ctrl_tx_path_tmac(rtwdev, RF_PATH_AB, RTW89_MAC_0);
+}
+
 static void rtw8852c_ctrl_btg(struct rtw89_dev *rtwdev, bool btg)
 {
 	if (btg) {
@@ -1973,6 +2166,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
 	.read_rf		= rtw89_phy_read_rf_v1,
 	.write_rf		= rtw89_phy_write_rf_v1,
 	.set_txpwr_ul_tb_offset	= rtw8852c_set_txpwr_ul_tb_offset,
+	.cfg_txrx_path		= rtw8852c_bb_cfg_txrx_path,
 	.pwr_on_func		= rtw8852c_pwr_on_func,
 	.pwr_off_func		= rtw8852c_pwr_off_func,
 	.fill_txdesc		= rtw89_core_fill_txdesc_v1,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 11/14] rtw89: 8852c: implement chip_ops related to TX power
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (9 preceding siblings ...)
  2022-04-21 12:08 ` [PATCH 10/14] rtw89: 8852c: configure default BB TX/RX path Ping-Ke Shih
@ 2022-04-21 12:09 ` Ping-Ke Shih
  2022-04-21 12:09 ` [PATCH 12/14] rtw89: 8852c: implement chip_ops::get_thermal Ping-Ke Shih
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:09 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

Three chip_ops are implemented in this patch. The ::set_txpwr_ctrl and
::init_txpwr_unit are called when we up interface and then configure TX
power registers to initial values. The ::set_txpwr_ctrl is to configure
'txpwr_ref' to make basic output TX power of OFDM and CCK rate to be the
same. The ::init_txpwr_unit is to initialize TSSI (a method to do TX power
compensation depends on thermal value) control and bandedge.

The ::set_txpwr is called once switching channel. First, it sets TX power
for each rate section (e.g. CCK, OFDM), and then sets TX power offset
between 1SS and 2SS rate. Finally, it sets TX power limit to prevent
power over regulation.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 324 ++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/rtw8852c.h |   1 +
 2 files changed, 325 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 290c453d8c23a..adcc2b597419d 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -1778,6 +1778,32 @@ static void rtw8852c_rfk_channel(struct rtw89_dev *rtwdev)
 	rtw89_fw_h2c_rf_ntfy_mcc(rtwdev);
 }
 
+static u32 rtw8852c_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev,
+				     enum rtw89_phy_idx phy_idx, s16 ref)
+{
+	s8 ofst_int = 0;
+	u8 base_cw_0db = 0x27;
+	u16 tssi_16dbm_cw = 0x12c;
+	s16 pwr_s10_3 = 0;
+	s16 rf_pwr_cw = 0;
+	u16 bb_pwr_cw = 0;
+	u32 pwr_cw = 0;
+	u32 tssi_ofst_cw = 0;
+
+	pwr_s10_3 = (ref << 1) + (s16)(ofst_int) + (s16)(base_cw_0db << 3);
+	bb_pwr_cw = FIELD_GET(GENMASK(2, 0), pwr_s10_3);
+	rf_pwr_cw = FIELD_GET(GENMASK(8, 3), pwr_s10_3);
+	rf_pwr_cw = clamp_t(s16, rf_pwr_cw, 15, 63);
+	pwr_cw = (rf_pwr_cw << 3) | bb_pwr_cw;
+
+	tssi_ofst_cw = (u32)((s16)tssi_16dbm_cw + (ref << 1) - (16 << 3));
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+		    "[TXPWR] tssi_ofst_cw=%d rf_cw=0x%x bb_cw=0x%x\n",
+		    tssi_ofst_cw, rf_pwr_cw, bb_pwr_cw);
+
+	return (tssi_ofst_cw << 18) | (pwr_cw << 9) | (ref & GENMASK(8, 0));
+}
+
 static
 void rtw8852c_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
 				     s8 pw_ofst, enum rtw89_mac_idx mac_idx)
@@ -1813,6 +1839,301 @@ void rtw8852c_set_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev,
 	}
 }
 
+static void rtw8852c_set_txpwr_ref(struct rtw89_dev *rtwdev,
+				   enum rtw89_phy_idx phy_idx)
+{
+	static const u32 addr[RF_PATH_NUM_8852C] = {0x5800, 0x7800};
+	const u32 mask = 0x7FFFFFF;
+	const u8 ofst_ofdm = 0x4;
+	const u8 ofst_cck = 0x8;
+	s16 ref_ofdm = 0;
+	s16 ref_cck = 0;
+	u32 val;
+	u8 i;
+
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n");
+
+	rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_CTRL,
+				     GENMASK(27, 10), 0x0);
+
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb ofdm txpwr ref\n");
+	val = rtw8852c_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_ofdm);
+
+	for (i = 0; i < RF_PATH_NUM_8852C; i++)
+		rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_ofdm, mask, val,
+				      phy_idx);
+
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set bb cck txpwr ref\n");
+	val = rtw8852c_bb_cal_txpwr_ref(rtwdev, phy_idx, ref_cck);
+
+	for (i = 0; i < RF_PATH_NUM_8852C; i++)
+		rtw89_phy_write32_idx(rtwdev, addr[i] + ofst_cck, mask, val,
+				      phy_idx);
+}
+
+static void rtw8852c_set_txpwr_byrate(struct rtw89_dev *rtwdev,
+				      enum rtw89_phy_idx phy_idx)
+{
+	u8 ch = rtwdev->hal.current_channel;
+	static const u8 rs[] = {
+		RTW89_RS_CCK,
+		RTW89_RS_OFDM,
+		RTW89_RS_MCS,
+		RTW89_RS_HEDCM,
+	};
+	s8 tmp;
+	u8 i, j;
+	u32 val, shf, addr = R_AX_PWR_BY_RATE;
+	struct rtw89_rate_desc cur;
+
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+		    "[TXPWR] set txpwr byrate with ch=%d\n", ch);
+
+	for (cur.nss = 0; cur.nss <= RTW89_NSS_2; cur.nss++) {
+		for (i = 0; i < ARRAY_SIZE(rs); i++) {
+			if (cur.nss >= rtw89_rs_nss_max[rs[i]])
+				continue;
+
+			val = 0;
+			cur.rs = rs[i];
+
+			for (j = 0; j < rtw89_rs_idx_max[rs[i]]; j++) {
+				cur.idx = j;
+				shf = (j % 4) * 8;
+				tmp = rtw89_phy_read_txpwr_byrate(rtwdev, &cur);
+				val |= (tmp << shf);
+
+				if ((j + 1) % 4)
+					continue;
+
+				rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val);
+				val = 0;
+				addr += 4;
+			}
+		}
+	}
+}
+
+static void rtw8852c_set_txpwr_offset(struct rtw89_dev *rtwdev,
+				      enum rtw89_phy_idx phy_idx)
+{
+	struct rtw89_rate_desc desc = {
+		.nss = RTW89_NSS_1,
+		.rs = RTW89_RS_OFFSET,
+	};
+	u32 val = 0;
+	s8 v;
+
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr offset\n");
+
+	for (desc.idx = 0; desc.idx < RTW89_RATE_OFFSET_MAX; desc.idx++) {
+		v = rtw89_phy_read_txpwr_byrate(rtwdev, &desc);
+		val |= ((v & 0xf) << (4 * desc.idx));
+	}
+
+	rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_AX_PWR_RATE_OFST_CTRL,
+				     GENMASK(19, 0), val);
+}
+
+static void rtw8852c_bb_set_tx_shape_dfir(struct rtw89_dev *rtwdev,
+					  u8 tx_shape_idx,
+					  enum rtw89_phy_idx phy_idx)
+{
+#define __DFIR_CFG_MASK 0xffffff
+#define __DFIR_CFG_NR 8
+#define __DECL_DFIR_VAR(_prefix, _name, _val...) \
+	static const u32 _prefix ## _ ## _name[] = {_val}; \
+	static_assert(ARRAY_SIZE(_prefix ## _ ## _name) == __DFIR_CFG_NR)
+#define __DECL_DFIR_PARAM(_name, _val...) __DECL_DFIR_VAR(param, _name, _val)
+#define __DECL_DFIR_ADDR(_name, _val...) __DECL_DFIR_VAR(addr, _name, _val)
+
+	__DECL_DFIR_PARAM(flat,
+			  0x003D23FF, 0x0029B354, 0x000FC1C8, 0x00FDB053,
+			  0x00F86F9A, 0x00FAEF92, 0x00FE5FCC, 0x00FFDFF5);
+	__DECL_DFIR_PARAM(sharp,
+			  0x003D83FF, 0x002C636A, 0x0013F204, 0x00008090,
+			  0x00F87FB0, 0x00F99F83, 0x00FDBFBA, 0x00003FF5);
+	__DECL_DFIR_PARAM(sharp_14,
+			  0x003B13FF, 0x001C42DE, 0x00FDB0AD, 0x00F60F6E,
+			  0x00FD8F92, 0x0002D011, 0x0001C02C, 0x00FFF00A);
+	__DECL_DFIR_ADDR(filter,
+			 0x45BC, 0x45CC, 0x45D0, 0x45D4, 0x45D8, 0x45C0,
+			 0x45C4, 0x45C8);
+	u8 ch = rtwdev->hal.current_channel;
+	const u32 *param;
+	int i;
+
+	if (ch > 14) {
+		rtw89_warn(rtwdev,
+			   "set tx shape dfir by unknown ch: %d on 2G\n", ch);
+		return;
+	}
+
+	if (ch == 14)
+		param = param_sharp_14;
+	else
+		param = tx_shape_idx == 0 ? param_flat : param_sharp;
+
+	for (i = 0; i < __DFIR_CFG_NR; i++) {
+		rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+			    "set tx shape dfir: 0x%x: 0x%x\n", addr_filter[i],
+			    param[i]);
+		rtw89_phy_write32_idx(rtwdev, addr_filter[i], __DFIR_CFG_MASK,
+				      param[i], phy_idx);
+	}
+
+#undef __DECL_DFIR_ADDR
+#undef __DECL_DFIR_PARAM
+#undef __DECL_DFIR_VAR
+#undef __DFIR_CFG_NR
+#undef __DFIR_CFG_MASK
+}
+
+static void rtw8852c_set_tx_shape(struct rtw89_dev *rtwdev,
+				  enum rtw89_phy_idx phy_idx)
+{
+	u8 band = rtwdev->hal.current_band_type;
+	u8 regd = rtw89_regd_get(rtwdev, band);
+	u8 tx_shape_cck = rtw89_8852c_tx_shape[band][RTW89_RS_CCK][regd];
+	u8 tx_shape_ofdm = rtw89_8852c_tx_shape[band][RTW89_RS_OFDM][regd];
+
+	if (band == RTW89_BAND_2G)
+		rtw8852c_bb_set_tx_shape_dfir(rtwdev, tx_shape_cck, phy_idx);
+
+	rtw89_phy_tssi_ctrl_set_bandedge_cfg(rtwdev,
+					     (enum rtw89_mac_idx)phy_idx,
+					     tx_shape_ofdm);
+}
+
+static void rtw8852c_set_txpwr_limit(struct rtw89_dev *rtwdev,
+				     enum rtw89_phy_idx phy_idx)
+{
+#define __MAC_TXPWR_LMT_PAGE_SIZE 40
+	u8 ch = rtwdev->hal.current_channel;
+	u8 bw = rtwdev->hal.current_band_width;
+	struct rtw89_txpwr_limit lmt[NTX_NUM_8852C];
+	u32 addr, val;
+	const s8 *ptr;
+	u8 i, j, k;
+
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+		    "[TXPWR] set txpwr limit with ch=%d bw=%d\n", ch, bw);
+
+	for (i = 0; i < NTX_NUM_8852C; i++) {
+		rtw89_phy_fill_txpwr_limit(rtwdev, &lmt[i], i);
+
+		for (j = 0; j < __MAC_TXPWR_LMT_PAGE_SIZE; j += 4) {
+			addr = R_AX_PWR_LMT + j + __MAC_TXPWR_LMT_PAGE_SIZE * i;
+			ptr = (s8 *)&lmt[i] + j;
+			val = 0;
+
+			for (k = 0; k < 4; k++)
+				val |= (ptr[k] << (8 * k));
+
+			rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val);
+		}
+	}
+#undef __MAC_TXPWR_LMT_PAGE_SIZE
+}
+
+static void rtw8852c_set_txpwr_limit_ru(struct rtw89_dev *rtwdev,
+					enum rtw89_phy_idx phy_idx)
+{
+#define __MAC_TXPWR_LMT_RU_PAGE_SIZE 24
+	u8 ch = rtwdev->hal.current_channel;
+	u8 bw = rtwdev->hal.current_band_width;
+	struct rtw89_txpwr_limit_ru lmt_ru[NTX_NUM_8852C];
+	u32 addr, val;
+	const s8 *ptr;
+	u8 i, j, k;
+
+	rtw89_debug(rtwdev, RTW89_DBG_TXPWR,
+		    "[TXPWR] set txpwr limit ru with ch=%d bw=%d\n", ch, bw);
+
+	for (i = 0; i < NTX_NUM_8852C; i++) {
+		rtw89_phy_fill_txpwr_limit_ru(rtwdev, &lmt_ru[i], i);
+
+		for (j = 0; j < __MAC_TXPWR_LMT_RU_PAGE_SIZE; j += 4) {
+			addr = R_AX_PWR_RU_LMT + j +
+			       __MAC_TXPWR_LMT_RU_PAGE_SIZE * i;
+			ptr = (s8 *)&lmt_ru[i] + j;
+			val = 0;
+
+			for (k = 0; k < 4; k++)
+				val |= (ptr[k] << (8 * k));
+
+			rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, val);
+		}
+	}
+
+#undef __MAC_TXPWR_LMT_RU_PAGE_SIZE
+}
+
+static void rtw8852c_set_txpwr(struct rtw89_dev *rtwdev)
+{
+	rtw8852c_set_txpwr_byrate(rtwdev, RTW89_PHY_0);
+	rtw8852c_set_txpwr_offset(rtwdev, RTW89_PHY_0);
+	rtw8852c_set_tx_shape(rtwdev, RTW89_PHY_0);
+	rtw8852c_set_txpwr_limit(rtwdev, RTW89_PHY_0);
+	rtw8852c_set_txpwr_limit_ru(rtwdev, RTW89_PHY_0);
+}
+
+static void rtw8852c_set_txpwr_ctrl(struct rtw89_dev *rtwdev)
+{
+	rtw8852c_set_txpwr_ref(rtwdev, RTW89_PHY_0);
+}
+
+static void
+rtw8852c_init_tssi_ctrl(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+	static const struct rtw89_reg2_def ctrl_ini[] = {
+		{0xD938, 0x00010100},
+		{0xD93C, 0x0500D500},
+		{0xD940, 0x00000500},
+		{0xD944, 0x00000005},
+		{0xD94C, 0x00220000},
+		{0xD950, 0x00030000},
+	};
+	u32 addr;
+	int i;
+
+	for (addr = R_AX_TSSI_CTRL_HEAD; addr <= R_AX_TSSI_CTRL_TAIL; addr += 4)
+		rtw89_mac_txpwr_write32(rtwdev, phy_idx, addr, 0);
+
+	for (i = 0; i < ARRAY_SIZE(ctrl_ini); i++)
+		rtw89_mac_txpwr_write32(rtwdev, phy_idx, ctrl_ini[i].addr,
+					ctrl_ini[i].data);
+
+	rtw89_phy_tssi_ctrl_set_bandedge_cfg(rtwdev,
+					     (enum rtw89_mac_idx)phy_idx,
+					     RTW89_TSSI_BANDEDGE_FLAT);
+}
+
+static int
+rtw8852c_init_txpwr_unit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
+{
+	int ret;
+
+	ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL2, 0x07763333);
+	if (ret)
+		return ret;
+
+	ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_COEXT_CTRL, 0x01ebf000);
+	if (ret)
+		return ret;
+
+	ret = rtw89_mac_txpwr_write32(rtwdev, phy_idx, R_AX_PWR_UL_CTRL0, 0x0002f8ff);
+	if (ret)
+		return ret;
+
+	rtw8852c_set_txpwr_ul_tb_offset(rtwdev, 0, phy_idx == RTW89_PHY_1 ?
+							      RTW89_MAC_1 :
+							      RTW89_MAC_0);
+	rtw8852c_init_tssi_ctrl(rtwdev, phy_idx);
+
+	return 0;
+}
+
 static void rtw8852c_bb_cfg_rx_path(struct rtw89_dev *rtwdev, u8 rx_path)
 {
 	struct rtw89_hal *hal = &rtwdev->hal;
@@ -2163,6 +2484,9 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
 	.rfk_init		= rtw8852c_rfk_init,
 	.rfk_channel		= rtw8852c_rfk_channel,
 	.power_trim		= rtw8852c_power_trim,
+	.set_txpwr		= rtw8852c_set_txpwr,
+	.set_txpwr_ctrl		= rtw8852c_set_txpwr_ctrl,
+	.init_txpwr_unit	= rtw8852c_init_txpwr_unit,
 	.read_rf		= rtw89_phy_read_rf_v1,
 	.write_rf		= rtw89_phy_write_rf_v1,
 	.set_txpwr_ul_tb_offset	= rtw8852c_set_txpwr_ul_tb_offset,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.h b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
index ac642808a81ff..558dd0f048f2b 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
@@ -9,6 +9,7 @@
 
 #define RF_PATH_NUM_8852C 2
 #define BB_PATH_NUM_8852C 2
+#define NTX_NUM_8852C 2
 
 struct rtw8852c_u_efuse {
 	u8 rsvd[0x38];
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 12/14] rtw89: 8852c: implement chip_ops::get_thermal
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (10 preceding siblings ...)
  2022-04-21 12:09 ` [PATCH 11/14] rtw89: 8852c: implement chip_ops related to TX power Ping-Ke Shih
@ 2022-04-21 12:09 ` Ping-Ke Shih
  2022-04-21 12:09 ` [PATCH 13/14] rtw89: 8852c: fill freq and band of RX status by PPDU report Ping-Ke Shih
  2022-04-21 12:09 ` [PATCH 14/14] rtw89: 8852c: add chip_ops related to BTC Ping-Ke Shih
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:09 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

Read thermal value, and then we can use EWMA thermal value to do RF
calibrations if the value is changed over a threshold.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index adcc2b597419d..daf467eaef665 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2327,6 +2327,17 @@ static void rtw8852c_bb_cfg_txrx_path(struct rtw89_dev *rtwdev)
 	rtw8852c_ctrl_tx_path_tmac(rtwdev, RF_PATH_AB, RTW89_MAC_0);
 }
 
+static u8 rtw8852c_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path)
+{
+	rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1);
+	rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x0);
+	rtw89_write_rf(rtwdev, rf_path, RR_TM, RR_TM_TRI, 0x1);
+
+	fsleep(200);
+
+	return rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL);
+}
+
 static void rtw8852c_ctrl_btg(struct rtw89_dev *rtwdev, bool btg)
 {
 	if (btg) {
@@ -2487,6 +2498,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
 	.set_txpwr		= rtw8852c_set_txpwr,
 	.set_txpwr_ctrl		= rtw8852c_set_txpwr_ctrl,
 	.init_txpwr_unit	= rtw8852c_init_txpwr_unit,
+	.get_thermal		= rtw8852c_get_thermal,
 	.read_rf		= rtw89_phy_read_rf_v1,
 	.write_rf		= rtw89_phy_write_rf_v1,
 	.set_txpwr_ul_tb_offset	= rtw8852c_set_txpwr_ul_tb_offset,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 13/14] rtw89: 8852c: fill freq and band of RX status by PPDU report
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (11 preceding siblings ...)
  2022-04-21 12:09 ` [PATCH 12/14] rtw89: 8852c: implement chip_ops::get_thermal Ping-Ke Shih
@ 2022-04-21 12:09 ` Ping-Ke Shih
  2022-04-21 12:09 ` [PATCH 14/14] rtw89: 8852c: add chip_ops related to BTC Ping-Ke Shih
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:09 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

Hardware reports PPDU status containing encoded channel index to driver,
so we decode it and then fill freq and band.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index daf467eaef665..f66e4e091e439 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2440,6 +2440,38 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev)
 	btc->cx.wl.status.map.init_ok = true;
 }
 
+static void rtw8852c_fill_freq_with_ppdu(struct rtw89_dev *rtwdev,
+					 struct rtw89_rx_phy_ppdu *phy_ppdu,
+					 struct ieee80211_rx_status *status)
+{
+	u8 chan_idx = phy_ppdu->chan_idx;
+	enum nl80211_band band;
+	u8 ch;
+
+	if (chan_idx == 0)
+		return;
+
+	rtw8852c_decode_chan_idx(rtwdev, chan_idx, &ch, &band);
+	status->freq = ieee80211_channel_to_frequency(ch, band);
+	status->band = band;
+}
+
+static void rtw8852c_query_ppdu(struct rtw89_dev *rtwdev,
+				struct rtw89_rx_phy_ppdu *phy_ppdu,
+				struct ieee80211_rx_status *status)
+{
+	u8 path;
+	s8 *rx_power = phy_ppdu->rssi;
+
+	status->signal = max_t(s8, rx_power[RF_PATH_A], rx_power[RF_PATH_B]);
+	for (path = 0; path < rtwdev->chip->rf_path_num; path++) {
+		status->chains |= BIT(path);
+		status->chain_signal[path] = rx_power[path];
+	}
+	if (phy_ppdu->valid)
+		rtw8852c_fill_freq_with_ppdu(rtwdev, phy_ppdu, status);
+}
+
 static int rtw8852c_mac_enable_bb_rf(struct rtw89_dev *rtwdev)
 {
 	int ret;
@@ -2499,6 +2531,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
 	.set_txpwr_ctrl		= rtw8852c_set_txpwr_ctrl,
 	.init_txpwr_unit	= rtw8852c_init_txpwr_unit,
 	.get_thermal		= rtw8852c_get_thermal,
+	.query_ppdu		= rtw8852c_query_ppdu,
 	.read_rf		= rtw89_phy_read_rf_v1,
 	.write_rf		= rtw89_phy_write_rf_v1,
 	.set_txpwr_ul_tb_offset	= rtw8852c_set_txpwr_ul_tb_offset,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 14/14] rtw89: 8852c: add chip_ops related to BTC
  2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
                   ` (12 preceding siblings ...)
  2022-04-21 12:09 ` [PATCH 13/14] rtw89: 8852c: fill freq and band of RX status by PPDU report Ping-Ke Shih
@ 2022-04-21 12:09 ` Ping-Ke Shih
  13 siblings, 0 replies; 20+ messages in thread
From: Ping-Ke Shih @ 2022-04-21 12:09 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

Add some chip_ops to support BT coexistence to work properly.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/reg.h      |   7 +
 drivers/net/wireless/realtek/rtw89/rtw8852c.c | 187 ++++++++++++++++++
 2 files changed, 194 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 6dc11e8e2a839..83cb509d2fbe9 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -3048,11 +3048,18 @@
 #define B_AX_BT_CNT_RST_V1 BIT(1)
 #define B_AX_BT_CNT_EN BIT(0)
 
+#define R_BTC_BT_CNT_HIGH 0xDA14
+#define R_BTC_BT_CNT_LOW 0xDA18
+
 #define R_AX_BTC_FUNC_EN 0xDA20
 #define R_AX_BTC_FUNC_EN_C1 0xFA20
 #define B_AX_PTA_WL_TX_EN BIT(1)
 #define B_AX_PTA_EDCCA_EN BIT(0)
 
+#define R_BTC_COEX_WL_REQ 0xDA24
+#define B_BTC_TX_BCN_HI BIT(22)
+#define B_BTC_RSP_ACK_HI BIT(10)
+
 #define R_BTC_BREAK_TABLE 0xDA2C
 #define BTC_BREAK_PARAM 0xf0ffffff
 
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index f66e4e091e439..858611c64e6bf 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -2338,6 +2338,33 @@ static u8 rtw8852c_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p
 	return rtw89_read_rf(rtwdev, rf_path, RR_TM, RR_TM_VAL);
 }
 
+static void rtw8852c_btc_set_rfe(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_module *module = &btc->mdinfo;
+
+	module->rfe_type = rtwdev->efuse.rfe_type;
+	module->cv = rtwdev->hal.cv;
+	module->bt_solo = 0;
+	module->switch_type = BTC_SWITCH_INTERNAL;
+
+	if (module->rfe_type > 0)
+		module->ant.num = (module->rfe_type % 2 ? 2 : 3);
+	else
+		module->ant.num = 2;
+
+	module->ant.diversity = 0;
+	module->ant.isolation = 10;
+
+	if (module->ant.num == 3) {
+		module->ant.type = BTC_ANT_DEDICATED;
+		module->bt_pos = BTC_BT_ALONE;
+	} else {
+		module->ant.type = BTC_ANT_SHARED;
+		module->bt_pos = BTC_BT_BTG;
+	}
+}
+
 static void rtw8852c_ctrl_btg(struct rtw89_dev *rtwdev, bool btg)
 {
 	if (btg) {
@@ -2440,6 +2467,159 @@ static void rtw8852c_btc_init_cfg(struct rtw89_dev *rtwdev)
 	btc->cx.wl.status.map.init_ok = true;
 }
 
+static
+void rtw8852c_btc_set_wl_pri(struct rtw89_dev *rtwdev, u8 map, bool state)
+{
+	u32 bitmap = 0;
+	u32 reg = 0;
+
+	switch (map) {
+	case BTC_PRI_MASK_TX_RESP:
+		reg = R_BTC_COEX_WL_REQ;
+		bitmap = B_BTC_RSP_ACK_HI;
+		break;
+	case BTC_PRI_MASK_BEACON:
+		reg = R_BTC_COEX_WL_REQ;
+		bitmap = B_BTC_TX_BCN_HI;
+		break;
+	default:
+		return;
+	}
+
+	if (state)
+		rtw89_write32_set(rtwdev, reg, bitmap);
+	else
+		rtw89_write32_clr(rtwdev, reg, bitmap);
+}
+
+union rtw8852c_btc_wl_txpwr_ctrl {
+	u32 txpwr_val;
+	struct {
+		union {
+			u16 ctrl_all_time;
+			struct {
+				s16 data:9;
+				u16 rsvd:6;
+				u16 flag:1;
+			} all_time;
+		};
+		union {
+			u16 ctrl_gnt_bt;
+			struct {
+				s16 data:9;
+				u16 rsvd:7;
+			} gnt_bt;
+		};
+	};
+} __packed;
+
+static void
+rtw8852c_btc_set_wl_txpwr_ctrl(struct rtw89_dev *rtwdev, u32 txpwr_val)
+{
+	union rtw8852c_btc_wl_txpwr_ctrl arg = { .txpwr_val = txpwr_val };
+	s32 val;
+
+#define __write_ctrl(_reg, _msk, _val, _en, _cond)		\
+do {								\
+	const typeof(_msk) __msk = _msk;			\
+	const typeof(_en) __en = _en;				\
+	u32 _wrt = FIELD_PREP(__msk, _val);			\
+	BUILD_BUG_ON((__msk & __en) != 0);			\
+	if (_cond)						\
+		_wrt |= __en;					\
+	else							\
+		_wrt &= ~__en;					\
+	rtw89_mac_txpwr_write32_mask(rtwdev, RTW89_PHY_0, _reg,	\
+				     __msk | __en, _wrt);	\
+} while (0)
+
+	switch (arg.ctrl_all_time) {
+	case 0xffff:
+		val = 0;
+		break;
+	default:
+		val = arg.all_time.data;
+		break;
+	}
+
+	__write_ctrl(R_AX_PWR_RATE_CTRL, B_AX_FORCE_PWR_BY_RATE_VALUE_MASK,
+		     val, B_AX_FORCE_PWR_BY_RATE_EN,
+		     arg.ctrl_all_time != 0xffff);
+
+	switch (arg.ctrl_gnt_bt) {
+	case 0xffff:
+		val = 0;
+		break;
+	default:
+		val = arg.gnt_bt.data;
+		break;
+	};
+
+	__write_ctrl(R_AX_PWR_COEXT_CTRL, B_AX_TXAGC_BT_MASK, val,
+		     B_AX_TXAGC_BT_EN, arg.ctrl_gnt_bt != 0xffff);
+
+#undef __write_ctrl
+}
+
+static
+s8 rtw8852c_btc_get_bt_rssi(struct rtw89_dev *rtwdev, s8 val)
+{
+	return clamp_t(s8, val, -100, 0) + 100;
+}
+
+static
+void rtw8852c_btc_bt_aci_imp(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_dm *dm = &btc->dm;
+	struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+	struct rtw89_btc_bt_link_info *b = &bt->link_info;
+
+	/* fix LNA2 = level-5 for BT ACI issue at BTG */
+	if (btc->dm.wl_btg_rx && b->profile_cnt.now != 0)
+		dm->trx_para_level = 1;
+}
+
+static
+void rtw8852c_btc_update_bt_cnt(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_btc *btc = &rtwdev->btc;
+	struct rtw89_btc_cx *cx = &btc->cx;
+	u32 val;
+
+	val = rtw89_read32(rtwdev, R_BTC_BT_CNT_HIGH);
+	cx->cnt_bt[BTC_BCNT_HIPRI_TX] = FIELD_GET(B_AX_STATIS_BT_HI_TX_MASK, val);
+	cx->cnt_bt[BTC_BCNT_HIPRI_RX] = FIELD_GET(B_AX_STATIS_BT_HI_RX_MASK, val);
+
+	val = rtw89_read32(rtwdev, R_BTC_BT_CNT_LOW);
+	cx->cnt_bt[BTC_BCNT_LOPRI_TX] = FIELD_GET(B_AX_STATIS_BT_LO_TX_1_MASK, val);
+	cx->cnt_bt[BTC_BCNT_LOPRI_RX] = FIELD_GET(B_AX_STATIS_BT_LO_RX_1_MASK, val);
+
+	/* clock-gate off before reset counter*/
+	rtw89_write32_set(rtwdev, R_AX_BTC_CFG, B_AX_DIS_BTC_CLK_G);
+	rtw89_write32_clr(rtwdev, R_AX_BT_CNT_CFG, B_AX_BT_CNT_RST);
+	rtw89_write32_set(rtwdev, R_AX_BT_CNT_CFG, B_AX_BT_CNT_RST);
+	rtw89_write32_clr(rtwdev, R_AX_BTC_CFG, B_AX_DIS_BTC_CLK_G);
+}
+
+static
+void rtw8852c_btc_wl_s1_standby(struct rtw89_dev *rtwdev, bool state)
+{
+	rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x80000);
+	rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWA, RFREG_MASK, 0x1);
+	rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD1, RFREG_MASK, 0x620);
+
+	/* set WL standby = Rx for GNT_BT_Tx = 1->0 settle issue */
+	if (state)
+		rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0,
+			       RFREG_MASK, 0x179c);
+	else
+		rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWD0,
+			       RFREG_MASK, 0x208);
+
+	rtw89_write_rf(rtwdev, RF_PATH_B, RR_LUTWE, RFREG_MASK, 0x0);
+}
+
 static void rtw8852c_fill_freq_with_ppdu(struct rtw89_dev *rtwdev,
 					 struct rtw89_rx_phy_ppdu *phy_ppdu,
 					 struct ieee80211_rx_status *status)
@@ -2546,7 +2726,14 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = {
 	.resume_sch_tx		= rtw89_mac_resume_sch_tx_v1,
 	.h2c_dctl_sec_cam	= rtw89_fw_h2c_dctl_sec_cam_v1,
 
+	.btc_set_rfe		= rtw8852c_btc_set_rfe,
 	.btc_init_cfg		= rtw8852c_btc_init_cfg,
+	.btc_set_wl_pri		= rtw8852c_btc_set_wl_pri,
+	.btc_set_wl_txpwr_ctrl	= rtw8852c_btc_set_wl_txpwr_ctrl,
+	.btc_get_bt_rssi	= rtw8852c_btc_get_bt_rssi,
+	.btc_bt_aci_imp		= rtw8852c_btc_bt_aci_imp,
+	.btc_update_bt_cnt	= rtw8852c_btc_update_bt_cnt,
+	.btc_wl_s1_standby	= rtw8852c_btc_wl_s1_standby,
 };
 
 const struct rtw89_chip_info rtw8852c_chip_info = {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode
  2022-04-21 12:08 ` [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode Ping-Ke Shih
@ 2022-04-23 12:32   ` Kalle Valo
  2022-04-23 12:37     ` Kalle Valo
  0 siblings, 1 reply; 20+ messages in thread
From: Kalle Valo @ 2022-04-23 12:32 UTC (permalink / raw)
  To: Ping-Ke Shih; +Cc: linux-wireless

Ping-Ke Shih <pkshih@realtek.com> wrote:

> In lower power mode, there are very low amount of RX, and it must process
> in a separated function instead of schedule_napi(), because the existing
> napi_poll does many things to optimize performance, but not all registers
> can access in low power mode. The simple way is to use threadfn to process
> the simple thing.
> 
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>

The title is hard to understand.

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20220421120903.73715-5-pkshih@realtek.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode
  2022-04-23 12:32   ` Kalle Valo
@ 2022-04-23 12:37     ` Kalle Valo
  2022-04-24  2:58       ` Pkshih
  0 siblings, 1 reply; 20+ messages in thread
From: Kalle Valo @ 2022-04-23 12:37 UTC (permalink / raw)
  To: Ping-Ke Shih; +Cc: linux-wireless

Kalle Valo <kvalo@kernel.org> writes:

> Ping-Ke Shih <pkshih@realtek.com> wrote:
>
>> In lower power mode, there are very low amount of RX, and it must process
>> in a separated function instead of schedule_napi(), because the existing
>> napi_poll does many things to optimize performance, but not all registers
>> can access in low power mode. The simple way is to use threadfn to process
>> the simple thing.
>> 
>> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
>
> The title is hard to understand.

If you can provide a new title I can fix it during commit.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode
  2022-04-23 12:37     ` Kalle Valo
@ 2022-04-24  2:58       ` Pkshih
  2022-04-24  4:15         ` Kalle Valo
  0 siblings, 1 reply; 20+ messages in thread
From: Pkshih @ 2022-04-24  2:58 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless

On Sat, 2022-04-23 at 15:37 +0300, Kalle Valo wrote:
> Kalle Valo <kvalo@kernel.org> writes:
> 
> > Ping-Ke Shih <pkshih@realtek.com> wrote:
> > 
> > > In lower power mode, there are very low amount of RX, and it must process
> > > in a separated function instead of schedule_napi(), because the existing
> > > napi_poll does many things to optimize performance, but not all registers
> > > can access in low power mode. The simple way is to use threadfn to process
> > > the simple thing.
> > > 
> > > Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
> > 
> > The title is hard to understand.
> 
> If you can provide a new title I can fix it during commit.
> 

Please help re-title to "rtw89: pci: add a separated interrupt handler for low power mode".

Thank you
Ping-Ke



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode
  2022-04-24  2:58       ` Pkshih
@ 2022-04-24  4:15         ` Kalle Valo
  0 siblings, 0 replies; 20+ messages in thread
From: Kalle Valo @ 2022-04-24  4:15 UTC (permalink / raw)
  To: Pkshih; +Cc: linux-wireless

Pkshih <pkshih@realtek.com> writes:

> On Sat, 2022-04-23 at 15:37 +0300, Kalle Valo wrote:
>> Kalle Valo <kvalo@kernel.org> writes:
>> 
>> > Ping-Ke Shih <pkshih@realtek.com> wrote:
>> > 
>> > > In lower power mode, there are very low amount of RX, and it must process
>> > > in a separated function instead of schedule_napi(), because the existing
>> > > napi_poll does many things to optimize performance, but not all registers
>> > > can access in low power mode. The simple way is to use threadfn to process
>> > > the simple thing.
>> > > 
>> > > Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
>> > 
>> > The title is hard to understand.
>> 
>> If you can provide a new title I can fix it during commit.
>> 
>
> Please help re-title to "rtw89: pci: add a separated interrupt handler for low power mode".

This is much better, thanks. I'll update the title during commit.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 01/14] rtw89: pci: add variant IMR/ISR and configure functions
  2022-04-21 12:08 ` [PATCH 01/14] rtw89: pci: add variant IMR/ISR and configure functions Ping-Ke Shih
@ 2022-04-24 11:31   ` Kalle Valo
  0 siblings, 0 replies; 20+ messages in thread
From: Kalle Valo @ 2022-04-24 11:31 UTC (permalink / raw)
  To: Ping-Ke Shih; +Cc: linux-wireless

Ping-Ke Shih <pkshih@realtek.com> wrote:

> 8852CE uses different but similar IMR/ISR registers, and its masks are also
> different in various states, so add config_intr_mask ops to configure masks
> according to under_recovery or low_power states.
> 
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>

14 patches applied to wireless-next.git, thanks.

948e521c7285 rtw89: pci: add variant IMR/ISR and configure functions
e1757e804501 rtw89: pci: add variant RPWM/CPWM to enter low power mode
837202684657 rtw89: pci: reclaim TX BD only if it really need
c83dcd0508e2 rtw89: pci: add a separate interrupt handler for low power mode
98816def1973 rtw89: ser: re-enable interrupt in threadfn if under_recovery
52edbb9fb78a rtw89: ps: access TX/RX rings via another registers in low power mode
d7259cdbd055 rtw89: pci: allow to process RPP prior to TX BD
fc5f311fce74 rtw89: don't flush hci queues and send h2c if power is off
16b44ed0ffd3 rtw89: add RF H2C to notify firmware
cd89a47105dc rtw89: 8852c: configure default BB TX/RX path
af0cac159b1c rtw89: 8852c: implement chip_ops related to TX power
3ecca403d9bf rtw89: 8852c: implement chip_ops::get_thermal
f4ae7ccc2bbf rtw89: 8852c: fill freq and band of RX status by PPDU report
2fb822f82a59 rtw89: 8852c: add chip_ops related to BTC

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20220421120903.73715-2-pkshih@realtek.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2022-04-24 11:31 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-21 12:08 [PATCH 00/14] rtw89: 8852c: extend PCI code to support 8852ce and add 8852c chip_ops Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 01/14] rtw89: pci: add variant IMR/ISR and configure functions Ping-Ke Shih
2022-04-24 11:31   ` Kalle Valo
2022-04-21 12:08 ` [PATCH 02/14] rtw89: pci: add variant RPWM/CPWM to enter low power mode Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 03/14] rtw89: pci: reclaim TX BD only if it really need Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 04/14] rtw89: pci: does RX in interrupt threadfn if low power mode Ping-Ke Shih
2022-04-23 12:32   ` Kalle Valo
2022-04-23 12:37     ` Kalle Valo
2022-04-24  2:58       ` Pkshih
2022-04-24  4:15         ` Kalle Valo
2022-04-21 12:08 ` [PATCH 05/14] rtw89: ser: re-enable interrupt in threadfn if under_recovery Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 06/14] rtw89: ps: access TX/RX rings via another registers in low power mode Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 07/14] rtw89: pci: allow to process RPP prior to TX BD Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 08/14] rtw89: don't flush hci queues and send h2c if power is off Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 09/14] rtw89: add RF H2C to notify firmware Ping-Ke Shih
2022-04-21 12:08 ` [PATCH 10/14] rtw89: 8852c: configure default BB TX/RX path Ping-Ke Shih
2022-04-21 12:09 ` [PATCH 11/14] rtw89: 8852c: implement chip_ops related to TX power Ping-Ke Shih
2022-04-21 12:09 ` [PATCH 12/14] rtw89: 8852c: implement chip_ops::get_thermal Ping-Ke Shih
2022-04-21 12:09 ` [PATCH 13/14] rtw89: 8852c: fill freq and band of RX status by PPDU report Ping-Ke Shih
2022-04-21 12:09 ` [PATCH 14/14] rtw89: 8852c: add chip_ops related to BTC Ping-Ke Shih

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.