.. | .. |
---|
10 | 10 | |
---|
11 | 11 | #include <linux/clk.h> |
---|
12 | 12 | #include <linux/gpio/consumer.h> |
---|
13 | | -#include <linux/iopoll.h> |
---|
14 | 13 | #include <linux/miscdevice.h> |
---|
15 | 14 | #include <linux/mfd/syscon.h> |
---|
16 | 15 | #include <linux/module.h> |
---|
.. | .. |
---|
95 | 94 | #define PCIE_ELBI_LOCAL_BASE 0x200e00 |
---|
96 | 95 | |
---|
97 | 96 | #define PCIE_ELBI_APP_ELBI_INT_GEN0 0x0 |
---|
98 | | -#define PCIE_ELBI_APP_ELBI_INT_GEN0_SIGIO BIT(0) |
---|
| 97 | +#define PCIE_ELBI_APP_ELBI_INT_GEN0_IRQ_USER BIT(0) |
---|
99 | 98 | |
---|
100 | 99 | #define PCIE_ELBI_APP_ELBI_INT_GEN1 0x4 |
---|
101 | 100 | |
---|
102 | 101 | #define PCIE_ELBI_LOCAL_ENABLE_OFF 0x8 |
---|
| 102 | + |
---|
| 103 | +#define PCIE_ELBI_USER_DATA_OFF 0x10 |
---|
103 | 104 | |
---|
104 | 105 | #define PCIE_DIRECT_SPEED_CHANGE BIT(17) |
---|
105 | 106 | |
---|
.. | .. |
---|
132 | 133 | u32 ib_target_size[PCIE_BAR_MAX_NUM]; |
---|
133 | 134 | void *ib_target_base[PCIE_BAR_MAX_NUM]; |
---|
134 | 135 | struct dma_trx_obj *dma_obj; |
---|
135 | | - struct fasync_struct *async; |
---|
136 | 136 | phys_addr_t dbi_base_physical; |
---|
137 | 137 | struct pcie_ep_obj_info *obj_info; |
---|
138 | 138 | enum pcie_ep_mmap_resource cur_mmap_res; |
---|
139 | 139 | struct workqueue_struct *hot_rst_wq; |
---|
140 | 140 | struct work_struct hot_rst_work; |
---|
| 141 | + struct mutex file_mutex; |
---|
| 142 | + DECLARE_BITMAP(virtual_id_irq_bitmap, RKEP_EP_VIRTUAL_ID_MAX); |
---|
| 143 | + wait_queue_head_t wq_head; |
---|
141 | 144 | }; |
---|
142 | 145 | |
---|
143 | 146 | struct rockchip_pcie_misc_dev { |
---|
.. | .. |
---|
207 | 210 | struct device_node *np = dev->of_node; |
---|
208 | 211 | void *addr; |
---|
209 | 212 | struct resource *dbi_base; |
---|
210 | | - struct resource *apb_base; |
---|
211 | 213 | struct device_node *mem; |
---|
212 | 214 | struct resource reg; |
---|
213 | 215 | char name[8]; |
---|
.. | .. |
---|
223 | 225 | rockchip->pci.dbi_base = devm_ioremap_resource(dev, dbi_base); |
---|
224 | 226 | if (IS_ERR(rockchip->pci.dbi_base)) |
---|
225 | 227 | return PTR_ERR(rockchip->pci.dbi_base); |
---|
| 228 | + rockchip->pci.atu_base = rockchip->pci.dbi_base + DEFAULT_DBI_ATU_OFFSET; |
---|
226 | 229 | rockchip->dbi_base_physical = dbi_base->start; |
---|
227 | 230 | |
---|
228 | | - apb_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
---|
229 | | - "pcie-apb"); |
---|
230 | | - if (!apb_base) { |
---|
| 231 | + rockchip->apb_base = devm_platform_ioremap_resource_byname(pdev, "pcie-apb"); |
---|
| 232 | + if (!rockchip->apb_base) { |
---|
231 | 233 | dev_err(dev, "get pcie-apb failed\n"); |
---|
232 | 234 | return -ENODEV; |
---|
233 | 235 | } |
---|
234 | | - rockchip->apb_base = devm_ioremap_resource(dev, apb_base); |
---|
235 | | - if (IS_ERR(rockchip->apb_base)) |
---|
236 | | - return PTR_ERR(rockchip->apb_base); |
---|
237 | 236 | |
---|
238 | 237 | rockchip->rst_gpio = devm_gpiod_get_optional(dev, "reset", |
---|
239 | 238 | GPIOD_OUT_HIGH); |
---|
.. | .. |
---|
533 | 532 | |
---|
534 | 533 | /* Resize BAR0 4M 32bits, BAR2 64M 64bits-pref, BAR4 1MB 32bits */ |
---|
535 | 534 | bar = BAR_0; |
---|
536 | | - dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0xfffff0); |
---|
| 535 | + dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x40); |
---|
537 | 536 | dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x2c0); |
---|
538 | 537 | rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); |
---|
539 | 538 | |
---|
540 | 539 | bar = BAR_2; |
---|
541 | | - dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0xfffff0); |
---|
| 540 | + dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x400); |
---|
542 | 541 | dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x6c0); |
---|
543 | 542 | rockchip_pcie_ep_set_bar_flag(rockchip, bar, |
---|
544 | 543 | PCI_BASE_ADDRESS_MEM_PREFETCH | PCI_BASE_ADDRESS_MEM_TYPE_64); |
---|
545 | 544 | |
---|
546 | 545 | bar = BAR_4; |
---|
547 | | - dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0xfffff0); |
---|
| 546 | + dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x10); |
---|
548 | 547 | dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0); |
---|
549 | 548 | rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); |
---|
550 | 549 | |
---|
.. | .. |
---|
580 | 579 | |
---|
581 | 580 | as_type = DW_PCIE_AS_MEM; |
---|
582 | 581 | |
---|
583 | | - ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr, as_type); |
---|
| 582 | + ret = dw_pcie_prog_inbound_atu(pci, 0, free_win, bar, cpu_addr, as_type); |
---|
584 | 583 | if (ret < 0) { |
---|
585 | 584 | dev_err(pci->dev, "Failed to program IB window\n"); |
---|
586 | 585 | return ret; |
---|
.. | .. |
---|
647 | 646 | rockchip_pcie_writel_apb(rockchip, BIT(interrupt_num), PCIE_CLIENT_MSI_GEN_CON); |
---|
648 | 647 | } |
---|
649 | 648 | |
---|
| 649 | +static int rockchip_pcie_raise_irq_user(struct rockchip_pcie *rockchip, u32 index) |
---|
| 650 | +{ |
---|
| 651 | + if (index >= RKEP_EP_VIRTUAL_ID_MAX) { |
---|
| 652 | + dev_err(rockchip->pci.dev, "raise irq_user, virtual id %d out of range\n", index); |
---|
| 653 | + |
---|
| 654 | + return -EINVAL; |
---|
| 655 | + } |
---|
| 656 | + |
---|
| 657 | + mutex_lock(&rockchip->file_mutex); |
---|
| 658 | + rockchip->obj_info->irq_type_rc = OBJ_IRQ_USER; |
---|
| 659 | + rockchip->obj_info->irq_user_data_rc = index; |
---|
| 660 | + rockchip_pcie_raise_msi_irq(rockchip, PCIe_CLIENT_MSI_OBJ_IRQ); |
---|
| 661 | + mutex_unlock(&rockchip->file_mutex); |
---|
| 662 | + |
---|
| 663 | + return 0; |
---|
| 664 | +} |
---|
| 665 | + |
---|
| 666 | +static int rockchip_pcie_poll_irq_user(struct rockchip_pcie *rockchip, struct pcie_ep_obj_poll_virtual_id_cfg *cfg) |
---|
| 667 | +{ |
---|
| 668 | + u32 index = cfg->virtual_id; |
---|
| 669 | + |
---|
| 670 | + if (index >= RKEP_EP_VIRTUAL_ID_MAX) { |
---|
| 671 | + dev_err(rockchip->pci.dev, "poll irq_user, virtual id %d out of range\n", index); |
---|
| 672 | + |
---|
| 673 | + return -EINVAL; |
---|
| 674 | + } |
---|
| 675 | + |
---|
| 676 | + cfg->poll_status = NSIGPOLL; |
---|
| 677 | + if (cfg->sync) |
---|
| 678 | + wait_event_interruptible(rockchip->wq_head, |
---|
| 679 | + test_bit(index, rockchip->virtual_id_irq_bitmap)); |
---|
| 680 | + else |
---|
| 681 | + wait_event_interruptible_timeout(rockchip->wq_head, |
---|
| 682 | + test_bit(index, rockchip->virtual_id_irq_bitmap), |
---|
| 683 | + cfg->timeout_ms); |
---|
| 684 | + if (test_and_clear_bit(index, rockchip->virtual_id_irq_bitmap)) |
---|
| 685 | + cfg->poll_status = POLL_IN; |
---|
| 686 | + |
---|
| 687 | + dev_dbg(rockchip->pci.dev, "poll virtual id %d, ret=%d\n", index, cfg->poll_status); |
---|
| 688 | + |
---|
| 689 | + return 0; |
---|
| 690 | +} |
---|
| 691 | + |
---|
650 | 692 | static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg) |
---|
651 | 693 | { |
---|
652 | 694 | struct rockchip_pcie *rockchip = arg; |
---|
.. | .. |
---|
656 | 698 | union int_status wr_status, rd_status; |
---|
657 | 699 | union int_clear clears; |
---|
658 | 700 | u32 reg, mask; |
---|
659 | | - bool sigio = false; |
---|
660 | 701 | |
---|
661 | 702 | /* ELBI helper, only check the valid bits, and discard the rest interrupts */ |
---|
662 | 703 | elbi_reg = dw_pcie_readl_dbi(pci, PCIE_ELBI_LOCAL_BASE + PCIE_ELBI_APP_ELBI_INT_GEN0); |
---|
663 | | - if (elbi_reg & PCIE_ELBI_APP_ELBI_INT_GEN0_SIGIO) { |
---|
664 | | - sigio = true; |
---|
665 | | - rockchip->obj_info->irq_type_ep = OBJ_IRQ_ELBI; |
---|
| 704 | + if (elbi_reg & PCIE_ELBI_APP_ELBI_INT_GEN0_IRQ_USER) { |
---|
666 | 705 | rockchip_pcie_elbi_clear(rockchip); |
---|
| 706 | + |
---|
| 707 | + if (rockchip->obj_info->irq_type_ep == OBJ_IRQ_USER) { |
---|
| 708 | + reg = rockchip->obj_info->irq_user_data_ep; |
---|
| 709 | + if (reg < RKEP_EP_VIRTUAL_ID_MAX) { |
---|
| 710 | + set_bit(reg, rockchip->virtual_id_irq_bitmap); |
---|
| 711 | + wake_up_interruptible(&rockchip->wq_head); |
---|
| 712 | + } |
---|
| 713 | + } |
---|
667 | 714 | goto out; |
---|
668 | 715 | } |
---|
669 | 716 | |
---|
.. | .. |
---|
716 | 763 | rockchip->obj_info->irq_type_ep = OBJ_IRQ_DMA; |
---|
717 | 764 | rockchip->obj_info->dma_status_ep.wr |= wr_status.asdword; |
---|
718 | 765 | rockchip->obj_info->dma_status_ep.rd |= rd_status.asdword; |
---|
719 | | - sigio = true; |
---|
720 | 766 | } |
---|
721 | 767 | |
---|
722 | 768 | out: |
---|
723 | | - if (sigio) { |
---|
724 | | - dev_dbg(rockchip->pci.dev, "SIGIO\n"); |
---|
725 | | - kill_fasync(&rockchip->async, SIGIO, POLL_IN); |
---|
726 | | - } |
---|
727 | | - |
---|
728 | 769 | reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); |
---|
729 | 770 | if (reg & BIT(2)) |
---|
730 | 771 | queue_work(rockchip->hot_rst_wq, &rockchip->hot_rst_work); |
---|
.. | .. |
---|
949 | 990 | .link_up = rockchip_pcie_link_up, |
---|
950 | 991 | }; |
---|
951 | 992 | |
---|
952 | | -static int pcie_ep_fasync(int fd, struct file *file, int mode) |
---|
953 | | -{ |
---|
954 | | - struct rockchip_pcie *rockchip = (struct rockchip_pcie *)file->private_data; |
---|
955 | | - |
---|
956 | | - return fasync_helper(fd, file, mode, &rockchip->async); |
---|
957 | | -} |
---|
958 | | - |
---|
959 | 993 | static int pcie_ep_open(struct inode *inode, struct file *file) |
---|
960 | 994 | { |
---|
961 | 995 | struct miscdevice *miscdev = file->private_data; |
---|
.. | .. |
---|
967 | 1001 | return 0; |
---|
968 | 1002 | } |
---|
969 | 1003 | |
---|
970 | | -static int pcie_ep_release(struct inode *inode, struct file *file) |
---|
971 | | -{ |
---|
972 | | - return pcie_ep_fasync(-1, file, 0); |
---|
973 | | -} |
---|
974 | | - |
---|
975 | 1004 | static long pcie_ep_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
---|
976 | 1005 | { |
---|
977 | 1006 | struct rockchip_pcie *rockchip = (struct rockchip_pcie *)file->private_data; |
---|
978 | | - struct pcie_ep_user_data msg; |
---|
979 | 1007 | struct pcie_ep_dma_cache_cfg cfg; |
---|
980 | 1008 | void __user *uarg = (void __user *)arg; |
---|
981 | | - int i, ret; |
---|
| 1009 | + struct pcie_ep_obj_poll_virtual_id_cfg poll_cfg; |
---|
982 | 1010 | enum pcie_ep_mmap_resource mmap_res; |
---|
| 1011 | + int ret, index; |
---|
983 | 1012 | |
---|
984 | 1013 | switch (cmd) { |
---|
985 | | - case PCIE_DMA_GET_ELBI_DATA: |
---|
986 | | - for (i = 4; i <= 6; i++) |
---|
987 | | - msg.elbi_app_user[i - 4] = dw_pcie_readl_dbi(&rockchip->pci, |
---|
988 | | - PCIE_ELBI_LOCAL_BASE + i * 4); |
---|
989 | | - for (i = 8; i <= 15; i++) |
---|
990 | | - msg.elbi_app_user[i - 5] = dw_pcie_readl_dbi(&rockchip->pci, |
---|
991 | | - PCIE_ELBI_LOCAL_BASE + i * 4); |
---|
992 | | - |
---|
993 | | - ret = copy_to_user(uarg, &msg, sizeof(msg)); |
---|
994 | | - if (ret) { |
---|
995 | | - dev_err(rockchip->pci.dev, "failed to get elbi data\n"); |
---|
996 | | - return -EFAULT; |
---|
997 | | - } |
---|
998 | | - break; |
---|
999 | 1014 | case PCIE_DMA_CACHE_INVALIDE: |
---|
1000 | 1015 | ret = copy_from_user(&cfg, uarg, sizeof(cfg)); |
---|
1001 | 1016 | if (ret) { |
---|
.. | .. |
---|
1018 | 1033 | dw_pcie_writel_dbi(&rockchip->pci, PCIE_DMA_OFFSET + PCIE_DMA_RD_INT_MASK, |
---|
1019 | 1034 | 0xffffffff); |
---|
1020 | 1035 | break; |
---|
1021 | | - case PCIE_DMA_RAISE_MSI_OBJ_IRQ_USER: |
---|
1022 | | - rockchip->obj_info->irq_type_rc = OBJ_IRQ_USER; |
---|
| 1036 | + case PCIE_EP_RAISE_MSI: |
---|
1023 | 1037 | rockchip_pcie_raise_msi_irq(rockchip, PCIe_CLIENT_MSI_OBJ_IRQ); |
---|
1024 | | - break; |
---|
1025 | | - case PCIE_EP_GET_USER_INFO: |
---|
1026 | | - msg.bar0_phys_addr = rockchip->ib_target_address[0]; |
---|
1027 | | - |
---|
1028 | | - ret = copy_to_user(uarg, &msg, sizeof(msg)); |
---|
1029 | | - if (ret) { |
---|
1030 | | - dev_err(rockchip->pci.dev, "failed to get elbi data\n"); |
---|
1031 | | - return -EFAULT; |
---|
1032 | | - } |
---|
1033 | 1038 | break; |
---|
1034 | 1039 | case PCIE_EP_SET_MMAP_RESOURCE: |
---|
1035 | 1040 | ret = copy_from_user(&mmap_res, uarg, sizeof(mmap_res)); |
---|
.. | .. |
---|
1044 | 1049 | } |
---|
1045 | 1050 | |
---|
1046 | 1051 | rockchip->cur_mmap_res = mmap_res; |
---|
| 1052 | + break; |
---|
| 1053 | + case PCIE_EP_RAISE_IRQ_USER: |
---|
| 1054 | + ret = copy_from_user(&index, uarg, sizeof(index)); |
---|
| 1055 | + if (ret) { |
---|
| 1056 | + dev_err(rockchip->pci.dev, |
---|
| 1057 | + "failed to get raise irq data copy from userspace\n"); |
---|
| 1058 | + return -EFAULT; |
---|
| 1059 | + } |
---|
| 1060 | + |
---|
| 1061 | + ret = rockchip_pcie_raise_irq_user(rockchip, index); |
---|
| 1062 | + if (ret < 0) |
---|
| 1063 | + return -EFAULT; |
---|
| 1064 | + break; |
---|
| 1065 | + case PCIE_EP_POLL_IRQ_USER: |
---|
| 1066 | + ret = copy_from_user(&poll_cfg, uarg, sizeof(poll_cfg)); |
---|
| 1067 | + if (ret) { |
---|
| 1068 | + dev_err(rockchip->pci.dev, |
---|
| 1069 | + "failed to get poll irq data copy from userspace\n"); |
---|
| 1070 | + |
---|
| 1071 | + return -EFAULT; |
---|
| 1072 | + } |
---|
| 1073 | + |
---|
| 1074 | + ret = rockchip_pcie_poll_irq_user(rockchip, &poll_cfg); |
---|
| 1075 | + if (ret < 0) |
---|
| 1076 | + return -EFAULT; |
---|
| 1077 | + |
---|
| 1078 | + if (copy_to_user(uarg, &poll_cfg, sizeof(poll_cfg))) |
---|
| 1079 | + return -EFAULT; |
---|
1047 | 1080 | break; |
---|
1048 | 1081 | default: |
---|
1049 | 1082 | break; |
---|
.. | .. |
---|
1105 | 1138 | static const struct file_operations pcie_ep_ops = { |
---|
1106 | 1139 | .owner = THIS_MODULE, |
---|
1107 | 1140 | .open = pcie_ep_open, |
---|
1108 | | - .release = pcie_ep_release, |
---|
1109 | 1141 | .unlocked_ioctl = pcie_ep_ioctl, |
---|
1110 | | - .fasync = pcie_ep_fasync, |
---|
1111 | 1142 | .mmap = pcie_ep_mmap, |
---|
1112 | 1143 | }; |
---|
1113 | 1144 | |
---|
.. | .. |
---|
1270 | 1301 | rockchip->dma_obj->config_dma_func = rockchip_pcie_config_dma_dwc; |
---|
1271 | 1302 | rockchip->dma_obj->get_dma_status = rockchip_pcie_get_dma_status; |
---|
1272 | 1303 | } |
---|
| 1304 | + mutex_init(&rockchip->file_mutex); |
---|
1273 | 1305 | |
---|
1274 | 1306 | /* Enable client ELBI interrupt */ |
---|
1275 | 1307 | rockchip_pcie_writel_apb(rockchip, 0x80000000, PCIE_CLIENT_INTR_MASK); |
---|
1276 | 1308 | /* Enable ELBI interrupt */ |
---|
1277 | 1309 | rockchip_pcie_local_elbi_enable(rockchip); |
---|
1278 | 1310 | |
---|
| 1311 | + init_waitqueue_head(&rockchip->wq_head); |
---|
1279 | 1312 | ret = rockchip_pcie_request_sys_irq(rockchip, pdev); |
---|
1280 | 1313 | if (ret) |
---|
1281 | 1314 | goto deinit_phy; |
---|