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