#ifndef __SPARC_OPENPROM_H
#define __SPARC_OPENPROM_H

/* openprom.h:  Prom structures and defines for access to the OPENBOOT
 *              prom routines and data areas.
 *
 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 */

/* In the v0 interface of the openboot prom we could traverse a nice
 * little list structure to figure out where in vm-space the prom had
 * mapped itself and how much space it was taking up. In the v2 prom
 * interface we have to rely on 'magic' values. :-( Most of the machines
 * I have checked on have the prom mapped here all the time though.
 */

#define KADB_DEBUGGER_BEGVM     0xffc00000    /* Where kern debugger is in virt-mem */

#define	LINUX_OPPROM_BEGVM	0xffd00000
#define	LINUX_OPPROM_ENDVM	0xfff00000

#define	LINUX_OPPROM_MAGIC      0x10010407

#ifndef __ASSEMBLY__
/* The device functions structure for the v0 prom. Nice and neat, open,
 * close, read & write divvied up between net + block + char devices. We
 * also have a seek routine only usable for block devices. The divide
 * and conquer strategy of this struct becomes unnecessary for v2.
 *
 * V0 device names are limited to two characters, 'sd' for scsi-disk,
 * 'le' for local-ethernet, etc. Note that it is technically possible
 * to boot a kernel off of a tape drive and use the tape as the root
 * partition! In order to do this you have to have 'magic' formatted
 * tapes from Sun supposedly :-)
 */

struct linux_dev_v0_funcs {
	int	(*v0_devopen)(char *device_str);
	int	(*v0_devclose)(int dev_desc);
	int	(*v0_rdblkdev)(int dev_desc, int num_blks, int blk_st, char*  buf);
	int	(*v0_wrblkdev)(int dev_desc, int num_blks, int blk_st, char*  buf);
	int	(*v0_wrnetdev)(int dev_desc, int num_bytes, char*  buf);
	int	(*v0_rdnetdev)(int dev_desc, int num_bytes, char*  buf);
	int	(*v0_rdchardev)(int dev_desc, int num_bytes, int dummy, char*  buf);
	int	(*v0_wrchardev)(int dev_desc, int num_bytes, int dummy, char*  buf);
	int	(*v0_seekdev)(int dev_desc, long logical_offst, int from);
};

/* The OpenBoot Prom device operations for version-2 interfaces are both
 * good and bad. They now allow you to address ANY device whatsoever
 * that is in the machine via these funny "device paths". They look like
 * this:
 *
 *   "/sbus/esp@0,0xf004002c/sd@3,1"
 *
 * You can basically reference any device on the machine this way, and
 * you pass this string to the v2 dev_ops. Producing these strings all
 * the time can be a pain in the rear after a while. Why v2 has memory
 * allocations in here are beyond me. Perhaps they figure that if you
 * are going to use only the prom's device drivers then your memory
 * management is either non-existent or pretty sad. :-)
 */

struct linux_dev_v2_funcs {
	int	(*v2_inst2pkg)(int d);	/* Convert ihandle to phandle */

	/* "dumb" prom memory management routines, probably
	 *  only safe to use for mapping device address spaces...
         */

	char* 	(*v2_dumb_mem_alloc)(char*  va, unsigned sz);
	void	(*v2_dumb_mem_free)(char*  va, unsigned sz);

	/* "dumb" mmap() munmap(), copy on write? what's that? */
	char* 	(*v2_dumb_mmap)(char*  virta, int which_io, unsigned paddr, unsigned sz);
	void	(*v2_dumb_munmap)(char*  virta, unsigned size);

	/* Basic Operations, self-explanatory */
	int	(*v2_dev_open)(char *devpath);
	void	(*v2_dev_close)(int d);
	int	(*v2_dev_read)(int d, char*  buf, int nbytes);
	int	(*v2_dev_write)(int d, char*  buf, int nbytes);
	void	(*v2_dev_seek)(int d, int hi, int lo);

	/* Never issued (multistage load support) */
	void	(*v2_wheee2)(void);
	void	(*v2_wheee3)(void);
};

/* Just like the device ops, they slightly screwed up the mem-list
 * from v0 to v2. Probably easier on the prom-writer dude, sucks for
 * us though. See above comment about prom-vm mapped address space
 * magic numbers. :-(
 */

struct linux_mlist_v0 {
	struct	linux_mlist_v0 *theres_more;
	char* 	start_adr;
	unsigned num_bytes;
};

/* The linux_mlist_v0's are pointed to by this structure. One list
 * per description. This means one list for total physical memory,
 * one for prom's address mapping, and one for physical mem left after
 * the kernel is loaded.
 */

struct linux_mem_v0 {
	struct	linux_mlist_v0 **v0_totphys;	/* all of physical */
	struct	linux_mlist_v0 **v0_prommap;	/* addresses map'd by prom */
	struct  linux_mlist_v0 **v0_available;	/* what phys. is left over */
};

/* Arguments sent to the kernel from the boot prompt. */

struct linux_arguments_v0 {
	char	*argv[8];		/* argv format for boot string */
	char	args[100];		/* string space */
	char	boot_dev[2];		/* e.g., "sd" for `b sd(...' */
	int	boot_dev_ctrl;		/* controller # */
	int	boot_dev_unit;		/* unit # */
	int	dev_partition;		/* partition # */
	char	*kernel_file_name;	/* kernel to boot, e.g., "vmunix" */
	void	*aieee1;		/* give me some time  :> */
};

/* Prom version-2 gives us the raw strings for boot arguments and
 * boot device path. We also get the stdin and stdout file pseudo
 * descriptors for use with the mungy v2 device functions.
 */
struct linux_bootargs_v2 {
	char	**bootpath;		/* V2: Path to boot device */
	char	**bootargs;		/* V2: Boot args */
	int	*fd_stdin;		/* V2: Stdin descriptor */
	int	*fd_stdout;		/* V2: Stdout descriptor */
};

/* This is the actual Prom Vector from which everything else is accessed
 * via struct and function pointers, etc. The prom when it loads us into
 * memory plops a pointer to this master structure in register %o0 before
 * it jumps to the kernel start address. I will update this soon to cover
 * the v3 semantics (cpu_start, cpu_stop and other SMP fun things). :-)
 */

struct linux_romvec {
	/* Version numbers. */
	unsigned int	pv_magic_cookie;      /* Magic Mushroom... */
	unsigned int	pv_romvers;	      /* iface vers (0, 2, or 3) */
	unsigned int	pv_plugin_revision;   /* revision relative to above vers */
	unsigned int	pv_printrev;	      /* print revision */

	/* Version 0 memory descriptors (see below). */
	struct linux_mem_v0 pv_v0mem;	      /* V0: Memory description lists. */

	/* Node operations (see below). */
	struct	linux_nodeops *pv_nodeops;   /* node functions, gets device data */

	char	**pv_bootstr;		    /* Boot command, eg sd(0,0,0)vmunix */

	struct	linux_dev_v0_funcs pv_v0devops; 	/* V0: device ops */

	/*
	 * PROMDEV_* cookies.  I fear these may vanish in lieu of fd0/fd1
	 * (see below) in future PROMs, but for now they work fine.
	 */
	char	*pv_stdin;		/* stdin cookie */
	char	*pv_stdout;		/* stdout cookie */
#define	PROMDEV_KBD	0		/* input from keyboard */
#define	PROMDEV_SCREEN	0		/* output to screen */
#define	PROMDEV_TTYA	1		/* in/out to ttya */
#define	PROMDEV_TTYB	2		/* in/out to ttyb */

	/* Blocking getchar/putchar.  NOT REENTRANT! (grr) */
	int	(*pv_getchar)(void);
	void	(*pv_putchar)(int ch);

	/* Non-blocking variants that return -1 on error. */
	int	(*pv_nbgetchar)(void);
	int	(*pv_nbputchar)(int ch);

	/* Put counted string (can be very slow). */
	void	(*pv_putstr)(char *str, int len);

	/* Miscellany. */
	void	(*pv_reboot)(char *bootstr);
	void	(*pv_printf)(const char *fmt, ...);
	void	(*pv_abort)(void);	/* BREAK key abort */
	int	*pv_ticks;		/* milliseconds since last reset */
	void    (*pv_halt)(void);	/* End the show */
	void	(**pv_synchook)(void);	/* "sync" ptr to function */

	/*
	 * This eval's a FORTH string.  Unfortunately, its interface
	 * changed between V0 and V2, which gave us much pain.
	 */
	union {
		void	(*v0_eval)(int len, char *str);
		void	(*v2_eval)(char *str);
	} pv_fortheval;

	struct	linux_arguments_v0 **pv_v0bootargs; /* V0: Boot args */

	/* Extract Ethernet address from network device. */
	unsigned int	(*pv_enaddr)(int d, char *enaddr);

	struct	linux_bootargs_v2 pv_v2bootargs;    /* V2: Boot args+std-in/out */
	struct	linux_dev_v2_funcs pv_v2devops;	    /* V2: device operations */

	int	filler[15];

	/*
	 * The following is machine-dependent.
	 *
	 * The sun4c needs a PROM function to set a PMEG for another
	 * context, so that the kernel can map itself in all contexts.
	 * It is not possible simply to set the context register, because
	 * contexts 1 through N may have invalid translations for the
	 * current program counter.  The hardware has a mode in which
	 * all memory references go to the PROM, so the PROM can do it
	 * easily.
	 */
	void	(*pv_setctxt)(int ctxt, char*  va, int pmeg);

	/* Prom version 3 Multiprocessor routines. This stuff is crazy.
	 * No joke. Calling these when there is only one cpu probably
	 * crashes the machine, have to test this. :-)
         */

	/* v3_cpustart() will start the cpu 'whichcpu' in mmu-context
	 * 'thiscontext' executing at address 'prog_counter'
         */

	int (*v3_cpustart)(unsigned int whichcpu, int ctxtbl_ptr,
			   int thiscontext, char* prog_counter);

	/* v3_cpustop() will cause cpu 'whichcpu' to stop executing
	 * until a resume cpu call is made.
	 */

	int (*v3_cpustop)(unsigned int whichcpu);

	/* v3_cpuidle() will idle cpu 'whichcpu' until a stop or
	 * resume cpu call is made.
	 */

	int (*v3_cpuidle)(unsigned int whichcpu);

	/* v3_cpuresume() will resume processor 'whichcpu' executing
	 * starting with whatever 'pc' and 'npc' were left at the
	 * last 'idle' or 'stop' call.
	 */

	int (*v3_cpuresume)(unsigned int whichcpu);

};

/*
 * In addition to the global stuff defined in the PROM vectors above,
 * the PROM has quite a collection of `nodes'.  A node is described by
 * an integer---these seem to be internal pointers, actually---and the
 * nodes are arranged into an N-ary tree.  Each node implements a fixed
 * set of functions, as described below.  The first two deal with the tree
 * structure, allowing traversals in either breadth- or depth-first fashion.
 * The rest deal with `properties'.
 *
 * A node property is simply a name/value pair.  The names are C strings
 * (NUL-terminated); the values are arbitrary byte strings (counted strings).
 * Many values are really just C strings.  Sometimes these are NUL-terminated,
 * sometimes not, depending on the the interface version; v0 seems to
 * terminate and v2 not.  Many others are simply integers stored as four
 * bytes in machine order: you just get them and go.  The third popular
 * format is an `address', which is made up of one or more sets of three
 * integers as defined below.
 *
 * One uses these functions to traverse the device tree to see what devices
 * this machine has attached to it.
 *
 * N.B.: for the `next' functions, next(0) = first, and next(last) = 0.
 * Whoever designed this part had good taste.  On the other hand, these
 * operation vectors are global, rather than per-node, yet the pointers
 * are not in the openprom vectors but rather found by indirection from
 * there.  So the taste balances out.
 */

struct linux_nodeops {
	/*
	 * Tree traversal.
	 */
	int	(*no_nextnode)(int node);	/* next(node) */
	int	(*no_child)(int node);	/* first child */

	/*
	 * Property functions.  Proper use of getprop requires calling
	 * proplen first to make sure it fits.  Kind of a pain, but no
	 * doubt more convenient for the PROM coder.
	 */
	int	(*no_proplen)(int node, char*  name);
	int	(*no_getprop)(int node, char*  name, char*  val);
	int	(*no_setprop)(int node, char*  name, char*  val, int len);
	char* 	(*no_nextprop)(int node, char*  name);
};

/* More fun PROM structures for device probing. */
#define PROMREG_MAX     16
#define PROMVADDR_MAX   16
#define PROMINTR_MAX    15

struct linux_prom_registers {
  int which_io;         /* is this in OBIO space? */
  char *phys_addr;      /* The physical address of this register */
  int reg_size;         /* How many bytes does this register take up? */
};

struct linux_prom_irqs {
  int pri;    /* IRQ priority */
  int vector; /* This is foobar, what does it do? */
};

/* Element of the "ranges" vector */
struct linux_prom_ranges {
	unsigned int	ot_child_space;
	unsigned int	ot_child_base;		/* Bus feels this */
	unsigned int	ot_parent_space;
	unsigned int	ot_parent_base;		/* CPU looks from here */
	unsigned int	or_size;
};

#endif /* !(__ASSEMBLY__) */

#endif /* !(__SPARC_OPENPROM_H) */
