navienginebsp/ne1_tb/nktest/hw_init.cpp
changeset 0 5de814552237
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/navienginebsp/ne1_tb/nktest/hw_init.cpp	Tue Sep 28 18:00:05 2010 +0100
@@ -0,0 +1,617 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+* ne1_tb\nktest\hw_init.cpp
+*
+*/
+
+
+
+#include <arm.h>
+#include <nkutils.h>
+#include <diag.h>
+#include "kernboot.h"
+//#include <naviengine.h>
+
+#ifdef __SMP__
+#include <arm_gic.h>
+#endif
+
+
+const TUint KHwBaseMPcorePrivatePhys = 0xC0000000u;
+
+extern void DumpExcInfo(TArmExcInfo&);
+extern void DumpFullRegSet(SFullArmRegSet& a);
+
+extern "C" void Interrupt_Init1();
+extern "C" void Interrupt_Init2AP();
+extern "C" void Interrupt_Init3();
+
+extern "C" TLinAddr DebugPortBase();
+
+extern "C" TUint KernCoreStats_EnterIdle(TUint);
+extern "C" void KernCoreStats_LeaveIdle(TInt,TUint);
+
+extern "C" {
+extern TLinAddr RomHeaderAddress;
+extern TLinAddr SuperPageAddress;
+}
+
+#ifdef __SMP__
+TSpinLock DbgSpinLock(TSpinLock::EOrderGenericIrqLow1);
+#endif
+
+
+struct NETimer
+	{
+	static inline NETimer& Timer(TUint a) { return *(NETimer*)(0x18036000u + (a<<10)); }
+	volatile TUint32 iTimerCount;
+	volatile TUint32 iTimerCtrl;
+	volatile TUint32 iTimerReset;
+	volatile TUint32 iGTOPulseStart;
+	volatile TUint32 iGTOPulseEnd;
+	volatile TUint32 iGTICtrl;
+	volatile TUint32 iGTIRisingEdgeCapture;
+	volatile TUint32 iGTIFallingEdgeCapture;
+	volatile TUint32 iGTInterrupt;
+	volatile TUint32 iGTInterruptEnable;
+	volatile TUint32 iPrescaler;
+	};
+
+class ArmGic
+	{
+public:
+	static void Dump();
+	static void DumpCpuIfc();
+	};
+
+#ifdef __SMP__
+
+extern "C" void ApMainGeneric(volatile SAPBootInfo* aInfo);
+
+extern "C" {
+SVariantInterfaceBlock TheVIB;
+
+SVariantInterfaceBlock* InitVIB()
+	{
+	SVariantInterfaceBlock* v = &TheVIB;
+	v->iVer = 0;
+	v->iSize = sizeof(TheVIB);
+	v->iMaxCpuClock = UI64LIT(400000000);	// 400MHz
+	v->iMaxTimerClock = 200000000u;			// 200MHz = CPU CLK / 2
+	v->iScuAddr = KHwBaseMPcorePrivatePhys + 0x0;
+	v->iGicDistAddr = KHwBaseMPcorePrivatePhys + 0x1000;
+	v->iGicCpuIfcAddr = KHwBaseMPcorePrivatePhys + 0x100;
+	v->iLocalTimerAddr = KHwBaseMPcorePrivatePhys + 0x600;
+	return v;
+	}
+}
+
+#endif
+
+static TInt SystemTimerInterruptHandle = -1;
+
+extern "C" {
+
+void TimerIsr(TAny* aPtr)
+	{
+	NETimer& NET = NETimer::Timer(0);
+	NET.iGTInterrupt = 0x1fu;
+	__e32_io_completion_barrier();
+	((NTimerQ*)aPtr)->Tick();
+	}
+
+void StartSystemTimer()
+	{
+	__KTRACE_OPT(KBOOT,DEBUGPRINT(">StartSystemTimer()"));
+
+	NETimer& NET = NETimer::Timer(0);
+	NET.iTimerCtrl = 0;
+	NET.iGTICtrl = 0;
+	__e32_io_completion_barrier();
+	NET.iTimerCtrl = 2;
+	__e32_io_completion_barrier();
+	NET.iTimerReset = 66666;
+//	NET.iTimerReset = 66666666;
+	__e32_io_completion_barrier();
+	NET.iGTInterrupt = 0x1fu;
+	__e32_io_completion_barrier();
+
+	NTimerQ& m=*(NTimerQ*)NTimerQ::TimerAddress();
+	TUint32 flags = NKern::EIrqBind_Count;
+	TInt r = NKern::InterruptBind(36-32, &TimerIsr, &m, flags, 0);
+	DEBUGPRINT("r=%08x", r);
+	__NK_ASSERT_ALWAYS(r>=0);
+	SystemTimerInterruptHandle = r;
+
+	NKern::InterruptEnable(r);
+	DEBUGPRINT("r=%08x", r);
+
+	NET.iGTInterruptEnable = 0x10u;
+	__e32_io_completion_barrier();
+	NET.iTimerCtrl = 3;
+	__e32_io_completion_barrier();
+
+//	NTimerQ& m=*(NTimerQ*)NTimerQ::TimerAddress();
+//	TInt r=Interrupt::Bind(EIntIdTimer,&MsTimerTick,&m);
+//	__NK_ASSERT_ALWAYS(r>=0);
+//	initTimer(PIT_COUNT_FOR_1MS);
+//	r=Interrupt::Enable(r);
+//	KPrintf("r=%d",r);
+//	__NK_ASSERT_ALWAYS(r>=0);
+	__KTRACE_OPT(KBOOT,DEBUGPRINT("<StartSystemTimer()"));
+
+	TInt i;
+	for (i=0; i<50; ++i)
+		{
+		DEBUGPRINT("Count %8d IRQ %02x", NET.iTimerCount, NET.iGTInterrupt);
+		}
+
+	ArmGic::Dump();
+	ArmGic::DumpCpuIfc();
+	}
+
+void HijackSystemTimer(NSchedulable* aTieTo)
+	{
+	TInt r = NKern::InterruptUnbind(SystemTimerInterruptHandle);
+	// need to accept KErrArgument because if the tied thread/group
+	// has gone away the interrupt will be unbound already and the
+	// handle is not valid
+	__NK_ASSERT_ALWAYS(r==KErrNone || r==KErrArgument);
+
+	NTimerQ& m=*(NTimerQ*)NTimerQ::TimerAddress();
+	TUint32 flags = NKern::EIrqBind_Count;
+	if (aTieTo)
+		flags |= NKern::EIrqBind_Tied;
+	r = NKern::InterruptBind(36-32, &TimerIsr, &m, flags, aTieTo);
+	__NK_ASSERT_ALWAYS(r>=0);
+	SystemTimerInterruptHandle = r;
+	NKern::InterruptEnable(r);
+	}
+
+static int debug_uart_data_available()
+	{
+	TUint32 base = DebugPortBase();
+	volatile TUint8& LSR = *(volatile TUint8*)(base + 0x14);
+	return LSR & 0x01;
+	}
+
+static int debug_uart_poll()
+	{
+	TUint32 base = DebugPortBase();
+	volatile TUint8& LSR = *(volatile TUint8*)(base + 0x14);
+	volatile TUint8& RXHR = *(volatile TUint8*)(base + 0x00);
+	if (LSR & 0x01)
+		return RXHR;
+	return -1;
+	}
+
+static void write_debug_uart(char aChar)
+	{
+	TUint32 base = DebugPortBase();
+	volatile TUint8& LSR = *(volatile TUint8*)(base + 0x14);
+	volatile TUint8& TXHR = *(volatile TUint8*)(base + 0x00);
+
+	while (!(LSR & 0x20))
+		{}
+
+	TXHR = (TUint8)aChar;
+	}
+
+const DiagIO DebugUartIO =
+	{
+	&debug_uart_data_available,
+	&debug_uart_poll,
+	&write_debug_uart
+	};
+
+static void init_debug_uart()
+	{
+	write_debug_uart('*');
+	TheIoFunctions = &DebugUartIO;
+	}
+
+// have DFAR DFSR IFSR R13 R14 CPSR ExcCode R5-R11 R0-R4 R12 PC saved
+struct X
+	{
+	TUint32	iDFAR;
+	TUint32	iDFSR;
+	TUint32	iIFSR;
+	TUint32	iR13;
+	TUint32	iR14;
+	TUint32	iCPSR;
+	TUint32	iExcCode;
+	TUint32	iR5;
+	TUint32	iR6;
+	TUint32	iR7;
+	TUint32	iR8;
+	TUint32	iR9;
+	TUint32	iR10;
+	TUint32	iR11;
+	TUint32	iR0;
+	TUint32	iR1;
+	TUint32	iR2;
+	TUint32	iR3;
+	TUint32	iR4;
+	TUint32	iR12;
+	TUint32	iR15;
+	};
+
+extern "C" {
+void hw_init_exc(TUint32* a)
+	{
+	X& x = *(X*)a;
+	TInt irq = DbgSpinLock.LockIrqSave();
+	DumpStruct(
+		"-------------------------------------\n"
+		"DFAR %w DFSR %w IFSR %w\n"
+		"R13  %w R14  %w CPSR %w ExcCode %w\n"
+		"R5   %w R6   %w R7   %w R8   %w\n"
+		"R9   %w R10  %w R11  %w\n"
+		"R0   %w R1   %w R2   %w R3   %w\n"
+		"R4   %w R12  %w PC   %w\n",
+		a);
+	if (x.iExcCode==2)
+		{
+		TUint32* p = (TUint32*)x.iR15;
+		TUint32 inst = *p;
+		if (inst>=0xe7ffdef0u && inst<0xe7ffdeffu)
+			{
+			PrtHex8(inst);
+			NewLine();
+			x.iR15 += 4;
+			DbgSpinLock.UnlockIrqRestore(irq);
+			return;
+			}
+		}
+	RunCrashDebugger();
+	}
+}
+
+extern "C" void __DebugMsgGlobalCtor(TUint addr, TUint cpsr)
+	{
+	PrtHex8(cpsr); PutSpc(); PrtHex8(addr); NewLine();
+	}
+
+extern "C" TUint64 fast_counter_x(TUint32*);
+extern "C" void HwInit0()
+	{
+	init_debug_uart();
+
+	NETimer& T1 = NETimer::Timer(1);
+	NETimer& T2 = NETimer::Timer(2);
+
+	T1.iTimerCtrl = 0;	// stop and reset timer 1
+	T1.iGTICtrl = 0;	// disable timer 1 capture modes
+	T2.iTimerCtrl = 0;	// stop and reset timer 2
+	T2.iGTICtrl = 0;	// disable timer 2 capture modes
+	__e32_io_completion_barrier();
+	T1.iPrescaler = 1;	// Timer 1 prescaled by 1 (=66.667MHz)
+	T2.iPrescaler = 1;	// Timer 2 prescaled by 1
+//	T1.iPrescaler = 4;	// Timer 1 prescaled by 4 (=16.667MHz)
+//	T2.iPrescaler = 4;	// Timer 2 prescaled by 4
+	__e32_io_completion_barrier();
+	T1.iGTInterruptEnable = 0;
+	T2.iGTInterruptEnable = 0;
+	__e32_io_completion_barrier();
+	T1.iGTInterrupt = 0x1f;
+	T2.iGTInterrupt = 0x1f;
+	__e32_io_completion_barrier();
+	T1.iTimerCtrl = 2;	// deassert reset for timer 1, count still stopped
+	T2.iTimerCtrl = 2;	// deassert reset for timer 2, count still stopped
+	__e32_io_completion_barrier();
+	T1.iTimerReset = 0xfffffeffu;	// timer 1 wraps after 2^32-256 counts
+	T2.iTimerReset = 0xffffffffu;	// timer 2 wraps after 2^32 counts
+	__e32_io_completion_barrier();
+	T1.iTimerCtrl = 3;	// start timer 1
+	__e32_io_completion_barrier();
+	T2.iTimerCtrl = 3;	// start timer 2
+	__e32_io_completion_barrier();
+
+	// Each time T1 wraps, (T1-T2) increases by 256 after starting at 0
+	// t1=T1; t2=T2; n=(t1-t2)>>8; time = t1 + n * (2^32-256)
+
+	TUint32 t[2];
+	TUint64 x = fast_counter_x(t);
+	DEBUGPRINT("t1=%08x t2=%08x result %08x %08x", t[0], t[1], I64HIGH(x), I64LOW(x));
+	}
+
+void Hw_Init1()
+	{
+	__CHECKPOINT();
+
+#ifdef __SMP__
+	NKern::Init0(InitVIB());
+#else
+	NKern::Init0(0);
+#endif
+	Interrupt_Init1();
+	__CHECKPOINT();
+	Arm::Init1Interrupts();
+	__CHECKPOINT();
+	}
+
+#ifdef __SMP__
+extern "C" void Hw_InitAPs()
+	{
+	TSubScheduler& ss = SubScheduler();
+	SSuperPageBase& spg = *(SSuperPageBase*)::SuperPageAddress;
+	TInt ncpus = 4;
+	TInt cpu;
+	for (cpu=1; cpu<ncpus; ++cpu)
+		{
+		TAny* stack = 0;
+		NThread* thread = 0;
+		stack = malloc(4096);
+		__NK_ASSERT_ALWAYS(stack);
+		memset(stack, (0xe1|(cpu<<1)), 4096);
+		thread = new NThread;
+		__NK_ASSERT_ALWAYS(thread);
+
+		SArmAPBootInfo info;
+		memclr(&info,sizeof(info));
+		info.iCpu = cpu;
+		info.iInitStackSize = 4096;
+		info.iInitStackBase = (TLinAddr)stack;
+		info.iMain = &ApMainGeneric;
+		info.iArgs[0] = (TAny*)thread;
+		info.iAPBootLin = spg.iAPBootPageLin;
+		info.iAPBootPhys = spg.iAPBootPagePhys;
+		info.iAPBootCodeLin = ::RomHeaderAddress;
+		info.iAPBootCodePhys = spg.iRomHeaderPhys;
+		info.iAPBootPageDirPhys = spg.iAPBootPageDirPhys;
+		TUint32 delta = cpu*0x2000;
+		info.iInitR13Fiq = TLinAddr(ss.iSSX.iFiqStackTop) + delta;
+		info.iInitR13Irq = TLinAddr(ss.iSSX.iIrqStackTop) + delta;
+		info.iInitR13Abt = TLinAddr(ss.iSSX.iAbtStackTop) + delta;
+		info.iInitR13Und = TLinAddr(ss.iSSX.iUndStackTop) + delta;
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iCpu=%08x", info.iCpu));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iInitStackSize=%08x", info.iInitStackSize));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iInitStackBase=%08x", info.iInitStackBase));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iMain=%08x", info.iMain));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iArgs=%08x %08x %08x %08x", info.iArgs[0], info.iArgs[1], info.iArgs[2], info.iArgs[3]));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iAPBootLin=%08x", info.iAPBootLin));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iAPBootPhys=%08x", info.iAPBootPhys));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iAPBootCodeLin=%08x", info.iAPBootCodeLin));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iAPBootCodePhys=%08x", info.iAPBootCodePhys));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iAPBootPageDirPhys=%08x", info.iAPBootPageDirPhys));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iInitR13Fiq=%08x", info.iInitR13Fiq));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iInitR13Irq=%08x", info.iInitR13Irq));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iInitR13Abt=%08x", info.iInitR13Abt));
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("iInitR13Und=%08x", info.iInitR13Und));
+		TInt r = NKern::BootAP(&info);
+		__KTRACE_OPT(KBOOT,DEBUGPRINT("ret %d", r));
+		if (r==KErrNone)
+			{
+			while (__e32_atomic_load_acq32(&info.iArgs[1])==0)
+				__cpu_yield();
+			__KTRACE_OPT(KBOOT,DEBUGPRINT("CPU %d: OK NullThread=%08x InitialStack=%08x", cpu, thread, stack));
+			stack = 0;
+			thread = 0;
+			}
+		__NK_ASSERT_ALWAYS(r==KErrNone);
+		if (stack)
+			free(stack);
+		if (thread)
+			free(thread);
+		}
+	}
+#endif
+
+void Hw_Init3()
+	{
+	Interrupt_Init3();
+	StartSystemTimer();
+	}
+}
+
+extern "C" void NKCrashHandler(TInt aPhase, const TAny*, TInt)
+	{
+	if (aPhase==0)
+		{
+		return;
+		}
+	__finish();
+	}
+
+extern "C" void ExcFault(void* aExcInfo)
+	{
+#ifdef __SMP__
+	SubScheduler().iSSX.iExcInfo = aExcInfo;
+	SFullArmRegSet& a = *SubScheduler().iSSX.iRegs;
+#else
+	TheScheduler.i_ExcInfo = aExcInfo;
+	SFullArmRegSet& a = *(SFullArmRegSet*)TheScheduler.i_Regs;
+#endif
+	if (aExcInfo)
+		{
+		Arm::SaveState(a);
+		Arm::UpdateState(a, *(TArmExcInfo*)aExcInfo);
+		}
+	DumpFullRegSet(a);
+	NKern::NotifyCrash(0,0);
+	}
+
+/**
+Faults the system, noting file name and line number.
+
+Used from nanokernel code and in various __ASSERT macros.
+
+@param	file	The file name as a C string (__FILE__).
+@param	line	The line number (__LINE__).
+
+@see Kern::Fault()
+*/
+extern "C" void NKFault(const char* file, TInt line)
+	{
+	KPrintf("FAULT at line %d file %s", line, file);
+	NKern::NotifyCrash(0,0);
+	}
+
+
+void DebugPrint(const char* s, int l)
+	{
+	TInt i;
+#ifdef __SMP__
+	TInt irq=0;
+	if (!NKern::Crashed())
+		irq = DbgSpinLock.LockIrqSave();
+#endif
+	for (i=0; i<l; ++i)
+		PutC(*s++);
+#ifdef __SMP__
+	if (!NKern::Crashed())
+		DbgSpinLock.UnlockIrqRestore(irq);
+#endif
+	}
+
+TInt __timer_period()
+	{
+	return 1000;
+	}
+
+#ifdef __SMP__
+TInt __microseconds_to_timeslice_ticks(TInt us)
+	{
+	return NKern::TimesliceTicks(us);
+	}
+
+TInt __fast_counter_to_timeslice_ticks(TUint64 aFCdelta)
+	{
+	// fast counter freq = 400MHz/6
+	// timeslice freq = 400MHz/128
+	aFCdelta*=3;
+	aFCdelta>>=6;
+	return (TInt)aFCdelta;
+	}
+#else
+TInt __microseconds_to_timeslice_ticks(TInt us)
+	{
+	return (us+999)/1000;
+	}
+
+TInt __fast_counter_to_timeslice_ticks(TUint64 aFCdelta)
+	{
+	TUint64 fcf = fast_counter_freq();
+	TUint64 x = (aFCdelta * 1000 + (fcf - 1)) / fcf;
+	return (TInt)x;
+	}
+#endif
+
+extern "C" {
+extern TLinAddr RomHeaderAddress;
+void __finish()
+	{
+	RunCrashDebugger();
+
+//	TLinAddr f = RomHeaderAddress + 124;
+//	(*(void (*)(TInt))f)(0x80000000);
+
+	}
+}
+
+extern "C" void NKIdle(TUint32 aStage)
+	{
+/*
+	SCpuIdleHandler* cih = NKern::CpuIdleHandler();
+#ifdef __SMP__
+	TSubScheduler& ss = SubScheduler();
+	if (cih && cih->iHandler)
+		(*cih->iHandler)(cih->iPtr, aStage, ss.iUncached);
+#else
+	if (cih && cih->iHandler)
+		(*cih->iHandler)(cih->iPtr, aStage);
+#endif
+	else if (K::PowerModel)
+		K::PowerModel->CpuIdle();
+	else
+		Arm::TheAsic->Idle();
+*/
+	__cpu_idle();
+	}
+
+
+extern "C" TUint32 IrqDispatch(TUint32 aVector)
+	{
+	if (aVector<32 || aVector>127)
+		{
+		GIC_CPU_IFC.iEoi = aVector;
+		*(TInt*)0xdeaddead = 0;
+		return aVector;
+		}
+	NKern::Interrupt(aVector - 32);
+	return aVector;
+	}
+
+const TUint8 IntIsEdge[96] =
+	{
+	0, 1, 0, 0,		0, 0, 0, 0,		0, 0, 0, 0,		0, 0, 0, 1,
+	0, 0, 0, 0,		0, 0, 0, 0,		0, 0, 0, 0,		0, 0, 0, 0,
+	0, 0, 0, 0,		0, 0, 0, 1,		1, 0, 0, 0,		0, 0, 1, 1,
+	1, 1, 1, 1,		1, 1, 0, 0,		0, 0, 0, 0,		0, 0, 0, 0,
+	0, 1, 1, 0,		0, 0, 0, 0,		0, 0, 0, 0,		0, 0, 0, 0,
+	0, 0, 0, 0,		0, 0, 0, 0,		0, 0, 0, 0,		0, 0, 0, 0
+	};
+
+extern "C" void Interrupt_Init1()
+	{
+	__KTRACE_OPT(KBOOT, DEBUGPRINT(">Interrupt_Init1()"));
+	Arm::SetIrqHandler((TLinAddr)&IrqDispatch);
+	TInt i;
+	for (i=32; i<128; ++i)
+		{
+		TBool edge = IntIsEdge[i-32];
+		TUint32 flags = 0;
+		if (i>=36 && i<42)
+			flags |= NKern::EIrqInit_Count;	// timers count all interrupts
+		if (edge)
+			flags |= NKern::EIrqInit_RisingEdge;
+		else
+			flags |= NKern::EIrqInit_LevelHigh;
+		TInt r = NKern::InterruptInit(i-32, flags, i, i);
+		__KTRACE_OPT(KBOOT, DEBUGPRINT("InterruptInit %d(%02x) -> %d", i-32, i, r));
+		__NK_ASSERT_ALWAYS(r==KErrNone);
+		}
+
+	__KTRACE_OPT(KBOOT, DEBUGPRINT("<Interrupt_Init1()"));
+	}
+
+extern "C" void Interrupt_Init2AP()
+	{
+	}
+
+extern "C" void Interrupt_Init3()
+	{
+	}
+
+
+#include <e32rom.h>
+
+extern "C" TLinAddr DebugPortBase()
+	{
+	const TRomHeader& romHdr = *(const TRomHeader*)RomHeaderAddress;
+	if (romHdr.iDebugPort & 1)
+		return 0x18034400u;
+	return 0x18034000u;
+	}
+
+
+extern "C" TUint KernCoreStats_EnterIdle(TUint)
+	{
+	return (TUint) EFalse;
+	}
+
+extern "C" void KernCoreStats_LeaveIdle(TInt,TUint)
+	{
+	}