Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:40

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief Driver for Exar XR17D15x Multiport UARTs
0007  *
0008  * This driver supports 2, 4 or 8 port Exar parts which are NS16550
0009  * compatible.
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 1989-2012.
0014  *  On-Line Applications Research Corporation (OAR).
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #include <bsp.h>
0039 #include <termios.h>
0040 #include <stdio.h>
0041 #include <stdlib.h>
0042 
0043 #include <rtems/termiostypes.h>
0044 #include <libchip/serial.h>
0045 #include <libchip/ns16550.h>
0046 #include <rtems/bspIo.h>
0047 #include <rtems/pci.h>
0048 #include <bsp/exar17d15x.h>
0049 #include "../../shared/dev/serial/legacy-console.h"
0050 
0051 #define MAX_BOARDS 4
0052 
0053 /*
0054  *  This is the rate for the clock internal to the parts.
0055  */
0056 #define EXAR_CLOCK_RATE  (921600*16)
0057 
0058 /*
0059  *  Supported PCI Ids
0060  */
0061 #define PCI_VENDOR_ID_EXAR 0x13A8
0062 #define PCI_VENDOR_ID_EXAR_XR17D158 0x0158
0063 #define PCI_VENDOR_ID_EXAR_XR17D154 0x0154
0064 #define PCI_VENDOR_ID_EXAR_XR17D152 0x0152
0065 
0066 /*
0067  * Structure to manage each instance found.
0068  */
0069 typedef struct {
0070   uint16_t  vendor;
0071   uint16_t  device;
0072   uint8_t   ports;
0073 } exar_parts_t;
0074 
0075 static exar_parts_t Supported[] = {
0076   { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D158, 8 },
0077   { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D154, 4 },
0078   { PCI_VENDOR_ID_EXAR, PCI_VENDOR_ID_EXAR_XR17D152, 2 },
0079   { 0, 0, 0 }
0080 };
0081 
0082 /*
0083  * Information saved from PCI scan
0084  */
0085 typedef struct {
0086   bool      found;
0087   uint32_t  base;
0088   uint8_t   irq;
0089   uint8_t   bus;
0090   uint8_t   slot;
0091   uint8_t   ports;
0092 } exar17d15x_conf_t;
0093 
0094 /*
0095  *  Register Access Routines
0096  */
0097 static uint8_t xr17d15x_get_register(uintptr_t addr, uint8_t i)
0098 {
0099   uint8_t          val = 0;
0100   volatile uint8_t *reg = (volatile uint8_t *)(addr + i);
0101 
0102   val = *reg;
0103   // printk( "RD %p -> 0x%02x\n", reg, val );
0104   return val;
0105 }
0106 
0107 static void xr17d15x_set_register(uintptr_t addr, uint8_t i, uint8_t val)
0108 {
0109   volatile uint8_t *reg = (volatile uint8_t *)(addr + i);
0110 
0111   // printk( "WR %p <- 0x%02x\n", reg, val );
0112   *reg = val;
0113 }
0114 
0115 rtems_device_driver exar17d15x_initialize(
0116   rtems_device_major_number  major,
0117   rtems_device_minor_number  minor_arg,
0118   void                      *arg
0119 )
0120 {
0121   // int  pbus, pdev, pfun;
0122   exar17d15x_conf_t  conf[MAX_BOARDS];
0123   int              boards = 0;
0124   int              b = 0;
0125   int              p;
0126   console_tbl     *ports;
0127   console_tbl     *port_p;
0128   int              pbus;
0129   int              pdev;
0130   int              pfun;
0131   int              status;
0132   int              instance;
0133   int              i;
0134   int              total_ports = 0;
0135 
0136   for ( b=0 ; b<MAX_BOARDS ; b++ ) {
0137     conf[b].found = false;
0138   }
0139 
0140   /*
0141    *  Scan for Serial port boards
0142    *
0143    *  NOTE: There appear to be Exar parts with 2 and 4 ports which would
0144    *        be easy to support.  Just change the hard-coded 8 ports per
0145    *        board to variable and adjust.
0146    *
0147    *  NOTE: There are likely other board vendors which could be supported
0148    *        by this.
0149    */
0150   for ( instance=0 ; instance < MAX_BOARDS ; instance++ ) {
0151 
0152     for ( i=0 ; Supported[i].ports != 0 ; i++ ) {
0153       status = pci_find_device(
0154         Supported[i].vendor,
0155         Supported[i].device,
0156         instance,
0157         &pbus,
0158         &pdev,
0159         &pfun
0160       );
0161       if ( status == PCIB_ERR_SUCCESS ) {
0162         boards++;
0163         conf[instance].found = true;
0164         conf[instance].ports = Supported[i].ports;
0165         total_ports += conf[instance].ports;
0166         break;
0167       }
0168     }
0169 
0170     if ( status != PCIB_ERR_SUCCESS )
0171       continue;
0172 
0173     pci_read_config_byte(
0174       pbus,
0175       pdev,
0176       pfun,
0177       PCI_INTERRUPT_LINE,
0178       &conf[instance].irq
0179     );
0180     pci_read_config_dword(
0181       pbus,
0182       pdev,
0183       pfun,
0184       PCI_BASE_ADDRESS_0,
0185       &conf[instance].base
0186     );
0187     printk(
0188       "Found Exar 17D15x %d at 0x%08lx IRQ %d with %d ports\n",
0189       instance,
0190       (uintptr_t) conf[instance].base,
0191       conf[instance].irq,
0192       conf[instance].ports
0193     );
0194   }
0195 
0196   /*
0197    *  Now allocate array of device structures and fill them in
0198    */
0199   ports = calloc( total_ports, sizeof( console_tbl ) );
0200   port_p = ports;
0201   for ( b=0 ; b<MAX_BOARDS ; b++ ) {
0202     if ( conf[b].found == false )
0203       continue;
0204     for ( p=0 ; p<conf[b].ports ; p++ ) {
0205       char name[32];
0206 
0207       sprintf( name, "/dev/exar17d15x_%d_%d", b, p );
0208       //printk("Found %s\n", name );
0209       port_p->sDeviceName   = strdup( name );
0210       port_p->deviceType    = SERIAL_NS16550;
0211       #if 1
0212         port_p->pDeviceFns    = &ns16550_fns_polled;
0213       #else
0214         port_p->pDeviceFns    = &ns16550_fns;
0215       #endif
0216 
0217       port_p->deviceProbe   = NULL;
0218       port_p->pDeviceFlow   = NULL;
0219       port_p->ulMargin      = 16;
0220       port_p->ulHysteresis  = 8;
0221       port_p->pDeviceParams = (void *) 9600;
0222       port_p->ulCtrlPort1   = conf[b].base + (p * 0x0200);
0223       port_p->ulCtrlPort2   = 0;                   /* NA */
0224       port_p->ulDataPort    = 0;                   /* NA */
0225       port_p->getRegister   = xr17d15x_get_register;
0226       port_p->setRegister   = xr17d15x_set_register;
0227       port_p->getData       = NULL;                /* NA */
0228       port_p->setData       = NULL;                /* NA */
0229       port_p->ulClock       = EXAR_CLOCK_RATE;
0230       port_p->ulIntVector   = conf[b].irq;
0231 
0232       port_p++;
0233     }  /* end ports */
0234   }    /* end boards */
0235 
0236   /*
0237    *  Register the devices
0238    */
0239   if ( boards )
0240     console_register_devices( ports, total_ports );
0241 
0242   return RTEMS_SUCCESSFUL;
0243 }