1*74fc44eeSmsaitoh /* $NetBSD: puccn.c,v 1.14 2014/03/05 05:56:04 msaitoh Exp $ */
2fa8ff381Sjeffs
3fa8ff381Sjeffs /*
4fa8ff381Sjeffs * Derived from pci.c
5fa8ff381Sjeffs * Copyright (c) 2000 Geocast Networks Systems. All rights reserved.
6fa8ff381Sjeffs *
7fa8ff381Sjeffs * Copyright (c) 1995, 1996, 1997, 1998
8fa8ff381Sjeffs * Christopher G. Demetriou. All rights reserved.
9fa8ff381Sjeffs * Copyright (c) 1994 Charles M. Hannum. All rights reserved.
10fa8ff381Sjeffs *
11fa8ff381Sjeffs * Redistribution and use in source and binary forms, with or without
12fa8ff381Sjeffs * modification, are permitted provided that the following conditions
13fa8ff381Sjeffs * are met:
14fa8ff381Sjeffs * 1. Redistributions of source code must retain the above copyright
15fa8ff381Sjeffs * notice, this list of conditions and the following disclaimer.
16fa8ff381Sjeffs * 2. Redistributions in binary form must reproduce the above copyright
17fa8ff381Sjeffs * notice, this list of conditions and the following disclaimer in the
18fa8ff381Sjeffs * documentation and/or other materials provided with the distribution.
19fa8ff381Sjeffs * 3. All advertising materials mentioning features or use of this software
20fa8ff381Sjeffs * must display the following acknowledgement:
21fa8ff381Sjeffs * This product includes software developed by Charles M. Hannum.
22fa8ff381Sjeffs * 4. The name of the author may not be used to endorse or promote products
23fa8ff381Sjeffs * derived from this software without specific prior written permission.
24fa8ff381Sjeffs *
25fa8ff381Sjeffs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26fa8ff381Sjeffs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27fa8ff381Sjeffs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28fa8ff381Sjeffs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29fa8ff381Sjeffs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30fa8ff381Sjeffs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31fa8ff381Sjeffs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32fa8ff381Sjeffs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33fa8ff381Sjeffs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34fa8ff381Sjeffs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35fa8ff381Sjeffs */
36fa8ff381Sjeffs
37fa8ff381Sjeffs
38fa8ff381Sjeffs /*
39fa8ff381Sjeffs * Machine independent support for PCI serial console support.
40fa8ff381Sjeffs *
41fa8ff381Sjeffs * Scan the PCI bus for something which resembles a 16550
42fa8ff381Sjeffs */
43fa8ff381Sjeffs
449048aaaeSlukem #include <sys/cdefs.h>
45*74fc44eeSmsaitoh __KERNEL_RCSID(0, "$NetBSD: puccn.c,v 1.14 2014/03/05 05:56:04 msaitoh Exp $");
469048aaaeSlukem
47d84d2c6cSlukem #include "opt_kgdb.h"
48d84d2c6cSlukem
49fa8ff381Sjeffs #include <sys/param.h>
50fa8ff381Sjeffs #include <sys/systm.h>
51fa8ff381Sjeffs #include <sys/conf.h>
52fa8ff381Sjeffs #include <sys/device.h>
53fa8ff381Sjeffs
54fa8ff381Sjeffs #include <dev/pci/pcireg.h>
55fa8ff381Sjeffs #include <dev/pci/pcivar.h>
56fa8ff381Sjeffs #include <dev/pci/pcidevs.h>
57fa8ff381Sjeffs
58fa8ff381Sjeffs #include <sys/termios.h>
59fa8ff381Sjeffs #include <dev/ic/comreg.h>
60fa8ff381Sjeffs #include <dev/ic/comvar.h>
61fa8ff381Sjeffs
62fa8ff381Sjeffs #include <dev/cons.h>
63fa8ff381Sjeffs
64fa8ff381Sjeffs #include <dev/pci/pucvar.h>
65fa8ff381Sjeffs #include <dev/pci/puccn.h>
66fa8ff381Sjeffs
67fa8ff381Sjeffs #ifndef CONSPEED
68fa8ff381Sjeffs #define CONSPEED TTYDEF_SPEED
69fa8ff381Sjeffs #endif
70fa8ff381Sjeffs #ifndef CONMODE
71fa8ff381Sjeffs #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE|CSTOPB|PARENB))|CS8) /* 8N1 */
72fa8ff381Sjeffs #endif
73fa8ff381Sjeffs
74fa8ff381Sjeffs cons_decl(com);
75fa8ff381Sjeffs
76fa8ff381Sjeffs static bus_addr_t puccnbase;
77fa8ff381Sjeffs static bus_space_tag_t puctag;
78e4bf50ceSmsaitoh static int puccnflags;
79fa8ff381Sjeffs
80fa8ff381Sjeffs #ifdef KGDB
81fa8ff381Sjeffs static bus_addr_t pucgdbbase;
82fa8ff381Sjeffs #endif
83fa8ff381Sjeffs
84fa8ff381Sjeffs /*
85fa8ff381Sjeffs * Static dev/func variables allow pucprobe to be called multiple times,
86fa8ff381Sjeffs * resuming the search where it left off, never retrying the same adaptor.
87fa8ff381Sjeffs */
88fa8ff381Sjeffs
89fa8ff381Sjeffs static bus_addr_t
pucprobe_doit(struct consdev * cn)90fa8ff381Sjeffs pucprobe_doit(struct consdev *cn)
91fa8ff381Sjeffs {
92fa8ff381Sjeffs struct pci_attach_args pa;
93fa8ff381Sjeffs int bus;
94fa8ff381Sjeffs static int dev = 0, func = 0;
9578cbf1e0Scube int maxdev, nfunctions = 0, i; /* XXX */
9678cbf1e0Scube pcireg_t reg, bhlcr, subsys = 0; /* XXX */
97fa8ff381Sjeffs int foundport = 0;
98fa8ff381Sjeffs const struct puc_device_description *desc;
99fa8ff381Sjeffs pcireg_t base;
100fa8ff381Sjeffs
101fa8ff381Sjeffs /* Fetch our tags */
1024f699800Ssoren #if defined(amd64) || defined(i386)
103e4bf50ceSmsaitoh if (cpu_puc_cnprobe(cn, &pa) != 0)
1044f699800Ssoren #endif
105fa8ff381Sjeffs return 0;
1064f699800Ssoren
107fa8ff381Sjeffs pci_decompose_tag(pa.pa_pc, pa.pa_tag, &bus, &maxdev, NULL);
108fa8ff381Sjeffs
1094317f499Smsaitoh /* Scan through devices and find a communication class device. */
110fa8ff381Sjeffs for (; dev <= maxdev ; dev++) {
111fa8ff381Sjeffs pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, 0);
112fa8ff381Sjeffs reg = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_ID_REG);
113fa8ff381Sjeffs if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID
114fa8ff381Sjeffs || PCI_VENDOR(reg) == 0)
115fa8ff381Sjeffs continue;
116fa8ff381Sjeffs bhlcr = pci_conf_read(pa.pa_pc, pa.pa_tag, PCI_BHLC_REG);
117fa8ff381Sjeffs if (PCI_HDRTYPE_MULTIFN(bhlcr)) {
118fa8ff381Sjeffs nfunctions = 8;
119fa8ff381Sjeffs } else {
120fa8ff381Sjeffs nfunctions = 1;
121fa8ff381Sjeffs }
122fa8ff381Sjeffs resume_scan:
123fa8ff381Sjeffs for (; func < nfunctions; func++) {
124fa8ff381Sjeffs pa.pa_tag = pci_make_tag(pa.pa_pc, bus, dev, func);
125*74fc44eeSmsaitoh reg = pci_conf_read(pa.pa_pc, pa.pa_tag,
126*74fc44eeSmsaitoh PCI_CLASS_REG);
127fa8ff381Sjeffs if (PCI_CLASS(reg) == PCI_CLASS_COMMUNICATIONS
128fa8ff381Sjeffs && PCI_SUBCLASS(reg)
129fa8ff381Sjeffs == PCI_SUBCLASS_COMMUNICATIONS_SERIAL) {
130*74fc44eeSmsaitoh pa.pa_id = pci_conf_read(pa.pa_pc, pa.pa_tag,
131*74fc44eeSmsaitoh PCI_ID_REG);
132fa8ff381Sjeffs subsys = pci_conf_read(pa.pa_pc, pa.pa_tag,
133fa8ff381Sjeffs PCI_SUBSYS_ID_REG);
134fa8ff381Sjeffs foundport = 1;
135fa8ff381Sjeffs break;
136fa8ff381Sjeffs }
137fa8ff381Sjeffs }
138fa8ff381Sjeffs if (foundport)
139fa8ff381Sjeffs break;
140fa8ff381Sjeffs
141fa8ff381Sjeffs func = 0;
142fa8ff381Sjeffs }
1434317f499Smsaitoh
1444317f499Smsaitoh /*
1454317f499Smsaitoh * If all devices was scanned and couldn't find any communication
1464317f499Smsaitoh * device, return with 0.
1474317f499Smsaitoh */
148fa8ff381Sjeffs if (!foundport)
149fa8ff381Sjeffs return 0;
150e4bf50ceSmsaitoh
151e4bf50ceSmsaitoh /* Clear foundport flag */
152fa8ff381Sjeffs foundport = 0;
153fa8ff381Sjeffs
1544317f499Smsaitoh /* Check whether the device is in the puc device table or not */
155fa8ff381Sjeffs desc = puc_find_description(PCI_VENDOR(pa.pa_id),
156fa8ff381Sjeffs PCI_PRODUCT(pa.pa_id), PCI_VENDOR(subsys), PCI_PRODUCT(subsys));
1574317f499Smsaitoh
1584317f499Smsaitoh /* If not, check the next communication device */
159fa8ff381Sjeffs if (desc == NULL) {
1604317f499Smsaitoh /* Resume from the next function */
161fa8ff381Sjeffs func++;
162fa8ff381Sjeffs goto resume_scan;
163fa8ff381Sjeffs }
164fa8ff381Sjeffs
1654317f499Smsaitoh /*
1664317f499Smsaitoh * We found a device and it's on the puc table. Set the tag and
1674317f499Smsaitoh * the base address.
1684317f499Smsaitoh */
169*74fc44eeSmsaitoh for (i = 0; PUC_PORT_VALID(desc, i); i++) {
170fa8ff381Sjeffs if (desc->ports[i].type != PUC_PORT_TYPE_COM)
171fa8ff381Sjeffs continue;
172e4bf50ceSmsaitoh puccnflags = desc->ports[i].flags;
173fa8ff381Sjeffs base = pci_conf_read(pa.pa_pc, pa.pa_tag, desc->ports[i].bar);
174fa8ff381Sjeffs base += desc->ports[i].offset;
175fa8ff381Sjeffs
176e4bf50ceSmsaitoh if (PCI_MAPREG_TYPE(base) == PCI_MAPREG_TYPE_IO) {
177e4bf50ceSmsaitoh puctag = pa.pa_iot;
178fa8ff381Sjeffs base = PCI_MAPREG_IO_ADDR(base);
179e4bf50ceSmsaitoh }
180e4bf50ceSmsaitoh #if 0 /* For MMIO device */
181e4bf50ceSmsaitoh else {
182e4bf50ceSmsaitoh puctag = pa.pa_memt;
183e4bf50ceSmsaitoh base = PCI_MAPREG_MEM_ADDR(base);
184e4bf50ceSmsaitoh }
185e4bf50ceSmsaitoh #endif
186e4bf50ceSmsaitoh
187fa8ff381Sjeffs if (com_is_console(puctag, base, NULL))
188fa8ff381Sjeffs continue;
189fa8ff381Sjeffs foundport = 1;
190fa8ff381Sjeffs break;
191fa8ff381Sjeffs }
192fa8ff381Sjeffs
193fa8ff381Sjeffs if (foundport == 0) {
194fa8ff381Sjeffs func++;
195fa8ff381Sjeffs goto resume_scan;
196fa8ff381Sjeffs }
197fa8ff381Sjeffs
198e4bf50ceSmsaitoh #if 0
199fa8ff381Sjeffs cn->cn_pri = CN_REMOTE;
200e4bf50ceSmsaitoh #else
201e4bf50ceSmsaitoh if (cn)
202e4bf50ceSmsaitoh cn->cn_pri = CN_REMOTE;
203e4bf50ceSmsaitoh #endif
204e4bf50ceSmsaitoh return base;
205fa8ff381Sjeffs }
206fa8ff381Sjeffs
207fa8ff381Sjeffs #ifdef KGDB
208fa8ff381Sjeffs void
puc_gdbprobe(struct consdev * cn)209*74fc44eeSmsaitoh puc_gdbprobe(struct consdev *cn)
210fa8ff381Sjeffs {
2114317f499Smsaitoh
212fa8ff381Sjeffs pucgdbbase = pucprobe_doit(cn);
213fa8ff381Sjeffs }
214fa8ff381Sjeffs
215fa8ff381Sjeffs void
puc_gdbinit(struct consdev * cn)216*74fc44eeSmsaitoh puc_gdbinit(struct consdev *cn)
217fa8ff381Sjeffs {
2184317f499Smsaitoh
2194317f499Smsaitoh if (pucgdbbase == 0)
220fa8ff381Sjeffs return;
2214317f499Smsaitoh
2220eff6718Sthorpej com_kgdb_attach(puctag, pucgdbbase, CONSPEED, COM_FREQ,
2230eff6718Sthorpej COM_TYPE_NORMAL, CONMODE);
224fa8ff381Sjeffs }
225fa8ff381Sjeffs #endif
226fa8ff381Sjeffs
227fa8ff381Sjeffs void
puc_cnprobe(struct consdev * cn)228e4bf50ceSmsaitoh puc_cnprobe(struct consdev *cn)
229fa8ff381Sjeffs {
2304317f499Smsaitoh
231fa8ff381Sjeffs puccnbase = pucprobe_doit(cn);
232fa8ff381Sjeffs }
233fa8ff381Sjeffs
234e4bf50ceSmsaitoh int
puc_cninit(struct consdev * cn)235e4bf50ceSmsaitoh puc_cninit(struct consdev *cn)
236fa8ff381Sjeffs {
2374317f499Smsaitoh
238e4bf50ceSmsaitoh if (puccnbase == 0)
239e4bf50ceSmsaitoh return -1;
240e4bf50ceSmsaitoh
241e4bf50ceSmsaitoh return comcnattach(puctag, puccnbase, CONSPEED,
242e4bf50ceSmsaitoh puccnflags & PUC_COM_CLOCKMASK, COM_TYPE_NORMAL,
2430eff6718Sthorpej CONMODE);
244fa8ff381Sjeffs }
245fa8ff381Sjeffs
246fa8ff381Sjeffs /* comcngetc, comcnputc, comcnpollc provided by dev/ic/com.c */
247