/*	$NetBSD: autoconf.c,v 1.29 2017/05/22 16:59:32 ragge Exp $ */
/*
 * Copyright (c) 1994, 1998 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

 /* All bugs are subject to removal without further notice */
		


#include <sys/param.h>

#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include "../include/mtpr.h"
#include "../include/sid.h"
#include "../include/intr.h"
#include "../include/rpb.h"
#include "../include/scb.h"

#include "vaxstand.h"

void autoconf(void);
void findcpu(void);
void consinit(void);
void scbinit(void);
void scb_stray(void *);
void longjmp(int *, int);
void rtimer(void *);

long *bootregs;

/*
 * Do some initial setup. Also create a fake RPB for net-booted machines
 * that don't have an in-prom VMB.
 */

void
autoconf(void)
{
	int copyrpb = 1;
	int fromnet = (bootregs[12] != -1);

	findcpu(); /* Configures CPU variables */
	consinit(); /* Allow us to print out things */
	scbinit(); /* Fix interval clock etc */

#ifdef DEV_DEBUG
	printf("Register contents:\n");
	for (copyrpb = 0; copyrpb < 13; copyrpb++)
		printf("r%d: %lx\n", copyrpb, bootregs[copyrpb]);
#endif
	switch (vax_boardtype) {

	case VAX_BTYP_780:
	case VAX_BTYP_790:
	case VAX_BTYP_8000:
	case VAX_BTYP_9CC:
	case VAX_BTYP_9RR:
	case VAX_BTYP_1202:
		if (fromnet == 0)
			break;
		copyrpb = 0;
		bootrpb.devtyp = bootregs[0];
		bootrpb.adpphy = bootregs[1];
		bootrpb.csrphy = bootregs[2];
		bootrpb.unit = bootregs[3];
		bootrpb.rpb_bootr5 = bootregs[5];
		bootrpb.pfncnt = 0;
		break;

	case VAX_BTYP_46:
	case VAX_BTYP_48:
		{int *map, i;

		/* Map all 16MB of I/O space to low 16MB of memory */
		map = (int *)0x700000; /* XXX */
		*(int *)0x20080008 = (int)map; /* XXX */
		for (i = 0; i < 0x8000; i++)
			map[i] = 0x80000000 | i;
		}break;

		break;
	}

	if (copyrpb) {
		struct rpb *prpb = (struct rpb *)bootregs[11];
		memcpy(&bootrpb, (void *)prpb, sizeof(struct rpb));
		if (prpb->iovec) {
			bootrpb.iovec = (int)alloc(prpb->iovecsz);
			memcpy((void *)bootrpb.iovec, (void *)prpb->iovec,
			    prpb->iovecsz);
		}
	}
}

/*
 * Clock handling routines, needed to do timing in standalone programs.
 */

volatile int tickcnt;

satime_t
getsecs(void)
{
	return tickcnt/100;
}

struct ivec_dsp **scb;
struct ivec_dsp *scb_vec;
extern struct ivec_dsp idsptch;
extern int jbuf[10];

static void
mcheck(void *arg)
{
	int off, *mfp = (int *)(void *)&arg;

	off = (mfp[7]/4 + 8);
	printf("Machine check, pc=%x, psl=%x\n", mfp[off], mfp[off+1]);
	longjmp(jbuf, 1);
}

/*
 * Init the SCB and set up a handler for all vectors in the lower space,
 * to detect unwanted interrupts.
 */
void
scbinit(void)
{
	int i, addr;

	/*
	 * Allocate space. We need one page for the SCB, and 128*20 == 2.5k
	 * for the vectors. The SCB must be on a page boundary.
	 */
	i = (int)alloc(VAX_NBPG + 128*sizeof(scb_vec[0])) + VAX_PGOFSET;
	i &= ~VAX_PGOFSET;

	mtpr(i, PR_SCBB);
	scb = (void *)i;
	scb_vec = (struct ivec_dsp *)(i + VAX_NBPG);

	for (i = 0; i < 128; i++) {
		scb[i] = &scb_vec[i];
		addr = (int)scb[i];
		addr |= SCB_ISTACK;		/* Only interrupt stack */
		scb[i] = (struct ivec_dsp*)addr;
		scb_vec[i] = idsptch;
		scb_vec[i].hoppaddr = scb_stray;
		scb_vec[i].pushlarg = (void *) (i * 4);
		scb_vec[i].ev = NULL;
	}
	scb_vec[0xc0/4].hoppaddr = rtimer;
	scb_vec[4/4].hoppaddr = mcheck;

	if (vax_boardtype != VAX_BTYP_VXT)
		mtpr(-10000, PR_NICR);		/* Load in count register */
	mtpr(0x800000d1, PR_ICCS);	/* Start clock and enable interrupt */

	mtpr(20, PR_IPL);
}

extern int sluttid, senast, skip;

void
rtimer(void *arg)
{
	mtpr(IPL_HIGH, PR_IPL);
	tickcnt++;
	mtpr(0xc1, PR_ICCS);
	if (skip)
		return;
	if ((vax_boardtype == VAX_BTYP_46) ||
	    (vax_boardtype == VAX_BTYP_48) ||
	    (vax_boardtype == VAX_BTYP_49)) {
		int nu = sluttid - getsecs();
		if (senast != nu) {
			mtpr(20, PR_IPL);
			longjmp(jbuf, 1);
		}
	}
}

#ifdef __ELF__
#define	IDSPTCH "idsptch"
#define	EIDSPTCH "eidsptch"
#define	CMN_IDSPTCH "cmn_idsptch"
#else
#define	IDSPTCH "_idsptch"
#define	EIDSPTCH "_eidsptch"
#define	CMN_IDSPTCH "_cmn_idsptch"
#endif

__asm(
"	.text;"
"	.align	2;"
"	.globl  " IDSPTCH ", " EIDSPTCH ";"
IDSPTCH ":;"
"	pushr   $0x3f;"
"	.word	0x9f16;"
"	.long   " CMN_IDSPTCH ";"
"	.long	0;"
"	.long	0;"
"	.long	0;"
EIDSPTCH ":;"

CMN_IDSPTCH ":;"
"	movl	(%sp)+,%r0;"
"	pushl	4(%r0);"
"	calls	$1,*(%r0);"
"	popr	$0x3f;"
"	rei;"
);

/*
 * Stray interrupt handler.
 * This function must _not_ save any registers (in the reg save mask).
 */
void
scb_stray(void *arg)
{
	static int vector, ipl;

	ipl = mfpr(PR_IPL);
	vector = (int) arg;
	printf("stray interrupt: vector 0x%x, ipl %d\n", vector, ipl);
}
