[2cc30b0d] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @brief Driver for Exar XR17D15x Multiport UARTs |
---|
| 5 | * |
---|
| 6 | * This driver supports 2, 4 or 8 port Exar parts which are NS16550 |
---|
| 7 | * compatible. |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | /* |
---|
| 11 | * COPYRIGHT (c) 1989-2012. |
---|
| 12 | * On-Line Applications Research Corporation (OAR). |
---|
| 13 | * |
---|
| 14 | * The license and distribution terms for this file may be |
---|
| 15 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 16 | * http://www.rtems.org/license/LICENSE. |
---|
[2cc30b0d] | 17 | */ |
---|
| 18 | |
---|
| 19 | #include <bsp.h> |
---|
| 20 | #include <termios.h> |
---|
| 21 | #include <stdio.h> |
---|
| 22 | #include <stdlib.h> |
---|
| 23 | |
---|
| 24 | #include <rtems/termiostypes.h> |
---|
| 25 | #include <libchip/serial.h> |
---|
| 26 | #include <libchip/ns16550.h> |
---|
| 27 | #include <rtems/bspIo.h> |
---|
| 28 | #include <rtems/pci.h> |
---|
| 29 | #include <bsp/exar17d15x.h> |
---|
| 30 | #include "../../../shared/console_private.h" |
---|
| 31 | |
---|
| 32 | #define MAX_BOARDS 4 |
---|
| 33 | |
---|
| 34 | /* |
---|
| 35 | * This is the rate for the clock internal to the parts. |
---|
| 36 | */ |
---|
| 37 | #define EXAR_CLOCK_RATE (921600*16) |
---|
| 38 | |
---|
| 39 | /* |
---|
| 40 | * Supported PCI Ids |
---|
| 41 | */ |
---|
| 42 | #define PCI_VENDOR_ID_EXAR 0x13A8 |
---|
| 43 | #define PCI_VENDOR_ID_EXAR_XR17D158 0x0158 |
---|
| 44 | #define PCI_VENDOR_ID_EXAR_XR17D154 0x0154 |
---|
| 45 | #define PCI_VENDOR_ID_EXAR_XR17D152 0x0152 |
---|
| 46 | |
---|
| 47 | /* |
---|
| 48 | * Structure to manage each instance found. |
---|
| 49 | */ |
---|
| 50 | typedef struct { |
---|
| 51 | uint16_t vendor; |
---|
| 52 | uint16_t device; |
---|
| 53 | uint8_t ports; |
---|
| 54 | } exar_parts_t; |
---|
| 55 | |
---|
| 56 | static exar_parts_t Supported[] = { |
---|
| 57 | { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D158, 8 }, |
---|
| 58 | { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D154, 4 }, |
---|
| 59 | { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D152, 2 }, |
---|
| 60 | { 0, 0, 0 } |
---|
| 61 | }; |
---|
| 62 | |
---|
| 63 | /* |
---|
| 64 | * Information saved from PCI scan |
---|
| 65 | */ |
---|
| 66 | typedef struct { |
---|
| 67 | bool found; |
---|
| 68 | uint32_t base; |
---|
| 69 | uint8_t irq; |
---|
| 70 | uint8_t bus; |
---|
| 71 | uint8_t slot; |
---|
| 72 | uint8_t ports; |
---|
| 73 | } exar17d15x_conf_t; |
---|
| 74 | |
---|
| 75 | /* |
---|
| 76 | * Register Access Routines |
---|
| 77 | */ |
---|
| 78 | static uint8_t xr17d15x_get_register(uint32_t addr, uint8_t i) |
---|
| 79 | { |
---|
| 80 | uint8_t val = 0; |
---|
| 81 | volatile uint8_t *reg = (volatile uint8_t *)(addr + i); |
---|
| 82 | |
---|
| 83 | val = *reg; |
---|
| 84 | // printk( "RD %p -> 0x%02x\n", reg, val ); |
---|
| 85 | return val; |
---|
| 86 | } |
---|
| 87 | |
---|
| 88 | static void xr17d15x_set_register(uint32_t addr, uint8_t i, uint8_t val) |
---|
| 89 | { |
---|
| 90 | volatile uint8_t *reg = (volatile uint8_t *)(addr + i); |
---|
| 91 | |
---|
| 92 | // printk( "WR %p <- 0x%02x\n", reg, val ); |
---|
| 93 | *reg = val; |
---|
| 94 | } |
---|
| 95 | |
---|
| 96 | rtems_device_driver exar17d15x_initialize( |
---|
| 97 | rtems_device_major_number major, |
---|
| 98 | rtems_device_minor_number minor_arg, |
---|
| 99 | void *arg |
---|
| 100 | ) |
---|
| 101 | { |
---|
| 102 | // int pbus, pdev, pfun; |
---|
| 103 | exar17d15x_conf_t conf[MAX_BOARDS]; |
---|
| 104 | int boards = 0; |
---|
| 105 | int b = 0; |
---|
| 106 | int p; |
---|
| 107 | console_tbl *ports; |
---|
| 108 | console_tbl *port_p; |
---|
| 109 | int pbus; |
---|
| 110 | int pdev; |
---|
| 111 | int pfun; |
---|
| 112 | int status; |
---|
| 113 | int instance; |
---|
| 114 | int i; |
---|
| 115 | int total_ports = 0; |
---|
| 116 | |
---|
| 117 | for ( b=0 ; b<MAX_BOARDS ; b++ ) { |
---|
| 118 | conf[b].found = false; |
---|
| 119 | } |
---|
| 120 | |
---|
| 121 | /* |
---|
| 122 | * Scan for Serial port boards |
---|
| 123 | * |
---|
| 124 | * NOTE: There appear to be Exar parts with 2 and 4 ports which would |
---|
| 125 | * be easy to support. Just change the hard-coded 8 ports per |
---|
| 126 | * board to variable and adjust. |
---|
| 127 | * |
---|
| 128 | * NOTE: There are likely other board vendors which could be supported |
---|
| 129 | * by this. |
---|
| 130 | */ |
---|
| 131 | for ( instance=0 ; instance < MAX_BOARDS ; instance++ ) { |
---|
| 132 | |
---|
| 133 | for ( i=0 ; Supported[i].ports != 0 ; i++ ) { |
---|
| 134 | status = pci_find_device( |
---|
| 135 | Supported[i].vendor, |
---|
| 136 | Supported[i].device, |
---|
| 137 | instance, |
---|
| 138 | &pbus, |
---|
| 139 | &pdev, |
---|
| 140 | &pfun |
---|
| 141 | ); |
---|
| 142 | if ( status == PCIB_ERR_SUCCESS ) { |
---|
| 143 | boards++; |
---|
| 144 | conf[instance].found = true; |
---|
| 145 | conf[instance].ports = Supported[i].ports; |
---|
| 146 | total_ports += conf[instance].ports; |
---|
| 147 | break; |
---|
| 148 | } |
---|
| 149 | } |
---|
| 150 | |
---|
| 151 | if ( status != PCIB_ERR_SUCCESS ) |
---|
| 152 | continue; |
---|
| 153 | |
---|
| 154 | pci_read_config_byte( |
---|
| 155 | pbus, |
---|
| 156 | pdev, |
---|
| 157 | pfun, |
---|
| 158 | PCI_INTERRUPT_LINE, |
---|
| 159 | &conf[instance].irq |
---|
| 160 | ); |
---|
| 161 | pci_read_config_dword( |
---|
| 162 | pbus, |
---|
| 163 | pdev, |
---|
| 164 | pfun, |
---|
| 165 | PCI_BASE_ADDRESS_0, |
---|
| 166 | &conf[instance].base |
---|
| 167 | ); |
---|
| 168 | printk( |
---|
| 169 | "Found Exar 17D15x %d at 0x%08x IRQ %d with %d ports\n", |
---|
| 170 | instance, |
---|
| 171 | conf[instance].base, |
---|
| 172 | conf[instance].irq, |
---|
| 173 | conf[instance].ports |
---|
| 174 | ); |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | /* |
---|
| 178 | * Now allocate array of device structures and fill them in |
---|
| 179 | */ |
---|
| 180 | ports = calloc( total_ports, sizeof( console_tbl ) ); |
---|
| 181 | port_p = ports; |
---|
| 182 | for ( b=0 ; b<MAX_BOARDS ; b++ ) { |
---|
| 183 | if ( conf[b].found == false ) |
---|
| 184 | continue; |
---|
| 185 | for ( p=0 ; p<conf[b].ports ; p++ ) { |
---|
| 186 | char name[32]; |
---|
| 187 | |
---|
| 188 | sprintf( name, "/dev/exar17d15x_%d_%d", b, p ); |
---|
| 189 | //printk("Found %s\n", name ); |
---|
| 190 | port_p->sDeviceName = strdup( name ); |
---|
| 191 | port_p->deviceType = SERIAL_NS16550; |
---|
| 192 | #if 1 |
---|
| 193 | port_p->pDeviceFns = &ns16550_fns_polled; |
---|
| 194 | #else |
---|
| 195 | port_p->pDeviceFns = &ns16550_fns; |
---|
| 196 | #endif |
---|
| 197 | |
---|
| 198 | port_p->deviceProbe = NULL; |
---|
| 199 | port_p->pDeviceFlow = NULL; |
---|
| 200 | port_p->ulMargin = 16; |
---|
| 201 | port_p->ulHysteresis = 8; |
---|
| 202 | port_p->pDeviceParams = (void *) 9600; |
---|
| 203 | port_p->ulCtrlPort1 = conf[b].base + (p * 0x0200); |
---|
| 204 | port_p->ulCtrlPort2 = 0; /* NA */ |
---|
| 205 | port_p->ulDataPort = 0; /* NA */ |
---|
| 206 | port_p->getRegister = xr17d15x_get_register; |
---|
| 207 | port_p->setRegister = xr17d15x_set_register; |
---|
| 208 | port_p->getData = NULL; /* NA */ |
---|
| 209 | port_p->setData = NULL; /* NA */ |
---|
| 210 | port_p->ulClock = EXAR_CLOCK_RATE; |
---|
| 211 | port_p->ulIntVector = conf[b].irq; |
---|
| 212 | |
---|
| 213 | port_p++; |
---|
| 214 | } /* end ports */ |
---|
| 215 | } /* end boards */ |
---|
| 216 | |
---|
| 217 | /* |
---|
| 218 | * Register the devices |
---|
| 219 | */ |
---|
| 220 | if ( boards ) |
---|
| 221 | console_register_devices( ports, total_ports ); |
---|
| 222 | |
---|
| 223 | return RTEMS_SUCCESSFUL; |
---|
| 224 | } |
---|