1 /* $NetBSD: i80312.c,v 1.18 2005/12/11 12:16:51 christos Exp $ */
4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
39 * Autoconfiguration support for the Intel i80312 Companion I/O chip.
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: i80312.c,v 1.18 2005/12/11 12:16:51 christos Exp $");
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/device.h>
49 #define _ARM32_BUS_DMA_PRIVATE
50 #include <machine/bus.h>
52 #include <arm/xscale/i80312reg.h>
53 #include <arm/xscale/i80312var.h>
55 #include <dev/pci/ppbreg.h>
58 * Statically-allocated bus_space structure used to access the
59 * i80312's own registers.
61 struct bus_space i80312_bs_tag
;
64 * There can be only one i80312, so we keep a global pointer to
65 * the softc, so board-specific code can use features of the
66 * i80312 without having to have a handle on the softc itself.
68 struct i80312_softc
*i80312_softc
;
70 static void i80312_pci_dma_init(struct i80312_softc
*);
71 static void i80312_local_dma_init(struct i80312_softc
*);
73 static int i80312_iopxs_print(void *, const char *);
75 /* Built-in devices. */
76 static const struct iopxs_device
{
81 /* { "iopaau", I80312_AAU_BASE, I80312_AAU_SIZE }, */
82 /* { "iopdma", I80312_DMA_BASE0, I80312_DMA_SIZE }, */
83 /* { "iopdma", I80312_DMA_BASE1, I80312_DMA_SIZE }, */
84 { "iopiic", I80312_IIC_BASE
, I80312_IIC_SIZE
},
85 /* { "iopmu", I80312_MSG_BASE, I80312_MU_SIZE }, */
92 * Board-independent attach routine for the i80312.
95 i80312_attach(struct i80312_softc
*sc
)
97 struct pcibus_attach_args pba
;
98 const struct iopxs_device
*id
;
99 struct iopxs_attach_args ia
;
106 * Slice off some useful subregion handles.
109 if (bus_space_subregion(sc
->sc_st
, sc
->sc_sh
, I80312_PPB_BASE
,
110 I80312_PPB_SIZE
, &sc
->sc_ppb_sh
))
111 panic("%s: unable to subregion PPB registers",
112 sc
->sc_dev
.dv_xname
);
114 if (bus_space_subregion(sc
->sc_st
, sc
->sc_sh
, I80312_ATU_BASE
,
115 I80312_ATU_SIZE
, &sc
->sc_atu_sh
))
116 panic("%s: unable to subregion ATU registers",
117 sc
->sc_dev
.dv_xname
);
119 if (bus_space_subregion(sc
->sc_st
, sc
->sc_sh
, I80312_INTC_BASE
,
120 I80312_INTC_SIZE
, &sc
->sc_intc_sh
))
121 panic("%s: unable to subregion INTC registers",
122 sc
->sc_dev
.dv_xname
);
124 /* We expect the Memory Controller to be already sliced off. */
127 * Disable the private space decode.
129 sc
->sc_sder
= bus_space_read_1(sc
->sc_st
, sc
->sc_ppb_sh
,
131 sc
->sc_sder
&= ~PPB_SDER_PMSE
;
132 bus_space_write_1(sc
->sc_st
, sc
->sc_ppb_sh
,
133 I80312_PPB_SDER
, sc
->sc_sder
);
136 * Program the Secondary ID Select register.
138 bus_space_write_2(sc
->sc_st
, sc
->sc_ppb_sh
,
139 I80312_PPB_SISR
, sc
->sc_sisr
);
142 * Program the private secondary bus spaces.
144 if (sc
->sc_privmem_size
&& sc
->sc_privio_size
) {
145 bus_space_write_1(sc
->sc_st
, sc
->sc_ppb_sh
, I80312_PPB_SIOBR
,
146 (sc
->sc_privio_base
>> 12) << 4);
147 bus_space_write_1(sc
->sc_st
, sc
->sc_ppb_sh
, I80312_PPB_SIOLR
,
148 ((sc
->sc_privio_base
+ sc
->sc_privio_size
- 1)
151 bus_space_write_2(sc
->sc_st
, sc
->sc_ppb_sh
, I80312_PPB_SMBR
,
152 (sc
->sc_privmem_base
>> 20) << 4);
153 bus_space_write_2(sc
->sc_st
, sc
->sc_ppb_sh
, I80312_PPB_SMLR
,
154 ((sc
->sc_privmem_base
+ sc
->sc_privmem_size
- 1)
157 sc
->sc_sder
|= PPB_SDER_PMSE
;
158 bus_space_write_1(sc
->sc_st
, sc
->sc_ppb_sh
, I80312_PPB_SDER
,
160 } else if (sc
->sc_privmem_size
|| sc
->sc_privio_size
) {
161 printf("%s: WARNING: privmem_size 0x%08x privio_size 0x%08x\n",
162 sc
->sc_dev
.dv_xname
, sc
->sc_privmem_size
,
164 printf("%s: private bus spaces not enabled\n",
165 sc
->sc_dev
.dv_xname
);
169 * Program the Primary Inbound window.
172 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
173 PCI_MAPREG_START
, sc
->sc_pin_base
);
174 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
175 I80312_ATU_PIAL
, ATU_LIMIT(sc
->sc_pin_size
));
176 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
177 I80312_ATU_PIATV
, sc
->sc_pin_xlate
);
180 * Program the Secondary Inbound window.
182 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
183 I80312_ATU_SIAM
, sc
->sc_sin_base
);
184 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
185 I80312_ATU_SIAL
, ATU_LIMIT(sc
->sc_sin_size
));
186 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
187 I80312_ATU_SIATV
, sc
->sc_sin_xlate
);
190 * Mask (disable) the ATU interrupt sources.
191 * XXX May want to revisit this if we encounter
192 * XXX an application that wants it.
194 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
196 ATU_AIM_MPEIM
| ATU_AIM_TATIM
| ATU_AIM_TAMIM
|
197 ATU_AIM_MAIM
| ATU_AIM_SAIM
| ATU_AIM_DPEIM
|
199 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
201 ATU_AIM_MPEIM
| ATU_AIM_TATIM
| ATU_AIM_TAMIM
|
202 ATU_AIM_MAIM
| ATU_AIM_SAIM
| ATU_AIM_DPEIM
);
207 * Primary Outbound ATU Enable
208 * Secondary Outbound ATU Enable
209 * Secondary Direct Addressing Select
210 * Direct Addressing Enable
212 atucr
= bus_space_read_4(sc
->sc_st
, sc
->sc_atu_sh
, I80312_ATU_ACR
);
213 atucr
&= ~(ATU_ACR_POAE
|ATU_ACR_SOAE
|ATU_ACR_SDAS
|ATU_ACR_DAE
);
216 * Program the Primary Outbound windows.
218 if (sc
->sc_pmemout_size
)
219 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
220 I80312_ATU_POMWV
, sc
->sc_pmemout_base
);
221 if (sc
->sc_pioout_size
)
222 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
223 I80312_ATU_POIOWV
, sc
->sc_pioout_base
);
224 if (sc
->sc_pmemout_size
|| sc
->sc_pioout_size
)
225 atucr
|= ATU_ACR_POAE
;
228 * Program the Secondary Outbound windows.
230 if (sc
->sc_smemout_size
)
231 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
232 I80312_ATU_SOMWV
, sc
->sc_smemout_base
);
233 if (sc
->sc_sioout_size
)
234 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
235 I80312_ATU_SOIOWV
, sc
->sc_sioout_base
);
236 if (sc
->sc_smemout_size
|| sc
->sc_sioout_size
)
237 atucr
|= ATU_ACR_SOAE
;
239 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
, I80312_ATU_ACR
, atucr
);
242 * Enable bus mastering, memory access, SERR, and parity
243 * checking on the ATU.
245 if (sc
->sc_is_host
) {
246 preg
= bus_space_read_4(sc
->sc_st
, sc
->sc_atu_sh
,
247 PCI_COMMAND_STATUS_REG
);
248 preg
|= PCI_COMMAND_MEM_ENABLE
| PCI_COMMAND_MASTER_ENABLE
|
249 PCI_COMMAND_PARITY_ENABLE
| PCI_COMMAND_SERR_ENABLE
;
250 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
251 PCI_COMMAND_STATUS_REG
, preg
);
253 preg
= bus_space_read_4(sc
->sc_st
, sc
->sc_atu_sh
,
255 preg
|= PCI_COMMAND_MEM_ENABLE
| PCI_COMMAND_MASTER_ENABLE
|
256 PCI_COMMAND_PARITY_ENABLE
| PCI_COMMAND_SERR_ENABLE
;
257 bus_space_write_4(sc
->sc_st
, sc
->sc_atu_sh
,
258 I80312_ATU_SACS
, preg
);
261 * Configure the bridge. If we're a host, set the primary
262 * bus to bus #0 and the secondary bus to bus #1. We also
263 * set the PPB's subordinate bus # to 1. It will be fixed
264 * up later when we fully configure the bus.
266 * If we're a slave, just use the bus #'s that the host
269 if (sc
->sc_is_host
) {
270 bus_space_write_4(sc
->sc_st
, sc
->sc_ppb_sh
,
272 (0 << PCI_BRIDGE_BUS_PRIMARY_SHIFT
) |
273 (1 << PCI_BRIDGE_BUS_SECONDARY_SHIFT
) |
274 (1 << PCI_BRIDGE_BUS_SUBORDINATE_SHIFT
));
277 /* Initialize the bus space tags. */
278 i80312_io_bs_init(&sc
->sc_pci_iot
, sc
);
279 i80312_mem_bs_init(&sc
->sc_pci_memt
, sc
);
281 /* Initialize the PCI chipset tag. */
282 i80312_pci_init(&sc
->sc_pci_chipset
, sc
);
284 /* Initialize the DMA tags. */
285 i80312_pci_dma_init(sc
);
286 i80312_local_dma_init(sc
);
289 * Attach all the IOP built-ins.
291 for (id
= iopxs_devices
; id
->id_name
!= NULL
; id
++) {
292 ia
.ia_name
= id
->id_name
;
293 ia
.ia_st
= sc
->sc_st
;
294 ia
.ia_sh
= sc
->sc_sh
;
295 ia
.ia_dmat
= &sc
->sc_local_dmat
;
296 ia
.ia_offset
= id
->id_offset
;
297 ia
.ia_size
= id
->id_size
;
299 (void) config_found_ia(&sc
->sc_dev
, "iopxs", &ia
, i80312_iopxs_print
);
303 * Attach the PCI bus.
305 * Note: We only probe the Secondary PCI bus, since that
306 * is the only bus on which we can have a private device
309 preg
= bus_space_read_4(sc
->sc_st
, sc
->sc_ppb_sh
, PPB_REG_BUSINFO
);
310 pba
.pba_iot
= &sc
->sc_pci_iot
;
311 pba
.pba_memt
= &sc
->sc_pci_memt
;
312 pba
.pba_dmat
= &sc
->sc_pci_dmat
;
313 pba
.pba_dmat64
= NULL
;
314 pba
.pba_pc
= &sc
->sc_pci_chipset
;
315 pba
.pba_bus
= PPB_BUSINFO_SECONDARY(preg
);
316 pba
.pba_bridgetag
= NULL
;
317 pba
.pba_intrswiz
= 3;
319 /* XXX MRL/MRM/MWI seem to have problems, at the moment. */
320 pba
.pba_flags
= PCI_FLAGS_IO_ENABLED
| PCI_FLAGS_MEM_ENABLED
/* |
321 PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY */;
322 (void) config_found_ia(&sc
->sc_dev
, "pcibus", &pba
, pcibusprint
);
326 * i80312_iopxs_print:
328 * Autoconfiguration cfprint routine when attaching
329 * to the "iopxs" device.
332 i80312_iopxs_print(void *aux
, const char *pnp
)
339 * i80312_pci_dma_init:
341 * Initialize the PCI DMA tag.
344 i80312_pci_dma_init(struct i80312_softc
*sc
)
346 bus_dma_tag_t dmat
= &sc
->sc_pci_dmat
;
347 struct arm32_dma_range
*dr
= &sc
->sc_pci_dma_range
;
349 dr
->dr_sysbase
= sc
->sc_sin_xlate
;
350 dr
->dr_busbase
= sc
->sc_sin_base
;
351 dr
->dr_len
= sc
->sc_sin_size
;
356 dmat
->_dmamap_create
= _bus_dmamap_create
;
357 dmat
->_dmamap_destroy
= _bus_dmamap_destroy
;
358 dmat
->_dmamap_load
= _bus_dmamap_load
;
359 dmat
->_dmamap_load_mbuf
= _bus_dmamap_load_mbuf
;
360 dmat
->_dmamap_load_uio
= _bus_dmamap_load_uio
;
361 dmat
->_dmamap_load_raw
= _bus_dmamap_load_raw
;
362 dmat
->_dmamap_unload
= _bus_dmamap_unload
;
363 dmat
->_dmamap_sync_pre
= _bus_dmamap_sync
;
364 dmat
->_dmamap_sync_post
= NULL
;
366 dmat
->_dmamem_alloc
= _bus_dmamem_alloc
;
367 dmat
->_dmamem_free
= _bus_dmamem_free
;
368 dmat
->_dmamem_map
= _bus_dmamem_map
;
369 dmat
->_dmamem_unmap
= _bus_dmamem_unmap
;
370 dmat
->_dmamem_mmap
= _bus_dmamem_mmap
;
374 * i80312_local_dma_init:
376 * Initialize the local DMA tag.
379 i80312_local_dma_init(struct i80312_softc
*sc
)
381 bus_dma_tag_t dmat
= &sc
->sc_local_dmat
;
383 dmat
->_ranges
= NULL
;
386 dmat
->_dmamap_create
= _bus_dmamap_create
;
387 dmat
->_dmamap_destroy
= _bus_dmamap_destroy
;
388 dmat
->_dmamap_load
= _bus_dmamap_load
;
389 dmat
->_dmamap_load_mbuf
= _bus_dmamap_load_mbuf
;
390 dmat
->_dmamap_load_uio
= _bus_dmamap_load_uio
;
391 dmat
->_dmamap_load_raw
= _bus_dmamap_load_raw
;
392 dmat
->_dmamap_unload
= _bus_dmamap_unload
;
393 dmat
->_dmamap_sync_pre
= _bus_dmamap_sync
;
394 dmat
->_dmamap_sync_post
= NULL
;
396 dmat
->_dmamem_alloc
= _bus_dmamem_alloc
;
397 dmat
->_dmamem_free
= _bus_dmamem_free
;
398 dmat
->_dmamem_map
= _bus_dmamem_map
;
399 dmat
->_dmamem_unmap
= _bus_dmamem_unmap
;
400 dmat
->_dmamem_mmap
= _bus_dmamem_mmap
;