2008-07-14 15:03:10 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2008 by Maurus Cuelenaere
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "jz4740.h"
|
2008-07-17 10:13:56 +00:00
|
|
|
#include "mips.h"
|
2009-01-21 20:58:33 +00:00
|
|
|
#include "mmu-mips.h"
|
2008-07-15 17:17:01 +00:00
|
|
|
#include "panic.h"
|
2008-12-20 01:48:46 +00:00
|
|
|
#include "system.h"
|
2008-07-17 10:13:56 +00:00
|
|
|
#include "kernel.h"
|
2011-12-21 18:02:50 +00:00
|
|
|
#include "power.h"
|
2008-07-14 15:03:10 +00:00
|
|
|
|
2009-06-03 16:25:54 +00:00
|
|
|
#define EXTENDED_EXCEPTION_DESC 0
|
|
|
|
#if EXTENDED_EXCEPTION_DESC
|
2009-07-26 14:00:25 +00:00
|
|
|
#include "backlight-target.h"
|
2009-06-03 16:25:54 +00:00
|
|
|
#include "font.h"
|
|
|
|
#include "lcd.h"
|
|
|
|
#endif
|
|
|
|
|
2008-08-09 23:31:38 +00:00
|
|
|
#define NUM_DMA 6
|
|
|
|
#define NUM_GPIO 128
|
|
|
|
#define IRQ_MAX (IRQ_GPIO_0 + NUM_GPIO)
|
|
|
|
|
2008-08-10 21:44:48 +00:00
|
|
|
static int irq;
|
2008-08-09 23:31:38 +00:00
|
|
|
static void UIRQ(void)
|
|
|
|
{
|
2009-02-13 00:45:49 +00:00
|
|
|
panicf("Unhandled interrupt occurred: %d", irq);
|
2008-08-09 23:31:38 +00:00
|
|
|
}
|
|
|
|
|
2009-02-13 00:45:49 +00:00
|
|
|
#define intr(name) extern __attribute__((weak,alias("UIRQ"))) void name (void)
|
|
|
|
|
|
|
|
intr(I2C);intr(EMC);intr(UHC);intr(UART0);intr(SADC);intr(MSC);intr(RTC);
|
|
|
|
intr(SSI);intr(CIM);intr(AIC);intr(ETH);intr(TCU2);intr(TCU1);intr(TCU0);
|
|
|
|
intr(UDC);intr(IPU);intr(LCD);
|
|
|
|
|
|
|
|
intr(DMA0);intr(DMA1);intr(DMA2);intr(DMA3);intr(DMA4);intr(DMA5);
|
|
|
|
|
|
|
|
intr(GPIO0);intr(GPIO1);intr(GPIO2);intr(GPIO3);intr(GPIO4);intr(GPIO5);
|
|
|
|
intr(GPIO6);intr(GPIO7);intr(GPIO8);intr(GPIO9);intr(GPIO10);intr(GPIO11);
|
|
|
|
intr(GPIO12);intr(GPIO13);intr(GPIO14);intr(GPIO15);intr(GPIO16);intr(GPIO17);
|
|
|
|
intr(GPIO18);intr(GPIO19);intr(GPIO20);intr(GPIO21);intr(GPIO22);intr(GPIO23);
|
|
|
|
intr(GPIO24);intr(GPIO25);intr(GPIO26);intr(GPIO27);intr(GPIO28);intr(GPIO29);
|
|
|
|
intr(GPIO30);intr(GPIO31);intr(GPIO32);intr(GPIO33);intr(GPIO34);intr(GPIO35);
|
|
|
|
intr(GPIO36);intr(GPIO37);intr(GPIO38);intr(GPIO39);intr(GPIO40);intr(GPIO41);
|
|
|
|
intr(GPIO42);intr(GPIO43);intr(GPIO44);intr(GPIO45);intr(GPIO46);intr(GPIO47);
|
|
|
|
intr(GPIO48);intr(GPIO49);intr(GPIO50);intr(GPIO51);intr(GPIO52);intr(GPIO53);
|
|
|
|
intr(GPIO54);intr(GPIO55);intr(GPIO56);intr(GPIO57);intr(GPIO58);intr(GPIO59);
|
|
|
|
intr(GPIO60);intr(GPIO61);intr(GPIO62);intr(GPIO63);intr(GPIO64);intr(GPIO65);
|
|
|
|
intr(GPIO66);intr(GPIO67);intr(GPIO68);intr(GPIO69);intr(GPIO70);intr(GPIO71);
|
|
|
|
intr(GPIO72);intr(GPIO73);intr(GPIO74);intr(GPIO75);intr(GPIO76);intr(GPIO77);
|
|
|
|
intr(GPIO78);intr(GPIO79);intr(GPIO80);intr(GPIO81);intr(GPIO82);intr(GPIO83);
|
|
|
|
intr(GPIO84);intr(GPIO85);intr(GPIO86);intr(GPIO87);intr(GPIO88);intr(GPIO89);
|
|
|
|
intr(GPIO90);intr(GPIO91);intr(GPIO92);intr(GPIO93);intr(GPIO94);intr(GPIO95);
|
|
|
|
intr(GPIO96);intr(GPIO97);intr(GPIO98);intr(GPIO99);intr(GPIO100);intr(GPIO101);
|
|
|
|
intr(GPIO102);intr(GPIO103);intr(GPIO104);intr(GPIO105);intr(GPIO106);
|
|
|
|
intr(GPIO107);intr(GPIO108);intr(GPIO109);intr(GPIO110);intr(GPIO111);
|
|
|
|
intr(GPIO112);intr(GPIO113);intr(GPIO114);intr(GPIO115);intr(GPIO116);
|
|
|
|
intr(GPIO117);intr(GPIO118);intr(GPIO119);intr(GPIO120);intr(GPIO121);
|
|
|
|
intr(GPIO122);intr(GPIO123);intr(GPIO124);intr(GPIO125);intr(GPIO126);
|
|
|
|
intr(GPIO127);
|
2008-08-09 23:31:38 +00:00
|
|
|
|
|
|
|
static void (* const irqvector[])(void) =
|
|
|
|
{
|
2008-08-10 21:44:48 +00:00
|
|
|
I2C,EMC,UHC,UIRQ,UIRQ,UIRQ,UIRQ,UIRQ,
|
|
|
|
UART0,UIRQ,UIRQ,SADC,UIRQ,MSC,RTC,SSI,
|
|
|
|
CIM,AIC,ETH,UIRQ,TCU2,TCU1,TCU0,UDC,
|
|
|
|
UIRQ,UIRQ,UIRQ,UIRQ,IPU,LCD,UIRQ,DMA0,
|
|
|
|
DMA1,DMA2,DMA3,DMA4,DMA5,UIRQ,UIRQ,UIRQ,
|
|
|
|
UIRQ,UIRQ,UIRQ,UIRQ,UIRQ,UIRQ,UIRQ,
|
2008-08-09 23:31:38 +00:00
|
|
|
GPIO0,GPIO1,GPIO2,GPIO3,GPIO4,GPIO5,GPIO6,GPIO7,
|
|
|
|
GPIO8,GPIO9,GPIO10,GPIO11,GPIO12,GPIO13,GPIO14,GPIO15,
|
|
|
|
GPIO16,GPIO17,GPIO18,GPIO19,GPIO20,GPIO21,GPIO22,GPIO23,
|
|
|
|
GPIO24,GPIO25,GPIO26,GPIO27,GPIO28,GPIO29,GPIO30,GPIO31,
|
|
|
|
GPIO32,GPIO33,GPIO34,GPIO35,GPIO36,GPIO37,GPIO38,GPIO39,
|
|
|
|
GPIO40,GPIO41,GPIO42,GPIO43,GPIO44,GPIO45,GPIO46,GPIO47,
|
|
|
|
GPIO48,GPIO49,GPIO50,GPIO51,GPIO52,GPIO53,GPIO54,GPIO55,
|
|
|
|
GPIO56,GPIO57,GPIO58,GPIO59,GPIO60,GPIO61,GPIO62,GPIO63,
|
|
|
|
GPIO64,GPIO65,GPIO66,GPIO67,GPIO68,GPIO69,GPIO70,GPIO71,
|
|
|
|
GPIO72,GPIO73,GPIO74,GPIO75,GPIO76,GPIO77,GPIO78,GPIO79,
|
|
|
|
GPIO80,GPIO81,GPIO82,GPIO83,GPIO84,GPIO85,GPIO86,GPIO87,
|
|
|
|
GPIO88,GPIO89,GPIO90,GPIO91,GPIO92,GPIO93,GPIO94,GPIO95,
|
|
|
|
GPIO96,GPIO97,GPIO98,GPIO99,GPIO100,GPIO101,GPIO102,GPIO103,
|
|
|
|
GPIO104,GPIO105,GPIO106,GPIO107,GPIO108,GPIO109,GPIO110,GPIO111,
|
|
|
|
GPIO112,GPIO113,GPIO114,GPIO115,GPIO116,GPIO117,GPIO118,GPIO119,
|
|
|
|
GPIO120,GPIO121,GPIO122,GPIO123,GPIO124,GPIO125,GPIO126,GPIO127
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int dma_irq_mask = 0;
|
|
|
|
static unsigned int gpio_irq_mask[4] = {0};
|
|
|
|
|
2008-08-10 21:44:48 +00:00
|
|
|
void system_enable_irq(unsigned int irq)
|
2008-08-09 23:31:38 +00:00
|
|
|
{
|
|
|
|
register unsigned int t;
|
|
|
|
if ((irq >= IRQ_GPIO_0) && (irq <= IRQ_GPIO_0 + NUM_GPIO))
|
|
|
|
{
|
|
|
|
__gpio_unmask_irq(irq - IRQ_GPIO_0);
|
|
|
|
t = (irq - IRQ_GPIO_0) >> 5;
|
|
|
|
gpio_irq_mask[t] |= (1 << ((irq - IRQ_GPIO_0) & 0x1f));
|
|
|
|
__intc_unmask_irq(IRQ_GPIO0 - t);
|
|
|
|
}
|
|
|
|
else if ((irq >= IRQ_DMA_0) && (irq <= IRQ_DMA_0 + NUM_DMA))
|
|
|
|
{
|
|
|
|
__dmac_channel_enable_irq(irq - IRQ_DMA_0);
|
|
|
|
dma_irq_mask |= (1 << (irq - IRQ_DMA_0));
|
|
|
|
__intc_unmask_irq(IRQ_DMAC);
|
|
|
|
}
|
|
|
|
else if (irq < 32)
|
|
|
|
__intc_unmask_irq(irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dis_irq(unsigned int irq)
|
|
|
|
{
|
|
|
|
register unsigned int t;
|
|
|
|
if ((irq >= IRQ_GPIO_0) && (irq <= IRQ_GPIO_0 + NUM_GPIO))
|
|
|
|
{
|
|
|
|
__gpio_mask_irq(irq - IRQ_GPIO_0);
|
|
|
|
t = (irq - IRQ_GPIO_0) >> 5;
|
|
|
|
gpio_irq_mask[t] &= ~(1 << ((irq - IRQ_GPIO_0) & 0x1f));
|
|
|
|
if (!gpio_irq_mask[t])
|
|
|
|
__intc_mask_irq(IRQ_GPIO0 - t);
|
|
|
|
}
|
2012-10-26 10:55:13 +00:00
|
|
|
else if ((irq >= IRQ_DMA_0) && (irq < IRQ_DMA_0 + NUM_DMA))
|
2008-08-09 23:31:38 +00:00
|
|
|
{
|
|
|
|
__dmac_channel_disable_irq(irq - IRQ_DMA_0);
|
|
|
|
dma_irq_mask &= ~(1 << (irq - IRQ_DMA_0));
|
|
|
|
if (!dma_irq_mask)
|
|
|
|
__intc_mask_irq(IRQ_DMAC);
|
|
|
|
}
|
|
|
|
else if (irq < 32)
|
|
|
|
__intc_mask_irq(irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ack_irq(unsigned int irq)
|
|
|
|
{
|
|
|
|
if ((irq >= IRQ_GPIO_0) && (irq <= IRQ_GPIO_0 + NUM_GPIO))
|
|
|
|
{
|
|
|
|
__intc_ack_irq(IRQ_GPIO0 - ((irq - IRQ_GPIO_0)>>5));
|
|
|
|
__gpio_ack_irq(irq - IRQ_GPIO_0);
|
|
|
|
}
|
|
|
|
else if ((irq >= IRQ_DMA_0) && (irq <= IRQ_DMA_0 + NUM_DMA))
|
|
|
|
__intc_ack_irq(IRQ_DMAC);
|
|
|
|
else if (irq < 32)
|
|
|
|
__intc_ack_irq(irq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_irq_number(void)
|
|
|
|
{
|
2009-02-13 00:45:49 +00:00
|
|
|
static unsigned long ipl;
|
|
|
|
register int irq;
|
2008-08-09 23:31:38 +00:00
|
|
|
|
|
|
|
ipl |= REG_INTC_IPR;
|
2008-08-26 21:48:49 +00:00
|
|
|
|
2009-03-25 22:42:24 +00:00
|
|
|
if (UNLIKELY(ipl == 0))
|
2008-08-09 23:31:38 +00:00
|
|
|
return -1;
|
|
|
|
|
2009-03-25 22:42:24 +00:00
|
|
|
__asm__ __volatile__("negu $8, %0 \n"
|
|
|
|
"and $8, %0, $8 \n"
|
|
|
|
"clz %0, %1 \n"
|
|
|
|
"li $8, 31 \n"
|
|
|
|
"subu %0, $8, %0 \n"
|
|
|
|
: "=r" (irq)
|
|
|
|
: "r" (ipl)
|
|
|
|
: "t0"
|
|
|
|
);
|
2008-08-09 23:31:38 +00:00
|
|
|
|
2009-03-25 22:42:24 +00:00
|
|
|
if (UNLIKELY(irq < 0))
|
2008-08-09 23:31:38 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
ipl &= ~(1 << irq);
|
|
|
|
|
|
|
|
switch (irq)
|
|
|
|
{
|
|
|
|
case IRQ_GPIO0:
|
|
|
|
irq = __gpio_group_irq(0) + IRQ_GPIO_0;
|
|
|
|
break;
|
|
|
|
case IRQ_GPIO1:
|
|
|
|
irq = __gpio_group_irq(1) + IRQ_GPIO_0 + 32;
|
|
|
|
break;
|
|
|
|
case IRQ_GPIO2:
|
|
|
|
irq = __gpio_group_irq(2) + IRQ_GPIO_0 + 64;
|
|
|
|
break;
|
|
|
|
case IRQ_GPIO3:
|
|
|
|
irq = __gpio_group_irq(3) + IRQ_GPIO_0 + 96;
|
|
|
|
break;
|
|
|
|
case IRQ_DMAC:
|
|
|
|
irq = __dmac_get_irq() + IRQ_DMA_0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return irq;
|
|
|
|
}
|
|
|
|
|
2008-07-14 15:03:10 +00:00
|
|
|
void intr_handler(void)
|
|
|
|
{
|
2009-03-25 22:42:24 +00:00
|
|
|
register int irq = get_irq_number();
|
2008-12-20 01:48:46 +00:00
|
|
|
if(UNLIKELY(irq < 0))
|
2008-08-09 23:31:38 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
ack_irq(irq);
|
2008-12-20 01:48:46 +00:00
|
|
|
if(LIKELY(irq > 0))
|
2008-08-09 23:31:38 +00:00
|
|
|
irqvector[irq-1]();
|
2008-07-14 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
2008-12-20 01:48:46 +00:00
|
|
|
#define EXC(x,y) case (x): return (y);
|
2008-08-15 15:52:54 +00:00
|
|
|
static char* parse_exception(unsigned int cause)
|
|
|
|
{
|
2008-12-20 01:48:46 +00:00
|
|
|
switch(cause & M_CauseExcCode)
|
|
|
|
{
|
|
|
|
EXC(EXC_INT, "Interrupt");
|
|
|
|
EXC(EXC_MOD, "TLB Modified");
|
|
|
|
EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)");
|
|
|
|
EXC(EXC_ADEL, "Address Error (Load or Ifetch)");
|
|
|
|
EXC(EXC_ADES, "Address Error (Store)");
|
|
|
|
EXC(EXC_TLBS, "TLB Exception (Store)");
|
|
|
|
EXC(EXC_IBE, "Instruction Bus Error");
|
|
|
|
EXC(EXC_DBE, "Data Bus Error");
|
|
|
|
EXC(EXC_SYS, "Syscall");
|
|
|
|
EXC(EXC_BP, "Breakpoint");
|
|
|
|
EXC(EXC_RI, "Reserved Instruction");
|
|
|
|
EXC(EXC_CPU, "Coprocessor Unusable");
|
|
|
|
EXC(EXC_OV, "Overflow");
|
|
|
|
EXC(EXC_TR, "Trap Instruction");
|
|
|
|
EXC(EXC_FPE, "Floating Point Exception");
|
|
|
|
EXC(EXC_C2E, "COP2 Exception");
|
|
|
|
EXC(EXC_MDMX, "MDMX Exception");
|
|
|
|
EXC(EXC_WATCH, "Watch Exception");
|
|
|
|
EXC(EXC_MCHECK, "Machine Check Exception");
|
|
|
|
EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode");
|
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-08-15 15:52:54 +00:00
|
|
|
}
|
|
|
|
|
2008-08-09 23:31:38 +00:00
|
|
|
void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc)
|
2008-12-04 18:26:19 +00:00
|
|
|
{
|
2009-06-03 16:25:54 +00:00
|
|
|
#if EXTENDED_EXCEPTION_DESC
|
|
|
|
(void)epc;
|
|
|
|
|
|
|
|
/* Depends on crt0.S ! */
|
|
|
|
char *registers[] = { "ra", "fp", "gp", "t9", "t8", "s7", "s6", "s5", "s4",
|
|
|
|
"s3", "s2", "s1", "s0", "t7", "t6", "t5", "t4", "t3",
|
|
|
|
"t2", "t1", "t0", "a3", "a2", "a1", "a0", "v1", "v0",
|
|
|
|
"$1", "LO", "HI", "STATUS", "EPC" };
|
|
|
|
int i;
|
|
|
|
|
2009-11-14 11:27:41 +00:00
|
|
|
#ifdef HAVE_LCD_BITMAP
|
|
|
|
#if LCD_DEPTH > 1
|
2009-06-04 12:08:33 +00:00
|
|
|
lcd_set_backdrop(NULL);
|
2009-11-14 11:27:41 +00:00
|
|
|
lcd_set_drawmode(DRMODE_SOLID);
|
|
|
|
lcd_set_foreground(LCD_BLACK);
|
|
|
|
lcd_set_background(LCD_WHITE);
|
|
|
|
#endif
|
2009-06-03 16:25:54 +00:00
|
|
|
lcd_setfont(FONT_SYSFIXED);
|
2009-11-14 11:27:41 +00:00
|
|
|
lcd_set_viewport(NULL);
|
|
|
|
#endif
|
|
|
|
lcd_clear_display();
|
2015-01-08 23:22:40 +00:00
|
|
|
backlight_hw_on();
|
2009-06-03 16:25:54 +00:00
|
|
|
|
|
|
|
lcd_puts(0, 0, parse_exception(cause));
|
2010-05-06 19:28:12 +00:00
|
|
|
lcd_putsf(0, 1, "0x%08x at 0x%08x", read_c0_badvaddr(), epc);
|
2009-06-03 16:25:54 +00:00
|
|
|
for(i=0; i< 0x80/4; i+=2)
|
|
|
|
{
|
|
|
|
unsigned int* ptr = (unsigned int*)(stack_ptr + i*4);
|
2010-05-06 19:28:12 +00:00
|
|
|
lcd_putsf(0, 3 + i/2, "%s: 0x%08x %s: 0x%08x", registers[i], *ptr, registers[i+1], *(ptr+1));
|
2009-06-03 16:25:54 +00:00
|
|
|
}
|
|
|
|
lcd_update();
|
|
|
|
|
|
|
|
system_exception_wait();
|
|
|
|
#else
|
2009-02-23 16:10:46 +00:00
|
|
|
panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr);
|
2009-06-03 16:25:54 +00:00
|
|
|
#endif
|
2008-07-14 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
2009-02-13 00:45:49 +00:00
|
|
|
void tlb_refill_handler(void)
|
2008-07-14 15:03:10 +00:00
|
|
|
{
|
2009-02-13 00:45:49 +00:00
|
|
|
panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr());
|
2008-07-14 15:03:10 +00:00
|
|
|
}
|
|
|
|
|
2008-07-17 10:13:56 +00:00
|
|
|
void udelay(unsigned int usec)
|
|
|
|
{
|
2009-02-13 00:45:49 +00:00
|
|
|
unsigned int i = usec * (__cpm_get_cclk() / 2000000);
|
2008-07-17 10:13:56 +00:00
|
|
|
__asm__ __volatile__ (
|
|
|
|
".set noreorder \n"
|
|
|
|
"1: \n"
|
|
|
|
"bne %0, $0, 1b \n"
|
|
|
|
"addi %0, %0, -1 \n"
|
|
|
|
".set reorder \n"
|
|
|
|
: "=r" (i)
|
|
|
|
: "0" (i)
|
|
|
|
);
|
|
|
|
}
|
2008-11-04 20:30:01 +00:00
|
|
|
|
2008-07-17 10:13:56 +00:00
|
|
|
void mdelay(unsigned int msec)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
for(i=0; i<msec; i++)
|
|
|
|
udelay(1000);
|
|
|
|
}
|
|
|
|
|
2008-12-20 01:48:46 +00:00
|
|
|
static int dma_count = 0;
|
|
|
|
void dma_enable(void)
|
2008-11-04 20:30:01 +00:00
|
|
|
{
|
2008-12-20 01:48:46 +00:00
|
|
|
if(++dma_count == 1)
|
|
|
|
{
|
|
|
|
__cpm_start_dmac();
|
|
|
|
|
|
|
|
REG_DMAC_DCCSR(0) = 0;
|
|
|
|
REG_DMAC_DCCSR(1) = 0;
|
|
|
|
REG_DMAC_DCCSR(2) = 0;
|
|
|
|
REG_DMAC_DCCSR(3) = 0;
|
|
|
|
REG_DMAC_DCCSR(4) = 0;
|
|
|
|
REG_DMAC_DCCSR(5) = 0;
|
|
|
|
|
2009-02-26 21:15:40 +00:00
|
|
|
REG_DMAC_DMACR = (DMAC_DMACR_PR_RR | DMAC_DMACR_DMAE);
|
2008-12-20 01:48:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dma_disable(void)
|
|
|
|
{
|
|
|
|
if(--dma_count == 0)
|
|
|
|
{
|
|
|
|
REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE;
|
|
|
|
__cpm_stop_dmac();
|
|
|
|
}
|
2008-11-04 20:30:01 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
/* PLL output clock = EXTAL * NF / (NR * NO)
|
|
|
|
*
|
|
|
|
* NF = FD + 2, NR = RD + 2
|
|
|
|
* NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3)
|
|
|
|
*/
|
|
|
|
static void pll_init(void) ICODE_ATTR;
|
|
|
|
static void pll_init(void)
|
2008-12-31 01:11:04 +00:00
|
|
|
{
|
|
|
|
register unsigned int cfcr, plcr1;
|
2009-02-09 10:02:38 +00:00
|
|
|
int n2FR[33] = {
|
|
|
|
0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
|
|
|
|
7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
9
|
|
|
|
};
|
2009-02-23 16:10:46 +00:00
|
|
|
int div[5] = {0, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */
|
2009-02-09 10:02:38 +00:00
|
|
|
int nf, pllout2;
|
|
|
|
|
|
|
|
cfcr = CPM_CPCCR_CLKOEN |
|
|
|
|
CPM_CPCCR_PCS |
|
2009-03-25 22:42:24 +00:00
|
|
|
(n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
|
|
|
|
(n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
|
2009-02-09 10:02:38 +00:00
|
|
|
(n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
|
|
|
|
(n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) |
|
|
|
|
(n2FR[div[4]] << CPM_CPCCR_LDIV_BIT) |
|
|
|
|
CPM_CPCCR_CE; /* Perform clock divisions immediately */
|
2008-12-31 01:11:04 +00:00
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
pllout2 = (cfcr & CPM_CPCCR_PCS) ? CPU_FREQ : (CPU_FREQ / 2);
|
2008-12-31 01:11:04 +00:00
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
/* Init USB Host clock, pllout2 must be n*48MHz */
|
|
|
|
REG_CPM_UHCCDR = pllout2 / 48000000 - 1;
|
|
|
|
|
|
|
|
nf = CPU_FREQ * 2 / CFG_EXTAL;
|
2008-12-31 01:11:04 +00:00
|
|
|
plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */
|
2009-03-25 22:42:24 +00:00
|
|
|
(0 << CPM_CPPCR_PLLN_BIT) | /* RD=0, NR=2 */
|
2009-02-09 10:02:38 +00:00
|
|
|
(0 << CPM_CPPCR_PLLOD_BIT) | /* OD=0, NO=1 */
|
|
|
|
(0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */
|
|
|
|
CPM_CPPCR_PLLEN; /* enable PLL */
|
|
|
|
|
2008-12-31 01:11:04 +00:00
|
|
|
/* init PLL */
|
2009-02-09 10:02:38 +00:00
|
|
|
REG_CPM_CPCCR = cfcr;
|
|
|
|
REG_CPM_CPPCR = plcr1;
|
2008-12-31 01:11:04 +00:00
|
|
|
}
|
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
// SDRAM paramters
|
|
|
|
#define CFG_SDRAM_BW16 0 /* Data bus width: 0-32bit, 1-16bit */
|
|
|
|
#define CFG_SDRAM_BANK4 1 /* Banks each chip: 0-2bank, 1-4bank */
|
|
|
|
#define CFG_SDRAM_ROW 12 /* Row address: 11 to 13 */
|
|
|
|
#define CFG_SDRAM_COL 8 /* Column address: 8 to 12 */
|
|
|
|
#define CFG_SDRAM_CASL 2 /* CAS latency: 2 or 3 */
|
|
|
|
|
|
|
|
// SDRAM Timings, unit: ns
|
|
|
|
#define CFG_SDRAM_TRAS 45 /* RAS# Active Time */
|
|
|
|
#define CFG_SDRAM_RCD 20 /* RAS# to CAS# Delay */
|
|
|
|
#define CFG_SDRAM_TPC 20 /* RAS# Precharge Time */
|
|
|
|
#define CFG_SDRAM_TRWL 7 /* Write Latency Time */
|
|
|
|
#define CFG_SDRAM_TREF 7812 /* Refresh period: 8192 refresh cycles/64ms */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Init SDRAM memory.
|
|
|
|
*/
|
|
|
|
static void sdram_init(void) ICODE_ATTR;
|
|
|
|
static void sdram_init(void)
|
|
|
|
{
|
|
|
|
register unsigned int dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns;
|
|
|
|
|
|
|
|
unsigned int cas_latency_sdmr[2] = {
|
|
|
|
EMC_SDMR_CAS_2,
|
|
|
|
EMC_SDMR_CAS_3,
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned int cas_latency_dmcr[2] = {
|
|
|
|
1 << EMC_DMCR_TCL_BIT, /* CAS latency is 2 */
|
|
|
|
2 << EMC_DMCR_TCL_BIT /* CAS latency is 3 */
|
|
|
|
};
|
|
|
|
|
|
|
|
int div[] = { 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 };
|
|
|
|
|
|
|
|
cpu_clk = CPU_FREQ;
|
|
|
|
mem_clk = cpu_clk * div[__cpm_get_cdiv()] / div[__cpm_get_mdiv()];
|
|
|
|
|
|
|
|
//REG_EMC_BCR = 0; /* Disable bus release */
|
|
|
|
REG_EMC_RTCSR = 0; /* Disable clock for counting */
|
|
|
|
REG_EMC_RTCOR = 0;
|
|
|
|
REG_EMC_RTCNT = 0;
|
|
|
|
|
|
|
|
/* Fault DMCR value for mode register setting */
|
|
|
|
#define SDRAM_ROW0 11
|
|
|
|
#define SDRAM_COL0 8
|
|
|
|
#define SDRAM_BANK40 0
|
|
|
|
|
|
|
|
dmcr0 = ((SDRAM_ROW0 - 11) << EMC_DMCR_RA_BIT) |
|
|
|
|
((SDRAM_COL0 - 8) << EMC_DMCR_CA_BIT) |
|
|
|
|
(SDRAM_BANK40 << EMC_DMCR_BA_BIT) |
|
|
|
|
(CFG_SDRAM_BW16 << EMC_DMCR_BW_BIT) |
|
|
|
|
EMC_DMCR_EPIN | cas_latency_dmcr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
|
|
|
|
|
|
|
|
/* Basic DMCR value */
|
|
|
|
dmcr = ((CFG_SDRAM_ROW - 11) << EMC_DMCR_RA_BIT) |
|
|
|
|
((CFG_SDRAM_COL - 8) << EMC_DMCR_CA_BIT) |
|
|
|
|
(CFG_SDRAM_BANK4 << EMC_DMCR_BA_BIT) |
|
|
|
|
(CFG_SDRAM_BW16 << EMC_DMCR_BW_BIT) |
|
|
|
|
EMC_DMCR_EPIN | cas_latency_dmcr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
|
|
|
|
|
|
|
|
/* SDRAM timimg */
|
|
|
|
ns = 1000000000 / mem_clk;
|
|
|
|
tmp = CFG_SDRAM_TRAS / ns;
|
|
|
|
if (tmp < 4)
|
|
|
|
tmp = 4;
|
|
|
|
if (tmp > 11)
|
|
|
|
tmp = 11;
|
|
|
|
dmcr |= ((tmp - 4) << EMC_DMCR_TRAS_BIT);
|
|
|
|
tmp = CFG_SDRAM_RCD / ns;
|
|
|
|
if (tmp > 3)
|
|
|
|
tmp = 3;
|
|
|
|
dmcr |= (tmp << EMC_DMCR_RCD_BIT);
|
|
|
|
tmp = CFG_SDRAM_TPC / ns;
|
|
|
|
if (tmp > 7)
|
|
|
|
tmp = 7;
|
|
|
|
dmcr |= (tmp << EMC_DMCR_TPC_BIT);
|
|
|
|
tmp = CFG_SDRAM_TRWL / ns;
|
|
|
|
if (tmp > 3)
|
|
|
|
tmp = 3;
|
|
|
|
dmcr |= (tmp << EMC_DMCR_TRWL_BIT);
|
|
|
|
tmp = (CFG_SDRAM_TRAS + CFG_SDRAM_TPC) / ns;
|
|
|
|
if (tmp > 14)
|
|
|
|
tmp = 14;
|
|
|
|
dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT);
|
|
|
|
|
|
|
|
/* SDRAM mode value */
|
|
|
|
sdmode = EMC_SDMR_BT_SEQ |
|
|
|
|
EMC_SDMR_OM_NORMAL |
|
|
|
|
EMC_SDMR_BL_4 | cas_latency_sdmr[((CFG_SDRAM_CASL == 3) ? 1 : 0)];
|
|
|
|
|
|
|
|
/* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */
|
|
|
|
REG_EMC_DMCR = dmcr;
|
|
|
|
REG8(EMC_SDMR0 | sdmode) = 0;
|
|
|
|
|
|
|
|
/* Wait for precharge, > 200us */
|
|
|
|
tmp = (cpu_clk / 1000000) * 1000;
|
|
|
|
while (tmp--);
|
|
|
|
|
|
|
|
/* Stage 2. Enable auto-refresh */
|
|
|
|
REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH;
|
|
|
|
|
|
|
|
tmp = CFG_SDRAM_TREF / ns;
|
2008-12-31 01:11:04 +00:00
|
|
|
tmp = tmp / 64 + 1;
|
2009-02-09 10:02:38 +00:00
|
|
|
if (tmp > 0xff)
|
2008-12-31 01:11:04 +00:00
|
|
|
tmp = 0xff;
|
2009-02-09 10:02:38 +00:00
|
|
|
REG_EMC_RTCOR = tmp;
|
|
|
|
REG_EMC_RTCNT = 0;
|
|
|
|
REG_EMC_RTCSR = EMC_RTCSR_CKS_64; /* Divisor is 64, CKO/64 */
|
2008-12-31 01:11:04 +00:00
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
/* Wait for number of auto-refresh cycles */
|
|
|
|
tmp = (cpu_clk / 1000000) * 1000;
|
|
|
|
while (tmp--);
|
2008-12-31 01:11:04 +00:00
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
/* Stage 3. Mode Register Set */
|
|
|
|
REG_EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET;
|
|
|
|
REG8(EMC_SDMR0 | sdmode) = 0;
|
2008-12-31 01:11:04 +00:00
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
/* Set back to basic DMCR value */
|
|
|
|
REG_EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET;
|
2008-12-31 01:11:04 +00:00
|
|
|
|
2009-02-09 10:02:38 +00:00
|
|
|
/* everything is ok now */
|
2008-12-31 01:11:04 +00:00
|
|
|
}
|
|
|
|
|
2009-02-13 00:45:49 +00:00
|
|
|
/* Gets called *before* main */
|
|
|
|
void ICODE_ATTR system_main(void)
|
2008-07-17 10:13:56 +00:00
|
|
|
{
|
2008-08-09 23:31:38 +00:00
|
|
|
int i;
|
2009-02-09 10:02:38 +00:00
|
|
|
|
2008-07-17 10:13:56 +00:00
|
|
|
__dcache_writeback_all();
|
|
|
|
__icache_invalidate_all();
|
2008-08-09 23:31:38 +00:00
|
|
|
|
2008-09-14 16:26:08 +00:00
|
|
|
write_c0_status(1 << 28 | 1 << 10 ); /* Enable CP | Mask interrupt 2 */
|
2008-08-26 21:48:49 +00:00
|
|
|
|
2008-08-15 15:52:54 +00:00
|
|
|
/* Disable all interrupts */
|
|
|
|
for(i=0; i<IRQ_MAX; i++)
|
2008-08-10 21:44:48 +00:00
|
|
|
dis_irq(i);
|
2008-08-06 20:39:02 +00:00
|
|
|
|
2009-02-13 00:45:49 +00:00
|
|
|
mmu_init();
|
|
|
|
pll_init();
|
|
|
|
sdram_init();
|
2008-07-17 10:13:56 +00:00
|
|
|
|
2008-12-20 13:10:04 +00:00
|
|
|
/* Disable unneeded clocks, clocks are enabled when needed */
|
|
|
|
__cpm_stop_all();
|
2008-12-31 01:11:04 +00:00
|
|
|
__cpm_suspend_usbhost();
|
|
|
|
|
2008-11-04 20:30:01 +00:00
|
|
|
/* Enable interrupts at core level */
|
2009-02-13 00:45:49 +00:00
|
|
|
enable_interrupt();
|
2008-07-17 10:13:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void system_reboot(void)
|
|
|
|
{
|
|
|
|
REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN;
|
|
|
|
REG_WDT_TCNT = 0;
|
|
|
|
REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */
|
|
|
|
REG_TCU_TSCR = TCU_TSSR_WDTSC; /* enable wdt clock */
|
|
|
|
REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */
|
|
|
|
|
|
|
|
while (1);
|
2008-07-14 15:03:10 +00:00
|
|
|
}
|
2008-08-26 21:48:49 +00:00
|
|
|
|
2009-01-08 10:15:32 +00:00
|
|
|
void system_exception_wait(void)
|
|
|
|
{
|
|
|
|
/* check for power button without including any .h file */
|
2009-07-03 21:34:40 +00:00
|
|
|
while(1)
|
2009-01-08 10:15:32 +00:00
|
|
|
{
|
2009-07-03 21:34:40 +00:00
|
|
|
if( (~REG_GPIO_PXPIN(3)) & (1 << 29) )
|
|
|
|
return;
|
|
|
|
asm volatile("nop");
|
2009-01-08 10:15:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-26 21:48:49 +00:00
|
|
|
void power_off(void)
|
|
|
|
{
|
2009-02-16 22:49:58 +00:00
|
|
|
/* Enable RTC clock */
|
|
|
|
__cpm_start_rtc();
|
|
|
|
|
2008-08-26 21:48:49 +00:00
|
|
|
/* Put system into hibernate mode */
|
|
|
|
__rtc_clear_alarm_flag();
|
|
|
|
__rtc_clear_hib_stat_all();
|
2008-11-04 20:30:01 +00:00
|
|
|
/* __rtc_set_scratch_pattern(0x12345678); */
|
2008-08-26 21:48:49 +00:00
|
|
|
__rtc_enable_alarm_wakeup();
|
2009-02-13 00:45:49 +00:00
|
|
|
__rtc_set_hrcr_val(0xFE0);
|
|
|
|
__rtc_set_hwfcr_val(0xFFFF << 4);
|
2008-08-26 21:48:49 +00:00
|
|
|
__rtc_power_down();
|
|
|
|
|
|
|
|
while(1);
|
|
|
|
}
|
2009-02-09 10:02:38 +00:00
|
|
|
|
|
|
|
void system_init(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int system_memory_guard(int newmode)
|
|
|
|
{
|
|
|
|
(void)newmode;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-07-03 21:34:40 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
|
|
|
|
void set_cpu_frequency(long frequency)
|
|
|
|
{
|
|
|
|
unsigned long cfcr = REG_CPM_CPCCR;
|
|
|
|
cfcr &= ~CPM_CPCCR_CDIV_MASK;
|
|
|
|
|
2009-12-05 19:55:29 +00:00
|
|
|
if(frequency != CPUFREQ_NORMAL)
|
2009-07-03 21:34:40 +00:00
|
|
|
cfcr |= (0 << CPM_CPCCR_CDIV_BIT);
|
|
|
|
else
|
|
|
|
cfcr |= (2 << CPM_CPCCR_CDIV_BIT);
|
|
|
|
|
|
|
|
REG_CPM_CPCCR = cfcr;
|
|
|
|
cpu_frequency = frequency;
|
|
|
|
}
|
|
|
|
#endif
|