1 /* $NetBSD: cpc700.c,v 1.15 2009/05/12 12:15:37 cegger Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at Sandburst Corp.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * The IBM CPC700 is a bridge chip for the PowerPC. It contains
36 * - PCI bus master & slave controller
37 * - interrupt controller
42 * This driver handles the overall device and enumeration of the
43 * supported subdevices. NetBSD knows how to handle:
45 * - interrupt controller
47 * Skeleton drivers are provided for the timer and IIC.
49 * XXX This driver assumes that there is only one instance of it.
52 #include <sys/cdefs.h>
53 __KERNEL_RCSID(0, "$NetBSD: cpc700.c,v 1.15 2009/05/12 12:15:37 cegger Exp $");
58 #include <sys/param.h>
59 #include <sys/extent.h>
60 #include <sys/device.h>
61 #include <sys/malloc.h>
62 #include <sys/systm.h>
67 #include <dev/pci/pcivar.h>
68 #include <dev/pci/pcireg.h>
69 #include <dev/pci/pciconf.h>
71 #include <dev/ic/cpc700reg.h>
72 #include <dev/ic/cpc700var.h>
73 #include <dev/ic/cpc700uic.h>
76 struct pcibus_attach_args pba
;
77 struct cpcbus_attach_args cba
;
82 cpc_attach(device_t self
, pci_chipset_tag_t pc
, bus_space_tag_t mem
,
83 bus_space_tag_t pciio
, bus_dma_tag_t tag
, int attachpci
,
86 static bus_space_tag_t the_cpc_tag
;
87 static bus_space_handle_t the_cpc_handle
;
88 #define INL(a) bus_space_read_stream_4(the_cpc_tag, the_cpc_handle, (a))
89 #define OUTL(a, d) bus_space_write_stream_4(the_cpc_tag, the_cpc_handle, (a), d)
92 cpc_print(void *aux
, const char *pnp
)
94 struct cpcbus_attach_args
*caa
= aux
;
97 aprint_normal("%s at %s", caa
->cpca_name
, pnp
);
99 aprint_normal(" addr 0x%08x", caa
->cpca_addr
);
100 if (caa
->cpca_irq
!= CPCBUSCF_IRQ_DEFAULT
)
101 aprint_normal(" irq %d", caa
->cpca_irq
);
107 cpc_submatch(device_t parent
, cfdata_t cf
,
108 const int *ldesc
, void *aux
)
110 struct cpcbus_attach_args
*caa
= aux
;
112 if (cf
->cf_loc
[CPCBUSCF_ADDR
] != caa
->cpca_addr
)
115 return (config_match(parent
, cf
, aux
));
122 cpc_attach(device_t self
, pci_chipset_tag_t pc
, bus_space_tag_t mem
,
123 bus_space_tag_t pciio
, bus_dma_tag_t dma
, int attachpci
,
126 union attach_args aa
;
136 { "com", CPC_COM0
, CPC_IB_UART_0
},
137 { "com", CPC_COM1
, CPC_IB_UART_1
},
138 { "cpctim", CPC_TIMER
, CPCBUSCF_IRQ_DEFAULT
},
139 { "cpciic", CPC_IIC0
, CPC_IB_IIC_0
},
140 { "cpciic", CPC_IIC1
, CPC_IB_IIC_1
},
143 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
144 struct extent
*ioext
, *memext
;
145 #ifdef PCI_CONFIGURE_VERBOSE
146 extern int pci_conf_debug
;
152 printf(": IBM CPC700\n");
155 if (bus_space_map(mem
, CPC_UIC_BASE
, CPC_UIC_SIZE
, 0,
157 aprint_error_dev(self
, "can't map i/o space\n");
161 aa
.cba
.cpca_tag
= mem
;
162 aa
.cba
.cpca_freq
= freq
;
163 for (i
= 0; devs
[i
].name
; i
++) {
164 aa
.cba
.cpca_name
= devs
[i
].name
;
165 aa
.cba
.cpca_addr
= devs
[i
].addr
;
166 aa
.cba
.cpca_irq
= devs
[i
].irq
;
167 config_found_sm_loc(self
, "cpcbus", NULL
, &aa
.cba
,
168 cpc_print
, cpc_submatch
);
171 tag
= pci_make_tag(pc
, 0, 0, 0);
173 aa
.pba
.pba_iot
= pciio
;
174 aa
.pba
.pba_memt
= mem
;
175 aa
.pba
.pba_dmat
= dma
;
177 aa
.pba
.pba_flags
= PCI_FLAGS_MEM_ENABLED
| PCI_FLAGS_IO_ENABLED
;
180 /* Save PCI error condition reg. */
181 erren
= pci_conf_read(pc
, tag
, CPC_PCI_BRDGERR
);
182 /* Don't generate errors during probe. */
183 pci_conf_write(pc
, tag
, CPC_PCI_BRDGERR
, 0);
186 v
= pci_conf_read(pc
, tag
, CPC_BRIDGE_OPTIONS2
);
187 v
&= ~(CPC_BRIDGE_O2_ILAT_MASK
| CPC_BRIDGE_O2_SLAT_MASK
);
188 v
|= (CPC_BRIDGE_O2_ILAT_PRIM_ASYNC
<< CPC_BRIDGE_O2_ILAT_SHIFT
) |
189 (CPC_BRIDGE_O2_2LAT_PRIM_ASYNC
<< CPC_BRIDGE_O2_SLAT_SHIFT
);
190 pci_conf_write(pc
, tag
, CPC_BRIDGE_OPTIONS2
, v
);
192 #if NPCI > 0 && defined(PCI_NETBSD_CONFIGURE)
193 ioext
= extent_create("pciio", CPC_PCI_IO_START
, CPC_PCI_IO_END
,
194 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
195 memext
= extent_create("pcimem", CPC_PCI_MEM_BASE
, CPC_PCI_MEM_END
,
196 M_DEVBUF
, NULL
, 0, EX_NOWAIT
);
198 pci_configure_bus(0, ioext
, memext
, NULL
, 0, 32);
200 extent_destroy(ioext
);
201 extent_destroy(memext
);
204 config_found_ia(self
, "pcibus", &aa
.pba
, pcibusprint
);
206 /* Restore error triggers, and clear errors */
207 pci_conf_write(pc
, tag
, CPC_PCI_BRDGERR
, erren
| CPC_PCI_CLEARERR
);
210 /***************************************************************************/
213 * Interrupt controller.
217 cpc700_init_intr(bus_space_tag_t bt
, bus_space_handle_t bh
,
218 u_int32_t active
, u_int32_t level
)
224 * See CPC700 manual for information about what
225 * interrupts have which properties.
227 OUTL(CPC_UIC_SR
, 0xffffffff); /* clear all intrs */
228 OUTL(CPC_UIC_ER
, 0x00000000); /* disable all intrs */
229 OUTL(CPC_UIC_CR
, 0xffffffff); /* gen INT not MCP */
230 OUTL(CPC_UIC_PR
, 0xffff8000 | active
); /* 0 = active low */
231 OUTL(CPC_UIC_TR
, 0xc0000000 | level
); /* 0 = level intr */
232 OUTL(CPC_UIC_VR
, CPC_UIC_CVR_PRI
); /* intr 0 is highest */
236 cpc700_read_irq(void)
241 irqs
= INL(CPC_UIC_MSR
);
242 for (irq
= 0; irq
< ICU_LEN
; irq
++) {
243 if (irqs
& CPC_INTR_MASK(irq
))
252 OUTL(CPC_UIC_SR
, CPC_INTR_MASK(irq
));
256 cpc700_disable_irq(int irq
)
260 reg
= INL(CPC_UIC_ER
);
261 reg
&= ~CPC_INTR_MASK(irq
);
262 OUTL(CPC_UIC_ER
, reg
);
266 cpc700_enable_irq(int irq
)
270 reg
= INL(CPC_UIC_ER
);
271 reg
|= CPC_INTR_MASK(irq
);
272 OUTL(CPC_UIC_ER
, reg
);