1/*	$NetBSD: tc_vsbus.c,v 1.10 2021/05/08 09:03:30 rin Exp $	*/
2/*-
3 * Copyright (c) 2008 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Matt Thomas <matt@3am-software.com>.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: tc_vsbus.c,v 1.10 2021/05/08 09:03:30 rin Exp $");
33
34#include <sys/param.h>
35#include <sys/bus.h>
36#include <sys/cpu.h>
37#include <sys/device.h>
38
39#include <machine/cpu.h>
40#include <machine/pte.h>
41#include <machine/scb.h>
42#include <machine/sid.h>
43#include <machine/vsbus.h>
44
45#include <dev/tc/tcvar.h>
46
47#define NSLOTS	1
48
49struct tc_vsbus_softc {
50	struct tc_softc sc_tc;
51	struct tc_slotdesc sc_slots[NSLOTS];
52	struct vax_bus_dma_tag sc_dmatag;
53	struct vax_sgmap sc_sgmap;
54	struct evcnt sc_ev;
55	int (*sc_intr_func)(void *);
56	void *sc_intr_arg;
57	bus_space_tag_t sc_bst;
58	bus_space_handle_t sc_bsh_csr;
59	int sc_cvec;
60};
61
62static int tc_vsbus_match(device_t, cfdata_t, void *);
63static void tc_vsbus_attach(device_t, device_t, void *);
64
65static int tc_vsbus_dma_init(device_t);
66static bus_dma_tag_t tc_vsbus_get_dma_tag(int);
67
68static void tc_vsbus_intr(void *);
69static void tc_vsbus_intr_establish(device_t, void *, int, int (*)(void *),
70    void *);
71static void tc_vsbus_intr_disestablish(device_t, void *);
72static const struct evcnt *tc_vsbus_intr_evcnt(device_t, void *);
73
74static int vax_tc_bus_space_map(void *, bus_addr_t, bus_size_t, int,
75    bus_space_handle_t *, int);
76static int vax_tc_bus_space_subregion(void *, bus_space_handle_t, bus_size_t,
77    bus_size_t, bus_space_handle_t *);
78static void vax_tc_bus_space_unmap(void *, bus_space_handle_t, bus_size_t, int);
79static int vax_tc_bus_space_alloc(void *, bus_addr_t, bus_addr_t, bus_size_t,
80    bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *);
81static void vax_tc_bus_space_free(void *, bus_space_handle_t, bus_size_t);
82static paddr_t vax_tc_bus_space_mmap(void *, bus_addr_t, off_t, int, int);
83
84CFATTACH_DECL_NEW(tc_vsbus, sizeof(struct tc_vsbus_softc),
85    tc_vsbus_match, tc_vsbus_attach, 0, 0);
86
87static bus_dma_tag_t tc_vsbus_dmat;
88
89struct vax_bus_space vax_tc_bus_space = {
90	NULL,
91	vax_tc_bus_space_map,
92	vax_tc_bus_space_unmap,
93	vax_tc_bus_space_subregion,
94	vax_tc_bus_space_alloc,
95	vax_tc_bus_space_free,
96	vax_tc_bus_space_mmap,
97};
98
99/*
100 * taken from KA46 System Board Specification, KA46-0-DBF, Rev. X.02,
101 * 10 October 1990
102 */
103#define KA46_BWF0			0x20080014
104#define   KA46_BWF0_ADP			__BIT(31)
105#define KA46_BWF0_SZ			4
106
107/*
108 * taken from KA49 Processor Module Specification V 1.1, 20 August 1992
109 */
110#define KA49_CFG			0x25800000
111#define   KA49_CFG_BA			__BIT(0)
112#define KA49_CFG_SZ			2
113
114/*
115 * taken from Pmariah TURBOchannel Adapter Specification, 29 November 1991
116 */
117#define KA4x_TCA_BASE			0x30000000
118#define KA4x_TCA_DIAG_TRIG		(KA4x_TCA_BASE + 0x4000000)
119#define KA4x_TCA_MAP_CHK_SEQ		(KA4x_TCA_BASE + 0x4800000)
120#define KA4x_TCA_FIFO_DIAG		(KA4x_TCA_BASE + 0x5000000)
121#define KA4x_TCA_SGMAP			(KA4x_TCA_BASE + 0x5800000)
122#define KA4x_TCA_DIAG_ROM		(KA4x_TCA_BASE + 0x6000000)
123#define KA4x_TCA_CSR			(KA4x_TCA_BASE + 0x6800000)
124#define   KA4x_TCA_CSR_BLK_SZ		__BITS(0, 2)	/* 0x00007 RW   */
125#define   KA4x_TCA_CSR_SPARE		__BIT(3)	/* 0x00008 RW   */
126#define   KA4x_TCA_CSR_BAD_PAR		__BITS(4, 7)	/* 0x000f0 RW   */
127#define   KA4x_TCA_CSR_RST_TC		__BIT(8)	/* 0x00100 RW   */
128#define   KA4x_TCA_CSR_EN_MAP		__BIT(9)	/* 0x00200 RW   */
129#define   KA4x_TCA_CSR_INVAL_REF	__BIT(10)	/* 0x00400 RW1C */
130#define   KA4x_TCA_CSR_TC_TMO		__BIT(11)	/* 0x00800 RW   */
131#define   KA4x_TCA_CSR_EN_TC_IRQ	__BIT(12)	/* 0x01000 RW   */
132#define   KA4x_TCA_CSR_TC_IRQ		__BIT(13)	/* 0x02000 R    */
133#define   KA4x_TCA_CSR_ERR		__BIT(14)	/* 0x04000 RW1C */
134#define   KA4x_TCA_CSR_ALT_CYC_ST	__BIT(15)	/* 0x08000 RW   */
135#define   KA4x_TCA_CSR_EN_PAR		__BIT(16)	/* 0x10000 RW   */
136#define   KA4x_TCA_CSR_FIFO_EMPTY	__BIT(17)	/* 0x20000 R    */
137#define KA4x_TCA_CSR_SZ			4
138
139static int
140tc_vsbus_match(device_t parent, cfdata_t cfdata, void *aux)
141{
142	struct vsbus_attach_args * const va = aux;
143	uint32_t *csr;
144	bus_space_tag_t bst = va->va_memt;
145	bus_space_handle_t bsh;
146	int found, rc;
147
148	if (va->va_paddr != KA4x_TCA_CSR)
149		return 0;
150
151	/* Bus adaptor present? */
152	switch (vax_boardtype) {
153	case VAX_BTYP_46:
154		if (bus_space_map(bst, KA46_BWF0, KA46_BWF0_SZ, 0, &bsh))
155			return 0;
156		found = ((bus_space_read_4(bst, bsh, 0) & KA46_BWF0_ADP) != 0);
157		bus_space_unmap(bst, bsh, KA46_BWF0_SZ);
158		/*
159		 * On VS4000/60, although interrupting on a real vector, fool
160		 * vsbus interrupt, as no interrupt bit will be set in
161		 * vsbus_softc's sc_intreq for TC adaptor.
162		 */
163		rc = 20;
164		break;
165	case VAX_BTYP_49:
166		if (bus_space_map(bst, KA49_CFG, KA49_CFG_SZ, 0, &bsh))
167			return 0;
168		found = ((bus_space_read_2(bst, bsh, 0) & KA49_CFG_BA) != 0);
169		bus_space_unmap(bst, bsh, KA49_CFG_SZ);
170		rc = 10;
171		break;
172	default:
173		return 0;
174	}
175	if (!found)
176		return 0;
177
178	/* XXX Assume a found bus adaptor is the TC bus adaptor. */
179
180	/* Force interrupt. */
181	csr = (uint32_t *)va->va_addr;
182	*csr |= KA4x_TCA_CSR_TC_TMO;
183	DELAY(10000);
184	*csr &= ~KA4x_TCA_CSR_TC_TMO;
185	DELAY(10000);
186
187	return rc;
188}
189
190#define INIT_SLOTSZ	1
191
192static void
193tc_vsbus_attach(device_t parent, device_t self, void *aux)
194{
195	struct tcbus_attach_args tba;
196	struct vsbus_attach_args * const va = aux;
197	struct tc_vsbus_softc * const sc = device_private(self);
198	struct tc_rommap *rommap;
199	bus_space_tag_t bst = va->va_memt;
200	bus_space_handle_t bsh_csr, bsh_slot;
201	const bus_size_t slotb = 4194304;
202	uint32_t csr;
203	int error, slotsz;
204
205	sc->sc_cvec = va->va_cvec;
206
207	error = bus_space_map(bst, KA4x_TCA_CSR, KA4x_TCA_CSR_SZ, 0, &bsh_csr);
208	if (error) {
209		aprint_normal(": failed to map TCA CSR: %d\n", error);
210		return;
211	}
212	sc->sc_bst = bst;
213	sc->sc_bsh_csr = bsh_csr;
214
215	/* Deassert TC option reset and clean up. */
216	csr = bus_space_read_4(bst, bsh_csr, 0);
217	csr &= ~(KA4x_TCA_CSR_TC_TMO | KA4x_TCA_CSR_RST_TC);
218	csr |= KA4x_TCA_CSR_ERR | KA4x_TCA_CSR_INVAL_REF;
219	bus_space_write_4(bst, bsh_csr, 0, csr);
220
221	/*
222	 * Map initial number of "slots" (4 MB each) to read the option ROM
223	 * header.
224	 */
225	error = bus_space_map(bst, KA4x_TCA_BASE, INIT_SLOTSZ * slotb,
226	    BUS_SPACE_MAP_LINEAR, &bsh_slot);
227	if (error) {
228		aprint_normal(": failed to map TC slot: %d", error);
229		goto fail;
230	}
231	/* Determine number of slots required from option ROM header. */
232	slotsz = 0;
233	if (tc_checkslot((tc_addr_t)bus_space_vaddr(bst, bsh_slot), NULL,
234	    &rommap))
235		slotsz = rommap->tcr_ssize.v;
236	if (slotsz == 0) {
237		/* Invalid option ROM header or no option present. */
238		bus_space_unmap(bst, bsh_slot, INIT_SLOTSZ * slotb);
239		goto fail;
240	} else if (slotsz > INIT_SLOTSZ) {
241		/* Remap with actual slot size required. */
242		bus_space_unmap(bst, bsh_slot, INIT_SLOTSZ * slotb);
243		error = bus_space_map(bst, KA4x_TCA_BASE, slotsz * slotb,
244		    BUS_SPACE_MAP_LINEAR, &bsh_slot);
245		if (error) {
246			aprint_normal(": failed to map TC slot: %d", error);
247			goto fail;
248		}
249	} else
250		slotsz = INIT_SLOTSZ;
251
252	/* Pass pre-mapped space for TC drivers not bus_space'ified yet. */
253	sc->sc_slots[0].tcs_addr = (tc_addr_t)bus_space_vaddr(bst, bsh_slot);
254	sc->sc_slots[0].tcs_cookie = sc;
255
256	tba.tba_busname = "tc";
257	/* Tag with custom methods for pre-mapped bus_space. */
258	tba.tba_memt = &vax_tc_bus_space;
259	tba.tba_speed = TC_SPEED_12_5_MHZ;
260	tba.tba_nslots = __arraycount(sc->sc_slots);
261	tba.tba_slots = sc->sc_slots;
262	tba.tba_nbuiltins = 0;
263	tba.tba_intr_evcnt = tc_vsbus_intr_evcnt;
264	tba.tba_intr_establish = tc_vsbus_intr_establish;
265	tba.tba_intr_disestablish = tc_vsbus_intr_disestablish;
266	tba.tba_get_dma_tag = tc_vsbus_get_dma_tag;
267
268	error = tc_vsbus_dma_init(self);
269	if (error) {
270		aprint_normal(": failed to init DMA: %d", error);
271		bus_space_unmap(bst, bsh_slot, slotsz * slotb);
272		goto fail;
273	}
274
275	evcnt_attach_dynamic(&sc->sc_ev, EVCNT_TYPE_INTR, NULL,
276	    device_xname(self), "intr");
277
278	/* Enable SGDMA and option IRQ now. */
279	csr = bus_space_read_4(bst, bsh_csr, 0);
280	csr &= ~(KA4x_TCA_CSR_TC_TMO | KA4x_TCA_CSR_RST_TC);
281	csr |= KA4x_TCA_CSR_ERR | KA4x_TCA_CSR_EN_TC_IRQ |
282	    KA4x_TCA_CSR_INVAL_REF | KA4x_TCA_CSR_EN_MAP;
283	bus_space_write_4(bst, bsh_csr, 0, csr);
284
285	/* XXX: why not config_found(9)?? */
286	tcattach(parent, self, &tba);
287
288	return;
289
290fail:
291	aprint_normal("\n");
292	/* Clear possible timeout bit which asserts TC interrupt. */
293	csr = bus_space_read_4(bst, bsh_csr, 0);
294	csr &= ~KA4x_TCA_CSR_TC_TMO;
295	bus_space_write_4(bst, bsh_csr, 0, csr);
296	bus_space_unmap(bst, bsh_csr, KA4x_TCA_CSR_SZ);
297}
298
299static int
300tc_vsbus_dma_init(device_t dev)
301{
302	struct tc_vsbus_softc * const sc = device_private(dev);
303	struct pte *pte;
304	bus_dma_tag_t dmat = &sc->sc_dmatag;
305	bus_space_tag_t bst = sc->sc_bst;
306	bus_space_handle_t bsh;
307	const bus_size_t ptecnt = 8192;
308	const bus_size_t mapsize = ptecnt * sizeof(pte[0]);
309	int error;
310
311	vax_sgmap_dmatag_init(dmat, sc, ptecnt);
312
313	dmat->_sgmap = &sc->sc_sgmap;
314
315	error = bus_space_map(bst, KA4x_TCA_SGMAP, mapsize,
316	    BUS_SPACE_MAP_LINEAR, &bsh);
317	if (error)
318		return error;
319	bus_space_set_region_4(bst, bsh, 0, 0, ptecnt);
320	pte = bus_space_vaddr(bst, bsh);
321
322	/* Initialize the SGMAP. */
323	vax_sgmap_init(dmat, &sc->sc_sgmap, "tc_sgmap", dmat->_wbase,
324	    dmat->_wsize, pte, 0);
325
326	tc_vsbus_dmat = dmat;
327
328	return 0;
329}
330
331static bus_dma_tag_t
332tc_vsbus_get_dma_tag(int slotno)
333{
334
335	return tc_vsbus_dmat;
336}
337
338static void
339tc_vsbus_intr(void *arg)
340{
341	struct tc_vsbus_softc * const sc = arg;
342	bus_space_tag_t bst = sc->sc_bst;
343	bus_space_handle_t bsh = sc->sc_bsh_csr;
344	uint32_t csr;
345
346	sc->sc_ev.ev_count++;
347
348	csr = bus_space_read_4(bst, bsh, 0);
349	if (__predict_true((csr & KA4x_TCA_CSR_TC_IRQ) == 0))	/* active low */
350		sc->sc_intr_func(sc->sc_intr_arg);
351
352	/* Clear possible timeout bit which asserts TC interrupt. */
353	csr = bus_space_read_4(bst, bsh, 0);
354	csr &= ~KA4x_TCA_CSR_TC_TMO;
355	bus_space_write_4(bst, bsh, 0, csr);
356}
357
358static void
359tc_vsbus_intr_establish(device_t dv, void *cookie, int level,
360    int (*func)(void *), void *arg)
361{
362	struct tc_vsbus_softc * const sc = cookie;
363
364	sc->sc_intr_func = func;
365	sc->sc_intr_arg = arg;
366
367	scb_vecalloc(sc->sc_cvec, tc_vsbus_intr, sc, SCB_ISTACK, &sc->sc_ev);
368}
369
370static void
371tc_vsbus_intr_disestablish(device_t dv, void *cookie)
372{
373
374	/* Do nothing. */
375}
376
377static const struct evcnt *
378tc_vsbus_intr_evcnt(device_t dv, void *cookie)
379{
380	struct tc_vsbus_softc * const sc = device_private(dv);
381
382	return &sc->sc_ev;
383}
384
385static int
386vax_tc_bus_space_map(void *t, bus_addr_t pa, bus_size_t size, int cacheable,
387    bus_space_handle_t *bshp, int f2)
388{
389
390	/* bus_space is pre-mapped, so "pa" is a virtual address already. */
391	*bshp = pa;
392	return 0;
393}
394
395static int
396vax_tc_bus_space_subregion(void *t, bus_space_handle_t h, bus_size_t o,
397    bus_size_t s, bus_space_handle_t *hp)
398{
399
400	*hp = h + o;
401	return 0;
402}
403
404static void
405vax_tc_bus_space_unmap(void *t, bus_space_handle_t h, bus_size_t size, int f)
406{
407
408	/* Do nothing. */
409}
410
411static int
412vax_tc_bus_space_alloc(void *t, bus_addr_t rs, bus_addr_t re, bus_size_t s,
413    bus_size_t a, bus_size_t b, int f, bus_addr_t *ap, bus_space_handle_t *hp)
414{
415
416	panic("vax_tc_bus_space_alloc not implemented");
417}
418
419static void
420vax_tc_bus_space_free(void *t, bus_space_handle_t h, bus_size_t s)
421{
422
423	panic("vax_tc_bus_space_free not implemented");
424}
425
426static paddr_t
427vax_tc_bus_space_mmap(void *v, bus_addr_t addr, off_t off, int prot, int flags)
428{
429	bus_addr_t rv;
430
431	rv = addr + off;
432	return btop(rv);
433}
434