/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */

#ifndef lint
static char    *rcsid = "$Header:rbinit.c 12.0$";
#endif


#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include "pcparam.h"
#include "abios_st.h"
#include "dio.h"
#include "rb.h"
#include "bios.h"
#include "vga.h"
#include "vars.h"
#include "mc.h"


extern struct dio_rtn_codes *hd_return_code[];	/* In dio.c   */
extern struct dio_rtn_codes *fd_return_code[];	/* In dio.c   */
extern struct dio_rtn_codes *op_return_code;	/* In opdio.c   */
extern struct ubpc *ub_pc;
extern struct XCLOCK xclock;
extern struct msdata msdata;
extern struct spkdata spkdata[];
extern struct mask_int old_mask;
extern struct debug_info debug_info[];
extern u_short  debug_size;
extern struct mcdev MCFAR mcdev[];	/* for sharing information */


/*
 * The rest are defined in rb.c
 */


extern struct vga_params *vga;



extern char    *rbrcsid;
extern struct kbdata kbdata[NCPU];


#ifdef DEBUG
extern struct defaults defaults[];
#endif /* DEBUG */


/*
 * Code
 */


/*************************************************************************
 * rompstart - start up the Coprocessor.
 *
 *           Front end to the pcifmove function.
 *
 * This routine starts the coprocessor by placing the ipl address
 * into physical location 0 and setting the IPL complete bit in
 * the PCIF romp control register.
 */

void rompstart(addr)
	u_long          addr;
{

	u_long          raddr = exchl(addr);	/* Back to IBM format from
						 * Intel Format */
	if (cur_cbcb->cpu == 0)
		printf("Start Coprocessor %d at %#lx\n", cur_cbcb->cpu, addr);
	else
		printf("Set IPL address Coprocessor %d to %#lx\n", cur_cbcb->cpu, addr);

	/*
	 * Write the IAR address to 0  and tell coprocessor to start running 
	 */
	if (moveout(0L, (char far *) &raddr, 4) < 0)
		pcpanic("Failed write of ipl address");
	else if (cur_cbcb->cpu == 0 || (option_flag&OPTION_AUTOIPL)) {
		SETBIT(cur_cbcb->port+R_CTRL, R_IPLC);
		cur_cbcb->state = STATE_RUNNING;
	}
}





void init_wind(base)			/* initialize ROMP windows */
u_short		base;
{
	register int    j;

	for (j = 0; j <= 3; j++)
		IOOUT((base + j), j);
}

int rompinit(base,pc_base)			/* initialize the ROMP per the */
u_short	base;
u_long pc_base;

{

	u_short         j;
#ifdef DEBUG
	register int    initdebug = *dbugptr & INITDEBUG;
#endif /* DEBUG */


	DEBUGF(initdebug, printf("Initialize Coprocessor: %x\n",base));
	DEBUGF(initdebug, printf("\tpcif is at 0x%lx\n", (long) pc_base));

	if (option_flag&OPTION_AT) {
		outp(0x43,0x76);	/* increase pc refresh rate */
		outp(0x41,0x0c);
		outp(0x41,0x00);
	}
	RSETALL(base+P_CTRL);	/* reset all the PCIF registers */
	RSETALL(base+P_STAT);
	RSETALL(base+R_CLOCK);
	RSETALL(base+R_CTRL);
	RSETALL(base+R_INTR);

	if (option_flag&OPTION_AT) {
		outp(0xd6,0xc1);
		outp(0xd4,0x01);
	}

	DEBUGF(initdebug, printf("\tReset all the PCIF registers\n"));

	SETBIT(base+R_CTRL, R_MM);	/* turn on master mode in PCIF */
	DEBUGF(initdebug, printf("\tTurn on Master Mode\n"));


	if (intlv_flag)
	{
		SETBIT(base+R_CTRL, R_INTL);	/* turn on interleaved mode */
		DEBUGF(initdebug, printf("\tInterleave On\n"));
	}
	IOOUT(base+P_BASE, (pc_base >> 18));	/* set the PC base address */
	SETBIT(base+P_CTRL, P_ECCON);/* enable ecc correction */

	SETBIT(base+P_CTRL, P_2WIND);/* enable first two windows */
	SETBIT(base+P_CTRL, P_4WIND);/* enable next two windows */

	SETBIT(base+R_CLOCK, R_CPOR);/* POR the ROMP */
	DELAY(10);
	RSETBIT(base+R_CLOCK, R_CPOR);	/* turn off POR */
	DELAY(10);
	SETBIT(base+R_CLOCK, R_RSET);
	DELAY(10);
	RSETBIT(base+R_CLOCK, R_RSET);

	j = IOIN(base+R_STAT) & 0x00ff;
	if (j != 0x7f)		/* if ROMP status is bad */
		return (j);	/* return with error */
	else
		return (0);
}




/*
 * init_cbcb - Initialize the cbcb
 *
 *   Zero it out, then fill in the addresses of the PC control blocks that
 *   we know about.
 */

void init_cbcb(cbcb)
	struct cbcb    *cbcb;
{
	register int    i;
	char far       *farptr;
	int		cpu = cbcb->cpu;
#ifdef DEBUG
	u_short         ldebug = (*dbugptr & INITDEBUG) != 0;
#endif

	DEBUGF(ldebug, printf("Initialize the cbcb\n",cbcb));


	for (i=0; i<ncpu; ++i)
	{
		farptr = (char far *) &cbcbptr[i];
		cbcb->cbcb[i] = exchl(physaddr((u_long) farptr, 0, 0));
	}
	farptr = (char far *) cbcb->vec_map;
	cbcb->cbcb_ent[SVENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	farptr = (char far *) &kbdata[cpu];
	cbcb->cbcb_ent[KBENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	farptr = (char far *) &xclock;
	cbcb->cbcb_ent[CLENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	hd_return_code[cpu] = cpu + (struct dio_rtn_codes *) align(hd_return_code[0],4,int);
	farptr = (char far *) (hd_return_code[cpu]);
	cbcb->cbcb_ent[HDENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	fd_return_code[cpu] = cpu + (struct dio_rtn_codes *) align(fd_return_code[0],4,int);
	farptr = (char far *) (fd_return_code[cpu]);
	cbcb->cbcb_ent[FDENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	farptr = (char far *) op_return_code;
	cbcb->cbcb_ent[OPENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	farptr = (char far *) &vga[cpu];
	cbcb->cbcb_ent[BIOSENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	farptr = (char far *) &mcdev[cpu];
	cbcb->cbcb_ent[MCENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	ub_pc = (struct ubpc *) align(ub_pc,4,int);
	farptr = (char far *) ub_pc;
	cbcb->cbcb_ent[UBENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	cbcb->cbcb_ent[AFIENT].pc_cb = exchl(physaddr((u_long) 0, 0, 0));


	farptr = (char far *) &msdata;
	cbcb->cbcb_ent[MSENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	farptr = (char far *) &spkdata[cpu];
	cbcb->cbcb_ent[SPKENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

	farptr = (char far *) &old_mask;
	cbcb->cbcb_ent[MASKENT].pc_cb = exchl(physaddr((u_long) farptr, 0, 0));

#ifdef DEBUG
	cbcb->dummy2 = '>';
	cbcb->dummy3 = '<';
	cbcb->debug = debug;
#endif /* DEBUG */

	farptr = (char far *) &debug_info[0];
	cbcb->debug_info = exchl(physaddr((u_long) farptr, 0, 0));
	cbcb->debug_size = exchw(debug_size);
	cbcb->magic = exchw(CBCB_MAGIC);	/* put in magic # */
}


/*
 * Initialize memory on the coprocessor.
 *
 * This routine enables num_win PC to Unix windows, then
 * it writes all zeros to all of coprocessor memmory.
 */
void init_rmem(cbcb,num_win)
	struct cbcb    *cbcb;
	int             num_win;
{
	int             i;
	u_short		base = cbcb->port;
	u_long          lval1, addr;
	char far       *buff = (char far *) buff_dio;

#ifdef DEBUG
	int             ldebug = *dbugptr & INITDEBUG;	/* Local debug flag */
#endif /* DEBUG */

	for (i = 0; i < num_win; i++)	/* Enable the windows */
		SETBIT(base+P_CTRL, i);


	for (lval1 = 0; lval1 < MEMBLOCK; lval1++)
		buff[lval1] = 0;	/* make sure its zero */

	printf("\nClear Coprocessor Memory (%#lx):\n", cbcb->physmem_bytes);

	addr = 0;
	while (addr < cbcb->physmem_bytes)
	{
		lval1 = cbcb->physmem_bytes - addr;
		if (lval1 > MEMBLOCK)
			lval1 = MEMBLOCK;

		if ((i = moveout((u_long) addr, (char far *) buff, LOWORD(lval1))) < 0)
		{
			i = LOBYTE(i);
			printf("(%d) Error Clearing Memory\n", i);
			pcpanic("Can't clear memory");
		}
		addr += lval1;
		printf("%#lx\r", addr);
	}
	printf("\n");

	for (i = 0; i < num_win; i++)
		RSETBIT(base+P_CTRL, i);

	DEBUGF(ldebug, printf("init_rmem() exit\n"));
}


/*
 * reset the romp when we are about to go back to DOS
 */
romp_reset()
{
	SETBIT(cur_cbcb->port+R_CLOCK, R_CPOR);	/* POR the ROMP */
	DELAY(10);
	RSETBIT(cur_cbcb->port+R_CLOCK, R_CPOR);	/* turn off POR */
	DELAY(10);
	SETBIT(cur_cbcb->port+R_CLOCK, R_RSET);
	DELAY(10);
	RSETBIT(cur_cbcb->port+R_CLOCK, R_RSET);
	DELAY(10);
}

romprestart()
{
	struct restart rest_block, rest_block2;

	if (movein(RESTART_ADDR, (char far *) &rest_block, 
			sizeof rest_block) < 0)
		pcpanic("couldn't read restart block");
	if (exchl(rest_block.magic) != RESTART_MAGIC)
		pcpanic("coprocessor not waiting for restart");
	DELAY(10);	/* allow it to be incremented */
	if (movein(RESTART_ADDR, (char far *) &rest_block2, 
			sizeof rest_block) < 0)
		pcpanic("couldn't read restart block");
	if (rest_block.counter == rest_block2.counter)
		pcpanic("coprocessor isn't running");
	rest_block.magic = 0;	/* tell it we're ready to go */
	if (moveout(RESTART_ADDR, (char far *) &rest_block, 
			sizeof rest_block) < 0)
		pcpanic("couldn't write restart block");

}
