1 /* $NetBSD: pci_hades.c,v 1.16 2019/05/04 09:03:08 tsutsui Exp $ */
2
3 /*
4 * Copyright (c) 1996 Leo Weppelman. All rights reserved.
5 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
6 * Copyright (c) 1994 Charles M. Hannum. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Charles M. Hannum.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: pci_hades.c,v 1.16 2019/05/04 09:03:08 tsutsui Exp $");
36
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41
42 #include <uvm/uvm_extern.h>
43
44 #include <sys/bus.h>
45
46 #include <dev/pci/pcivar.h>
47 #include <dev/pci/pcireg.h>
48
49 #include <machine/cpu.h>
50 #include <machine/iomap.h>
51 #include <machine/mfp.h>
52 #include <sys/bswap.h>
53
54 #include <atari/atari/device.h>
55 #include <atari/pci/pci_vga.h>
56 #include <atari/dev/grf_etreg.h>
57
58 int
pci_bus_maxdevs(pci_chipset_tag_t pc,int busno)59 pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
60 {
61
62 return 4;
63 }
64
65 static int pci_config_offset(pcitag_t);
66
67 /*
68 * Atari_init.c maps the config areas PAGE_SIZE bytes apart....
69 */
70 static int
pci_config_offset(pcitag_t tag)71 pci_config_offset(pcitag_t tag)
72 {
73 int device;
74
75 device = (tag >> 11) & 0x1f;
76
77 return device * PAGE_SIZE;
78 }
79
80 pcireg_t
pci_conf_read(pci_chipset_tag_t pc,pcitag_t tag,int reg)81 pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
82 {
83 uint32_t data;
84
85 if ((uint32_t)reg >= PCI_CONF_SIZE)
86 return 0xffffffff;
87
88 data = *(uint32_t *)(pci_conf_addr + pci_config_offset(tag) + reg);
89 return bswap32(data);
90 }
91
92 void
pci_conf_write(pci_chipset_tag_t pc,pcitag_t tag,int reg,pcireg_t data)93 pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
94 {
95
96 if ((uint32_t)reg >= PCI_CONF_SIZE)
97 return;
98
99 *((uint32_t *)(pci_conf_addr + pci_config_offset(tag) + reg))
100 = bswap32(data);
101 }
102
103 /*
104 * The interrupt stuff is rather ugly. On the Hades, all interrupt lines
105 * for a slot are wired together and connected to IO 0,1,2 or 5 (slots:
106 * (0-3) on the TT-MFP. The Pci-config code initializes the irq. number
107 * to the slot position.
108 */
109 static pci_intr_info_t iinfo[4] = { { -1 }, { -1 }, { -1 }, { -1 } };
110
111 static int iifun(int, int);
112
113 static int
iifun(int slot,int sr)114 iifun(int slot, int sr)
115 {
116 pci_intr_info_t *iinfo_p;
117 int s;
118
119 iinfo_p = &iinfo[slot];
120
121 /*
122 * Disable the interrupts
123 */
124 MFP2->mf_imrb &= ~iinfo_p->imask;
125
126 if ((sr & PSL_IPL) >= (iinfo_p->ipl & PSL_IPL)) {
127 /*
128 * We're running at a too high priority now.
129 */
130 add_sicallback((si_farg)iifun, (void*)slot, 0);
131 } else {
132 s = splx(iinfo_p->ipl);
133 (void)(iinfo_p->ifunc)(iinfo_p->iarg);
134 splx(s);
135
136 /*
137 * Re-enable interrupts after handling
138 */
139 MFP2->mf_imrb |= iinfo_p->imask;
140 }
141 return 1;
142 }
143
144 int
pci_intr_setattr(pci_chipset_tag_t pc,pci_intr_handle_t * ih,int attr,uint64_t data)145 pci_intr_setattr(pci_chipset_tag_t pc, pci_intr_handle_t *ih,
146 int attr, uint64_t data)
147 {
148
149 switch (attr) {
150 case PCI_INTR_MPSAFE:
151 return 0;
152 default:
153 return ENODEV;
154 }
155 }
156
157 void *
pci_intr_establish(pci_chipset_tag_t pc,pci_intr_handle_t ih,int level,int (* ih_fun)(void *),void * ih_arg)158 pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
159 int (*ih_fun)(void *), void *ih_arg)
160 {
161 pci_intr_info_t *iinfo_p;
162 struct intrhand *ihand;
163 int slot;
164
165 slot = ih;
166 iinfo_p = &iinfo[slot];
167
168 if (iinfo_p->ipl > 0)
169 panic("pci_intr_establish: interrupt was already established");
170
171 ihand = intr_establish((slot == 3) ? 23 : 16 + slot, USER_VEC, 0,
172 (hw_ifun_t)iifun, (void *)slot);
173 if (ihand != NULL) {
174 iinfo_p->ipl = level;
175 iinfo_p->imask = (slot == 3) ? 0x80 : (0x01 << slot);
176 iinfo_p->ifunc = ih_fun;
177 iinfo_p->iarg = ih_arg;
178 iinfo_p->ihand = ihand;
179
180 /*
181 * Enable (unmask) the interrupt
182 */
183 MFP2->mf_imrb |= iinfo_p->imask;
184 MFP2->mf_ierb |= iinfo_p->imask;
185 return iinfo_p;
186 }
187 return NULL;
188 }
189
190 void
pci_intr_disestablish(pci_chipset_tag_t pc,void * cookie)191 pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
192 {
193 pci_intr_info_t *iinfo_p = (pci_intr_info_t *)cookie;
194
195 if (iinfo->ipl < 0)
196 panic("pci_intr_disestablish: interrupt was not established");
197
198 MFP2->mf_imrb &= ~iinfo->imask;
199 MFP2->mf_ierb &= ~iinfo->imask;
200 (void)intr_disestablish(iinfo_p->ihand);
201 iinfo_p->ipl = -1;
202 }
203
204 /*
205 * XXX: Why are we repeating this everywhere! (Leo)
206 */
207 #define PCI_LINMEMBASE 0x0e000000
208
209 static const uint8_t crt_tab[] = {
210 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
211 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
212 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
213 0xff };
214
215 static const uint8_t seq_tab[] = {
216 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00
217 };
218
219 static const uint8_t attr_tab[] = {
220 0x0c, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00
221 };
222
223 static const uint8_t gdc_tab[] = {
224 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff
225 };
226
227 void
ati_vga_init(pci_chipset_tag_t pc,pcitag_t tag,int id,volatile uint8_t * ba,uint8_t * fb)228 ati_vga_init(pci_chipset_tag_t pc, pcitag_t tag, int id, volatile uint8_t *ba,
229 uint8_t *fb)
230 {
231 uint32_t csr;
232 int i;
233
234 /* Turn on the card */
235 pci_conf_write(pc, tag, PCI_MAPREG_START, PCI_LINMEMBASE);
236 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
237 csr |= (PCI_COMMAND_MEM_ENABLE|PCI_COMMAND_IO_ENABLE);
238 csr |= PCI_COMMAND_MASTER_ENABLE;
239 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr);
240
241 /*
242 * Make sure we're allowed to write all crt-registers and reload them.
243 */
244 WCrt(ba, CRT_ID_END_VER_RETR, (RCrt(ba, CRT_ID_END_VER_RETR) & 0x7f));
245
246 for (i = 0; i < 0x18; i++)
247 WCrt(ba, i, crt_tab[i]);
248 for (i = 0; i < 8; i++)
249 WSeq(ba, i, seq_tab[i]);
250 for (i = 0; i < 9; i++)
251 WGfx(ba, i, gdc_tab[i]);
252 for (i = 0x10; i < 0x18; i++)
253 WAttr(ba, i, attr_tab[i - 0x10]);
254 WAttr(ba, 0x20, 0);
255 }
256