1 /* $NetBSD: cy_pci.c,v 1.22 2007/10/19 12:00:42 ad Exp $ */
6 * Driver for Cyclades Cyclom-8/16/32 multiport serial cards
7 * (currently not tested with Cyclom-32 cards)
12 #include <sys/cdefs.h>
13 __KERNEL_RCSID(0, "$NetBSD: cy_pci.c,v 1.22 2007/10/19 12:00:42 ad Exp $");
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/device.h>
22 #include <dev/pci/pcivar.h>
23 #include <dev/pci/pcireg.h>
24 #include <dev/pci/pcidevs.h>
26 #include <dev/ic/cd1400reg.h>
27 #include <dev/ic/cyreg.h>
28 #include <dev/ic/cyvar.h>
31 struct cy_softc sc_cy
; /* real cy softc */
33 bus_space_tag_t sc_iot
; /* PLX runtime i/o tag */
34 bus_space_handle_t sc_ioh
; /* PLX runtime i/o handle */
37 static const struct cy_pci_product
{
38 pci_product_id_t cp_product
; /* product ID */
39 pcireg_t cp_memtype
; /* memory type */
40 } cy_pci_products
[] = {
41 { PCI_PRODUCT_CYCLADES_CYCLOMY_1
,
42 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT_1M
},
43 { PCI_PRODUCT_CYCLADES_CYCLOM4Y_1
,
44 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT_1M
},
45 { PCI_PRODUCT_CYCLADES_CYCLOM8Y_1
,
46 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT_1M
},
48 { PCI_PRODUCT_CYCLADES_CYCLOMY_2
,
49 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT
},
50 { PCI_PRODUCT_CYCLADES_CYCLOM4Y_2
,
51 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT
},
52 { PCI_PRODUCT_CYCLADES_CYCLOM8Y_2
,
53 PCI_MAPREG_TYPE_MEM
|PCI_MAPREG_MEM_TYPE_32BIT
},
58 static const int cy_pci_nproducts
=
59 sizeof(cy_pci_products
) / sizeof(cy_pci_products
[0]);
61 static const struct cy_pci_product
*
62 cy_pci_lookup(const struct pci_attach_args
*pa
)
64 const struct cy_pci_product
*cp
;
67 if (PCI_VENDOR(pa
->pa_id
) != PCI_VENDOR_CYCLADES
)
70 for (i
= 0; i
< cy_pci_nproducts
; i
++) {
71 cp
= &cy_pci_products
[i
];
72 if (PCI_PRODUCT(pa
->pa_id
) == cp
->cp_product
)
79 cy_pci_match(device_t parent
, cfdata_t match
, void *aux
)
81 struct pci_attach_args
*pa
= aux
;
83 return (cy_pci_lookup(pa
) != NULL
);
87 cy_pci_attach(device_t parent
, device_t self
, void *aux
)
89 struct cy_pci_softc
*psc
= device_private(self
);
90 struct cy_softc
*sc
= &psc
->sc_cy
;
91 struct pci_attach_args
*pa
= aux
;
93 const struct cy_pci_product
*cp
;
99 aprint_naive(": Multi-port serial controller\n");
101 sc
->sc_bustype
= CY_BUSTYPE_PCI
;
103 cp
= cy_pci_lookup(pa
);
105 panic("cy_pci_attach: impossible");
107 aprint_normal(": Cyclades-Y multiport serial\n");
109 if (pci_mapreg_map(pa
, 0x14, PCI_MAPREG_TYPE_IO
, 0,
110 &psc
->sc_iot
, &psc
->sc_ioh
, NULL
, NULL
) != 0) {
111 aprint_error_dev(sc
->sc_dev
, "unable to map PLX registers\n");
115 if (pci_mapreg_map(pa
, 0x18, cp
->cp_memtype
, 0,
116 &sc
->sc_memt
, &sc
->sc_bsh
, NULL
, NULL
) != 0) {
117 aprint_error_dev(sc
->sc_dev
,"unable to map device registers\n");
121 if (cy_find(sc
) == 0) {
122 aprint_error_dev(sc
->sc_dev
, "unable to find CD1400s\n");
127 * XXX Like the Cyclades-Z, we should really check the EEPROM to
128 * determine the "poll or interrupt" setting. For now, we always
129 * map the interrupt and enable it in the PLX.
132 /* Map and establish the interrupt. */
133 if (pci_intr_map(pa
, &ih
) != 0) {
134 aprint_error_dev(sc
->sc_dev
, "unable to map interrupt\n");
137 intrstr
= pci_intr_string(pa
->pa_pc
, ih
);
138 sc
->sc_ih
= pci_intr_establish(pa
->pa_pc
, ih
, IPL_TTY
, cy_intr
, sc
);
139 if (sc
->sc_ih
== NULL
) {
140 aprint_error_dev(sc
->sc_dev
, "unable to establish interrupt");
142 aprint_error(" at %s", intrstr
);
146 aprint_normal_dev(sc
->sc_dev
, "interrupting at %s\n", intrstr
);
150 plx_ver
= bus_space_read_1(sc
->sc_memt
, sc
->sc_bsh
, CY_PLX_VER
) & 0x0f;
152 /* Enable PCI card interrupts */
155 bus_space_write_2(psc
->sc_iot
, psc
->sc_ioh
, CY_PCI_INTENA_9050
,
156 bus_space_read_2(psc
->sc_iot
, psc
->sc_ioh
,
157 CY_PCI_INTENA_9050
) | 0x40);
163 bus_space_write_2(psc
->sc_iot
, psc
->sc_ioh
, CY_PCI_INTENA
,
164 bus_space_read_2(psc
->sc_iot
, psc
->sc_ioh
,
165 CY_PCI_INTENA
) | 0x900);
169 CFATTACH_DECL_NEW(cy_pci
, sizeof(struct cy_pci_softc
),
170 cy_pci_match
, cy_pci_attach
, NULL
, NULL
);