From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 06 Nov 2023 03:04:41 +0000 Subject: [PATCH] rk3568 rt init --- 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