wifi: rtw89: pci: use DBI function for 8852AE/8852BE/8851BE
authorChin-Yen Lee <timlee@realtek.com>
Wed, 3 Jan 2024 01:23:46 +0000 (09:23 +0800)
committerKalle Valo <kvalo@kernel.org>
Wed, 10 Jan 2024 14:48:40 +0000 (16:48 +0200)
Sometimes driver can't use kernel API pci_read/write_config_byte
to access the PCI config space of above address 0x100 due to
the negotiated PCI setting. 8852AE/8852BE/8851BE provide another
way called DBI function, which belongs to WiFi mac and could
access all PCI config space for this case.

Link: https://lore.kernel.org/linux-wireless/79fe81b7db7148b9a7da2353c16d70fb@realtek.com/T/#t
Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://msgid.link/20240103012346.6822-1-pkshih@realtek.com
drivers/net/wireless/realtek/rtw89/pci.c
drivers/net/wireless/realtek/rtw89/pci.h

index 769f1ce62ebcc01d04fff047d76fa57e69e51f62..9943ed856248fdf723148cab5432f44baeca423d 100644 (file)
@@ -1907,22 +1907,87 @@ static int rtw89_write16_mdio_clr(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u
        return 0;
 }
 
+static int rtw89_dbi_write8(struct rtw89_dev *rtwdev, u16 addr, u8 data)
+{
+       u16 addr_2lsb = addr & B_AX_DBI_2LSB;
+       u16 write_addr;
+       u8 flag;
+       int ret;
+
+       write_addr = addr & B_AX_DBI_ADDR_MSK;
+       write_addr |= u16_encode_bits(BIT(addr_2lsb), B_AX_DBI_WREN_MSK);
+       rtw89_write8(rtwdev, R_AX_DBI_WDATA + addr_2lsb, data);
+       rtw89_write16(rtwdev, R_AX_DBI_FLAG, write_addr);
+       rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_WFLAG >> 16);
+
+       ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10,
+                                      10 * RTW89_PCI_WR_RETRY_CNT, false,
+                                      rtwdev, R_AX_DBI_FLAG + 2);
+       if (ret)
+               rtw89_err(rtwdev, "failed to write DBI register, addr=0x%X\n",
+                         addr);
+
+       return ret;
+}
+
+static int rtw89_dbi_read8(struct rtw89_dev *rtwdev, u16 addr, u8 *value)
+{
+       u16 read_addr = addr & B_AX_DBI_ADDR_MSK;
+       u8 flag;
+       int ret;
+
+       rtw89_write16(rtwdev, R_AX_DBI_FLAG, read_addr);
+       rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_RFLAG >> 16);
+
+       ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10,
+                                      10 * RTW89_PCI_WR_RETRY_CNT, false,
+                                      rtwdev, R_AX_DBI_FLAG + 2);
+       if (ret) {
+               rtw89_err(rtwdev, "failed to read DBI register, addr=0x%X\n",
+                         addr);
+               return ret;
+       }
+
+       read_addr = R_AX_DBI_RDATA + (addr & 3);
+       *value = rtw89_read8(rtwdev, read_addr);
+
+       return 0;
+}
+
 static int rtw89_pci_write_config_byte(struct rtw89_dev *rtwdev, u16 addr,
                                       u8 data)
 {
        struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+       enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
        struct pci_dev *pdev = rtwpci->pdev;
+       int ret;
+
+       ret = pci_write_config_byte(pdev, addr, data);
+       if (!ret)
+               return 0;
 
-       return pci_write_config_byte(pdev, addr, data);
+       if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B)
+               ret = rtw89_dbi_write8(rtwdev, addr, data);
+
+       return ret;
 }
 
 static int rtw89_pci_read_config_byte(struct rtw89_dev *rtwdev, u16 addr,
                                      u8 *value)
 {
        struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+       enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
        struct pci_dev *pdev = rtwpci->pdev;
+       int ret;
 
-       return pci_read_config_byte(pdev, addr, value);
+       ret = pci_read_config_byte(pdev, addr, value);
+       if (!ret)
+               return 0;
+
+       if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B)
+               ret = rtw89_dbi_read8(rtwdev, addr, value);
+
+       return ret;
 }
 
 static int rtw89_pci_config_byte_set(struct rtw89_dev *rtwdev, u16 addr,
index ca5de77fee90a6c2fdb61db30bf285ad1f51b2a3..1fb7c209fa0da1c4ade792a03273eccecbc27eff 100644 (file)
@@ -42,6 +42,7 @@
 #define B_AX_DBI_WFLAG                 BIT(16)
 #define B_AX_DBI_WREN_MSK              GENMASK(15, 12)
 #define B_AX_DBI_ADDR_MSK              GENMASK(11, 2)
+#define B_AX_DBI_2LSB                  GENMASK(1, 0)
 #define R_AX_DBI_WDATA                 0x1094
 #define R_AX_DBI_RDATA                 0x1098