├── 50-xtrx.rules ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── debian ├── postinst └── prerm ├── dkms.conf ├── xtrx.c ├── xtrx_defs.h └── xtrxll_regs.vh /50-xtrx.rules: -------------------------------------------------------------------------------- 1 | KERNEL=="xtrx*", SUBSYSTEM=="xtrx", MODE="0666" -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(xtrx-pcie-linux-driver NONE) 3 | 4 | # Set the version information here 5 | set(MAJOR_VERSION 0) 6 | set(API_COMPAT 0) 7 | set(MINOR_VERSION 1) 8 | set(MAINT_VERSION 2) 9 | 10 | set(LIBVER "${MAJOR_VERSION}.${API_COMPAT}.${MINOR_VERSION}") 11 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all") 12 | 13 | ######################################################################## 14 | # package generator 15 | ######################################################################## 16 | if(NOT CPACK_GENERATOR) 17 | set(CPACK_GENERATOR DEB) 18 | endif() 19 | set(CPACK_PACKAGE_NAME "xtrx-pcie-linux-driver") 20 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "XTRX PCIe kernel dkms driver") 21 | set(CPACK_PACKAGE_VENDOR "Fairwaves, Inc.") 22 | set(CPACK_PACKAGE_CONTACT "http://fairwaves.co/wp/contact-us/") 23 | set(CPACK_PACKAGE_VERSION ${LIBVER}-${MAINT_VERSION}) 24 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "linux-headers-generic (>= 4.4.0), dkms") 25 | 26 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") 27 | set(CPACK_SET_DESTDIR "") 28 | set(CPACK_PACKAGING_INSTALL_PREFIX "/usr") 29 | set(CPACK_PACKAGE_CONTACT "Sergey Kostanbaev ") 30 | 31 | ######################################################################### 32 | # DKMS intallation 33 | ######################################################################### 34 | set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/debian/postinst;${CMAKE_CURRENT_SOURCE_DIR}/debian/prerm;" ) 35 | 36 | set(DKMSVER "${LIBVER}-${MAINT_VERSION}") 37 | install(FILES Makefile dkms.conf xtrx.c xtrx_defs.h DESTINATION "src/xtrx-${DKMSVER}" COMPONENT xtrx-drv) 38 | install(FILES xtrxll_regs.vh DESTINATION "src/xtrx-${DKMSVER}" COMPONENT xtrx-drv) 39 | 40 | ######################################################################## 41 | # Install udev rules 42 | ######################################################################## 43 | option(INSTALL_UDEV_RULES "Install udev rules for xtrx-drv" OFF) 44 | if (INSTALL_UDEV_RULES) 45 | set(UDEV_RULES_PATH 46 | "/etc/udev/rules.d" 47 | CACHE STRING 48 | "Target directory for udev rule installation. Ensure you have permissions to write to this directory." 49 | ) 50 | install ( 51 | FILES 50-xtrx.rules 52 | DESTINATION ${UDEV_RULES_PATH} 53 | COMPONENT "xtrx-drv" 54 | ) 55 | else (INSTALL_UDEV_RULES) 56 | message (STATUS "Udev rules not being installed, install them with -DINSTALL_UDEV_RULES=ON") 57 | endif (INSTALL_UDEV_RULES) 58 | 59 | include(CPack) #include last 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | 3 | obj-m += xtrx.o 4 | 5 | else 6 | 7 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 8 | 9 | modules modules_install clean:: 10 | make -C $(KERNELDIR) M=$(PWD) $@ 11 | 12 | clean:: 13 | rm -f *.o Module.markers modules.order 14 | 15 | endif 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xtrx_linux_pcie_drv 2 | XTRX PCI driver for linux 3 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "$1" = "configure" ]; then 5 | new_version="0.0.1-2" 6 | occurrences=/usr/sbin/dkms status | grep "xtrx" | grep "${new_version}" | wc -l 7 | if [ ! occurrences > 0 ]; 8 | then 9 | /usr/sbin/dkms add -m xtrx -v ${new_version} 10 | fi 11 | /usr/sbin/dkms build -m xtrx -v ${new_version} 12 | /usr/sbin/dkms install -m xtrx -v ${new_version} 13 | fi 14 | 15 | #DEBHELPER# 16 | -------------------------------------------------------------------------------- /debian/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "$1" = "remove" ]; then 5 | cur_version="0.0.1-1" 6 | /usr/sbin/dkms remove -m xtrx -v ${cur_version} --all 7 | fi 8 | 9 | #DEBHELPER# 10 | -------------------------------------------------------------------------------- /dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="xtrx" 2 | PACKAGE_VERSION="0.0.1-2" 3 | MAKE[0]="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build" 4 | CLEAN="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build clean" 5 | DEST_MODULE_LOCATION[0]=/extra 6 | BUILT_MODULE_NAME[0]=xtrx 7 | AUTOINSTALL="yes" 8 | 9 | -------------------------------------------------------------------------------- /xtrx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * xtrx - kernel driver support for XTRX PCIe 3 | * 4 | * Copyright (C) 2014, 2016, 2017 Sergey Kostanbaev 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, 19 | * USA. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "xtrx_defs.h" 50 | 51 | #define localparam static const uint32_t 52 | #include "xtrxll_regs.vh" 53 | 54 | #define MAX_XTRX_DEVS 64 55 | 56 | #define DRV_NAME "xtrx" 57 | #define PFX DRV_NAME ": " 58 | 59 | #define DEVICE_NAME DRV_NAME 60 | #define CLASS_NAME DRV_NAME 61 | 62 | 63 | #define XTRX_UART_LINE_GPS 0 64 | #define XTRX_UART_LINE_SIM 1 65 | 66 | #ifndef PCI_EXP_DEVCTL_READRQ_4096B 67 | #define PCI_EXP_DEVCTL_READRQ_4096B 0x5000 68 | #endif 69 | 70 | /* Move out to extrnal CMD */ 71 | #define GET_HWID_COMPAT(x) ((x >> 8) & 0xff) 72 | #define MAKE_I2C_CMD(RD, RDZSZ, WRSZ, DEVNO, DATA) (\ 73 | (((RD) & 1U) << 31) | \ 74 | (((RDZSZ) & 7U) << 28) | \ 75 | (((WRSZ) & 3U) << 26) | \ 76 | (((DEVNO) & 3U) << 24) | \ 77 | (((DATA) & 0xffffffu) << 0)) 78 | #define MAKE_LP8758XX_I2C_CMD(BUS, REG, IN) \ 79 | MAKE_I2C_CMD(0, 0, 2, (BUS), (REG) | ((u32)(IN) << 8)) 80 | #define MAKE_LP8758LMS_I2C_CMD(REG, IN) \ 81 | MAKE_LP8758XX_I2C_CMD(3, REG, IN) 82 | 83 | 84 | /* Serial virtual devices */ 85 | struct xtrx_dev; 86 | 87 | enum xtrx_uart_types { 88 | XTRX_UART_GPS, /**< UART device for GPS NMEA */ 89 | XTRX_UART_SIM, /**< UART device for T0 smartcard */ 90 | XTRX_UART_NUM, 91 | }; 92 | 93 | 94 | #define BUFS 32 95 | #define BUF_SIZE 32768 96 | 97 | #define BUF_SIZE_MIN 8192 98 | #define BUF_SIZE_MAX 4194304 99 | 100 | #define UART_PORT_OPEN 1 101 | 102 | 103 | struct xtrx_dmabuf_nfo { 104 | void* virt; 105 | dma_addr_t phys; 106 | }; 107 | 108 | typedef enum xtrx_interrupt_type { 109 | XTRX_MSI_4, 110 | XTRX_MSI_SINGLE, 111 | XTRX_LEGACY 112 | } xtrx_interrupt_type_t; 113 | 114 | 115 | enum xtrx_pwr_blocks { 116 | XTRX_BLK_CHAR_DEV = 1, 117 | XTRX_BLK_GPS_UART = 2, 118 | XTRX_BLK_SIM_UART = 4, 119 | }; 120 | 121 | struct xtrx_dev { 122 | struct xtrx_dev *next; /* next device in list */ 123 | unsigned devno; 124 | unsigned locked_msk; 125 | unsigned valid; /* usage counter */ 126 | 127 | spinlock_t slock; 128 | 129 | struct cdev cdev; 130 | struct device* cdevice; 131 | 132 | xtrx_interrupt_type_t inttype; 133 | 134 | wait_queue_head_t queue_ctrl; /* wait queue ctrl */ 135 | wait_queue_head_t queue_i2c; /* wait queue i2c */ 136 | wait_queue_head_t queue_tx; /* wait queue tx */ 137 | wait_queue_head_t queue_rx; /* wait queue rx */ 138 | wait_queue_head_t onepps_ctrl; 139 | 140 | struct pci_dev *pdev; /* pci device */ 141 | 142 | struct pps_device *pps; /* 1PPS events from GPS */ 143 | 144 | void __iomem *bar0_addr; 145 | void __iomem *bar1_addr; 146 | 147 | void *shared_mmap; 148 | 149 | unsigned buf_rx_size; /* actual size of each buffer in the RX ring */ 150 | unsigned buf_tx_size; /* actual size of each buffer in the TX ring */ 151 | 152 | struct xtrx_dmabuf_nfo buf_rx[BUFS]; /* RX bufs */ 153 | struct xtrx_dmabuf_nfo buf_tx[BUFS]; /* TX bufs */ 154 | 155 | struct uart_port port_gps; 156 | struct uart_port port_sim; 157 | 158 | 159 | unsigned gps_ctrl_state; 160 | unsigned sim_ctrl_state; 161 | u32 hwid; 162 | u32 pwr_msk; 163 | }; 164 | 165 | 166 | static struct xtrx_dev *xtrx_list = NULL; 167 | static int devices = 0; 168 | static dev_t dev_first; /* Global variable for the first device number */ 169 | static struct class* xtrx_class = NULL; 170 | 171 | 172 | MODULE_AUTHOR("Sergey Kostanbaev "); 173 | MODULE_DESCRIPTION("XTRX low-level PCIe driver"); 174 | MODULE_LICENSE("GPL"); 175 | MODULE_VERSION("0.1"); 176 | 177 | /* Some ARM platform pci_alloc_consistent() reports VA that can't be 178 | * mmaped to userspce. Convertion DMA->PA->VA does the trick on that 179 | * platforms 180 | */ 181 | 182 | #if defined(__arm__) || defined(__aarch64__) 183 | #define VA_DMA_ADDR_FIXUP 184 | #endif 185 | 186 | 187 | static void xtrx_writel(struct xtrx_dev *dev, unsigned int off, unsigned int value) 188 | { 189 | iowrite32(cpu_to_be32(value), (void __iomem *)((unsigned long)dev->bar0_addr + 4*off)); 190 | } 191 | 192 | static unsigned int xtrx_readl(struct xtrx_dev *dev, unsigned int off) 193 | { 194 | return be32_to_cpu(ioread32((void __iomem *)((unsigned long)dev->bar0_addr + 4*off))); 195 | } 196 | 197 | static int xtrx_power_op(struct xtrx_dev *dev, int on, unsigned mask) 198 | { 199 | unsigned long flags; 200 | 201 | int do_pwr_op = 0; 202 | spin_lock_irqsave(&dev->slock, flags); 203 | if (on) { 204 | if (dev->pwr_msk == 0) { 205 | do_pwr_op = 1; 206 | } 207 | dev->pwr_msk |= mask; 208 | } else { 209 | if (dev->pwr_msk) { 210 | dev->pwr_msk &= ~mask; 211 | if (dev->pwr_msk == 0) { 212 | do_pwr_op = 1; 213 | } 214 | } 215 | } 216 | spin_unlock_irqrestore(&dev->slock, flags); 217 | 218 | if (!do_pwr_op) 219 | return 0; 220 | 221 | printk(KERN_NOTICE PFX " 3V3 CTRL:%d\n", on); 222 | if (on) { 223 | xtrx_writel(dev, UL_GP_ADDR + GP_PORT_WR_TMP102, 224 | MAKE_LP8758LMS_I2C_CMD(0x0c, 0xfc)); 225 | xtrx_writel(dev, UL_GP_ADDR + GP_PORT_WR_TMP102, 226 | MAKE_LP8758LMS_I2C_CMD(0x04, 0x88)); 227 | } else { 228 | xtrx_writel(dev, UL_GP_ADDR + GP_PORT_WR_TMP102, 229 | MAKE_LP8758LMS_I2C_CMD(0x04, 0xc8)); 230 | } 231 | return 1; 232 | } 233 | 234 | #define PORT_XTRX 0x03300330 235 | 236 | /* 237 | * serial core request to check if uart tx fifo is empty 238 | */ 239 | static unsigned int xtrx_uart_tx_empty(struct uart_port *port) 240 | { 241 | // TODO 242 | //printk(KERN_NOTICE PFX "Start TX empty?: %d\n", port->line); 243 | return TIOCSER_TEMT; 244 | } 245 | 246 | static struct xtrx_dev *xtrx_dev_from_uart_port(struct uart_port *port) 247 | { 248 | if (port->line % XTRX_UART_NUM == XTRX_UART_LINE_SIM) { 249 | return (struct xtrx_dev *)((unsigned long)port - offsetof(struct xtrx_dev, port_sim)); 250 | } else if (port->line % XTRX_UART_NUM == XTRX_UART_LINE_GPS) { 251 | return (struct xtrx_dev *)((unsigned long)port - offsetof(struct xtrx_dev, port_gps)); 252 | } else { 253 | return NULL; 254 | } 255 | } 256 | 257 | static void xtrx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) 258 | { 259 | struct xtrx_dev *dev; 260 | if (port->line % XTRX_UART_NUM == XTRX_UART_LINE_SIM) { 261 | dev = xtrx_dev_from_uart_port(port); 262 | if (!(mctrl & TIOCM_RTS)) { 263 | dev->sim_ctrl_state |= WR_SIM_CTRL_RESET; 264 | } else { 265 | dev->sim_ctrl_state &= ~WR_SIM_CTRL_RESET; 266 | } 267 | xtrx_writel(dev, GP_PORT_WR_SIM_CTRL, dev->sim_ctrl_state); 268 | 269 | printk(KERN_NOTICE PFX "SIM mctrl=%x\n", dev->sim_ctrl_state); 270 | } 271 | } 272 | 273 | static unsigned int xtrx_uart_get_mctrl(struct uart_port *port) 274 | { 275 | return TIOCM_CTS; 276 | } 277 | 278 | static void xtrx_uart_stop_tx(struct uart_port *port) 279 | { 280 | // TODO 281 | } 282 | 283 | static void xtrx_uart_start_tx(struct uart_port *port) 284 | { 285 | // TODO 286 | //printk(KERN_NOTICE PFX "Start TX: %d\n", port->line); 287 | } 288 | 289 | static void xtrx_uart_stop_rx(struct uart_port *port) 290 | { 291 | // TODO 292 | } 293 | 294 | static void xtrx_uart_enable_ms(struct uart_port *port) 295 | { 296 | } 297 | 298 | static void xtrx_uart_break_ctl(struct uart_port *port, int ctl) 299 | { 300 | } 301 | 302 | 303 | static void xtrx_uart_do_rx(struct uart_port *port, unsigned* fifo_used); 304 | 305 | static int xtrx_uart_startup(struct uart_port *port) 306 | { 307 | unsigned long flags; 308 | struct xtrx_dev *dev = xtrx_dev_from_uart_port(port); 309 | if (port->line % XTRX_UART_NUM == XTRX_UART_LINE_SIM) { 310 | spin_lock_irqsave(&port->lock, flags); 311 | 312 | if (dev->sim_ctrl_state & WR_SIM_CTRL_ENABLE) { 313 | spin_unlock_irqrestore(&port->lock, flags); 314 | printk(KERN_NOTICE PFX "Port %d is already claimed!\n", port->line); 315 | return -EBUSY; 316 | } 317 | 318 | dev->sim_ctrl_state = WR_SIM_CTRL_ENABLE; 319 | xtrx_writel(dev, GP_PORT_WR_SIM_CTRL, dev->sim_ctrl_state); 320 | 321 | spin_unlock_irqrestore(&port->lock, flags); 322 | 323 | xtrx_power_op(dev, 1, XTRX_BLK_SIM_UART); 324 | } else { 325 | dev->gps_ctrl_state = UART_PORT_OPEN; 326 | 327 | spin_lock(&dev->port_gps.lock); 328 | if (dev->gps_ctrl_state) { 329 | unsigned tx_fifo_used; 330 | xtrx_uart_do_rx(&dev->port_gps, &tx_fifo_used); 331 | //xtrx_uart_do_tx(&dev->port_gps, tx_fifo_used); 332 | } 333 | spin_unlock(&dev->port_gps.lock); 334 | 335 | xtrx_power_op(dev, 1, XTRX_BLK_GPS_UART); 336 | } 337 | 338 | printk(KERN_NOTICE PFX "Port opened: %d\n", port->line); 339 | return 0; 340 | } 341 | 342 | static void xtrx_uart_shutdown(struct uart_port *port) 343 | { 344 | unsigned long flags; 345 | 346 | struct xtrx_dev *dev = xtrx_dev_from_uart_port(port); 347 | if (port->line % XTRX_UART_NUM == XTRX_UART_LINE_SIM) { 348 | spin_lock_irqsave(&port->lock, flags); 349 | 350 | dev->sim_ctrl_state = 0; 351 | xtrx_writel(dev, GP_PORT_WR_SIM_CTRL, dev->sim_ctrl_state); 352 | 353 | spin_unlock_irqrestore(&port->lock, flags); 354 | 355 | xtrx_power_op(dev, 0, XTRX_BLK_SIM_UART); 356 | } else { 357 | dev->gps_ctrl_state = 0; 358 | 359 | xtrx_power_op(dev, 0, XTRX_BLK_GPS_UART); 360 | } 361 | 362 | printk(KERN_NOTICE PFX "Port closed: %d\n", port->line); 363 | } 364 | 365 | static void xtrx_uart_set_termios(struct uart_port *port, 366 | struct ktermios *new, 367 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) 368 | struct ktermios *old 369 | #else 370 | const struct ktermios *old 371 | #endif 372 | ) 373 | { 374 | unsigned long flags; 375 | 376 | spin_lock_irqsave(&port->lock, flags); 377 | // TODO: Set HW registers 378 | spin_unlock_irqrestore(&port->lock, flags); 379 | } 380 | 381 | static const char *xtrx_uart_type(struct uart_port *port) 382 | { 383 | return (port->type == PORT_XTRX) ? "xtrx_uart" : NULL; 384 | } 385 | 386 | static int xtrx_uart_request_port(struct uart_port *port) 387 | { 388 | printk(KERN_NOTICE PFX "Port request: %d\n", port->line); 389 | return 0; 390 | } 391 | 392 | static void xtrx_uart_release_port(struct uart_port *port) 393 | { 394 | printk(KERN_NOTICE PFX "Port release: %d\n", port->line); 395 | } 396 | 397 | static void xtrx_uart_config_port(struct uart_port *port, int flags) 398 | { 399 | printk(KERN_NOTICE PFX "Port config: %d (%x)\n", port->line, flags); 400 | 401 | if (flags & UART_CONFIG_TYPE) { 402 | if (xtrx_uart_request_port(port)) 403 | return; 404 | port->type = PORT_XTRX; 405 | } 406 | } 407 | 408 | static int xtrx_uart_verify_port(struct uart_port *port, 409 | struct serial_struct *serinfo) 410 | { 411 | if (port->type != PORT_XTRX) 412 | return -EINVAL; 413 | return 0; 414 | } 415 | 416 | void xtrx_uart_do_rx(struct uart_port *port, unsigned* fifo_used) 417 | { 418 | struct tty_port *tty_port = &port->state->port; 419 | struct xtrx_dev *dev = xtrx_dev_from_uart_port(port); 420 | unsigned int max_count; 421 | char flag; 422 | int processed = 0; 423 | 424 | max_count = 33; 425 | do { 426 | unsigned int c; 427 | c = xtrx_readl(dev, (port->line % XTRX_UART_NUM == XTRX_UART_LINE_GPS) ? 428 | GP_PORT_RD_UART_RX : GP_PORT_RD_SIM_RX); 429 | 430 | if (fifo_used) 431 | *fifo_used = ((c >> UART_FIFOTX_USED_OFF) & ((1 << UART_FIFOTX_USED_BITS) - 1)) + ((c & (1 << UART_FIFOTX_EMPTY)) ? 0 : 1); 432 | 433 | if (c & (1 << UART_FIFORX_EMPTY)) 434 | break; 435 | 436 | //printk(KERN_NOTICE PFX "Char %d: %x\n", port->line, c); 437 | port->icount.rx++; 438 | flag = TTY_NORMAL; 439 | c &= 0xff; 440 | 441 | tty_insert_flip_char(tty_port, c, flag); 442 | 443 | processed = 1; 444 | } while (--max_count); 445 | 446 | if (processed) { 447 | spin_unlock(&port->lock); 448 | tty_flip_buffer_push(tty_port); 449 | spin_lock(&port->lock); 450 | } 451 | } 452 | 453 | 454 | static void xtrx_uart_do_tx(struct uart_port *port, unsigned fifo_used) 455 | { 456 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) 457 | struct circ_buf *xmit; 458 | #else 459 | struct tty_port *tport; 460 | #endif 461 | unsigned int max_count; 462 | struct xtrx_dev *dev = xtrx_dev_from_uart_port(port); 463 | 464 | if (port->x_char) { 465 | xtrx_writel(dev, (port->line % XTRX_UART_NUM == XTRX_UART_LINE_GPS) ? 466 | GP_PORT_WR_UART_TX : GP_PORT_WR_SIM_TX, 467 | port->x_char); 468 | port->icount.tx++; 469 | port->x_char = 0; 470 | return; 471 | } 472 | 473 | if (uart_tx_stopped(port)) { 474 | xtrx_uart_stop_tx(port); 475 | return; 476 | } 477 | 478 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) 479 | xmit = &port->state->xmit; 480 | if (uart_circ_empty(xmit)) 481 | goto txq_empty; 482 | #else 483 | tport = &port->state->port; 484 | if (kfifo_is_empty(&tport->xmit_fifo)) 485 | goto txq_empty; 486 | #endif 487 | 488 | max_count = port->fifosize - fifo_used; 489 | while (max_count--) { 490 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) 491 | unsigned int c; 492 | 493 | c = xmit->buf[xmit->tail] & 0xff; 494 | //printk(KERN_NOTICE PFX "Char: %x\n", c); 495 | #else 496 | unsigned char c; 497 | 498 | if (kfifo_is_empty(&tport->xmit_fifo) || kfifo_get(&tport->xmit_fifo, &c) == 0) 499 | break; 500 | #endif 501 | xtrx_writel(dev, (port->line % XTRX_UART_NUM == XTRX_UART_LINE_GPS) ? 502 | GP_PORT_WR_UART_TX : GP_PORT_WR_SIM_TX, c); 503 | 504 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) 505 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 506 | port->icount.tx++; 507 | if (uart_circ_empty(xmit)) 508 | break; 509 | #endif 510 | } 511 | 512 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 10, 0) 513 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 514 | uart_write_wakeup(port); 515 | 516 | if (uart_circ_empty(xmit)) 517 | goto txq_empty; 518 | #else 519 | if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) 520 | uart_write_wakeup(port); 521 | 522 | if (kfifo_is_empty(&tport->xmit_fifo)) 523 | goto txq_empty; 524 | #endif 525 | return; 526 | 527 | txq_empty: 528 | /* nothing to send, disable transmit interrupt */ 529 | // TODO 530 | return; 531 | } 532 | 533 | /* 534 | static int xtrx_uart_verify_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg) 535 | { 536 | printk(KERN_NOTICE PFX "UART IOCTL %d: %08x -> %016lx\n", 537 | port->line, cmd, arg); 538 | return -EINVAL; 539 | } 540 | */ 541 | 542 | static struct uart_ops xtrx_uart_ops = { 543 | .tx_empty = xtrx_uart_tx_empty, 544 | .get_mctrl = xtrx_uart_get_mctrl, 545 | .set_mctrl = xtrx_uart_set_mctrl, 546 | .start_tx = xtrx_uart_start_tx, 547 | .stop_tx = xtrx_uart_stop_tx, 548 | .stop_rx = xtrx_uart_stop_rx, 549 | .enable_ms = xtrx_uart_enable_ms, 550 | .break_ctl = xtrx_uart_break_ctl, 551 | .startup = xtrx_uart_startup, 552 | .shutdown = xtrx_uart_shutdown, 553 | .set_termios = xtrx_uart_set_termios, 554 | .type = xtrx_uart_type, 555 | .release_port = xtrx_uart_release_port, 556 | .request_port = xtrx_uart_request_port, 557 | .config_port = xtrx_uart_config_port, 558 | .verify_port = xtrx_uart_verify_port, 559 | //.ioctl = xtrx_uart_verify_ioctl, 560 | }; 561 | 562 | static struct uart_driver xtrx_uart_driver = { 563 | .owner = THIS_MODULE, 564 | .driver_name = "xtrxuart", 565 | .dev_name = "ttyXTRX", 566 | .nr = XTRX_UART_NUM * MAX_XTRX_DEVS, 567 | .cons = NULL, 568 | }; 569 | 570 | 571 | // TTY functions 572 | static int xtrx_uart_init(struct xtrx_dev* dev, unsigned xtrx_no) 573 | { 574 | int ret; 575 | 576 | // Register GPS port 577 | dev->port_gps.membase = (void __iomem *)((unsigned long)dev->bar0_addr + GP_PORT_RD_UART_RX*4); 578 | dev->port_gps.iotype = UPIO_MEM; 579 | //dev->port_gps.irq = -1; 580 | dev->port_gps.ops = &xtrx_uart_ops; 581 | dev->port_gps.flags = UPF_BOOT_AUTOCONF; 582 | dev->port_gps.dev = &dev->pdev->dev; 583 | dev->port_gps.fifosize = 32; 584 | dev->port_gps.uartclk = 9600*16; 585 | dev->port_gps.line = xtrx_no * XTRX_UART_NUM + XTRX_UART_LINE_GPS; 586 | 587 | ret = uart_add_one_port(&xtrx_uart_driver, &dev->port_gps); 588 | if (ret) { 589 | printk(KERN_NOTICE PFX "Unable to initialize UART GPS port: %d\n", ret); 590 | return ret; 591 | } 592 | 593 | // Register SIM port 594 | dev->port_sim.membase = (void __iomem *)((unsigned long)dev->bar0_addr + GP_PORT_RD_SIM_RX*4); 595 | dev->port_sim.iotype = UPIO_MEM; 596 | //dev->port_sim.irq = -1; 597 | dev->port_sim.ops = &xtrx_uart_ops; 598 | dev->port_sim.flags = UPF_BOOT_AUTOCONF; 599 | dev->port_sim.dev = &dev->pdev->dev; 600 | dev->port_sim.fifosize = 32; 601 | dev->port_sim.uartclk = 9600*16; 602 | dev->port_sim.line = xtrx_no * XTRX_UART_NUM + XTRX_UART_LINE_SIM; 603 | 604 | ret = uart_add_one_port(&xtrx_uart_driver, &dev->port_sim); 605 | if (ret) { 606 | uart_remove_one_port(&xtrx_uart_driver, &dev->port_gps); 607 | printk(KERN_NOTICE PFX "Unable to initialize UART SIM port: %d\n", ret); 608 | return ret; 609 | } 610 | 611 | dev->sim_ctrl_state = 0; 612 | return 0; 613 | } 614 | 615 | static void xtrx_uart_deinit(struct xtrx_dev* dev) 616 | { 617 | uart_remove_one_port(&xtrx_uart_driver, &dev->port_gps); 618 | uart_remove_one_port(&xtrx_uart_driver, &dev->port_sim); 619 | } 620 | 621 | // DMA functions 622 | static void xtrx_set_dma_bufs(struct xtrx_dev *d, struct xtrx_dmabuf_nfo *pbufs, unsigned config_off, unsigned len) 623 | { 624 | int i; 625 | unsigned len_qw = len / 16; 626 | 627 | //Initialize DMA buffers 628 | for (i = 0; i < BUFS; i++) { 629 | uintptr_t addr = ((uintptr_t)d->bar0_addr) + config_off + 4 * i; 630 | uint32_t reg = ((len_qw - 1) & 0xFFF) | (0xFFFFF000 & pbufs[i].phys); 631 | printk(KERN_NOTICE PFX "buf[%d]=%lx [virt %p] => %08x\n", i, (unsigned long)pbufs[i].phys, pbufs[i].virt, reg); 632 | 633 | iowrite32(cpu_to_be32(reg), (void __iomem *)(addr)); 634 | memset(pbufs[i].virt, i+1, len); 635 | } 636 | } 637 | 638 | 639 | static void xtrx_update_rxdma_len(struct xtrx_dev *d, struct xtrx_dmabuf_nfo *pbufs, unsigned len) 640 | { 641 | if ((GET_HWID_COMPAT(d->hwid) >= 1)) { 642 | uint32_t pktsz = (unsigned)((len / 16) - 1) | (1U << 31); 643 | xtrx_writel(d, UL_RXDMA_ADDR + 32, pktsz); 644 | } else { 645 | xtrx_set_dma_bufs(d, pbufs, 0x800, len); 646 | } 647 | } 648 | 649 | static int xtrx_allocdma(struct xtrx_dev *d, struct xtrx_dmabuf_nfo *pbufs, unsigned config_off, unsigned buflen) 650 | { 651 | int i; 652 | for (i = 0; i < BUFS; i++) { 653 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) 654 | pbufs[i].virt = pci_alloc_consistent(d->pdev, buflen, &pbufs[i].phys); 655 | #else 656 | pbufs[i].virt = dmam_alloc_coherent(&d->pdev->dev, buflen, &pbufs[i].phys, GFP_KERNEL); 657 | #endif 658 | if (!pbufs[i].virt) { 659 | printk(KERN_INFO PFX "Failed to allocate %d DMA buffer", i); 660 | for (; i >= 0; --i) { 661 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) 662 | pci_free_consistent(d->pdev, buflen, pbufs[i].virt, pbufs[i].phys); 663 | #else 664 | dma_free_coherent(&d->pdev->dev, buflen, pbufs[i].virt, pbufs[i].phys); 665 | #endif 666 | } 667 | return -1; 668 | } 669 | } 670 | 671 | xtrx_set_dma_bufs(d, pbufs, config_off, buflen); 672 | return 0; 673 | } 674 | 675 | static int xtrx_allocdma_tx(struct xtrx_dev *d, unsigned size) 676 | { 677 | int res = xtrx_allocdma(d, d->buf_tx, 0xC00, size); 678 | if (res) { 679 | d->buf_tx_size = 0; 680 | return res; 681 | } 682 | 683 | d->buf_tx_size = size; 684 | return 0; 685 | } 686 | 687 | static int xtrx_allocdma_rx(struct xtrx_dev *d, unsigned size) 688 | { 689 | int res = xtrx_allocdma(d, d->buf_rx, 0x800, size); 690 | if (res) { 691 | d->buf_rx_size = 0; 692 | return res; 693 | } 694 | 695 | xtrx_update_rxdma_len(d, d->buf_rx, size); 696 | d->buf_rx_size = size; 697 | return 0; 698 | } 699 | 700 | 701 | 702 | static void xtrx_freedma_rx(struct xtrx_dev *d) 703 | { 704 | int i; 705 | for (i = 0; i < BUFS; i++) { 706 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) 707 | pci_free_consistent(d->pdev, d->buf_rx_size, d->buf_rx[i].virt, d->buf_rx[i].phys); 708 | #else 709 | dma_free_coherent(&d->pdev->dev, d->buf_rx_size, d->buf_rx[i].virt, d->buf_rx[i].phys); 710 | #endif 711 | } 712 | d->buf_rx_size = 0; 713 | } 714 | 715 | static void xtrx_freedma_tx(struct xtrx_dev *d) 716 | { 717 | int i; 718 | for (i = 0; i < BUFS; i++) { 719 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) 720 | pci_free_consistent(d->pdev, d->buf_tx_size, d->buf_tx[i].virt, d->buf_tx[i].phys); 721 | #else 722 | dma_free_coherent(&d->pdev->dev, d->buf_tx_size, d->buf_tx[i].virt, d->buf_tx[i].phys); 723 | #endif 724 | } 725 | d->buf_tx_size = 0; 726 | } 727 | 728 | 729 | // Interrupt routine functions 730 | static void xtrx_interrupt_gpspps(struct xtrx_dev *xtrxdev) 731 | { 732 | struct pps_event_time ts; 733 | pps_get_ts(&ts); 734 | pps_event(xtrxdev->pps, &ts, PPS_CAPTUREASSERT, NULL); 735 | } 736 | 737 | static void xtrx_process_l_interrupts(struct xtrx_dev *xtrxdev, uint32_t imask) 738 | { 739 | if (imask & (1 << INT_RFIC0_SPI)) { 740 | atomic_inc((atomic_t*)xtrxdev->shared_mmap + XTRX_KERN_MMAP_CTRL_IRQS); 741 | wake_up_interruptible(&xtrxdev->queue_ctrl); 742 | } 743 | 744 | if (imask & (1 << INT_I2C)) { 745 | atomic_inc((atomic_t*)xtrxdev->shared_mmap + XTRX_KERN_MMAP_I2C_IRQS); 746 | wake_up_interruptible(&xtrxdev->queue_i2c); 747 | } 748 | 749 | if (imask & (1 << INT_GPS_UART_RX)) { 750 | // TODO tty or user notificatio 751 | //atomic_inc((atomic_t*)xtrxdev->shared_mmap + XTRX_KERN_MMAP_GPS_RX_IRQS); 752 | //wake_up_interruptible(&xtrxdev->uart_gps_rx); 753 | 754 | spin_lock(&xtrxdev->port_gps.lock); 755 | if (xtrxdev->gps_ctrl_state) { 756 | unsigned tx_fifo_used; 757 | xtrx_uart_do_rx(&xtrxdev->port_gps, &tx_fifo_used); 758 | xtrx_uart_do_tx(&xtrxdev->port_gps, tx_fifo_used); 759 | } 760 | spin_unlock(&xtrxdev->port_gps.lock); 761 | } 762 | 763 | if (imask & (1 << INT_SIM_UART_RX)) { 764 | // TODO tty or user notificatio 765 | //atomic_inc((atomic_t*)xtrxdev->shared_mmap + XTRX_KERN_MMAP_SIM_RX_IRQS); 766 | //wake_up_interruptible(&xtrxdev->uart_gps_rx); 767 | 768 | spin_lock(&xtrxdev->port_sim.lock); 769 | if (xtrxdev->sim_ctrl_state & WR_SIM_CTRL_ENABLE) { 770 | unsigned tx_fifo_used; 771 | xtrx_uart_do_rx(&xtrxdev->port_sim, &tx_fifo_used); 772 | xtrx_uart_do_tx(&xtrxdev->port_sim, tx_fifo_used); 773 | } 774 | spin_unlock(&xtrxdev->port_sim.lock); 775 | } 776 | } 777 | 778 | static irqreturn_t xtrx_msi_irq_pps(int irq, void *data) 779 | { 780 | struct xtrx_dev *xtrxdev = data; 781 | xtrx_interrupt_gpspps(xtrxdev); 782 | 783 | atomic_inc((atomic_t*)xtrxdev->shared_mmap + XTRX_KERN_MMAP_1PPS_IRQS); 784 | wake_up_interruptible(&xtrxdev->onepps_ctrl); 785 | return IRQ_HANDLED; 786 | } 787 | 788 | static irqreturn_t xtrx_msi_irq_tx(int irq, void *data) 789 | { 790 | struct xtrx_dev *xtrxdev = data; 791 | atomic_inc((atomic_t*)xtrxdev->shared_mmap + XTRX_KERN_MMAP_TX_IRQS); 792 | wake_up_interruptible(&xtrxdev->queue_tx); 793 | return IRQ_HANDLED; 794 | } 795 | 796 | static irqreturn_t xtrx_msi_irq_rx(int irq, void *data) 797 | { 798 | struct xtrx_dev *xtrxdev = data; 799 | atomic_inc((atomic_t*)xtrxdev->shared_mmap + XTRX_KERN_MMAP_RX_IRQS); 800 | wake_up_interruptible(&xtrxdev->queue_rx); 801 | return IRQ_HANDLED; 802 | } 803 | 804 | static irqreturn_t xtrx_msi_irq_other(int irq, void *data) 805 | { 806 | struct xtrx_dev *xtrxdev = data; 807 | uint32_t imask; 808 | 809 | imask = xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS); 810 | xtrx_process_l_interrupts(xtrxdev, imask); 811 | 812 | return IRQ_HANDLED; 813 | } 814 | 815 | 816 | static irqreturn_t xtrx_irq_legacy(int irq, void *data) 817 | { 818 | struct xtrx_dev *xtrxdev = data; 819 | uint32_t imask = xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS); 820 | if (imask == 0) { 821 | return IRQ_NONE; 822 | } 823 | 824 | if (imask & (1 << (INT_1PPS))) { 825 | xtrx_msi_irq_pps(irq, data); 826 | } 827 | if (imask & (1 << (INT_DMA_TX))) { 828 | xtrx_msi_irq_tx(irq, data); 829 | } 830 | if (imask & (1 << (INT_DMA_RX))) { 831 | xtrx_msi_irq_rx(irq, data); 832 | } 833 | xtrx_process_l_interrupts(xtrxdev, imask); 834 | 835 | return IRQ_HANDLED; 836 | } 837 | 838 | static irqreturn_t xtrx_msi_irq_single(int irq, void *data) 839 | { 840 | xtrx_irq_legacy(irq, data); 841 | return IRQ_HANDLED; 842 | } 843 | 844 | 845 | static struct pps_source_info xtrx_pps_info = { 846 | .name = "xtrx_pps", 847 | .path = "", 848 | .mode = PPS_CAPTUREASSERT|PPS_OFFSETASSERT|PPS_ECHOASSERT| 849 | PPS_CANWAIT|PPS_TSFMT_TSPEC, 850 | .owner = THIS_MODULE, 851 | }; 852 | 853 | static int xtrxfd_open(struct inode *inode, struct file *filp) 854 | { 855 | struct xtrx_dev *dev; 856 | unsigned long flags; 857 | int granted = 0; 858 | 859 | dev = container_of(inode->i_cdev, struct xtrx_dev, cdev); 860 | filp->private_data = dev; 861 | 862 | spin_lock_irqsave(&dev->slock, flags); 863 | if ((dev->locked_msk & XTRX_BLK_CHAR_DEV) == 0) { 864 | 865 | dev->locked_msk |= XTRX_BLK_CHAR_DEV; 866 | granted = 1; 867 | } 868 | spin_unlock_irqrestore(&dev->slock, flags); 869 | 870 | return (granted) ? 0 : -EBUSY; 871 | } 872 | 873 | static int xtrxfd_release(struct inode *inode, struct file *filp) 874 | { 875 | struct xtrx_dev *xtrxdev = filp->private_data; 876 | unsigned long flags; 877 | 878 | if (xtrxdev->valid == 0) { 879 | printk(KERN_INFO PFX "XTRX:%d dev is invalid!\n", xtrxdev->devno); 880 | return 0; 881 | } 882 | 883 | xtrx_power_op(xtrxdev, 0, XTRX_BLK_CHAR_DEV); 884 | 885 | spin_lock_irqsave(&xtrxdev->slock, flags); 886 | xtrxdev->locked_msk &= ~XTRX_BLK_CHAR_DEV; 887 | spin_unlock_irqrestore(&xtrxdev->slock, flags); 888 | return 0; 889 | } 890 | 891 | static ssize_t xtrxfd_read(struct file *filp, char __user *buf, size_t count, 892 | loff_t *f_pos) 893 | { 894 | struct xtrx_dev *xtrxdev = filp->private_data; 895 | int i; 896 | int timeout = 2 * HZ; 897 | 898 | if (!xtrxdev) 899 | return -ENODEV; 900 | 901 | if (!f_pos) 902 | return -EINVAL; 903 | 904 | if (count > 1) { 905 | timeout = HZ * count / 1000; 906 | if (timeout < 1) 907 | timeout = 1; 908 | } 909 | 910 | switch (*f_pos) { 911 | case XTRX_KERN_MMAP_1PPS_IRQS: 912 | i = wait_event_interruptible_timeout( 913 | xtrxdev->onepps_ctrl, 914 | atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_1PPS_IRQS) != 0, 915 | 2 * HZ); 916 | 917 | if (!i) { 918 | return -EAGAIN; 919 | } 920 | return atomic_xchg(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_1PPS_IRQS, 0); 921 | 922 | case XTRX_KERN_MMAP_CTRL_IRQS: 923 | 924 | i = wait_event_interruptible_timeout( 925 | xtrxdev->queue_ctrl, 926 | atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_CTRL_IRQS) != 0, 927 | 2 * HZ); 928 | 929 | if (!i) { 930 | return -EAGAIN; 931 | } 932 | return atomic_xchg(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_CTRL_IRQS, 0); 933 | 934 | case XTRX_KERN_MMAP_I2C_IRQS: 935 | i = wait_event_interruptible_timeout( 936 | xtrxdev->queue_i2c, 937 | atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_I2C_IRQS) != 0, 938 | 2 * HZ); 939 | 940 | if (!i) { 941 | return -EAGAIN; 942 | } 943 | return atomic_xchg(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_I2C_IRQS, 0); 944 | 945 | case XTRX_KERN_MMAP_RX_IRQS: 946 | i = wait_event_interruptible_timeout( 947 | xtrxdev->queue_rx, 948 | atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_RX_IRQS) != 0, 949 | timeout/*2 * HZ*/); 950 | 951 | if (!i) { 952 | return -EAGAIN; 953 | } 954 | return atomic_xchg(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_RX_IRQS, 0); 955 | 956 | case XTRX_KERN_MMAP_TX_IRQS: 957 | i = wait_event_interruptible_timeout( 958 | xtrxdev->queue_tx, 959 | atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_TX_IRQS) != 0, 960 | timeout/*2 * HZ*/); 961 | 962 | if (!i) { 963 | return -EAGAIN; 964 | } 965 | return atomic_xchg(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_TX_IRQS, 0); 966 | } 967 | 968 | 969 | return -EINVAL; 970 | } 971 | 972 | static ssize_t xtrxfd_write(struct file *filp, const char __user *buf, size_t count, 973 | loff_t *f_pos) 974 | { 975 | return -EINVAL; 976 | } 977 | 978 | static unsigned int xtrxfd_poll(struct file *filp, poll_table *wait) 979 | { 980 | struct xtrx_dev *xtrxdev = filp->private_data; 981 | unsigned int mask = 0; 982 | 983 | poll_wait(filp, &xtrxdev->queue_ctrl, wait); 984 | poll_wait(filp, &xtrxdev->queue_tx, wait); 985 | poll_wait(filp, &xtrxdev->queue_rx, wait); 986 | 987 | if (atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_CTRL_IRQS)) 988 | mask |= POLLIN | POLLRDNORM; 989 | 990 | if (atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_RX_IRQS)) 991 | mask |= POLLIN | POLLRDBAND; 992 | 993 | if (atomic_read(((atomic_t*)xtrxdev->shared_mmap) + XTRX_KERN_MMAP_TX_IRQS)) 994 | mask |= POLLOUT | POLLWRBAND; 995 | 996 | return mask; 997 | } 998 | 999 | // TODO more ioctls 1000 | // FIXME fix ioctl numbers 1001 | static long xtrxfd_ioctl(struct file *filp, 1002 | unsigned int ioctl_num,/* The number of the ioctl */ 1003 | unsigned long ioctl_param) /* The parameter to it */ 1004 | { 1005 | int err; 1006 | struct xtrx_dev *xtrxdev = filp->private_data; 1007 | printk(KERN_WARNING PFX "ioctl(%x, %lx) [%lx]", ioctl_num, ioctl_param, (unsigned long)xtrxdev->bar0_addr); 1008 | 1009 | switch (ioctl_num) { 1010 | case 0x123458: { 1011 | int i; 1012 | for ( i = 0; (i < BUFS); ++i) { 1013 | memset( xtrxdev->buf_rx[i].virt, i + 1, xtrxdev->buf_rx_size); 1014 | } 1015 | return 0; 1016 | } 1017 | case 0x123459: { 1018 | if (ioctl_param > xtrxdev->buf_rx_size) 1019 | return -E2BIG; 1020 | if (ioctl_param < BUF_SIZE_MIN) 1021 | return -EINVAL; 1022 | 1023 | xtrx_update_rxdma_len(xtrxdev, xtrxdev->buf_rx, ioctl_param); 1024 | return 0; 1025 | } 1026 | case 0x12345A: { 1027 | if (ioctl_param > BUF_SIZE_MAX || ioctl_param < BUF_SIZE_MIN) { 1028 | printk(KERN_WARNING PFX " INCORRECT SZ!\n"); 1029 | return -EINVAL; 1030 | } 1031 | if (ioctl_param <= xtrxdev->buf_rx_size) 1032 | return xtrxdev->buf_rx_size; 1033 | 1034 | xtrx_freedma_rx(xtrxdev); 1035 | err = xtrx_allocdma_rx(xtrxdev, ioctl_param); 1036 | if (err < 0) { 1037 | return err; 1038 | } 1039 | return xtrxdev->buf_rx_size; 1040 | } 1041 | case 0x12345B: { 1042 | return xtrx_power_op(xtrxdev, ioctl_param, XTRX_BLK_CHAR_DEV); 1043 | } 1044 | default: return -EINVAL; 1045 | } 1046 | return 0; 1047 | } 1048 | 1049 | static void xtrxfd_vma_open(struct vm_area_struct *vma) 1050 | { 1051 | printk(KERN_NOTICE PFX "VMA open, virt %lx, phys %lx\n", 1052 | vma->vm_start, vma->vm_pgoff << PAGE_SHIFT); 1053 | } 1054 | 1055 | static void xtrxfd_vma_close(struct vm_area_struct *vma) 1056 | { 1057 | printk(KERN_NOTICE PFX "VMA close.\n"); 1058 | } 1059 | 1060 | static struct vm_operations_struct xtrxfd_remap_vm_ops = { 1061 | .open = xtrxfd_vma_open, 1062 | .close = xtrxfd_vma_close, 1063 | }; 1064 | 1065 | static int xtrxfd_mmap(struct file *filp, struct vm_area_struct *vma) 1066 | { 1067 | struct xtrx_dev *xtrxdev = filp->private_data; 1068 | enum xtrx_mmap_region { 1069 | REGION_STAT, 1070 | REGION_CTRL, 1071 | REGION_TX_DEVMEM, 1072 | REGION_RX_BUF, 1073 | REGION_TX_BUF, 1074 | } region; 1075 | 1076 | if (vma->vm_pgoff == (XTRX_MMAP_STAT_OFF >> PAGE_SHIFT)) { 1077 | region = REGION_STAT; 1078 | } else if (vma->vm_pgoff == 0) { 1079 | region = REGION_CTRL; 1080 | } else if (vma->vm_pgoff == (XTRX_MMAP_TX_BUF_OFF >> PAGE_SHIFT)) { 1081 | region = REGION_TX_DEVMEM; 1082 | } else if (vma->vm_pgoff == (XTRX_MMAP_RX_OFF >> PAGE_SHIFT)) { 1083 | region = REGION_RX_BUF; 1084 | } else if (vma->vm_pgoff == (XTRX_MMAP_TX_OFF >> PAGE_SHIFT)) { 1085 | region = REGION_TX_BUF; 1086 | } else { 1087 | printk(KERN_NOTICE PFX "call: UNKNOWN REGION: VMA=%p vma->vm_pgoff=%lu\n", vma, vma->vm_pgoff); 1088 | return -ENXIO; 1089 | } 1090 | 1091 | printk(KERN_NOTICE PFX "call: REGION=%d VMA=%p vma->vm_pgoff=%lu\n", 1092 | region, vma, vma->vm_pgoff); 1093 | 1094 | if (region == REGION_STAT) { 1095 | if ((vma->vm_end - vma->vm_start) != (1 << PAGE_SHIFT)) { 1096 | return -EINVAL; 1097 | } 1098 | //vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 1099 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) 1100 | vma->vm_flags |= VM_LOCKED; 1101 | #else 1102 | vm_flags_set(vma, VM_LOCKED); 1103 | #endif 1104 | 1105 | if (remap_pfn_range(vma, vma->vm_start, 1106 | virt_to_phys((void*)((unsigned long)xtrxdev->shared_mmap)) >> PAGE_SHIFT, 1107 | vma->vm_end - vma->vm_start, 1108 | vma->vm_page_prot)) 1109 | return -EAGAIN; 1110 | 1111 | vma->vm_ops = &xtrxfd_remap_vm_ops; 1112 | xtrxfd_vma_open(vma); 1113 | return 0; 1114 | } else if (region == REGION_CTRL || region == REGION_TX_DEVMEM) { 1115 | unsigned long pfn; 1116 | int bar = (region == REGION_CTRL) ? 0 : 1; 1117 | vma->vm_page_prot = pgprot_device(vma->vm_page_prot); 1118 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) 1119 | vma->vm_flags |= VM_IO; 1120 | #else 1121 | vm_flags_set(vma, VM_IO); 1122 | #endif 1123 | pfn = pci_resource_start(xtrxdev->pdev, bar) >> PAGE_SHIFT; 1124 | 1125 | if (io_remap_pfn_range(vma, vma->vm_start, pfn, 1126 | vma->vm_end - vma->vm_start, 1127 | vma->vm_page_prot)) 1128 | return -EAGAIN; 1129 | 1130 | vma->vm_ops = &xtrxfd_remap_vm_ops; 1131 | xtrxfd_vma_open(vma); 1132 | return 0; 1133 | } else if (region == REGION_RX_BUF || region == REGION_TX_BUF) { 1134 | unsigned long pfn, off; 1135 | unsigned i; 1136 | int ret; 1137 | struct xtrx_dmabuf_nfo *pbufs = (region == REGION_RX_BUF) ? xtrxdev->buf_rx : xtrxdev->buf_tx; 1138 | unsigned bufsize = (region == REGION_RX_BUF) ? xtrxdev->buf_rx_size : xtrxdev->buf_tx_size; 1139 | 1140 | if ((vma->vm_end - vma->vm_start) != BUFS * bufsize) { 1141 | printk(KERN_NOTICE PFX "mmap() : end-start=%lx -> %lx\n", 1142 | (long)(vma->vm_end - vma->vm_start), (long)(BUFS * bufsize)); 1143 | return -EINVAL; 1144 | } 1145 | 1146 | //vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 1147 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) 1148 | vma->vm_flags |= VM_LOCKED; 1149 | #else 1150 | vm_flags_set(vma, VM_LOCKED); 1151 | #endif 1152 | 1153 | for (i = 0, off = 0; i < BUFS; ++i, off += bufsize) { 1154 | #ifdef VA_DMA_ADDR_FIXUP 1155 | void *va = phys_to_virt(dma_to_phys(&xtrxdev->pdev->dev, pbufs[i].phys)); 1156 | #else 1157 | void *va = pbufs[i].virt; 1158 | #endif 1159 | pfn = page_to_pfn(virt_to_page(va)); 1160 | 1161 | ret = remap_pfn_range(vma, vma->vm_start + off, 1162 | pfn, 1163 | bufsize, 1164 | vma->vm_page_prot); 1165 | } 1166 | 1167 | return ret; 1168 | } 1169 | 1170 | return -EINVAL; 1171 | } 1172 | 1173 | struct file_operations xtrx_fops = { 1174 | .owner = THIS_MODULE, 1175 | // .llseek = xtrxfd_llseek, 1176 | .read = xtrxfd_read, 1177 | .write = xtrxfd_write, 1178 | .unlocked_ioctl = xtrxfd_ioctl, 1179 | .open = xtrxfd_open, 1180 | .poll = xtrxfd_poll, 1181 | .mmap = xtrxfd_mmap, 1182 | .release = xtrxfd_release, 1183 | }; 1184 | 1185 | static int xtrx_setup_cdev(struct xtrx_dev *xtrxdev) 1186 | { 1187 | dev_t dev_num = dev_first + xtrxdev->devno; 1188 | 1189 | cdev_init(&xtrxdev->cdev, &xtrx_fops); 1190 | xtrxdev->cdev.owner = THIS_MODULE; 1191 | xtrxdev->cdev.ops = &xtrx_fops; 1192 | return cdev_add (&xtrxdev->cdev, dev_num, 1); 1193 | } 1194 | 1195 | static int xtrx_probe(struct pci_dev *pdev, 1196 | const struct pci_device_id *id) 1197 | { 1198 | struct xtrx_dev* xtrxdev; 1199 | int err; 1200 | void __iomem* bar0_addr; 1201 | void __iomem* bar1_addr; 1202 | unsigned xtrx_no = devices; 1203 | 1204 | printk(KERN_INFO PFX "Initializing %s\n", pci_name(pdev)); 1205 | #ifdef VA_DMA_ADDR_FIXUP 1206 | printk(KERN_INFO PFX "Buggy va/dma mapping on the platform! Fixup enabled\n"); 1207 | #endif 1208 | 1209 | err = pci_enable_device(pdev); 1210 | if (err) { 1211 | dev_err(&pdev->dev, "Cannot enable PCI device, " 1212 | "aborting.\n"); 1213 | return err; 1214 | } 1215 | 1216 | /* Reconfigure MaxReadReq to 4KB */ 1217 | pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL, 1218 | PCI_EXP_DEVCTL_READRQ, PCI_EXP_DEVCTL_READRQ_4096B); 1219 | 1220 | pci_set_master(pdev); 1221 | 1222 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) 1223 | if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { 1224 | #else 1225 | if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) { 1226 | #endif 1227 | dev_err(&pdev->dev,"No suitable consistent DMA available.\n"); 1228 | goto err_disable_pdev; 1229 | } 1230 | 1231 | /* 1232 | * Check for BARs. We expect 0: 4KB 1233 | */ 1234 | if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || 1235 | pci_resource_len(pdev, 0) < 1 << 12) { 1236 | dev_err(&pdev->dev, "Missing UL BAR, aborting.\n"); 1237 | err = -ENODEV; 1238 | goto err_disable_pdev; 1239 | } 1240 | 1241 | err = pci_request_regions(pdev, DRV_NAME); 1242 | if (err) { 1243 | dev_err(&pdev->dev, "Cannot obtain PCI resources, " 1244 | "aborting.\n"); 1245 | goto err_disable_pdev; 1246 | } 1247 | 1248 | bar0_addr = pci_iomap(pdev, 0, 1 << 12); 1249 | if (!bar0_addr) { 1250 | dev_err(&pdev->dev, "Failed to map BAR 0.\n"); 1251 | goto err_free_res; 1252 | } 1253 | 1254 | bar1_addr = pci_iomap(pdev, 1, 1 << 16); 1255 | if (!bar1_addr) { 1256 | dev_err(&pdev->dev, "Failed to map BAR 1.\n"); 1257 | goto err_unmap0; 1258 | } 1259 | 1260 | xtrxdev = kzalloc(sizeof(*xtrxdev), GFP_KERNEL); 1261 | if (!xtrxdev) { 1262 | dev_err(&pdev->dev, "Failed to allocate memory.\n"); 1263 | err = -ENOMEM; 1264 | goto err_unmap1; 1265 | } 1266 | pci_set_drvdata(pdev, xtrxdev); 1267 | xtrxdev->bar0_addr = bar0_addr; 1268 | xtrxdev->bar1_addr = bar1_addr; 1269 | xtrxdev->devno = xtrx_no; 1270 | xtrxdev->pdev = pdev; 1271 | xtrxdev->locked_msk = 0; 1272 | xtrxdev->gps_ctrl_state = 0; 1273 | xtrxdev->sim_ctrl_state = 0; 1274 | xtrxdev->pwr_msk = 0; 1275 | xtrxdev->valid = 0; 1276 | spin_lock_init(&xtrxdev->slock); 1277 | 1278 | xtrxdev->shared_mmap = (char*)get_zeroed_page(GFP_KERNEL); 1279 | if (!xtrxdev->shared_mmap) { 1280 | dev_err(&pdev->dev, "Failed to allocate kernel mmap memory.\n"); 1281 | err = -ENOMEM; 1282 | goto err_alloc0; 1283 | } 1284 | 1285 | xtrxdev->hwid = xtrx_readl(xtrxdev, GP_PORT_RD_HWCFG); 1286 | 1287 | xtrxdev->pps = pps_register_source(&xtrx_pps_info, 1288 | PPS_CAPTUREASSERT | PPS_OFFSETASSERT); 1289 | if (!xtrxdev->pps) { 1290 | dev_err(&pdev->dev, "Failed to register 1PPS source.\n"); 1291 | } 1292 | 1293 | init_waitqueue_head(&xtrxdev->queue_ctrl); 1294 | init_waitqueue_head(&xtrxdev->queue_tx); 1295 | init_waitqueue_head(&xtrxdev->queue_rx); 1296 | init_waitqueue_head(&xtrxdev->onepps_ctrl); 1297 | init_waitqueue_head(&xtrxdev->queue_i2c); 1298 | 1299 | 1300 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(4,11,0) 1301 | err = pci_enable_msi_range(pdev, XTRX_MSI_COUNT, XTRX_MSI_COUNT); 1302 | #else 1303 | err = pci_alloc_irq_vectors(pdev, XTRX_MSI_COUNT, XTRX_MSI_COUNT, PCI_IRQ_MSI); 1304 | #endif 1305 | if (err == XTRX_MSI_COUNT) { 1306 | xtrxdev->inttype = XTRX_MSI_4; 1307 | 1308 | err = request_irq(pdev->irq + INT_1PPS, xtrx_msi_irq_pps, 0, "xtrx_pps", xtrxdev); 1309 | if (err) { 1310 | dev_err(&pdev->dev, "Failed to register CTRL MSI.\n"); 1311 | err = -ENODEV; 1312 | goto err_msi; 1313 | } 1314 | 1315 | err = request_irq(pdev->irq + INT_DMA_TX, xtrx_msi_irq_tx, 0, "xtrx_tx", xtrxdev); 1316 | if (err) { 1317 | dev_err(&pdev->dev, "Failed to register TX MSI.\n"); 1318 | err = -ENODEV; 1319 | goto err_irq_0; 1320 | } 1321 | 1322 | err = request_irq(pdev->irq + INT_DMA_RX, xtrx_msi_irq_rx, 0, "xtrx_rx", xtrxdev); 1323 | if (err) { 1324 | dev_err(&pdev->dev, "Failed to register RX MSI.\n"); 1325 | err = -ENODEV; 1326 | goto err_irq_1; 1327 | } 1328 | 1329 | err = request_irq(pdev->irq + 3, xtrx_msi_irq_other, 0, "xtrx_other", xtrxdev); 1330 | if (err) { 1331 | dev_err(&pdev->dev, "Failed to register OTHER MSI.\n"); 1332 | err = -ENODEV; 1333 | goto err_irq_2; 1334 | } 1335 | } else { 1336 | 1337 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(4,11,0) 1338 | err = pci_enable_msi_range(pdev, 1, 1); 1339 | #else 1340 | err = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); 1341 | #endif 1342 | if (err == 1) { 1343 | xtrxdev->inttype = XTRX_MSI_SINGLE; 1344 | 1345 | err = request_irq(pdev->irq, xtrx_msi_irq_single, 0, "xtrx_msi_single", xtrxdev); 1346 | if (err) { 1347 | dev_err(&pdev->dev, "Failed to register SINGLE MSI.\n"); 1348 | err = -ENODEV; 1349 | goto err_msi; 1350 | } 1351 | } else { 1352 | dev_err(&pdev->dev, "Failed to enable MSI, falling back to legacy mode.\n"); 1353 | xtrxdev->inttype = XTRX_LEGACY; 1354 | 1355 | err = request_irq(pdev->irq, xtrx_irq_legacy, IRQF_SHARED, "xtrx_legacy", xtrxdev); 1356 | if (err) { 1357 | dev_err(&pdev->dev, "Failed to register Legacy interrupt.\n"); 1358 | err = -ENODEV; 1359 | goto err_alloc1; 1360 | } 1361 | } 1362 | } 1363 | 1364 | /* Clear pending interrupts */ 1365 | xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS); 1366 | 1367 | /* Enable interrupts */ 1368 | xtrx_writel(xtrxdev, GP_PORT_WR_INT_PCIE, (1U << INT_PCIE_I_FLAG) | 0xfff); 1369 | 1370 | // Mark that we don't have preallocated buffers 1371 | xtrxdev->buf_rx_size = 0; 1372 | xtrxdev->buf_tx_size = 0; 1373 | 1374 | memset(xtrxdev->buf_rx, 0, sizeof(xtrxdev->buf_rx)); 1375 | memset(xtrxdev->buf_tx, 0, sizeof(xtrxdev->buf_tx)); 1376 | 1377 | err = xtrx_allocdma_rx(xtrxdev, BUF_SIZE); 1378 | if (err) { 1379 | dev_err(&pdev->dev, "Failed to register RX DMA buffers.\n"); 1380 | err = -ENODEV; 1381 | goto err_irq_3; 1382 | } 1383 | 1384 | err = xtrx_allocdma_tx(xtrxdev, BUF_SIZE); 1385 | if (err) { 1386 | dev_err(&pdev->dev, "Failed to register TX DMA buffers.\n"); 1387 | err = -ENODEV; 1388 | goto err_rx_bufs; 1389 | } 1390 | 1391 | err = xtrx_uart_init(xtrxdev, xtrx_no); 1392 | if (err) { 1393 | goto err_uart; 1394 | } 1395 | 1396 | xtrxdev->valid = 1; 1397 | xtrxdev->cdevice = device_create(xtrx_class, 1398 | &pdev->dev, 1399 | MKDEV(MAJOR(dev_first), MINOR(dev_first) + devices), 1400 | NULL, 1401 | DEVICE_NAME "%d", 1402 | devices); 1403 | if (IS_ERR(xtrxdev->cdevice)) { 1404 | printk(KERN_NOTICE PFX "Unable to register device class\n"); 1405 | goto failed_device; 1406 | } 1407 | 1408 | err = xtrx_setup_cdev(xtrxdev); 1409 | if (err) { 1410 | printk(KERN_NOTICE PFX "Error %d initializing cdev\n", err); 1411 | goto failed_cdev; 1412 | } 1413 | 1414 | devices++; 1415 | xtrxdev->next = xtrx_list; 1416 | xtrx_list = xtrxdev; 1417 | return 0; 1418 | 1419 | //cdev_del(&xtrxdev->cdev); 1420 | failed_cdev: 1421 | device_destroy(xtrx_class, MKDEV(MAJOR(dev_first), MINOR(dev_first) + devices)); 1422 | failed_device: 1423 | xtrx_uart_deinit(xtrxdev); 1424 | err_uart: 1425 | xtrx_freedma_tx(xtrxdev); 1426 | err_rx_bufs: 1427 | xtrx_freedma_rx(xtrxdev); 1428 | err_irq_3: 1429 | xtrx_writel(xtrxdev, GP_PORT_WR_INT_PCIE, (1U << INT_PCIE_I_FLAG)); 1430 | xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS); 1431 | 1432 | if (xtrxdev->inttype == XTRX_LEGACY) { 1433 | free_irq(pdev->irq, xtrxdev); 1434 | } else if (xtrxdev->inttype == XTRX_MSI_SINGLE) { 1435 | free_irq(pdev->irq, xtrxdev); 1436 | 1437 | pci_disable_msi(pdev); 1438 | } else if (xtrxdev->inttype == XTRX_MSI_4) { 1439 | free_irq(pdev->irq + 3, xtrxdev); 1440 | err_irq_2: 1441 | free_irq(pdev->irq + 2, xtrxdev); 1442 | err_irq_1: 1443 | free_irq(pdev->irq + 1, xtrxdev); 1444 | err_irq_0: 1445 | free_irq(pdev->irq + 0, xtrxdev); 1446 | err_msi: 1447 | pci_disable_msi(pdev); 1448 | } 1449 | err_alloc1: 1450 | if (xtrxdev->pps) { 1451 | pps_unregister_source(xtrxdev->pps); 1452 | } 1453 | free_page((unsigned long)xtrxdev->shared_mmap); 1454 | err_alloc0: 1455 | kfree(xtrxdev); 1456 | err_unmap1: 1457 | pci_iounmap(pdev, bar1_addr); 1458 | err_unmap0: 1459 | pci_iounmap(pdev, bar0_addr); 1460 | err_free_res: 1461 | pci_release_regions(pdev); 1462 | 1463 | err_disable_pdev: 1464 | pci_clear_master(pdev); /* Nobody seems to do this */ 1465 | 1466 | pci_disable_device(pdev); 1467 | pci_set_drvdata(pdev, NULL); 1468 | return err; 1469 | }; 1470 | 1471 | 1472 | static void xtrx_remove(struct pci_dev *pdev) 1473 | { 1474 | struct xtrx_dev* xtrxdev = pci_get_drvdata(pdev); 1475 | printk(KERN_INFO PFX "Removing device %s\n", pci_name(pdev)); 1476 | 1477 | /* Disable interrupts */ 1478 | xtrx_writel(xtrxdev, GP_PORT_WR_INT_PCIE, (1U << INT_PCIE_I_FLAG)); 1479 | /* Clear pending interrupts */ 1480 | xtrx_readl(xtrxdev, GP_PORT_RD_INTERRUPTS); 1481 | 1482 | cdev_del(&xtrxdev->cdev); 1483 | device_destroy(xtrx_class, MKDEV(MAJOR(dev_first), MINOR(xtrxdev->devno))); 1484 | 1485 | xtrx_uart_deinit(xtrxdev); 1486 | 1487 | if (xtrxdev->inttype == XTRX_LEGACY) { 1488 | free_irq(pdev->irq, xtrxdev); 1489 | } else if (xtrxdev->inttype == XTRX_MSI_SINGLE) { 1490 | free_irq(pdev->irq, xtrxdev); 1491 | 1492 | pci_disable_msi(pdev); 1493 | } else if (xtrxdev->inttype == XTRX_MSI_4) { 1494 | free_irq(pdev->irq + 0, xtrxdev); 1495 | free_irq(pdev->irq + 1, xtrxdev); 1496 | free_irq(pdev->irq + 2, xtrxdev); 1497 | free_irq(pdev->irq + 3, xtrxdev); 1498 | 1499 | pci_disable_msi(pdev); 1500 | } 1501 | if (xtrxdev->pps) { 1502 | pps_unregister_source(xtrxdev->pps); 1503 | } 1504 | 1505 | xtrxdev->valid = 0; 1506 | 1507 | pci_iounmap(pdev, xtrxdev->bar1_addr); 1508 | pci_iounmap(pdev, xtrxdev->bar0_addr); 1509 | pci_release_regions(pdev); 1510 | 1511 | pci_clear_master(pdev); 1512 | pci_disable_device(pdev); 1513 | pci_set_drvdata(pdev, NULL); 1514 | 1515 | devices--; 1516 | // TODO: Unchain from list and free the memory 1517 | 1518 | xtrx_freedma_tx(xtrxdev); 1519 | xtrx_freedma_rx(xtrxdev); 1520 | 1521 | } 1522 | 1523 | static struct pci_device_id xtrx_pci_table[] = { 1524 | { PCI_DEVICE(0x10EE, 0xFAE3), 1525 | .driver_data = 0 }, 1526 | { PCI_DEVICE(0x10EE, 0x7011), 1527 | .driver_data = 1 }, 1528 | { PCI_DEVICE(0x10EE, 0x7012), 1529 | .driver_data = 2 }, 1530 | { 0, } 1531 | }; 1532 | 1533 | MODULE_DEVICE_TABLE(pci, xtrx_pci_table); 1534 | 1535 | static struct pci_driver xtrx_driver = { 1536 | .name = DRV_NAME, 1537 | .id_table = xtrx_pci_table, 1538 | .probe = xtrx_probe, 1539 | .remove = xtrx_remove 1540 | }; 1541 | 1542 | 1543 | static int __init xtrx_init(void) 1544 | { 1545 | int err; 1546 | 1547 | err = uart_register_driver(&xtrx_uart_driver); 1548 | if (err) { 1549 | printk(KERN_NOTICE PFX "Unable to initialize UART driver: %d\n", err); 1550 | goto failed_uart; 1551 | } 1552 | 1553 | err = alloc_chrdev_region(&dev_first, 0, MAX_XTRX_DEVS, DRV_NAME); 1554 | if (err) { 1555 | printk(KERN_NOTICE PFX "Unable to allocate chrdev region: %d\n", err); 1556 | goto failed_chrdev; 1557 | } 1558 | 1559 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 1560 | xtrx_class = class_create(THIS_MODULE, CLASS_NAME); 1561 | #else 1562 | xtrx_class = class_create(CLASS_NAME); 1563 | #endif 1564 | 1565 | if (IS_ERR(xtrx_class)) { 1566 | printk(KERN_NOTICE PFX "Unable to register xtrx class\n"); 1567 | goto failed_setup_cdev; 1568 | } 1569 | 1570 | err = pci_register_driver(&xtrx_driver); 1571 | if (err) { 1572 | printk(KERN_NOTICE PFX "Unable to register PCI driver: %d\n", err); 1573 | goto failed_pci; 1574 | } 1575 | return 0; 1576 | 1577 | failed_pci: 1578 | class_destroy(xtrx_class); 1579 | failed_setup_cdev: 1580 | unregister_chrdev_region(dev_first, devices); 1581 | failed_chrdev: 1582 | uart_unregister_driver(&xtrx_uart_driver); 1583 | failed_uart: 1584 | return err; 1585 | } 1586 | 1587 | static void __exit xtrx_cleanup(void) 1588 | { 1589 | 1590 | struct xtrx_dev *ptr = xtrx_list, *next; 1591 | 1592 | pci_unregister_driver(&xtrx_driver); 1593 | 1594 | class_destroy(xtrx_class); 1595 | 1596 | unregister_chrdev_region(dev_first, devices); 1597 | 1598 | uart_unregister_driver(&xtrx_uart_driver); 1599 | 1600 | 1601 | while (ptr != NULL) { 1602 | next = ptr->next; 1603 | free_page((unsigned long)ptr->shared_mmap); 1604 | kfree(ptr); 1605 | ptr = next; 1606 | } 1607 | 1608 | } 1609 | 1610 | 1611 | module_init(xtrx_init); 1612 | module_exit(xtrx_cleanup); 1613 | 1614 | -------------------------------------------------------------------------------- /xtrx_defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * xtrx kernel ABI definitions header file 3 | * Copyright (c) 2017 Sergey Kostanbaev 4 | * For more information, please visit: http://xtrx.io 5 | * 6 | * This library is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | */ 20 | #ifndef XTRX_DEFS_H 21 | #define XTRX_DEFS_H 22 | 23 | #define XTRX_MMAP_TX_BUF_OFF 2097152 24 | 25 | #define XTRX_MMAP_STAT_OFF 4194304 26 | 27 | #define XTRX_MMAP_RX_OFF 67108864 28 | #define XTRX_MMAP_TX_OFF 134217728 29 | 30 | 31 | #define XTRX_IOCTL_MAGIC 0xEE 32 | #define XTRX_IOCTL_RXALLOCBUFS _IO( XTRX_IOCTL_MAGIC, 0 ) 33 | 34 | #define XTRX_IOCTL_SPI_TRANSACT 0x123456 35 | 36 | 37 | 38 | /* HW specific */ 39 | #define XTRX_MSI_COUNT 4 40 | 41 | 42 | /* Kernel shared mmap */ 43 | 44 | #define XTRX_KERN_MMAP_1PPS_IRQS 0 45 | #define XTRX_KERN_MMAP_TX_IRQS 1 46 | #define XTRX_KERN_MMAP_RX_IRQS 2 47 | #define XTRX_KERN_MMAP_CTRL_IRQS 3 48 | 49 | #define XTRX_KERN_MMAP_GPS_RX_IRQS 5 50 | #define XTRX_KERN_MMAP_GPS_TX_IRQS 6 51 | #define XTRX_KERN_MMAP_SIM_RX_IRQS 7 52 | #define XTRX_KERN_MMAP_SIM_TX_IRQS 8 53 | #define XTRX_KERN_MMAP_I2C_IRQS 9 54 | 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /xtrxll_regs.vh: -------------------------------------------------------------------------------- 1 | // 2 | // Port constant that used in driver and in FPGA code 3 | // 4 | 5 | //WR 6 | localparam GP_PORT_WR_SPI_LMS7_0 = 0; 7 | localparam GP_PORT_WR_INT_PCIE = 1; 8 | localparam GP_PORT_WR_DAC_SPI = 2; 9 | localparam GP_PORT_WR_TMP102 = 3; 10 | 11 | localparam GP_PORT_WR_UART_TX = 4; 12 | localparam GP_PORT_WR_SIM_TX = 5; 13 | localparam GP_PORT_WR_SIM_CTRL = 6; 14 | localparam GP_PORT_WR_LMS_CTRL = 7; 15 | 16 | localparam GP_PORT_WR_TXDMA_CNF_L = 8; 17 | localparam GP_PORT_WR_TXDMA_CNF_T = 9; 18 | localparam GP_PORT_WR_TCMD_D = 10; 19 | localparam GP_PORT_WR_TCMD_T = 11; 20 | 21 | localparam GP_PORT_WR_RXDMA_CNFRM = 12; 22 | localparam GP_PORT_WR_RXTXDMA = 13; 23 | localparam GP_PORT_WR_TXMMCM = 14; 24 | localparam GP_PORT_WR_RF_SWITCHES = 15; 25 | 26 | localparam GP_PORT_WR_QSPI_EXCMD = 16; 27 | localparam GP_PORT_WR_QSPI_CMD = 17; 28 | localparam GP_PORT_WR_MEM_CTRL = 18; 29 | localparam GP_PORT_WR_USB_CTRL = 19; 30 | 31 | localparam GP_PORT_WR_USB_FIFO_CTRL = 20; 32 | localparam GP_PORT_WR_USB_FIFO_PTRS = 21; 33 | localparam GP_PORT_WR_FE_CMD = 22; 34 | localparam GP_PORT_WR_PPS_CMD = 23; 35 | 36 | localparam GP_PORT_WR_GPIO_FUNC = 24; 37 | localparam GP_PORT_WR_GPIO_DIR = 25; 38 | localparam GP_PORT_WR_GPIO_OUT = 26; 39 | localparam GP_PORT_WR_GPIO_CS = 27; 40 | 41 | localparam GP_PORT_WR_GLOBCMDR0 = 28; 42 | localparam GP_PORT_WR_GLOBCMDR1 = 29; 43 | 44 | //RD 45 | localparam GP_PORT_RD_SPI_LMS7_0 = 0; 46 | localparam GP_PORT_RD_INTERRUPTS = 1; 47 | localparam GP_PORT_RD_ONEPPS = 2; 48 | localparam GP_PORT_RD_TMP102 = 3; 49 | 50 | localparam GP_PORT_RD_UART_RX = 4; 51 | localparam GP_PORT_RD_SIM_RX = 5; 52 | localparam GP_PORT_RD_SIM_STAT = 6; 53 | localparam GP_PORT_RD_MCU_STAT = 7; 54 | 55 | localparam GP_PORT_RD_TXDMA_STAT = 8; 56 | localparam GP_PORT_RD_TXDMA_STATM = 9; 57 | localparam GP_PORT_RD_TXDMA_STATTS= 10; 58 | localparam GP_PORT_RD_TXDMA_ST_CPL= 11; 59 | 60 | localparam GP_PORT_RD_RXDMA_STAT = 12; 61 | localparam GP_PORT_RD_RXDMA_STATTS= 13; 62 | localparam GP_PORT_RD_TXMMCM = 14; 63 | localparam GP_PORT_RD_TCMDSTAT = 15; 64 | 65 | localparam GP_PORT_RD_QSPI_RB = 16; 66 | localparam GP_PORT_RD_QSPI_STAT = 17; 67 | localparam GP_PORT_RD_MEM_RB = 18; 68 | localparam GP_PORT_RD_MCU_DEBUG = 19; 69 | 70 | localparam GP_PORT_RD_REF_OSC = 20; 71 | localparam GP_PORT_RD_RXIQ_MISS = 21; 72 | localparam GP_PORT_RD_RXIQ_ODD = 22; 73 | localparam GP_PORT_RD_RXIQ_BI_BQ = 23; 74 | 75 | localparam GP_PORT_RD_USB_RB = 24; 76 | localparam GP_PORT_RD_RXIQ_PERIOD = 25; 77 | localparam GP_PORT_RD_HWCFG = 26; 78 | localparam GP_PORT_RD_GPIO_IN = 27; 79 | 80 | localparam GP_PORT_RD_USB_DEBUG0 = 28; 81 | localparam GP_PORT_RD_USB_DEBUG1 = 29; 82 | localparam GP_PORT_RD_USB_DEBUG2 = 30; 83 | localparam GP_PORT_RD_USB_DEBUG3 = 31; 84 | 85 | localparam GP_PORT_RD_USB_EP0_O = 32; 86 | localparam GP_PORT_RD_USB_EP1_O = 32 + 1; 87 | localparam GP_PORT_RD_USB_EP2_O = 32 + 2; 88 | localparam GP_PORT_RD_USB_EP3_O = 32 + 3; 89 | localparam GP_PORT_RD_USB_EP4_O = 32 + 4; 90 | localparam GP_PORT_RD_USB_EP5_O = 32 + 5; 91 | localparam GP_PORT_RD_USB_EP6_O = 32 + 6; 92 | localparam GP_PORT_RD_USB_EP7_O = 32 + 7; 93 | localparam GP_PORT_RD_USB_EP8_O = 32 + 8; 94 | localparam GP_PORT_RD_USB_EP9_O = 32 + 9; 95 | localparam GP_PORT_RD_USB_EP10_O = 32 + 10; 96 | localparam GP_PORT_RD_USB_EP11_O = 32 + 11; 97 | localparam GP_PORT_RD_USB_EP12_O = 32 + 12; 98 | localparam GP_PORT_RD_USB_EP13_O = 32 + 13; 99 | localparam GP_PORT_RD_USB_EP14_O = 32 + 14; 100 | localparam GP_PORT_RD_USB_EP15_O = 32 + 15; 101 | 102 | localparam GP_PORT_RD_USB_EP0_I = 48; 103 | localparam GP_PORT_RD_USB_EP1_I = 48 + 1; 104 | localparam GP_PORT_RD_USB_EP2_I = 48 + 2; 105 | localparam GP_PORT_RD_USB_EP3_I = 48 + 3; 106 | localparam GP_PORT_RD_USB_EP4_I = 48 + 4; 107 | localparam GP_PORT_RD_USB_EP5_I = 48 + 5; 108 | localparam GP_PORT_RD_USB_EP6_I = 48 + 6; 109 | localparam GP_PORT_RD_USB_EP7_I = 48 + 7; 110 | localparam GP_PORT_RD_USB_EP8_I = 48 + 8; 111 | localparam GP_PORT_RD_USB_EP9_I = 48 + 9; 112 | localparam GP_PORT_RD_USB_EP10_I = 48 + 10; 113 | localparam GP_PORT_RD_USB_EP11_I = 48 + 11; 114 | localparam GP_PORT_RD_USB_EP12_I = 48 + 12; 115 | localparam GP_PORT_RD_USB_EP13_I = 48 + 13; 116 | localparam GP_PORT_RD_USB_EP14_I = 48 + 14; 117 | localparam GP_PORT_RD_USB_EP15_I = 48 + 15; 118 | 119 | // WR bus routing 120 | localparam UL_GP_ADDR = 0; 121 | localparam UL_MCU_ADDR = 256; 122 | localparam UL_RXDMA_ADDR = 512; 123 | localparam UL_TXDMA_ADDR = 768; 124 | 125 | localparam UL_RD_MEM_ADDR = 512; 126 | 127 | 128 | // Bits in GP_PORT_LMS_CTRL 129 | localparam GP_PORT_LMS_CTRL_DIGRESET = 0; 130 | localparam GP_PORT_LMS_CTRL_RESET = 1; 131 | localparam GP_PORT_LMS_CTRL_GPWR = 2; 132 | localparam GP_PORT_LMS_CTRL_RXEN = 3; 133 | localparam GP_PORT_LMS_CTRL_TXEN = 4; 134 | 135 | localparam GP_PORT_LMS_FCLK_RX_GEN = 6; 136 | localparam GP_PORT_LMS_RX_TERM_DIS = 7; 137 | 138 | localparam GP_PORT_XTRX_ENBPVIO_N = 8; 139 | localparam GP_PORT_XTRX_ENBP3V3_N = 9; 140 | localparam GP_PORT_XTRX_EXT_CLK = 10; 141 | localparam GP_PORT_XTRX_PD_TCXO = 11; 142 | 143 | 144 | // Bits in GP_PORT_RD_SIM_RX / GP_PORT_RD_UART_RX / GP_PORT_RD_SIM_STAT 145 | localparam UART_FIFORX_PARERR = 14; 146 | localparam UART_FIFORX_EMPTY = 15; 147 | 148 | localparam UART_FIFOTX_USED_OFF = 16; 149 | localparam UART_FIFOTX_USED_BITS = 5; 150 | localparam UART_FIFOTX_EMPTY = 21; 151 | 152 | // Bits in GP_PORT_WR_SIM_CTRL 153 | localparam WR_SIM_CTRL_RESET = 0; 154 | localparam WR_SIM_CTRL_ENABLE = 1; 155 | localparam WR_SIM_CTRL_33V = 2; 156 | 157 | // Bits in GP_PORT_WR_TXMMCM 158 | 159 | localparam GP_PORT_DRP_ADDR_OFF = 16; 160 | localparam GP_PORT_DRP_ADDR_BITS = 7; 161 | localparam GP_PORT_DRP_REGEN = 23; 162 | localparam GP_PORT_DRP_REGWR = 24; 163 | localparam GP_PORT_DRP_GPIO_OFF = 25; 164 | localparam GP_PORT_DRP_NUM_OFF = 30; 165 | 166 | //localparam GP_PORT_TXMMCM_REGEN = 23; 167 | //localparam GP_PORT_TXMMCM_REGWR = 24; 168 | //localparam GP_PORT_TXMMCM_CLKSEL = 25; 169 | //localparam GP_PORT_TXMMCM_RESET = 26; 170 | //localparam GP_PORT_TXMMCM_PWRDOWN = 27; 171 | // Bits in GP_PORT_RD_TXMMCM 172 | 173 | //localparam GP_PORT_TXMMCM_LOCKED = 28; 174 | //localparam GP_PORT_TXMMCM_RDY = 29; 175 | //localparam GP_PORT_TXMMCM_STOPPED = 30; 176 | //localparam GP_PORT_TXMMCM_STOPPEDF= 31; 177 | 178 | 179 | localparam GP_PORT_IN_DRP0 = 16; 180 | localparam GP_PORT_IN_DRP1 = 20; 181 | localparam GP_PORT_IN_DRP2 = 24; 182 | localparam GP_PORT_IN_DRP3 = 28; 183 | 184 | localparam GP_PORT_IN_MMCM_LOCKED = 0; 185 | localparam GP_PORT_IN_MMCM_STOPPED = 1; 186 | localparam GP_PORT_IN_MMCM_STOPPEDF= 2; 187 | 188 | localparam GP_PORT_OUT_MMCM_CLKSEL1 = 0; 189 | localparam GP_PORT_OUT_MMCM_RESET = 1; 190 | localparam GP_PORT_OUT_MMCM_PWRDOWN = 2; 191 | 192 | 193 | //localparam GP_PORT_TXMMCM_LOCKED = 28; 194 | //localparam GP_PORT_TXMMCM_RDY = 29; 195 | //localparam GP_PORT_TXMMCM_STOPPED = 30; 196 | //localparam GP_PORT_TXMMCM_STOPPEDF= 31; 197 | 198 | localparam DRP_PORT_MMCM_TX = 0; 199 | localparam DRP_PORT_MMCM_RX = 1; 200 | localparam DRP_PORT_MMCM_PCIE = 2; 201 | 202 | // Formats for RX/TX DMA 203 | localparam FMT_STOP = 0; 204 | localparam FMT_8BIT = 1; 205 | localparam FMT_12BIT = 2; 206 | localparam FMT_16BIT = 3; 207 | 208 | localparam WR_RXDMA_FE_FMT_OFF = 0; 209 | localparam WR_RXDMA_FE_DECIM_OFF = 2; 210 | localparam WR_RXDMA_FE_PAUSED = 4; 211 | localparam WR_RXDMA_FE_RESET = 5; 212 | localparam WR_RXDMA_FE_SISO = 6; 213 | 214 | 215 | localparam GP_PORT_TXDMA_CTRL_MODE_REP = 2; 216 | localparam GP_PORT_TXDMA_CTRL_MODE_SISO = 3; 217 | localparam _GP_PORT_TXDMA_CTRL_REP_OFF = 4; 218 | localparam GP_PORT_TXDMA_CTRL_MODE_INTER_OFF = 4; 219 | 220 | 221 | 222 | localparam GP_PORT_WR_RXTXDMA_RXOFF = 20; 223 | localparam GP_PORT_WR_RXTXDMA_RXV = 30; 224 | localparam GP_PORT_WR_RXTXDMA_TXV = 31; 225 | 226 | 227 | localparam INT_1PPS = 0; 228 | localparam INT_DMA_TX = 1; 229 | localparam INT_DMA_RX = 2; 230 | localparam INT_RFIC0_SPI = 3; 231 | localparam INT_GPS_UART_TX = 4; 232 | localparam INT_GPS_UART_RX = 5; 233 | localparam INT_SIM_UART_TX = 6; 234 | localparam INT_SIM_UART_RX = 7; 235 | localparam INT_I2C = 8; 236 | localparam INT_NCMD = 9; 237 | 238 | localparam INT_COUNT = 10; 239 | 240 | 241 | localparam INT_PCIE_I_FLAG = 15; 242 | 243 | localparam INT_PCIE_E_NO_RX_DMA_FLOW = 24; 244 | 245 | localparam INT_PCIE_E_OVRD = 30; 246 | localparam INT_PCIE_E_FLAG = 31; 247 | 248 | 249 | //localparam TIMED_COMMANDS 250 | localparam TC_TS_BITS = 30; 251 | localparam TC_ROUTE_BITS = 2; 252 | localparam TC_DATA_BITS = 4; 253 | 254 | 255 | 256 | localparam TC_ROUTE_RX_FRM = 0; 257 | 258 | 259 | localparam RD_TCMDSTAT_FIFOREADY = 5; 260 | 261 | 262 | localparam MCU_CTRL_VALID = 8; 263 | localparam MCU_CTRL_RESET = 9; 264 | localparam MCU_CTRL_SUSP = 10; 265 | localparam MCU_CTRL_REGSEL = 11; 266 | localparam MCU_CTRL_PAGESEL = 16; 267 | 268 | 269 | localparam MCU_STAT_FIFO_EMPTY = 8; 270 | localparam MCU_STAT_CPU_STOP = 9; 271 | localparam MCU_STAT_PC = 10; 272 | 273 | 274 | 275 | --------------------------------------------------------------------------------