1*c7fb772bSthorpej /* $NetBSD: becc.c,v 1.18 2021/08/07 16:18:46 thorpej Exp $ */
2b1b164a8Sthorpej
3b1b164a8Sthorpej /*
4891be168Sthorpej * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
5b1b164a8Sthorpej * All rights reserved.
6b1b164a8Sthorpej *
7b1b164a8Sthorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8b1b164a8Sthorpej *
9b1b164a8Sthorpej * Redistribution and use in source and binary forms, with or without
10b1b164a8Sthorpej * modification, are permitted provided that the following conditions
11b1b164a8Sthorpej * are met:
12b1b164a8Sthorpej * 1. Redistributions of source code must retain the above copyright
13b1b164a8Sthorpej * notice, this list of conditions and the following disclaimer.
14b1b164a8Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
15b1b164a8Sthorpej * notice, this list of conditions and the following disclaimer in the
16b1b164a8Sthorpej * documentation and/or other materials provided with the distribution.
17b1b164a8Sthorpej * 3. All advertising materials mentioning features or use of this software
18b1b164a8Sthorpej * must display the following acknowledgement:
19b1b164a8Sthorpej * This product includes software developed for the NetBSD Project by
20b1b164a8Sthorpej * Wasabi Systems, Inc.
21b1b164a8Sthorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22b1b164a8Sthorpej * or promote products derived from this software without specific prior
23b1b164a8Sthorpej * written permission.
24b1b164a8Sthorpej *
25b1b164a8Sthorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26b1b164a8Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27b1b164a8Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28b1b164a8Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29b1b164a8Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30b1b164a8Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31b1b164a8Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32b1b164a8Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33b1b164a8Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34b1b164a8Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35b1b164a8Sthorpej * POSSIBILITY OF SUCH DAMAGE.
36b1b164a8Sthorpej */
37b1b164a8Sthorpej
38b1b164a8Sthorpej /*
39b1b164a8Sthorpej * Autoconfiguration support for the ADI Engineering Big Endian
40b1b164a8Sthorpej * Companion Chip.
41b1b164a8Sthorpej */
42b1b164a8Sthorpej
4308716eaeSlukem #include <sys/cdefs.h>
44*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: becc.c,v 1.18 2021/08/07 16:18:46 thorpej Exp $");
4508716eaeSlukem
46b1b164a8Sthorpej #include <sys/param.h>
47b1b164a8Sthorpej #include <sys/systm.h>
48b1b164a8Sthorpej #include <sys/device.h>
49b1b164a8Sthorpej
50b1b164a8Sthorpej #define _ARM32_BUS_DMA_PRIVATE
51ed9977b1Sdyoung #include <sys/bus.h>
52b1b164a8Sthorpej
53b1b164a8Sthorpej #include <arm/xscale/i80200reg.h>
54b1b164a8Sthorpej #include <arm/xscale/beccreg.h>
55b1b164a8Sthorpej #include <arm/xscale/beccvar.h>
56b1b164a8Sthorpej
57b1b164a8Sthorpej /*
58b1b164a8Sthorpej * Virtual address at which the BECC is mapped. This is filled in
59b1b164a8Sthorpej * by machine-dependent code.
60b1b164a8Sthorpej */
61b1b164a8Sthorpej vaddr_t becc_vaddr;
62b1b164a8Sthorpej
63b1b164a8Sthorpej /*
64b1b164a8Sthorpej * BECC revision number. This is initialized by early bootstrap code.
65b1b164a8Sthorpej */
66b1b164a8Sthorpej int becc_rev;
67b1b164a8Sthorpej const char *becc_revisions[] = {
68b1b164a8Sthorpej "<= 7",
69b1b164a8Sthorpej "8",
70b1b164a8Sthorpej ">= 9",
71b1b164a8Sthorpej };
72b1b164a8Sthorpej
73b1b164a8Sthorpej /*
74b1b164a8Sthorpej * There can be only one BECC, so we keep a global pointer to
75b1b164a8Sthorpej * the softc, so board-specific code can use features of the
76b1b164a8Sthorpej * BECC without having to have a handle on the softc itself.
77b1b164a8Sthorpej */
78b1b164a8Sthorpej struct becc_softc *becc_softc;
79b1b164a8Sthorpej
80a2b8c7fbSmsaitoh static int becc_search(device_t, cfdata_t, const int *, void *);
81891be168Sthorpej static int becc_print(void *, const char *);
82891be168Sthorpej
83b1b164a8Sthorpej static void becc_pci_dma_init(struct becc_softc *);
84891be168Sthorpej static void becc_local_dma_init(struct becc_softc *);
85b1b164a8Sthorpej
86b1b164a8Sthorpej /*
87b1b164a8Sthorpej * becc_attach:
88b1b164a8Sthorpej *
89b1b164a8Sthorpej * Board-independent attach routine for the BECC.
90b1b164a8Sthorpej */
91b1b164a8Sthorpej void
becc_attach(struct becc_softc * sc)92b1b164a8Sthorpej becc_attach(struct becc_softc *sc)
93b1b164a8Sthorpej {
94b1b164a8Sthorpej struct pcibus_attach_args pba;
95b1b164a8Sthorpej uint32_t reg;
96b1b164a8Sthorpej
97b1b164a8Sthorpej becc_softc = sc;
98b1b164a8Sthorpej
99b1b164a8Sthorpej /*
100b1b164a8Sthorpej * Set the AF bit in the BCUMOD since the BECC will honor it.
101b1b164a8Sthorpej * This allows the BECC to return the requested 4-byte word
102b1b164a8Sthorpej * first when filling a cache line.
103b1b164a8Sthorpej */
1045f1c88d7Sperry __asm volatile("mrc p13, 0, %0, c1, c1, 0" : "=r" (reg));
1055f1c88d7Sperry __asm volatile("mcr p13, 0, %0, c1, c1, 0" : : "r" (reg | BCUMOD_AF));
106b1b164a8Sthorpej
107b1b164a8Sthorpej /*
108b1b164a8Sthorpej * Program the address windows of the PCI core. Note
109b1b164a8Sthorpej * that PCI master and target cycles must be disabled
110b1b164a8Sthorpej * while we configure the windows.
111b1b164a8Sthorpej */
112b1b164a8Sthorpej reg = becc_pcicore_read(sc, PCI_COMMAND_STATUS_REG);
113b1b164a8Sthorpej reg &= ~(PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_MASTER_ENABLE);
114b1b164a8Sthorpej becc_pcicore_write(sc, PCI_COMMAND_STATUS_REG, reg);
115b1b164a8Sthorpej
116b1b164a8Sthorpej /*
117b1b164a8Sthorpej * Program the two inbound PCI memory windows.
118b1b164a8Sthorpej */
119b1b164a8Sthorpej becc_pcicore_write(sc, PCI_MAPREG_START + 0,
120b1b164a8Sthorpej sc->sc_iwin[0].iwin_base | PCI_MAPREG_MEM_TYPE_32BIT |
121b1b164a8Sthorpej PCI_MAPREG_MEM_PREFETCHABLE_MASK);
122b1b164a8Sthorpej reg = becc_pcicore_read(sc, PCI_MAPREG_START + 0);
123b1b164a8Sthorpej BECC_CSR_WRITE(BECC_PSTR0, sc->sc_iwin[0].iwin_xlate & PSTRx_ADDRMASK);
124b1b164a8Sthorpej
125b1b164a8Sthorpej becc_pcicore_write(sc, PCI_MAPREG_START + 4,
126b1b164a8Sthorpej sc->sc_iwin[1].iwin_base | PCI_MAPREG_MEM_TYPE_32BIT |
127b1b164a8Sthorpej PCI_MAPREG_MEM_PREFETCHABLE_MASK);
128b1b164a8Sthorpej reg = becc_pcicore_read(sc, PCI_MAPREG_START + 4);
129b1b164a8Sthorpej BECC_CSR_WRITE(BECC_PSTR1, sc->sc_iwin[1].iwin_xlate & PSTRx_ADDRMASK);
130b1b164a8Sthorpej
131b1b164a8Sthorpej /*
132b1b164a8Sthorpej * ...and the third on v8 and later.
133b1b164a8Sthorpej */
134b1b164a8Sthorpej if (becc_rev >= BECC_REV_V8) {
135b1b164a8Sthorpej becc_pcicore_write(sc, PCI_MAPREG_START + 8,
136b1b164a8Sthorpej sc->sc_iwin[2].iwin_base | PCI_MAPREG_MEM_TYPE_32BIT |
137b1b164a8Sthorpej PCI_MAPREG_MEM_PREFETCHABLE_MASK);
138b1b164a8Sthorpej reg = becc_pcicore_read(sc, PCI_MAPREG_START + 8);
13914acc892Sthorpej BECC_CSR_WRITE(BECC_PSTR2,
140b1b164a8Sthorpej sc->sc_iwin[2].iwin_xlate & PSTR2_ADDRMASK);
141b1b164a8Sthorpej }
142b1b164a8Sthorpej
143b1b164a8Sthorpej /*
1446955d476Sthorpej * Program the two outbound PCI memory windows.
1456955d476Sthorpej * NOTE: WE DO NOT BYTE-SWAP OUTBOUND WINDOWS IN BIG-ENDIAN
1466955d476Sthorpej * MODE. I know this seems counter-intuitive, but that's
1476955d476Sthorpej * how it is.
148b1b164a8Sthorpej *
149b1b164a8Sthorpej * There's a third window on v9 and later, but we don't
150b1b164a8Sthorpej * use it for anything; program it anyway, just to be
151b1b164a8Sthorpej * safe.
152b1b164a8Sthorpej */
153b1b164a8Sthorpej BECC_CSR_WRITE(BECC_POMR1, sc->sc_owin_xlate[0] /* | POMRx_F32 */);
154b1b164a8Sthorpej BECC_CSR_WRITE(BECC_POMR2, sc->sc_owin_xlate[1] /* | POMRx_F32 */);
155b1b164a8Sthorpej
156b1b164a8Sthorpej if (becc_rev >= BECC_REV_V9)
157b1b164a8Sthorpej BECC_CSR_WRITE(BECC_POMR3,
158b1b164a8Sthorpej sc->sc_owin_xlate[2] /* | POMRx_F32 */);
159b1b164a8Sthorpej
160b1b164a8Sthorpej /*
1616955d476Sthorpej * Program the PCI I/O window. See note above about byte-swapping.
162b1b164a8Sthorpej *
163b1b164a8Sthorpej * XXX What about STREAM transfers?
164b1b164a8Sthorpej */
165b1b164a8Sthorpej BECC_CSR_WRITE(BECC_POIR, sc->sc_ioout_xlate);
166b1b164a8Sthorpej
167b1b164a8Sthorpej /*
168b1b164a8Sthorpej * Configure PCI configuration cycle access.
169b1b164a8Sthorpej */
170b1b164a8Sthorpej BECC_CSR_WRITE(BECC_POCR, 0);
171b1b164a8Sthorpej
172b1b164a8Sthorpej /*
173b1b164a8Sthorpej * ...and now reenable PCI access.
174b1b164a8Sthorpej */
175b1b164a8Sthorpej reg = becc_pcicore_read(sc, PCI_COMMAND_STATUS_REG);
176b1b164a8Sthorpej reg |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE |
177b1b164a8Sthorpej PCI_COMMAND_PARITY_ENABLE | PCI_COMMAND_SERR_ENABLE;
178b1b164a8Sthorpej becc_pcicore_write(sc, PCI_COMMAND_STATUS_REG, reg);
179b1b164a8Sthorpej
180b1b164a8Sthorpej /* Initialize the bus space tags. */
181b1b164a8Sthorpej becc_io_bs_init(&sc->sc_pci_iot, sc);
182b1b164a8Sthorpej becc_mem_bs_init(&sc->sc_pci_memt, sc);
183b1b164a8Sthorpej
184b1b164a8Sthorpej /* Initialize the PCI chipset tag. */
185b1b164a8Sthorpej becc_pci_init(&sc->sc_pci_chipset, sc);
186b1b164a8Sthorpej
187b1b164a8Sthorpej /* Initialize the DMA tags. */
188b1b164a8Sthorpej becc_pci_dma_init(sc);
189891be168Sthorpej becc_local_dma_init(sc);
190891be168Sthorpej
191891be168Sthorpej /*
192891be168Sthorpej * Attach any on-chip peripherals. We used indirect config, since
193891be168Sthorpej * the BECC is a soft-core with a variety of peripherals, depending
194891be168Sthorpej * on configuration.
195891be168Sthorpej */
1962685996bSthorpej config_search(sc->sc_dev, NULL,
197*c7fb772bSthorpej CFARGS(.search = becc_search,
198*c7fb772bSthorpej .iattr = "becc"));
199b1b164a8Sthorpej
200b1b164a8Sthorpej /*
201b1b164a8Sthorpej * Attach the PCI bus.
202b1b164a8Sthorpej */
203b1b164a8Sthorpej pba.pba_iot = &sc->sc_pci_iot;
204b1b164a8Sthorpej pba.pba_memt = &sc->sc_pci_memt;
205b1b164a8Sthorpej pba.pba_dmat = &sc->sc_pci_dmat;
2067dd7f8baSfvdl pba.pba_dmat64 = NULL;
207b1b164a8Sthorpej pba.pba_pc = &sc->sc_pci_chipset;
208b1b164a8Sthorpej pba.pba_bus = 0;
209b1b164a8Sthorpej pba.pba_bridgetag = NULL;
210b1b164a8Sthorpej pba.pba_intrswiz = 0;
211b1b164a8Sthorpej pba.pba_intrtag = 0;
212a6b2b839Sdyoung pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY |
213b1b164a8Sthorpej PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY;
2142685996bSthorpej config_found(sc->sc_dev, &pba, pcibusprint,
215*c7fb772bSthorpej CFARGS(.iattr = "pcibus"));
216b1b164a8Sthorpej }
217b1b164a8Sthorpej
218b1b164a8Sthorpej /*
219891be168Sthorpej * becc_search:
220891be168Sthorpej *
221891be168Sthorpej * Indirect autoconfiguration glue for BECC.
222891be168Sthorpej */
223891be168Sthorpej static int
becc_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)224a2b8c7fbSmsaitoh becc_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
225891be168Sthorpej {
226a2b8c7fbSmsaitoh struct becc_softc *sc = device_private(parent);
227891be168Sthorpej struct becc_attach_args ba;
228891be168Sthorpej
229891be168Sthorpej ba.ba_dmat = &sc->sc_local_dmat;
230891be168Sthorpej
2312685996bSthorpej if (config_probe(parent, cf, &ba))
232*c7fb772bSthorpej config_attach(parent, cf, &ba, becc_print, CFARGS_NONE);
233891be168Sthorpej
234891be168Sthorpej return (0);
235891be168Sthorpej }
236891be168Sthorpej
237891be168Sthorpej /*
238891be168Sthorpej * becc_print:
239891be168Sthorpej *
240891be168Sthorpej * Autoconfiguration cfprint routine when attaching
241891be168Sthorpej * to the BECC.
242891be168Sthorpej */
243891be168Sthorpej static int
becc_print(void * aux,const char * pnp)244891be168Sthorpej becc_print(void *aux, const char *pnp)
245891be168Sthorpej {
246891be168Sthorpej
247891be168Sthorpej return (UNCONF);
248891be168Sthorpej }
249891be168Sthorpej
250891be168Sthorpej /*
251b1b164a8Sthorpej * becc_pci_dma_init:
252b1b164a8Sthorpej *
253b1b164a8Sthorpej * Initialize the PCI DMA tag.
254b1b164a8Sthorpej */
255b1b164a8Sthorpej static void
becc_pci_dma_init(struct becc_softc * sc)256b1b164a8Sthorpej becc_pci_dma_init(struct becc_softc *sc)
257b1b164a8Sthorpej {
258b1b164a8Sthorpej bus_dma_tag_t dmat = &sc->sc_pci_dmat;
259b1b164a8Sthorpej struct arm32_dma_range *dr = sc->sc_pci_dma_range;
260b1b164a8Sthorpej int i = 0;
261b1b164a8Sthorpej
262b1b164a8Sthorpej /*
263b1b164a8Sthorpej * If we have the 128MB window, put it first, since it
264b1b164a8Sthorpej * will always cover the entire memory range.
265b1b164a8Sthorpej */
266b1b164a8Sthorpej if (becc_rev >= BECC_REV_V8) {
267b1b164a8Sthorpej dr[i].dr_sysbase = sc->sc_iwin[2].iwin_xlate;
268b1b164a8Sthorpej dr[i].dr_busbase = sc->sc_iwin[2].iwin_base;
269b1b164a8Sthorpej dr[i].dr_len = (128U * 1024 * 1024);
270b1b164a8Sthorpej i++;
271b1b164a8Sthorpej }
272b1b164a8Sthorpej
273b1b164a8Sthorpej dr[i].dr_sysbase = sc->sc_iwin[0].iwin_xlate;
274b1b164a8Sthorpej dr[i].dr_busbase = sc->sc_iwin[0].iwin_base;
275b1b164a8Sthorpej dr[i].dr_len = (32U * 1024 * 1024);
276b1b164a8Sthorpej i++;
277b1b164a8Sthorpej
278b1b164a8Sthorpej dr[i].dr_sysbase = sc->sc_iwin[1].iwin_xlate;
279b1b164a8Sthorpej dr[i].dr_busbase = sc->sc_iwin[1].iwin_base;
280b1b164a8Sthorpej dr[i].dr_len = (32U * 1024 * 1024);
281b1b164a8Sthorpej i++;
282b1b164a8Sthorpej
283b1b164a8Sthorpej dmat->_ranges = dr;
284b1b164a8Sthorpej dmat->_nranges = i;
285b1b164a8Sthorpej
286b1b164a8Sthorpej dmat->_dmamap_create = _bus_dmamap_create;
287b1b164a8Sthorpej dmat->_dmamap_destroy = _bus_dmamap_destroy;
288b1b164a8Sthorpej dmat->_dmamap_load = _bus_dmamap_load;
289b1b164a8Sthorpej dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf;
290b1b164a8Sthorpej dmat->_dmamap_load_uio = _bus_dmamap_load_uio;
291b1b164a8Sthorpej dmat->_dmamap_load_raw = _bus_dmamap_load_raw;
292b1b164a8Sthorpej dmat->_dmamap_unload = _bus_dmamap_unload;
293b1b164a8Sthorpej dmat->_dmamap_sync_pre = _bus_dmamap_sync;
294b1b164a8Sthorpej dmat->_dmamap_sync_post = NULL;
295b1b164a8Sthorpej
296b1b164a8Sthorpej dmat->_dmamem_alloc = _bus_dmamem_alloc;
297b1b164a8Sthorpej dmat->_dmamem_free = _bus_dmamem_free;
298b1b164a8Sthorpej dmat->_dmamem_map = _bus_dmamem_map;
299b1b164a8Sthorpej dmat->_dmamem_unmap = _bus_dmamem_unmap;
300b1b164a8Sthorpej dmat->_dmamem_mmap = _bus_dmamem_mmap;
3014710b77fSmatt
3024710b77fSmatt dmat->_dmatag_subregion = _bus_dmatag_subregion;
3034710b77fSmatt dmat->_dmatag_destroy = _bus_dmatag_destroy;
304b1b164a8Sthorpej }
305b1b164a8Sthorpej
306891be168Sthorpej /*
307891be168Sthorpej * becc_local_dma_init:
308891be168Sthorpej *
309891be168Sthorpej * Initialize the local DMA tag.
310891be168Sthorpej */
311891be168Sthorpej static void
becc_local_dma_init(struct becc_softc * sc)312891be168Sthorpej becc_local_dma_init(struct becc_softc *sc)
313891be168Sthorpej {
314891be168Sthorpej bus_dma_tag_t dmat = &sc->sc_local_dmat;
315891be168Sthorpej
316891be168Sthorpej dmat->_ranges = NULL;
317891be168Sthorpej dmat->_nranges = 0;
318891be168Sthorpej
319891be168Sthorpej dmat->_dmamap_create = _bus_dmamap_create;
320891be168Sthorpej dmat->_dmamap_destroy = _bus_dmamap_destroy;
321891be168Sthorpej dmat->_dmamap_load = _bus_dmamap_load;
322891be168Sthorpej dmat->_dmamap_load_mbuf = _bus_dmamap_load_mbuf;
323891be168Sthorpej dmat->_dmamap_load_uio = _bus_dmamap_load_uio;
324891be168Sthorpej dmat->_dmamap_load_raw = _bus_dmamap_load_raw;
325891be168Sthorpej dmat->_dmamap_unload = _bus_dmamap_unload;
326891be168Sthorpej dmat->_dmamap_sync_pre = _bus_dmamap_sync;
327891be168Sthorpej dmat->_dmamap_sync_post = NULL;
328891be168Sthorpej
329891be168Sthorpej dmat->_dmamem_alloc = _bus_dmamem_alloc;
330891be168Sthorpej dmat->_dmamem_free = _bus_dmamem_free;
331891be168Sthorpej dmat->_dmamem_map = _bus_dmamem_map;
332891be168Sthorpej dmat->_dmamem_unmap = _bus_dmamem_unmap;
333891be168Sthorpej dmat->_dmamem_mmap = _bus_dmamem_mmap;
334891be168Sthorpej }
335891be168Sthorpej
336b1b164a8Sthorpej uint32_t
becc_pcicore_read(struct becc_softc * sc,bus_addr_t reg)337b1b164a8Sthorpej becc_pcicore_read(struct becc_softc *sc, bus_addr_t reg)
338b1b164a8Sthorpej {
339b1b164a8Sthorpej vaddr_t va = sc->sc_pci_cfg_base | (1U << BECC_IDSEL_BIT) | reg;
340b1b164a8Sthorpej
3415f1c88d7Sperry return (*(volatile uint32_t *) va);
342b1b164a8Sthorpej }
343b1b164a8Sthorpej
344b1b164a8Sthorpej void
becc_pcicore_write(struct becc_softc * sc,bus_addr_t reg,uint32_t val)345b1b164a8Sthorpej becc_pcicore_write(struct becc_softc *sc, bus_addr_t reg, uint32_t val)
346b1b164a8Sthorpej {
347b1b164a8Sthorpej vaddr_t va = sc->sc_pci_cfg_base | (1U << BECC_IDSEL_BIT) | reg;
348b1b164a8Sthorpej
3495f1c88d7Sperry *(volatile uint32_t *) va = val;
350b1b164a8Sthorpej }
351