 /*
 * Copyright (c) 1998-2002 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * Copyright (c) 1998-2002 Apple Computer, Inc.  All rights reserved.
 *
 *  DRI: William Gulland
 *
 */

#ifndef _IOKIT_K2_H
#define _IOKIT_K2_H

#include <IOKit/IOLocks.h>

#include <IOKit/platform/AppleMacIO.h>

#include "USBKeyLargo.h"
#include "KeyLargoWatchDogTimer.h"
#include "KeyLargo.h"

enum {
    kK2DeviceId41		= 0x41,				// K2
	kK2Version0			= 0,

};

enum {
    // K2 registers different from or in addition to Keylargo
    kK2FCRCount			= 11,
    kK2FCRBase			= 0x00024,			// FCRs 10 to 6 are before 0 to 5!
    kK2FCR10			= 0x00024,
    kK2FCR9				= 0x00028,
    kK2FCR8				= 0x0002c,
    kK2FCR7				= 0x00030,
    kK2FCR6				= 0x00034,
    
    	// Feature Control Register 0 Definitions new in K2
    kK2FCR0USB0SWReset					= 1 << 21,			// USB0_SW_Reset_h
    kK2FCR0USB1SWReset					= 1 << 25,			// USB1_SW_Reset_h
	kK2FCR0RingPMEDisable				= 1 << 27,			// Ring_PME_disable_h

    	// Feature Control Register 1 Definitions new in K2
    kK2FCR1PCI1BusReset					= 1 << 8,			// PCI1_BusReset_L
    kK2FCR1PCI1SleepResetEn				= 1 << 9,			// PCI1_SleepResetEn
    kK2FCR1PCI1ClkEnable				= 1 << 14,			// PCI1_ClkEnable
    kK2FCR1FWClkEnable					= 1 << 15,			// FW_ClkEnable
    kK2FCR1FWReset						= 1 << 16,			// FW_Reset_L
    kK2FCR1GBClkEnable					= 1 << 22,			// GB_ClkEnable
    kK2FCR1GBPwrDown					= 1 << 23,			// GB_PwrDown
    kK2FCR1GBReset						= 1 << 24,			// GB_Reset_L
    kK2FCR1SATAClkEnable				= 1 << 25,			// SATA_ClkEnable
    kK2FCR1SATAPwrDown					= 1 << 26,			// SATA_PwrDown
    kK2FCR1SATAReset					= 1 << 27,			// SATA_Reset_L
    kK2FCR1UATAClkEnable				= 1 << 28,			// UATA_ClkEnable
    kK2FCR1UATAReset					= 1 << 30,			// UATA_Reset_L
    kK2FCR1UATAChooseClk66				= 1 << 31,			// UATA_ChooseClk66
    
        // Feature Control Register 2 is all different in K2
    kK2FCR2PWM0AutoStopEn				= 1 << 4,			// PWM0AutoStopEn
    kK2FCR2PWM1AutoStopEn				= 1 << 5,			// PWM1AutoStopEn
    kK2FCR2PWM2AutoStopEn				= 1 << 6,			// PWM2AutoStopEn
    kK2FCR2PWM3AutoStopEn				= 1 << 7,			// PWM3AutoStopEn
    kK2FCR2PWM0OverTempEn				= 1 << 8,			// PWM0_OverTempEn
    kK2FCR2PWM1OverTempEn				= 1 << 9,			// PWM1_OverTempEn
    kK2FCR2PWM2OverTempEn				= 1 << 10,			// PWM2_OverTempEn
    kK2FCR2PWM3OverTempEn				= 1 << 11,			// PWM3_OverTempEn
    kK2FCR2HTEnableInterrupts			= 1 << 15,			// HT_EnableInterrupts
    kK2FCR2SBMPICEnableOutputs			= 1 << 16,			// SB_MPIC_EnableOutputs
    kK2FCR2SBMPICReset					= 1 << 17,			// SB_MPIC_Reset_L
    kK2FCR2FWLinkOnIntEn				= 1 << 18,			// FW_LinkOnIntEn
    kK2FCR2FWAltLinkOnSel				= 1 << 19,			// FW_AltLinkOnSel
    kK2FCR2PWMsEn						= 1 << 20,			// PWMs_EN_h
    kK2FCR2GBWakeIntEn					= 1 << 21,			// GB_WakeIntEn
    kK2FCR2GBEnergyIntEn				= 1 << 22,			// GB_EnergyIntEn
    kK2FCR2BlockExtGPIO1				= 1 << 23,			// BlockExtGPIO1
    kK2FCR2PCI0BridgeInt				= 1 << 24,			// PCI0_BridgeInt
    kK2FCR2PCI1BridgeInt				= 1 << 25,			// PCI1_BridgeInt
    kK2FCR2PCI2BridgeInt				= 1 << 26,			// PCI2_BridgeInt
    kK2FCR2PCI3BridgeInt				= 1 << 27,			// PCI3_BridgeInt
    kK2FCR2PCI4BridgeInt				= 1 << 28,			// PCI4_BridgeInt
    kK2FCR2HTNonFatalError				= 1 << 30,			// HT_NonFatalError_L
    kK2FCR2HTFatalError					= 1 << 31,			// HT_FatalError_L
    
        	// Feature Control Register 3 Definitions new in K2
    kK2FCR3EnableOsc25Shutdown			= 1 << 0,			// EnableOsc25Shutdown
    kK2FCR3EnableFWPadPwrdown			= 1 << 1, 			// EnableFWpadPwrdown
    kK2FCR3EnableGBpadPwrdown			= 1 << 2,			// EnableGBpadPwrdown
    kK2FCR3EnablePLL0Shutdown			= 1 << 7,			// EnablePLL0Shutdown
    kK2FCR3EnablePLL6Shutdown			= 1 << 8, 			// EnablePLL6Shutdown
    kK2FCR3DynClkStopEnable				= 1 << 11,			// DynClkStopEnable
    
            // Feature Control Register 9 definitions
    kK2FCR9PCI1Clk66isStopped			= 1 << 0,
    kK2FCR9PCI2Clk66isStopped			= 1 << 1,
    kK2FCR9FWClk66isStopped				= 1 << 2,
    kK2FCR9UATAClk66isStopped			= 1 << 3,
    kK2FCR9UATAClk100isStopped			= 1 << 4,
    kK2FCR9PCI3Clk66isStopped			= 1 << 5,
    kK2FCR9GBClk66isStopped				= 1 << 6,
    kK2FCR9PCI4Clk66isStopped			= 1 << 7,
    kK2FCR9SATAClk66isStopped			= 1 << 8,
    kK2FCR9USB0Clk48isStopped			= 1 << 9,
    kK2FCR9USB1Clk48isStopped			= 1 << 10,
    kK2FCR9Clk45isStopped				= 1 << 11,
    kK2FCR9Clk49isStopped				= 1 << 12,
    kK2FCR9Osc25Shutdown				= 1 << 15,
    kK2FCR9ClkStopDelayShift			= 29,
    kK2FCR9ClkStopDelayMask				= 7 << 29
    
};


// desired state of K2 FCR registers when sleeping
enum {
	// Feature Control Register 0 Sleep Settings for K2
    kK2FCR0SleepBitsSet			=	0,
	
    kK2FCR0SleepBitsClear		=	kKeyLargoFCR0USB1CellEnable |
										kKeyLargoFCR0USB0CellEnable,

	// Feature Control Register 0 Sleep Settings for SCC
    kK2FCR0SCCSleepBitsSet		=	0,
	
    kK2FCR0SCCSleepBitsClear	=	kKeyLargoFCR0SccCellEnable |
										kKeyLargoFCR0SccBEnable |
										kKeyLargoFCR0SccAEnable,

    // Feature Control Register 1 Sleep Settings
    kK2FCR1SleepBitsSet			=	0,
	
    kK2FCR1SleepBitsClear		=	kKeyLargoFCR1I2S1Enable |
										kKeyLargoFCR1I2S1ClkEnable |
										kKeyLargoFCR1I2S1CellEnable |
										kKeyLargoFCR1I2S0Enable |
										kKeyLargoFCR1I2S0ClkEnable |
										kKeyLargoFCR1I2S0CellEnable |
										kK2FCR1GBClkEnable |
										kK2FCR1SATAClkEnable |
										kK2FCR1UATAClkEnable,
                                                
    // Feature Control Register 2 Sleep Settings
    kK2FCR2SleepBitsSet			=	0,
	
    // Stop interrupts when going to sleep
    kK2FCR2SleepBitsClear		=	kK2FCR2SBMPICEnableOutputs,

    // Feature Control Register 3 Sleep and Restart Settings
    // Keep Osc25 running to keep Ethernet PHY powered.
    kK2FCR3SleepBitsSet			=	0,
										
    kK2FCR3SleepBitsClear		=	kK2FCR3EnableOsc25Shutdown,	

    // do not turn off SPI interface when restarting
	
    kK2FCR3RestartBitsSet		=	0,
										
    kK2FCR3RestartBitsClear		=	0,
                                                
    // Feature Control Register 4 Sleep Settings    
    kK2FCR4SleepBitsSet			=	0,
	kK2FCR4SleepBitsClear		=	0

};

// Just one kind of GPIO in K2
enum {
    kK2GPIOBase					= 	0x58,
    kK2GPIOCount				= 	51
};

// HyperTransport Link Capabilites Block offset (these are the only ones we care about)
enum {
	kHTLinkCapLDTCapOffset		= 0x0,		// Capabilities is in low byte
	kHTLinkCapLinkCtrlOffset	= 0x4,		// Link width is in high 16 bits
	kHTLinkCapLDTOffset			= 0xC		// Link frequency is in bits 8-11
};

class AppleK2Device : public AppleMacIODevice
{
    OSDeclareDefaultStructors(AppleK2Device);
    
public:
    bool compareName( OSString * name, OSString ** matched = 0 ) const;
    IOReturn getResources( void );
};

class AppleK2 : public KeyLargo
{
	OSDeclareDefaultStructors(AppleK2);
  
private:
	UInt32				k2CPUVCoreSelectGPIO;
 
	// remember if we need to keep the SCC enabled during sleep
	bool			keepSCCenabledInSleep;
	
	void			EnableSCC(bool state, UInt8 device, bool type);
	void			PowerModem(bool state);
	void 			ModemResetLow();
	void 			ModemResetHigh();
	void			PowerI2S (bool powerOn, UInt32 cellNum);
	IOReturn		SetPowerSupply (bool powerHi);
	void			AdjustBusSpeeds ( void );
  
	KeyLargoWatchDogTimer	*watchDogTimer;
    IOService		*fProvider;
    UInt32			fPHandle;
	
	// ***Added for outputting the FCR values to the IORegistry
	const OSSymbol	*k2_FCRNode;
	const OSObject	*fcrs[kK2FCRCount];  
	const OSArray	*fcrArray;
  
	// callPlatformFunction symbols
	const OSSymbol 	*keyLargo_resetUniNEthernetPhy;
	const OSSymbol 	*keyLargo_restoreRegisterState;
	const OSSymbol 	*keyLargo_syncTimeBase;
	const OSSymbol 	*keyLargo_recalibrateBusSpeeds;
	const OSSymbol 	*keyLargo_saveRegisterState;
	const OSSymbol 	*keyLargo_turnOffIO;
	const OSSymbol 	*keyLargo_writeRegUInt8;
	const OSSymbol 	*keyLargo_safeWriteRegUInt8;
	const OSSymbol 	*keyLargo_safeReadRegUInt8;
	const OSSymbol 	*keyLargo_safeWriteRegUInt32;
	const OSSymbol 	*keyLargo_safeReadRegUInt32;
	const OSSymbol 	*keyLargo_getHostKeyLargo;
	const OSSymbol 	*keyLargo_powerI2S;
	const OSSymbol 	*keyLargo_setPowerSupply;
    const OSSymbol	*mac_io_publishChildren;
    const OSSymbol	*mac_io_publishChild;
    const OSSymbol	*k2_enableFireWireClock;
    const OSSymbol	*k2_enableEthernetClock;
    const OSSymbol	*k2_getHTLinkFrequency;
    const OSSymbol	*k2_setHTLinkFrequency;
    const OSSymbol	*k2_getHTLinkWidth;
    const OSSymbol	*k2_setHTLinkWidth;
    
	// Power Management support functions and data structures:
	// These come (almost) unchanged from the MacOS9 Power
	// Manager plug-in (p99powerplugin.c)

	struct MPICTimers {
		UInt32			currentCountRegister;
		UInt32			baseCountRegister;
		UInt32			vectorPriorityRegister;
		UInt32			destinationRegister;
	};
	typedef struct MPICTimers MPICTimers;
	typedef volatile MPICTimers *MPICTimersPtr;

	struct K2MPICState {
		UInt32 			mpicIPI[kKeyLargoMPICIPICount];
		UInt32 			mpicSpuriousVector;
		UInt32 			mpicTimerFrequencyReporting;
		MPICTimers 		mpicTimers[kKeyLargoMPICTimerCount];
		UInt32 			mpicInterruptSourceVectorPriority[kKeyLargoMPICVectorsCount];
		UInt32 			mpicInterruptSourceDestination[kKeyLargoMPICVectorsCount];
		UInt32			mpicCurrentTaskPriorities[kKeyLargoMPICTaskPriorityCount];
	};
	typedef struct K2MPICState K2MPICState;
	typedef volatile K2MPICState *k2MPICStatePtr;

	struct K2GPIOState {
		UInt32 			gpioLevels[2];
		UInt8 			gpio[kK2GPIOCount];
	};
	typedef struct K2GPIOState K2GPIOState;
	typedef volatile K2GPIOState *k2GPIOStatePtr;

	struct K2ConfigRegistersState {
		UInt32 			mediaBay;
		UInt32 			featureControl[kK2FCRCount];
	};
	typedef struct K2ConfigRegistersState K2ConfigRegistersState;
	typedef volatile K2ConfigRegistersState *k2ConfigRegistersStatePtr;

	// This is a short version of the IODBDMAChannelRegisters which includes only
	// the registers we actually mean to save
	struct DBDMAChannelRegisters {
		UInt32			commandPtrLo;
		UInt32			interruptSelect;
		UInt32			branchSelect;
		UInt32			waitSelect;
	};
	typedef struct DBDMAChannelRegisters DBDMAChannelRegisters;
	typedef volatile DBDMAChannelRegisters *DBDMAChannelRegistersPtr;

	struct K2DBDMAState {
		DBDMAChannelRegisters 	dmaChannel[kKeyLargoDBDMAChannelCount];
	};
	typedef struct K2DBDMAState K2DBDMAState;
	typedef volatile K2DBDMAState *k2DBDMAStatePtr;

	struct K2I2SState {
		UInt32					i2s[kKeyLargoI2SRegisterCount * kKeyLargoI2SChannelCount];
	};
	typedef struct K2I2SState K2I2SState;
	typedef volatile K2I2SState *k2I2SStateStatePtr;

	struct K2State {
		bool							thisStateIsValid;
		K2MPICState				savedMPICState;
		K2GPIOState				savedGPIOState;
		K2ConfigRegistersState	savedConfigRegistersState;
		K2DBDMAState				savedDBDMAState;
		K2I2SState				savedI2SState;
		UInt8							savedVIAState[9];
	};
	typedef struct K2State K2State;
	
	// Base offset to HyperTransport link capabilities block
	UInt32 htLinkCapabilitiesBase;

	// These are actually the buffers where we save k2's state (above there
	// are only definitions).
	K2State savedK2State;
  
	// Methods to save and restore the state:
	void saveK2State();
	void restoreK2State();

	// this is to ensure mutual exclusive access to
	// the k2 registers:
	IOSimpleLock *mutex;

	// Remember the bus speed:
	long long busSpeed;
  
	// Reference counts for shared hardware
	long clk45RefCount;			// 45.1 MHz clock - Audio, I2S & SCC
	long clk49RefCount;			// 49.1 MHz clock - Audio & I2S
  
    OSArray *fPlatformFuncArray;	// The array of IOPlatformFunction objects

	void resetUniNEthernetPhy(void);
    void enablePCIDeviceClock(UInt32 mask, bool enable, IOService *nub);
    bool performFunction(IOPlatformFunction *func, void *pfParam1 = 0,
			void *pfParam2 = 0, void *pfParam3 = 0, void *pfParam4 = 0);
    void logClockState();
         
public:
	virtual bool      init(OSDictionary *);
	virtual bool      start(IOService *provider);
	virtual void      stop(IOService *provider);
 
    // Override to publish just immediate children
    virtual void publishBelow( IORegistryEntry * root );
    
    // Override to remove 'k2-' frame nub name
    virtual void processNub( IOService * nub );

    // Override to create AppleK2Device nubs
    virtual IOService * createNub( IORegistryEntry * from );

	virtual IOReturn callPlatformFunction(const OSSymbol *functionName,
					bool waitForFunction, void *param1, void *param2,
					void *param3, void *param4);
  
    virtual IOReturn callPlatformFunction( const char * functionName,
					   bool waitForFunction,
					   void *param1, void *param2,
					   void *param3, void *param4 );

	virtual long long syncTimeBase(void);
	virtual void	  recalibrateBusSpeeds(void);

	virtual void      turnOffK2IO(bool restart);

	virtual void	  setReferenceCounts (void);
	virtual void      saveRegisterState(void);
	virtual void      restoreRegisterState(void);
	virtual void      enableCells();
  
	// share register access:
	void safeWriteRegUInt32(unsigned long offset, UInt32 mask, UInt32 data);

	// Power handling methods:
	void initForPM (IOService *provider);
	IOReturn setPowerState(unsigned long powerStateOrdinal, IOService* whatDevice);
  
	virtual bool getHTLinkFrequency (UInt32 *freqResult);
	virtual bool setHTLinkFrequency (UInt32 newFreq);
	virtual bool getHTLinkWidth (UInt32 *linkOutWidthResult, UInt32 *linkInWidthResult);
	virtual bool setHTLinkWidth (UInt32 newLinkOutWidth, UInt32 newLinkInWidth);

};

#endif /* ! _IOKIT_K2_H */
