Add support for Oxford PCI Express Expresso family devices.

For these devices, the number of supported ports is read from a register
in BAR 0.

PR:		kern/134878
Submitted by:	David Wood  david of wood2 org uk
MFC after:	1 week
This commit is contained in:
John Baldwin 2011-04-28 19:19:25 +00:00
parent 41b1c25960
commit 6e9f075a26

View File

@ -56,6 +56,7 @@ static puc_config_f puc_config_syba;
static puc_config_f puc_config_siig;
static puc_config_f puc_config_timedia;
static puc_config_f puc_config_titan;
static puc_config_f puc_config_oxford_pcie;
const struct puc_cfg puc_pci_devices[] = {
@ -619,7 +620,7 @@ const struct puc_cfg puc_pci_devices[] = {
* Boards with an Oxford Semiconductor chip.
*
* Oxford Semiconductor provides documentation for their chip at:
* <URL:http://www.oxsemi.com/products/uarts/index.html>
* <URL:http://www.plxtech.com/products/uart/>
*
* As sold by Kouwell <URL:http://www.kouwell.com/>.
* I/O Flex PCI I/O Card Model-223 with 4 serial and 1 parallel ports.
@ -679,6 +680,63 @@ const struct puc_cfg puc_pci_devices[] = {
PUC_PORT_4S, 0x10, 0, 8,
},
/*
* Oxford Semiconductor PCI Express Expresso family
*
* Found in many 'native' PCI Express serial boards such as:
*
* eMegatech MP954ER4 (4 port) and MP958ER8 (8 port)
* <URL:http://www.emegatech.com.tw/pdrs232pcie.html>
*
* Lindy 51189 (4 port)
* <URL:http://www.lindy.com> <URL:http://tinyurl.com/lindy-51189>
*
* StarTech.com PEX4S952 (4 port) and PEX8S952 (8 port)
* <URL:http://www.startech.com>
*/
{ 0x1415, 0xc158, 0xffff, 0,
"Oxford Semiconductor OXPCIe952 UARTs",
DEFAULT_RCLK * 0x22,
PUC_PORT_NONSTANDARD, 0x10, 0, -1,
.config_function = puc_config_oxford_pcie
},
{ 0x1415, 0xc15d, 0xffff, 0,
"Oxford Semiconductor OXPCIe952 UARTs (function 1)",
DEFAULT_RCLK * 0x22,
PUC_PORT_NONSTANDARD, 0x10, 0, -1,
.config_function = puc_config_oxford_pcie
},
{ 0x1415, 0xc208, 0xffff, 0,
"Oxford Semiconductor OXPCIe954 UARTs",
DEFAULT_RCLK * 0x22,
PUC_PORT_NONSTANDARD, 0x10, 0, -1,
.config_function = puc_config_oxford_pcie
},
{ 0x1415, 0xc20d, 0xffff, 0,
"Oxford Semiconductor OXPCIe954 UARTs (function 1)",
DEFAULT_RCLK * 0x22,
PUC_PORT_NONSTANDARD, 0x10, 0, -1,
.config_function = puc_config_oxford_pcie
},
{ 0x1415, 0xc308, 0xffff, 0,
"Oxford Semiconductor OXPCIe958 UARTs",
DEFAULT_RCLK * 0x22,
PUC_PORT_NONSTANDARD, 0x10, 0, -1,
.config_function = puc_config_oxford_pcie
},
{ 0x1415, 0xc30d, 0xffff, 0,
"Oxford Semiconductor OXPCIe958 UARTs (function 1)",
DEFAULT_RCLK * 0x22,
PUC_PORT_NONSTANDARD, 0x10, 0, -1,
.config_function = puc_config_oxford_pcie
},
{ 0x14d2, 0x8010, 0xffff, 0,
"VScom PCI-100L",
DEFAULT_RCLK * 8,
@ -1252,6 +1310,81 @@ puc_config_timedia(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port,
return (ENXIO);
}
static int
puc_config_oxford_pcie(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port,
intptr_t *res)
{
const struct puc_cfg *cfg = sc->sc_cfg;
int idx;
struct puc_bar *bar;
uint8_t value;
switch (cmd) {
case PUC_CFG_SETUP:
device_printf(sc->sc_dev, "%d UARTs detected\n",
sc->sc_nports);
/* Set UARTs to enhanced mode */
bar = puc_get_bar(sc, cfg->rid);
if (bar == NULL)
return (ENXIO);
for (idx = 0; idx < sc->sc_nports; idx++) {
value = bus_read_1(bar->b_res, 0x1000 + (idx << 9)
+ 0x92);
bus_write_1(bar->b_res, 0x1000 + (idx << 9) + 0x92,
value | 0x10);
}
return (0);
case PUC_CFG_GET_LEN:
*res = 0x200;
return (0);
case PUC_CFG_GET_NPORTS:
/*
* Check if we are being called from puc_bfe_attach()
* or puc_bfe_probe(). If puc_bfe_probe(), we cannot
* puc_get_bar(), so we return a value of 16. This has cosmetic
* side-effects at worst; in PUC_CFG_GET_DESC,
* (int)sc->sc_cfg_data will not contain the true number of
* ports in PUC_CFG_GET_DESC, but we are not implementing that
* call for this device family anyway.
*
* The check is for initialisation of sc->sc_bar[idx], which is
* only done in puc_bfe_attach().
*/
idx = 0;
do {
if (sc->sc_bar[idx++].b_rid != -1) {
sc->sc_cfg_data = 16;
*res = sc->sc_cfg_data;
return (0);
}
} while (idx < PUC_PCI_BARS);
bar = puc_get_bar(sc, cfg->rid);
if (bar == NULL)
return (ENXIO);
value = bus_read_1(bar->b_res, 0x04);
if (value == 0)
return (ENXIO);
sc->sc_cfg_data = value;
*res = sc->sc_cfg_data;
return (0);
case PUC_CFG_GET_OFS:
*res = 0x1000 + (port << 9);
return (0);
case PUC_CFG_GET_TYPE:
*res = PUC_TYPE_SERIAL;
return (0);
default:
break;
}
return (ENXIO);
}
static int
puc_config_titan(struct puc_softc *sc, enum puc_cfg_cmd cmd, int port,
intptr_t *res)