1 /*
2 * Copyright (C) 2003-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: PlayStation 2 misc stuff (timer, DMA, interrupts, ...)
29 *
30 * offset 0x0000 timer control
31 * offset 0x8000 DMA controller
32 * offset 0xf000 Interrupt register
33 *
34 * The 16 normal PS2 interrupts interrupt at MIPS interrupt 2.
35 * The 16 DMA interrupts are connected to MIPS interrupt 3.
36 *
37 * SBUS interrupts go via PS2 interrupt 1.
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "cpu.h"
45 #include "device.h"
46 #include "machine.h"
47 #include "memory.h"
48 #include "misc.h"
49
50 #include "thirdparty/ee_timerreg.h"
51 #include "thirdparty/ps2_dmacreg.h"
52
53
54 #define TICK_STEPS_SHIFT 14
55
56 /* NOTE/TODO: This should be the same as in ps2_gs: */
57 #define DEV_PS2_GIF_FAKE_BASE 0x50000000
58
59 #define N_PS2_DMA_CHANNELS 10
60 #define N_PS2_TIMERS 4
61
62 struct ps2_data {
63 uint32_t timer_count[N_PS2_TIMERS];
64 uint32_t timer_comp[N_PS2_TIMERS];
65 uint32_t timer_mode[N_PS2_TIMERS];
66 uint32_t timer_hold[N_PS2_TIMERS];
67 /* NOTE: only 0 and 1 are valid */
68 struct interrupt timer_irq[N_PS2_TIMERS];
69
70 uint64_t dmac_reg[DMAC_REGSIZE / 0x10];
71 struct interrupt dmac_irq; /* MIPS irq 3 */
72 struct interrupt dma_channel2_irq; /* irq path of channel 2 */
73
74 uint64_t other_memory_base[N_PS2_DMA_CHANNELS];
75
76 uint32_t intr;
77 uint32_t imask;
78 uint32_t sbus_smflg;
79 struct interrupt intr_irq; /* MIPS irq 2 */
80 struct interrupt sbus_irq; /* PS2 irq 1 */
81 };
82
83 #define DEV_PS2_LENGTH 0x10000
84
85
ps2_intr_interrupt_assert(struct interrupt * interrupt)86 void ps2_intr_interrupt_assert(struct interrupt *interrupt)
87 {
88 struct ps2_data *d = (struct ps2_data *) interrupt->extra;
89 d->intr |= (1 << interrupt->line);
90 if (d->intr & d->imask)
91 INTERRUPT_ASSERT(d->intr_irq);
92 }
ps2_intr_interrupt_deassert(struct interrupt * interrupt)93 void ps2_intr_interrupt_deassert(struct interrupt *interrupt)
94 {
95 struct ps2_data *d = (struct ps2_data *) interrupt->extra;
96 d->intr &= ~(1 << interrupt->line);
97 if (!(d->intr & d->imask))
98 INTERRUPT_DEASSERT(d->intr_irq);
99 }
ps2_dmac_interrupt_assert(struct interrupt * interrupt)100 void ps2_dmac_interrupt_assert(struct interrupt *interrupt)
101 {
102 struct ps2_data *d = (struct ps2_data *) interrupt->extra;
103 d->dmac_reg[0x601] |= (1 << interrupt->line);
104 /* TODO: DMA interrupt mask? */
105 if (d->dmac_reg[0x601] & 0xffff)
106 INTERRUPT_ASSERT(d->dmac_irq);
107 }
ps2_dmac_interrupt_deassert(struct interrupt * interrupt)108 void ps2_dmac_interrupt_deassert(struct interrupt *interrupt)
109 {
110 struct ps2_data *d = (struct ps2_data *) interrupt->extra;
111 d->dmac_reg[0x601] &= ~(1 << interrupt->line);
112 /* TODO: DMA interrupt mask? */
113 if (!(d->dmac_reg[0x601] & 0xffff))
114 INTERRUPT_DEASSERT(d->dmac_irq);
115 }
ps2_sbus_interrupt_assert(struct interrupt * interrupt)116 void ps2_sbus_interrupt_assert(struct interrupt *interrupt)
117 {
118 /* Note: sbus irq 0 = mask 0x100, sbus irq 1 = mask 0x400 */
119 struct ps2_data *d = (struct ps2_data *) interrupt->extra;
120 d->sbus_smflg |= (1 << (8 + interrupt->line * 2));
121 /* TODO: SBUS interrupt mask? */
122 if (d->sbus_smflg != 0)
123 INTERRUPT_ASSERT(d->sbus_irq);
124 }
ps2_sbus_interrupt_deassert(struct interrupt * interrupt)125 void ps2_sbus_interrupt_deassert(struct interrupt *interrupt)
126 {
127 /* Note: sbus irq 0 = mask 0x100, sbus irq 1 = mask 0x400 */
128 struct ps2_data *d = (struct ps2_data *) interrupt->extra;
129 d->sbus_smflg &= ~(1 << (8 + interrupt->line * 2));
130 /* TODO: SBUS interrupt mask? */
131 if (d->sbus_smflg == 0)
132 INTERRUPT_DEASSERT(d->sbus_irq);
133 }
134
135
DEVICE_TICK(ps2)136 DEVICE_TICK(ps2)
137 {
138 struct ps2_data *d = (struct ps2_data *) extra;
139 int i;
140
141 /*
142 * Right now this interrupts every now and then.
143 * The main interrupt in NetBSD should be 100 Hz. TODO.
144 */
145 for (i=0; i<N_PS2_TIMERS; i++) {
146 /* Count-up Enable: TODO: by how much? */
147 if (d->timer_mode[i] & T_MODE_CUE)
148 d->timer_count[i] ++;
149
150 if (d->timer_mode[i] & (T_MODE_CMPE | T_MODE_OVFE)) {
151 /* Zero return: */
152 if (d->timer_mode[i] & T_MODE_ZRET)
153 d->timer_count[i] = 0;
154
155 INTERRUPT_ASSERT(d->timer_irq[i]);
156
157 /* timer 1..3 are "single-shot"? TODO */
158 if (i > 0) {
159 d->timer_mode[i] &=
160 ~(T_MODE_CMPE | T_MODE_OVFF);
161 }
162 }
163 }
164 }
165
166
DEVICE_ACCESS(ps2)167 DEVICE_ACCESS(ps2)
168 {
169 uint64_t idata = 0, odata = 0;
170 int regnr = 0;
171 struct ps2_data *d = (struct ps2_data *) extra;
172 int timer_nr = 0;
173
174 if (writeflag == MEM_WRITE)
175 idata = memory_readmax64(cpu, data, len);
176
177 if (relative_addr >= 0x8000 && relative_addr < 0x8000 + DMAC_REGSIZE) {
178 regnr = (relative_addr - 0x8000) / 16;
179 if (writeflag == MEM_READ)
180 odata = d->dmac_reg[regnr];
181 else
182 d->dmac_reg[regnr] = idata;
183 }
184
185 /*
186 * Timer control:
187 * The four timers are at offsets 0, 0x800, 0x1000, and 0x1800.
188 */
189 if (relative_addr < TIMER_REGSIZE) {
190 /* 0, 1, 2, or 3 */
191 timer_nr = (relative_addr & 0x1800) >> 11;
192 relative_addr &= (TIMER_OFS-1);
193 }
194
195 switch (relative_addr) {
196 case 0x0000: /* timer count */
197 if (writeflag == MEM_READ) {
198 odata = d->timer_count[timer_nr];
199 if (timer_nr == 0) {
200 /* :-) TODO: remove this? */
201 d->timer_count[timer_nr] ++;
202 }
203 debug("[ ps2: read timer %i count: 0x%llx ]\n",
204 timer_nr, (long long)odata);
205 } else {
206 d->timer_count[timer_nr] = idata;
207 debug("[ ps2: write timer %i count: 0x%llx ]\n",
208 timer_nr, (long long)idata);
209 }
210 break;
211 case 0x0010: /* timer mode */
212 if (writeflag == MEM_READ) {
213 odata = d->timer_mode[timer_nr];
214 debug("[ ps2: read timer %i mode: 0x%llx ]\n",
215 timer_nr, (long long)odata);
216 } else {
217 d->timer_mode[timer_nr] = idata;
218 debug("[ ps2: write timer %i mode: 0x%llx ]\n",
219 timer_nr, (long long)idata);
220 }
221 break;
222 case 0x0020: /* timer comp */
223 if (writeflag == MEM_READ) {
224 odata = d->timer_comp[timer_nr];
225 debug("[ ps2: read timer %i comp: 0x%llx ]\n",
226 timer_nr, (long long)odata);
227 } else {
228 d->timer_comp[timer_nr] = idata;
229 debug("[ ps2: write timer %i comp: 0x%llx ]\n",
230 timer_nr, (long long)idata);
231 }
232 break;
233 case 0x0030: /* timer hold */
234 if (writeflag == MEM_READ) {
235 odata = d->timer_hold[timer_nr];
236 debug("[ ps2: read timer %i hold: 0x%llx ]\n",
237 timer_nr, (long long)odata);
238 if (timer_nr >= 2)
239 fatal("[ WARNING: ps2: read from non-"
240 "existant timer %i hold register ]\n");
241 } else {
242 d->timer_hold[timer_nr] = idata;
243 debug("[ ps2: write timer %i hold: 0x%llx ]\n",
244 timer_nr, (long long)idata);
245 if (timer_nr >= 2)
246 fatal("[ WARNING: ps2: write to "
247 "non-existant timer %i hold register ]\n",
248 timer_nr);
249 }
250 break;
251
252 case 0x8000 + D2_CHCR_REG:
253 if (writeflag==MEM_READ) {
254 odata = d->dmac_reg[regnr];
255 /* debug("[ ps2: dmac read from D2_CHCR "
256 "(0x%llx) ]\n", (long long)d->dmac_reg[regnr]); */
257 } else {
258 /* debug("[ ps2: dmac write to D2_CHCR, "
259 "data 0x%016llx ]\n", (long long) idata); */
260 if (idata & D_CHCR_STR) {
261 int length = d->dmac_reg[D2_QWC_REG/0x10] * 16;
262 uint64_t from_addr = d->dmac_reg[
263 D2_MADR_REG/0x10];
264 uint64_t to_addr = d->dmac_reg[
265 D2_TADR_REG/0x10];
266 unsigned char *copy_buf;
267
268 debug("[ ps2: dmac [ch2] transfer addr="
269 "0x%016llx len=0x%lx ]\n", (long long)
270 d->dmac_reg[D2_MADR_REG/0x10],
271 (long)length);
272
273 CHECK_ALLOCATION(copy_buf = (unsigned char *) malloc(length));
274
275 cpu->memory_rw(cpu, cpu->mem, from_addr,
276 copy_buf, length, MEM_READ,
277 CACHE_NONE | PHYSICAL);
278 cpu->memory_rw(cpu, cpu->mem,
279 d->other_memory_base[DMA_CH_GIF] + to_addr,
280 copy_buf, length, MEM_WRITE,
281 CACHE_NONE | PHYSICAL);
282 free(copy_buf);
283
284 /* Done with the transfer: */
285 d->dmac_reg[D2_QWC_REG/0x10] = 0;
286 idata &= ~D_CHCR_STR;
287
288 /* interrupt DMA channel 2 */
289 INTERRUPT_ASSERT(d->dma_channel2_irq);
290 } else
291 debug("[ ps2: dmac [ch2] stopping "
292 "transfer ]\n");
293 d->dmac_reg[regnr] = idata;
294 return 1;
295 }
296 break;
297
298 case 0x8000 + D2_QWC_REG:
299 case 0x8000 + D2_MADR_REG:
300 case 0x8000 + D2_TADR_REG:
301 /* no debug output */
302 break;
303
304 case 0xe010: /* dmac interrupt status (and mask, */
305 /* the upper 16 bits) */
306 if (writeflag == MEM_WRITE) {
307 uint32_t oldmask = d->dmac_reg[regnr] & 0xffff0000;
308 /* Clear out those bits that are set in idata: */
309 d->dmac_reg[regnr] &= ~idata;
310 d->dmac_reg[regnr] &= 0xffff;
311 d->dmac_reg[regnr] |= oldmask;
312 if (((d->dmac_reg[regnr] & 0xffff) &
313 ((d->dmac_reg[regnr]>>16) & 0xffff)) == 0) {
314 INTERRUPT_DEASSERT(d->dmac_irq);
315 }
316 } else {
317 /* Hm... make it seem like the mask bits are (at
318 least as much as) the interrupt assertions: */
319 odata = d->dmac_reg[regnr];
320 odata |= (odata << 16);
321 }
322 break;
323
324 case 0xf000: /* interrupt register */
325 if (writeflag == MEM_READ) {
326 odata = d->intr;
327 debug("[ ps2: read from Interrupt Register:"
328 " 0x%llx ]\n", (long long)odata);
329
330 /* TODO: This is _NOT_ correct behavior: */
331 // d->intr = 0;
332 // INTERRUPT_DEASSERT(d->intr_irq);
333 } else {
334 debug("[ ps2: write to Interrupt Register: "
335 "0x%llx ]\n", (long long)idata);
336 /* Clear out bits that are set in idata: */
337 d->intr &= ~idata;
338
339 if ((d->intr & d->imask) == 0)
340 INTERRUPT_DEASSERT(d->intr_irq);
341 }
342 break;
343
344 case 0xf010: /* interrupt mask */
345 if (writeflag == MEM_READ) {
346 odata = d->imask;
347 /* debug("[ ps2: read from Interrupt Mask "
348 "Register: 0x%llx ]\n", (long long)odata); */
349 } else {
350 /* debug("[ ps2: write to Interrupt Mask "
351 "Register: 0x%llx ]\n", (long long)idata); */
352 /* Note: written value indicates which bits
353 to _toggle_, not which bits to set! */
354 d->imask ^= idata;
355 }
356 break;
357
358 case 0xf230: /* sbus interrupt register? */
359 if (writeflag == MEM_READ) {
360 odata = d->sbus_smflg;
361 debug("[ ps2: read from SBUS SMFLG:"
362 " 0x%llx ]\n", (long long)odata);
363 } else {
364 /* Clear bits on write: */
365 debug("[ ps2: write to SBUS SMFLG:"
366 " 0x%llx ]\n", (long long)idata);
367 d->sbus_smflg &= ~idata;
368 /* irq 1 is SBUS */
369 if (d->sbus_smflg == 0)
370 INTERRUPT_DEASSERT(d->sbus_irq);
371 }
372 break;
373 default:
374 if (writeflag==MEM_READ) {
375 debug("[ ps2: read from addr 0x%x: 0x%llx ]\n",
376 (int)relative_addr, (long long)odata);
377 } else {
378 debug("[ ps2: write to addr 0x%x: 0x%llx ]\n",
379 (int)relative_addr, (long long)idata);
380 }
381 }
382
383 if (writeflag == MEM_READ)
384 memory_writemax64(cpu, data, len, odata);
385
386 return 1;
387 }
388
389
DEVINIT(ps2)390 DEVINIT(ps2)
391 {
392 struct ps2_data *d;
393 int i;
394 struct interrupt templ;
395 char n[300];
396
397 CHECK_ALLOCATION(d = (struct ps2_data *) malloc(sizeof(struct ps2_data)));
398 memset(d, 0, sizeof(struct ps2_data));
399
400 d->other_memory_base[DMA_CH_GIF] = DEV_PS2_GIF_FAKE_BASE;
401
402 /* Connect to MIPS irq 2 (interrupt controller) and 3 (dmac): */
403 snprintf(n, sizeof(n), "%s.2", devinit->interrupt_path);
404 INTERRUPT_CONNECT(n, d->intr_irq);
405 snprintf(n, sizeof(n), "%s.3", devinit->interrupt_path);
406 INTERRUPT_CONNECT(n, d->dmac_irq);
407
408 /*
409 * Register interrupts:
410 *
411 * 16 normal IRQs (machine[x].cpu[x].ps2_intr.%i)
412 * 16 DMA IRQs (machine[x].cpu[x].ps2_dmac.%i)
413 * 2 sbus IRQs (machine[x].cpu[x].ps2_sbus.%i)
414 */
415 for (i=0; i<16; i++) {
416 snprintf(n, sizeof(n), "%s.ps2_intr.%i",
417 devinit->interrupt_path, i);
418 memset(&templ, 0, sizeof(templ));
419 templ.line = i;
420 templ.name = n;
421 templ.extra = d;
422 templ.interrupt_assert = ps2_intr_interrupt_assert;
423 templ.interrupt_deassert = ps2_intr_interrupt_deassert;
424 interrupt_handler_register(&templ);
425 }
426 for (i=0; i<16; i++) {
427 snprintf(n, sizeof(n), "%s.ps2_dmac.%i",
428 devinit->interrupt_path, i);
429 memset(&templ, 0, sizeof(templ));
430 templ.line = i;
431 templ.name = n;
432 templ.extra = d;
433 templ.interrupt_assert = ps2_dmac_interrupt_assert;
434 templ.interrupt_deassert = ps2_dmac_interrupt_deassert;
435 interrupt_handler_register(&templ);
436 }
437 for (i=0; i<2; i++) {
438 snprintf(n, sizeof(n), "%s.ps2_sbus.%i",
439 devinit->interrupt_path, i);
440 memset(&templ, 0, sizeof(templ));
441 templ.line = i;
442 templ.name = n;
443 templ.extra = d;
444 templ.interrupt_assert = ps2_sbus_interrupt_assert;
445 templ.interrupt_deassert = ps2_sbus_interrupt_deassert;
446 interrupt_handler_register(&templ);
447 }
448
449 /* Connect to DMA channel 2 irq: */
450 snprintf(n, sizeof(n), "%s.ps2_dmac.2", devinit->interrupt_path);
451 INTERRUPT_CONNECT(n, d->dma_channel2_irq);
452
453 /* Connect to SBUS interrupt, at ps2 interrupt 1: */
454 snprintf(n, sizeof(n), "%s.ps2_intr.1", devinit->interrupt_path);
455 INTERRUPT_CONNECT(n, d->sbus_irq);
456
457 /* Connect to the timers' interrupts: */
458 for (i=0; i<N_PS2_TIMERS; i++) {
459 /* PS2 irq 9 is timer0, etc. */
460 snprintf(n, sizeof(n), "%s.ps2_intr.%i",
461 devinit->interrupt_path, 9 + i);
462 INTERRUPT_CONNECT(n, d->timer_irq[i]);
463 }
464
465 memory_device_register(devinit->machine->memory, "ps2", devinit->addr,
466 DEV_PS2_LENGTH, dev_ps2_access, d, DM_DEFAULT, NULL);
467 machine_add_tickfunction(devinit->machine,
468 dev_ps2_tick, d, TICK_STEPS_SHIFT);
469
470 return 1;
471 }
472
473