/*
 * $Header: /smsa/bsd:include/arm/fiq.h:bsd  1.4  $
 * $Source: /smsa/bsd:include/arm/fiq.h: $
 *
 * Copyright (c) 1988 Acorn Computers Ltd., Cambridge, England
 *
 */

#ifndef	__arm_fiq_h
#define	__arm_fiq_h
#define	__machine_fiq_h		"arm"

/*
 * fiq.h
 *		
 * Description of FIQ devices interface, provided by code in fiq.s.
 * This is used by all device drivers which handle FIQs (Fast Interrupt
 * reQuests).
 *
 */

/* Tags for which fiq device is which */
#define DEV_FDC		0			/* FDC (controller) FIQ */
#define DEV_ECO		1			/* Econet FIQ */
#define DEV_XCB		2			/* FIQ from expansion card */
#define DEV_FDD		3			/* special for fdc data */
#define DEV__LAST	3

/*
 * Procedures for FIQ control.  These are all specified in C syntax: to
 * use them from assembler, a "_" should be prefixed to the name.
 * 
 * To initialise FIQ handling for a given device, call:
 *
 * fiq_setup (dev, regs, vec)
 *
 * where:
 *	dev	is one of the DEV_XXX codes defined above;
 *	regs	points at a word-aligned block of memory containing the
 *		initial register context (r8-r11 for FDC data FIQ, r3-r6
 *		for the others) to be seen by the service code;
 *	vec	is the code address to be jumped to to handle the FIQ:
 *		this must be in assembler for various good reasons(!).

 * 
 * The routine fiq_setup is normally used to initialise control for the
 * devices whose FIQ handling uses the control block structure outlined
 * below: these are DEV_XCB, DEV_ECO and DEV_FDC.  However as a special
 * case it also allows "DEV_FDD" to be specified as the dev parameter;
 * doing so causes the initialisation of the actual FIQ-mode registers in
 * the cpu, from values supplied via the regs parameter.  The vec parameter
 * is installed as the address to be jumped to when the very earliest FIQ
 * handling code detects that a data request has been received from the
 * floppy disc hardware.  The processing of such requests does not go
 * through the full FIQ dispatch mechanism; in particular, FIQs remain
 * disabled throughout, and return from the data transfer code is by means
 * of the instruction:
 *
 *	subs	pc, lr, #4
 *
 * rather than by jumping to the special FIQ-service return code.
 *
 * Note: fiq_setup does NOT turn on FIQs for the device concerned - this
 * should be performed later by using the routine
 *
 * fiq_enable (dev_set) 
 * 
 * which takes as parameter a set of values in the form
 *
 *	((1 << DEV_XXX) | (1 << DEV_YYY) ...) 
 * 
 * and enables fiqs from the requested devices to be passed to the cpu.  The
 * routine call:
 *
 * fiq_disable (dev_set)
 *
 * reverses the process.  FIQs from devices not included in the set are not
 * affected by these calls.  Note that it is not safe merely to modify the
 * IOC FIQ mask register: these routines should be used for possible future
 * expansion compatibility.
 *
 *
 * Each class of fiq device apart from floppy disc data (DEV_FDD), i.e.
 * FDC(controller), Econet and XCB, has its own control block in which
 * information regarding FIQs from that device (class) is maintained.  
 *
 * Each control block comprises 17 words in the following format:
 *
 *	Word 	Offset	Contents
 *	===============================
 *	 0	-28	saved_r0
 *	 1	-24	saved_r1
 *	 2	-20	saved_r2
 *	 3	-16	saved_r3
 *	 4	-12	saved_r4
 *	 5	 -8	saved_r5
 *	 6	 -4	saved_r6
 * cb => 7	  0	device_r2
 *	 8	  4	device_r3
 *	 9	  8	device_r4
 *	10	 12	device_r5
 *	11	 16	device_r6
 *	12	 20	device_vector
 *	13	 24	saved_r7
 *	14	 28	return_pc
 *	15	 32	saved_fiq_mask
 *	16	 36	saved_vector
 *
 * The point labelled "cb" above is where r7 points during execution of the
 * FIQ service routine for a device.
 */

#define CB_SIZE	(17*4)	/* overall size in bytes */
#define CB_BASE	(7*4)	/* offset from start of block to normal base */

/*
 * Offsets into the control block, where the base is the value of r7 passed
 * in to the device FIQ service routine
 */
#define _dev_r2			0
#define _dev_r3			4
#define _dev_r4			8
#define _dev_r5			12
#define _dev_r6			16
#define _dev_vector		20
#define _dev_saved_r7		24
#define _dev_return_pc		28
#define	_dev_saved_fiq_mask	32
#define _dev_saved_vector	36

/* Symbolic name for the control block pointer register */
#define r_cb			r7

/* Symbolic addresses for control block fields, usable from assembler */
#define fiq_dev_r2		[r_cb, #_dev_r2]
#define fiq_dev_r3		[r_cb, #_dev_r3]
#define fiq_dev_r4		[r_cb, #_dev_r4]
#define fiq_dev_r5		[r_cb, #_dev_r5]
#define fiq_dev_r6		[r_cb, #_dev_r6]
#define fiq_dev_vector		[r_cb, #_dev_vector]
#define fiq_dev_saved_r7	[r_cb, #_dev_saved_r7]
#define fiq_dev_return_pc	[r_cb, #_dev_return_pc]
#define	fiq_dev_saved_fiq_mask	[r_cb, #_dev_saved_fiq_mask]
#define	fiq_dev_saved_vector	[r_cb, #_dev_saved_vector]

/*
 * On entry to the device specific FIQ service code:
 *
 * (a) the processor is in FIQ mode, with FIQs (but not IRQs) enabled.
 * (b) FIQs from higher priority devices than the current one are enabled.
 * (c) r7 is pointing into the control block, as described above.
 * (d) r14_fiq has been preserved in the control block.
 * (e) the original r0-r7 have been preserved in the control block.
 * (f) r2-r6 have been preloaded from the control block.
 * (g) r13_fiq contains the address of IOC (0x03200000).
 *
 * During execution of the FIQ service routine:
 *
 * (a) r0-r6 may be freely used by the routine.
 * (b) r7 may be modified, but its value on entry must be restored on exit from
 *     the routine.
 * (c) with the original r7 value in place, the macro "fiq_dev_vector" defined
 *     below may be used to address the location within the control block of
 *     the service routine address to be used for subsequent FIQs from the
 *     device.
 * (d) r13_fiq may be used to address IOC but must NOT be modified in any way
 *     at any time during execution of the routine.
 * (e) no other fiq-mode-specific register (r8_fiq-r12_fiq,r14_fiq) can be used
 *     in any way: values in these registers can change at any time because of
 *     higher priority FIQs.
 * (f) in extremis, conditions (d) and (e) can be overridden iff FIQs are
 *     completely disabled by modifying the PSR; this should only be used for
 *     VERY short periods: the contents of r8_fiq-r14_fiq MUST be preserved.
 *
 * The routine must exit by branching to the global label "fiq_exit".  At this
 * point, the device code must have left things such that:
 *
 * (a) r7 contains the value it had on entry to the routine.
 * (b) the processor is in FIQ mode, FIQs enabled, IRQs disabled.
 *
 * On exit from the FIQ code:
 *
 * (a) r2-r6 as returned from the service routine will be saved back into the
 *     control block for the next FIQ service call to the device.
 * (b) the values of r0-r1 will be lost.
 *
 * If the service routine does not need to have the values of r2-r6 saved back
 * on exit (either because they have not been modified, or else because the
 * values are of no interest) step (a) can be omitted by branching to the label 
 * fiq_exit_no_save instead of fiq_exit.
 *
 *
 * A special routine:
 *
 * fiq_fake (a0, a1, dev, vec)
 *
 * is provided for the purpose of faking a FIQ from a device.  This will 
 * normally be used to allow special startup code to run in an environment
 * similar to that which the normal device fiq service routine will find.
 * The dev parameter is one of the DEV_xxx codes (but note that DEV_FDD
 * may not be used: a panic will ensue if it is!) and the vec parameter is
 * the address of the code which will be entered as if from an actual FIQ.
 * The a0 and a1 parameters are values which will appear in r0/r1 during
 * execution of the routine; these are undefined for the normal (real) FIQ
 * service case, but are passed in here for code which is only run via
 * fiq_fake.  Note that there is something of a fudge in relation to the
 * vec parameter: a real FIQ service routine can modify the vector to be
 * used for the next FIQ by updating the device_vector field of the control
 * block.  However in this case that field will have been replaced
 * temporarily by the vec parameter, to be restored when fiq_fake tidies
 * up at the end of its operations.  In order for faked FIQ service code
 * to correctly install a new vector, it must put it in the saved_vector
 * field of the control block rather than the device_vector field; the
 * saved_vector field is where fake_fiq preserves the original vector 
 * while it is faking the FIQ, so on return it will load the new value and
 * put it into device_vector, as required.
 */

#endif/*__arm_fiq_h*/

/* EOF fiq.h */
