/************************************************
Monitor LPC2148
Marcos Augusto Stemmer
*************************************************/

#include <arch/nxp/lpc23xx.h>
#include "monarm.h"

/* espera t milisegundos (usa timer T1) */
void espera_ms(unsigned t)
{
t += T1TC;
while(t != T1TC);
}

/*****************************************************
Inicializacao da DRAM na interface EMC do lpc2478
Beaseado no arquivo de inicializacao do u-boot:
u-boot-1.3.2-olimex/board/lpc_2478_stk/lowlevel_init.c
******************************************************/
void ConfigureEMC(void)
{
volatile unsigned int i, dummy = dummy;
PCONP   |= 0x00000800;	/* Liga energia e PCLK da mem Externa (EMC) */
// Seleciona pinos de enderecos, dados sinais da mem externa
PINSEL5  = 0x55010115;
PINMODE5 = 0xAA02022A;
PINSEL7  = 0x55555555;
PINMODE7 = 0xAAAAAAAA;
PINSEL6  = 0x55555555;
PINMODE6 = 0xAAAAAAAA;
PINSEL8  = 0x15555555;
PINMODE8 = 0x2AAAAAAA;
// No PINSEL9 pimeiro 4 e' Wr
PINSEL9  = 0x00040000;
PINMODE9 = 0x00080000;

EMC_CTRL = 1;	// All clocks driven high
EMC_CONFIG = 0;	// Litle Endian
// Timing for 21ns clock period (48MHz)
EMC_DYN_RP     = 1;   //>20ns = 2 clk
EMC_DYN_RAS    = 2;   //>45ns = 3 clk
EMC_DYN_SREX   = 3;   //>80-100ns = 4 clk
EMC_DYN_APR    = 1;   //
EMC_DYN_DAL    = 3+2;   //2 clk
EMC_DYN_WR     = 3;   //2 clk
EMC_DYN_RC     = 3;   //>65ns = 4 clk
EMC_DYN_RFC    = 3;   //>80-100ns = 4 clk
EMC_DYN_XSR    = 3;   //>80-100ns = 4 clk
EMC_DYN_RRD    = 0;   //>15ns = 1-2 clk
EMC_DYN_MRD    = 3;   //2 clk
EMC_DYN_RD_CFG = 1;   //or 1,2,3
// Latencia do RAS=3 e CAS=3
EMC_DYN_RASCAS0 = 0x303;
#ifdef MT48LC16M16
// 13 row 9 col MT48LC16M16 - 32 bit data bus
EMC_DYN_CFG0 = 0 | (1u << 14)	// 1:32bit; 0:16bit data
		| (0u << 12)	// Low power
		| (3u << 9)	// 4 bancos 13row 9col
		| (1u << 7);	// 32 bit de dados
#else
// 12 row 8 col MT48LC4M16 - 32 bit data bus
EMC_DYN_CFG0 = 0 | (1u << 14)	// 1:32bit; 0:16bit data
		| (0u << 12)	// Low power
		| (1u << 9)	// 4 bancos 12row 8col
		| (1u << 7);	// 32 bit de dados
#endif
espera_ms(100);	// espera 100ms
EMC_DYN_CTRL = 0x183;	// comando SDRAM_NOP
espera_ms(200);	// espera 200ms
EMC_DYN_CTRL = 0x103;	// comando SDRAM_PALL (Precahrge All)
EMC_DYN_RFSH = 1;	// shortest possible refresh period
//wait at least 128 ABH clock cycles
for(i=0; i<0x40; i++) asm volatile(" nop");
//Set correct refresh period
EMC_DYN_RFSH = 7813/16;	// 7813 ciclos = 162us
EMC_DYN_CTRL = 0x83;	// SDRAM_SET_MODE command
//Set mode register in SDRAM [Burst 4, Sequential, CAS-3 (pconf=0x32<<13)]
#ifdef MT48LC16M16
dummy = *(volatile unsigned int *)(DYNAMIC_MEM0_BASE+(0x32 << 13));
#else
dummy = *(volatile unsigned int *)(DYNAMIC_MEM0_BASE+(0x32 << 12));
#endif
EMC_DYN_CTRL = 0;	// SDRAM_NORMAL
EMC_DYN_CFG0 |= (1u<<19);  //Enable buffer
espera_ms(1);
}

int main (void)
{
int c, tf;
union address ad;
c=12000000;
/* configura PLL SYSCLK = 12MHz*16/4 = 48MHz */
//c = PLL_Init(4,16);	// SYSCLK = 48MHz
/* Configura T1 para contar milisegundos */
T1TCR = 0;		// Desabilita T1
T1PR = c/1000 - 1;	// Incrementa T1TC 1000 a cada miliseg
T1TCR = 2;		// Inicializa T1
T1TCR = 1;		// Habilita T1
U0init();
ConfigureEMC();	// Inicailiza a DRAM
/* Reset and enable T0 */
T0TCR = 2; T0TCR=0;
/* Set T0 prescaler to increment every 1/32 second */
T0PR = (SYSCLK / 32)-1;
T0TCR=1;
LCDinit();
LCDprompt();
ad0config();
U0puts("\r\nMonitor LPC2478 PUCRS-NXP 0.01\r\n");
if(!(RTC_CCR & 0x10)){
	RTC_CCR=0; RTC_CCR=2; RTC_CCR=0;
	RTC_CCR=0x11;
	}
do	{
	U0puts("\r\n>");
	tf=T0TC+16;
	while(!(U0LSR & RXDREADY)){
		if(tf!=T0TC) continue;
		tf=T0TC+32;
		U0putchar('\r');
		LCDcomando(0x8c);
		escreve_num(le_adc0());
		LCDputchar(' ');
		LCDcomando(0xc8);
		pr2dec(RTC_HOUR);
		LCDputchar(':');
		pr2dec(RTC_MIN);
		LCDputchar(':');
		pr2dec(RTC_SEC);
		U0putchar('>');
		}
	c=U0RBR;
	if(c > 'Z') c ^= ('A' ^ 'a');
	switch(c){
		case 0x1b: c=U0getchar();
			if(c==0x5b) c=U0getchar();
			break;
		case 'C': copy(0); break;
		case 'V': copy(1); break;
		case 'D': dump(); break;
		case 'W': escreve_word(); break;
		case 'X': execute(); break;
		case 'A': acerta_relogio(); break;
		case 'I': IAP_functions(); LCDprompt(); break;
		case 'E': escreve_mem(); break;
		case ':': lehex(0x40000000); U0putchar('#'); break;
		case '?': case 'H':
			U0puts("\r\nA Acerta relogio\r\nC Copia\r\nD Dump\r\n"
			"E Escreve na memoria\r\nX eXecuta\r\n"
			"L Le ADC0\r\n"
			"I IAP In Application programming\r\n"
			"P Executa programa em 0x40000000\r\n"
			"W Le/escreve Word (32 bit) na memoria\r\n"
			"V Verifica (compara) memoria\r\n"
			"<ESC> Cancela ou termina um comando\r\n");
			break;
		case 'P': ad.w=0x40000000; 
			*ad.pw=0xe59ff018;
			(ad.f)(); break;
		case '0': U0puts("T0 = "); prword(T0TC); break;
		}
	} while(1);
return 0;
}

void UNDEF_Routine(){}
void SWI_Routine(){}
void FIQ_Routine(){}
