net: wireless: rockchip: add rtl8822be pcie wifi driver
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8822be / hal / rtl8822b / pci / rtl8822be_io.c
diff --git a/drivers/net/wireless/rockchip_wlan/rtl8822be/hal/rtl8822b/pci/rtl8822be_io.c b/drivers/net/wireless/rockchip_wlan/rtl8822be/hal/rtl8822b/pci/rtl8822be_io.c
new file mode 100644 (file)
index 0000000..ac39ef6
--- /dev/null
@@ -0,0 +1,349 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ *
+ ******************************************************************************/
+#define _RTL8822BE_IO_C_
+
+#include <drv_types.h>         /* PADAPTER and etc. */
+
+#ifdef RTK_129X_PLATFORM
+#include <soc/realtek/rtd129x_lockapi.h>
+
+#define IO_2K_MASK 0xFFFFF800
+#define IO_4K_MASK 0xFFFFF000
+#define MAX_RETRY 5
+
+static u32 pci_io_read_129x(struct dvobj_priv *pdvobjpriv, u32 addr, u8 size)
+{
+       unsigned long mask_addr = pdvobjpriv->mask_addr;
+       unsigned long tran_addr = pdvobjpriv->tran_addr;
+       u8 busnumber = pdvobjpriv->pcipriv.busnumber;
+       u32 rval = 0;
+       u32 mask;
+       u32 translate_val = 0;
+       u32 tmp_addr = addr & 0xFFF;
+       _irqL irqL;
+       u32 pci_error_status = 0;
+       int retry_cnt = 0;
+       unsigned long flags;
+
+       _enter_critical(&pdvobjpriv->io_reg_lock, &irqL);
+
+       /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
+        * can't be used because of 1295 hardware issue.
+        */
+       if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
+           (tmp_addr == 0xC68))) {
+               mask = IO_2K_MASK;
+               writel(0xFFFFF800, (u8 *)mask_addr);
+               translate_val = readl((u8 *)tran_addr);
+               writel(translate_val|(addr&mask), (u8 *)tran_addr);
+       } else if (addr >= 0x1000) {
+               mask = IO_4K_MASK;
+               translate_val = readl((u8 *)tran_addr);
+               writel(translate_val|(addr&mask), (u8 *)tran_addr);
+       } else
+               mask = 0x0;
+
+pci_read_129x_retry:
+
+       /* All RBUS1 driver need to have a workaround for emmc hardware error */
+       /* Need to protect 0xXXXX_X8XX~ 0xXXXX_X9XX */
+       if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
+               rtk_lockapi_lock(flags, __func__);
+
+       switch (size) {
+       case 1:
+               rval = readb((u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
+               break;
+       case 2:
+               rval = readw((u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
+               break;
+       case 4:
+               rval = readl((u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
+               break;
+       default:
+               RTW_WARN("RTD129X: %s: wrong size %d\n", __func__, size);
+               break;
+       }
+
+       if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
+               rtk_lockapi_unlock(flags, __func__);
+
+       //DLLP error patch
+       pci_error_status = readl( (u8 *)(pdvobjpriv->ctrl_start + 0x7C));
+       if(pci_error_status & 0x1F) {
+               writel(pci_error_status, (u8 *)(pdvobjpriv->ctrl_start + 0x7C));
+               RTW_WARN("RTD129X: %s: DLLP(#%d) 0x%x reg=0x%x val=0x%x\n", __func__, retry_cnt, pci_error_status, addr, rval);
+
+               if(retry_cnt < MAX_RETRY) {
+                       retry_cnt++;
+                       goto pci_read_129x_retry;
+               }
+       }
+
+       /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
+        * can't be used because of 1295 hardware issue.
+        */
+       if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
+           (tmp_addr == 0xC68))) {
+               writel(translate_val, (u8 *)tran_addr);
+               writel(0xFFFFF000, (u8 *)mask_addr);
+       } else if (addr >= 0x1000) {
+               writel(translate_val, (u8 *)tran_addr);
+       }
+
+       _exit_critical(&pdvobjpriv->io_reg_lock, &irqL);
+
+       return rval;
+}
+
+static void pci_io_write_129x(struct dvobj_priv *pdvobjpriv,
+                             u32 addr, u8 size, u32 wval)
+{
+       unsigned long mask_addr = pdvobjpriv->mask_addr;
+       unsigned long tran_addr = pdvobjpriv->tran_addr;
+       u8 busnumber = pdvobjpriv->pcipriv.busnumber;
+       u32 mask;
+       u32 translate_val = 0;
+       u32 tmp_addr = addr & 0xFFF;
+       _irqL irqL;
+       unsigned long flags;
+
+       _enter_critical(&pdvobjpriv->io_reg_lock, &irqL);
+
+       /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
+        * can't be used because of 1295 hardware issue.
+        */
+       if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
+           (tmp_addr == 0xC68))) {
+               mask = IO_2K_MASK;
+               writel(0xFFFFF800, (u8 *)mask_addr);
+               translate_val = readl((u8 *)tran_addr);
+               writel(translate_val|(addr&mask), (u8 *)tran_addr);
+       } else if (addr >= 0x1000) {
+               mask = IO_4K_MASK;
+               translate_val = readl((u8 *)tran_addr);
+               writel(translate_val|(addr&mask), (u8 *)tran_addr);
+       } else
+               mask = 0x0;
+
+       /* All RBUS1 driver need to have a workaround for emmc hardware error */
+       /* Need to protect 0xXXXX_X8XX~ 0xXXXX_X9XX */
+       if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
+               rtk_lockapi_lock(flags, __func__);
+
+       switch (size) {
+       case 1:
+               writeb((u8)wval,
+                      (u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
+               break;
+       case 2:
+               writew((u16)wval,
+                      (u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
+               break;
+       case 4:
+               writel((u32)wval,
+                      (u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
+               break;
+       default:
+               RTW_WARN("RTD129X: %s: wrong size %d\n", __func__, size);
+               break;
+       }
+
+       if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
+               rtk_lockapi_unlock(flags, __func__);
+
+       /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
+        * can't be used because of 1295 hardware issue.
+        */
+       if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
+           (tmp_addr == 0xC68))) {
+               writel(translate_val, (u8 *)tran_addr);
+               writel(0xFFFFF000, (u8 *)mask_addr);
+       } else if (addr >= 0x1000) {
+               writel(translate_val, (u8 *)tran_addr);
+       }
+
+       _exit_critical(&pdvobjpriv->io_reg_lock, &irqL);
+}
+
+static u8 pci_read8_129x(struct intf_hdl *phdl, u32 addr)
+{
+       struct dvobj_priv  *pdvobjpriv = (struct dvobj_priv  *)phdl->pintf_dev;
+
+       return (u8)pci_io_read_129x(pdvobjpriv, addr, 1);
+}
+
+static u16 pci_read16_129x(struct intf_hdl *phdl, u32 addr)
+{
+       struct dvobj_priv  *pdvobjpriv = (struct dvobj_priv  *)phdl->pintf_dev;
+
+       return (u16)pci_io_read_129x(pdvobjpriv, addr, 2);
+}
+
+static u32 pci_read32_129x(struct intf_hdl *phdl, u32 addr)
+{
+       struct dvobj_priv  *pdvobjpriv = (struct dvobj_priv  *)phdl->pintf_dev;
+
+       return (u32)pci_io_read_129x(pdvobjpriv, addr, 4);
+}
+
+/*
+ * 2009.12.23. by tynli. Suggested by SD1 victorh.
+ * For ASPM hang on AMD and Nvidia.
+ * 20100212 Tynli: Do read IO operation after write for
+ * all PCI bridge suggested by SD1. Origianally this is only for INTEL.
+ */
+static int pci_write8_129x(struct intf_hdl *phdl, u32 addr, u8 val)
+{
+       struct dvobj_priv  *pdvobjpriv = (struct dvobj_priv  *)phdl->pintf_dev;
+
+       pci_io_write_129x(pdvobjpriv, addr, 1, val);
+       return 1;
+}
+
+static int pci_write16_129x(struct intf_hdl *phdl, u32 addr, u16 val)
+{
+       struct dvobj_priv  *pdvobjpriv = (struct dvobj_priv  *)phdl->pintf_dev;
+
+       pci_io_write_129x(pdvobjpriv, addr, 2, val);
+       return 2;
+}
+
+static int pci_write32_129x(struct intf_hdl *phdl, u32 addr, u32 val)
+{
+       struct dvobj_priv  *pdvobjpriv = (struct dvobj_priv  *)phdl->pintf_dev;
+
+       pci_io_write_129x(pdvobjpriv, addr, 4, val);
+       return 4;
+}
+
+#else /* original*/
+
+static u8 pci_read8(struct intf_hdl *phdl, u32 addr)
+{
+       struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
+
+       return 0xff & readb((u8 *)pdvobjpriv->pci_mem_start + addr);
+}
+
+static u16 pci_read16(struct intf_hdl *phdl, u32 addr)
+{
+       struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
+
+       return readw((u8 *)pdvobjpriv->pci_mem_start + addr);
+}
+
+static u32 pci_read32(struct intf_hdl *phdl, u32 addr)
+{
+       struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
+
+       return readl((u8 *)pdvobjpriv->pci_mem_start + addr);
+}
+
+/*
+ * 2009.12.23. by tynli. Suggested by SD1 victorh.
+ * For ASPM hang on AMD and Nvidia.
+ * 20100212 Tynli: Do read IO operation after write for
+ * all PCI bridge suggested by SD1. Origianally this is only for INTEL.
+ */
+static int pci_write8(struct intf_hdl *phdl, u32 addr, u8 val)
+{
+       struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
+
+       writeb(val, (u8 *)pdvobjpriv->pci_mem_start + addr);
+       return 1;
+}
+
+static int pci_write16(struct intf_hdl *phdl, u32 addr, u16 val)
+{
+       struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
+
+       writew(val, (u8 *)pdvobjpriv->pci_mem_start + addr);
+       return 2;
+}
+
+static int pci_write32(struct intf_hdl *phdl, u32 addr, u32 val)
+{
+       struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
+
+       writel(val, (u8 *)pdvobjpriv->pci_mem_start + addr);
+       return 4;
+}
+#endif /* RTK_129X_PLATFORM */
+
+static void pci_read_mem(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *rmem)
+{
+       RTW_INFO("%s(%d)fake function\n", __func__, __LINE__);
+}
+
+static void pci_write_mem(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *wmem)
+{
+       RTW_INFO("%s(%d)fake function\n", __func__, __LINE__);
+}
+
+static u32 pci_read_port(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *rmem)
+{
+       return 0;
+}
+
+static u32 pci_write_port(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *wmem)
+{
+       _adapter *padapter = (_adapter *)phdl->padapter;
+
+       padapter->pnetdev->trans_start = jiffies;
+
+       return 0;
+}
+
+void rtl8822be_set_intf_ops(struct _io_ops *pops)
+{
+       _func_enter_;
+
+       _rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops));
+
+#ifdef RTK_129X_PLATFORM
+       pops->_read8 = &pci_read8_129x;
+       pops->_read16 = &pci_read16_129x;
+       pops->_read32 = &pci_read32_129x;
+#else
+       pops->_read8 = &pci_read8;
+       pops->_read16 = &pci_read16;
+       pops->_read32 = &pci_read32;
+#endif /* RTK_129X_PLATFORM */
+
+       pops->_read_mem = &pci_read_mem;
+       pops->_read_port = &pci_read_port;
+
+#ifdef RTK_129X_PLATFORM
+       pops->_write8 = &pci_write8_129x;
+       pops->_write16 = &pci_write16_129x;
+       pops->_write32 = &pci_write32_129x;
+#else
+       pops->_write8 = &pci_write8;
+       pops->_write16 = &pci_write16;
+       pops->_write32 = &pci_write32;
+#endif /* RTK_129X_PLATFORM */
+
+       pops->_write_mem = &pci_write_mem;
+       pops->_write_port = &pci_write_port;
+
+       _func_exit_;
+
+}