From f45e756958099c35d6afb746df1d40a1c6302cfc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 07 Nov 2023 06:20:23 +0000
Subject: [PATCH] enable wifi gpio
---
kernel/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c | 376 ++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 296 insertions(+), 80 deletions(-)
diff --git a/kernel/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/kernel/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c
index 9c6966f..09a5dc9 100644
--- a/kernel/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c
+++ b/kernel/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
+#include <linux/iopoll.h>
#include <linux/miscdevice.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
@@ -81,7 +82,15 @@
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
#define PCIE_CLIENT_LTSSM_STATUS 0x300
#define PCIE_CLIENT_INTR_MASK 0x24
+#define PCIE_LTSSM_APP_DLY1_EN BIT(0)
+#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
+#define PCIE_LTSSM_APP_DLY1_DONE BIT(2)
+#define PCIE_LTSSM_APP_DLY2_DONE BIT(3)
#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4)
+#define PCIE_CLIENT_MSI_GEN_CON 0x38
+
+#define PCIe_CLIENT_MSI_OBJ_IRQ 0 /* rockchip ep object special irq */
+
#define PCIE_ELBI_REG_NUM 0x2
#define PCIE_ELBI_LOCAL_BASE 0x200e00
@@ -99,6 +108,11 @@
#define PCIE_DBI_SIZE 0x400000
+#define PCIE_EP_OBJ_INFO_DRV_VERSION 0x00000001
+
+#define PCIE_BAR_MAX_NUM 6
+#define PCIE_HOTRESET_TMOUT_US 10000
+
struct rockchip_pcie {
struct dw_pcie pci;
void __iomem *apb_base;
@@ -113,13 +127,17 @@
u32 num_ib_windows;
u32 num_ob_windows;
phys_addr_t *outbound_addr;
- u8 bar_to_atu[6];
- dma_addr_t ib_target_address;
- u32 ib_target_size;
- void *ib_target_base;
+ u8 bar_to_atu[PCIE_BAR_MAX_NUM];
+ dma_addr_t ib_target_address[PCIE_BAR_MAX_NUM];
+ u32 ib_target_size[PCIE_BAR_MAX_NUM];
+ void *ib_target_base[PCIE_BAR_MAX_NUM];
struct dma_trx_obj *dma_obj;
struct fasync_struct *async;
phys_addr_t dbi_base_physical;
+ struct pcie_ep_obj_info *obj_info;
+ enum pcie_ep_mmap_resource cur_mmap_res;
+ struct workqueue_struct *hot_rst_wq;
+ struct work_struct hot_rst_work;
};
struct rockchip_pcie_misc_dev {
@@ -138,6 +156,12 @@
};
MODULE_DEVICE_TABLE(of, rockchip_pcie_ep_of_match);
+
+static void rockchip_pcie_devmode_update(struct rockchip_pcie *rockchip, int mode, int submode)
+{
+ rockchip->obj_info->devmode.mode = mode;
+ rockchip->obj_info->devmode.submode = submode;
+}
static int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip, u32 reg)
{
@@ -186,6 +210,8 @@
struct resource *apb_base;
struct device_node *mem;
struct resource reg;
+ char name[8];
+ int i, idx;
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"pcie-dbi");
@@ -255,22 +281,42 @@
rockchip->outbound_addr = addr;
- mem = of_parse_phandle(np, "memory-region", 0);
- if (!mem) {
- dev_err(dev, "missing \"memory-region\" property\n");
- return -ENODEV;
+ for (i = 0; i < PCIE_BAR_MAX_NUM; i++) {
+ snprintf(name, sizeof(name), "bar%d", i);
+ idx = of_property_match_string(np, "memory-region-names", name);
+ if (idx < 0)
+ continue;
+
+ mem = of_parse_phandle(np, "memory-region", idx);
+ if (!mem) {
+ dev_err(dev, "missing \"memory-region\" %s property\n", name);
+ return -ENODEV;
+ }
+
+ ret = of_address_to_resource(mem, 0, ®);
+ if (ret < 0) {
+ dev_err(dev, "missing \"reg\" %s property\n", name);
+ return -ENODEV;
+ }
+
+ rockchip->ib_target_address[i] = reg.start;
+ rockchip->ib_target_size[i] = resource_size(®);
+ rockchip->ib_target_base[i] = rockchip_pcie_map_kernel(reg.start,
+ resource_size(®));
+ dev_info(dev, "%s: assigned [0x%llx-%llx]\n", name, rockchip->ib_target_address[i],
+ rockchip->ib_target_address[i] + rockchip->ib_target_size[i] - 1);
}
- ret = of_address_to_resource(mem, 0, ®);
- if (ret < 0) {
- dev_err(dev, "missing \"reg\" property\n");
+ if (rockchip->ib_target_size[0]) {
+ rockchip->obj_info = (struct pcie_ep_obj_info *)rockchip->ib_target_base[0];
+ memset_io(rockchip->obj_info, 0, sizeof(struct pcie_ep_obj_info));
+ rockchip->obj_info->magic = PCIE_EP_OBJ_INFO_MAGIC;
+ rockchip->obj_info->version = PCIE_EP_OBJ_INFO_DRV_VERSION;
+ rockchip_pcie_devmode_update(rockchip, RKEP_MODE_KERNEL, RKEP_SMODE_INIT);
+ } else {
+ dev_err(dev, "missing bar0 memory region\n");
return -ENODEV;
}
-
- rockchip->ib_target_address = reg.start;
- rockchip->ib_target_size = resource_size(®);
- rockchip->ib_target_base = rockchip_pcie_map_kernel(reg.start,
- resource_size(®));
return 0;
}
@@ -485,24 +531,27 @@
resbar_base = rockchip_pci_find_resbar_capability(rockchip);
- /* Resize BAR0 4M 32bits, BAR2 64M 64bits-pref */
- bar = 0;
+ /* Resize BAR0 4M 32bits, BAR2 64M 64bits-pref, BAR4 1MB 32bits */
+ bar = BAR_0;
dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0xfffff0);
dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x2c0);
- rockchip_pcie_ep_set_bar_flag(rockchip, BAR_0, PCI_BASE_ADDRESS_MEM_TYPE_32);
+ rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32);
- bar = 2;
+ bar = BAR_2;
dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0xfffff0);
dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x6c0);
- rockchip_pcie_ep_set_bar_flag(rockchip, BAR_2,
+ rockchip_pcie_ep_set_bar_flag(rockchip, bar,
PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64);
- /* Disable BAR1 BAR4 BAR5*/
- bar = 1;
+ bar = BAR_4;
+ dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0xfffff0);
+ dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0);
+ rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32);
+
+ /* Disable BAR1 BAR5*/
+ bar = BAR_1;
dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0);
- bar = 4;
- dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0);
- bar = 5;
+ bar = BAR_5;
dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0);
}
@@ -514,14 +563,13 @@
dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, 0x0580);
}
-static int rockchip_pcie_ep_set_bar(struct rockchip_pcie *rockchip)
+static int rockchip_pcie_ep_set_bar(struct rockchip_pcie *rockchip, enum pci_barno bar,
+ dma_addr_t cpu_addr)
{
int ret;
u32 free_win;
struct dw_pcie *pci = &rockchip->pci;
- enum pci_barno bar;
enum dw_pcie_as_type as_type;
- dma_addr_t cpu_addr;
free_win = find_first_zero_bit(rockchip->ib_window_map,
rockchip->num_ib_windows);
@@ -531,8 +579,6 @@
}
as_type = DW_PCIE_AS_MEM;
- bar = BAR_0;
- cpu_addr = rockchip->ib_target_address;
ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr, as_type);
if (ret < 0) {
@@ -544,7 +590,6 @@
set_bit(free_win, rockchip->ib_window_map);
return 0;
-
}
static void rockchip_pcie_fast_link_setup(struct rockchip_pcie *rockchip)
@@ -553,7 +598,8 @@
/* LTSSM EN ctrl mode */
val = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_HOT_RESET_CTRL);
- val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16);
+ val |= (PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN) |
+ ((PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN) << 16);
rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL);
}
@@ -571,98 +617,117 @@
static void rockchip_pcie_local_elbi_enable(struct rockchip_pcie *rockchip)
{
int i;
- u32 dlbi_reg;
+ u32 elbi_reg;
struct dw_pcie *pci = &rockchip->pci;
for (i = 0; i < PCIE_ELBI_REG_NUM; i++) {
- dlbi_reg = PCIE_ELBI_LOCAL_BASE + PCIE_ELBI_LOCAL_ENABLE_OFF +
+ elbi_reg = PCIE_ELBI_LOCAL_BASE + PCIE_ELBI_LOCAL_ENABLE_OFF +
i * 4;
- dw_pcie_writel_dbi(pci, dlbi_reg, 0xffff0000);
+ dw_pcie_writel_dbi(pci, elbi_reg, 0xffff0000);
}
}
static void rockchip_pcie_elbi_clear(struct rockchip_pcie *rockchip)
{
int i;
- u32 dlbi_reg;
+ u32 elbi_reg;
struct dw_pcie *pci = &rockchip->pci;
u32 val;
for (i = 0; i < PCIE_ELBI_REG_NUM; i++) {
- dlbi_reg = PCIE_ELBI_LOCAL_BASE + i * 4;
- val = dw_pcie_readl_dbi(pci, dlbi_reg);
+ elbi_reg = PCIE_ELBI_LOCAL_BASE + i * 4;
+ val = dw_pcie_readl_dbi(pci, elbi_reg);
val <<= 16;
- dw_pcie_writel_dbi(pci, dlbi_reg, val);
+ dw_pcie_writel_dbi(pci, elbi_reg, val);
}
+}
+
+static void rockchip_pcie_raise_msi_irq(struct rockchip_pcie *rockchip, u8 interrupt_num)
+{
+ rockchip_pcie_writel_apb(rockchip, BIT(interrupt_num), PCIE_CLIENT_MSI_GEN_CON);
}
static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg)
{
struct rockchip_pcie *rockchip = arg;
struct dw_pcie *pci = &rockchip->pci;
- u32 dlbi_reg;
+ u32 elbi_reg;
u32 chn;
- union int_status status;
+ union int_status wr_status, rd_status;
union int_clear clears;
- u32 reg, val;
+ u32 reg, mask;
+ bool sigio = false;
/* ELBI helper, only check the valid bits, and discard the rest interrupts */
- dlbi_reg = dw_pcie_readl_dbi(pci, PCIE_ELBI_LOCAL_BASE + PCIE_ELBI_APP_ELBI_INT_GEN0);
- if (dlbi_reg & PCIE_ELBI_APP_ELBI_INT_GEN0_SIGIO) {
- dev_dbg(rockchip->pci.dev, "SIGIO\n");
- kill_fasync(&rockchip->async, SIGIO, POLL_IN);
+ elbi_reg = dw_pcie_readl_dbi(pci, PCIE_ELBI_LOCAL_BASE + PCIE_ELBI_APP_ELBI_INT_GEN0);
+ if (elbi_reg & PCIE_ELBI_APP_ELBI_INT_GEN0_SIGIO) {
+ sigio = true;
+ rockchip->obj_info->irq_type_ep = OBJ_IRQ_ELBI;
+ rockchip_pcie_elbi_clear(rockchip);
+ goto out;
}
- rockchip_pcie_elbi_clear(rockchip);
-
/* DMA helper */
- status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET +
- PCIE_DMA_WR_INT_STATUS);
+ mask = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_MASK);
+ wr_status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS) & (~mask);
+ mask = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK);
+ rd_status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS) & (~mask);
+
for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) {
- if (status.donesta & BIT(chn)) {
- clears.doneclr = 0x1 << chn;
+ if (wr_status.donesta & BIT(chn)) {
+ clears.doneclr = BIT(chn);
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
if (rockchip->dma_obj && rockchip->dma_obj->cb)
rockchip->dma_obj->cb(rockchip->dma_obj, chn, DMA_TO_BUS);
}
- if (status.abortsta & BIT(chn)) {
+ if (wr_status.abortsta & BIT(chn)) {
dev_err(pci->dev, "%s, abort\n", __func__);
- clears.abortclr = 0x1 << chn;
+ clears.abortclr = BIT(chn);
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
PCIE_DMA_WR_INT_CLEAR, clears.asdword);
}
}
- status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET +
- PCIE_DMA_RD_INT_STATUS);
for (chn = 0; chn < PCIE_DMA_CHANEL_MAX_NUM; chn++) {
- if (status.donesta & BIT(chn)) {
- clears.doneclr = 0x1 << chn;
+ if (rd_status.donesta & BIT(chn)) {
+ clears.doneclr = BIT(chn);
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
if (rockchip->dma_obj && rockchip->dma_obj->cb)
rockchip->dma_obj->cb(rockchip->dma_obj, chn, DMA_FROM_BUS);
}
- if (status.abortsta & BIT(chn)) {
+ if (rd_status.abortsta & BIT(chn)) {
dev_err(pci->dev, "%s, abort\n", __func__);
- clears.abortclr = 0x1 << chn;
+ clears.abortclr = BIT(chn);
dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
PCIE_DMA_RD_INT_CLEAR, clears.asdword);
}
}
- reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC);
- if (reg & BIT(2)) {
- /* Setup command register */
- val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
- val &= 0xffff0000;
- val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
- dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
+ if (wr_status.asdword || rd_status.asdword) {
+ rockchip->obj_info->irq_type_rc = OBJ_IRQ_DMA;
+ rockchip->obj_info->dma_status_rc.wr |= wr_status.asdword;
+ rockchip->obj_info->dma_status_rc.rd |= rd_status.asdword;
+ rockchip_pcie_raise_msi_irq(rockchip, PCIe_CLIENT_MSI_OBJ_IRQ);
+
+ rockchip->obj_info->irq_type_ep = OBJ_IRQ_DMA;
+ rockchip->obj_info->dma_status_ep.wr |= wr_status.asdword;
+ rockchip->obj_info->dma_status_ep.rd |= rd_status.asdword;
+ sigio = true;
}
+
+out:
+ if (sigio) {
+ dev_dbg(rockchip->pci.dev, "SIGIO\n");
+ kill_fasync(&rockchip->async, SIGIO, POLL_IN);
+ }
+
+ reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC);
+ if (reg & BIT(2))
+ queue_work(rockchip->hot_rst_wq, &rockchip->hot_rst_work);
rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC);
@@ -706,7 +771,7 @@
if (!rockchip_pcie_udma_enabled(rockchip))
return 0;
- rockchip->dma_obj = pcie_dw_dmatest_register(pci, true);
+ rockchip->dma_obj = pcie_dw_dmatest_register(pci->dev, true);
if (IS_ERR(rockchip->dma_obj)) {
dev_err(rockchip->pci.dev, "failed to prepare dmatest\n");
return -EINVAL;
@@ -812,6 +877,73 @@
table->start.chnl = table->chn;
}
+static void rockchip_pcie_hot_rst_work(struct work_struct *work)
+{
+ struct rockchip_pcie *rockchip = container_of(work, struct rockchip_pcie, hot_rst_work);
+ u32 status;
+ int ret;
+
+ if (rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_HOT_RESET_CTRL) & PCIE_LTSSM_APP_DLY2_EN) {
+ ret = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_LTSSM_STATUS,
+ status, ((status & 0x3F) == 0), 100, PCIE_HOTRESET_TMOUT_US);
+ if (ret)
+ dev_err(rockchip->pci.dev, "wait for detect quiet failed!\n");
+
+ rockchip_pcie_writel_apb(rockchip, (PCIE_LTSSM_APP_DLY2_DONE) | ((PCIE_LTSSM_APP_DLY2_DONE) << 16),
+ PCIE_CLIENT_HOT_RESET_CTRL);
+ }
+}
+
+static int rockchip_pcie_get_dma_status(struct dma_trx_obj *obj, u8 chn, enum dma_dir dir)
+{
+ struct rockchip_pcie *rockchip = dev_get_drvdata(obj->dev);
+ struct dw_pcie *pci = &rockchip->pci;
+ union int_status status;
+ union int_clear clears;
+ int ret = 0;
+
+ dev_dbg(pci->dev, "%s %x %x\n", __func__,
+ dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS),
+ dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS));
+
+ if (dir == DMA_TO_BUS) {
+ status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_WR_INT_STATUS);
+ if (status.donesta & BIT(chn)) {
+ clears.doneclr = BIT(chn);
+ dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
+ PCIE_DMA_WR_INT_CLEAR, clears.asdword);
+ ret = 1;
+ }
+
+ if (status.abortsta & BIT(chn)) {
+ dev_err(pci->dev, "%s, write abort\n", __func__);
+ clears.abortclr = BIT(chn);
+ dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
+ PCIE_DMA_WR_INT_CLEAR, clears.asdword);
+ ret = -1;
+ }
+ } else {
+ status.asdword = dw_pcie_readl_dbi(pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_STATUS);
+
+ if (status.donesta & BIT(chn)) {
+ clears.doneclr = BIT(chn);
+ dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
+ PCIE_DMA_RD_INT_CLEAR, clears.asdword);
+ ret = 1;
+ }
+
+ if (status.abortsta & BIT(chn)) {
+ dev_err(pci->dev, "%s, read abort %x\n", __func__, status.asdword);
+ clears.abortclr = BIT(chn);
+ dw_pcie_writel_dbi(pci, PCIE_DMA_OFFSET +
+ PCIE_DMA_RD_INT_CLEAR, clears.asdword);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = rockchip_pcie_start_link,
.link_up = rockchip_pcie_link_up,
@@ -847,6 +979,7 @@
struct pcie_ep_dma_cache_cfg cfg;
void __user *uarg = (void __user *)arg;
int i, ret;
+ enum pcie_ep_mmap_resource mmap_res;
switch (cmd) {
case PCIE_DMA_GET_ELBI_DATA:
@@ -885,6 +1018,33 @@
dw_pcie_writel_dbi(&rockchip->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK,
0xffffffff);
break;
+ case PCIE_DMA_RAISE_MSI_OBJ_IRQ_USER:
+ rockchip->obj_info->irq_type_rc = OBJ_IRQ_USER;
+ rockchip_pcie_raise_msi_irq(rockchip, PCIe_CLIENT_MSI_OBJ_IRQ);
+ break;
+ case PCIE_EP_GET_USER_INFO:
+ msg.bar0_phys_addr = rockchip->ib_target_address[0];
+
+ ret = copy_to_user(uarg, &msg, sizeof(msg));
+ if (ret) {
+ dev_err(rockchip->pci.dev, "failed to get elbi data\n");
+ return -EFAULT;
+ }
+ break;
+ case PCIE_EP_SET_MMAP_RESOURCE:
+ ret = copy_from_user(&mmap_res, uarg, sizeof(mmap_res));
+ if (ret) {
+ dev_err(rockchip->pci.dev, "failed to get copy from\n");
+ return -EFAULT;
+ }
+
+ if (mmap_res >= PCIE_EP_MMAP_RESOURCE_MAX) {
+ dev_err(rockchip->pci.dev, "mmap index %d is out of number\n", mmap_res);
+ return -EINVAL;
+ }
+
+ rockchip->cur_mmap_res = mmap_res;
+ break;
default:
break;
}
@@ -896,18 +1056,45 @@
struct rockchip_pcie *rockchip = (struct rockchip_pcie *)file->private_data;
size_t size = vma->vm_end - vma->vm_start;
int err;
+ unsigned long addr;
- if (size > PCIE_DBI_SIZE) {
- dev_warn(rockchip->pci.dev, "mmap size is out of limitation\n");
+ switch (rockchip->cur_mmap_res) {
+ case PCIE_EP_MMAP_RESOURCE_DBI:
+ if (size > PCIE_DBI_SIZE) {
+ dev_warn(rockchip->pci.dev, "dbi mmap size is out of limitation\n");
+ return -EINVAL;
+ }
+ addr = rockchip->dbi_base_physical;
+ break;
+ case PCIE_EP_MMAP_RESOURCE_BAR0:
+ if (size > rockchip->ib_target_size[0]) {
+ dev_warn(rockchip->pci.dev, "bar0 mmap size is out of limitation\n");
+ return -EINVAL;
+ }
+ addr = rockchip->ib_target_address[0];
+ break;
+ case PCIE_EP_MMAP_RESOURCE_BAR2:
+ if (size > rockchip->ib_target_size[2]) {
+ dev_warn(rockchip->pci.dev, "bar2 mmap size is out of limitation\n");
+ return -EINVAL;
+ }
+ addr = rockchip->ib_target_address[2];
+ break;
+ default:
+ dev_err(rockchip->pci.dev, "cur mmap_res %d is unsurreport\n", rockchip->cur_mmap_res);
return -EINVAL;
}
vma->vm_flags |= VM_IO;
vma->vm_flags |= (VM_DONTEXPAND | VM_DONTDUMP);
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (rockchip->cur_mmap_res == PCIE_EP_MMAP_RESOURCE_BAR2)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
err = remap_pfn_range(vma, vma->vm_start,
- __phys_to_pfn(rockchip->dbi_base_physical),
+ __phys_to_pfn(addr),
size, vma->vm_page_prot);
if (err)
return -EAGAIN;
@@ -941,13 +1128,13 @@
ret = misc_register(&pcie_dev->dev);
if (ret) {
- pr_err("pcie: failed to register misc device.\n");
+ dev_err(rockchip->pci.dev, "pcie: failed to register misc device.\n");
return ret;
}
pcie_dev->pcie = rockchip;
- pr_info("register misc device pcie-dev\n");
+ dev_info(rockchip->pci.dev, "register misc device pcie_ep\n");
return 0;
}
@@ -957,7 +1144,8 @@
struct device *dev = &pdev->dev;
struct rockchip_pcie *rockchip;
int ret;
- int retry;
+ int retry, i;
+ u32 reg;
rockchip = devm_kzalloc(dev, sizeof(*rockchip), GFP_KERNEL);
if (!rockchip)
@@ -993,8 +1181,10 @@
goto disable_regulator;
if (dw_pcie_link_up(&rockchip->pci)) {
- pr_info("%s, %d, already linkup\n", __func__, __LINE__);
+ dev_info(dev, "already linkup\n");
goto already_linkup;
+ } else {
+ dev_info(dev, "initial\n");
}
ret = rockchip_pcie_phy_init(rockchip);
@@ -1015,6 +1205,27 @@
rockchip_pcie_fast_link_setup(rockchip);
rockchip_pcie_start_link(&rockchip->pci);
+ rockchip_pcie_devmode_update(rockchip, RKEP_MODE_KERNEL, RKEP_SMODE_LNKRDY);
+
+ rockchip->hot_rst_wq = create_singlethread_workqueue("rkep_hot_rst_wq");
+ if (!rockchip->hot_rst_wq) {
+ dev_err(dev, "failed to create hot_rst workqueue\n");
+ ret = -ENOMEM;
+ goto deinit_phy;
+ }
+ INIT_WORK(&rockchip->hot_rst_work, rockchip_pcie_hot_rst_work);
+
+ reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC);
+ if ((reg & BIT(2)) &&
+ (rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_HOT_RESET_CTRL) & PCIE_LTSSM_APP_DLY2_EN)) {
+ rockchip_pcie_writel_apb(rockchip, PCIE_LTSSM_APP_DLY2_DONE | (PCIE_LTSSM_APP_DLY2_DONE << 16),
+ PCIE_CLIENT_HOT_RESET_CTRL);
+ dev_info(dev, "hot reset ever\n");
+ }
+ rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC);
+
+ /* Enable client reset or link down interrupt */
+ rockchip_pcie_writel_apb(rockchip, 0x40000, PCIE_CLIENT_INTR_MASK);
for (retry = 0; retry < 10000; retry++) {
if (dw_pcie_link_up(&rockchip->pci)) {
@@ -1042,8 +1253,11 @@
}
already_linkup:
+ rockchip_pcie_devmode_update(rockchip, RKEP_MODE_KERNEL, RKEP_SMODE_LNKUP);
rockchip->pci.iatu_unroll_enabled = rockchip_pcie_iatu_unroll_enabled(&rockchip->pci);
- rockchip_pcie_ep_set_bar(rockchip);
+ for (i = 0; i < PCIE_BAR_MAX_NUM; i++)
+ if (rockchip->ib_target_size[i])
+ rockchip_pcie_ep_set_bar(rockchip, i, rockchip->ib_target_address[i]);
ret = rockchip_pcie_init_dma_trx(rockchip);
if (ret) {
@@ -1054,6 +1268,7 @@
if (rockchip->dma_obj) {
rockchip->dma_obj->start_dma_func = rockchip_pcie_start_dma_dwc;
rockchip->dma_obj->config_dma_func = rockchip_pcie_config_dma_dwc;
+ rockchip->dma_obj->get_dma_status = rockchip_pcie_get_dma_status;
}
/* Enable client ELBI interrupt */
@@ -1086,9 +1301,10 @@
.of_match_table = rockchip_pcie_ep_of_match,
.suppress_bind_attrs = true,
},
+ .probe = rockchip_pcie_ep_probe,
};
-module_platform_driver_probe(rk_plat_pcie_driver, rockchip_pcie_ep_probe);
+module_platform_driver(rk_plat_pcie_driver);
MODULE_AUTHOR("Simon Xue <xxm@rock-chips.com>");
MODULE_DESCRIPTION("RockChip PCIe Controller EP driver");
--
Gitblit v1.6.2