/*
 * Copyright (c) 1994-1999 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ifndef	_SYS_FHC_H
#define	_SYS_FHC_H

#pragma ident	"@(#)fhc.h	1.68	99/10/22 SMI"

#ifdef	__cplusplus
extern "C" {
#endif

#include <sys/types32.h>

/* useful debugging stuff */
#define	FHC_ATTACH_DEBUG	0x1
#define	FHC_INTERRUPT_DEBUG	0x2
#define	FHC_REGISTERS_DEBUG	0x4
#define	FHC_CTLOPS_DEBUG	0x8

#define	FHC_BOARDS 0
#define	FHC_CLOCKS 1

/*
 * OBP supplies us with 6 register sets for the FHC. The code for the fhc
 * driver relies on these register sets being presented by the PROM in the
 * order specified below. If this changes, the following comments must be
 * revised and the code in fhc_init() must be changed to reflect these
 * revisions.
 *
 * They are:
 * 	0	FHC internal registers
 * 	1	IGR Interrupt Group Number
 *	2	FanFail IMR, ISMR
 *	3	System IMR, ISMR
 *	4	UART IMR, ISMR
 *	5	TOD IMR, ISMR
 */

/*
 * The offsets are defined as offsets from the base of the OBP register
 * set which the register belongs to.
 */

/* Register set 0 */
#define	FHC_OFF_ID		0x0	/* FHC ID register */
#define	FHC_OFF_RCTRL		0x10	/* FHC Reset Control and Status */
#define	FHC_OFF_CTRL		0x20	/* FHC Control and Status */
#define	FHC_OFF_BSR		0x30	/* FHC Board Status Register */
#define	FHC_OFF_JTAG_CTRL	0xF0	/* JTAG Control Register */
#define	FHC_OFF_JTAG_CMD	0x100	/* JTAG Comamnd Register */

/* Register sets 2-5, the ISMR offset is the same */
#define	FHC_OFF_ISMR		0x10	/* FHC Interrupt State Machine */

/* Bit field defines for FHC Control and Status Register */
#define	FHC_CENTERDIS		0x00100000

/* NOTE: this bit is only used by firmware and must always be cleared by OS */
#define	FHC_CSR_SYNC		0x00010000
#define	FHC_MOD_OFF		0x00008000
#define	FHC_ACDC_OFF		0x00004000
#define	FHC_FHC_OFF		0x00002000
#define	FHC_EPDA_OFF		0x00001000
#define	FHC_EPDB_OFF		0x00000800
#define	FHC_PS_OFF		0x00000400
#define	FHC_NOT_BRD_PRES	0x00000200
#define	FHC_LED_LEFT		0x00000040
#define	FHC_LED_MID		0x00000020
#define	FHC_LED_RIGHT		0x00000010

/* Bit field defines for FHC Reset Control and Status Register */
#define	FHC_POR			0x80000000
#define	FHC_SOFT_POR		0x40000000
#define	FHC_SOFT_XIR		0x20000000

/* Bit field defines for the JTAG control register. */
#define	JTAG_MASTER_EN		0x80000000
#define	JTAG_MASTER_NPRES	0x40000000


/* Macros for decoding UPA speed pins from the Board Status Register */
#define	CPU_0_PINS(bsr)		(((bsr) >> 10) & 0x7)
#define	CPU_1_PINS(bsr)		(((bsr) >> 7) & 0x7)

#define	CID_REV_MASK		0x0fffffff
#define	ULTRAI_COMPID		0x0002502f
#define	ULTRAII_COMPID		0x0003602f

/* Macro for extracting the "plus" bit from the Board Status Register */
#define	ISPLUSBRD(bsr)		(((bsr) & 1) == 0)

/* Macros for physical acccess */
#define	FHC_OFFSET		0xf8000000ull
#define	FHC_REGOFF		0x800000ull
#define	FHC_OFF_IGN		0x2000ull
#define	FHC_OFF_SIM		0x6000ull
#define	FHC_OFF_SSM		0x6010ull
#define	FHC_OFF_UIM		0x8000ull
#define	FHC_OFF_USM		0x8010ull
#define	FHC_CTRL(board)		(FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
				FHC_REGOFF + FHC_OFF_CTRL)
#define	FHC_JTAG_CTRL(board)	(FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
				FHC_REGOFF + FHC_OFF_JTAG_CTRL)
#define	FHC_IGN(board)		(FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
				FHC_REGOFF + FHC_OFF_IGN)
#define	FHC_SIM(board)		(FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
				FHC_REGOFF + FHC_OFF_SIM)
#define	FHC_SSM(board)		(FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
				FHC_REGOFF + FHC_OFF_SSM)
#define	FHC_UIM(board)		(FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
				FHC_REGOFF + FHC_OFF_UIM)
#define	FHC_USM(board)		(FHC_BOARD_BASE(2*(board)) + FHC_OFFSET + \
				FHC_REGOFF + FHC_OFF_USM)

/*
 * the foolowing defines are used for trans phy-addr to board number
 */
#define	BOARD_PHYADDR_SHIFT	24
#define	CLOCKBOARD_PHYADDR_BITS	0x1fff8
#define	IO_BOARD_NUMBER_SHIFT	10
#define	IO_BOARD_NUMBER_MASK	0xf

/*
 * The following defines are used by the fhc driver to determine the
 * difference between IO and CPU type boards. This will be replaced
 * later by JTAG scan to determine board type.
 */

/* XXX */
#define	FHC_UPADATA64A		0x40000
#define	FHC_UPADATA64B		0x20000
/* XXX */

/* Bit field defines for Board Status Register */
#define	FHC_DIAG_MODE		0x40

/* Bit field defines for the FHC Board Status Register when on a disk board */
#define	FHC_FANFAIL		0x00000040
#define	FHC_SCSI_VDD_OK		0x00000001

/* Size of temperature recording array */
#define	MAX_TEMP_HISTORY	16

/* Maximum number of boards in system */
#define	MAX_BOARDS		16

/* Maximum number of Board Power Supplies. */
#define	MAX_PS_COUNT		8

/* Use predefined strings to name the kstats from this driver. */
#define	FHC_KSTAT_NAME		"fhc"
#define	CSR_KSTAT_NAMED		"csr"
#define	BSR_KSTAT_NAMED		"bsr"

/*
 * The following defines are for the AC chip, but are needed to be global,
 * so have been put in the fhc header file.
 */

/*
 * Most Sunfire ASICs have the chip rev encoded into bits 31-28 of the
 * component ID register.
 */
#define	CHIP_REV(c)	((c) >> 28)

#ifndef _ASM

/* Use predefined strings to name the kstats from this driver. */

/* Bit field defines for Interrupt Mapping registers */
#define	IMR_VALID	((uint_t)1 << INR_EN_SHIFT) /* Mondo valid bit */

/* Bit defines for Interrupt State Machine Register */
#define	INT_PENDING	3	/* state of the interrupt dispatch */

struct intr_regs {
	volatile uint_t *mapping_reg;
	volatile uint_t *clear_reg;
	uint_t mapping_reg_cache;	/* cache current value for CPR */
};

#define	BD_IVINTR_SHFT		0x7

/*
 * Convert the Board Number field in the FHC Board Status Register to
 * a board number. The field in the register is bits 0,3-1 of the board
 * number. Therefore a macro is necessary to extract the board number.
 */
#define	FHC_BSR_TO_BD(bsr)	((((bsr) >> 16) & 0x1)  | \
				(((bsr) >> 12) & 0xE))

#define	FHC_INO(ino) ((ino) & 0x7)
#define	FHC_CPU2BOARD(cpuid) ((cpuid) >> 1)
#define	FHC_CPU_IS_A(cpuid) (!((cpuid) & 1))
#define	FHC_CPU_IS_B(cpuid) ((cpuid) & 1)
#define	FHC_BOARD2CPU_A(board) ((board) << 1)
#define	FHC_BOARD2CPU_B(board) (((board) << 1) + 1)
#define	FHC_PS2BOARD(ps) ((((ps) & 0x6) << 1) | ((ps) & 0x1))
#define	FHC_BOARD2PS(board) ((((board) & 0xc) >> 1) | ((board) & 0x1))
#define	FHC_OTHER_CPU_ID(cpuid) ((cpuid) ^ 1)

/* this base address is assumed to never map to real memory */
#define	FHC_BASE_NOMEM		(1ull << 40)
#define	FHC_MAX_ECACHE_SIZE	(16 * 1024 * 1024)

#define	FHC_BOARD_0		0x1c000000000ull
#define	FHC_BOARD_SPAN		0x200000000ull
#define	FHC_DTAG_OFFSET		0xfa000000ull
#define	FHC_BOARD_BASE(cpuid)	(FHC_BOARD_0 + (cpuid) * FHC_BOARD_SPAN)
#define	FHC_DTAG_BASE(cpuid)	(FHC_BOARD_BASE(cpuid) + FHC_DTAG_OFFSET)
#define	FHC_DTAG_LOW		0x300000000ull
#define	FHC_DTAG_HIGH		0x3ull
#define	FHC_DTAG_SIZE		(16 * 1024 * 1024)
#define	FHC_DTAG_SKIP		64

/*
 * Each Sunfire CPU Board has 32Kbytes of SRAM on the FireHose Bus.
 *
 * The SRAM is allocated as follows:
 *
 * 0x1ff.f020.0000 - 0x1ff.f020.5fff  scratch/stacks
 * 0x1ff.f020.6000 - 0x1ff.f020.67ff  reset info     (2K bytes)
 * 0x1ff.f020.6800 - 0x1ff.f020.6fff  POST private   (2K bytes)
 * 0x1ff.f020.7000 - 0x1ff.f020.77ff  OS private     (2K bytes)
 * 0x1ff.f020.7800 - 0x1ff.f020.7fff  OBP private    (2K bytes)
 */
#define	FHC_LOCAL_SRAM_BASE	0x1fff0200000ull
#define	FHC_GLOBAL_SRAM_BASE	0x1c0f8200000ull
#define	FHC_CPU2GLOBAL_SRAM(mid) \
			(FHC_GLOBAL_SRAM_BASE + (mid) * 0x200000000ull)

#define	FHC_SRAM_OS_BASE	0x7000
#define	FHC_LOCAL_OS_PAGEBASE	((FHC_LOCAL_SRAM_BASE + FHC_SRAM_OS_BASE) & \
				MMU_PAGEMASK)
#define	FHC_SRAM_OS_OFFSET	((FHC_LOCAL_SRAM_BASE + FHC_SRAM_OS_BASE) & \
				MMU_PAGEOFFSET)

#define	FHC_SHUTDOWN_WAIT_MSEC	1000

#define	FHC_MAX_INO	4

#define	FHC_SYS_INO		0x0
#define	FHC_UART_INO		0x1
#define	FHC_TOD_INO		0x2
#define	FHC_FANFAIL_INO		0x3

/*
 * Defines for the kstats created for passing temperature values and
 * history out to user level programs. All temperatures passed out
 * will be in degrees Centigrade, corrected for the board type the
 * temperature was read from. Since each Board type has a different
 * response curve for the A/D convertor, the temperatures are all
 * calibrated inside the kernel.
 */

#define	OVERTEMP_KSTAT_NAME	"temperature"

/*
 * This kstat is used for manually overriding temperatures.
 */

#define	TEMP_OVERRIDE_KSTAT_NAME	"temperature override"

/*
 * Time averaging based method of recording temperature history.
 * Higher level temperature arrays are composed of temperature averages
 * of the array one level below. When the lower array completes a
 * set of data, the data is averaged and placed into the higher
 * level array. Then the lower level array is overwritten until
 * it is once again complete, where the process repeats.
 *
 * This method gives a user a fine grained view of the last minute,
 * and larger grained views of the temperature as one goes back in
 * time.
 *
 * The time units for the longer samples are based on the value
 * of the OVERTEMP_TIMEOUT_SEC and the number of elements in each
 * of the arrays between level 1 and the higher level.
 */

#define	OVERTEMP_TIMEOUT_SEC	2

/* definition of the clock board index */
#define	CLOCK_BOARD_INDEX	16

#define	L1_SZ		30	/* # of OVERTEMP_TIMEOUT_SEC samples */
#define	L2_SZ		15	/* size of array for level 2 samples */
#define	L3_SZ		12	/* size of array for level 3 samples */
#define	L4_SZ		4	/* size of array for level 4 samples */
#define	L5_SZ		2	/* size of array for level 5 samples */

/*
 * Macros for determining when to do the temperature averaging of arrays.
 */
#define	L2_INDEX(i)	((i) / L1_SZ)
#define	L2_REM(i)	((i) % L1_SZ)
#define	L3_INDEX(i)	((i) / (L1_SZ * L2_SZ))
#define	L3_REM(i)	((i) % (L1_SZ * L2_SZ))
#define	L4_INDEX(i)	((i) / (L1_SZ * L2_SZ * L3_SZ))
#define	L4_REM(i)	((i) % (L1_SZ * L2_SZ * L3_SZ))
#define	L5_INDEX(i)	((i) / (L1_SZ * L2_SZ * L3_SZ * L4_SZ))
#define	L5_REM(i)	((i) % (L1_SZ * L2_SZ * L3_SZ * L4_SZ))

/*
 * define for an illegal temperature. This temperature will never be seen
 * in a real system, so it is used as an illegal value in the various
 * functions processing the temperature data structure.
 */
#define	NA_TEMP		0x7FFF

/*
 * State variable for board temperature. Each board has its own
 * temperature state. State transitions from OK -> bad direction
 * happen instantaneously, but use a counter in the opposite
 * direction, so that noise in the A/D counters does not cause
 * a large number of messages to appear.
 */
enum temp_state {	TEMP_OK = 0,		/* normal board temperature */
			TEMP_WARN = 1,		/* start warning operator */
			TEMP_DANGER = 2 };	/* get ready to shutdown */

/*
 * Number of temperature poll counts to wait before printing that the
 * system has cooled down.
 */
#define	TEMP_STATE_TIMEOUT_SEC	20
#define	TEMP_STATE_COUNT	((TEMP_STATE_TIMEOUT_SEC) / \
				(OVERTEMP_TIMEOUT_SEC))

/*
 * Number of poll counts that a system temperature must be at or above danger
 * temperature before system is halted and powers down.
 */
#define	SHUTDOWN_TIMEOUT_SEC	20
#define	SHUTDOWN_COUNT		((SHUTDOWN_TIMEOUT_SEC) / \
				(OVERTEMP_TIMEOUT_SEC))

/*
 * State variable for temperature trend.  Each state represents the
 * current temperature trend for a given device.
 */
enum temp_trend {	TREND_UNKNOWN = 0,	/* Unknown temperature trend */
			TREND_RAPID_FALL = 1,	/* Rapidly falling temp. */
			TREND_FALL = 2,		/* Falling temperature */
			TREND_STABLE = 3,	/* Stable temperature */
			TREND_RISE = 4,		/* Rising temperature */
			TREND_RAPID_RISE = 5,   /* Rapidly rising temperature */
			TREND_NOISY = 6 };	/* Unknown trend (noisy) */

/* Thresholds for temperature trend */
#define	NOISE_THRESH		2
#define	RAPID_RISE_THRESH	4
#define	RAPID_FALL_THRESH	4

/*
 * Main structure for passing the calibrated and time averaged temperature
 * values to user processes. This structure is copied out via the kstat
 * mechanism.
 */
#define	TEMP_KSTAT_VERSION 3	/* version of temp_stats structure */
struct temp_stats {
	uint_t index;		/* index of current temperature */
	short l1[L1_SZ];	/* OVERTEMP_TIMEOUT_SEC samples */
	short l2[L2_SZ];	/* level 2 samples */
	short l3[L3_SZ];	/* level 3 samples */
	short l4[L4_SZ];	/* level 4 samples */
	short l5[L5_SZ];	/* level 5 samples */
	short max;		/* maximum temperature recorded */
	short min;		/* minimum temperature recorded */
	enum temp_state state;	/* state of board temperature */
	int temp_cnt;		/* counter for state changes */
	int shutdown_cnt;	/* counter for overtemp shutdown */
	int version;		/* version of this structure */
	enum temp_trend trend;	/* temperature trend for board */
	short override;		/* override temperature for testing */
};

/* The variable fhc_cpu_warning_temp_threshold is initialized to this value. */
#define	FHC_CPU_WARNING_TEMP_THRESHOLD		45

/*
 * Fault list management.
 *
 * The following defines and enum definitions have been created to support
 * the fault list (struct ft_list). These defines must match with the
 * fault string table in fhc.c. If any faults are added, they must be
 * added at the end of this list, and the table must be modified
 * accordingly.
 */
enum ft_type {
	FT_CORE_PS = 0,		/* Core power supply */
	FT_OVERTEMP,		/* Temperature */
	FT_AC_PWR,		/* AC power Supply */
	FT_PPS,			/* Perpheral Power Supply */
	FT_CLK_33,		/* System 3.3 Volt Power */
	FT_CLK_50,		/* System 5.0 Volt Power */
	FT_V5_P,		/* Peripheral 5V Power */
	FT_V12_P,		/* Peripheral 12V Power */
	FT_V5_AUX,		/* Auxiliary 5V Power */
	FT_V5_P_PCH,		/* Peripheral 5V Precharge */
	FT_V12_P_PCH,		/* Peripheral 12V Precharge */
	FT_V3_PCH,		/* System 3V Precharge */
	FT_V5_PCH,		/* System 5V Precharge */
	FT_PPS_FAN,		/* Perpheral Power Supply Fan */
	FT_RACK_EXH,		/* Rack Exhaust Fan */
	FT_DSK_FAN,		/* 4 (or 5) Slot Disk Fan */
	FT_AC_FAN,		/* AC Box Fan */
	FT_KEYSW_FAN,		/* Key Switch Fan */
	FT_INSUFFICIENT_POWER,	/* System has insufficient power */
	FT_PROM,		/* fault inherited from PROM */
	FT_HOT_PLUG,		/* hot plug unavailable */
	FT_TODFAULT		/* tod error detection */
};

enum ft_class {
	FT_BOARD,
	FT_SYSTEM
};

/*
 * This extern allows other drivers to use the ft_str_table if they
 * have fhc specified as a depends_on driver.
 */
extern char *ft_str_table[];

/* Maximum length of string table entries */
#define	MAX_FT_DESC	64

#define	FT_LIST_KSTAT_NAME	"fault_list"

/*
 * The fault list structure is a structure for holding information on
 * kernel detected faults. The fault list structures are linked into
 * a list and the list is protected by the ftlist_mutex. There are
 * also several routines for manipulating the fault list.
 */
struct ft_list {
	int32_t unit;		/* unit number of faulting device */
	enum ft_type type;	/* type of faulting device */
	int32_t pad;		/* padding to replace old next pointer */
	enum ft_class fclass;	/* System or board class fault */
	time32_t create_time;	/* Time stamp at fault detection */
	char msg[MAX_FT_DESC];	/* fault string */
};

/*
 * Allow binary compabilitity between ILP32 and LP64 by
 * eliminating the next pointer and making ft_list a fixed size.
 * The structure name "ft_list" remains unchanged for
 * source compatiblity of kstat applications.
 */
struct ft_link_list {
	struct ft_list f;
	struct ft_link_list *next;
};

/*
 * Board list management.
 *
 * Enumerated types for defining type of system and clock
 * boards. It is used by both the kernel and user programs.
 */
enum board_type {
	UNINIT_BOARD = 0,		/* Uninitialized board type */
	UNKNOWN_BOARD,			/* Unknown board type */
	CPU_BOARD,			/* System board CPU(s) */
	MEM_BOARD,			/* System board no CPUs */
	IO_2SBUS_BOARD,			/* 2 SBus & SOC IO Board */
	IO_SBUS_FFB_BOARD,		/* SBus & FFB SOC IO Board */
	IO_PCI_BOARD,			/* PCI IO Board */
	DISK_BOARD,			/* Disk Drive Board */
	CLOCK_BOARD,			/* System Clock board */
	IO_2SBUS_SOCPLUS_BOARD,		/* 2 SBus & SOC+ IO board */
	IO_SBUS_FFB_SOCPLUS_BOARD	/* SBus&FFB&SOC+ board */
};

/*
 * Defined strings for comparing with OBP board-type property. If OBP ever
 * changes the board-type properties, these string defines must be changed
 * as well.
 */
#define	CPU_BD_NAME			"cpu"
#define	MEM_BD_NAME			"mem"
#define	IO_2SBUS_BD_NAME		"dual-sbus"
#define	IO_SBUS_FFB_BD_NAME		"upa-sbus"
#define	IO_PCI_BD_NAME			"dual-pci"
#define	DISK_BD_NAME			"disk"
#define	IO_2SBUS_SOCPLUS_BD_NAME	"dual-sbus-soc+"
#define	IO_SBUS_FFB_SOCPLUS_BD_NAME	"upa-sbus-soc+"

/*
 * The following structures and union are needed because the bd_info
 * structure describes all types of system boards.
 * XXX - We cannot determine Spitfire rev from JTAG scan, so it is
 * left blank for now. Future implementations might fill in this info.
 */
struct cpu_info {
	int cpu_rev;		/* CPU revision */
	int cpu_speed;		/* rated speed of CPU in MHz */
	int cpu_compid;		/* CPU component ID */
	int sdb0_compid;	/* SDB component ID */
	int sdb1_compid;	/* SDB component ID */
	int ec_compid;		/* Ecache RAM ID, needed for cache size */
	int cache_size;		/* Cache size in bytes */
	int cpu_sram_mode;	/* module's sram mode */
	int cpu_detected;	/* Something on the CPU JTAG ring. */
};

struct io1_info {
	int sio0_compid;	/* Sysio component ID */
	int sio1_compid;	/* Sysio component ID */
	int hme_compid;		/* several revs in existence */
	int soc_compid;		/* SOC */
};

struct io1plus_info {
	int sio0_compid;	/* Sysio component ID */
	int sio1_compid;	/* Sysio component ID */
	int hme_compid;		/* several revs in existence */
	int socplus_compid;	/* SOC+ */
};

/* Defines for the FFB size field */
#define	FFB_FAILED	-1
#define	FFB_NOT_FOUND	0
#define	FFB_SINGLE	1
#define	FFB_DOUBLE	2

struct io2_info {
	int fbc_compid;		/* FBC component ID */
	int ffb_size;		/* not present, single or dbl buffered */
	int sio1_compid;	/* Sysio component ID */
	int hme_compid;		/* several revs in existence */
	int soc_compid;		/* SOC component ID */
};

struct io2plus_info {
	int fbc_compid;		/* FBC component ID */
	int ffb_size;		/* not present, single or dbl buffered */
	int sio1_compid;	/* Sysio component ID */
	int hme_compid;		/* several revs in existence */
	int socplus_compid;	/* or SOC+ component ID */
};

struct io3_info {
	int psyo0_compid;	/* Psycho+ component ID */
	int psyo1_compid;	/* Psycho+ component ID */
	int cheo_compid;	/* Cheerio component ID */
};

struct dsk_info {
	int disk_pres[2];
	int disk_id[2];
};

union bd_un {
	struct cpu_info cpu[2];
	struct io1_info io1;
	struct io2_info io2;
	struct io3_info io3;
	struct dsk_info dsk;
	struct io1plus_info io1plus;
	struct io2plus_info io2plus;
};

/*
 * board_state and bd_info are maintained for backward
 * compatibility with prtdiag and others user programs that may rely
 * on them.
 */
enum board_state {
	UNKNOWN_STATE = 0,	/* Unknown board */
	ACTIVE_STATE,		/* active and working */
	HOTPLUG_STATE,		/* Hot plugged board */
	LOWPOWER_STATE, 	/* Powered down board */
	DISABLED_STATE,		/* Board disabled by PROM */
	FAILED_STATE		/* Board failed by POST */
};

struct bd_info {
	enum board_type type;		/* Type of board */
	enum board_state state;		/* current state of this board */
	int board;			/* board number */
	int fhc_compid;			/* fhc component id */
	int ac_compid;			/* ac component id */
	char prom_rev[64];		/* best guess as to what is needed */
	union bd_un bd;
};

/*
 * Config admin interface.
 *
 * Receptacle states.
 */
typedef enum {
	SYSC_CFGA_RSTATE_EMPTY = 0,		/* Empty state */
	SYSC_CFGA_RSTATE_DISCONNECTED,		/* DISCONNECTED state */
	SYSC_CFGA_RSTATE_CONNECTED		/* CONNECTED state */
} sysc_cfga_rstate_t;

/*
 * Occupant states.
 */
typedef enum {
	SYSC_CFGA_OSTATE_UNCONFIGURED = 0,	/* UNCONFIGURED state */
	SYSC_CFGA_OSTATE_CONFIGURED		/* CONFIGURED state */
} sysc_cfga_ostate_t;

/*
 * Receptacle/Occupant condition.
 */
typedef enum {
	SYSC_CFGA_COND_UNKNOWN = 0,	/* Unknown condition */
	SYSC_CFGA_COND_OK,		/* Condition OK */
	SYSC_CFGA_COND_FAILING,		/* Failing */
	SYSC_CFGA_COND_FAILED,		/* Failed */
	SYSC_CFGA_COND_UNUSABLE		/* Unusable */
} sysc_cfga_cond_t;

/*
 * Error definitions for CFGADM platform library
 */
typedef enum {
	SYSC_ERR_DEFAULT = 0,	/* generic errors */
	SYSC_ERR_INTRANS,	/* hardware in transition */
	SYSC_ERR_UTHREAD,	/* can't stop user thread */
	SYSC_ERR_KTHREAD,	/* can't stop kernel thread */
	SYSC_ERR_SUSPEND,	/* can't suspend a device */
	SYSC_ERR_RESUME,	/* can't resume a device */
	SYSC_ERR_POWER,		/* not enough power for slot */
	SYSC_ERR_COOLING,	/* not enough cooling for slot */
	SYSC_ERR_PRECHARGE,	/* not enough precharge for slot */
	SYSC_ERR_HOTPLUG,	/* Hot Plug Unavailable */
	SYSC_ERR_HW_COMPAT,	/* incompatible hardware found during dr */
	SYSC_ERR_NON_DR_PROM,	/* prom not support Dynamic Reconfiguration */
	SYSC_ERR_CORE_RESOURCE,	/* core resource cannot be removed */
	SYSC_ERR_PROM,		/* error encountered in OBP/POST */
	SYSC_ERR_DR_INIT,	/* error encountered in sysc_dr_init op */
	SYSC_ERR_NDI_ATTACH,	/* error encountered in NDI attach operations */
	SYSC_ERR_NDI_DETACH,	/* error encountered in NDI detach operations */
	SYSC_ERR_RSTATE,	/* wrong receptacle state */
	SYSC_ERR_OSTATE,	/* wrong occupant state */
	SYSC_ERR_COND		/* invalid condition */
} sysc_err_t;

/*
 * Config admin structure.
 */
typedef struct sysc_cfga_stat {
	/* generic representation of the attachment point below */
	sysc_cfga_rstate_t rstate;	/* current receptacle state */
	sysc_cfga_ostate_t ostate;	/* current occupant state */
	sysc_cfga_cond_t condition;	/* current board condition */
	time32_t last_change;		/* last state/condition change */
	uint_t in_transition:1;		/* board is in_transition */

	/* platform specific below */
	enum board_type type;		/* Type of board */
	int board;			/* board number */
	int fhc_compid;			/* fhc component id */
	int ac_compid;			/* ac component id */
	char prom_rev[64];		/* best guess as to what is needed */
	union bd_un bd;
	uint_t no_detach:1;		/* board is non_detachable */
	uint_t plus_board:1;		/* board is 98 MHz capable */
} sysc_cfga_stat_t;

/*
 * Config admin command structure for SYSC_CFGA ioctls.
 */
typedef struct sysc_cfga_cmd {
	uint_t		force:1;	/* force this state transition */
	uint_t		test:1;		/* Need to test hardware */
	int		arg;		/* generic data for test */
	sysc_err_t	errtype;	/* error code returned */
	char		*outputstr;	/* output returned from ioctl */
} sysc_cfga_cmd_t;

typedef struct sysc_cfga_cmd32 {
	uint_t		force:1;	/* force this state transition */
	uint_t		test:1;		/* Need to test hardware */
	int		arg;		/* generic data for test */
	sysc_err_t	errtype;	/* error code returned */
	caddr32_t	outputstr;	/* output returned from ioctl */
} sysc_cfga_cmd32_t;

typedef struct sysc_cfga_pkt {
	sysc_cfga_cmd_t	cmd_cfga;
	char		*errbuf;	/* internal error buffer */
} sysc_cfga_pkt_t;

/*
 * Sysctrl DR sequencer interface.
 */
typedef struct sysc_dr_handle {
	dnode_t *dev_list;		/* list of top nodeid for board */
	int dev_list_len;		/* length devinfo list */
	int flags;			/* dr specific flags */
	int error;			/* dr operation error */
	char *errstr;			/* dr config/unfig error message */
} sysc_dr_handle_t;

#define	SYSC_DR_MAX_NODE	32
#define	SYSC_DR_FHC		0x1	/* connect phase init (fhc) */
#define	SYSC_DR_DEVS		0x2	/* config phase init (devices) */
#define	SYSC_DR_FORCE		0x4	/* force detach */
#define	SYSC_DR_REMOVE		0x8	/* remove dev_info */

#define	SYSC_DR_HANDLE_FHC	0x0
#define	SYSC_DR_HANDLE_DEVS	0x1

/*
 * Sysctrl event interface.
 */
typedef enum sysc_evt {
	SYSC_EVT_BD_EMPTY = 0,
	SYSC_EVT_BD_PRESENT,
	SYSC_EVT_BD_DISABLED,
	SYSC_EVT_BD_FAILED,
	SYSC_EVT_BD_OVERTEMP,
	SYSC_EVT_BD_TEMP_OK,
	SYSC_EVT_BD_PS_CHANGE,
	SYSC_EVT_BD_INS_FAILED,
	SYSC_EVT_BD_INSERTED,
	SYSC_EVT_BD_REMOVED,
	SYSC_EVT_BD_HP_DISABLED,
	SYSC_EVT_BD_CORE_RESOURCE_DISCONNECT
} sysc_evt_t;

/*
 * sysctrl audit message events
 */
typedef enum sysc_audit_evt {
	SYSC_AUDIT_RSTATE_EMPTY = 0,
	SYSC_AUDIT_RSTATE_CONNECT,
	SYSC_AUDIT_RSTATE_DISCONNECT,
	SYSC_AUDIT_RSTATE_SUCCEEDED,
	SYSC_AUDIT_RSTATE_EMPTY_FAILED,
	SYSC_AUDIT_RSTATE_CONNECT_FAILED,
	SYSC_AUDIT_RSTATE_DISCONNECT_FAILED,
	SYSC_AUDIT_OSTATE_CONFIGURE,
	SYSC_AUDIT_OSTATE_UNCONFIGURE,
	SYSC_AUDIT_OSTATE_SUCCEEDED,
	SYSC_AUDIT_OSTATE_CONFIGURE_FAILED,
	SYSC_AUDIT_OSTATE_UNCONFIGURE_FAILED
} sysc_audit_evt_t;

typedef struct {
	void (*update)(void *, sysc_cfga_stat_t *, sysc_evt_t);
	void *soft;
} sysc_evt_handle_t;

void fhc_bd_sc_register(void f(void *, sysc_cfga_stat_t *, sysc_evt_t), void *);

/*
 * The board list structure is the central storage for the kernel's
 * knowledge of normally booted and hotplugged boards.
 */
typedef struct bd_list {
	struct fhc_soft_state *softsp;	/* handle for DDI soft state */
	sysc_cfga_stat_t sc;		/* board info */
	sysc_dr_handle_t sh[2];		/* sysctrl dr interface */
	void *dev_softsp;		/* opaque pointer to device state */
	void *ac_softsp;		/* opaque pointer to our AC */
	struct kstat *ksp;		/* pointer used in kstat destroy */
	int fault;			/* failure on this board? */
	int flags;			/* board state flags */
} fhc_bd_t;

/*
 * Fhc_bd.c holds 2 resizable arrays of boards. First for clock
 * boards under central and second for normally booted and
 * hotplugged boards.
 */
typedef struct resizable_bd_list {
	fhc_bd_t **boards;
	int size;
	int last;
	int sorted;
} fhc_bd_resizable_t;

#define	BDF_VALID		0x1			/* board entry valid */
#define	BDF_DETACH		0x2			/* board detachable */
#define	BDF_DISABLED		0x4			/* board disabled */

#define	SYSC_OUTPUT_LEN		MAXPATHLEN		/* output str len */

/*
 * Board list management interface.
 */
int			fhc_max_boards(void);
void		fhc_bdlist_init(void);
void		fhc_bdlist_fini(void);
void		fhc_bdlist_prime(int, int, int);
fhc_bd_t	*fhc_bdlist_lock(int);
void		fhc_bdlist_unlock(void);

void		fhc_bd_init(struct fhc_soft_state *, int, enum board_type);
fhc_bd_t 	*fhc_bd(int);
fhc_bd_t	*fhc_bd_clock(void);
fhc_bd_t 	*fhc_bd_first(void);
fhc_bd_t 	*fhc_bd_next(fhc_bd_t *);
enum board_type	fhc_bd_type(int);
char 		*fhc_bd_typestr(enum board_type);
int		fhc_bd_valid(int);
int		fhc_bd_detachable(int);

int		fhc_bd_insert_scan(void);
int		fhc_bd_remove_scan(void);
int		fhc_bd_test(int, sysc_cfga_pkt_t *);
int		fhc_bd_test_set_cond(int, sysc_cfga_pkt_t *);
void		fhc_bd_update(int, sysc_evt_t);
void		fhc_bd_env_set(int, void *);

#ifdef DEBUG
int		fhc_bdlist_locked(void);
#endif
int		fhc_bd_busy(int);
int		fhc_bd_is_jtag_master(int);
int		fhc_bd_is_plus(int);

#if defined(_KERNEL)

/*
 * In order to indicate that we are in an environmental chamber, or
 * oven, the test people will set the 'mfg-mode' property in the
 * options node to 'chamber'. Therefore we have the following define.
 */
#define	CHAMBER_VALUE	"chamber"

/*
 * zs design for fhc has two zs' interrupting on same interrupt mondo
 * This requires us to poll for zs and zs alone. The poll list has been
 * defined as a fixed size for simplicity.
 */
#define	MAX_ZS_CNT	2

/* FHC Interrupt routine wrapper structure */
struct fhc_wrapper_arg {
	struct fhc_soft_state *softsp;
	volatile uint_t *clear_reg;
	volatile uint_t *mapping_reg;
	dev_info_t *child;
	uint32_t inum;
	uint_t (*funcp)(caddr_t);
	caddr_t arg;
};

/*
 * The JTAG master command structure. It contains the address of the
 * the JTAG controller on this system board. The controller can only
 * be used if this FHC holds the JTAG master signal. This is checked
 * by reading the JTAG control register on this FHC.
 */
struct jt_mstr {
	volatile uint_t *jtag_cmd;
	int is_master;
	kmutex_t lock;
};

/* Functions exported to manage the fault list */
void reg_fault(int, enum ft_type, enum ft_class);
void clear_fault(int, enum ft_type, enum ft_class);
int process_fault_list(void);
void create_ft_kstats(int);

/* memloc's are protected under the bdlist lock */
struct fhc_memloc {
	struct fhc_memloc *next;
	int		board;		/* reference our board element */
	uint_t		pa;		/* base PA of this segment (in MB) */
	uint_t		size;		/* size of this segment (in MB) */
};

/* Functions used to manage memory 'segments' */
#define	FHC_MEMLOC_SHIFT	20
#define	FHC_MEMLOC_MAX		(0x10000000000ull >> FHC_MEMLOC_SHIFT)
void fhc_add_memloc(int board, uint64_t pa, uint_t size);
void fhc_del_memloc(int board);
uint64_t fhc_find_memloc_gap(uint_t size);
void fhc_program_memory(int board, uint64_t base);

/* Structures used in the driver to manage the hardware */
struct fhc_soft_state {
	dev_info_t *dip;		/* dev info of myself */
	struct bd_list *list;		/* pointer to board list entry */
	int is_central;			/* A central space instance of FHC */
	volatile uint_t *id;		/* FHC ID register */
	volatile uint_t *rctrl;		/* FHC Reset Control and Status */
	volatile uint_t *bsr;		/* FHC Board Status register */
	volatile uint_t *jtag_ctrl;	/* JTAG Control register */
	volatile uint_t *igr;		/* Interrupt Group Number */
	struct intr_regs intr_regs[FHC_MAX_INO];
	struct fhc_wrapper_arg poll_list[MAX_ZS_CNT];
	struct fhc_wrapper_arg *intr_list[FHC_MAX_INO];
	kmutex_t poll_list_lock;
	uchar_t spurious_zs_cntr;	/* Spurious counter for zs devices */
	kmutex_t pokefault_mutex;
	int pokefault;

	/* this lock protects the following data */
	/* ! non interrupt use only ! */
	kmutex_t ctrl_lock;		/* lock for access to FHC CSR */
	volatile uint_t *ctrl;		/* FHC Control and Status */

	/* The JTAG master structure has internal locking */
	struct jt_mstr jt_master;

	/* the pointer to the kstat is stored for deletion upon detach */
	kstat_t *fhc_ksp;
};

/*
 * Function shared with child drivers which require fhc
 * support. They gain access to this function through the use of the
 * _depends_on variable.
 */
enum board_type get_board_type(int board);
void update_temp(dev_info_t pdip, struct temp_stats *envstat, uchar_t value);
enum temp_trend temp_trend(struct temp_stats *);
void fhc_reboot(void);
int overtemp_kstat_update(kstat_t *ksp, int rw);
int temp_override_kstat_update(kstat_t *ksp, int rw);
void init_temp_arrays(struct temp_stats *envstat);
void update_board_leds(fhc_bd_t *, uint_t, uint_t);
struct jt_mstr *jtag_master_lock(void);
void jtag_master_unlock(struct jt_mstr *);
extern int fhc_board_poweroffcpus(int board, char *errbuf);


/* FHC interrupt specification */
struct fhcintrspec {
	uint_t mondo;
	uint_t pil;
	dev_info_t *child;
	struct fhc_wrapper_arg *handler_arg;
};

/* kstat structure used by fhc to pass data to user programs. */
struct fhc_kstat {
	struct kstat_named csr;	/* FHC Control and Status Register */
	struct kstat_named bsr;	/* FHC Board Status Register */
};

#endif	/* _KERNEL */

#endif _ASM

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_FHC_H */
