File indexing completed on 2025-05-11 08:23:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #ifdef __rtems__
0037 #include <stddef.h>
0038 #include <stdint.h>
0039 #include <i386_io.h>
0040 #else
0041 #include <sys/cdefs.h>
0042 __FBSDID("$FreeBSD$");
0043
0044 #include <sys/param.h>
0045 #include <sys/systm.h>
0046 #include <sys/bus.h>
0047 #include <sys/conf.h>
0048 #include <sys/kernel.h>
0049 #include <sys/module.h>
0050 #include <machine/bus.h>
0051 #include <sys/rman.h>
0052 #include <machine/resource.h>
0053
0054 #include <dev/pci/pcivar.h>
0055
0056 #include <dev/uart/uart.h>
0057 #include <dev/uart/uart_bus.h>
0058
0059 #endif
0060
0061 #define DEFAULT_RCLK 1843200
0062
0063 #ifndef __rtems__
0064 static int uart_pci_probe(device_t dev);
0065
0066 static device_method_t uart_pci_methods[] = {
0067
0068 DEVMETHOD(device_probe, uart_pci_probe),
0069 DEVMETHOD(device_attach, uart_bus_attach),
0070 DEVMETHOD(device_detach, uart_bus_detach),
0071 DEVMETHOD(device_resume, uart_bus_resume),
0072 DEVMETHOD_END
0073 };
0074
0075 static driver_t uart_pci_driver = {
0076 uart_driver_name,
0077 uart_pci_methods,
0078 sizeof(struct uart_softc),
0079 };
0080 #endif
0081
0082 struct pci_id {
0083 uint16_t vendor;
0084 uint16_t device;
0085 uint16_t subven;
0086 uint16_t subdev;
0087 const char *desc;
0088 int rid;
0089 int rclk;
0090 int regshft;
0091 };
0092
0093 static const struct pci_id pci_ns8250_ids[] = {
0094 { 0x1028, 0x0008, 0xffff, 0, "Dell Remote Access Card III", 0x14,
0095 128 * DEFAULT_RCLK },
0096 { 0x1028, 0x0012, 0xffff, 0, "Dell RAC 4 Daughter Card Virtual UART", 0x14,
0097 128 * DEFAULT_RCLK },
0098 { 0x1033, 0x0074, 0x1033, 0x8014, "NEC RCV56ACF 56k Voice Modem", 0x10 },
0099 { 0x1033, 0x007d, 0x1033, 0x8012, "NEC RS232C", 0x10 },
0100 { 0x103c, 0x1048, 0x103c, 0x1227, "HP Diva Serial [GSP] UART - Powerbar SP2",
0101 0x10 },
0102 { 0x103c, 0x1048, 0x103c, 0x1301, "HP Diva RMP3", 0x14 },
0103 { 0x103c, 0x1290, 0xffff, 0, "HP Auxiliary Diva Serial Port", 0x18 },
0104 { 0x103c, 0x3301, 0xffff, 0, "HP iLO serial port", 0x10 },
0105 { 0x11c1, 0x0480, 0xffff, 0, "Agere Systems Venus Modem (V90, 56KFlex)", 0x14 },
0106 { 0x115d, 0x0103, 0xffff, 0, "Xircom Cardbus Ethernet + 56k Modem", 0x10 },
0107 { 0x1282, 0x6585, 0xffff, 0, "Davicom 56PDV PCI Modem", 0x10 },
0108 { 0x12b9, 0x1008, 0xffff, 0, "3Com 56K FaxModem Model 5610", 0x10 },
0109 { 0x131f, 0x1000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x18 },
0110 { 0x131f, 0x1001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x18 },
0111 { 0x131f, 0x1002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x18 },
0112 { 0x131f, 0x2000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x10 },
0113 { 0x131f, 0x2001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x10 },
0114 { 0x131f, 0x2002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x10 },
0115 { 0x135c, 0x0190, 0xffff, 0, "Quatech SSCLP-100", 0x18 },
0116 { 0x135c, 0x01c0, 0xffff, 0, "Quatech SSCLP-200/300", 0x18 },
0117 { 0x135e, 0x7101, 0xffff, 0, "Sealevel Systems Single Port RS-232/422/485/530",
0118 0x18 },
0119 { 0x1407, 0x0110, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port A", 0x10 },
0120 { 0x1407, 0x0111, 0xffff, 0, "Lava Computer mfg DSerial-PCI Port B", 0x10 },
0121 { 0x1407, 0x0510, 0xffff, 0, "Lava SP Serial 550 PCI", 0x10 },
0122 { 0x1409, 0x7168, 0x1409, 0x4025, "Timedia Technology Serial Port", 0x10,
0123 8 * DEFAULT_RCLK },
0124 { 0x1409, 0x7168, 0x1409, 0x4027, "Timedia Technology Serial Port", 0x10,
0125 8 * DEFAULT_RCLK },
0126 { 0x1409, 0x7168, 0x1409, 0x4028, "Timedia Technology Serial Port", 0x10,
0127 8 * DEFAULT_RCLK },
0128 { 0x1409, 0x7168, 0x1409, 0x5025, "Timedia Technology Serial Port", 0x10,
0129 8 * DEFAULT_RCLK },
0130 { 0x1409, 0x7168, 0x1409, 0x5027, "Timedia Technology Serial Port", 0x10,
0131 8 * DEFAULT_RCLK },
0132 { 0x1415, 0x950b, 0xffff, 0, "Oxford Semiconductor OXCB950 Cardbus 16950 UART",
0133 0x10, 16384000 },
0134 { 0x1415, 0xc120, 0xffff, 0, "Oxford Semiconductor OXPCIe952 PCIe 16950 UART",
0135 0x10 },
0136 { 0x14e4, 0x4344, 0xffff, 0, "Sony Ericsson GC89 PC Card", 0x10},
0137 { 0x151f, 0x0000, 0xffff, 0, "TOPIC Semiconductor TP560 56k modem", 0x10 },
0138 { 0x1fd4, 0x1999, 0x1fd4, 0x0001, "Sunix SER5xxxx Serial Port", 0x10,
0139 8 * DEFAULT_RCLK },
0140 { 0x8086, 0x0f0a, 0xffff, 0, "Intel ValleyView LPIO1 HSUART#1", 0x10,
0141 24 * DEFAULT_RCLK, 2 },
0142 { 0x8086, 0x0f0c, 0xffff, 0, "Intel ValleyView LPIO1 HSUART#2", 0x10,
0143 24 * DEFAULT_RCLK, 2 },
0144 { 0x8086, 0x1c3d, 0xffff, 0, "Intel AMT - KT Controller", 0x10 },
0145 { 0x8086, 0x1d3d, 0xffff, 0, "Intel C600/X79 Series Chipset KT Controller", 0x10 },
0146 { 0x8086, 0x2a07, 0xffff, 0, "Intel AMT - PM965/GM965 KT Controller", 0x10 },
0147 { 0x8086, 0x2a47, 0xffff, 0, "Mobile 4 Series Chipset KT Controller", 0x10 },
0148 { 0x8086, 0x2e17, 0xffff, 0, "4 Series Chipset Serial KT Controller", 0x10 },
0149 { 0x8086, 0x3b67, 0xffff, 0, "5 Series/3400 Series Chipset KT Controller",
0150 0x10 },
0151 { 0x8086, 0x8811, 0xffff, 0, "Intel EG20T Serial Port 0", 0x10 },
0152 { 0x8086, 0x8812, 0xffff, 0, "Intel EG20T Serial Port 1", 0x10 },
0153 { 0x8086, 0x8813, 0xffff, 0, "Intel EG20T Serial Port 2", 0x10 },
0154 { 0x8086, 0x8814, 0xffff, 0, "Intel EG20T Serial Port 3", 0x10 },
0155 { 0x8086, 0x8c3d, 0xffff, 0, "Intel Lynx Point KT Controller", 0x10 },
0156 { 0x8086, 0x8cbd, 0xffff, 0, "Intel Wildcat Point KT Controller", 0x10 },
0157 { 0x8086, 0x9c3d, 0xffff, 0, "Intel Lynx Point-LP HECI KT", 0x10 },
0158 { 0x9710, 0x9820, 0x1000, 1, "NetMos NM9820 Serial Port", 0x10 },
0159 { 0x9710, 0x9835, 0x1000, 1, "NetMos NM9835 Serial Port", 0x10 },
0160 { 0x9710, 0x9865, 0xa000, 0x1000, "NetMos NM9865 Serial Port", 0x10 },
0161 { 0x9710, 0x9900, 0xa000, 0x1000,
0162 "MosChip MCS9900 PCIe to Peripheral Controller", 0x10 },
0163 { 0x9710, 0x9901, 0xa000, 0x1000,
0164 "MosChip MCS9901 PCIe to Peripheral Controller", 0x10 },
0165 { 0x9710, 0x9904, 0xa000, 0x1000,
0166 "MosChip MCS9904 PCIe to Peripheral Controller", 0x10 },
0167 { 0x9710, 0x9922, 0xa000, 0x1000,
0168 "MosChip MCS9922 PCIe to Peripheral Controller", 0x10 },
0169 { 0xdeaf, 0x9051, 0xffff, 0, "Middle Digital PC Weasel Serial Port", 0x10 },
0170 { 0xffff, 0, 0xffff, 0, NULL, 0, 0}
0171 };
0172
0173 #ifndef __rtems__
0174 const static struct pci_id *
0175 uart_pci_match(device_t dev, const struct pci_id *id)
0176 {
0177 uint16_t device, subdev, subven, vendor;
0178
0179 vendor = pci_get_vendor(dev);
0180 device = pci_get_device(dev);
0181 while (id->vendor != 0xffff &&
0182 (id->vendor != vendor || id->device != device))
0183 id++;
0184 if (id->vendor == 0xffff)
0185 return (NULL);
0186 if (id->subven == 0xffff)
0187 return (id);
0188 subven = pci_get_subvendor(dev);
0189 subdev = pci_get_subdevice(dev);
0190 while (id->vendor == vendor && id->device == device &&
0191 (id->subven != subven || id->subdev != subdev))
0192 id++;
0193 return ((id->vendor == vendor && id->device == device) ? id : NULL);
0194 }
0195
0196 static int
0197 uart_pci_probe(device_t dev)
0198 {
0199 struct uart_softc *sc;
0200 const struct pci_id *id;
0201 int result;
0202
0203 sc = device_get_softc(dev);
0204
0205 id = uart_pci_match(dev, pci_ns8250_ids);
0206 if (id != NULL) {
0207 sc->sc_class = &uart_ns8250_class;
0208 goto match;
0209 }
0210
0211 return (ENXIO);
0212
0213 match:
0214 result = uart_bus_probe(dev, id->regshft, id->rclk, id->rid, 0);
0215
0216 if (result > 0)
0217 return (result);
0218
0219 if (id->desc)
0220 device_set_desc(dev, id->desc);
0221 return (result);
0222 }
0223
0224 DRIVER_MODULE(uart, pci, uart_pci_driver, uart_devclass, NULL, NULL);
0225 #endif
0226
0227 #ifdef __rtems__
0228
0229 #include <bsp.h>
0230 #include <bsp/bspimpl.h>
0231
0232 #include <stdio.h>
0233 #include <stdlib.h>
0234
0235 #include <libchip/serial.h>
0236 #include <libchip/ns16550.h>
0237 #include <rtems/bspIo.h>
0238 #include <rtems/pci.h>
0239 #include "../../shared/dev/serial/legacy-console.h"
0240
0241 #define MAX_BOARDS 4
0242
0243
0244
0245
0246 typedef struct {
0247 bool found;
0248 const char* desc;
0249 uint32_t base;
0250 uint8_t irq;
0251 uint8_t bus;
0252 uint8_t slot;
0253 int ports;
0254 uint32_t clock;
0255 } port_instance_conf_t;
0256
0257
0258
0259
0260
0261 #define UART_PCI_IO (0)
0262
0263 static uint8_t pci_ns16550_mem_get_register(uintptr_t addr, uint8_t i)
0264 {
0265 uint8_t val = 0;
0266 volatile uint32_t *reg = (volatile uint32_t *)(addr + (i*4));
0267 val = *reg;
0268 if (UART_PCI_IO)
0269 printk( "RD(%p -> 0x%02x) ", reg, val );
0270 return val;
0271 }
0272
0273 static void pci_ns16550_mem_set_register(uintptr_t addr, uint8_t i, uint8_t val)
0274 {
0275 volatile uint32_t *reg = (volatile uint32_t *)(addr + (i*4));
0276 if (UART_PCI_IO)
0277 printk( "WR(%p <- 0x%02x) ", reg, val );
0278 *reg = val;
0279 }
0280
0281
0282
0283
0284 static uint8_t pci_ns16550_io_get_register(uintptr_t addr, uint8_t i)
0285 {
0286 uint8_t val = rtems_inb(addr + i);
0287 if (UART_PCI_IO)
0288 printk( "RD(%p -> 0x%02x) ", (void*) addr + i, val );
0289 return val;
0290 }
0291
0292 static void pci_ns16550_io_set_register(uintptr_t addr, uint8_t i, uint8_t val)
0293 {
0294 if (UART_PCI_IO)
0295 printk( "WR(%p <- 0x%02x) ", (void*) addr + i, val );
0296 rtems_outb(addr + i, val);
0297 }
0298
0299 void pci_uart_probe(void)
0300 {
0301 port_instance_conf_t conf[MAX_BOARDS];
0302 int boards = 0;
0303 int b = 0;
0304 console_tbl *ports;
0305 console_tbl *port_p;
0306 int bus;
0307 int dev;
0308 int fun;
0309 int status;
0310 int instance;
0311 int i;
0312 int total_ports = 0;
0313
0314 for ( b=0 ; b<MAX_BOARDS ; b++ ) {
0315 conf[b].found = false;
0316 }
0317
0318
0319
0320
0321 for ( instance=0 ; instance < MAX_BOARDS ; instance++ ) {
0322
0323 for ( i=0 ; pci_ns8250_ids[i].vendor != 0xffff ; i++ ) {
0324 if ( pci_ns8250_ids[i].vendor == 0xffff ) {
0325 break;
0326 }
0327
0328
0329
0330
0331
0332 status = pci_find_device(
0333 pci_ns8250_ids[i].vendor,
0334 pci_ns8250_ids[i].device,
0335 instance,
0336 &bus,
0337 &dev,
0338 &fun
0339 );
0340 if ( status == PCIB_ERR_SUCCESS ) {
0341 uint8_t irq;
0342 uint32_t base;
0343 bool io;
0344
0345 pci_read_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0, &base );
0346
0347
0348
0349
0350
0351 io = (base & 1) == 1;
0352 if (io || (!io && (((base >> 1) & 3) != 2))) {
0353 boards++;
0354 conf[instance].found = true;
0355 conf[instance].desc = pci_ns8250_ids[i].desc;
0356 conf[instance].clock = pci_ns8250_ids[i].rclk;
0357 conf[instance].ports = 1;
0358 total_ports += conf[instance].ports;
0359
0360 pci_read_config_byte( bus, dev, fun, PCI_INTERRUPT_LINE, &irq );
0361
0362 conf[instance].irq = irq;
0363 conf[instance].base = base;
0364 }
0365 }
0366 }
0367 }
0368
0369
0370
0371
0372 if (boards) {
0373 int device_instance;
0374
0375 ports = calloc( total_ports, sizeof( console_tbl ) );
0376 if (ports != NULL) {
0377 port_p = ports;
0378 device_instance = 1;
0379 for (b = 0; b < MAX_BOARDS; b++) {
0380 uint32_t base = 0;
0381 bool io;
0382 const char* locatable = "";
0383 const char* prefectable = locatable;
0384 char name[32];
0385 if ( conf[b].found == false )
0386 continue;
0387 sprintf( name, "/dev/pcicom%d", device_instance++ );
0388 port_p->sDeviceName = strdup( name );
0389 port_p->deviceType = SERIAL_NS16550;
0390 if ( conf[b].irq <= 15 ) {
0391 port_p->pDeviceFns = &ns16550_fns;
0392 } else {
0393 printk(
0394 "%s IRQ=%d >= 16 requires APIC support, using polling\n",
0395 name,
0396 conf[b].irq
0397 );
0398 port_p->pDeviceFns = &ns16550_fns_polled;
0399 }
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418 io = (conf[b].base & 1) == 1;
0419
0420 if (io) {
0421 base = conf[b].base & 0xfffffffc;
0422 } else {
0423 int loc = (conf[b].base >> 1) & 3;
0424 if (loc == 0) {
0425 base = conf[b].base & 0xfffffff0;
0426 locatable = ",A32";
0427 } else if (loc == 1) {
0428 base = conf[b].base & 0x0000fff0;
0429 locatable = ",A16";
0430 }
0431 prefectable = (conf[b].base & (1 << 3)) == 0 ? ",no-prefech" : ",prefetch";
0432 }
0433
0434 port_p->deviceProbe = NULL;
0435 port_p->pDeviceFlow = NULL;
0436 port_p->ulMargin = 16;
0437 port_p->ulHysteresis = 8;
0438 port_p->pDeviceParams = (void *) 9600;
0439 port_p->ulCtrlPort1 = base;
0440 port_p->ulCtrlPort2 = 0;
0441 port_p->ulDataPort = 0;
0442 if (io) {
0443 port_p->getRegister = pci_ns16550_io_get_register;
0444 port_p->setRegister = pci_ns16550_io_set_register;
0445 } else {
0446 port_p->getRegister = pci_ns16550_mem_get_register;
0447 port_p->setRegister = pci_ns16550_mem_set_register;
0448 }
0449 port_p->getData = NULL;
0450 port_p->setData = NULL;
0451 port_p->ulClock = conf[b].clock;
0452 port_p->ulIntVector = conf[b].irq;
0453
0454
0455 printk(
0456 "%s:%d:%s,%s:0x%lx%s%s,irq:%d,clk:%lu\n",
0457 name, b, conf[b].desc,
0458 io ? "io" : "mem", (uintptr_t) base, locatable, prefectable,
0459 conf[b].irq, (uintptr_t) conf[b].clock
0460 );
0461
0462
0463 port_p++;
0464 }
0465
0466
0467
0468
0469 console_register_devices( ports, total_ports );
0470
0471
0472
0473
0474 }
0475 }
0476 }
0477 #endif