Initial revision
This commit is contained in:
43
cpu/arm720t/Makefile
Normal file
43
cpu/arm720t/Makefile
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# (C) Copyright 2000
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# See file CREDITS for list of people who contributed to this
|
||||
# project.
|
||||
#
|
||||
# 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 program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
# MA 02111-1307 USA
|
||||
#
|
||||
|
||||
include $(TOPDIR)/config.mk
|
||||
|
||||
LIB = lib$(CPU).a
|
||||
|
||||
START = start.o
|
||||
OBJS = serial.o interrupts.o cpu.o
|
||||
|
||||
all: .depend $(START) $(LIB)
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) crv $@ $(OBJS)
|
||||
|
||||
#########################################################################
|
||||
|
||||
.depend: Makefile $(START:.o=.S) $(OBJS:.o=.c)
|
||||
$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
|
||||
|
||||
sinclude .depend
|
||||
|
||||
#########################################################################
|
||||
265
cpu/arm720t/interrupts.c
Normal file
265
cpu/arm720t/interrupts.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clps7111.h>
|
||||
|
||||
#include <asm/proc-armv/ptrace.h>
|
||||
|
||||
extern void reset_cpu(ulong addr);
|
||||
|
||||
/* we always count down the max. */
|
||||
#define TIMER_LOAD_VAL 0xffff
|
||||
|
||||
/* macro to read the 16 bit timer */
|
||||
#define READ_TIMER (IO_TC1D & 0xffff)
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
/* enable IRQ/FIQ interrupts */
|
||||
void enable_interrupts (void)
|
||||
{
|
||||
unsigned long temp;
|
||||
__asm__ __volatile__("mrs %0, cpsr\n"
|
||||
"bic %0, %0, #0x80\n"
|
||||
"msr cpsr_c, %0"
|
||||
: "=r" (temp)
|
||||
:
|
||||
: "memory");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* disable IRQ/FIQ interrupts
|
||||
* returns true if interrupts had been enabled before we disabled them
|
||||
*/
|
||||
int disable_interrupts (void)
|
||||
{
|
||||
unsigned long old,temp;
|
||||
__asm__ __volatile__("mrs %0, cpsr\n"
|
||||
"orr %1, %0, #0x80\n"
|
||||
"msr cpsr_c, %1"
|
||||
: "=r" (old), "=r" (temp)
|
||||
:
|
||||
: "memory");
|
||||
return (old & 0x80) == 0;
|
||||
}
|
||||
#else
|
||||
void enable_interrupts (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int disable_interrupts (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void bad_mode (void)
|
||||
{
|
||||
panic ("Resetting CPU ...\n");
|
||||
reset_cpu (0);
|
||||
}
|
||||
|
||||
void show_regs (struct pt_regs *regs)
|
||||
{
|
||||
unsigned long flags;
|
||||
const char *processor_modes[] =
|
||||
{ "USER_26", "FIQ_26", "IRQ_26", "SVC_26", "UK4_26", "UK5_26",
|
||||
"UK6_26", "UK7_26",
|
||||
"UK8_26", "UK9_26", "UK10_26", "UK11_26", "UK12_26", "UK13_26",
|
||||
"UK14_26", "UK15_26",
|
||||
"USER_32", "FIQ_32", "IRQ_32", "SVC_32", "UK4_32", "UK5_32",
|
||||
"UK6_32", "ABT_32",
|
||||
"UK8_32", "UK9_32", "UK10_32", "UND_32", "UK12_32", "UK13_32",
|
||||
"UK14_32", "SYS_32"
|
||||
};
|
||||
|
||||
flags = condition_codes (regs);
|
||||
|
||||
printf ("pc : [<%08lx>] lr : [<%08lx>]\n"
|
||||
"sp : %08lx ip : %08lx fp : %08lx\n",
|
||||
instruction_pointer (regs),
|
||||
regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
|
||||
printf ("r10: %08lx r9 : %08lx r8 : %08lx\n",
|
||||
regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
|
||||
printf ("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
|
||||
regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
|
||||
printf ("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
|
||||
regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
|
||||
printf ("Flags: %c%c%c%c",
|
||||
flags & CC_N_BIT ? 'N' : 'n',
|
||||
flags & CC_Z_BIT ? 'Z' : 'z',
|
||||
flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
|
||||
printf (" IRQs %s FIQs %s Mode %s%s\n",
|
||||
interrupts_enabled (regs) ? "on" : "off",
|
||||
fast_interrupts_enabled (regs) ? "on" : "off",
|
||||
processor_modes[processor_mode (regs)],
|
||||
thumb_mode (regs) ? " (T)" : "");
|
||||
}
|
||||
|
||||
void do_undefined_instruction (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("undefined instruction\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_software_interrupt (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("software interrupt\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_prefetch_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("prefetch abort\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_data_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("data abort\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_not_used (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("not used\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_fiq (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("fast interrupt request\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_irq (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("interrupt request\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
static ulong timestamp;
|
||||
static ulong lastdec;
|
||||
|
||||
int interrupt_init (void)
|
||||
{
|
||||
/* disable all interrupts */
|
||||
IO_INTMR1 = 0;
|
||||
|
||||
/* operate timer 1 in prescale mode */
|
||||
IO_SYSCON1 |= SYSCON1_TC1M;
|
||||
|
||||
/* select 2kHz clock source for timer 1 */
|
||||
IO_SYSCON1 &= ~SYSCON1_TC1S;
|
||||
|
||||
/* set timer 1 counter */
|
||||
lastdec = IO_TC1D = TIMER_LOAD_VAL;
|
||||
timestamp = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* timer without interrupts
|
||||
*/
|
||||
|
||||
void reset_timer (void)
|
||||
{
|
||||
reset_timer_masked ();
|
||||
}
|
||||
|
||||
ulong get_timer (ulong base)
|
||||
{
|
||||
return get_timer_masked () - base;
|
||||
}
|
||||
|
||||
void set_timer (ulong t)
|
||||
{
|
||||
timestamp = t;
|
||||
}
|
||||
|
||||
void udelay (unsigned long usec)
|
||||
{
|
||||
ulong tmo;
|
||||
|
||||
tmo = usec / 1000;
|
||||
tmo *= CFG_HZ;
|
||||
tmo /= 1000;
|
||||
|
||||
tmo += get_timer (0);
|
||||
|
||||
while (get_timer_masked () < tmo)
|
||||
/*NOP*/;
|
||||
}
|
||||
|
||||
void reset_timer_masked (void)
|
||||
{
|
||||
/* reset time */
|
||||
lastdec = READ_TIMER;
|
||||
timestamp = 0;
|
||||
}
|
||||
|
||||
ulong get_timer_masked (void)
|
||||
{
|
||||
ulong now = READ_TIMER;
|
||||
|
||||
if (lastdec >= now) {
|
||||
/* normal mode */
|
||||
timestamp += lastdec - now;
|
||||
} else {
|
||||
/* we have an overflow ... */
|
||||
timestamp += lastdec + TIMER_LOAD_VAL - now;
|
||||
}
|
||||
lastdec = now;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void udelay_masked (unsigned long usec)
|
||||
{
|
||||
ulong tmo;
|
||||
|
||||
tmo = usec / 1000;
|
||||
tmo *= CFG_HZ;
|
||||
tmo /= 1000;
|
||||
|
||||
reset_timer_masked ();
|
||||
|
||||
while (get_timer_masked () < tmo)
|
||||
/*NOP*/;
|
||||
}
|
||||
43
cpu/arm920t/Makefile
Normal file
43
cpu/arm920t/Makefile
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# (C) Copyright 2000, 2001, 2002
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# See file CREDITS for list of people who contributed to this
|
||||
# project.
|
||||
#
|
||||
# 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 program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
# MA 02111-1307 USA
|
||||
#
|
||||
|
||||
include $(TOPDIR)/config.mk
|
||||
|
||||
LIB = lib$(CPU).a
|
||||
|
||||
START = start.o
|
||||
OBJS = serial.o interrupts.o cpu.o speed.o
|
||||
|
||||
all: .depend $(START) $(LIB)
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) crv $@ $(OBJS)
|
||||
|
||||
#########################################################################
|
||||
|
||||
.depend: Makefile $(START:.o=.S) $(OBJS:.o=.c)
|
||||
$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
|
||||
|
||||
sinclude .depend
|
||||
|
||||
#########################################################################
|
||||
304
cpu/arm920t/interrupts.c
Normal file
304
cpu/arm920t/interrupts.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <arm920t.h>
|
||||
#if defined(CONFIG_S3C2400)
|
||||
#include <s3c2400.h>
|
||||
#elif defined(CONFIG_S3C2410)
|
||||
#include <s3c2410.h>
|
||||
#endif
|
||||
|
||||
#include <asm/proc-armv/ptrace.h>
|
||||
|
||||
extern void reset_cpu(ulong addr);
|
||||
int timer_load_val = 0;
|
||||
|
||||
/* macro to read the 16 bit timer */
|
||||
#define READ_TIMER (rTCNTO4 & 0xffff)
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
/* enable IRQ interrupts */
|
||||
void enable_interrupts (void)
|
||||
{
|
||||
unsigned long temp;
|
||||
__asm__ __volatile__("mrs %0, cpsr\n"
|
||||
"bic %0, %0, #0x80\n"
|
||||
"msr cpsr_c, %0"
|
||||
: "=r" (temp)
|
||||
:
|
||||
: "memory");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* disable IRQ/FIQ interrupts
|
||||
* returns true if interrupts had been enabled before we disabled them
|
||||
*/
|
||||
int disable_interrupts (void)
|
||||
{
|
||||
unsigned long old,temp;
|
||||
__asm__ __volatile__("mrs %0, cpsr\n"
|
||||
"orr %1, %0, #0xc0\n"
|
||||
"msr cpsr_c, %1"
|
||||
: "=r" (old), "=r" (temp)
|
||||
:
|
||||
: "memory");
|
||||
return (old & 0x80) == 0;
|
||||
}
|
||||
#else
|
||||
void enable_interrupts (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int disable_interrupts (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void bad_mode (void)
|
||||
{
|
||||
panic ("Resetting CPU ...\n");
|
||||
reset_cpu (0);
|
||||
}
|
||||
|
||||
void show_regs (struct pt_regs *regs)
|
||||
{
|
||||
unsigned long flags;
|
||||
const char *processor_modes[] = {
|
||||
"USER_26", "FIQ_26", "IRQ_26", "SVC_26",
|
||||
"UK4_26", "UK5_26", "UK6_26", "UK7_26",
|
||||
"UK8_26", "UK9_26", "UK10_26", "UK11_26",
|
||||
"UK12_26", "UK13_26", "UK14_26", "UK15_26",
|
||||
"USER_32", "FIQ_32", "IRQ_32", "SVC_32",
|
||||
"UK4_32", "UK5_32", "UK6_32", "ABT_32",
|
||||
"UK8_32", "UK9_32", "UK10_32", "UND_32",
|
||||
"UK12_32", "UK13_32", "UK14_32", "SYS_32",
|
||||
};
|
||||
|
||||
flags = condition_codes (regs);
|
||||
|
||||
printf ("pc : [<%08lx>] lr : [<%08lx>]\n"
|
||||
"sp : %08lx ip : %08lx fp : %08lx\n",
|
||||
instruction_pointer (regs),
|
||||
regs->ARM_lr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp);
|
||||
printf ("r10: %08lx r9 : %08lx r8 : %08lx\n",
|
||||
regs->ARM_r10, regs->ARM_r9, regs->ARM_r8);
|
||||
printf ("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n",
|
||||
regs->ARM_r7, regs->ARM_r6, regs->ARM_r5, regs->ARM_r4);
|
||||
printf ("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n",
|
||||
regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0);
|
||||
printf ("Flags: %c%c%c%c",
|
||||
flags & CC_N_BIT ? 'N' : 'n',
|
||||
flags & CC_Z_BIT ? 'Z' : 'z',
|
||||
flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v');
|
||||
printf (" IRQs %s FIQs %s Mode %s%s\n",
|
||||
interrupts_enabled (regs) ? "on" : "off",
|
||||
fast_interrupts_enabled (regs) ? "on" : "off",
|
||||
processor_modes[processor_mode (regs)],
|
||||
thumb_mode (regs) ? " (T)" : "");
|
||||
}
|
||||
|
||||
void do_undefined_instruction (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("undefined instruction\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_software_interrupt (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("software interrupt\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_prefetch_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("prefetch abort\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_data_abort (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("data abort\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_not_used (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("not used\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_fiq (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("fast interrupt request\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
void do_irq (struct pt_regs *pt_regs)
|
||||
{
|
||||
printf ("interrupt request\n");
|
||||
show_regs (pt_regs);
|
||||
bad_mode ();
|
||||
}
|
||||
|
||||
static ulong timestamp;
|
||||
static ulong lastdec;
|
||||
|
||||
int interrupt_init (void)
|
||||
{
|
||||
/* use PWM Timer 4 because it has no output */
|
||||
/* prescaler for Timer 4 is 16 */
|
||||
rTCFG0 = 0x0f00;
|
||||
if (timer_load_val == 0)
|
||||
{
|
||||
/*
|
||||
* for 10 ms clock period @ PCLK with 4 bit divider = 1/2
|
||||
* (default) and prescaler = 16. Should be 10390
|
||||
* @33.25MHz and 15625 @ 50 MHz
|
||||
*/
|
||||
timer_load_val = get_PCLK()/(2 * 16 * 100);
|
||||
}
|
||||
/* load value for 10 ms timeout */
|
||||
lastdec = rTCNTB4 = timer_load_val;
|
||||
/* auto load, manual update of Timer 4 */
|
||||
rTCON = 0x600000;
|
||||
/* auto load, start Timer 4 */
|
||||
rTCON = 0x500000;
|
||||
timestamp = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* timer without interrupts
|
||||
*/
|
||||
|
||||
void reset_timer (void)
|
||||
{
|
||||
reset_timer_masked ();
|
||||
}
|
||||
|
||||
ulong get_timer (ulong base)
|
||||
{
|
||||
return get_timer_masked () - base;
|
||||
}
|
||||
|
||||
void set_timer (ulong t)
|
||||
{
|
||||
timestamp = t;
|
||||
}
|
||||
|
||||
void udelay (unsigned long usec)
|
||||
{
|
||||
ulong tmo;
|
||||
|
||||
tmo = usec / 1000;
|
||||
tmo *= (timer_load_val * 100);
|
||||
tmo /= 1000;
|
||||
|
||||
tmo += get_timer (0);
|
||||
|
||||
while (get_timer_masked () < tmo)
|
||||
/*NOP*/;
|
||||
}
|
||||
|
||||
void reset_timer_masked (void)
|
||||
{
|
||||
/* reset time */
|
||||
lastdec = READ_TIMER;
|
||||
timestamp = 0;
|
||||
}
|
||||
|
||||
ulong get_timer_masked (void)
|
||||
{
|
||||
ulong now = READ_TIMER;
|
||||
|
||||
if (lastdec >= now) {
|
||||
/* normal mode */
|
||||
timestamp += lastdec - now;
|
||||
} else {
|
||||
/* we have an overflow ... */
|
||||
timestamp += lastdec + timer_load_val - now;
|
||||
}
|
||||
lastdec = now;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void udelay_masked (unsigned long usec)
|
||||
{
|
||||
ulong tmo;
|
||||
|
||||
tmo = usec / 1000;
|
||||
tmo *= (timer_load_val * 100);
|
||||
tmo /= 1000;
|
||||
|
||||
reset_timer_masked ();
|
||||
|
||||
while (get_timer_masked () < tmo)
|
||||
/*NOP*/;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is derived from PowerPC code (read timebase as long long).
|
||||
* On ARM it just returns the timer value.
|
||||
*/
|
||||
unsigned long long get_ticks(void)
|
||||
{
|
||||
return get_timer(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is derived from PowerPC code (timebase clock frequency).
|
||||
* On ARM it returns the number of timer ticks per second.
|
||||
*/
|
||||
ulong get_tbclk (void)
|
||||
{
|
||||
ulong tbclk;
|
||||
|
||||
#if defined(CONFIG_SMDK2400) || defined(CONFIG_TRAB)
|
||||
tbclk = timer_load_val * 100;
|
||||
#elif defined(CONFIG_SMDK2410)
|
||||
tbclk = CFG_HZ;
|
||||
#endif
|
||||
|
||||
return tbclk;
|
||||
}
|
||||
200
cpu/arm920t/serial.c
Normal file
200
cpu/arm920t/serial.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#if defined(CONFIG_S3C2400) || defined(CONFIG_TRAB)
|
||||
#include <s3c2400.h>
|
||||
#elif defined(CONFIG_S3C2410)
|
||||
#include <s3c2410.h>
|
||||
#endif
|
||||
|
||||
|
||||
void serial_setbrg (void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int i;
|
||||
unsigned int reg = 0;
|
||||
|
||||
/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
|
||||
reg = get_PCLK() / (16 * gd->baudrate) - 1;
|
||||
|
||||
#ifdef CONFIG_SERIAL1
|
||||
/* FIFO enable, Tx/Rx FIFO clear */
|
||||
rUFCON0 = 0x07;
|
||||
rUMCON0 = 0x0;
|
||||
/* Normal,No parity,1 stop,8 bit */
|
||||
rULCON0 = 0x3;
|
||||
/*
|
||||
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
|
||||
* normal,interrupt or polling
|
||||
*/
|
||||
rUCON0 = 0x245;
|
||||
rUBRDIV0 = reg;
|
||||
|
||||
#ifdef CONFIG_HWFLOW
|
||||
rUMCON0 = 0x1; /* RTS up */
|
||||
#endif
|
||||
for (i = 0; i < 100; i++);
|
||||
#elif CONFIG_SERIAL2
|
||||
# if defined(CONFIG_TRAB)
|
||||
# #error "TRAB supports only CONFIG_SERIAL1"
|
||||
# endif
|
||||
/* FIFO enable, Tx/Rx FIFO clear */
|
||||
rUFCON1 = 0x06;
|
||||
rUMCON1 = 0x0;
|
||||
/* Normal,No parity,1 stop,8 bit */
|
||||
rULCON1 = 0x3;
|
||||
/*
|
||||
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
|
||||
* normal,interrupt or polling
|
||||
*/
|
||||
rUCON1 = 0x245;
|
||||
rUBRDIV1 = reg;
|
||||
|
||||
#ifdef CONFIG_HWFLOW
|
||||
rUMCON1 = 0x1; /* RTS up */
|
||||
#endif
|
||||
for (i = 0; i < 100; i++);
|
||||
#else
|
||||
#error "Bad: you didn't configure serial ..."
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*
|
||||
*/
|
||||
int serial_init (void)
|
||||
{
|
||||
serial_setbrg ();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a single byte from the serial port. Returns 1 on success, 0
|
||||
* otherwise. When the function is succesfull, the character read is
|
||||
* written into its argument c.
|
||||
*/
|
||||
int serial_getc (void)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL1
|
||||
while (!(rUTRSTAT0 & 0x1));
|
||||
|
||||
return rURXH0 & 0xff;
|
||||
#elif CONFIG_SERIAL2
|
||||
while (!(rUTRSTAT1 & 0x1));
|
||||
|
||||
return rURXH1 & 0xff;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HWFLOW
|
||||
static int hwflow = 0; /* turned off by default */
|
||||
int hwflow_onoff(int on)
|
||||
{
|
||||
switch(on) {
|
||||
case 0:
|
||||
default:
|
||||
break; /* return current */
|
||||
case 1:
|
||||
hwflow = 1; /* turn on */
|
||||
break;
|
||||
case -1:
|
||||
hwflow = 0; /* turn off */
|
||||
break;
|
||||
}
|
||||
return hwflow;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
static int be_quiet = 0;
|
||||
void disable_putc(void)
|
||||
{
|
||||
be_quiet = 1;
|
||||
}
|
||||
|
||||
void enable_putc(void)
|
||||
{
|
||||
be_quiet = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Output a single byte to the serial port.
|
||||
*/
|
||||
void serial_putc (const char c)
|
||||
{
|
||||
#ifdef CONFIG_MODEM_SUPPORT
|
||||
if (be_quiet)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL1
|
||||
/* wait for room in the tx FIFO on SERIAL1 */
|
||||
while (!(rUTRSTAT0 & 0x2));
|
||||
|
||||
#ifdef CONFIG_HWFLOW
|
||||
/* Wait for CTS up */
|
||||
while(hwflow && !(rUMSTAT0 & 0x1))
|
||||
;
|
||||
#endif
|
||||
|
||||
rUTXH0 = c;
|
||||
#elif CONFIG_SERIAL2
|
||||
/* wait for room in the tx FIFO on SERIAL2 */
|
||||
while (!(rUTRSTAT1 & 0x2));
|
||||
|
||||
#ifdef CONFIG_HWFLOW
|
||||
/* Wait for CTS up */
|
||||
while(hwflow && !(rUMSTAT1 & 0x1))
|
||||
;
|
||||
#endif
|
||||
rUTXH1 = c;
|
||||
#endif
|
||||
|
||||
/* If \n, also do \r */
|
||||
if (c == '\n')
|
||||
serial_putc ('\r');
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether a character is in the RX buffer
|
||||
*/
|
||||
int serial_tstc (void)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL1
|
||||
return rUTRSTAT0 & 0x1;
|
||||
#elif CONFIG_SERIAL2
|
||||
return rUTRSTAT1 & 0x1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
serial_puts (const char *s)
|
||||
{
|
||||
while (*s) {
|
||||
serial_putc (*s++);
|
||||
}
|
||||
}
|
||||
96
cpu/arm920t/speed.c
Normal file
96
cpu/arm920t/speed.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* (C) Copyright 2001-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* David Mueller, ELSOFT AG, d.mueller@elsoft.ch
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* This code should work for both the S3C2400 and the S3C2410
|
||||
* as they seem to have the same PLL and clock machinery inside.
|
||||
* The different address mapping is handled by the s3c24xx.h files below.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#if defined(CONFIG_S3C2400)
|
||||
#include <s3c2400.h>
|
||||
#elif defined(CONFIG_S3C2410)
|
||||
#include <s3c2410.h>
|
||||
#endif
|
||||
|
||||
#define MPLL 0
|
||||
#define UPLL 1
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* NOTE: This describes the proper use of this file.
|
||||
*
|
||||
* CONFIG_PLL_INPUT_FREQ should be defined as the input frequency of the PLL.
|
||||
*
|
||||
* get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of
|
||||
* the specified bus in HZ.
|
||||
*/
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static ulong get_PLLCLK(int pllreg)
|
||||
{
|
||||
ulong r, m, p, s;
|
||||
|
||||
if (pllreg == MPLL)
|
||||
r = rMPLLCON;
|
||||
else if (pllreg == UPLL)
|
||||
r = rUPLLCON;
|
||||
else
|
||||
hang();
|
||||
|
||||
m = ((r & 0xFF000) >> 12) + 8;
|
||||
p = ((r & 0x003F0) >> 4) + 2;
|
||||
s = r & 0x3;
|
||||
|
||||
return((CONFIG_PLL_INPUT_FREQ * m) / (p << s));
|
||||
}
|
||||
|
||||
/* return FCLK frequency */
|
||||
ulong get_FCLK(void)
|
||||
{
|
||||
return(get_PLLCLK(MPLL));
|
||||
}
|
||||
|
||||
/* return HCLK frequency */
|
||||
ulong get_HCLK(void)
|
||||
{
|
||||
ulong clkdiv = rCLKDIVN;
|
||||
|
||||
return((clkdiv & 0x2) ? get_FCLK()/2 : get_FCLK());
|
||||
}
|
||||
|
||||
/* return PCLK frequency */
|
||||
ulong get_PCLK(void)
|
||||
{
|
||||
ulong clkdiv = rCLKDIVN;
|
||||
|
||||
return((clkdiv & 0x1) ? get_HCLK()/2 : get_HCLK());
|
||||
}
|
||||
|
||||
/* return UCLK frequency */
|
||||
ulong get_UCLK(void)
|
||||
{
|
||||
return(get_PLLCLK(UPLL));
|
||||
}
|
||||
383
cpu/mpc824x/cpu_init.c
Normal file
383
cpu/mpc824x/cpu_init.c
Normal file
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Rob Taylor. Flying Pig Systems. robt@flyingpig.com.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <mpc824x.h>
|
||||
|
||||
#ifndef CFG_BANK0_ROW
|
||||
#define CFG_BANK0_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_BANK1_ROW
|
||||
#define CFG_BANK1_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_BANK2_ROW
|
||||
#define CFG_BANK2_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_BANK3_ROW
|
||||
#define CFG_BANK3_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_BANK4_ROW
|
||||
#define CFG_BANK4_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_BANK5_ROW
|
||||
#define CFG_BANK5_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_BANK6_ROW
|
||||
#define CFG_BANK6_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_BANK7_ROW
|
||||
#define CFG_BANK7_ROW 0
|
||||
#endif
|
||||
#ifndef CFG_DBUS_SIZE2
|
||||
#define CFG_DBUS_SIZE2 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Breath some life into the CPU...
|
||||
*
|
||||
* Set up the memory map,
|
||||
* initialize a bunch of registers,
|
||||
*/
|
||||
void
|
||||
cpu_init_f (void)
|
||||
{
|
||||
/* MOUSSE board is initialized in asm */
|
||||
#if !defined(CONFIG_MOUSSE) && !defined(CONFIG_BMW)
|
||||
register unsigned long val;
|
||||
CONFIG_WRITE_HALFWORD(PCICR, 0x06); /* Bus Master, respond to PCI memory space acesses*/
|
||||
/* CONFIG_WRITE_HALFWORD(PCISR, 0xffff); */ /*reset PCISR*/
|
||||
|
||||
#if defined(CONFIG_MUSENKI) || defined(CONFIG_PN62)
|
||||
/* Why is this here, you ask? Try, just try setting 0x8000
|
||||
* in PCIACR with CONFIG_WRITE_HALFWORD()
|
||||
* this one was a stumper, and we are annoyed
|
||||
*/
|
||||
|
||||
#define M_CONFIG_WRITE_HALFWORD( addr, data ) \
|
||||
__asm__ __volatile__( \
|
||||
" \
|
||||
stw %2,0(%0)\n \
|
||||
sync\n \
|
||||
sth %3,2(%1)\n \
|
||||
sync\n \
|
||||
" \
|
||||
: /* no output */ \
|
||||
: "r" (CONFIG_ADDR), "r" (CONFIG_DATA), \
|
||||
"r" (PCISWAP(addr & ~3)), "r" (PCISWAP(data << 16)) \
|
||||
);
|
||||
|
||||
M_CONFIG_WRITE_HALFWORD(PCIACR, 0x8000);
|
||||
#endif
|
||||
|
||||
CONFIG_WRITE_BYTE(PCLSR, 0x8); /* set PCI cache line size */
|
||||
|
||||
/*
|
||||
* Note that although this bit is cleared after a hard reset, it
|
||||
* must be explicitly set and then cleared by software during
|
||||
* initialization in order to guarantee correct operation of the
|
||||
* DLL and the SDRAM_CLK[0:3] signals (if they are used).
|
||||
*/
|
||||
CONFIG_READ_BYTE (AMBOR, val);
|
||||
CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
|
||||
CONFIG_WRITE_BYTE(AMBOR, val | 0x20);
|
||||
CONFIG_WRITE_BYTE(AMBOR, val & 0xDF);
|
||||
|
||||
CONFIG_READ_WORD(PICR1, val);
|
||||
#if defined(CONFIG_MPC8240)
|
||||
CONFIG_WRITE_WORD( PICR1,
|
||||
(val & (PICR1_ADDRESS_MAP | PICR1_RCS0)) |
|
||||
PIRC1_MSK | PICR1_PROC_TYPE_603E |
|
||||
PICR1_FLASH_WR_EN | PICR1_MCP_EN |
|
||||
PICR1_CF_DPARK | PICR1_EN_PCS |
|
||||
PICR1_CF_APARK );
|
||||
#elif defined(CONFIG_MPC8245)
|
||||
CONFIG_WRITE_WORD( PICR1,
|
||||
(val & (PICR1_RCS0)) |
|
||||
PICR1_PROC_TYPE_603E |
|
||||
PICR1_FLASH_WR_EN | PICR1_MCP_EN |
|
||||
PICR1_CF_DPARK | PICR1_NO_BUSW_CK |
|
||||
PICR1_DEC| PICR1_CF_APARK | 0x10); /* 8245 UM says bit 4 must be set */
|
||||
#else
|
||||
#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
|
||||
#endif
|
||||
|
||||
CONFIG_READ_WORD(PICR2, val);
|
||||
val= val & ~ (PICR2_CF_SNOOP_WS_MASK | PICR2_CF_APHASE_WS_MASK); /*mask off waitstate bits*/
|
||||
#ifndef CONFIG_PN62
|
||||
val |= PICR2_CF_SNOOP_WS_1WS | PICR2_CF_APHASE_WS_1WS; /*1 wait state*/
|
||||
#endif
|
||||
CONFIG_WRITE_WORD(PICR2, val);
|
||||
|
||||
CONFIG_WRITE_WORD(EUMBBAR, CFG_EUMB_ADDR);
|
||||
#ifndef CFG_RAMBOOT
|
||||
CONFIG_WRITE_WORD(MCCR1, (CFG_ROMNAL << MCCR1_ROMNAL_SHIFT) |
|
||||
(CFG_BANK0_ROW) |
|
||||
(CFG_BANK1_ROW << MCCR1_BANK1ROW_SHIFT) |
|
||||
(CFG_BANK2_ROW << MCCR1_BANK2ROW_SHIFT) |
|
||||
(CFG_BANK3_ROW << MCCR1_BANK3ROW_SHIFT) |
|
||||
(CFG_BANK4_ROW << MCCR1_BANK4ROW_SHIFT) |
|
||||
(CFG_BANK5_ROW << MCCR1_BANK5ROW_SHIFT) |
|
||||
(CFG_BANK6_ROW << MCCR1_BANK6ROW_SHIFT) |
|
||||
(CFG_BANK7_ROW << MCCR1_BANK7ROW_SHIFT) |
|
||||
(CFG_ROMFAL << MCCR1_ROMFAL_SHIFT));
|
||||
#endif
|
||||
|
||||
#if defined(CFG_ASRISE) && defined(CFG_ASFALL)
|
||||
CONFIG_WRITE_WORD(MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT |
|
||||
CFG_ASRISE << MCCR2_ASRISE_SHIFT |
|
||||
CFG_ASFALL << MCCR2_ASFALL_SHIFT);
|
||||
#else
|
||||
CONFIG_WRITE_WORD(MCCR2, CFG_REFINT << MCCR2_REFINT_SHIFT);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MPC8240)
|
||||
CONFIG_WRITE_WORD(MCCR3,
|
||||
(((CFG_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
|
||||
(CFG_REFREC << MCCR3_REFREC_SHIFT) |
|
||||
(CFG_RDLAT << MCCR3_RDLAT_SHIFT));
|
||||
#elif defined(CONFIG_MPC8245)
|
||||
CONFIG_WRITE_WORD(MCCR3,
|
||||
(((CFG_BSTOPRE & 0x003c) >> 2) << MCCR3_BSTOPRE2TO5_SHIFT) |
|
||||
(CFG_REFREC << MCCR3_REFREC_SHIFT));
|
||||
#else
|
||||
#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
|
||||
#endif
|
||||
|
||||
/* this is gross. We think these should all be the same, and various boards
|
||||
* should define CFG_ACTORW to 0 if they don't want to set it, or even, if
|
||||
* its not set, we define it to zero in this file
|
||||
*/
|
||||
#if defined(CONFIG_CU824) || defined(CONFIG_PN62)
|
||||
CONFIG_WRITE_WORD(MCCR4,
|
||||
(CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
|
||||
(CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
|
||||
MCCR4_BIT21 |
|
||||
(CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
|
||||
((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
|
||||
(((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
|
||||
CFG_SDMODE_BURSTLEN) << MCCR4_SDMODE_SHIFT) |
|
||||
(CFG_ACTORW << MCCR4_ACTTORW_SHIFT) |
|
||||
(((CFG_BSTOPRE & 0x03c0) >> 6) << MCCR4_BSTOPRE6TO9_SHIFT));
|
||||
#elif defined(CONFIG_MPC8240)
|
||||
CONFIG_WRITE_WORD(MCCR4,
|
||||
(CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
|
||||
(CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
|
||||
MCCR4_BIT21 |
|
||||
(CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
|
||||
((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
|
||||
(((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
|
||||
(CFG_SDMODE_BURSTLEN)) <<MCCR4_SDMODE_SHIFT) |
|
||||
(((CFG_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
|
||||
#elif defined(CONFIG_MPC8245)
|
||||
CONFIG_READ_WORD(MCCR1, val);
|
||||
val &= MCCR1_DBUS_SIZE0; /* test for 64-bit mem bus */
|
||||
|
||||
CONFIG_WRITE_WORD(MCCR4,
|
||||
(CFG_PRETOACT << MCCR4_PRETOACT_SHIFT) |
|
||||
(CFG_ACTTOPRE << MCCR4_ACTTOPRE_SHIFT) |
|
||||
(CFG_EXTROM ? MCCR4_EXTROM : 0) |
|
||||
(CFG_REGDIMM ? MCCR4_REGDIMM : 0) |
|
||||
(CFG_REGISTERD_TYPE_BUFFER ? MCCR4_REGISTERED: 0) |
|
||||
((CFG_BSTOPRE & 0x0003) <<MCCR4_BSTOPRE0TO1_SHIFT ) |
|
||||
(CFG_DBUS_SIZE2 << MCCR4_DBUS_SIZE2_SHIFT) |
|
||||
(((CFG_SDMODE_CAS_LAT <<4) | (CFG_SDMODE_WRAP <<3) |
|
||||
(val ? 2 : 3)) << MCCR4_SDMODE_SHIFT) |
|
||||
(CFG_ACTORW << MCCR4_ACTTORW_SHIFT) |
|
||||
(((CFG_BSTOPRE & 0x03c0) >> 6) <<MCCR4_BSTOPRE6TO9_SHIFT ));
|
||||
#else
|
||||
#error Specific type of MPC824x must be defined (i.e. CONFIG_MPC8240)
|
||||
#endif
|
||||
|
||||
CONFIG_WRITE_WORD(MSAR1,
|
||||
( (CFG_BANK0_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
|
||||
(((CFG_BANK1_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK2_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK3_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
|
||||
CONFIG_WRITE_WORD(EMSAR1,
|
||||
( (CFG_BANK0_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
|
||||
(((CFG_BANK1_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK2_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK3_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
|
||||
CONFIG_WRITE_WORD(MSAR2,
|
||||
( (CFG_BANK4_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
|
||||
(((CFG_BANK5_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK6_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK7_START & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
|
||||
CONFIG_WRITE_WORD(EMSAR2,
|
||||
( (CFG_BANK4_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
|
||||
(((CFG_BANK5_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK6_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK7_START & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
|
||||
CONFIG_WRITE_WORD(MEAR1,
|
||||
( (CFG_BANK0_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
|
||||
(((CFG_BANK1_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK2_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK3_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
|
||||
CONFIG_WRITE_WORD(EMEAR1,
|
||||
( (CFG_BANK0_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
|
||||
(((CFG_BANK1_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK2_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK3_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
|
||||
CONFIG_WRITE_WORD(MEAR2,
|
||||
( (CFG_BANK4_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) |
|
||||
(((CFG_BANK5_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK6_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK7_END & MICR_ADDR_MASK) >> MICR_ADDR_SHIFT) << 24));
|
||||
CONFIG_WRITE_WORD(EMEAR2,
|
||||
( (CFG_BANK4_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) |
|
||||
(((CFG_BANK5_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 8) |
|
||||
(((CFG_BANK6_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 16) |
|
||||
(((CFG_BANK7_END & MICR_EADDR_MASK) >> MICR_EADDR_SHIFT) << 24));
|
||||
|
||||
CONFIG_WRITE_BYTE(ODCR, CFG_ODCR);
|
||||
#ifdef CFG_DLL_MAX_DELAY
|
||||
CONFIG_WRITE_BYTE(MIOCR1, CFG_DLL_MAX_DELAY); /* needed to make DLL lock */
|
||||
#endif
|
||||
#if defined(CFG_DLL_EXTEND) && defined(CFG_PCI_HOLD_DEL)
|
||||
CONFIG_WRITE_BYTE(PMCR2, CFG_DLL_EXTEND | CFG_PCI_HOLD_DEL);
|
||||
#endif
|
||||
#if defined(MIOCR2) && defined(CFG_SDRAM_DSCD)
|
||||
CONFIG_WRITE_BYTE(MIOCR2, CFG_SDRAM_DSCD); /* change memory input */
|
||||
#endif /* setup & hold time */
|
||||
|
||||
CONFIG_WRITE_BYTE(MBER,
|
||||
CFG_BANK0_ENABLE |
|
||||
(CFG_BANK1_ENABLE << 1) |
|
||||
(CFG_BANK2_ENABLE << 2) |
|
||||
(CFG_BANK3_ENABLE << 3) |
|
||||
(CFG_BANK4_ENABLE << 4) |
|
||||
(CFG_BANK5_ENABLE << 5) |
|
||||
(CFG_BANK6_ENABLE << 6) |
|
||||
(CFG_BANK7_ENABLE << 7));
|
||||
|
||||
#ifdef CFG_PGMAX
|
||||
CONFIG_WRITE_BYTE(MPMR, CFG_PGMAX);
|
||||
#endif
|
||||
|
||||
/* ! Wait 200us before initialize other registers */
|
||||
/*FIXME: write a decent udelay wait */
|
||||
__asm__ __volatile__(
|
||||
" mtctr %0 \n \
|
||||
0: bdnz 0b\n"
|
||||
:
|
||||
: "r" (0x10000));
|
||||
|
||||
CONFIG_READ_WORD(MCCR1, val);
|
||||
CONFIG_WRITE_WORD(MCCR1, val | MCCR1_MEMGO); /* set memory access going */
|
||||
__asm__ __volatile__("eieio");
|
||||
|
||||
#endif /* !CONFIG_MOUSSE && !CONFIG_BMW */
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_MOUSSE
|
||||
#ifdef INCLUDE_MPC107_REPORT
|
||||
struct MPC107_s{
|
||||
unsigned int iobase;
|
||||
char desc[120];
|
||||
} MPC107Regs[] ={
|
||||
{BMC_BASE+0x0, "MPC107 Vendor/Device ID"},
|
||||
{BMC_BASE+0x4, "MPC107 PCI Command/Status Register"},
|
||||
{BMC_BASE+0x8, "MPC107 Revision"},
|
||||
{BMC_BASE+0xC, "MPC107 Cache Line Size"},
|
||||
{BMC_BASE+0x10, "MPC107 LMBAR"},
|
||||
{BMC_BASE+0x14, "MPC824x PCSR"},
|
||||
{BMC_BASE+0xA8, "MPC824x PICR1"},
|
||||
{BMC_BASE+0xAC, "MPC824x PICR2"},
|
||||
{BMC_BASE+0x46, "MPC824x PACR"},
|
||||
{BMC_BASE+0x310, "MPC824x ITWR"},
|
||||
{BMC_BASE+0x300, "MPC824x OMBAR"},
|
||||
{BMC_BASE+0x308, "MPC824x OTWR"},
|
||||
{BMC_BASE+0x14, "MPC107 Peripheral Control and Status Register"},
|
||||
{BMC_BASE+0x78, "MPC107 EUMBAR"},
|
||||
{BMC_BASE+0xC0, "MPC107 Processor Bus Error Status"},
|
||||
{BMC_BASE+0xC4, "MPC107 PCI Bus Error Status"},
|
||||
{BMC_BASE+0xC8, "MPC107 Processor/PCI Error Address"},
|
||||
{BMC_BASE+0xE0, "MPC107 AMBOR Register"},
|
||||
{BMC_BASE+0xF0, "MPC107 MCCR1 Register"},
|
||||
{BMC_BASE+0xF4, "MPC107 MCCR2 Register"},
|
||||
{BMC_BASE+0xF8, "MPC107 MCCR3 Register"},
|
||||
{BMC_BASE+0xFC, "MPC107 MCCR4 Register"}
|
||||
};
|
||||
#define N_MPC107_Regs (sizeof(MPC107Regs)/sizeof(MPC107Regs[0]))
|
||||
#endif /* INCLUDE_MPC107_REPORT */
|
||||
#endif /* CONFIG_MOUSSE */
|
||||
|
||||
/*
|
||||
* initialize higher level parts of CPU like time base and timers
|
||||
*/
|
||||
int cpu_init_r (void)
|
||||
{
|
||||
#ifdef CONFIG_MOUSSE
|
||||
#ifdef INCLUDE_MPC107_REPORT
|
||||
unsigned int tmp = 0, i;
|
||||
#endif
|
||||
/*
|
||||
* Initialize the EUMBBAR (Embedded Util Mem Block Base Addr Reg).
|
||||
* This is necessary before the EPIC, DMA ctlr, I2C ctlr, etc. can
|
||||
* be accessed.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_MPC8240 /* only on MPC8240 */
|
||||
mpc824x_mpc107_setreg (EUMBBAR, EUMBBAR_VAL);
|
||||
/* MOT/SPS: Issue #10002, PCI (FD Alias enable) */
|
||||
mpc824x_mpc107_setreg (AMBOR, 0x000000C0);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INCLUDE_MPC107_REPORT
|
||||
/* Check MPC824x PCI Device and Vendor ID */
|
||||
while ((tmp = mpc824x_mpc107_getreg (BMC_BASE)) != 0x31057) {
|
||||
printf (" MPC107: offset=0x%x, val = 0x%x\n",
|
||||
BMC_BASE,
|
||||
tmp);
|
||||
}
|
||||
|
||||
for (i = 0; i < N_MPC107_Regs; i++) {
|
||||
printf (" 0x%x/%s = 0x%x\n",
|
||||
MPC107Regs[i].iobase,
|
||||
MPC107Regs[i].desc,
|
||||
mpc824x_mpc107_getreg (MPC107Regs[i].iobase));
|
||||
}
|
||||
|
||||
printf ("IBAT0L = 0x%08X\n", mfspr (IBAT0L));
|
||||
printf ("IBAT0U = 0x%08X\n", mfspr (IBAT0U));
|
||||
printf ("IBAT1L = 0x%08X\n", mfspr (IBAT1L));
|
||||
printf ("IBAT1U = 0x%08X\n", mfspr (IBAT1U));
|
||||
printf ("IBAT2L = 0x%08X\n", mfspr (IBAT2L));
|
||||
printf ("IBAT2U = 0x%08X\n", mfspr (IBAT2U));
|
||||
printf ("IBAT3L = 0x%08X\n", mfspr (IBAT3L));
|
||||
printf ("IBAT3U = 0x%08X\n", mfspr (IBAT3U));
|
||||
printf ("DBAT0L = 0x%08X\n", mfspr (DBAT0L));
|
||||
printf ("DBAT0U = 0x%08X\n", mfspr (DBAT0U));
|
||||
printf ("DBAT1L = 0x%08X\n", mfspr (DBAT1L));
|
||||
printf ("DBAT1U = 0x%08X\n", mfspr (DBAT1U));
|
||||
printf ("DBAT2L = 0x%08X\n", mfspr (DBAT2L));
|
||||
printf ("DBAT2U = 0x%08X\n", mfspr (DBAT2U));
|
||||
printf ("DBAT3L = 0x%08X\n", mfspr (DBAT3L));
|
||||
printf ("DBAT3U = 0x%08X\n", mfspr (DBAT3U));
|
||||
#endif /* INCLUDE_MPC107_REPORT */
|
||||
#endif /* CONFIG_MOUSSE */
|
||||
return (0);
|
||||
}
|
||||
1228
cpu/mpc824x/drivers/i2c/i2c1.c
Normal file
1228
cpu/mpc824x/drivers/i2c/i2c1.c
Normal file
File diff suppressed because it is too large
Load Diff
78
cpu/mpc824x/pci.c
Normal file
78
cpu/mpc824x/pci.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* arch/ppc/kernel/mpc10x_common.c
|
||||
*
|
||||
* Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
|
||||
* Mem ctlr, EPIC, etc.
|
||||
*
|
||||
* Author: Mark A. Greer
|
||||
* mgreer@mvista.com
|
||||
*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/io.h>
|
||||
#include <pci.h>
|
||||
#include <mpc824x.h>
|
||||
|
||||
void pci_mpc824x_init (struct pci_controller *hose)
|
||||
{
|
||||
hose->first_busno = 0;
|
||||
hose->last_busno = 0xff;
|
||||
|
||||
/* System memory space */
|
||||
pci_set_region(hose->regions + 0,
|
||||
CHRP_PCI_MEMORY_BUS,
|
||||
CHRP_PCI_MEMORY_PHYS,
|
||||
CHRP_PCI_MEMORY_SIZE,
|
||||
PCI_REGION_MEM | PCI_REGION_MEMORY);
|
||||
|
||||
/* PCI memory space */
|
||||
pci_set_region(hose->regions + 1,
|
||||
CHRP_PCI_MEM_BUS,
|
||||
CHRP_PCI_MEM_PHYS,
|
||||
CHRP_PCI_MEM_SIZE,
|
||||
PCI_REGION_MEM);
|
||||
|
||||
/* ISA/PCI memory space */
|
||||
pci_set_region(hose->regions + 2,
|
||||
CHRP_ISA_MEM_BUS,
|
||||
CHRP_ISA_MEM_PHYS,
|
||||
CHRP_ISA_MEM_SIZE,
|
||||
PCI_REGION_MEM);
|
||||
|
||||
/* PCI I/O space */
|
||||
pci_set_region(hose->regions + 3,
|
||||
CHRP_PCI_IO_BUS,
|
||||
CHRP_PCI_IO_PHYS,
|
||||
CHRP_PCI_IO_SIZE,
|
||||
PCI_REGION_IO);
|
||||
|
||||
/* ISA/PCI I/O space */
|
||||
pci_set_region(hose->regions + 4,
|
||||
CHRP_ISA_IO_BUS,
|
||||
CHRP_ISA_IO_PHYS,
|
||||
CHRP_ISA_IO_SIZE,
|
||||
PCI_REGION_IO);
|
||||
|
||||
hose->region_count = 5;
|
||||
|
||||
pci_setup_indirect(hose,
|
||||
CHRP_REG_ADDR,
|
||||
CHRP_REG_DATA);
|
||||
|
||||
pci_register_hose(hose);
|
||||
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
}
|
||||
|
||||
#endif
|
||||
835
cpu/mpc824x/start.S
Normal file
835
cpu/mpc824x/start.S
Normal file
@@ -0,0 +1,835 @@
|
||||
/*
|
||||
* Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
|
||||
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
|
||||
* Copyright (C) 2000,2001,2002 Wolfgang Denk <wd@denx.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* U-Boot - Startup Code for PowerPC based Embedded Boards
|
||||
*
|
||||
*
|
||||
* The processor starts at 0x00000100 and the code is executed
|
||||
* from flash. The code is organized to be at an other address
|
||||
* in memory, but as long we don't jump around before relocating.
|
||||
* board_init lies at a quite high address and when the cpu has
|
||||
* jumped there, everything is ok.
|
||||
* This works because the cpu gives the FLASH (CS0) the whole
|
||||
* address space at startup, and board_init lies as a echo of
|
||||
* the flash somewhere up there in the memorymap.
|
||||
*
|
||||
* board_init will change CS0 to be positioned at the correct
|
||||
* address and (s)dram will be positioned at address 0
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <mpc824x.h>
|
||||
#include <version.h>
|
||||
|
||||
#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */
|
||||
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <ppc_defs.h>
|
||||
|
||||
#include <asm/cache.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
#ifndef CONFIG_IDENT_STRING
|
||||
#define CONFIG_IDENT_STRING ""
|
||||
#endif
|
||||
|
||||
/* We don't want the MMU yet.
|
||||
*/
|
||||
#undef MSR_KERNEL
|
||||
/* FP, Machine Check and Recoverable Interr. */
|
||||
#define MSR_KERNEL ( MSR_FP | MSR_ME | MSR_RI )
|
||||
|
||||
/*
|
||||
* Set up GOT: Global Offset Table
|
||||
*
|
||||
* Use r14 to access the GOT
|
||||
*/
|
||||
START_GOT
|
||||
GOT_ENTRY(_GOT2_TABLE_)
|
||||
GOT_ENTRY(_FIXUP_TABLE_)
|
||||
|
||||
GOT_ENTRY(_start)
|
||||
GOT_ENTRY(_start_of_vectors)
|
||||
GOT_ENTRY(_end_of_vectors)
|
||||
GOT_ENTRY(transfer_to_handler)
|
||||
|
||||
GOT_ENTRY(_end)
|
||||
GOT_ENTRY(.bss)
|
||||
#if defined(CONFIG_FADS)
|
||||
GOT_ENTRY(environment)
|
||||
#endif
|
||||
END_GOT
|
||||
|
||||
/*
|
||||
* r3 - 1st arg to board_init(): IMMP pointer
|
||||
* r4 - 2nd arg to board_init(): boot flag
|
||||
*/
|
||||
.text
|
||||
.long 0x27051956 /* U-Boot Magic Number */
|
||||
.globl version_string
|
||||
version_string:
|
||||
.ascii U_BOOT_VERSION
|
||||
.ascii " (", __DATE__, " - ", __TIME__, ")"
|
||||
.ascii CONFIG_IDENT_STRING, "\0"
|
||||
|
||||
. = EXC_OFF_SYS_RESET
|
||||
.globl _start
|
||||
_start:
|
||||
li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH */
|
||||
b boot_cold
|
||||
|
||||
. = EXC_OFF_SYS_RESET + 0x10
|
||||
|
||||
.globl _start_warm
|
||||
_start_warm:
|
||||
li r21, BOOTFLAG_WARM /* Software reboot */
|
||||
b boot_warm
|
||||
|
||||
boot_cold:
|
||||
boot_warm:
|
||||
|
||||
/* Initialize machine status; enable machine check interrupt */
|
||||
/*----------------------------------------------------------------------*/
|
||||
li r3, MSR_KERNEL /* Set FP, ME, RI flags */
|
||||
mtmsr r3
|
||||
mtspr SRR1, r3 /* Make SRR1 match MSR */
|
||||
|
||||
addis r0,0,0x0000 /* lets make sure that r0 is really 0 */
|
||||
mtspr HID0, r0 /* disable I and D caches */
|
||||
|
||||
mfspr r3, ICR /* clear Interrupt Cause Register */
|
||||
|
||||
mfmsr r3 /* turn off address translation */
|
||||
addis r4,0,0xffff
|
||||
ori r4,r4,0xffcf
|
||||
and r3,r3,r4
|
||||
mtmsr r3
|
||||
isync
|
||||
sync /* the MMU should be off... */
|
||||
|
||||
|
||||
in_flash:
|
||||
#if defined(CONFIG_BMW)
|
||||
bl early_init_f /* Must be ASM: no stack yet! */
|
||||
#endif
|
||||
/*
|
||||
* Setup BATs - cannot be done in C since we don't have a stack yet
|
||||
*/
|
||||
bl setup_bats
|
||||
|
||||
/* Enable MMU.
|
||||
*/
|
||||
mfmsr r3
|
||||
ori r3, r3, (MSR_IR | MSR_DR)
|
||||
mtmsr r3
|
||||
#if !defined(CONFIG_BMW)
|
||||
/* Enable and invalidate data cache.
|
||||
*/
|
||||
mfspr r3, HID0
|
||||
mr r2, r3
|
||||
ori r3, r3, HID0_DCE | HID0_DCI
|
||||
ori r2, r2, HID0_DCE
|
||||
sync
|
||||
mtspr HID0, r3
|
||||
mtspr HID0, r2
|
||||
sync
|
||||
|
||||
/* Allocate Initial RAM in data cache.
|
||||
*/
|
||||
lis r3, CFG_INIT_RAM_ADDR@h
|
||||
ori r3, r3, CFG_INIT_RAM_ADDR@l
|
||||
li r2, 128
|
||||
mtctr r2
|
||||
1:
|
||||
dcbz r0, r3
|
||||
addi r3, r3, 32
|
||||
bdnz 1b
|
||||
|
||||
/* Lock way0 in data cache.
|
||||
*/
|
||||
mfspr r3, 1011
|
||||
lis r2, 0xffff
|
||||
ori r2, r2, 0xff1f
|
||||
and r3, r3, r2
|
||||
ori r3, r3, 0x0080
|
||||
sync
|
||||
mtspr 1011, r3
|
||||
#endif /* !CONFIG_BMW */
|
||||
/*
|
||||
* Thisk the stack pointer *somewhere* sensible. Doesnt
|
||||
* matter much where as we'll move it when we relocate
|
||||
*/
|
||||
lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h
|
||||
ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l
|
||||
|
||||
li r0, 0 /* Make room for stack frame header and */
|
||||
stwu r0, -4(r1) /* clear final stack frame so that */
|
||||
stwu r0, -4(r1) /* stack backtraces terminate cleanly */
|
||||
|
||||
/* let the C-code set up the rest */
|
||||
/* */
|
||||
/* Be careful to keep code relocatable ! */
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
GET_GOT /* initialize GOT access */
|
||||
|
||||
/* r3: IMMR */
|
||||
bl cpu_init_f /* run low-level CPU init code (from Flash) */
|
||||
|
||||
mr r3, r21
|
||||
/* r3: BOOTFLAG */
|
||||
bl board_init_f /* run 1st part of board init code (from Flash) */
|
||||
|
||||
|
||||
|
||||
.globl _start_of_vectors
|
||||
_start_of_vectors:
|
||||
|
||||
/* Machine check */
|
||||
STD_EXCEPTION(EXC_OFF_MACH_CHCK, MachineCheck, MachineCheckException)
|
||||
|
||||
/* Data Storage exception. "Never" generated on the 860. */
|
||||
STD_EXCEPTION(EXC_OFF_DATA_STOR, DataStorage, UnknownException)
|
||||
|
||||
/* Instruction Storage exception. "Never" generated on the 860. */
|
||||
STD_EXCEPTION(EXC_OFF_INS_STOR, InstStorage, UnknownException)
|
||||
|
||||
/* External Interrupt exception. */
|
||||
STD_EXCEPTION(EXC_OFF_EXTERNAL, ExtInterrupt, external_interrupt)
|
||||
|
||||
/* Alignment exception. */
|
||||
. = EXC_OFF_ALIGN
|
||||
Alignment:
|
||||
EXCEPTION_PROLOG
|
||||
mfspr r4,DAR
|
||||
stw r4,_DAR(r21)
|
||||
mfspr r5,DSISR
|
||||
stw r5,_DSISR(r21)
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
li r20,MSR_KERNEL
|
||||
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
|
||||
lwz r6,GOT(transfer_to_handler)
|
||||
mtlr r6
|
||||
blrl
|
||||
.L_Alignment:
|
||||
.long AlignmentException - _start + EXC_OFF_SYS_RESET
|
||||
.long int_return - _start + EXC_OFF_SYS_RESET
|
||||
|
||||
/* Program check exception */
|
||||
. = EXC_OFF_PROGRAM
|
||||
ProgramCheck:
|
||||
EXCEPTION_PROLOG
|
||||
addi r3,r1,STACK_FRAME_OVERHEAD
|
||||
li r20,MSR_KERNEL
|
||||
rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
|
||||
lwz r6,GOT(transfer_to_handler)
|
||||
mtlr r6
|
||||
blrl
|
||||
.L_ProgramCheck:
|
||||
.long ProgramCheckException - _start + EXC_OFF_SYS_RESET
|
||||
.long int_return - _start + EXC_OFF_SYS_RESET
|
||||
|
||||
/* No FPU on MPC8xx. This exception is not supposed to happen.
|
||||
*/
|
||||
STD_EXCEPTION(EXC_OFF_FPUNAVAIL, FPUnavailable, UnknownException)
|
||||
|
||||
/* I guess we could implement decrementer, and may have
|
||||
* to someday for timekeeping.
|
||||
*/
|
||||
STD_EXCEPTION(EXC_OFF_DECR, Decrementer, timer_interrupt)
|
||||
STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
|
||||
STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
|
||||
|
||||
. = 0xc00
|
||||
/*
|
||||
* r0 - SYSCALL number
|
||||
* r3-... arguments
|
||||
*/
|
||||
SystemCall:
|
||||
addis r11,r0,0 /* get functions table addr */
|
||||
ori r11,r11,0 /* Note: this code is patched in trap_init */
|
||||
addis r12,r0,0 /* get number of functions */
|
||||
ori r12,r12,0
|
||||
|
||||
cmplw 0, r0, r12
|
||||
bge 1f
|
||||
|
||||
rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */
|
||||
add r11,r11,r0
|
||||
lwz r11,0(r11)
|
||||
|
||||
li r12,0xd00-4*3 /* save LR & SRRx */
|
||||
mflr r0
|
||||
stw r0,0(r12)
|
||||
mfspr r0,SRR0
|
||||
stw r0,4(r12)
|
||||
mfspr r0,SRR1
|
||||
stw r0,8(r12)
|
||||
|
||||
li r12,0xc00+_back-SystemCall
|
||||
mtlr r12
|
||||
mtspr SRR0,r11
|
||||
|
||||
1: SYNC
|
||||
rfi
|
||||
|
||||
_back:
|
||||
|
||||
mfmsr r11 /* Disable interrupts */
|
||||
li r12,0
|
||||
ori r12,r12,MSR_EE
|
||||
andc r11,r11,r12
|
||||
SYNC /* Some chip revs need this... */
|
||||
mtmsr r11
|
||||
SYNC
|
||||
|
||||
li r12,0xd00-4*3 /* restore regs */
|
||||
lwz r11,0(r12)
|
||||
mtlr r11
|
||||
lwz r11,4(r12)
|
||||
mtspr SRR0,r11
|
||||
lwz r11,8(r12)
|
||||
mtspr SRR1,r11
|
||||
|
||||
SYNC
|
||||
rfi
|
||||
|
||||
STD_EXCEPTION(EXC_OFF_TRACE, SingleStep, UnknownException)
|
||||
|
||||
STD_EXCEPTION(EXC_OFF_FPUNASSIST, Trap_0e, UnknownException)
|
||||
STD_EXCEPTION(EXC_OFF_PMI, Trap_0f, UnknownException)
|
||||
|
||||
STD_EXCEPTION(EXC_OFF_ITME, InstructionTransMiss, UnknownException)
|
||||
STD_EXCEPTION(EXC_OFF_DLTME, DataLoadTransMiss, UnknownException)
|
||||
STD_EXCEPTION(EXC_OFF_DSTME, DataStoreTransMiss, UnknownException)
|
||||
STD_EXCEPTION(EXC_OFF_IABE, InstructionBreakpoint, UnknownException)
|
||||
STD_EXCEPTION(EXC_OFF_SMIE, SysManageInt, UnknownException)
|
||||
STD_EXCEPTION(0x1500, Reserved5, UnknownException)
|
||||
STD_EXCEPTION(0x1600, Reserved6, UnknownException)
|
||||
STD_EXCEPTION(0x1700, Reserved7, UnknownException)
|
||||
STD_EXCEPTION(0x1800, Reserved8, UnknownException)
|
||||
STD_EXCEPTION(0x1900, Reserved9, UnknownException)
|
||||
STD_EXCEPTION(0x1a00, ReservedA, UnknownException)
|
||||
STD_EXCEPTION(0x1b00, ReservedB, UnknownException)
|
||||
STD_EXCEPTION(0x1c00, ReservedC, UnknownException)
|
||||
STD_EXCEPTION(0x1d00, ReservedD, UnknownException)
|
||||
STD_EXCEPTION(0x1e00, ReservedE, UnknownException)
|
||||
STD_EXCEPTION(0x1f00, ReservedF, UnknownException)
|
||||
|
||||
STD_EXCEPTION(EXC_OFF_RMTE, RunModeTrace, UnknownException)
|
||||
|
||||
.globl _end_of_vectors
|
||||
_end_of_vectors:
|
||||
|
||||
|
||||
. = 0x3000
|
||||
|
||||
/*
|
||||
* This code finishes saving the registers to the exception frame
|
||||
* and jumps to the appropriate handler for the exception.
|
||||
* Register r21 is pointer into trap frame, r1 has new stack pointer.
|
||||
*/
|
||||
.globl transfer_to_handler
|
||||
transfer_to_handler:
|
||||
stw r22,_NIP(r21)
|
||||
lis r22,MSR_POW@h
|
||||
andc r23,r23,r22
|
||||
stw r23,_MSR(r21)
|
||||
SAVE_GPR(7, r21)
|
||||
SAVE_4GPRS(8, r21)
|
||||
SAVE_8GPRS(12, r21)
|
||||
SAVE_8GPRS(24, r21)
|
||||
#if 0
|
||||
andi. r23,r23,MSR_PR
|
||||
mfspr r23,SPRG3 /* if from user, fix up tss.regs */
|
||||
beq 2f
|
||||
addi r24,r1,STACK_FRAME_OVERHEAD
|
||||
stw r24,PT_REGS(r23)
|
||||
2: addi r2,r23,-TSS /* set r2 to current */
|
||||
tovirt(r2,r2,r23)
|
||||
#endif
|
||||
mflr r23
|
||||
andi. r24,r23,0x3f00 /* get vector offset */
|
||||
stw r24,TRAP(r21)
|
||||
li r22,0
|
||||
stw r22,RESULT(r21)
|
||||
mtspr SPRG2,r22 /* r1 is now kernel sp */
|
||||
#if 0
|
||||
addi r24,r2,TASK_STRUCT_SIZE /* check for kernel stack overflow */
|
||||
cmplw 0,r1,r2
|
||||
cmplw 1,r1,r24
|
||||
crand 1,1,4
|
||||
bgt stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */
|
||||
#endif
|
||||
lwz r24,0(r23) /* virtual address of handler */
|
||||
lwz r23,4(r23) /* where to go when done */
|
||||
mtspr SRR0,r24
|
||||
ori r20,r20,0x30 /* enable IR, DR */
|
||||
mtspr SRR1,r20
|
||||
mtlr r23
|
||||
SYNC
|
||||
rfi /* jump to handler, enable MMU */
|
||||
|
||||
int_return:
|
||||
mfmsr r28 /* Disable interrupts */
|
||||
li r4,0
|
||||
ori r4,r4,MSR_EE
|
||||
andc r28,r28,r4
|
||||
SYNC /* Some chip revs need this... */
|
||||
mtmsr r28
|
||||
SYNC
|
||||
lwz r2,_CTR(r1)
|
||||
lwz r0,_LINK(r1)
|
||||
mtctr r2
|
||||
mtlr r0
|
||||
lwz r2,_XER(r1)
|
||||
lwz r0,_CCR(r1)
|
||||
mtspr XER,r2
|
||||
mtcrf 0xFF,r0
|
||||
REST_10GPRS(3, r1)
|
||||
REST_10GPRS(13, r1)
|
||||
REST_8GPRS(23, r1)
|
||||
REST_GPR(31, r1)
|
||||
lwz r2,_NIP(r1) /* Restore environment */
|
||||
lwz r0,_MSR(r1)
|
||||
mtspr SRR0,r2
|
||||
mtspr SRR1,r0
|
||||
lwz r0,GPR0(r1)
|
||||
lwz r2,GPR2(r1)
|
||||
lwz r1,GPR1(r1)
|
||||
SYNC
|
||||
rfi
|
||||
|
||||
/* Cache functions.
|
||||
*/
|
||||
.globl icache_enable
|
||||
icache_enable:
|
||||
mfspr r5,HID0 /* turn on the I cache. */
|
||||
ori r5,r5,0x8800 /* Instruction cache only! */
|
||||
addis r6,0,0xFFFF
|
||||
ori r6,r6,0xF7FF
|
||||
and r6,r5,r6 /* clear the invalidate bit */
|
||||
sync
|
||||
mtspr HID0,r5
|
||||
mtspr HID0,r6
|
||||
isync
|
||||
sync
|
||||
blr
|
||||
|
||||
.globl icache_disable
|
||||
icache_disable:
|
||||
mfspr r5,HID0
|
||||
addis r6,0,0xFFFF
|
||||
ori r6,r6,0x7FFF
|
||||
and r5,r5,r6
|
||||
sync
|
||||
mtspr HID0,r5
|
||||
isync
|
||||
sync
|
||||
blr
|
||||
|
||||
.globl icache_status
|
||||
icache_status:
|
||||
mfspr r3, HID0
|
||||
srwi r3, r3, 15 /* >>15 & 1=> select bit 16 */
|
||||
andi. r3, r3, 1
|
||||
blr
|
||||
|
||||
.globl dcache_enable
|
||||
dcache_enable:
|
||||
mfspr r5,HID0 /* turn on the D cache. */
|
||||
ori r5,r5,0x4400 /* Data cache only! */
|
||||
mfspr r4, PVR /* read PVR */
|
||||
srawi r3, r4, 16 /* shift off the least 16 bits */
|
||||
cmpi 0, 0, r3, 0xC /* Check for Max pvr */
|
||||
bne NotMax
|
||||
ori r5,r5,0x0040 /* setting the DCFA bit, for Max rev 1 errata */
|
||||
NotMax:
|
||||
addis r6,0,0xFFFF
|
||||
ori r6,r6,0xFBFF
|
||||
and r6,r5,r6 /* clear the invalidate bit */
|
||||
sync
|
||||
mtspr HID0,r5
|
||||
mtspr HID0,r6
|
||||
isync
|
||||
sync
|
||||
blr
|
||||
|
||||
.globl dcache_disable
|
||||
dcache_disable:
|
||||
mfspr r5,HID0
|
||||
addis r6,0,0xFFFF
|
||||
ori r6,r6,0xBFFF
|
||||
and r5,r5,r6
|
||||
sync
|
||||
mtspr HID0,r5
|
||||
isync
|
||||
sync
|
||||
blr
|
||||
|
||||
.globl dcache_status
|
||||
dcache_status:
|
||||
mfspr r3, HID0
|
||||
srwi r3, r3, 14 /* >>14 & 1=> select bit 17 */
|
||||
andi. r3, r3, 1
|
||||
blr
|
||||
|
||||
.globl dc_read
|
||||
dc_read:
|
||||
/*TODO : who uses this, what should it do?
|
||||
*/
|
||||
blr
|
||||
|
||||
|
||||
.globl get_pvr
|
||||
get_pvr:
|
||||
mfspr r3, PVR
|
||||
blr
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* void relocate_code (addr_sp, gd, addr_moni)
|
||||
*
|
||||
* This "function" does not return, instead it continues in RAM
|
||||
* after relocating the monitor code.
|
||||
*
|
||||
* r3 = dest
|
||||
* r4 = src
|
||||
* r5 = length in bytes
|
||||
* r6 = cachelinesize
|
||||
*/
|
||||
.globl relocate_code
|
||||
relocate_code:
|
||||
|
||||
mr r1, r3 /* Set new stack pointer */
|
||||
mr r9, r4 /* Save copy of Global Data pointer */
|
||||
mr r10, r5 /* Save copy of Destination Address */
|
||||
|
||||
mr r3, r5 /* Destination Address */
|
||||
#ifdef DEBUG
|
||||
lis r4, CFG_SDRAM_BASE@h /* Source Address */
|
||||
ori r4, r4, CFG_SDRAM_BASE@l
|
||||
#else
|
||||
lis r4, CFG_MONITOR_BASE@h /* Source Address */
|
||||
ori r4, r4, CFG_MONITOR_BASE@l
|
||||
#endif
|
||||
lis r5, CFG_MONITOR_LEN@h /* Length in Bytes */
|
||||
ori r5, r5, CFG_MONITOR_LEN@l
|
||||
li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
|
||||
|
||||
/*
|
||||
* Fix GOT pointer:
|
||||
*
|
||||
* New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address
|
||||
*
|
||||
* Offset:
|
||||
*/
|
||||
sub r15, r10, r4
|
||||
|
||||
/* First our own GOT */
|
||||
add r14, r14, r15
|
||||
/* the the one used by the C code */
|
||||
add r30, r30, r15
|
||||
|
||||
/*
|
||||
* Now relocate code
|
||||
*/
|
||||
|
||||
cmplw cr1,r3,r4
|
||||
addi r0,r5,3
|
||||
srwi. r0,r0,2
|
||||
beq cr1,4f /* In place copy is not necessary */
|
||||
beq 7f /* Protect against 0 count */
|
||||
mtctr r0
|
||||
bge cr1,2f
|
||||
|
||||
la r8,-4(r4)
|
||||
la r7,-4(r3)
|
||||
1: lwzu r0,4(r8)
|
||||
stwu r0,4(r7)
|
||||
bdnz 1b
|
||||
b 4f
|
||||
|
||||
2: slwi r0,r0,2
|
||||
add r8,r4,r0
|
||||
add r7,r3,r0
|
||||
3: lwzu r0,-4(r8)
|
||||
stwu r0,-4(r7)
|
||||
bdnz 3b
|
||||
|
||||
/*
|
||||
* Now flush the cache: note that we must start from a cache aligned
|
||||
* address. Otherwise we might miss one cache line.
|
||||
*/
|
||||
4: cmpwi r6,0
|
||||
add r5,r3,r5
|
||||
beq 7f /* Always flush prefetch queue in any case */
|
||||
subi r0,r6,1
|
||||
andc r3,r3,r0
|
||||
mr r4,r3
|
||||
5: dcbst 0,r4
|
||||
add r4,r4,r6
|
||||
cmplw r4,r5
|
||||
blt 5b
|
||||
sync /* Wait for all dcbst to complete on bus */
|
||||
mr r4,r3
|
||||
6: icbi 0,r4
|
||||
add r4,r4,r6
|
||||
cmplw r4,r5
|
||||
blt 6b
|
||||
7: sync /* Wait for all icbi to complete on bus */
|
||||
isync
|
||||
|
||||
/*
|
||||
* We are done. Do not return, instead branch to second part of board
|
||||
* initialization, now running from RAM.
|
||||
*/
|
||||
|
||||
addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
|
||||
mtlr r0
|
||||
blr
|
||||
|
||||
in_ram:
|
||||
|
||||
/*
|
||||
* Relocation Function, r14 point to got2+0x8000
|
||||
*
|
||||
* Adjust got2 pointers, no need to check for 0, this code
|
||||
* already puts a few entries in the table.
|
||||
*/
|
||||
li r0,__got2_entries@sectoff@l
|
||||
la r3,GOT(_GOT2_TABLE_)
|
||||
lwz r11,GOT(_GOT2_TABLE_)
|
||||
mtctr r0
|
||||
sub r11,r3,r11
|
||||
addi r3,r3,-4
|
||||
1: lwzu r0,4(r3)
|
||||
add r0,r0,r11
|
||||
stw r0,0(r3)
|
||||
bdnz 1b
|
||||
|
||||
/*
|
||||
* Now adjust the fixups and the pointers to the fixups
|
||||
* in case we need to move ourselves again.
|
||||
*/
|
||||
2: li r0,__fixup_entries@sectoff@l
|
||||
lwz r3,GOT(_FIXUP_TABLE_)
|
||||
cmpwi r0,0
|
||||
mtctr r0
|
||||
addi r3,r3,-4
|
||||
beq 4f
|
||||
3: lwzu r4,4(r3)
|
||||
lwzux r0,r4,r11
|
||||
add r0,r0,r11
|
||||
stw r10,0(r3)
|
||||
stw r0,0(r4)
|
||||
bdnz 3b
|
||||
4:
|
||||
clear_bss:
|
||||
/*
|
||||
* Now clear BSS segment
|
||||
*/
|
||||
lwz r3,GOT(.bss)
|
||||
lwz r4,GOT(_end)
|
||||
|
||||
cmplw 0, r3, r4
|
||||
beq 6f
|
||||
|
||||
li r0, 0
|
||||
5:
|
||||
stw r0, 0(r3)
|
||||
addi r3, r3, 4
|
||||
cmplw 0, r3, r4
|
||||
blt 5b
|
||||
6:
|
||||
|
||||
mr r3, r9 /* Global Data pointer */
|
||||
mr r4, r10 /* Destination Address */
|
||||
bl board_init_r
|
||||
|
||||
/* Problems accessing "end" in C, so do it here */
|
||||
.globl get_endaddr
|
||||
get_endaddr:
|
||||
lwz r3,GOT(_end)
|
||||
blr
|
||||
|
||||
/*
|
||||
* Copy exception vector code to low memory
|
||||
*
|
||||
* r3: dest_addr
|
||||
* r7: source address, r8: end address, r9: target address
|
||||
*/
|
||||
.globl trap_init
|
||||
trap_init:
|
||||
lwz r7, GOT(_start)
|
||||
lwz r8, GOT(_end_of_vectors)
|
||||
|
||||
rlwinm r9, r7, 0, 18, 31 /* _start & 0x3FFF */
|
||||
|
||||
cmplw 0, r7, r8
|
||||
bgelr /* return if r7>=r8 - just in case */
|
||||
|
||||
mflr r4 /* save link register */
|
||||
1:
|
||||
lwz r0, 0(r7)
|
||||
stw r0, 0(r9)
|
||||
addi r7, r7, 4
|
||||
addi r9, r9, 4
|
||||
cmplw 0, r7, r8
|
||||
bne 1b
|
||||
|
||||
/*
|
||||
* relocate `hdlr' and `int_return' entries
|
||||
*/
|
||||
li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET
|
||||
li r8, Alignment - _start + EXC_OFF_SYS_RESET
|
||||
2:
|
||||
bl trap_reloc
|
||||
addi r7, r7, 0x100 /* next exception vector */
|
||||
cmplw 0, r7, r8
|
||||
blt 2b
|
||||
|
||||
li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET
|
||||
bl trap_reloc
|
||||
|
||||
li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET
|
||||
bl trap_reloc
|
||||
|
||||
li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET
|
||||
li r8, SystemCall - _start + EXC_OFF_SYS_RESET
|
||||
3:
|
||||
bl trap_reloc
|
||||
addi r7, r7, 0x100 /* next exception vector */
|
||||
cmplw 0, r7, r8
|
||||
blt 3b
|
||||
|
||||
li r7, .L_SingleStep - _start + EXC_OFF_SYS_RESET
|
||||
li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET
|
||||
4:
|
||||
bl trap_reloc
|
||||
addi r7, r7, 0x100 /* next exception vector */
|
||||
cmplw 0, r7, r8
|
||||
blt 4b
|
||||
|
||||
mtlr r4 /* restore link register */
|
||||
blr
|
||||
|
||||
/*
|
||||
* Function: relocate entries for one exception vector
|
||||
*/
|
||||
trap_reloc:
|
||||
lwz r0, 0(r7) /* hdlr ... */
|
||||
add r0, r0, r3 /* ... += dest_addr */
|
||||
stw r0, 0(r7)
|
||||
|
||||
lwz r0, 4(r7) /* int_return ... */
|
||||
add r0, r0, r3 /* ... += dest_addr */
|
||||
stw r0, 4(r7)
|
||||
|
||||
blr
|
||||
|
||||
/* Setup the BAT registers.
|
||||
*/
|
||||
setup_bats:
|
||||
lis r4, CFG_IBAT0L@h
|
||||
ori r4, r4, CFG_IBAT0L@l
|
||||
lis r3, CFG_IBAT0U@h
|
||||
ori r3, r3, CFG_IBAT0U@l
|
||||
mtspr IBAT0L, r4
|
||||
mtspr IBAT0U, r3
|
||||
isync
|
||||
|
||||
lis r4, CFG_DBAT0L@h
|
||||
ori r4, r4, CFG_DBAT0L@l
|
||||
lis r3, CFG_DBAT0U@h
|
||||
ori r3, r3, CFG_DBAT0U@l
|
||||
mtspr DBAT0L, r4
|
||||
mtspr DBAT0U, r3
|
||||
isync
|
||||
|
||||
lis r4, CFG_IBAT1L@h
|
||||
ori r4, r4, CFG_IBAT1L@l
|
||||
lis r3, CFG_IBAT1U@h
|
||||
ori r3, r3, CFG_IBAT1U@l
|
||||
mtspr IBAT1L, r4
|
||||
mtspr IBAT1U, r3
|
||||
isync
|
||||
|
||||
lis r4, CFG_DBAT1L@h
|
||||
ori r4, r4, CFG_DBAT1L@l
|
||||
lis r3, CFG_DBAT1U@h
|
||||
ori r3, r3, CFG_DBAT1U@l
|
||||
mtspr DBAT1L, r4
|
||||
mtspr DBAT1U, r3
|
||||
isync
|
||||
|
||||
lis r4, CFG_IBAT2L@h
|
||||
ori r4, r4, CFG_IBAT2L@l
|
||||
lis r3, CFG_IBAT2U@h
|
||||
ori r3, r3, CFG_IBAT2U@l
|
||||
mtspr IBAT2L, r4
|
||||
mtspr IBAT2U, r3
|
||||
isync
|
||||
|
||||
lis r4, CFG_DBAT2L@h
|
||||
ori r4, r4, CFG_DBAT2L@l
|
||||
lis r3, CFG_DBAT2U@h
|
||||
ori r3, r3, CFG_DBAT2U@l
|
||||
mtspr DBAT2L, r4
|
||||
mtspr DBAT2U, r3
|
||||
isync
|
||||
|
||||
lis r4, CFG_IBAT3L@h
|
||||
ori r4, r4, CFG_IBAT3L@l
|
||||
lis r3, CFG_IBAT3U@h
|
||||
ori r3, r3, CFG_IBAT3U@l
|
||||
mtspr IBAT3L, r4
|
||||
mtspr IBAT3U, r3
|
||||
isync
|
||||
|
||||
lis r4, CFG_DBAT3L@h
|
||||
ori r4, r4, CFG_DBAT3L@l
|
||||
lis r3, CFG_DBAT3U@h
|
||||
ori r3, r3, CFG_DBAT3U@l
|
||||
mtspr DBAT3L, r4
|
||||
mtspr DBAT3U, r3
|
||||
isync
|
||||
|
||||
/* Invalidate TLBs.
|
||||
* -> for (val = 0; val < 0x20000; val+=0x1000)
|
||||
* -> tlbie(val);
|
||||
*/
|
||||
lis r3, 0
|
||||
lis r5, 2
|
||||
|
||||
1:
|
||||
tlbie r3
|
||||
addi r3, r3, 0x1000
|
||||
cmp 0, 0, r3, r5
|
||||
blt 1b
|
||||
|
||||
blr
|
||||
|
||||
|
||||
264
cpu/mpc8260/cpu_init.c
Normal file
264
cpu/mpc8260/cpu_init.c
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mpc8260.h>
|
||||
#include <asm/cpm_8260.h>
|
||||
#include <ioports.h>
|
||||
|
||||
static void config_8260_ioports (volatile immap_t * immr)
|
||||
{
|
||||
int portnum;
|
||||
|
||||
for (portnum = 0; portnum < 4; portnum++) {
|
||||
uint pmsk = 0,
|
||||
ppar = 0,
|
||||
psor = 0,
|
||||
pdir = 0,
|
||||
podr = 0,
|
||||
pdat = 0;
|
||||
iop_conf_t *iopc = (iop_conf_t *) & iop_conf_tab[portnum][0];
|
||||
iop_conf_t *eiopc = iopc + 32;
|
||||
uint msk = 1;
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* index 0 refers to pin 31,
|
||||
* index 31 refers to pin 0
|
||||
*/
|
||||
while (iopc < eiopc) {
|
||||
if (iopc->conf) {
|
||||
pmsk |= msk;
|
||||
if (iopc->ppar)
|
||||
ppar |= msk;
|
||||
if (iopc->psor)
|
||||
psor |= msk;
|
||||
if (iopc->pdir)
|
||||
pdir |= msk;
|
||||
if (iopc->podr)
|
||||
podr |= msk;
|
||||
if (iopc->pdat)
|
||||
pdat |= msk;
|
||||
}
|
||||
|
||||
msk <<= 1;
|
||||
iopc++;
|
||||
}
|
||||
|
||||
if (pmsk != 0) {
|
||||
volatile ioport_t *iop = ioport_addr (immr, portnum);
|
||||
uint tpmsk = ~pmsk;
|
||||
|
||||
/*
|
||||
* the (somewhat confused) paragraph at the
|
||||
* bottom of page 35-5 warns that there might
|
||||
* be "unknown behaviour" when programming
|
||||
* PSORx and PDIRx, if PPARx = 1, so I
|
||||
* decided this meant I had to disable the
|
||||
* dedicated function first, and enable it
|
||||
* last.
|
||||
*/
|
||||
iop->ppar &= tpmsk;
|
||||
iop->psor = (iop->psor & tpmsk) | psor;
|
||||
iop->pdat = (iop->pdat & tpmsk) | pdat;
|
||||
iop->pdir = (iop->pdir & tpmsk) | pdir;
|
||||
iop->podr = (iop->podr & tpmsk) | podr;
|
||||
iop->ppar |= ppar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Breath some life into the CPU...
|
||||
*
|
||||
* Set up the memory map,
|
||||
* initialize a bunch of registers,
|
||||
* initialize the UPM's
|
||||
*/
|
||||
void cpu_init_f (volatile immap_t * immr)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
volatile memctl8260_t *memctl = &immr->im_memctl;
|
||||
extern void m8260_cpm_reset (void);
|
||||
|
||||
/* Pointer is writable since we allocated a register for it */
|
||||
gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET);
|
||||
|
||||
/* Clear initial global data */
|
||||
memset ((void *) gd, 0, sizeof (gd_t));
|
||||
|
||||
/* RSR - Reset Status Register - clear all status (5-4) */
|
||||
gd->reset_status = immr->im_clkrst.car_rsr;
|
||||
immr->im_clkrst.car_rsr = RSR_ALLBITS;
|
||||
|
||||
/* RMR - Reset Mode Register - contains checkstop reset enable (5-5) */
|
||||
immr->im_clkrst.car_rmr = CFG_RMR;
|
||||
|
||||
/* BCR - Bus Configuration Register (4-25) */
|
||||
immr->im_siu_conf.sc_bcr = CFG_BCR;
|
||||
|
||||
/* SIUMCR - contains debug pin configuration (4-31) */
|
||||
immr->im_siu_conf.sc_siumcr = CFG_SIUMCR;
|
||||
|
||||
config_8260_ioports (immr);
|
||||
|
||||
/* initialize time counter status and control register (4-40) */
|
||||
immr->im_sit.sit_tmcntsc = CFG_TMCNTSC;
|
||||
|
||||
/* initialize the PIT (4-42) */
|
||||
immr->im_sit.sit_piscr = CFG_PISCR;
|
||||
|
||||
#if !defined(CONFIG_COGENT) /* done in start.S for the cogent */
|
||||
/* System clock control register (9-8) */
|
||||
immr->im_clkrst.car_sccr = CFG_SCCR;
|
||||
#endif /* !CONFIG_COGENT */
|
||||
|
||||
/*
|
||||
* Memory Controller:
|
||||
*/
|
||||
|
||||
/* Map banks 0 and 1 to the FLASH banks 0 and 1 at preliminary
|
||||
* addresses - these have to be modified later when FLASH size
|
||||
* has been determined
|
||||
*/
|
||||
|
||||
#if defined(CFG_OR0_REMAP)
|
||||
memctl->memc_or0 = CFG_OR0_REMAP;
|
||||
#endif
|
||||
#if defined(CFG_OR1_REMAP)
|
||||
memctl->memc_or1 = CFG_OR1_REMAP;
|
||||
#endif
|
||||
|
||||
/* now restrict to preliminary range */
|
||||
memctl->memc_br0 = CFG_BR0_PRELIM;
|
||||
memctl->memc_or0 = CFG_OR0_PRELIM;
|
||||
|
||||
#if defined(CFG_BR1_PRELIM) && defined(CFG_OR1_PRELIM)
|
||||
memctl->memc_or1 = CFG_OR1_PRELIM;
|
||||
memctl->memc_br1 = CFG_BR1_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR2_PRELIM) && defined(CFG_OR2_PRELIM)
|
||||
memctl->memc_or2 = CFG_OR2_PRELIM;
|
||||
memctl->memc_br2 = CFG_BR2_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR3_PRELIM) && defined(CFG_OR3_PRELIM)
|
||||
memctl->memc_or3 = CFG_OR3_PRELIM;
|
||||
memctl->memc_br3 = CFG_BR3_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR4_PRELIM) && defined(CFG_OR4_PRELIM)
|
||||
memctl->memc_or4 = CFG_OR4_PRELIM;
|
||||
memctl->memc_br4 = CFG_BR4_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR5_PRELIM) && defined(CFG_OR5_PRELIM)
|
||||
memctl->memc_or5 = CFG_OR5_PRELIM;
|
||||
memctl->memc_br5 = CFG_BR5_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR6_PRELIM) && defined(CFG_OR6_PRELIM)
|
||||
memctl->memc_or6 = CFG_OR6_PRELIM;
|
||||
memctl->memc_br6 = CFG_BR6_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR7_PRELIM) && defined(CFG_OR7_PRELIM)
|
||||
memctl->memc_or7 = CFG_OR7_PRELIM;
|
||||
memctl->memc_br7 = CFG_BR7_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR8_PRELIM) && defined(CFG_OR8_PRELIM)
|
||||
memctl->memc_or8 = CFG_OR8_PRELIM;
|
||||
memctl->memc_br8 = CFG_BR8_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR9_PRELIM) && defined(CFG_OR9_PRELIM)
|
||||
memctl->memc_or9 = CFG_OR9_PRELIM;
|
||||
memctl->memc_br9 = CFG_BR9_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR10_PRELIM) && defined(CFG_OR10_PRELIM)
|
||||
memctl->memc_or10 = CFG_OR10_PRELIM;
|
||||
memctl->memc_br10 = CFG_BR10_PRELIM;
|
||||
#endif
|
||||
|
||||
#if defined(CFG_BR11_PRELIM) && defined(CFG_OR11_PRELIM)
|
||||
memctl->memc_or11 = CFG_OR11_PRELIM;
|
||||
memctl->memc_br11 = CFG_BR11_PRELIM;
|
||||
#endif
|
||||
|
||||
m8260_cpm_reset ();
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize higher level parts of CPU like time base and timers
|
||||
*/
|
||||
int cpu_init_r (void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
volatile immap_t *immr = (immap_t *) gd->bd->bi_immr_base;
|
||||
|
||||
immr->im_cpm.cp_rccr = CFG_RCCR;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* print out the reason for the reset
|
||||
*/
|
||||
int prt_8260_rsr (void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct {
|
||||
ulong mask;
|
||||
char *desc;
|
||||
} bits[] = {
|
||||
{
|
||||
RSR_JTRS, "JTAG"}, {
|
||||
RSR_CSRS, "Check Stop"}, {
|
||||
RSR_SWRS, "Software Watchdog"}, {
|
||||
RSR_BMRS, "Bus Monitor"}, {
|
||||
RSR_ESRS, "External Soft"}, {
|
||||
RSR_EHRS, "External Hard"}
|
||||
};
|
||||
static int n = sizeof bits / sizeof bits[0];
|
||||
ulong rsr = gd->reset_status;
|
||||
int i;
|
||||
char *sep;
|
||||
|
||||
puts ("MPC8260 Reset Status:");
|
||||
|
||||
sep = " ";
|
||||
for (i = 0; i < n; i++)
|
||||
if (rsr & bits[i].mask) {
|
||||
printf ("%s%s", sep, bits[i].desc);
|
||||
sep = ", ";
|
||||
}
|
||||
|
||||
puts ("\n\n");
|
||||
return (0);
|
||||
}
|
||||
733
cpu/mpc8260/i2c.c
Normal file
733
cpu/mpc8260/i2c.c
Normal file
@@ -0,0 +1,733 @@
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
|
||||
*
|
||||
* (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#if defined(CONFIG_HARD_I2C)
|
||||
|
||||
#include <asm/cpm_8260.h>
|
||||
#include <i2c.h>
|
||||
|
||||
/* define to enable debug messages */
|
||||
#undef DEBUG_I2C
|
||||
|
||||
/* uSec to wait between polls of the i2c */
|
||||
#define DELAY_US 100
|
||||
/* uSec to wait for the CPM to start processing the buffer */
|
||||
#define START_DELAY_US 1000
|
||||
|
||||
/*
|
||||
* tx/rx per-byte timeout: we delay DELAY_US uSec between polls so the
|
||||
* timeout will be (tx_length + rx_length) * DELAY_US * TOUT_LOOP
|
||||
*/
|
||||
#define TOUT_LOOP 5
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Set default values
|
||||
*/
|
||||
#ifndef CFG_I2C_SPEED
|
||||
#define CFG_I2C_SPEED 50000
|
||||
#endif
|
||||
|
||||
#ifndef CFG_I2C_SLAVE
|
||||
#define CFG_I2C_SLAVE 0xFE
|
||||
#endif
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef void (*i2c_ecb_t)(int, int); /* error callback function */
|
||||
|
||||
/* This structure keeps track of the bd and buffer space usage. */
|
||||
typedef struct i2c_state {
|
||||
int rx_idx; /* index to next free Rx BD */
|
||||
int tx_idx; /* index to next free Tx BD */
|
||||
void *rxbd; /* pointer to next free Rx BD */
|
||||
void *txbd; /* pointer to next free Tx BD */
|
||||
int tx_space; /* number of Tx bytes left */
|
||||
unsigned char *tx_buf; /* pointer to free Tx area */
|
||||
i2c_ecb_t err_cb; /* error callback function */
|
||||
} i2c_state_t;
|
||||
|
||||
/* flags for i2c_send() and i2c_receive() */
|
||||
#define I2CF_ENABLE_SECONDARY 0x01 /* secondary_address is valid */
|
||||
#define I2CF_START_COND 0x02 /* tx: generate start condition */
|
||||
#define I2CF_STOP_COND 0x04 /* tx: generate stop condition */
|
||||
|
||||
/* return codes */
|
||||
#define I2CERR_NO_BUFFERS 0x01 /* no more BDs or buffer space */
|
||||
#define I2CERR_MSG_TOO_LONG 0x02 /* tried to send/receive to much data */
|
||||
#define I2CERR_TIMEOUT 0x03 /* timeout in i2c_doio() */
|
||||
#define I2CERR_QUEUE_EMPTY 0x04 /* i2c_doio called without send/receive */
|
||||
|
||||
/* error callback flags */
|
||||
#define I2CECB_RX_ERR 0x10 /* this is a receive error */
|
||||
#define I2CECB_RX_ERR_OV 0x02 /* receive overrun error */
|
||||
#define I2CECB_RX_MASK 0x0f /* mask for error bits */
|
||||
#define I2CECB_TX_ERR 0x20 /* this is a transmit error */
|
||||
#define I2CECB_TX_CL 0x01 /* transmit collision error */
|
||||
#define I2CECB_TX_UN 0x02 /* transmit underflow error */
|
||||
#define I2CECB_TX_NAK 0x04 /* transmit no ack error */
|
||||
#define I2CECB_TX_MASK 0x0f /* mask for error bits */
|
||||
#define I2CECB_TIMEOUT 0x40 /* this is a timeout error */
|
||||
|
||||
#define ERROR_I2C_NONE 0
|
||||
#define ERROR_I2C_LENGTH 1
|
||||
|
||||
#define I2C_WRITE_BIT 0x00
|
||||
#define I2C_READ_BIT 0x01
|
||||
|
||||
#define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */
|
||||
|
||||
|
||||
#define NUM_RX_BDS 4
|
||||
#define NUM_TX_BDS 4
|
||||
#define MAX_TX_SPACE 256
|
||||
|
||||
typedef struct I2C_BD
|
||||
{
|
||||
unsigned short status;
|
||||
unsigned short length;
|
||||
unsigned char *addr;
|
||||
} I2C_BD;
|
||||
#define BD_I2C_TX_START 0x0400 /* special status for i2c: Start condition */
|
||||
|
||||
#define BD_I2C_TX_CL 0x0001 /* collision error */
|
||||
#define BD_I2C_TX_UN 0x0002 /* underflow error */
|
||||
#define BD_I2C_TX_NAK 0x0004 /* no acknowledge error */
|
||||
#define BD_I2C_TX_ERR (BD_I2C_TX_NAK|BD_I2C_TX_UN|BD_I2C_TX_CL)
|
||||
|
||||
#define BD_I2C_RX_ERR BD_SC_OV
|
||||
|
||||
#ifdef DEBUG_I2C
|
||||
#define PRINTD(x) printf x
|
||||
#else
|
||||
#define PRINTD(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns the best value of I2BRG to meet desired clock speed of I2C with
|
||||
* input parameters (clock speed, filter, and predivider value).
|
||||
* It returns computer speed value and the difference between it and desired
|
||||
* speed.
|
||||
*/
|
||||
static inline int
|
||||
i2c_roundrate(int hz, int speed, int filter, int modval,
|
||||
int *brgval, int *totspeed)
|
||||
{
|
||||
int moddiv = 1 << (5-(modval & 3)), brgdiv, div;
|
||||
|
||||
PRINTD(("\t[I2C] trying hz=%d, speed=%d, filter=%d, modval=%d\n",
|
||||
hz, speed, filter, modval));
|
||||
|
||||
div = moddiv * speed;
|
||||
brgdiv = (hz + div - 1) / div;
|
||||
|
||||
PRINTD(("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv));
|
||||
|
||||
*brgval = (brgdiv / 2) - 3 - (2*filter);
|
||||
|
||||
if ((*brgval < 0) || (*brgval > 255)) {
|
||||
PRINTD(("\t\trejected brgval=%d\n", *brgval));
|
||||
return -1;
|
||||
}
|
||||
|
||||
brgdiv = 2 * (*brgval + 3 + (2 * filter));
|
||||
div = moddiv * brgdiv ;
|
||||
*totspeed = (hz + div - 1) / div;
|
||||
|
||||
PRINTD(("\t\taccepted brgval=%d, totspeed=%d\n", *brgval, *totspeed));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the I2C clock predivider and divider to meet required clock speed.
|
||||
*/
|
||||
static int i2c_setrate(int hz, int speed)
|
||||
{
|
||||
immap_t *immap = (immap_t *)CFG_IMMR ;
|
||||
volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
|
||||
int brgval,
|
||||
modval, /* 0-3 */
|
||||
bestspeed_diff = speed,
|
||||
bestspeed_brgval=0,
|
||||
bestspeed_modval=0,
|
||||
bestspeed_filter=0,
|
||||
totspeed,
|
||||
filter = 0; /* Use this fixed value */
|
||||
|
||||
for (modval = 0; modval < 4; modval++)
|
||||
{
|
||||
if (i2c_roundrate (hz, speed, filter, modval, &brgval, &totspeed) == 0)
|
||||
{
|
||||
int diff = speed - totspeed ;
|
||||
|
||||
if ((diff >= 0) && (diff < bestspeed_diff))
|
||||
{
|
||||
bestspeed_diff = diff ;
|
||||
bestspeed_modval = modval;
|
||||
bestspeed_brgval = brgval;
|
||||
bestspeed_filter = filter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRINTD(("[I2C] Best is:\n"));
|
||||
PRINTD(("[I2C] CPU=%dhz RATE=%d F=%d I2MOD=%08x I2BRG=%08x DIFF=%dhz\n",
|
||||
hz, speed,
|
||||
bestspeed_filter, bestspeed_modval, bestspeed_brgval,
|
||||
bestspeed_diff));
|
||||
|
||||
i2c->i2c_i2mod |= ((bestspeed_modval & 3) << 1) | (bestspeed_filter << 3);
|
||||
i2c->i2c_i2brg = bestspeed_brgval & 0xff;
|
||||
|
||||
PRINTD(("[I2C] i2mod=%08x i2brg=%08x\n", i2c->i2c_i2mod, i2c->i2c_i2brg));
|
||||
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
void i2c_init(int speed, int slaveadd)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR ;
|
||||
volatile cpm8260_t *cp = (cpm8260_t *)&immap->im_cpm;
|
||||
volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
|
||||
volatile iic_t *iip;
|
||||
ulong rbase, tbase;
|
||||
volatile I2C_BD *rxbd, *txbd;
|
||||
uint dpaddr;
|
||||
|
||||
dpaddr = *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE]));
|
||||
if (dpaddr == 0) {
|
||||
/* need to allocate dual port ram */
|
||||
dpaddr = m8260_cpm_dpalloc(64 +
|
||||
(NUM_RX_BDS * sizeof(I2C_BD)) + (NUM_TX_BDS * sizeof(I2C_BD)) +
|
||||
MAX_TX_SPACE, 64);
|
||||
*((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE])) = dpaddr;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise data in dual port ram:
|
||||
*
|
||||
* dpaddr -> parameter ram (64 bytes)
|
||||
* rbase -> rx BD (NUM_RX_BDS * sizeof(I2C_BD) bytes)
|
||||
* tbase -> tx BD (NUM_TX_BDS * sizeof(I2C_BD) bytes)
|
||||
* tx buffer (MAX_TX_SPACE bytes)
|
||||
*/
|
||||
|
||||
iip = (iic_t *)&immap->im_dprambase[dpaddr];
|
||||
memset((void*)iip, 0, sizeof(iic_t));
|
||||
|
||||
rbase = dpaddr + 64;
|
||||
tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD);
|
||||
|
||||
/* Disable interrupts */
|
||||
i2c->i2c_i2mod = 0x00;
|
||||
i2c->i2c_i2cmr = 0x00;
|
||||
i2c->i2c_i2cer = 0xff;
|
||||
i2c->i2c_i2add = slaveadd;
|
||||
|
||||
/*
|
||||
* Set the I2C BRG Clock division factor from desired i2c rate
|
||||
* and current CPU rate (we assume sccr dfbgr field is 0;
|
||||
* divide BRGCLK by 1)
|
||||
*/
|
||||
PRINTD(("[I2C] Setting rate...\n"));
|
||||
i2c_setrate (gd->brg_clk, CFG_I2C_SPEED) ;
|
||||
|
||||
/* Set I2C controller in master mode */
|
||||
i2c->i2c_i2com = 0x01;
|
||||
|
||||
/* Initialize Tx/Rx parameters */
|
||||
iip->iic_rbase = rbase;
|
||||
iip->iic_tbase = tbase;
|
||||
rxbd = (I2C_BD *)((unsigned char *)&immap->im_dprambase[iip->iic_rbase]);
|
||||
txbd = (I2C_BD *)((unsigned char *)&immap->im_dprambase[iip->iic_tbase]);
|
||||
|
||||
PRINTD(("[I2C] rbase = %04x\n", iip->iic_rbase));
|
||||
PRINTD(("[I2C] tbase = %04x\n", iip->iic_tbase));
|
||||
PRINTD(("[I2C] rxbd = %08x\n", (int)rxbd));
|
||||
PRINTD(("[I2C] txbd = %08x\n", (int)txbd));
|
||||
|
||||
/* Set big endian byte order */
|
||||
iip->iic_tfcr = 0x10;
|
||||
iip->iic_rfcr = 0x10;
|
||||
|
||||
/* Set maximum receive size. */
|
||||
iip->iic_mrblr = I2C_RXTX_LEN;
|
||||
|
||||
cp->cp_cpcr = mk_cr_cmd(CPM_CR_I2C_PAGE,
|
||||
CPM_CR_I2C_SBLOCK,
|
||||
0x00,
|
||||
CPM_CR_INIT_TRX) | CPM_CR_FLG;
|
||||
do {
|
||||
__asm__ __volatile__ ("eieio");
|
||||
} while (cp->cp_cpcr & CPM_CR_FLG);
|
||||
|
||||
/* Clear events and interrupts */
|
||||
i2c->i2c_i2cer = 0xff;
|
||||
i2c->i2c_i2cmr = 0x00;
|
||||
}
|
||||
|
||||
static
|
||||
void i2c_newio(i2c_state_t *state)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR ;
|
||||
volatile iic_t *iip;
|
||||
uint dpaddr;
|
||||
|
||||
PRINTD(("[I2C] i2c_newio\n"));
|
||||
|
||||
dpaddr = *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE]));
|
||||
iip = (iic_t *)&immap->im_dprambase[dpaddr];
|
||||
state->rx_idx = 0;
|
||||
state->tx_idx = 0;
|
||||
state->rxbd = (void*)&immap->im_dprambase[iip->iic_rbase];
|
||||
state->txbd = (void*)&immap->im_dprambase[iip->iic_tbase];
|
||||
state->tx_space = MAX_TX_SPACE;
|
||||
state->tx_buf = (uchar*)state->txbd + NUM_TX_BDS * sizeof(I2C_BD);
|
||||
state->err_cb = NULL;
|
||||
|
||||
PRINTD(("[I2C] rxbd = %08x\n", (int)state->rxbd));
|
||||
PRINTD(("[I2C] txbd = %08x\n", (int)state->txbd));
|
||||
PRINTD(("[I2C] tx_buf = %08x\n", (int)state->tx_buf));
|
||||
|
||||
/* clear the buffer memory */
|
||||
memset((char *)state->tx_buf, 0, MAX_TX_SPACE);
|
||||
}
|
||||
|
||||
static
|
||||
int i2c_send(i2c_state_t *state,
|
||||
unsigned char address,
|
||||
unsigned char secondary_address,
|
||||
unsigned int flags,
|
||||
unsigned short size,
|
||||
unsigned char *dataout)
|
||||
{
|
||||
volatile I2C_BD *txbd;
|
||||
int i,j;
|
||||
|
||||
PRINTD(("[I2C] i2c_send add=%02d sec=%02d flag=%02d size=%d\n",
|
||||
address, secondary_address, flags, size));
|
||||
|
||||
/* trying to send message larger than BD */
|
||||
if (size > I2C_RXTX_LEN)
|
||||
return I2CERR_MSG_TOO_LONG;
|
||||
|
||||
/* no more free bds */
|
||||
if (state->tx_idx >= NUM_TX_BDS || state->tx_space < (2 + size))
|
||||
return I2CERR_NO_BUFFERS;
|
||||
|
||||
txbd = (I2C_BD *)state->txbd;
|
||||
txbd->addr = state->tx_buf;
|
||||
|
||||
PRINTD(("[I2C] txbd = %08x\n", (int)txbd));
|
||||
|
||||
if (flags & I2CF_START_COND)
|
||||
{
|
||||
PRINTD(("[I2C] Formatting addresses...\n"));
|
||||
if (flags & I2CF_ENABLE_SECONDARY)
|
||||
{
|
||||
txbd->length = size + 2; /* Length of message plus dest addresses */
|
||||
txbd->addr[0] = address << 1;
|
||||
txbd->addr[1] = secondary_address;
|
||||
i = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
txbd->length = size + 1; /* Length of message plus dest address */
|
||||
txbd->addr[0] = address << 1; /* Write destination address to BD */
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
txbd->length = size; /* Length of message */
|
||||
i = 0;
|
||||
}
|
||||
|
||||
/* set up txbd */
|
||||
txbd->status = BD_SC_READY;
|
||||
if (flags & I2CF_START_COND)
|
||||
txbd->status |= BD_I2C_TX_START;
|
||||
if (flags & I2CF_STOP_COND)
|
||||
txbd->status |= BD_SC_LAST | BD_SC_WRAP;
|
||||
|
||||
/* Copy data to send into buffer */
|
||||
PRINTD(("[I2C] copy data...\n"));
|
||||
for(j = 0; j < size; i++, j++)
|
||||
txbd->addr[i] = dataout[j];
|
||||
|
||||
PRINTD(("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
|
||||
txbd->length,
|
||||
txbd->status,
|
||||
txbd->addr[0],
|
||||
txbd->addr[1]));
|
||||
|
||||
/* advance state */
|
||||
state->tx_buf += txbd->length;
|
||||
state->tx_space -= txbd->length;
|
||||
state->tx_idx++;
|
||||
state->txbd = (void*)(txbd + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int i2c_receive(i2c_state_t *state,
|
||||
unsigned char address,
|
||||
unsigned char secondary_address,
|
||||
unsigned int flags,
|
||||
unsigned short size_to_expect,
|
||||
unsigned char *datain)
|
||||
{
|
||||
volatile I2C_BD *rxbd, *txbd;
|
||||
|
||||
PRINTD(("[I2C] i2c_receive %02d %02d %02d\n", address, secondary_address, flags));
|
||||
|
||||
/* Expected to receive too much */
|
||||
if (size_to_expect > I2C_RXTX_LEN)
|
||||
return I2CERR_MSG_TOO_LONG;
|
||||
|
||||
/* no more free bds */
|
||||
if (state->tx_idx >= NUM_TX_BDS || state->rx_idx >= NUM_RX_BDS
|
||||
|| state->tx_space < 2)
|
||||
return I2CERR_NO_BUFFERS;
|
||||
|
||||
rxbd = (I2C_BD *)state->rxbd;
|
||||
txbd = (I2C_BD *)state->txbd;
|
||||
|
||||
PRINTD(("[I2C] rxbd = %08x\n", (int)rxbd));
|
||||
PRINTD(("[I2C] txbd = %08x\n", (int)txbd));
|
||||
|
||||
txbd->addr = state->tx_buf;
|
||||
|
||||
/* set up TXBD for destination address */
|
||||
if (flags & I2CF_ENABLE_SECONDARY)
|
||||
{
|
||||
txbd->length = 2;
|
||||
txbd->addr[0] = address << 1; /* Write data */
|
||||
txbd->addr[1] = secondary_address; /* Internal address */
|
||||
txbd->status = BD_SC_READY;
|
||||
}
|
||||
else
|
||||
{
|
||||
txbd->length = 1 + size_to_expect;
|
||||
txbd->addr[0] = (address << 1) | 0x01;
|
||||
txbd->status = BD_SC_READY;
|
||||
memset(&txbd->addr[1], 0, txbd->length);
|
||||
}
|
||||
|
||||
/* set up rxbd for reception */
|
||||
rxbd->status = BD_SC_EMPTY;
|
||||
rxbd->length = size_to_expect;
|
||||
rxbd->addr = datain;
|
||||
|
||||
txbd->status |= BD_I2C_TX_START;
|
||||
if (flags & I2CF_STOP_COND)
|
||||
{
|
||||
txbd->status |= BD_SC_LAST | BD_SC_WRAP;
|
||||
rxbd->status |= BD_SC_WRAP;
|
||||
}
|
||||
|
||||
PRINTD(("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
|
||||
txbd->length,
|
||||
txbd->status,
|
||||
txbd->addr[0],
|
||||
txbd->addr[1]));
|
||||
PRINTD(("[I2C] rxbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n",
|
||||
rxbd->length,
|
||||
rxbd->status,
|
||||
rxbd->addr[0],
|
||||
rxbd->addr[1]));
|
||||
|
||||
/* advance state */
|
||||
state->tx_buf += txbd->length;
|
||||
state->tx_space -= txbd->length;
|
||||
state->tx_idx++;
|
||||
state->txbd = (void*)(txbd + 1);
|
||||
state->rx_idx++;
|
||||
state->rxbd = (void*)(rxbd + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int i2c_doio(i2c_state_t *state)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *)CFG_IMMR ;
|
||||
volatile iic_t *iip;
|
||||
volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c;
|
||||
volatile I2C_BD *txbd, *rxbd;
|
||||
int j;
|
||||
int timeout;
|
||||
uint dpaddr;
|
||||
|
||||
PRINTD(("[I2C] i2c_doio\n"));
|
||||
|
||||
timeout = TOUT_LOOP * 256; /* arbitrarily long */
|
||||
|
||||
if (state->tx_idx <= 0 && state->rx_idx <= 0) {
|
||||
PRINTD(("[I2C] No I/O is queued\n"));
|
||||
return I2CERR_QUEUE_EMPTY;
|
||||
}
|
||||
|
||||
dpaddr = *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE]));
|
||||
iip = (iic_t *)&immap->im_dprambase[dpaddr];
|
||||
iip->iic_rbptr = iip->iic_rbase;
|
||||
iip->iic_tbptr = iip->iic_tbase;
|
||||
|
||||
/* Enable I2C */
|
||||
PRINTD(("[I2C] Enabling I2C...\n"));
|
||||
i2c->i2c_i2mod |= 0x01;
|
||||
|
||||
/* Begin transmission */
|
||||
i2c->i2c_i2com |= 0x80;
|
||||
|
||||
/* Loop until transmit & receive completed */
|
||||
|
||||
txbd = ((I2C_BD*)state->txbd) - 1;
|
||||
j = 0;
|
||||
if (state->tx_idx > 0) {
|
||||
timeout = TOUT_LOOP * txbd->length;
|
||||
|
||||
PRINTD(("[I2C] Transmitting...(txbd=0x%08lx)\n", (ulong)txbd));
|
||||
udelay(START_DELAY_US); /* give it time to start */
|
||||
while((txbd->status & BD_SC_READY) && (j++ < timeout)) {
|
||||
udelay(DELAY_US);
|
||||
if (ctrlc())
|
||||
return (-1);
|
||||
__asm__ __volatile__ ("eieio");
|
||||
}
|
||||
}
|
||||
|
||||
rxbd = ((I2C_BD*)state->rxbd) - 1;
|
||||
j = 0;
|
||||
if ((state->rx_idx > 0) && (j < timeout)) {
|
||||
timeout = TOUT_LOOP * rxbd->length;
|
||||
PRINTD(("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong)rxbd));
|
||||
udelay(START_DELAY_US); /* give it time to start */
|
||||
while((rxbd->status & BD_SC_EMPTY) && (j++ < timeout)) {
|
||||
udelay(DELAY_US);
|
||||
if (ctrlc())
|
||||
return (-1);
|
||||
__asm__ __volatile__ ("eieio");
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off I2C */
|
||||
i2c->i2c_i2mod &= ~0x01;
|
||||
|
||||
if (state->err_cb != NULL) {
|
||||
int n, i, b;
|
||||
|
||||
/*
|
||||
* if we have an error callback function, look at the
|
||||
* error bits in the bd status and pass them back
|
||||
*/
|
||||
|
||||
if ((n = state->tx_idx) > 0) {
|
||||
for (i = 0; i < n; i++) {
|
||||
txbd = ((I2C_BD*)state->txbd) - (n - i);
|
||||
if ((b = txbd->status & BD_I2C_TX_ERR) != 0)
|
||||
(*state->err_cb)(I2CECB_TX_ERR|b, i);
|
||||
}
|
||||
}
|
||||
|
||||
if ((n = state->rx_idx) > 0) {
|
||||
for (i = 0; i < n; i++) {
|
||||
rxbd = ((I2C_BD*)state->rxbd) - (n - i);
|
||||
if ((b = rxbd->status & BD_I2C_RX_ERR) != 0)
|
||||
(*state->err_cb)(I2CECB_RX_ERR|b, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (j >= timeout)
|
||||
(*state->err_cb)(I2CECB_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
/* sort out errors and return appropriate good/error status */
|
||||
if(j >= timeout)
|
||||
return(I2CERR_TIMEOUT);
|
||||
if((txbd->status & BD_I2C_TX_ERR) != 0)
|
||||
return(I2CECB_TX_ERR | (txbd->status & I2CECB_TX_MASK));
|
||||
if((rxbd->status & BD_I2C_RX_ERR) != 0)
|
||||
return(I2CECB_RX_ERR | (rxbd->status & I2CECB_RX_MASK));
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int had_tx_nak;
|
||||
|
||||
static void
|
||||
i2c_test_callback(int flags, int xnum)
|
||||
{
|
||||
if ((flags & I2CECB_TX_ERR) && (flags & I2CECB_TX_NAK))
|
||||
had_tx_nak = 1;
|
||||
}
|
||||
|
||||
int i2c_probe(uchar chip)
|
||||
{
|
||||
i2c_state_t state;
|
||||
int rc;
|
||||
uchar buf[1];
|
||||
|
||||
i2c_newio(&state);
|
||||
|
||||
state.err_cb = i2c_test_callback;
|
||||
had_tx_nak = 0;
|
||||
|
||||
rc = i2c_receive(&state, chip, 0, I2CF_START_COND|I2CF_STOP_COND, 1, buf);
|
||||
|
||||
if (rc != 0)
|
||||
return (rc);
|
||||
|
||||
rc = i2c_doio(&state);
|
||||
|
||||
if ((rc != 0) && (rc != I2CERR_TIMEOUT))
|
||||
return (rc);
|
||||
|
||||
return (had_tx_nak);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
|
||||
{
|
||||
i2c_state_t state;
|
||||
uchar xaddr[4];
|
||||
int rc;
|
||||
|
||||
xaddr[0] = (addr >> 24) & 0xFF;
|
||||
xaddr[1] = (addr >> 16) & 0xFF;
|
||||
xaddr[2] = (addr >> 8) & 0xFF;
|
||||
xaddr[3] = addr & 0xFF;
|
||||
|
||||
#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
|
||||
/*
|
||||
* EEPROM chips that implement "address overflow" are ones
|
||||
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
|
||||
* and the extra bits end up in the "chip address" bit slots.
|
||||
* This makes a 24WC08 (1Kbyte) chip look like four 256 byte
|
||||
* chips.
|
||||
*
|
||||
* Note that we consider the length of the address field to still
|
||||
* be one byte because the extra address bits are hidden in the
|
||||
* chip address.
|
||||
*/
|
||||
chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
|
||||
#endif
|
||||
|
||||
i2c_newio(&state);
|
||||
|
||||
rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, &xaddr[4-alen]);
|
||||
if (rc != 0) {
|
||||
printf("i2c_read: i2c_send failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = i2c_receive(&state, chip, 0, I2CF_STOP_COND, len, buffer);
|
||||
if (rc != 0) {
|
||||
printf("i2c_read: i2c_receive failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = i2c_doio(&state);
|
||||
if (rc != 0) {
|
||||
printf("i2c_read: i2c_doio failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
|
||||
{
|
||||
i2c_state_t state;
|
||||
uchar xaddr[4];
|
||||
int rc;
|
||||
|
||||
xaddr[0] = (addr >> 24) & 0xFF;
|
||||
xaddr[1] = (addr >> 16) & 0xFF;
|
||||
xaddr[2] = (addr >> 8) & 0xFF;
|
||||
xaddr[3] = addr & 0xFF;
|
||||
|
||||
#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
|
||||
/*
|
||||
* EEPROM chips that implement "address overflow" are ones
|
||||
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of address
|
||||
* and the extra bits end up in the "chip address" bit slots.
|
||||
* This makes a 24WC08 (1Kbyte) chip look like four 256 byte
|
||||
* chips.
|
||||
*
|
||||
* Note that we consider the length of the address field to still
|
||||
* be one byte because the extra address bits are hidden in the
|
||||
* chip address.
|
||||
*/
|
||||
chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
|
||||
#endif
|
||||
|
||||
i2c_newio(&state);
|
||||
|
||||
rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, &xaddr[4-alen]);
|
||||
if (rc != 0) {
|
||||
printf("i2c_write: first i2c_send failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = i2c_send(&state, 0, 0, I2CF_STOP_COND, len, buffer);
|
||||
if (rc != 0) {
|
||||
printf("i2c_write: second i2c_send failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = i2c_doio(&state);
|
||||
if (rc != 0) {
|
||||
printf("i2c_write: i2c_doio failed (%d)\n", rc);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uchar
|
||||
i2c_reg_read(uchar chip, uchar reg)
|
||||
{
|
||||
char buf;
|
||||
|
||||
i2c_read(chip, reg, 1, &buf, 1);
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
void
|
||||
i2c_reg_write(uchar chip, uchar reg, uchar val)
|
||||
{
|
||||
i2c_write(chip, reg, 1, &val, 1);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HARD_I2C */
|
||||
516
cpu/mpc8xx/cpu.c
Normal file
516
cpu/mpc8xx/cpu.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* (C) Copyright 2000-2002
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* m8xx.c
|
||||
*
|
||||
* CPU specific code
|
||||
*
|
||||
* written or collected and sometimes rewritten by
|
||||
* Magnus Damm <damm@bitsmart.com>
|
||||
*
|
||||
* minor modifications by
|
||||
* Wolfgang Denk <wd@denx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <asm/cache.h>
|
||||
|
||||
static char *cpu_warning = "\n " \
|
||||
"*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***";
|
||||
|
||||
#if ((defined(CONFIG_MPC860) || defined(CONFIG_MPC855)) && \
|
||||
!defined(CONFIG_MPC862))
|
||||
# ifdef CONFIG_MPC855
|
||||
# define ID_STR "PC855"
|
||||
# else
|
||||
# define ID_STR "PC860"
|
||||
# endif
|
||||
|
||||
static int check_CPU (long clock, uint pvr, uint immr)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
|
||||
uint k, m;
|
||||
char buf[32];
|
||||
char pre = 'X';
|
||||
char *mid = "xx";
|
||||
char *suf;
|
||||
|
||||
/* the highest 16 bits should be 0x0050 for a 860 */
|
||||
|
||||
if ((pvr >> 16) != 0x0050)
|
||||
return -1;
|
||||
|
||||
k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
|
||||
m = 0;
|
||||
|
||||
switch (k) {
|
||||
case 0x00020001: pre = 'p'; suf = ""; break;
|
||||
case 0x00030001: suf = ""; break;
|
||||
case 0x00120003: suf = "A"; break;
|
||||
case 0x00130003: suf = "A3"; break;
|
||||
|
||||
case 0x00200004: suf = "B"; break;
|
||||
|
||||
case 0x00300004: suf = "C"; break;
|
||||
case 0x00310004: suf = "C1"; m = 1;
|
||||
break;
|
||||
|
||||
case 0x00200064: mid = "SR"; suf = "B"; break;
|
||||
case 0x00300065: mid = "SR"; suf = "C"; break;
|
||||
case 0x00310065: mid = "SR"; suf = "C1"; m = 1; break;
|
||||
case 0x05010000: suf = "D3"; m = 1; break;
|
||||
case 0x05020000: suf = "D4"; m = 1; break;
|
||||
|
||||
/* this value is not documented anywhere */
|
||||
case 0x40000000: pre = 'P'; suf = "D"; m = 1; break;
|
||||
|
||||
default: suf = NULL; break;
|
||||
}
|
||||
|
||||
if (suf)
|
||||
printf ("%c" ID_STR "%sZPnn%s", pre, mid, suf);
|
||||
else
|
||||
printf ("unknown M" ID_STR " (0x%08x)", k);
|
||||
|
||||
printf (" at %s MHz:", strmhz (buf, clock));
|
||||
|
||||
printf (" %u kB I-Cache", checkicache () >> 10);
|
||||
printf (" %u kB D-Cache", checkdcache () >> 10);
|
||||
|
||||
/* lets check and see if we're running on a 860T (or P?) */
|
||||
|
||||
immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
|
||||
if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
|
||||
printf (" FEC present");
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
puts (cpu_warning);
|
||||
}
|
||||
|
||||
putc ('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_MPC862)
|
||||
|
||||
static int check_CPU (long clock, uint pvr, uint immr)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
|
||||
uint k, m;
|
||||
char buf[32];
|
||||
char pre = 'X';
|
||||
char *mid = "xx";
|
||||
char *suf;
|
||||
|
||||
/* the highest 16 bits should be 0x0050 for a 8xx */
|
||||
|
||||
if ((pvr >> 16) != 0x0050)
|
||||
return -1;
|
||||
|
||||
k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
|
||||
m = 0;
|
||||
|
||||
switch (k) {
|
||||
|
||||
/* this value is not documented anywhere */
|
||||
case 0x06000000: mid = "P"; suf = "0"; break;
|
||||
case 0x06010001: mid = "P"; suf = "A"; m = 1; break;
|
||||
case 0x07000003: mid = "P"; suf = "B"; m = 1; break;
|
||||
default: suf = NULL; break;
|
||||
}
|
||||
|
||||
if (suf)
|
||||
printf ("%cPC862%sZPnn%s", pre, mid, suf);
|
||||
else
|
||||
printf ("unknown MPC862 (0x%08x)", k);
|
||||
|
||||
printf (" at %s MHz:", strmhz (buf, clock));
|
||||
|
||||
printf (" %u kB I-Cache", checkicache () >> 10);
|
||||
printf (" %u kB D-Cache", checkdcache () >> 10);
|
||||
|
||||
/* lets check and see if we're running on a 862T (or P?) */
|
||||
|
||||
immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
|
||||
if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
|
||||
printf (" FEC present");
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
puts (cpu_warning);
|
||||
}
|
||||
|
||||
putc ('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_MPC823)
|
||||
|
||||
static int check_CPU (long clock, uint pvr, uint immr)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
|
||||
uint k, m;
|
||||
char buf[32];
|
||||
char *suf;
|
||||
|
||||
/* the highest 16 bits should be 0x0050 for a 8xx */
|
||||
|
||||
if ((pvr >> 16) != 0x0050)
|
||||
return -1;
|
||||
|
||||
k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
|
||||
m = 0;
|
||||
|
||||
switch (k) {
|
||||
/* MPC823 */
|
||||
case 0x20000000: suf = "0"; break;
|
||||
case 0x20010000: suf = "0.1"; break;
|
||||
case 0x20020000: suf = "Z2/3"; break;
|
||||
case 0x20020001: suf = "Z3"; break;
|
||||
case 0x21000000: suf = "A"; break;
|
||||
case 0x21010000: suf = "B"; m = 1; break;
|
||||
case 0x21010001: suf = "B2"; m = 1; break;
|
||||
/* MPC823E */
|
||||
case 0x24010000: suf = NULL;
|
||||
puts ("PPC823EZTnnB2");
|
||||
m = 1;
|
||||
break;
|
||||
default:
|
||||
suf = NULL;
|
||||
printf ("unknown MPC823 (0x%08x)", k);
|
||||
break;
|
||||
}
|
||||
if (suf)
|
||||
printf ("PPC823ZTnn%s", suf);
|
||||
|
||||
printf (" at %s MHz:", strmhz (buf, clock));
|
||||
|
||||
printf (" %u kB I-Cache", checkicache () >> 10);
|
||||
printf (" %u kB D-Cache", checkdcache () >> 10);
|
||||
|
||||
/* lets check and see if we're running on a 860T (or P?) */
|
||||
|
||||
immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
|
||||
if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
|
||||
puts (" FEC present");
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
puts (cpu_warning);
|
||||
}
|
||||
|
||||
putc ('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_MPC850)
|
||||
|
||||
static int check_CPU (long clock, uint pvr, uint immr)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
|
||||
uint k, m;
|
||||
char buf[32];
|
||||
|
||||
/* the highest 16 bits should be 0x0050 for a 8xx */
|
||||
|
||||
if ((pvr >> 16) != 0x0050)
|
||||
return -1;
|
||||
|
||||
k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]);
|
||||
m = 0;
|
||||
|
||||
switch (k) {
|
||||
case 0x20020001:
|
||||
printf ("XPC850xxZT");
|
||||
break;
|
||||
case 0x21000065:
|
||||
printf ("XPC850xxZTA");
|
||||
break;
|
||||
case 0x21010067:
|
||||
printf ("XPC850xxZTB");
|
||||
m = 1;
|
||||
break;
|
||||
case 0x21020068:
|
||||
printf ("XPC850xxZTC");
|
||||
m = 1;
|
||||
break;
|
||||
default:
|
||||
printf ("unknown MPC850 (0x%08x)", k);
|
||||
}
|
||||
printf (" at %s MHz:", strmhz (buf, clock));
|
||||
|
||||
printf (" %u kB I-Cache", checkicache () >> 10);
|
||||
printf (" %u kB D-Cache", checkdcache () >> 10);
|
||||
|
||||
/* lets check and see if we're running on a 850T (or P?) */
|
||||
|
||||
immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
|
||||
if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
|
||||
printf (" FEC present");
|
||||
}
|
||||
|
||||
if (!m) {
|
||||
puts (cpu_warning);
|
||||
}
|
||||
|
||||
putc ('\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#error CPU undefined
|
||||
#endif
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int checkcpu (void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
ulong clock = gd->cpu_clk;
|
||||
uint immr = get_immr (0); /* Return full IMMR contents */
|
||||
uint pvr = get_pvr ();
|
||||
|
||||
puts ("CPU: ");
|
||||
|
||||
/* 850 has PARTNUM 20 */
|
||||
/* 801 has PARTNUM 10 */
|
||||
return check_CPU (clock, pvr, immr);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* L1 i-cache */
|
||||
/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB) */
|
||||
/* the 860 P (plus) has 256 sets of 16 bytes in 4 ways (= 16 kB) */
|
||||
|
||||
int checkicache (void)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *) CFG_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
u32 cacheon = rd_ic_cst () & IDC_ENABLED;
|
||||
|
||||
#ifdef CONFIG_IP860
|
||||
u32 k = memctl->memc_br1 & ~0x00007fff; /* probe in flash memoryarea */
|
||||
#else
|
||||
u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
|
||||
#endif
|
||||
u32 m;
|
||||
u32 lines = -1;
|
||||
|
||||
wr_ic_cst (IDC_UNALL);
|
||||
wr_ic_cst (IDC_INVALL);
|
||||
wr_ic_cst (IDC_DISABLE);
|
||||
__asm__ volatile ("isync");
|
||||
|
||||
while (!((m = rd_ic_cst ()) & IDC_CERR2)) {
|
||||
wr_ic_adr (k);
|
||||
wr_ic_cst (IDC_LDLCK);
|
||||
__asm__ volatile ("isync");
|
||||
|
||||
lines++;
|
||||
k += 0x10; /* the number of bytes in a cacheline */
|
||||
}
|
||||
|
||||
wr_ic_cst (IDC_UNALL);
|
||||
wr_ic_cst (IDC_INVALL);
|
||||
|
||||
if (cacheon)
|
||||
wr_ic_cst (IDC_ENABLE);
|
||||
else
|
||||
wr_ic_cst (IDC_DISABLE);
|
||||
|
||||
__asm__ volatile ("isync");
|
||||
|
||||
return lines << 4;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* L1 d-cache */
|
||||
/* the standard 860 has 128 sets of 16 bytes in 2 ways (= 4 kB) */
|
||||
/* the 860 P (plus) has 256 sets of 16 bytes in 2 ways (= 8 kB) */
|
||||
/* call with cache disabled */
|
||||
|
||||
int checkdcache (void)
|
||||
{
|
||||
volatile immap_t *immap = (immap_t *) CFG_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
u32 cacheon = rd_dc_cst () & IDC_ENABLED;
|
||||
|
||||
#ifdef CONFIG_IP860
|
||||
u32 k = memctl->memc_br1 & ~0x00007fff; /* probe in flash memoryarea */
|
||||
#else
|
||||
u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
|
||||
#endif
|
||||
u32 m;
|
||||
u32 lines = -1;
|
||||
|
||||
wr_dc_cst (IDC_UNALL);
|
||||
wr_dc_cst (IDC_INVALL);
|
||||
wr_dc_cst (IDC_DISABLE);
|
||||
|
||||
while (!((m = rd_dc_cst ()) & IDC_CERR2)) {
|
||||
wr_dc_adr (k);
|
||||
wr_dc_cst (IDC_LDLCK);
|
||||
lines++;
|
||||
k += 0x10; /* the number of bytes in a cacheline */
|
||||
}
|
||||
|
||||
wr_dc_cst (IDC_UNALL);
|
||||
wr_dc_cst (IDC_INVALL);
|
||||
|
||||
if (cacheon)
|
||||
wr_dc_cst (IDC_ENABLE);
|
||||
else
|
||||
wr_dc_cst (IDC_DISABLE);
|
||||
|
||||
return lines << 4;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void upmconfig (uint upm, uint * table, uint size)
|
||||
{
|
||||
uint i;
|
||||
uint addr = 0;
|
||||
volatile immap_t *immap = (immap_t *) CFG_IMMR;
|
||||
volatile memctl8xx_t *memctl = &immap->im_memctl;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
memctl->memc_mdr = table[i]; /* (16-15) */
|
||||
memctl->memc_mcr = addr | upm; /* (16-16) */
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int do_reset (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc,
|
||||
char *argv[])
|
||||
{
|
||||
ulong msr, addr;
|
||||
|
||||
volatile immap_t *immap = (immap_t *) CFG_IMMR;
|
||||
|
||||
immap->im_clkrst.car_plprcr |= PLPRCR_CSR; /* Checkstop Reset enable */
|
||||
|
||||
/* Interrupts and MMU off */
|
||||
__asm__ volatile ("mtspr 81, 0");
|
||||
__asm__ volatile ("mfmsr %0":"=r" (msr));
|
||||
|
||||
msr &= ~0x1030;
|
||||
__asm__ volatile ("mtmsr %0"::"r" (msr));
|
||||
|
||||
/*
|
||||
* Trying to execute the next instruction at a non-existing address
|
||||
* should cause a machine check, resulting in reset
|
||||
*/
|
||||
#ifdef CFG_RESET_ADDRESS
|
||||
addr = CFG_RESET_ADDRESS;
|
||||
#else
|
||||
/*
|
||||
* note: when CFG_MONITOR_BASE points to a RAM address, CFG_MONITOR_BASE
|
||||
* - sizeof (ulong) is usually a valid address. Better pick an address
|
||||
* known to be invalid on your system and assign it to CFG_RESET_ADDRESS.
|
||||
* "(ulong)-1" used to be a good choice for many systems...
|
||||
*/
|
||||
addr = CFG_MONITOR_BASE - sizeof (ulong);
|
||||
#endif
|
||||
((void (*)(void)) addr) ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Get timebase clock frequency (like cpu_clk in Hz)
|
||||
*
|
||||
* See table 15-5 pp. 15-16, and SCCR[RTSEL] pp. 15-27.
|
||||
*/
|
||||
unsigned long get_tbclk (void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
volatile immap_t *immr = (volatile immap_t *) CFG_IMMR;
|
||||
ulong oscclk, factor;
|
||||
|
||||
if (immr->im_clkrst.car_sccr & SCCR_TBS) {
|
||||
return (gd->cpu_clk / 16);
|
||||
}
|
||||
|
||||
factor = (((CFG_PLPRCR) & PLPRCR_MF_MSK) >> PLPRCR_MF_SHIFT) + 1;
|
||||
|
||||
oscclk = gd->cpu_clk / factor;
|
||||
|
||||
if ((immr->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
|
||||
return (oscclk / 4);
|
||||
}
|
||||
return (oscclk / 16);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(CONFIG_WATCHDOG)
|
||||
void watchdog_reset (void)
|
||||
{
|
||||
int re_enable = disable_interrupts ();
|
||||
|
||||
reset_8xx_watchdog ((immap_t *) CFG_IMMR);
|
||||
if (re_enable)
|
||||
enable_interrupts ();
|
||||
}
|
||||
|
||||
void reset_8xx_watchdog (volatile immap_t * immr)
|
||||
{
|
||||
# if defined(CONFIG_LWMON)
|
||||
/*
|
||||
* The LWMON board uses a MAX6301 Watchdog
|
||||
* with the trigger pin connected to port PA.7
|
||||
*
|
||||
* (The old board version used a MAX706TESA Watchdog, which
|
||||
* had to be handled exactly the same.)
|
||||
*/
|
||||
# define WATCHDOG_BIT 0x0100
|
||||
immr->im_ioport.iop_papar &= ~(WATCHDOG_BIT); /* GPIO */
|
||||
immr->im_ioport.iop_padir |= WATCHDOG_BIT; /* Output */
|
||||
immr->im_ioport.iop_paodr &= ~(WATCHDOG_BIT); /* active output */
|
||||
|
||||
immr->im_ioport.iop_padat ^= WATCHDOG_BIT; /* Toggle WDI */
|
||||
# else
|
||||
/*
|
||||
* All other boards use the MPC8xx Internal Watchdog
|
||||
*/
|
||||
immr->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */
|
||||
immr->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */
|
||||
# endif /* CONFIG_LWMON */
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WATCHDOG */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
710
cpu/mpc8xx/fec.c
Normal file
710
cpu/mpc8xx/fec.c
Normal file
@@ -0,0 +1,710 @@
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <commproc.h>
|
||||
#include <net.h>
|
||||
#include <command.h>
|
||||
|
||||
#undef ET_DEBUG
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET)
|
||||
|
||||
#ifdef CFG_DISCOVER_PHY
|
||||
#include <miiphy.h>
|
||||
static void mii_discover_phy(void);
|
||||
#endif
|
||||
|
||||
/* Ethernet Transmit and Receive Buffers */
|
||||
#define DBUF_LENGTH 1520
|
||||
|
||||
#define TX_BUF_CNT 2
|
||||
|
||||
#define TOUT_LOOP 100
|
||||
|
||||
#define PKT_MAXBUF_SIZE 1518
|
||||
#define PKT_MINBUF_SIZE 64
|
||||
#define PKT_MAXBLR_SIZE 1520
|
||||
|
||||
|
||||
static char txbuf[DBUF_LENGTH];
|
||||
|
||||
static uint rxIdx; /* index of the current RX buffer */
|
||||
static uint txIdx; /* index of the current TX buffer */
|
||||
|
||||
/*
|
||||
* FEC Ethernet Tx and Rx buffer descriptors allocated at the
|
||||
* immr->udata_bd address on Dual-Port RAM
|
||||
* Provide for Double Buffering
|
||||
*/
|
||||
|
||||
typedef volatile struct CommonBufferDescriptor {
|
||||
cbd_t rxbd[PKTBUFSRX]; /* Rx BD */
|
||||
cbd_t txbd[TX_BUF_CNT]; /* Tx BD */
|
||||
} RTXBD;
|
||||
|
||||
static RTXBD *rtx = NULL;
|
||||
|
||||
static int fec_send(struct eth_device* dev, volatile void *packet, int length);
|
||||
static int fec_recv(struct eth_device* dev);
|
||||
static int fec_init(struct eth_device* dev, bd_t * bd);
|
||||
static void fec_halt(struct eth_device* dev);
|
||||
|
||||
int fec_initialize(bd_t *bis)
|
||||
{
|
||||
struct eth_device* dev;
|
||||
|
||||
dev = (struct eth_device*) malloc(sizeof *dev);
|
||||
|
||||
sprintf(dev->name, "FEC ETHERNET");
|
||||
dev->iobase = 0;
|
||||
dev->priv = 0;
|
||||
dev->init = fec_init;
|
||||
dev->halt = fec_halt;
|
||||
dev->send = fec_send;
|
||||
dev->recv = fec_recv;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int fec_send(struct eth_device* dev, volatile void *packet, int length)
|
||||
{
|
||||
int j, rc;
|
||||
volatile immap_t *immr = (immap_t *) CFG_IMMR;
|
||||
volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
|
||||
|
||||
/* section 16.9.23.3
|
||||
* Wait for ready
|
||||
*/
|
||||
j = 0;
|
||||
while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
|
||||
udelay(1);
|
||||
j++;
|
||||
}
|
||||
if (j>=TOUT_LOOP) {
|
||||
printf("TX not ready\n");
|
||||
}
|
||||
|
||||
rtx->txbd[txIdx].cbd_bufaddr = (uint)packet;
|
||||
rtx->txbd[txIdx].cbd_datlen = length;
|
||||
rtx->txbd[txIdx].cbd_sc |= BD_ENET_TX_READY | BD_ENET_TX_LAST;
|
||||
__asm__ ("eieio");
|
||||
|
||||
/* Activate transmit Buffer Descriptor polling */
|
||||
fecp->fec_x_des_active = 0x01000000; /* Descriptor polling active */
|
||||
|
||||
j = 0;
|
||||
while ((rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_READY) && (j<TOUT_LOOP)) {
|
||||
#if defined(CONFIG_ICU862)
|
||||
udelay(10);
|
||||
#else
|
||||
udelay(1);
|
||||
#endif
|
||||
j++;
|
||||
}
|
||||
if (j>=TOUT_LOOP) {
|
||||
printf("TX timeout\n");
|
||||
}
|
||||
#ifdef ET_DEBUG
|
||||
printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n",
|
||||
__FILE__,__LINE__,__FUNCTION__,j,rtx->txbd[txIdx].cbd_sc,
|
||||
(rtx->txbd[txIdx].cbd_sc & 0x003C)>>2);
|
||||
#endif
|
||||
/* return only status bits */;
|
||||
rc = (rtx->txbd[txIdx].cbd_sc & BD_ENET_TX_STATS);
|
||||
|
||||
txIdx = (txIdx + 1) % TX_BUF_CNT;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int fec_recv(struct eth_device* dev)
|
||||
{
|
||||
int length;
|
||||
volatile immap_t *immr = (immap_t *) CFG_IMMR;
|
||||
volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
|
||||
|
||||
for (;;) {
|
||||
/* section 16.9.23.2 */
|
||||
if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
|
||||
length = -1;
|
||||
break; /* nothing received - leave for() loop */
|
||||
}
|
||||
|
||||
length = rtx->rxbd[rxIdx].cbd_datlen;
|
||||
|
||||
if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) {
|
||||
#ifdef ET_DEBUG
|
||||
printf("%s[%d] err: %x\n",
|
||||
__FUNCTION__,__LINE__,rtx->rxbd[rxIdx].cbd_sc);
|
||||
#endif
|
||||
} else {
|
||||
/* Pass the packet up to the protocol layers. */
|
||||
NetReceive(NetRxPackets[rxIdx], length - 4);
|
||||
}
|
||||
|
||||
/* Give the buffer back to the FEC. */
|
||||
rtx->rxbd[rxIdx].cbd_datlen = 0;
|
||||
|
||||
/* wrap around buffer index when necessary */
|
||||
if ((rxIdx + 1) >= PKTBUFSRX) {
|
||||
rtx->rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
|
||||
rxIdx = 0;
|
||||
} else {
|
||||
rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
|
||||
rxIdx++;
|
||||
}
|
||||
|
||||
__asm__ ("eieio");
|
||||
|
||||
/* Try to fill Buffer Descriptors */
|
||||
fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* FEC Ethernet Initialization Routine
|
||||
*
|
||||
*************************************************************/
|
||||
|
||||
#define FEC_ECNTRL_PINMUX 0x00000004
|
||||
#define FEC_ECNTRL_ETHER_EN 0x00000002
|
||||
#define FEC_ECNTRL_RESET 0x00000001
|
||||
|
||||
#define FEC_RCNTRL_BC_REJ 0x00000010
|
||||
#define FEC_RCNTRL_PROM 0x00000008
|
||||
#define FEC_RCNTRL_MII_MODE 0x00000004
|
||||
#define FEC_RCNTRL_DRT 0x00000002
|
||||
#define FEC_RCNTRL_LOOP 0x00000001
|
||||
|
||||
#define FEC_TCNTRL_FDEN 0x00000004
|
||||
#define FEC_TCNTRL_HBC 0x00000002
|
||||
#define FEC_TCNTRL_GTS 0x00000001
|
||||
|
||||
#define FEC_RESET_DELAY 50
|
||||
|
||||
static int fec_init(struct eth_device* dev, bd_t * bd)
|
||||
{
|
||||
|
||||
int i;
|
||||
volatile immap_t *immr = (immap_t *) CFG_IMMR;
|
||||
volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
|
||||
|
||||
#if defined(CONFIG_FADS) && defined(CONFIG_MPC860T)
|
||||
/* configure FADS for fast (FEC) ethernet, half-duplex */
|
||||
/* The LXT970 needs about 50ms to recover from reset, so
|
||||
* wait for it by discovering the PHY before leaving eth_init().
|
||||
*/
|
||||
{
|
||||
volatile uint *bcsr4 = (volatile uint *) BCSR4;
|
||||
*bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1))
|
||||
| (BCSR4_FETHCFG0 | BCSR4_FETHFDE | BCSR4_FETHRST);
|
||||
|
||||
/* reset the LXT970 PHY */
|
||||
*bcsr4 &= ~BCSR4_FETHRST;
|
||||
udelay (10);
|
||||
*bcsr4 |= BCSR4_FETHRST;
|
||||
udelay (10);
|
||||
}
|
||||
#endif
|
||||
/* Whack a reset.
|
||||
* A delay is required between a reset of the FEC block and
|
||||
* initialization of other FEC registers because the reset takes
|
||||
* some time to complete. If you don't delay, subsequent writes
|
||||
* to FEC registers might get killed by the reset routine which is
|
||||
* still in progress.
|
||||
*/
|
||||
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
|
||||
for (i = 0;
|
||||
(fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
|
||||
++i) {
|
||||
udelay (1);
|
||||
}
|
||||
if (i == FEC_RESET_DELAY) {
|
||||
printf ("FEC_RESET_DELAY timeout\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We use strictly polling mode only
|
||||
*/
|
||||
fecp->fec_imask = 0;
|
||||
|
||||
/* Clear any pending interrupt
|
||||
*/
|
||||
fecp->fec_ievent = 0xffc0;
|
||||
|
||||
/* No need to set the IVEC register */
|
||||
|
||||
/* Set station address
|
||||
*/
|
||||
#define ea eth_get_dev()->enetaddr
|
||||
fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) |
|
||||
(ea[2] << 8) | (ea[3] ) ;
|
||||
fecp->fec_addr_high = (ea[4] << 8) | (ea[5] ) ;
|
||||
#undef ea
|
||||
|
||||
/* Clear multicast address hash table
|
||||
*/
|
||||
fecp->fec_hash_table_high = 0;
|
||||
fecp->fec_hash_table_low = 0;
|
||||
|
||||
/* Set maximum receive buffer size.
|
||||
*/
|
||||
fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
|
||||
|
||||
/* Set maximum frame length
|
||||
*/
|
||||
fecp->fec_r_hash = PKT_MAXBUF_SIZE;
|
||||
|
||||
/*
|
||||
* Setup Buffers and Buffer Desriptors
|
||||
*/
|
||||
rxIdx = 0;
|
||||
txIdx = 0;
|
||||
|
||||
if (!rtx) {
|
||||
#ifdef CFG_ALLOC_DPRAM
|
||||
rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + dpram_alloc_align(sizeof(RTXBD),8));
|
||||
#else
|
||||
rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* Setup Receiver Buffer Descriptors (13.14.24.18)
|
||||
* Settings:
|
||||
* Empty, Wrap
|
||||
*/
|
||||
for (i = 0; i < PKTBUFSRX; i++) {
|
||||
rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
|
||||
rtx->rxbd[i].cbd_datlen = 0; /* Reset */
|
||||
rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i];
|
||||
}
|
||||
rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
|
||||
|
||||
/*
|
||||
* Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
|
||||
* Settings:
|
||||
* Last, Tx CRC
|
||||
*/
|
||||
for (i = 0; i < TX_BUF_CNT; i++) {
|
||||
rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC;
|
||||
rtx->txbd[i].cbd_datlen = 0; /* Reset */
|
||||
rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]);
|
||||
}
|
||||
rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
|
||||
|
||||
/* Set receive and transmit descriptor base
|
||||
*/
|
||||
fecp->fec_r_des_start = (unsigned int) (&rtx->rxbd[0]);
|
||||
fecp->fec_x_des_start = (unsigned int) (&rtx->txbd[0]);
|
||||
|
||||
/* Enable MII mode
|
||||
*/
|
||||
#if 0 /* Full duplex mode */
|
||||
fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE;
|
||||
fecp->fec_x_cntrl = FEC_TCNTRL_FDEN;
|
||||
#else /* Half duplex mode */
|
||||
fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT;
|
||||
fecp->fec_x_cntrl = 0;
|
||||
#endif
|
||||
|
||||
/* Enable big endian and don't care about SDMA FC.
|
||||
*/
|
||||
fecp->fec_fun_code = 0x78000000;
|
||||
|
||||
/* Set MII speed to 2.5 MHz or slightly below.
|
||||
* According to the MPC860T (Rev. D) Fast ethernet controller user
|
||||
* manual (6.2.14),
|
||||
* the MII management interface clock must be less than or equal
|
||||
* to 2.5 MHz.
|
||||
* This MDC frequency is equal to system clock / (2 * MII_SPEED).
|
||||
* Then MII_SPEED = system_clock / 2 * 2,5 Mhz.
|
||||
*/
|
||||
fecp->fec_mii_speed = ((bd->bi_busfreq + 4999999) / 5000000) << 1;
|
||||
|
||||
#if !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
|
||||
/* Configure all of port D for MII.
|
||||
*/
|
||||
immr->im_ioport.iop_pdpar = 0x1fff;
|
||||
|
||||
/* Bits moved from Rev. D onward */
|
||||
if ((get_immr (0) & 0xffff) < 0x0501) {
|
||||
immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
|
||||
} else {
|
||||
immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
|
||||
}
|
||||
#else
|
||||
/* Configure port A for MII.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ICU862) && defined(CFG_DISCOVER_PHY)
|
||||
|
||||
/* On the ICU862 board the MII-MDC pin is routed to PD8 pin
|
||||
* of CPU, so for this board we need to configure Utopia and
|
||||
* enable PD8 to MII-MDC function */
|
||||
immr->im_ioport.iop_pdpar |= 0x4080;
|
||||
#endif
|
||||
|
||||
/* Has Utopia been configured? */
|
||||
if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
|
||||
/*
|
||||
* YES - Use MUXED mode for UTOPIA bus.
|
||||
* This frees Port A for use by MII (see 862UM table 41-6).
|
||||
*/
|
||||
immr->im_ioport.utmode &= ~0x80;
|
||||
} else {
|
||||
/*
|
||||
* NO - set SPLIT mode for UTOPIA bus.
|
||||
*
|
||||
* This doesn't really effect UTOPIA (which isn't
|
||||
* enabled anyway) but just tells the 862
|
||||
* to use port A for MII (see 862UM table 41-6).
|
||||
*/
|
||||
immr->im_ioport.utmode |= 0x80;
|
||||
}
|
||||
#endif /* !defined(CONFIG_ICU862) */
|
||||
|
||||
rxIdx = 0;
|
||||
txIdx = 0;
|
||||
|
||||
/* Now enable the transmit and receive processing
|
||||
*/
|
||||
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
|
||||
|
||||
#ifdef CFG_DISCOVER_PHY
|
||||
/* wait for the PHY to wake up after reset
|
||||
*/
|
||||
mii_discover_phy();
|
||||
#endif
|
||||
|
||||
/* And last, try to fill Rx Buffer Descriptors */
|
||||
fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void fec_halt(struct eth_device* dev)
|
||||
{
|
||||
#if 0
|
||||
volatile immap_t *immr = (immap_t *)CFG_IMMR;
|
||||
immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
void restart(void)
|
||||
{
|
||||
volatile immap_t *immr = (immap_t *)CFG_IMMR;
|
||||
immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CFG_DISCOVER_PHY) || (CONFIG_COMMANDS & CFG_CMD_MII)
|
||||
|
||||
static int phyaddr = -1; /* didn't find a PHY yet */
|
||||
static uint phytype;
|
||||
|
||||
/* Make MII read/write commands for the FEC.
|
||||
*/
|
||||
|
||||
#define mk_mii_read(ADDR, REG) (0x60020000 | ((ADDR << 23) | \
|
||||
(REG & 0x1f) << 18))
|
||||
|
||||
#define mk_mii_write(ADDR, REG, VAL) (0x50020000 | ((ADDR << 23) | \
|
||||
(REG & 0x1f) << 18) | \
|
||||
(VAL & 0xffff))
|
||||
|
||||
/* Interrupt events/masks.
|
||||
*/
|
||||
#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
|
||||
#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
|
||||
#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
|
||||
#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
|
||||
#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */
|
||||
#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
|
||||
#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */
|
||||
#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
|
||||
#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
|
||||
#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
|
||||
|
||||
/* PHY identification
|
||||
*/
|
||||
#define PHY_ID_LXT970 0x78100000 /* LXT970 */
|
||||
#define PHY_ID_LXT971 0x001378e0 /* LXT971 and 972 */
|
||||
#define PHY_ID_82555 0x02a80150 /* Intel 82555 */
|
||||
#define PHY_ID_QS6612 0x01814400 /* QS6612 */
|
||||
#define PHY_ID_AMD79C784 0x00225610 /* AMD 79C784 */
|
||||
#define PHY_ID_LSI80225 0x0016f870 /* LSI 80225 */
|
||||
#define PHY_ID_LSI80225B 0x0016f880 /* LSI 80225/B */
|
||||
|
||||
|
||||
/* send command to phy using mii, wait for result */
|
||||
static uint
|
||||
mii_send(uint mii_cmd)
|
||||
{
|
||||
uint mii_reply;
|
||||
volatile fec_t *ep;
|
||||
|
||||
ep = &(((immap_t *)CFG_IMMR)->im_cpm.cp_fec);
|
||||
|
||||
ep->fec_mii_data = mii_cmd; /* command to phy */
|
||||
|
||||
/* wait for mii complete */
|
||||
while (!(ep->fec_ievent & FEC_ENET_MII))
|
||||
; /* spin until done */
|
||||
mii_reply = ep->fec_mii_data; /* result from phy */
|
||||
ep->fec_ievent = FEC_ENET_MII; /* clear MII complete */
|
||||
#if 0
|
||||
printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
|
||||
__FILE__,__LINE__,__FUNCTION__,mii_cmd,mii_reply);
|
||||
#endif
|
||||
return (mii_reply & 0xffff); /* data read from phy */
|
||||
}
|
||||
#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CFG_CMD_MII) */
|
||||
|
||||
#if defined(CFG_DISCOVER_PHY)
|
||||
static void
|
||||
mii_discover_phy(void)
|
||||
{
|
||||
#define MAX_PHY_PASSES 11
|
||||
uint phyno;
|
||||
int pass;
|
||||
|
||||
phyaddr = -1; /* didn't find a PHY yet */
|
||||
for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
|
||||
if (pass > 1) {
|
||||
/* PHY may need more time to recover from reset.
|
||||
* The LXT970 needs 50ms typical, no maximum is
|
||||
* specified, so wait 10ms before try again.
|
||||
* With 11 passes this gives it 100ms to wake up.
|
||||
*/
|
||||
udelay(10000); /* wait 10ms */
|
||||
}
|
||||
for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
|
||||
phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR1));
|
||||
#ifdef ET_DEBUG
|
||||
printf("PHY type 0x%x pass %d type ", phytype, pass);
|
||||
#endif
|
||||
if (phytype != 0xffff) {
|
||||
phyaddr = phyno;
|
||||
phytype <<= 16;
|
||||
phytype |= mii_send(mk_mii_read(phyno,
|
||||
PHY_PHYIDR2));
|
||||
|
||||
#ifdef ET_DEBUG
|
||||
printf("PHY @ 0x%x pass %d type ",phyno,pass);
|
||||
switch (phytype & 0xfffffff0) {
|
||||
case PHY_ID_LXT970:
|
||||
printf("LXT970\n");
|
||||
break;
|
||||
case PHY_ID_LXT971:
|
||||
printf("LXT971\n");
|
||||
break;
|
||||
case PHY_ID_82555:
|
||||
printf("82555\n");
|
||||
break;
|
||||
case PHY_ID_QS6612:
|
||||
printf("QS6612\n");
|
||||
break;
|
||||
case PHY_ID_AMD79C784:
|
||||
printf("AMD79C784\n");
|
||||
break;
|
||||
case PHY_ID_LSI80225B:
|
||||
printf("LSI L80225/B\n");
|
||||
break;
|
||||
default:
|
||||
printf("0x%08x\n", phytype);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
if (phyaddr < 0) {
|
||||
printf("No PHY device found.\n");
|
||||
}
|
||||
}
|
||||
#endif /* CFG_DISCOVER_PHY */
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)
|
||||
|
||||
static int mii_init_done = 0;
|
||||
|
||||
/****************************************************************************
|
||||
* mii_init -- Initialize the MII for MII command without ethernet
|
||||
* This function is a subset of eth_init
|
||||
****************************************************************************
|
||||
*/
|
||||
void mii_init (void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
volatile immap_t *immr = (immap_t *) CFG_IMMR;
|
||||
volatile fec_t *fecp = &(immr->im_cpm.cp_fec);
|
||||
int i;
|
||||
|
||||
if (mii_init_done != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Whack a reset.
|
||||
* A delay is required between a reset of the FEC block and
|
||||
* initialization of other FEC registers because the reset takes
|
||||
* some time to complete. If you don't delay, subsequent writes
|
||||
* to FEC registers might get killed by the reset routine which is
|
||||
* still in progress.
|
||||
*/
|
||||
|
||||
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET;
|
||||
for (i = 0;
|
||||
(fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY);
|
||||
++i) {
|
||||
udelay (1);
|
||||
}
|
||||
if (i == FEC_RESET_DELAY) {
|
||||
printf ("FEC_RESET_DELAY timeout\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* We use strictly polling mode only
|
||||
*/
|
||||
fecp->fec_imask = 0;
|
||||
|
||||
/* Clear any pending interrupt
|
||||
*/
|
||||
fecp->fec_ievent = 0xffc0;
|
||||
|
||||
/* Set MII speed to 2.5 MHz or slightly below.
|
||||
* According to the MPC860T (Rev. D) Fast ethernet controller user
|
||||
* manual (6.2.14),
|
||||
* the MII management interface clock must be less than or equal
|
||||
* to 2.5 MHz.
|
||||
* This MDC frequency is equal to system clock / (2 * MII_SPEED).
|
||||
* Then MII_SPEED = system_clock / 2 * 2,5 Mhz.
|
||||
*/
|
||||
fecp->fec_mii_speed = ((bd->bi_busfreq + 4999999) / 5000000) << 1;
|
||||
|
||||
#if !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210)
|
||||
/* Configure all of port D for MII.
|
||||
*/
|
||||
immr->im_ioport.iop_pdpar = 0x1fff;
|
||||
|
||||
/* Bits moved from Rev. D onward */
|
||||
if ((get_immr (0) & 0xffff) < 0x0501) {
|
||||
immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
|
||||
} else {
|
||||
immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
|
||||
}
|
||||
#else
|
||||
/* Configure port A for MII.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_ICU862)
|
||||
|
||||
/* On the ICU862 board the MII-MDC pin is routed to PD8 pin
|
||||
* of CPU, so for this board we need to configure Utopia and
|
||||
* enable PD8 to MII-MDC function */
|
||||
immr->im_ioport.iop_pdpar |= 0x4080;
|
||||
#endif
|
||||
|
||||
/* Has Utopia been configured? */
|
||||
if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) {
|
||||
/*
|
||||
* YES - Use MUXED mode for UTOPIA bus.
|
||||
* This frees Port A for use by MII (see 862UM table 41-6).
|
||||
*/
|
||||
immr->im_ioport.utmode &= ~0x80;
|
||||
} else {
|
||||
/*
|
||||
* NO - set SPLIT mode for UTOPIA bus.
|
||||
*
|
||||
* This doesn't really effect UTOPIA (which isn't
|
||||
* enabled anyway) but just tells the 862
|
||||
* to use port A for MII (see 862UM table 41-6).
|
||||
*/
|
||||
immr->im_ioport.utmode |= 0x80;
|
||||
}
|
||||
#endif /* !defined(CONFIG_ICU862) */
|
||||
/* Now enable the transmit and receive processing
|
||||
*/
|
||||
fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN;
|
||||
|
||||
mii_init_done = 1;
|
||||
}
|
||||
/*****************************************************************************
|
||||
* Read and write a MII PHY register, routines used by MII Utilities
|
||||
*
|
||||
* FIXME: These routines are expected to return 0 on success, but mii_send
|
||||
* does _not_ return an error code. Maybe 0xFFFF means error, i.e.
|
||||
* no PHY connected...
|
||||
* For now always return 0.
|
||||
* FIXME: These routines only work after calling eth_init() at least once!
|
||||
* Otherwise they hang in mii_send() !!! Sorry!
|
||||
*****************************************************************************/
|
||||
|
||||
int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
|
||||
{
|
||||
short rdreg; /* register working value */
|
||||
|
||||
#ifdef MII_DEBUG
|
||||
printf ("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
|
||||
#endif
|
||||
rdreg = mii_send(mk_mii_read(addr, reg));
|
||||
|
||||
*value = rdreg;
|
||||
|
||||
#ifdef MII_DEBUG
|
||||
printf ("0x%04x\n", *value);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)
|
||||
{
|
||||
short rdreg; /* register working value */
|
||||
|
||||
#ifdef MII_DEBUG
|
||||
printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
|
||||
#endif
|
||||
|
||||
rdreg = mii_send(mk_mii_write(addr, reg, value));
|
||||
|
||||
#ifdef MII_DEBUG
|
||||
printf ("0x%04x\n", value);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)*/
|
||||
|
||||
#endif /* CFG_CMD_NET, FEC_ENET */
|
||||
571
cpu/mpc8xx/spi.c
Normal file
571
cpu/mpc8xx/spi.c
Normal file
@@ -0,0 +1,571 @@
|
||||
/*
|
||||
* Copyright (c) 2001 Navin Boppuri / Prashant Patel
|
||||
* <nboppuri@trinetcommunication.com>,
|
||||
* <pmpatel@trinetcommunication.com>
|
||||
* Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
|
||||
* Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* MPC8xx CPM SPI interface.
|
||||
*
|
||||
* Parts of this code are probably not portable and/or specific to
|
||||
* the board which I used for the tests. Please send fixes/complaints
|
||||
* to wd@denx.de
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mpc8xx.h>
|
||||
#include <commproc.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <malloc.h>
|
||||
#include <post.h>
|
||||
#include <net.h>
|
||||
|
||||
#if (defined(CONFIG_SPI)) || (CONFIG_POST & CFG_POST_SPI)
|
||||
|
||||
/* Warning:
|
||||
* You cannot enable DEBUG for early system initalization, i. e. when
|
||||
* this driver is used to read environment parameters like "baudrate"
|
||||
* from EEPROM which are used to initialize the serial port which is
|
||||
* needed to print the debug messages...
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#define SPI_EEPROM_WREN 0x06
|
||||
#define SPI_EEPROM_RDSR 0x05
|
||||
#define SPI_EEPROM_READ 0x03
|
||||
#define SPI_EEPROM_WRITE 0x02
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* Offset for initial SPI buffers in DPRAM:
|
||||
* We need a 520 byte scratch DPRAM area to use at an early stage.
|
||||
* It is used between the two initialization calls (spi_init_f()
|
||||
* and spi_init_r()).
|
||||
* The value 0xb00 makes it far enough from the start of the data
|
||||
* area (as well as from the stack pointer).
|
||||
* --------------------------------------------------------------- */
|
||||
#ifndef CFG_SPI_INIT_OFFSET
|
||||
#define CFG_SPI_INIT_OFFSET 0xB00
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define DPRINT(a) printf a;
|
||||
/* -----------------------------------------------
|
||||
* Helper functions to peek into tx and rx buffers
|
||||
* ----------------------------------------------- */
|
||||
static const char * const hex_digit = "0123456789ABCDEF";
|
||||
|
||||
static char quickhex (int i)
|
||||
{
|
||||
return hex_digit[i];
|
||||
}
|
||||
|
||||
static void memdump (void *pv, int num)
|
||||
{
|
||||
int i;
|
||||
unsigned char *pc = (unsigned char *) pv;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
|
||||
printf ("\t");
|
||||
for (i = 0; i < num; i++)
|
||||
printf ("%c", isprint (pc[i]) ? pc[i] : '.');
|
||||
printf ("\n");
|
||||
}
|
||||
#else /* !DEBUG */
|
||||
|
||||
#define DPRINT(a)
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/* -------------------
|
||||
* Function prototypes
|
||||
* ------------------- */
|
||||
void spi_init (void);
|
||||
|
||||
ssize_t spi_read (uchar *, int, uchar *, int);
|
||||
ssize_t spi_write (uchar *, int, uchar *, int);
|
||||
ssize_t spi_xfer (size_t);
|
||||
|
||||
/* -------------------
|
||||
* Variables
|
||||
* ------------------- */
|
||||
|
||||
#define MAX_BUFFER 0x104
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* Initially we place the RX and TX buffers at a fixed location in DPRAM!
|
||||
* ---------------------------------------------------------------------- */
|
||||
static uchar *rxbuf =
|
||||
(uchar *)&((cpm8xx_t *)&((immap_t *)CFG_IMMR)->im_cpm)->cp_dpmem
|
||||
[CFG_SPI_INIT_OFFSET];
|
||||
static uchar *txbuf =
|
||||
(uchar *)&((cpm8xx_t *)&((immap_t *)CFG_IMMR)->im_cpm)->cp_dpmem
|
||||
[CFG_SPI_INIT_OFFSET+MAX_BUFFER];
|
||||
|
||||
/* **************************************************************************
|
||||
*
|
||||
* Function: spi_init_f
|
||||
*
|
||||
* Description: Init SPI-Controller (ROM part)
|
||||
*
|
||||
* return: ---
|
||||
*
|
||||
* *********************************************************************** */
|
||||
void spi_init_f (void)
|
||||
{
|
||||
unsigned int dpaddr;
|
||||
|
||||
volatile spi_t *spi;
|
||||
volatile immap_t *immr;
|
||||
volatile cpic8xx_t *cpi;
|
||||
volatile cpm8xx_t *cp;
|
||||
volatile iop8xx_t *iop;
|
||||
volatile cbd_t *tbdf, *rbdf;
|
||||
|
||||
immr = (immap_t *) CFG_IMMR;
|
||||
cpi = (cpic8xx_t *)&immr->im_cpic;
|
||||
iop = (iop8xx_t *) &immr->im_ioport;
|
||||
cp = (cpm8xx_t *) &immr->im_cpm;
|
||||
|
||||
#ifdef CFG_SPI_UCODE_PATCH
|
||||
spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
|
||||
#else
|
||||
spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
|
||||
/* Disable relocation */
|
||||
spi->spi_rpbase = 0;
|
||||
#endif
|
||||
|
||||
/* 1 */
|
||||
/* ------------------------------------------------
|
||||
* Initialize Port B SPI pins -> page 34-8 MPC860UM
|
||||
* (we are only in Master Mode !)
|
||||
* ------------------------------------------------ */
|
||||
|
||||
/* --------------------------------------------
|
||||
* GPIO or per. Function
|
||||
* PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
|
||||
* PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
|
||||
* PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
|
||||
* PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
|
||||
* -------------------------------------------- */
|
||||
cp->cp_pbpar |= 0x0000000E; /* set bits */
|
||||
cp->cp_pbpar &= ~0x00000001; /* reset bit */
|
||||
|
||||
/* ----------------------------------------------
|
||||
* In/Out or per. Function 0/1
|
||||
* PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
|
||||
* PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
|
||||
* PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
|
||||
* PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
|
||||
* ---------------------------------------------- */
|
||||
cp->cp_pbdir |= 0x0000000F;
|
||||
|
||||
/* ----------------------------------------------
|
||||
* open drain or active output
|
||||
* PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
|
||||
* PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
|
||||
* PBODR[30] = 0 [0x00000002] -> active output: SPICLK
|
||||
* PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
|
||||
* ---------------------------------------------- */
|
||||
|
||||
cp->cp_pbodr |= 0x00000008;
|
||||
cp->cp_pbodr &= ~0x00000007;
|
||||
|
||||
/* Initialize the parameter ram.
|
||||
* We need to make sure many things are initialized to zero
|
||||
*/
|
||||
spi->spi_rstate = 0;
|
||||
spi->spi_rdp = 0;
|
||||
spi->spi_rbptr = 0;
|
||||
spi->spi_rbc = 0;
|
||||
spi->spi_rxtmp = 0;
|
||||
spi->spi_tstate = 0;
|
||||
spi->spi_tdp = 0;
|
||||
spi->spi_tbptr = 0;
|
||||
spi->spi_tbc = 0;
|
||||
spi->spi_txtmp = 0;
|
||||
|
||||
/* Allocate space for one transmit and one receive buffer
|
||||
* descriptor in the DP ram
|
||||
*/
|
||||
#ifdef CFG_ALLOC_DPRAM
|
||||
dpaddr = dpram_alloc_align (sizeof(cbd_t)*2, 8);
|
||||
#else
|
||||
dpaddr = CPM_SPI_BASE;
|
||||
#endif
|
||||
|
||||
/* 3 */
|
||||
/* Set up the SPI parameters in the parameter ram */
|
||||
spi->spi_rbase = dpaddr;
|
||||
spi->spi_tbase = dpaddr + sizeof (cbd_t);
|
||||
|
||||
/***********IMPORTANT******************/
|
||||
|
||||
/*
|
||||
* Setting transmit and receive buffer descriptor pointers
|
||||
* initially to rbase and tbase. Only the microcode patches
|
||||
* documentation talks about initializing this pointer. This
|
||||
* is missing from the sample I2C driver. If you dont
|
||||
* initialize these pointers, the kernel hangs.
|
||||
*/
|
||||
spi->spi_rbptr = spi->spi_rbase;
|
||||
spi->spi_tbptr = spi->spi_tbase;
|
||||
|
||||
/* 4 */
|
||||
#ifdef CFG_SPI_UCODE_PATCH
|
||||
/*
|
||||
* Initialize required parameters if using microcode patch.
|
||||
*/
|
||||
spi->spi_rstate = 0;
|
||||
spi->spi_tstate = 0;
|
||||
#else
|
||||
/* Init SPI Tx + Rx Parameters */
|
||||
while (cp->cp_cpcr & CPM_CR_FLG)
|
||||
;
|
||||
cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
|
||||
while (cp->cp_cpcr & CPM_CR_FLG)
|
||||
;
|
||||
#endif /* CFG_SPI_UCODE_PATCH */
|
||||
|
||||
/* 5 */
|
||||
/* Set SDMA configuration register */
|
||||
immr->im_siu_conf.sc_sdcr = 0x0001;
|
||||
|
||||
/* 6 */
|
||||
/* Set to big endian. */
|
||||
spi->spi_tfcr = SMC_EB;
|
||||
spi->spi_rfcr = SMC_EB;
|
||||
|
||||
/* 7 */
|
||||
/* Set maximum receive size. */
|
||||
spi->spi_mrblr = MAX_BUFFER;
|
||||
|
||||
/* 8 + 9 */
|
||||
/* tx and rx buffer descriptors */
|
||||
tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
|
||||
rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
|
||||
|
||||
tbdf->cbd_sc &= ~BD_SC_READY;
|
||||
rbdf->cbd_sc &= ~BD_SC_EMPTY;
|
||||
|
||||
/* Set the bd's rx and tx buffer address pointers */
|
||||
rbdf->cbd_bufaddr = (ulong) rxbuf;
|
||||
tbdf->cbd_bufaddr = (ulong) txbuf;
|
||||
|
||||
/* 10 + 11 */
|
||||
cp->cp_spim = 0; /* Mask all SPI events */
|
||||
cp->cp_spie = SPI_EMASK; /* Clear all SPI events */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
*
|
||||
* Function: spi_init_r
|
||||
*
|
||||
* Description: Init SPI-Controller (RAM part) -
|
||||
* The malloc engine is ready and we can move our buffers to
|
||||
* normal RAM
|
||||
*
|
||||
* return: ---
|
||||
*
|
||||
* *********************************************************************** */
|
||||
void spi_init_r (void)
|
||||
{
|
||||
volatile cpm8xx_t *cp;
|
||||
volatile spi_t *spi;
|
||||
volatile immap_t *immr;
|
||||
volatile cbd_t *tbdf, *rbdf;
|
||||
|
||||
immr = (immap_t *) CFG_IMMR;
|
||||
cp = (cpm8xx_t *) &immr->im_cpm;
|
||||
|
||||
#ifdef CFG_SPI_UCODE_PATCH
|
||||
spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
|
||||
#else
|
||||
spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
|
||||
/* Disable relocation */
|
||||
spi->spi_rpbase = 0;
|
||||
#endif
|
||||
|
||||
/* tx and rx buffer descriptors */
|
||||
tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
|
||||
rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
|
||||
|
||||
/* Allocate memory for RX and TX buffers */
|
||||
rxbuf = (uchar *) malloc (MAX_BUFFER);
|
||||
txbuf = (uchar *) malloc (MAX_BUFFER);
|
||||
|
||||
rbdf->cbd_bufaddr = (ulong) rxbuf;
|
||||
tbdf->cbd_bufaddr = (ulong) txbuf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: spi_write
|
||||
**************************************************************************** */
|
||||
ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(rxbuf, 0, MAX_BUFFER);
|
||||
memset(txbuf, 0, MAX_BUFFER);
|
||||
*txbuf = SPI_EEPROM_WREN; /* write enable */
|
||||
spi_xfer(1);
|
||||
memcpy(txbuf, addr, alen);
|
||||
*txbuf = SPI_EEPROM_WRITE; /* WRITE memory array */
|
||||
memcpy(alen + txbuf, buffer, len);
|
||||
spi_xfer(alen + len);
|
||||
/* ignore received data */
|
||||
for (i = 0; i < 1000; i++) {
|
||||
*txbuf = SPI_EEPROM_RDSR; /* read status */
|
||||
txbuf[1] = 0;
|
||||
spi_xfer(2);
|
||||
if (!(rxbuf[1] & 1)) {
|
||||
break;
|
||||
}
|
||||
udelay(1000);
|
||||
}
|
||||
if (i >= 1000) {
|
||||
printf ("*** spi_write: Time out while writing!\n");
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: spi_read
|
||||
**************************************************************************** */
|
||||
ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
|
||||
{
|
||||
memset(rxbuf, 0, MAX_BUFFER);
|
||||
memset(txbuf, 0, MAX_BUFFER);
|
||||
memcpy(txbuf, addr, alen);
|
||||
*txbuf = SPI_EEPROM_READ; /* READ memory array */
|
||||
|
||||
/*
|
||||
* There is a bug in 860T (?) that cuts the last byte of input
|
||||
* if we're reading into DPRAM. The solution we choose here is
|
||||
* to always read len+1 bytes (we have one extra byte at the
|
||||
* end of the buffer).
|
||||
*/
|
||||
spi_xfer(alen + len + 1);
|
||||
memcpy(buffer, alen + rxbuf, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: spi_xfer
|
||||
**************************************************************************** */
|
||||
ssize_t spi_xfer (size_t count)
|
||||
{
|
||||
volatile immap_t *immr;
|
||||
volatile cpm8xx_t *cp;
|
||||
volatile spi_t *spi;
|
||||
cbd_t *tbdf, *rbdf;
|
||||
ushort loop;
|
||||
int tm;
|
||||
|
||||
DPRINT (("*** spi_xfer entered ***\n"));
|
||||
|
||||
immr = (immap_t *) CFG_IMMR;
|
||||
cp = (cpm8xx_t *) &immr->im_cpm;
|
||||
|
||||
#ifdef CFG_SPI_UCODE_PATCH
|
||||
spi = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
|
||||
#else
|
||||
spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
|
||||
/* Disable relocation */
|
||||
spi->spi_rpbase = 0;
|
||||
#endif
|
||||
|
||||
tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
|
||||
rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
|
||||
|
||||
/* Set CS for device */
|
||||
cp->cp_pbdat &= ~0x0001;
|
||||
|
||||
/* Setting tx bd status and data length */
|
||||
tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
|
||||
tbdf->cbd_datlen = count;
|
||||
|
||||
DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
|
||||
tbdf->cbd_datlen));
|
||||
|
||||
/* Setting rx bd status and data length */
|
||||
rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
|
||||
rbdf->cbd_datlen = 0; /* rx length has no significance */
|
||||
|
||||
loop = cp->cp_spmode & SPMODE_LOOP;
|
||||
cp->cp_spmode = /*SPMODE_DIV16 |*/ /* BRG/16 mode not used here */
|
||||
loop |
|
||||
SPMODE_REV |
|
||||
SPMODE_MSTR |
|
||||
SPMODE_EN |
|
||||
SPMODE_LEN(8) | /* 8 Bits per char */
|
||||
SPMODE_PM(0x8) ; /* medium speed */
|
||||
cp->cp_spim = 0; /* Mask all SPI events */
|
||||
cp->cp_spie = SPI_EMASK; /* Clear all SPI events */
|
||||
|
||||
/* start spi transfer */
|
||||
DPRINT (("*** spi_xfer: Performing transfer ...\n"));
|
||||
cp->cp_spcom |= SPI_STR; /* Start transmit */
|
||||
|
||||
/* --------------------------------
|
||||
* Wait for SPI transmit to get out
|
||||
* or time out (1 second = 1000 ms)
|
||||
* -------------------------------- */
|
||||
for (tm=0; tm<1000; ++tm) {
|
||||
if (cp->cp_spie & SPI_TXB) { /* Tx Buffer Empty */
|
||||
DPRINT (("*** spi_xfer: Tx buffer empty\n"));
|
||||
break;
|
||||
}
|
||||
if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
|
||||
DPRINT (("*** spi_xfer: Tx BD done\n"));
|
||||
break;
|
||||
}
|
||||
udelay (1000);
|
||||
}
|
||||
if (tm >= 1000) {
|
||||
printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
|
||||
}
|
||||
DPRINT (("*** spi_xfer: ... transfer ended\n"));
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("\nspi_xfer: txbuf after xfer\n");
|
||||
memdump ((void *) txbuf, 16); /* dump of txbuf before transmit */
|
||||
printf ("spi_xfer: rxbuf after xfer\n");
|
||||
memdump ((void *) rxbuf, 16); /* dump of rxbuf after transmit */
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
/* Clear CS for device */
|
||||
cp->cp_pbdat |= 0x0001;
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif /* CONFIG_SPI || (CONFIG_POST & CFG_POST_SPI) */
|
||||
|
||||
/*
|
||||
* SPI test
|
||||
*
|
||||
* The Serial Peripheral Interface (SPI) is tested in the local loopback mode.
|
||||
* The interface is configured accordingly and several packets
|
||||
* are transfered. The configurable test parameters are:
|
||||
* TEST_MIN_LENGTH - minimum size of packet to transfer
|
||||
* TEST_MAX_LENGTH - maximum size of packet to transfer
|
||||
* TEST_NUM - number of tests
|
||||
*/
|
||||
|
||||
#if CONFIG_POST & CFG_POST_SPI
|
||||
|
||||
#define TEST_MIN_LENGTH 1
|
||||
#define TEST_MAX_LENGTH MAX_BUFFER
|
||||
#define TEST_NUM 1
|
||||
|
||||
static void packet_fill (char * packet, int length)
|
||||
{
|
||||
char c = (char) length;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
packet[i] = c++;
|
||||
}
|
||||
}
|
||||
|
||||
static int packet_check (char * packet, int length)
|
||||
{
|
||||
char c = (char) length;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
if (packet[i] != c++) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_post_test (int flags)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int res = -1;
|
||||
volatile immap_t *immr = (immap_t *) CFG_IMMR;
|
||||
volatile cpm8xx_t *cp = (cpm8xx_t *) &immr->im_cpm;
|
||||
int i;
|
||||
int l;
|
||||
|
||||
spi_init_f();
|
||||
spi_init_r();
|
||||
|
||||
cp->cp_spmode |= SPMODE_LOOP;
|
||||
|
||||
for (i = 0; i < TEST_NUM; i++)
|
||||
{
|
||||
for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8)
|
||||
{
|
||||
packet_fill(txbuf, l);
|
||||
|
||||
spi_xfer(l);
|
||||
|
||||
if (packet_check(rxbuf, l) < 0)
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res = 0;
|
||||
|
||||
Done:
|
||||
|
||||
cp->cp_spmode &= ~SPMODE_LOOP;
|
||||
|
||||
/*
|
||||
* SCC2 Ethernet parameter RAM space overlaps
|
||||
* the SPI parameter RAM space. So we need to restore
|
||||
* the SCC2 configuration if it is used by UART or Ethernet.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_8xx_CONS_SCC2)
|
||||
serial_init();
|
||||
#endif
|
||||
|
||||
#if defined(SCC_ENET) && (SCC_ENET == 1)
|
||||
eth_init(gd->bd);
|
||||
#endif
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
post_log("SPI test failed\n");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif /* CONFIG_POST & CFG_POST_SPI */
|
||||
867
cpu/ppc4xx/405gp_enet.c
Normal file
867
cpu/ppc4xx/405gp_enet.c
Normal file
@@ -0,0 +1,867 @@
|
||||
/*-----------------------------------------------------------------------------+
|
||||
*
|
||||
* This source code has been made available to you by IBM on an AS-IS
|
||||
* basis. Anyone receiving this source is licensed under IBM
|
||||
* copyrights to use it in any way he or she deems fit, including
|
||||
* copying it, modifying it, compiling it, and redistributing it either
|
||||
* with or without modifications. No license under IBM patents or
|
||||
* patent applications is to be implied by the copyright license.
|
||||
*
|
||||
* Any user of this software should understand that IBM cannot provide
|
||||
* technical support for this software and will not be responsible for
|
||||
* any consequences resulting from the use of this software.
|
||||
*
|
||||
* Any person who transfers this source code or any derivative work
|
||||
* must include the IBM copyright notice, this paragraph, and the
|
||||
* preceding two paragraphs in the transferred software.
|
||||
*
|
||||
* COPYRIGHT I B M CORPORATION 1995
|
||||
* LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
|
||||
*-----------------------------------------------------------------------------*/
|
||||
/*-----------------------------------------------------------------------------+
|
||||
*
|
||||
* File Name: enetemac.c
|
||||
*
|
||||
* Function: Device driver for the ethernet EMAC3 macro on the 405GP.
|
||||
*
|
||||
* Author: Mark Wisner
|
||||
*
|
||||
* Change Activity-
|
||||
*
|
||||
* Date Description of Change BY
|
||||
* --------- --------------------- ---
|
||||
* 05-May-99 Created MKW
|
||||
* 27-Jun-99 Clean up JWB
|
||||
* 16-Jul-99 Added MAL error recovery and better IP packet handling MKW
|
||||
* 29-Jul-99 Added Full duplex support MKW
|
||||
* 06-Aug-99 Changed names for Mal CR reg MKW
|
||||
* 23-Aug-99 Turned off SYE when running at 10Mbs MKW
|
||||
* 24-Aug-99 Marked descriptor empty after call_xlc MKW
|
||||
* 07-Sep-99 Set MAL RX buffer size reg to ENET_MAX_MTU_ALIGNED / 16 MCG
|
||||
* to avoid chaining maximum sized packets. Push starting
|
||||
* RX descriptor address up to the next cache line boundary.
|
||||
* 16-Jan-00 Added support for booting with IP of 0x0 MKW
|
||||
* 15-Mar-00 Updated enetInit() to enable broadcast addresses in the
|
||||
* EMAC_RXM register. JWB
|
||||
* 12-Mar-01 anne-sophie.harnois@nextream.fr
|
||||
* - Variables are compatible with those already defined in
|
||||
* include/net.h
|
||||
* - Receive buffer descriptor ring is used to send buffers
|
||||
* to the user
|
||||
* - Info print about send/received/handled packet number if
|
||||
* INFO_405_ENET is set
|
||||
* 17-Apr-01 stefan.roese@esd-electronics.com
|
||||
* - MAL reset in "eth_halt" included
|
||||
* - Enet speed and duplex output now in one line
|
||||
* 08-May-01 stefan.roese@esd-electronics.com
|
||||
* - MAL error handling added (eth_init called again)
|
||||
* 13-Nov-01 stefan.roese@esd-electronics.com
|
||||
* - Set IST bit in EMAC_M1 reg upon 100MBit or full duplex
|
||||
* 04-Jan-02 stefan.roese@esd-electronics.com
|
||||
* - Wait for PHY auto negotiation to complete added
|
||||
* 06-Feb-02 stefan.roese@esd-electronics.com
|
||||
* - Bug fixed in waiting for auto negotiation to complete
|
||||
* 26-Feb-02 stefan.roese@esd-electronics.com
|
||||
* - rx and tx buffer descriptors now allocated (no fixed address
|
||||
* used anymore)
|
||||
* 17-Jun-02 stefan.roese@esd-electronics.com
|
||||
* - MAL error debug printf 'M' removed (rx de interrupt may
|
||||
* occur upon many incoming packets with only 4 rx buffers).
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/processor.h>
|
||||
#include <ppc4xx.h>
|
||||
#include <commproc.h>
|
||||
#include <405gp_enet.h>
|
||||
#include <405_mal.h>
|
||||
#include <miiphy.h>
|
||||
#include <net.h>
|
||||
#include <malloc.h>
|
||||
#include "vecnum.h"
|
||||
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_440)
|
||||
|
||||
#define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */
|
||||
#define PHY_AUTONEGOTIATE_TIMEOUT 2000 /* 2000 ms autonegotiate timeout */
|
||||
|
||||
#define NUM_TX_BUFF 1
|
||||
/* AS.HARNOIS
|
||||
* Use PKTBUFSRX (include/net.h) instead of setting NUM_RX_BUFF again
|
||||
* These both variables are used to define the same thing!
|
||||
* #define NUM_RX_BUFF 4
|
||||
*/
|
||||
#define NUM_RX_BUFF PKTBUFSRX
|
||||
|
||||
/* Ethernet Transmit and Receive Buffers */
|
||||
/* AS.HARNOIS
|
||||
* In the same way ENET_MAX_MTU and ENET_MAX_MTU_ALIGNED are set from
|
||||
* PKTSIZE and PKTSIZE_ALIGN (include/net.h)
|
||||
*/
|
||||
#define ENET_MAX_MTU PKTSIZE
|
||||
#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN
|
||||
|
||||
static char *txbuf_ptr;
|
||||
|
||||
/* define the number of channels implemented */
|
||||
#define EMAC_RXCHL 1
|
||||
#define EMAC_TXCHL 1
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* Defines for MAL/EMAC interrupt conditions as reported in the UIC (Universal
|
||||
* Interrupt Controller).
|
||||
*-----------------------------------------------------------------------------*/
|
||||
#define MAL_UIC_ERR ( UIC_MAL_SERR | UIC_MAL_TXDE | UIC_MAL_RXDE)
|
||||
#define MAL_UIC_DEF (UIC_MAL_RXEOB | MAL_UIC_ERR)
|
||||
#define EMAC_UIC_DEF UIC_ENET
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* Global variables. TX and RX descriptors and buffers.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
static volatile mal_desc_t *tx;
|
||||
static volatile mal_desc_t *rx;
|
||||
static mal_desc_t *alloc_tx_buf = NULL;
|
||||
static mal_desc_t *alloc_rx_buf = NULL;
|
||||
|
||||
/* IER globals */
|
||||
static unsigned long emac_ier;
|
||||
static unsigned long mal_ier;
|
||||
|
||||
|
||||
/* Statistic Areas */
|
||||
#define MAX_ERR_LOG 10
|
||||
struct emac_stats {
|
||||
int data_len_err;
|
||||
int rx_frames;
|
||||
int rx;
|
||||
int rx_prot_err;
|
||||
};
|
||||
|
||||
static struct stats { /* Statistic Block */
|
||||
struct emac_stats emac;
|
||||
int int_err;
|
||||
short tx_err_log[MAX_ERR_LOG];
|
||||
short rx_err_log[MAX_ERR_LOG];
|
||||
} stats;
|
||||
|
||||
static int first_init = 0;
|
||||
|
||||
static int tx_err_index = 0; /* Transmit Error Index for tx_err_log */
|
||||
static int rx_err_index = 0; /* Receive Error Index for rx_err_log */
|
||||
|
||||
static int rx_slot = 0; /* MAL Receive Slot */
|
||||
static int rx_i_index = 0; /* Receive Interrupt Queue Index */
|
||||
static int rx_u_index = 0; /* Receive User Queue Index */
|
||||
static int rx_ready[NUM_RX_BUFF]; /* Receive Ready Queue */
|
||||
|
||||
static int tx_slot = 0; /* MAL Transmit Slot */
|
||||
static int tx_i_index = 0; /* Transmit Interrupt Queue Index */
|
||||
static int tx_u_index = 0; /* Transmit User Queue Index */
|
||||
static int tx_run[NUM_TX_BUFF]; /* Transmit Running Queue */
|
||||
|
||||
#undef INFO_405_ENET 1
|
||||
#ifdef INFO_405_ENET
|
||||
static int packetSent = 0;
|
||||
static int packetReceived = 0;
|
||||
static int packetHandled = 0;
|
||||
#endif
|
||||
|
||||
static char emac_hwd_addr[ENET_ADDR_LENGTH];
|
||||
|
||||
static bd_t *bis_save = NULL; /* for eth_init upon mal error */
|
||||
|
||||
static int is_receiving = 0; /* sync with eth interrupt */
|
||||
static int print_speed = 1; /* print speed message upon start */
|
||||
|
||||
static void enet_rcv (unsigned long malisr);
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* Prototypes and externals.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void mal_err (unsigned long isr, unsigned long uic, unsigned long mal_def,
|
||||
unsigned long mal_errr);
|
||||
void emac_err (unsigned long isr);
|
||||
|
||||
|
||||
void eth_halt (void)
|
||||
{
|
||||
mtdcr (malier, 0x00000000); /* disable mal interrupts */
|
||||
out32 (EMAC_IER, 0x00000000); /* disable emac interrupts */
|
||||
|
||||
/* 1st reset MAL */
|
||||
mtdcr (malmcr, MAL_CR_MMSR);
|
||||
|
||||
/* wait for reset */
|
||||
while (mfdcr (malmcr) & MAL_CR_MMSR) {
|
||||
};
|
||||
|
||||
/* EMAC RESET */
|
||||
out32 (EMAC_M0, EMAC_M0_SRST);
|
||||
|
||||
print_speed = 1; /* print speed message again next time */
|
||||
}
|
||||
|
||||
|
||||
int eth_init (bd_t * bis)
|
||||
{
|
||||
int i;
|
||||
unsigned long reg;
|
||||
unsigned long msr;
|
||||
unsigned long speed;
|
||||
unsigned long duplex;
|
||||
unsigned mode_reg;
|
||||
unsigned short reg_short;
|
||||
|
||||
msr = mfmsr ();
|
||||
mtmsr (msr & ~(MSR_EE)); /* disable interrupts */
|
||||
|
||||
#ifdef INFO_405_ENET
|
||||
/* AS.HARNOIS
|
||||
* We should have :
|
||||
* packetHandled <= packetReceived <= packetHandled+PKTBUFSRX
|
||||
* In the most cases packetHandled = packetReceived, but it
|
||||
* is possible that new packets (without relationship with
|
||||
* current transfer) have got the time to arrived before
|
||||
* netloop calls eth_halt
|
||||
*/
|
||||
printf ("About preceeding transfer:\n"
|
||||
"- Sent packet number %d\n"
|
||||
"- Received packet number %d\n"
|
||||
"- Handled packet number %d\n",
|
||||
packetSent, packetReceived, packetHandled);
|
||||
packetSent = 0;
|
||||
packetReceived = 0;
|
||||
packetHandled = 0;
|
||||
#endif
|
||||
|
||||
/* MAL RESET */
|
||||
mtdcr (malmcr, MAL_CR_MMSR);
|
||||
/* wait for reset */
|
||||
while (mfdcr (malmcr) & MAL_CR_MMSR) {
|
||||
};
|
||||
|
||||
tx_err_index = 0; /* Transmit Error Index for tx_err_log */
|
||||
rx_err_index = 0; /* Receive Error Index for rx_err_log */
|
||||
|
||||
rx_slot = 0; /* MAL Receive Slot */
|
||||
rx_i_index = 0; /* Receive Interrupt Queue Index */
|
||||
rx_u_index = 0; /* Receive User Queue Index */
|
||||
|
||||
tx_slot = 0; /* MAL Transmit Slot */
|
||||
tx_i_index = 0; /* Transmit Interrupt Queue Index */
|
||||
tx_u_index = 0; /* Transmit User Queue Index */
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
/* set RMII mode */
|
||||
out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0);
|
||||
#endif /* CONFIG_440 */
|
||||
|
||||
/* EMAC RESET */
|
||||
out32 (EMAC_M0, EMAC_M0_SRST);
|
||||
|
||||
/* wait for PHY to complete auto negotiation */
|
||||
reg_short = 0;
|
||||
#ifndef CONFIG_CS8952_PHY
|
||||
miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short);
|
||||
|
||||
/*
|
||||
* Wait if PHY is able of autonegotiation and autonegotiation is not complete
|
||||
*/
|
||||
if ((reg_short & PHY_BMSR_AUTN_ABLE)
|
||||
&& !(reg_short & PHY_BMSR_AUTN_COMP)) {
|
||||
puts ("Waiting for PHY auto negotiation to complete");
|
||||
i = 0;
|
||||
while (!(reg_short & PHY_BMSR_AUTN_COMP)) {
|
||||
if ((i++ % 100) == 0)
|
||||
putc ('.');
|
||||
udelay (10000); /* 10 ms */
|
||||
miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short);
|
||||
|
||||
/*
|
||||
* Timeout reached ?
|
||||
*/
|
||||
if (i * 10 > PHY_AUTONEGOTIATE_TIMEOUT) {
|
||||
puts (" TIMEOUT !\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
puts (" done\n");
|
||||
udelay (500000); /* another 500 ms (results in faster booting) */
|
||||
}
|
||||
#endif
|
||||
speed = miiphy_speed (CONFIG_PHY_ADDR);
|
||||
duplex = miiphy_duplex (CONFIG_PHY_ADDR);
|
||||
if (print_speed) {
|
||||
print_speed = 0;
|
||||
printf ("ENET Speed is %d Mbps - %s duplex connection\n",
|
||||
(int) speed, (duplex == HALF) ? "HALF" : "FULL");
|
||||
}
|
||||
|
||||
/* set the Mal configuration reg */
|
||||
#if defined(CONFIG_440)
|
||||
/* Errata 1.12: MAL_1 -- Disable MAL bursting */
|
||||
if( get_pvr() == PVR_440GP_RB )
|
||||
mtdcr (malmcr, MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
|
||||
else
|
||||
#else
|
||||
mtdcr (malmcr, MAL_CR_PLBB | MAL_CR_OPBBL | MAL_CR_LEA | MAL_CR_PLBLT_DEFAULT);
|
||||
#endif
|
||||
|
||||
/* Free "old" buffers */
|
||||
if (alloc_tx_buf) free(alloc_tx_buf);
|
||||
if (alloc_rx_buf) free(alloc_rx_buf);
|
||||
|
||||
/*
|
||||
* Malloc MAL buffer desciptors, make sure they are
|
||||
* aligned on cache line boundary size
|
||||
* (401/403/IOP480 = 16, 405 = 32)
|
||||
* and doesn't cross cache block boundaries.
|
||||
*/
|
||||
alloc_tx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_TX_BUFF) +
|
||||
((2 * CFG_CACHELINE_SIZE) - 2));
|
||||
if (((int)alloc_tx_buf & CACHELINE_MASK) != 0) {
|
||||
tx = (mal_desc_t *)((int)alloc_tx_buf + CFG_CACHELINE_SIZE -
|
||||
((int)alloc_tx_buf & CACHELINE_MASK));
|
||||
} else {
|
||||
tx = alloc_tx_buf;
|
||||
}
|
||||
|
||||
alloc_rx_buf = (mal_desc_t *)malloc((sizeof(mal_desc_t) * NUM_RX_BUFF) +
|
||||
((2 * CFG_CACHELINE_SIZE) - 2));
|
||||
if (((int)alloc_rx_buf & CACHELINE_MASK) != 0) {
|
||||
rx = (mal_desc_t *)((int)alloc_rx_buf + CFG_CACHELINE_SIZE -
|
||||
((int)alloc_rx_buf & CACHELINE_MASK));
|
||||
} else {
|
||||
rx = alloc_rx_buf;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_TX_BUFF; i++) {
|
||||
tx[i].ctrl = 0;
|
||||
tx[i].data_len = 0;
|
||||
if (first_init == 0)
|
||||
txbuf_ptr = (char *) malloc (ENET_MAX_MTU_ALIGNED);
|
||||
tx[i].data_ptr = txbuf_ptr;
|
||||
if ((NUM_TX_BUFF - 1) == i)
|
||||
tx[i].ctrl |= MAL_TX_CTRL_WRAP;
|
||||
tx_run[i] = -1;
|
||||
#if 0
|
||||
printf ("TX_BUFF %d @ 0x%08lx\n", i, (ulong) tx[i].data_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_RX_BUFF; i++) {
|
||||
rx[i].ctrl = 0;
|
||||
rx[i].data_len = 0;
|
||||
/* rx[i].data_ptr = (char *) &rx_buff[i]; */
|
||||
rx[i].data_ptr = (char *) NetRxPackets[i];
|
||||
if ((NUM_RX_BUFF - 1) == i)
|
||||
rx[i].ctrl |= MAL_RX_CTRL_WRAP;
|
||||
rx[i].ctrl |= MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR;
|
||||
rx_ready[i] = -1;
|
||||
#if 0
|
||||
printf ("RX_BUFF %d @ 0x%08lx\n", i, (ulong) rx[i].data_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy (emac_hwd_addr, bis->bi_enetaddr, ENET_ADDR_LENGTH);
|
||||
|
||||
reg = 0x00000000;
|
||||
|
||||
reg |= emac_hwd_addr[0]; /* set high address */
|
||||
reg = reg << 8;
|
||||
reg |= emac_hwd_addr[1];
|
||||
|
||||
out32 (EMAC_IAH, reg);
|
||||
|
||||
reg = 0x00000000;
|
||||
reg |= emac_hwd_addr[2]; /* set low address */
|
||||
reg = reg << 8;
|
||||
reg |= emac_hwd_addr[3];
|
||||
reg = reg << 8;
|
||||
reg |= emac_hwd_addr[4];
|
||||
reg = reg << 8;
|
||||
reg |= emac_hwd_addr[5];
|
||||
|
||||
out32 (EMAC_IAL, reg);
|
||||
|
||||
/* setup MAL tx & rx channel pointers */
|
||||
mtdcr (maltxctp0r, tx);
|
||||
mtdcr (malrxctp0r, rx);
|
||||
|
||||
/* Reset transmit and receive channels */
|
||||
mtdcr (malrxcarr, 0x80000000); /* 2 channels */
|
||||
mtdcr (maltxcarr, 0x80000000); /* 2 channels */
|
||||
|
||||
/* Enable MAL transmit and receive channels */
|
||||
mtdcr (maltxcasr, 0x80000000); /* 1 channel */
|
||||
mtdcr (malrxcasr, 0x80000000); /* 1 channel */
|
||||
|
||||
/* set RX buffer size */
|
||||
mtdcr (malrcbs0, ENET_MAX_MTU_ALIGNED / 16);
|
||||
|
||||
/* set transmit enable & receive enable */
|
||||
out32 (EMAC_M0, EMAC_M0_TXE | EMAC_M0_RXE);
|
||||
|
||||
/* set receive fifo to 4k and tx fifo to 2k */
|
||||
mode_reg = EMAC_M1_RFS_4K | EMAC_M1_TX_FIFO_2K;
|
||||
|
||||
/* set speed */
|
||||
if (speed == _100BASET)
|
||||
mode_reg = mode_reg | EMAC_M1_MF_100MBPS | EMAC_M1_IST;
|
||||
else
|
||||
mode_reg = mode_reg & ~0x00C00000; /* 10 MBPS */
|
||||
if (duplex == FULL)
|
||||
mode_reg = mode_reg | 0x80000000 | EMAC_M1_IST;
|
||||
|
||||
out32 (EMAC_M1, mode_reg);
|
||||
|
||||
/* Enable broadcast and indvidual address */
|
||||
out32 (EMAC_RXM, EMAC_RMR_BAE | EMAC_RMR_IAE
|
||||
/*| EMAC_RMR_ARRP| EMAC_RMR_SFCS | EMAC_RMR_SP */ );
|
||||
|
||||
/* we probably need to set the tx mode1 reg? maybe at tx time */
|
||||
|
||||
/* set transmit request threshold register */
|
||||
out32 (EMAC_TRTR, 0x18000000); /* 256 byte threshold */
|
||||
|
||||
/* set receive low/high water mark register */
|
||||
#if defined(CONFIG_440)
|
||||
/* 440GP has a 64 byte burst length */
|
||||
out32 (EMAC_RX_HI_LO_WMARK, 0x80009000);
|
||||
out32 (EMAC_TXM1, 0xf8640000);
|
||||
#else /* CONFIG_440 */
|
||||
/* 405s have a 16 byte burst length */
|
||||
out32 (EMAC_RX_HI_LO_WMARK, 0x0f002000);
|
||||
#endif /* CONFIG_440 */
|
||||
|
||||
/* Frame gap set */
|
||||
out32 (EMAC_I_FRAME_GAP_REG, 0x00000008);
|
||||
|
||||
if (first_init == 0) {
|
||||
/*
|
||||
* Connect interrupt service routines
|
||||
*/
|
||||
irq_install_handler (VECNUM_EWU0, (interrupt_handler_t *) enetInt, NULL);
|
||||
irq_install_handler (VECNUM_MS, (interrupt_handler_t *) enetInt, NULL);
|
||||
irq_install_handler (VECNUM_MTE, (interrupt_handler_t *) enetInt, NULL);
|
||||
irq_install_handler (VECNUM_MRE, (interrupt_handler_t *) enetInt, NULL);
|
||||
irq_install_handler (VECNUM_TXDE, (interrupt_handler_t *) enetInt, NULL);
|
||||
irq_install_handler (VECNUM_RXDE, (interrupt_handler_t *) enetInt, NULL);
|
||||
irq_install_handler (VECNUM_ETH0, (interrupt_handler_t *) enetInt, NULL);
|
||||
}
|
||||
|
||||
/* set up interrupt handler */
|
||||
/* setup interrupt controler to take interrupts from the MAL &
|
||||
EMAC */
|
||||
mtdcr (uicsr, 0xffffffff); /* clear pending interrupts */
|
||||
mtdcr (uicer, mfdcr (uicer) | MAL_UIC_DEF | EMAC_UIC_DEF);
|
||||
|
||||
/* set the MAL IER ??? names may change with new spec ??? */
|
||||
mal_ier = MAL_IER_DE | MAL_IER_NE | MAL_IER_TE | MAL_IER_OPBE |
|
||||
MAL_IER_PLBE;
|
||||
mtdcr (malesr, 0xffffffff); /* clear pending interrupts */
|
||||
mtdcr (maltxdeir, 0xffffffff); /* clear pending interrupts */
|
||||
mtdcr (malrxdeir, 0xffffffff); /* clear pending interrupts */
|
||||
mtdcr (malier, mal_ier);
|
||||
|
||||
/* Set EMAC IER */
|
||||
emac_ier = EMAC_ISR_PTLE | EMAC_ISR_BFCS |
|
||||
EMAC_ISR_PTLE | EMAC_ISR_ORE | EMAC_ISR_IRE;
|
||||
if (speed == _100BASET)
|
||||
emac_ier = emac_ier | EMAC_ISR_SYE;
|
||||
|
||||
out32 (EMAC_ISR, 0xffffffff); /* clear pending interrupts */
|
||||
out32 (EMAC_IER, emac_ier);
|
||||
|
||||
mtmsr (msr); /* enable interrupts again */
|
||||
|
||||
bis_save = bis;
|
||||
first_init = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int eth_send (volatile void *ptr, int len)
|
||||
{
|
||||
struct enet_frame *ef_ptr;
|
||||
ulong time_start, time_now;
|
||||
unsigned long temp_txm0;
|
||||
|
||||
ef_ptr = (struct enet_frame *) ptr;
|
||||
|
||||
/*-----------------------------------------------------------------------+
|
||||
* Copy in our address into the frame.
|
||||
*-----------------------------------------------------------------------*/
|
||||
(void) memcpy (ef_ptr->source_addr, emac_hwd_addr, ENET_ADDR_LENGTH);
|
||||
|
||||
/*-----------------------------------------------------------------------+
|
||||
* If frame is too long or too short, modify length.
|
||||
*-----------------------------------------------------------------------*/
|
||||
if (len > ENET_MAX_MTU)
|
||||
len = ENET_MAX_MTU;
|
||||
|
||||
/* memcpy ((void *) &tx_buff[tx_slot], (const void *) ptr, len); */
|
||||
memcpy ((void *) txbuf_ptr, (const void *) ptr, len);
|
||||
|
||||
/*-----------------------------------------------------------------------+
|
||||
* set TX Buffer busy, and send it
|
||||
*-----------------------------------------------------------------------*/
|
||||
tx[tx_slot].ctrl = (MAL_TX_CTRL_LAST |
|
||||
EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP) &
|
||||
~(EMAC_TX_CTRL_ISA | EMAC_TX_CTRL_RSA);
|
||||
if ((NUM_TX_BUFF - 1) == tx_slot)
|
||||
tx[tx_slot].ctrl |= MAL_TX_CTRL_WRAP;
|
||||
|
||||
tx[tx_slot].data_len = (short) len;
|
||||
tx[tx_slot].ctrl |= MAL_TX_CTRL_READY;
|
||||
|
||||
__asm__ volatile ("eieio");
|
||||
out32 (EMAC_TXM0, in32 (EMAC_TXM0) | EMAC_TXM0_GNP0);
|
||||
#ifdef INFO_405_ENET
|
||||
packetSent++;
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------------+
|
||||
* poll unitl the packet is sent and then make sure it is OK
|
||||
*-----------------------------------------------------------------------*/
|
||||
time_start = get_timer (0);
|
||||
while (1) {
|
||||
temp_txm0 = in32 (EMAC_TXM0);
|
||||
/* loop until either TINT turns on or 3 seconds elapse */
|
||||
if ((temp_txm0 & EMAC_TXM0_GNP0) != 0) {
|
||||
/* transmit is done, so now check for errors
|
||||
* If there is an error, an interrupt should
|
||||
* happen when we return
|
||||
*/
|
||||
time_now = get_timer (0);
|
||||
if ((time_now - time_start) > 3000) {
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
/*-----------------------------------------------------------------------------+
|
||||
| EnetInt.
|
||||
| EnetInt is the interrupt handler. It will determine the
|
||||
| cause of the interrupt and call the apporpriate servive
|
||||
| routine.
|
||||
+-----------------------------------------------------------------------------*/
|
||||
int enetInt ()
|
||||
{
|
||||
int serviced;
|
||||
int rc = -1; /* default to not us */
|
||||
unsigned long mal_isr;
|
||||
unsigned long emac_isr = 0;
|
||||
unsigned long mal_rx_eob;
|
||||
unsigned long my_uic0msr, my_uic1msr;
|
||||
|
||||
/* enter loop that stays in interrupt code until nothing to service */
|
||||
do {
|
||||
serviced = 0;
|
||||
|
||||
my_uic0msr = mfdcr (uic0msr);
|
||||
my_uic1msr = mfdcr (uic1msr);
|
||||
|
||||
if (!(my_uic0msr & UIC_MRE)
|
||||
&& !(my_uic1msr & (UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE))) {
|
||||
/* not for us */
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/* get and clear controller status interrupts */
|
||||
/* look at Mal and EMAC interrupts */
|
||||
if ((my_uic0msr & UIC_MRE)
|
||||
|| (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
|
||||
/* we have a MAL interrupt */
|
||||
mal_isr = mfdcr (malesr);
|
||||
/* look for mal error */
|
||||
if (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE)) {
|
||||
mal_err (mal_isr, my_uic0msr, MAL_UIC_DEF, MAL_UIC_ERR);
|
||||
serviced = 1;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
if (UIC_ETH0 & my_uic1msr) { /* look for EMAC errors */
|
||||
emac_isr = in32 (EMAC_ISR);
|
||||
if ((emac_ier & emac_isr) != 0) {
|
||||
emac_err (emac_isr);
|
||||
serviced = 1;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
if ((emac_ier & emac_isr)
|
||||
|| (my_uic1msr & (UIC_MS | UIC_MTDE | UIC_MRDE))) {
|
||||
mtdcr (uic0sr, UIC_MRE); /* Clear */
|
||||
mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
|
||||
return (rc); /* we had errors so get out */
|
||||
}
|
||||
|
||||
/* handle MAL RX EOB interupt from a receive */
|
||||
/* check for EOB on valid channels */
|
||||
if (my_uic0msr & UIC_MRE) {
|
||||
mal_rx_eob = mfdcr (malrxeobisr);
|
||||
if ((mal_rx_eob & 0x80000000) != 0) { /* call emac routine for channel 0 */
|
||||
/* clear EOB
|
||||
mtdcr(malrxeobisr, mal_rx_eob); */
|
||||
enet_rcv (emac_isr);
|
||||
/* indicate that we serviced an interrupt */
|
||||
serviced = 1;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
mtdcr (uic0sr, UIC_MRE); /* Clear */
|
||||
mtdcr (uic1sr, UIC_ETH0 | UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */
|
||||
} while (serviced);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
#else /* CONFIG_440 */
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* EnetInt.
|
||||
* EnetInt is the interrupt handler. It will determine the
|
||||
* cause of the interrupt and call the apporpriate servive
|
||||
* routine.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
int enetInt ()
|
||||
{
|
||||
int serviced;
|
||||
int rc = -1; /* default to not us */
|
||||
unsigned long mal_isr;
|
||||
unsigned long emac_isr = 0;
|
||||
unsigned long mal_rx_eob;
|
||||
unsigned long my_uicmsr;
|
||||
|
||||
/* enter loop that stays in interrupt code until nothing to service */
|
||||
do {
|
||||
serviced = 0;
|
||||
|
||||
my_uicmsr = mfdcr (uicmsr);
|
||||
if ((my_uicmsr & (MAL_UIC_DEF | EMAC_UIC_DEF)) == 0) { /* not for us */
|
||||
return (rc);
|
||||
}
|
||||
|
||||
|
||||
/* get and clear controller status interrupts */
|
||||
/* look at Mal and EMAC interrupts */
|
||||
if ((MAL_UIC_DEF & my_uicmsr) != 0) { /* we have a MAL interrupt */
|
||||
mal_isr = mfdcr (malesr);
|
||||
/* look for mal error */
|
||||
if ((my_uicmsr & MAL_UIC_ERR) != 0) {
|
||||
mal_err (mal_isr, my_uicmsr, MAL_UIC_DEF, MAL_UIC_ERR);
|
||||
serviced = 1;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
if ((EMAC_UIC_DEF & my_uicmsr) != 0) { /* look for EMAC errors */
|
||||
emac_isr = in32 (EMAC_ISR);
|
||||
if ((emac_ier & emac_isr) != 0) {
|
||||
emac_err (emac_isr);
|
||||
serviced = 1;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
if (((emac_ier & emac_isr) != 0) | ((MAL_UIC_ERR & my_uicmsr) != 0)) {
|
||||
mtdcr (uicsr, MAL_UIC_DEF | EMAC_UIC_DEF); /* Clear */
|
||||
return (rc); /* we had errors so get out */
|
||||
}
|
||||
|
||||
|
||||
/* handle MAL RX EOB interupt from a receive */
|
||||
/* check for EOB on valid channels */
|
||||
if ((my_uicmsr & UIC_MAL_RXEOB) != 0) {
|
||||
mal_rx_eob = mfdcr (malrxeobisr);
|
||||
if ((mal_rx_eob & 0x80000000) != 0) { /* call emac routine for channel 0 */
|
||||
/* clear EOB
|
||||
mtdcr(malrxeobisr, mal_rx_eob); */
|
||||
enet_rcv (emac_isr);
|
||||
/* indicate that we serviced an interrupt */
|
||||
serviced = 1;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
mtdcr (uicsr, MAL_UIC_DEF | EMAC_UIC_DEF); /* Clear */
|
||||
}
|
||||
while (serviced);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
#endif /* CONFIG_440 */
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* MAL Error Routine
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void mal_err (unsigned long isr, unsigned long uic, unsigned long maldef,
|
||||
unsigned long mal_errr)
|
||||
{
|
||||
mtdcr (malesr, isr); /* clear interrupt */
|
||||
|
||||
/* clear DE interrupt */
|
||||
mtdcr (maltxdeir, 0xC0000000);
|
||||
mtdcr (malrxdeir, 0x80000000);
|
||||
|
||||
#if 1 /*sr */
|
||||
printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n",
|
||||
isr, uic, maldef, mal_errr);
|
||||
#else
|
||||
#if 0
|
||||
/*
|
||||
* MAL error is RX DE error (out of rx buffers)! This is OK here, upon
|
||||
* many incoming packets with only 4 rx buffers.
|
||||
*/
|
||||
printf ("M"); /* just to see something upon mal error */
|
||||
#endif
|
||||
#endif /*sr */
|
||||
|
||||
eth_init (bis_save); /* start again... */
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* EMAC Error Routine
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void emac_err (unsigned long isr)
|
||||
{
|
||||
printf ("EMAC error occured.... ISR = %lx\n", isr);
|
||||
out32 (EMAC_ISR, isr);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* enet_rcv() handles the ethernet receive data
|
||||
*-----------------------------------------------------------------------------*/
|
||||
static void enet_rcv (unsigned long malisr)
|
||||
{
|
||||
struct enet_frame *ef_ptr;
|
||||
unsigned long data_len;
|
||||
unsigned long rx_eob_isr;
|
||||
|
||||
int handled = 0;
|
||||
int i;
|
||||
int loop_count = 0;
|
||||
|
||||
rx_eob_isr = mfdcr (malrxeobisr);
|
||||
if ((0x80000000 >> (EMAC_RXCHL - 1)) & rx_eob_isr) {
|
||||
/* clear EOB */
|
||||
mtdcr (malrxeobisr, rx_eob_isr);
|
||||
|
||||
/* EMAC RX done */
|
||||
while (1) { /* do all */
|
||||
i = rx_slot;
|
||||
|
||||
if ((MAL_RX_CTRL_EMPTY & rx[i].ctrl)
|
||||
|| (loop_count >= NUM_RX_BUFF))
|
||||
break;
|
||||
loop_count++;
|
||||
rx_slot++;
|
||||
if (NUM_RX_BUFF == rx_slot)
|
||||
rx_slot = 0;
|
||||
handled++;
|
||||
data_len = (unsigned long) rx[i].data_len; /* Get len */
|
||||
if (data_len) {
|
||||
if (data_len > ENET_MAX_MTU) /* Check len */
|
||||
data_len = 0;
|
||||
else {
|
||||
if (EMAC_RX_ERRORS & rx[i].ctrl) { /* Check Errors */
|
||||
data_len = 0;
|
||||
stats.rx_err_log[rx_err_index] = rx[i].ctrl;
|
||||
rx_err_index++;
|
||||
if (rx_err_index == MAX_ERR_LOG)
|
||||
rx_err_index = 0;
|
||||
} /* emac_erros */
|
||||
} /* data_len < max mtu */
|
||||
} /* if data_len */
|
||||
if (!data_len) { /* no data */
|
||||
rx[i].ctrl |= MAL_RX_CTRL_EMPTY; /* Free Recv Buffer */
|
||||
|
||||
stats.emac.data_len_err++; /* Error at Rx */
|
||||
}
|
||||
|
||||
/* !data_len */
|
||||
/* AS.HARNOIS */
|
||||
/* Check if user has already eaten buffer */
|
||||
/* if not => ERROR */
|
||||
else if (rx_ready[rx_i_index] != -1) {
|
||||
if (is_receiving)
|
||||
printf ("ERROR : Receive buffers are full!\n");
|
||||
break;
|
||||
} else {
|
||||
stats.emac.rx_frames++;
|
||||
stats.emac.rx += data_len;
|
||||
ef_ptr = (struct enet_frame *) rx[i].data_ptr;
|
||||
#ifdef INFO_405_ENET
|
||||
packetReceived++;
|
||||
#endif
|
||||
/* AS.HARNOIS
|
||||
* use ring buffer
|
||||
*/
|
||||
rx_ready[rx_i_index] = i;
|
||||
rx_i_index++;
|
||||
if (NUM_RX_BUFF == rx_i_index)
|
||||
rx_i_index = 0;
|
||||
|
||||
/* printf("X"); /|* test-only *|/ */
|
||||
|
||||
/* AS.HARNOIS
|
||||
* free receive buffer only when
|
||||
* buffer has been handled (eth_rx)
|
||||
rx[i].ctrl |= MAL_RX_CTRL_EMPTY;
|
||||
*/
|
||||
} /* if data_len */
|
||||
} /* while */
|
||||
} /* if EMACK_RXCHL */
|
||||
}
|
||||
|
||||
|
||||
int eth_rx (void)
|
||||
{
|
||||
int length;
|
||||
int user_index;
|
||||
unsigned long msr;
|
||||
|
||||
is_receiving = 1; /* tell driver */
|
||||
|
||||
for (;;) {
|
||||
/* AS.HARNOIS
|
||||
* use ring buffer and
|
||||
* get index from rx buffer desciptor queue
|
||||
*/
|
||||
user_index = rx_ready[rx_u_index];
|
||||
if (user_index == -1) {
|
||||
length = -1;
|
||||
break; /* nothing received - leave for() loop */
|
||||
}
|
||||
|
||||
msr = mfmsr ();
|
||||
mtmsr (msr & ~(MSR_EE));
|
||||
|
||||
length = rx[user_index].data_len;
|
||||
|
||||
/* Pass the packet up to the protocol layers. */
|
||||
/* NetReceive(NetRxPackets[rxIdx], length - 4); */
|
||||
/* NetReceive(NetRxPackets[i], length); */
|
||||
NetReceive (NetRxPackets[user_index], length - 4);
|
||||
/* Free Recv Buffer */
|
||||
rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY;
|
||||
/* Free rx buffer descriptor queue */
|
||||
rx_ready[rx_u_index] = -1;
|
||||
rx_u_index++;
|
||||
if (NUM_RX_BUFF == rx_u_index)
|
||||
rx_u_index = 0;
|
||||
|
||||
#ifdef INFO_405_ENET
|
||||
packetHandled++;
|
||||
#endif
|
||||
|
||||
mtmsr (msr); /* Enable IRQ's */
|
||||
}
|
||||
|
||||
is_receiving = 0; /* tell driver */
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_405GP */
|
||||
502
cpu/ppc4xx/405gp_pci.c
Normal file
502
cpu/ppc4xx/405gp_pci.c
Normal file
@@ -0,0 +1,502 @@
|
||||
/*-----------------------------------------------------------------------------+
|
||||
*
|
||||
* This source code has been made available to you by IBM on an AS-IS
|
||||
* basis. Anyone receiving this source is licensed under IBM
|
||||
* copyrights to use it in any way he or she deems fit, including
|
||||
* copying it, modifying it, compiling it, and redistributing it either
|
||||
* with or without modifications. No license under IBM patents or
|
||||
* patent applications is to be implied by the copyright license.
|
||||
*
|
||||
* Any user of this software should understand that IBM cannot provide
|
||||
* technical support for this software and will not be responsible for
|
||||
* any consequences resulting from the use of this software.
|
||||
*
|
||||
* Any person who transfers this source code or any derivative work
|
||||
* must include the IBM copyright notice, this paragraph, and the
|
||||
* preceding two paragraphs in the transferred software.
|
||||
*
|
||||
* COPYRIGHT I B M CORPORATION 1995
|
||||
* LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
|
||||
*-----------------------------------------------------------------------------*/
|
||||
/*----------------------------------------------------------------------------+
|
||||
*
|
||||
* File Name: 405gp_pci.c
|
||||
*
|
||||
* Function: Initialization code for the 405GP PCI Configuration regs.
|
||||
*
|
||||
* Author: Mark Game
|
||||
*
|
||||
* Change Activity-
|
||||
*
|
||||
* Date Description of Change BY
|
||||
* --------- --------------------- ---
|
||||
* 09-Sep-98 Created MCG
|
||||
* 02-Nov-98 Removed External arbiter selected message JWB
|
||||
* 27-Nov-98 Zero out PTMBAR2 and disable in PTM2MS JWB
|
||||
* 04-Jan-99 Zero out other unused PMM and PTM regs. Change bus scan MCG
|
||||
* from (0 to n) to (1 to n).
|
||||
* 17-May-99 Port to Walnut JWB
|
||||
* 17-Jun-99 Updated for VGA support JWB
|
||||
* 21-Jun-99 Updated to allow SRAM region to be a target from PCI bus JWB
|
||||
* 19-Jul-99 Updated for 405GP pass 1 errata #26 (Low PCI subsequent MCG
|
||||
* target latency timer values are not supported).
|
||||
* Should be fixed in pass 2.
|
||||
* 09-Sep-99 Removed use of PTM2 since the SRAM region no longer needs JWB
|
||||
* to be a PCI target. Zero out PTMBAR2 and disable in PTM2MS.
|
||||
* 10-Dec-99 Updated PCI_Write_CFG_Reg for pass2 errata #6 JWB
|
||||
* 11-Jan-00 Ensure PMMxMAs disabled before setting PMMxLAs. This is not
|
||||
* really required after a reset since PMMxMAs are already
|
||||
* disabled but is a good practice nonetheless. JWB
|
||||
* 12-Jun-01 stefan.roese@esd-electronics.com
|
||||
* - PCI host/adapter handling reworked
|
||||
* 09-Jul-01 stefan.roese@esd-electronics.com
|
||||
* - PCI host now configures from device 0 (not 1) to max_dev,
|
||||
* (host configures itself)
|
||||
* - On CPCI-405 pci base address and size is generated from
|
||||
* SDRAM and FLASH size (CFG regs not used anymore)
|
||||
* - Some minor changes for CPCI-405-A (adapter version)
|
||||
* 14-Sep-01 stefan.roese@esd-electronics.com
|
||||
* - CONFIG_PCI_SCAN_SHOW added to print pci devices upon startup
|
||||
* 28-Sep-01 stefan.roese@esd-electronics.com
|
||||
* - Changed pci master configuration for linux compatibility
|
||||
* (no need for bios_fixup() anymore)
|
||||
* 26-Feb-02 stefan.roese@esd-electronics.com
|
||||
* - Bug fixed in pci configuration (Andrew May)
|
||||
* - Removed pci class code init for CPCI405 board
|
||||
* 15-May-02 stefan.roese@esd-electronics.com
|
||||
* - New vga device handling
|
||||
* 29-May-02 stefan.roese@esd-electronics.com
|
||||
* - PCI class code init added (if defined)
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <cmd_boot.h>
|
||||
#if !defined(CONFIG_440)
|
||||
#include <405gp_pci.h>
|
||||
#endif
|
||||
#include <asm/processor.h>
|
||||
#include <pci.h>
|
||||
|
||||
#if defined(CONFIG_405GP)
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* pci_init. Initializes the 405GP PCI Configuration regs.
|
||||
*-----------------------------------------------------------------------------*/
|
||||
void pci_405gp_init(struct pci_controller *hose)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
int i, reg_num = 0;
|
||||
bd_t *bd = gd->bd;
|
||||
|
||||
unsigned short temp_short;
|
||||
unsigned long ptmpcila[2] = {CFG_PCI_PTM1PCI, CFG_PCI_PTM2PCI};
|
||||
#if defined(CONFIG_CPCI405)
|
||||
unsigned long ptmla[2] = {bd->bi_memstart, bd->bi_flashstart};
|
||||
unsigned long ptmms[2] = {~(bd->bi_memsize - 1) | 1, ~(bd->bi_flashsize - 1) | 1};
|
||||
#else
|
||||
unsigned long ptmla[2] = {CFG_PCI_PTM1LA, CFG_PCI_PTM2LA};
|
||||
unsigned long ptmms[2] = {CFG_PCI_PTM1MS, CFG_PCI_PTM2MS};
|
||||
#endif
|
||||
#if defined(CONFIG_PIP405) || defined (CONFIG_MIP405)
|
||||
unsigned long pmmla[3] = {0x80000000, 0xA0000000, 0};
|
||||
unsigned long pmmma[3] = {0xE0000001, 0xE0000001, 0};
|
||||
unsigned long pmmpcila[3] = {0x80000000, 0x00000000, 0};
|
||||
unsigned long pmmpciha[3] = {0x00000000, 0x00000000, 0};
|
||||
#else
|
||||
unsigned long pmmla[3] = {0x80000000, 0,0};
|
||||
unsigned long pmmma[3] = {0xC0000001, 0,0};
|
||||
unsigned long pmmpcila[3] = {0x80000000, 0,0};
|
||||
unsigned long pmmpciha[3] = {0x00000000, 0,0};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Register the hose
|
||||
*/
|
||||
hose->first_busno = 0;
|
||||
hose->last_busno = 0xff;
|
||||
|
||||
/* ISA/PCI I/O space */
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
MIN_PCI_PCI_IOADDR,
|
||||
MIN_PLB_PCI_IOADDR,
|
||||
0x10000,
|
||||
PCI_REGION_IO);
|
||||
|
||||
/* PCI I/O space */
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
0x00800000,
|
||||
0xe8800000,
|
||||
0x03800000,
|
||||
PCI_REGION_IO);
|
||||
|
||||
reg_num = 2;
|
||||
|
||||
/* Memory spaces */
|
||||
for (i=0; i<2; i++)
|
||||
if (ptmms[i] & 1)
|
||||
{
|
||||
if (!i) hose->pci_fb = hose->regions + reg_num;
|
||||
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
ptmpcila[i], ptmla[i],
|
||||
~(ptmms[i] & 0xfffff000) + 1,
|
||||
PCI_REGION_MEM |
|
||||
PCI_REGION_MEMORY);
|
||||
}
|
||||
|
||||
/* PCI memory spaces */
|
||||
for (i=0; i<3; i++)
|
||||
if (pmmma[i] & 1)
|
||||
{
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
pmmpcila[i], pmmla[i],
|
||||
~(pmmma[i] & 0xfffff000) + 1,
|
||||
PCI_REGION_MEM);
|
||||
}
|
||||
|
||||
hose->region_count = reg_num;
|
||||
|
||||
pci_setup_indirect(hose,
|
||||
PCICFGADR,
|
||||
PCICFGDATA);
|
||||
|
||||
if (hose->pci_fb)
|
||||
pciauto_region_init(hose->pci_fb);
|
||||
|
||||
pci_register_hose(hose);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* 405GP PCI Master configuration.
|
||||
* Map one 512 MB range of PLB/processor addresses to PCI memory space.
|
||||
* PLB address 0x80000000-0xBFFFFFFF ==> PCI address 0x80000000-0xBFFFFFFF
|
||||
* Use byte reversed out routines to handle endianess.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PMM0MA, pmmma[0]); /* ensure disabled b4 setting PMM0LA */
|
||||
out32r(PMM0LA, pmmla[0]);
|
||||
out32r(PMM0PCILA, pmmpcila[0]);
|
||||
out32r(PMM0PCIHA, pmmpciha[0]);
|
||||
out32r(PMM0MA, pmmma[0]);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PMM1 is not used. Initialize them to zero.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PMM1MA, pmmma[1]); /* ensure disabled b4 setting PMM2LA */
|
||||
out32r(PMM1LA, pmmla[1]);
|
||||
out32r(PMM1PCILA, pmmpcila[1]);
|
||||
out32r(PMM1PCIHA, pmmpciha[1]);
|
||||
out32r(PMM1MA, pmmma[1]);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PMM2 is not used. Initialize them to zero.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PMM2MA, pmmma[2]); /* ensure disabled b4 setting PMM2LA */
|
||||
out32r(PMM2LA, pmmla[2]);
|
||||
out32r(PMM2PCILA, pmmpcila[2]);
|
||||
out32r(PMM2PCIHA, pmmpciha[2]);
|
||||
out32r(PMM2MA, pmmma[2]);
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* 405GP PCI Target configuration. (PTM1)
|
||||
* Note: PTM1MS is hardwire enabled but we set the enable bit anyway.
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PTM1LA, ptmla[0]); /* insert address */
|
||||
out32r(PTM1MS, ptmms[0]); /* insert size, enable bit is 1 */
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* 405GP PCI Target configuration. (PTM2)
|
||||
*--------------------------------------------------------------------------*/
|
||||
out32r(PTM2LA, ptmla[1]); /* insert address */
|
||||
if (ptmms[1] == 0)
|
||||
{
|
||||
out32r(PTM2MS, 0x00000001); /* set enable bit */
|
||||
pci_write_config_dword(PCIDEVID_405GP, PCI_BASE_ADDRESS_2, 0x00000000);
|
||||
out32r(PTM2MS, 0x00000000); /* disable */
|
||||
}
|
||||
else
|
||||
{
|
||||
out32r(PTM2MS, ptmms[1]); /* insert size, enable bit is 1 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert Subsystem Vendor and Device ID
|
||||
*/
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_VENDOR_ID, CFG_PCI_SUBSYS_VENDORID);
|
||||
#ifdef CONFIG_CPCI405
|
||||
if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID);
|
||||
else
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID2);
|
||||
#else
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_SUBSYSTEM_ID, CFG_PCI_SUBSYS_DEVICEID);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Insert Class-code
|
||||
*/
|
||||
#ifdef CFG_PCI_CLASSCODE
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_CLASS_SUB_CODE, CFG_PCI_CLASSCODE);
|
||||
#endif /* CFG_PCI_CLASSCODE */
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* If PCI speed = 66Mhz, set 66Mhz capable bit.
|
||||
*--------------------------------------------------------------------------*/
|
||||
if (bd->bi_pci_busfreq >= 66000000) {
|
||||
pci_read_config_word(PCIDEVID_405GP, PCI_STATUS, &temp_short);
|
||||
pci_write_config_word(PCIDEVID_405GP,PCI_STATUS,(temp_short|PCI_STATUS_66MHZ));
|
||||
}
|
||||
|
||||
#if (CONFIG_PCI_HOST != PCI_HOST_ADAPTER)
|
||||
#if (CONFIG_PCI_HOSE == PCI_HOST_AUTO)
|
||||
if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
|
||||
#endif
|
||||
{
|
||||
/*--------------------------------------------------------------------------+
|
||||
* Write the 405GP PCI Configuration regs.
|
||||
* Enable 405GP to be a master on the PCI bus (PMM).
|
||||
* Enable 405GP to act as a PCI memory target (PTM).
|
||||
*--------------------------------------------------------------------------*/
|
||||
pci_read_config_word(PCIDEVID_405GP, PCI_COMMAND, &temp_short);
|
||||
pci_write_config_word(PCIDEVID_405GP, PCI_COMMAND, temp_short |
|
||||
PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set HCE bit (Host Configuration Enabled)
|
||||
*/
|
||||
pci_read_config_word(PCIDEVID_405GP, PCIBRDGOPT2, &temp_short);
|
||||
pci_write_config_word(PCIDEVID_405GP, PCIBRDGOPT2, (temp_short | 0x0001));
|
||||
|
||||
#ifdef CONFIG_PCI_PNP
|
||||
/*--------------------------------------------------------------------------+
|
||||
* Scan the PCI bus and configure devices found.
|
||||
*--------------------------------------------------------------------------*/
|
||||
#if (CONFIG_PCI_HOST == PCI_HOST_AUTO)
|
||||
if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
|
||||
#endif
|
||||
{
|
||||
#ifdef CONFIG_PCI_SCAN_SHOW
|
||||
printf("PCI: Bus Dev VenId DevId Class Int\n");
|
||||
#endif
|
||||
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
}
|
||||
#endif /* CONFIG_PCI_PNP */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* drivers/pci.c skips every host bridge but the 405GP since it could
|
||||
* be set as an Adapter.
|
||||
*
|
||||
* I (Andrew May) don't know what we should do here, but I don't want
|
||||
* the auto setup of a PCI device disabling what is done pci_405gp_init
|
||||
* as has happened before.
|
||||
*/
|
||||
void pci_405gp_setup_bridge(struct pci_controller *hose, pci_dev_t dev,
|
||||
struct pci_config_table *entry)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("405gp_setup_bridge\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
void pci_405gp_fixup_irq(struct pci_controller *hose, pci_dev_t dev)
|
||||
{
|
||||
unsigned char int_line = 0xff;
|
||||
|
||||
/*
|
||||
* Write pci interrupt line register (cpci405 specific)
|
||||
*/
|
||||
switch (PCI_DEV(dev) & 0x03)
|
||||
{
|
||||
case 0:
|
||||
int_line = 27 + 2;
|
||||
break;
|
||||
case 1:
|
||||
int_line = 27 + 3;
|
||||
break;
|
||||
case 2:
|
||||
int_line = 27 + 0;
|
||||
break;
|
||||
case 3:
|
||||
int_line = 27 + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
pci_hose_write_config_byte(hose, dev, PCI_INTERRUPT_LINE, int_line);
|
||||
}
|
||||
|
||||
void pci_405gp_setup_vga(struct pci_controller *hose, pci_dev_t dev,
|
||||
struct pci_config_table *entry)
|
||||
{
|
||||
unsigned int cmdstat = 0;
|
||||
|
||||
pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_io);
|
||||
|
||||
/* always enable io space on vga boards */
|
||||
pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
|
||||
cmdstat |= PCI_COMMAND_IO;
|
||||
pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
|
||||
}
|
||||
|
||||
#if !(defined(CONFIG_PIP405) || defined (CONFIG_MIP405))
|
||||
|
||||
/*
|
||||
*As is these functs get called out of flash Not a horrible
|
||||
*thing, but something to keep in mind. (no statics?)
|
||||
*/
|
||||
static struct pci_config_table pci_405gp_config_table[] = {
|
||||
/*if VendID is 0 it terminates the table search (ie Walnut)*/
|
||||
#if CFG_PCI_SUBSYS_VENDORID
|
||||
{CFG_PCI_SUBSYS_VENDORID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_bridge},
|
||||
#endif
|
||||
{PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
|
||||
|
||||
{PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA,
|
||||
PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, pci_405gp_setup_vga},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct pci_controller hose = {
|
||||
fixup_irq: pci_405gp_fixup_irq,
|
||||
config_table: pci_405gp_config_table,
|
||||
};
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
/*we want the ptrs to RAM not flash (ie don't use init list)*/
|
||||
hose.fixup_irq = pci_405gp_fixup_irq;
|
||||
hose.config_table = pci_405gp_config_table;
|
||||
pci_405gp_init(&hose);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#endif /* CONFIG_405GP */
|
||||
|
||||
/*-----------------------------------------------------------------------------+
|
||||
* CONFIG_440
|
||||
*-----------------------------------------------------------------------------*/
|
||||
#if defined(CONFIG_440) && defined(CONFIG_PCI)
|
||||
|
||||
static struct pci_controller ppc440_hose = {0};
|
||||
|
||||
|
||||
void pci_440_init (struct pci_controller *hose)
|
||||
{
|
||||
int reg_num = 0;
|
||||
unsigned long strap;
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* The PCI initialization sequence enable bit must be set ... if not abort
|
||||
* pci setup since updating the bit requires chip reset.
|
||||
*--------------------------------------------------------------------------*/
|
||||
strap = mfdcr(cpc0_strp1);
|
||||
if( (strap & 0x00040000) == 0 ){
|
||||
printf("PCI: CPC0_STRP1[PISE] not set.\n");
|
||||
printf("PCI: Configuration aborted.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI controller init
|
||||
*--------------------------------------------------------------------------*/
|
||||
hose->first_busno = 0;
|
||||
hose->last_busno = 0xff;
|
||||
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
0x00000000,
|
||||
PCIX0_IOBASE,
|
||||
0x10000,
|
||||
PCI_REGION_IO);
|
||||
|
||||
pci_set_region(hose->regions + reg_num++,
|
||||
CFG_PCI_TARGBASE,
|
||||
CFG_PCI_MEMBASE,
|
||||
0x10000000,
|
||||
PCI_REGION_MEM );
|
||||
hose->region_count = reg_num;
|
||||
|
||||
pci_setup_indirect(hose, PCIX0_CFGADR, PCIX0_CFGDATA);
|
||||
|
||||
#if defined(CFG_PCI_PRE_INIT)
|
||||
/* Let board change/modify hose & do initial checks */
|
||||
if( pci_pre_init (hose) == 0 ){
|
||||
printf("PCI: Board-specific initialization failed.\n");
|
||||
printf("PCI: Configuration aborted.\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
pci_register_hose( hose );
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI target init
|
||||
*--------------------------------------------------------------------------*/
|
||||
#if defined(CFG_PCI_TARGET_INIT)
|
||||
pci_target_init(hose); /* Let board setup pci target */
|
||||
#else
|
||||
out16r( PCIX0_SBSYSVID, CFG_PCI_SUBSYS_VENDORID );
|
||||
out16r( PCIX0_SBSYSID, CFG_PCI_SUBSYS_ID );
|
||||
out16r( PCIX0_CLS, 0x00060000 ); /* Bridge, host bridge */
|
||||
#endif
|
||||
|
||||
out32r( PCIX0_BRDGOPT1, 0x10000060 ); /* PLB Rq pri highest */
|
||||
out32r( PCIX0_BRDGOPT2, in32(PCIX0_BRDGOPT2) | 1 ); /* Enable host config */
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI master init: default is one 256MB region for PCI memory:
|
||||
* 0x3_00000000 - 0x3_0FFFFFFF ==> CFG_PCI_MEMBASE
|
||||
*--------------------------------------------------------------------------*/
|
||||
#if defined(CFG_PCI_MASTER_INIT)
|
||||
pci_master_init(hose); /* Let board setup pci master */
|
||||
#else
|
||||
out32r( PCIX0_POM0SA, 0 ); /* disable */
|
||||
out32r( PCIX0_POM1SA, 0 ); /* disable */
|
||||
out32r( PCIX0_POM2SA, 0 ); /* disable */
|
||||
out32r( PCIX0_POM0LAL, 0x00000000 );
|
||||
out32r( PCIX0_POM0LAH, 0x00000003 );
|
||||
out32r( PCIX0_POM0PCIAL, CFG_PCI_MEMBASE );
|
||||
out32r( PCIX0_POM0PCIAH, 0x00000000 );
|
||||
out32r( PCIX0_POM0SA, 0xf0000001 ); /* 256MB, enabled */
|
||||
out32r( PCIX0_STS, in32r( PCIX0_STS ) & ~0x0000fff8 );
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------------+
|
||||
* PCI host configuration -- we don't make any assumptions here ... the
|
||||
* _board_must_indicate_ what to do -- there's just too many runtime
|
||||
* scenarios in environments like cPCI, PPMC, etc. to make a determination
|
||||
* based on hard-coded values or state of arbiter enable.
|
||||
*--------------------------------------------------------------------------*/
|
||||
if( is_pci_host(hose) ){
|
||||
#ifdef CONFIG_PCI_SCAN_SHOW
|
||||
printf("PCI: Bus Dev VenId DevId Class Int\n");
|
||||
#endif
|
||||
out16r( PCIX0_CMD, in16r( PCIX0_CMD ) | PCI_COMMAND_MASTER);
|
||||
hose->last_busno = pci_hose_scan(hose);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pci_init(void)
|
||||
{
|
||||
pci_440_init (&ppc440_hose);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_440 & CONFIG_PCI */
|
||||
253
cpu/ppc4xx/cpu.c
Normal file
253
cpu/ppc4xx/cpu.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* m8xx.c
|
||||
*
|
||||
* CPU specific code
|
||||
*
|
||||
* written or collected and sometimes rewritten by
|
||||
* Magnus Damm <damm@bitsmart.com>
|
||||
*
|
||||
* minor modifications by
|
||||
* Wolfgang Denk <wd@denx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <command.h>
|
||||
#include <asm/cache.h>
|
||||
#include <ppc4xx.h>
|
||||
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
static int do_chip_reset( unsigned long sys0, unsigned long sys1 );
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int checkcpu (void)
|
||||
{
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_IOP480) || defined(CONFIG_440)
|
||||
uint pvr = get_pvr();
|
||||
#endif
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_IOP480)
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
ulong clock = gd->cpu_clk;
|
||||
char buf[32];
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
|
||||
PPC405_SYS_INFO sys_info;
|
||||
|
||||
puts ("CPU: ");
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
|
||||
#if CONFIG_405GP
|
||||
puts("IBM PowerPC 405GP");
|
||||
if (pvr == PVR_405GPR_RA) {
|
||||
putc('r');
|
||||
}
|
||||
puts(" Rev. ");
|
||||
#endif
|
||||
#if CONFIG_405CR
|
||||
puts("IBM PowerPC 405CR Rev. ");
|
||||
#endif
|
||||
switch (pvr) {
|
||||
case PVR_405GP_RB:
|
||||
putc('B');
|
||||
break;
|
||||
case PVR_405GP_RC:
|
||||
#if CONFIG_405CR
|
||||
case PVR_405CR_RC:
|
||||
#endif
|
||||
putc('C');
|
||||
break;
|
||||
case PVR_405GP_RD:
|
||||
putc('D');
|
||||
break;
|
||||
#if CONFIG_405GP
|
||||
case PVR_405GP_RE:
|
||||
putc('E');
|
||||
break;
|
||||
#endif
|
||||
case PVR_405CR_RA:
|
||||
case PVR_405GPR_RA:
|
||||
putc('A');
|
||||
break;
|
||||
case PVR_405CR_RB:
|
||||
putc('B');
|
||||
break;
|
||||
default:
|
||||
printf("? (PVR=%08x)", pvr);
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" at %s MHz (PLB=%lu, OPB=%lu, EBC=%lu MHz)\n", strmhz(buf, clock),
|
||||
sys_info.freqPLB / 1000000,
|
||||
sys_info.freqPLB / sys_info.pllOpbDiv / 1000000,
|
||||
sys_info.freqPLB / sys_info.pllExtBusDiv / 1000000);
|
||||
|
||||
#if CONFIG_405GP
|
||||
if (mfdcr(strap) & PSR_PCI_ASYNC_EN)
|
||||
printf(" PCI async ext clock used, ");
|
||||
else
|
||||
printf(" PCI sync clock at %lu MHz, ",
|
||||
sys_info.freqPLB / sys_info.pllPciDiv / 1000000);
|
||||
if (mfdcr(strap) & PSR_PCI_ARBIT_EN)
|
||||
printf("internal PCI arbiter enabled\n");
|
||||
else
|
||||
printf("external PCI arbiter enabled\n");
|
||||
#endif
|
||||
|
||||
if ((pvr | 0x00000001) == PVR_405GPR_RA) {
|
||||
printf(" 16 kB I-Cache 16 kB D-Cache");
|
||||
} else {
|
||||
printf(" 16 kB I-Cache 8 kB D-Cache");
|
||||
}
|
||||
|
||||
|
||||
#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
|
||||
|
||||
#ifdef CONFIG_IOP480
|
||||
printf("PLX IOP480 (PVR=%08x)", pvr);
|
||||
printf(" at %s MHz:", strmhz(buf, clock));
|
||||
printf(" %u kB I-Cache", 4);
|
||||
printf(" %u kB D-Cache", 2);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
puts("IBM PowerPC 440 Rev. ");
|
||||
switch(pvr)
|
||||
{
|
||||
case PVR_440GP_RB:
|
||||
putc('B');
|
||||
/* See errata 1.12: CHIP_4 */
|
||||
if( ( mfdcr(cpc0_sys0) != mfdcr(cpc0_strp0) )
|
||||
||( mfdcr(cpc0_sys1) != mfdcr(cpc0_strp1) ) ){
|
||||
puts("\n\t CPC0_SYSx DCRs corrupted. Resetting chip ...\n");
|
||||
udelay( 1000 * 1000 ); /* Give time for serial buf to clear */
|
||||
do_chip_reset( mfdcr(cpc0_strp0), mfdcr(cpc0_strp1) );
|
||||
}
|
||||
break;
|
||||
case PVR_440GP_RC:
|
||||
putc('C');
|
||||
break;
|
||||
default:
|
||||
printf("UNKNOWN (PVR=%08x)", pvr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
|
||||
{
|
||||
/*
|
||||
* Initiate system reset in debug control register DBCR
|
||||
*/
|
||||
__asm__ __volatile__("lis 3, 0x3000" ::: "r3");
|
||||
#if defined(CONFIG_440)
|
||||
__asm__ __volatile__("mtspr 0x134, 3");
|
||||
#else
|
||||
__asm__ __volatile__("mtspr 0x3f2, 3");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
static
|
||||
int do_chip_reset( unsigned long sys0, unsigned long sys1 )
|
||||
{
|
||||
/* Changes to cpc0_sys0 and cpc0_sys1 require chip
|
||||
* reset.
|
||||
*/
|
||||
mtdcr( cntrl0, mfdcr(cntrl0) | 0x80000000 ); /* Set SWE */
|
||||
mtdcr( cpc0_sys0, sys0 );
|
||||
mtdcr( cpc0_sys1, sys1 );
|
||||
mtdcr( cntrl0, mfdcr(cntrl0) & ~0x80000000 ); /* Clr SWE */
|
||||
mtspr( dbcr0, 0x20000000); /* Reset the chip */
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Get timebase clock frequency
|
||||
*/
|
||||
unsigned long get_tbclk (void)
|
||||
{
|
||||
#if defined(CONFIG_440)
|
||||
|
||||
sys_info_t sys_info;
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
return (sys_info.freqProcessor);
|
||||
|
||||
#elif defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405)
|
||||
|
||||
PPC405_SYS_INFO sys_info;
|
||||
|
||||
get_sys_info(&sys_info);
|
||||
return (sys_info.freqProcessor);
|
||||
|
||||
#elif defined(CONFIG_IOP480)
|
||||
|
||||
return (66000000);
|
||||
|
||||
#else
|
||||
|
||||
# error get_tbclk() not implemented
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_WATCHDOG)
|
||||
void
|
||||
watchdog_reset(void)
|
||||
{
|
||||
int re_enable = disable_interrupts();
|
||||
reset_4xx_watchdog();
|
||||
if (re_enable) enable_interrupts();
|
||||
}
|
||||
|
||||
void
|
||||
reset_4xx_watchdog(void)
|
||||
{
|
||||
/*
|
||||
* Clear TSR(WIS) bit
|
||||
*/
|
||||
mtspr(tsr, 0x40000000);
|
||||
}
|
||||
#endif /* CONFIG_WATCHDOG */
|
||||
417
cpu/ppc4xx/i2c.c
Normal file
417
cpu/ppc4xx/i2c.c
Normal file
@@ -0,0 +1,417 @@
|
||||
/*****************************************************************************/
|
||||
/* I2C Bus interface initialisation and I2C Commands */
|
||||
/* for PPC405GP */
|
||||
/* Author : AS HARNOIS */
|
||||
/* Date : 13.Dec.00 */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
#include <ppc4xx.h>
|
||||
#if defined(CONFIG_440)
|
||||
# include <440_i2c.h>
|
||||
#else
|
||||
# include <405gp_i2c.h>
|
||||
#endif
|
||||
#include <i2c.h>
|
||||
|
||||
#ifdef CONFIG_HARD_I2C
|
||||
|
||||
#define IIC_OK 0
|
||||
#define IIC_NOK 1
|
||||
#define IIC_NOK_LA 2 /* Lost arbitration */
|
||||
#define IIC_NOK_ICT 3 /* Incomplete transfer */
|
||||
#define IIC_NOK_XFRA 4 /* Transfer aborted */
|
||||
#define IIC_NOK_DATA 5 /* No data in buffer */
|
||||
#define IIC_NOK_TOUT 6 /* Transfer timeout */
|
||||
|
||||
#define IIC_TIMEOUT 1 /* 1 seconde */
|
||||
|
||||
|
||||
static void _i2c_bus_reset (void)
|
||||
{
|
||||
int i, status;
|
||||
|
||||
/* Reset status register */
|
||||
/* write 1 in SCMP and IRQA to clear these fields */
|
||||
out8 (IIC_STS, 0x0A);
|
||||
|
||||
/* write 1 in IRQP IRQD LA ICT XFRA to clear these fields */
|
||||
out8 (IIC_EXTSTS, 0x8F);
|
||||
__asm__ volatile ("eieio");
|
||||
|
||||
/*
|
||||
* Get current state, reset bus
|
||||
* only if no transfers are pending.
|
||||
*/
|
||||
i = 10;
|
||||
do {
|
||||
/* Get status */
|
||||
status = in8 (IIC_STS);
|
||||
udelay (500); /* 500us */
|
||||
i--;
|
||||
} while ((status & IIC_STS_PT) && (i > 0));
|
||||
/* Soft reset controller */
|
||||
status = in8 (IIC_XTCNTLSS);
|
||||
out8 (IIC_XTCNTLSS, (status | IIC_XTCNTLSS_SRST));
|
||||
__asm__ volatile ("eieio");
|
||||
|
||||
/* make sure where in initial state, data hi, clock hi */
|
||||
out8 (IIC_DIRECTCNTL, 0xC);
|
||||
for (i = 0; i < 10; i++) {
|
||||
if ((in8 (IIC_DIRECTCNTL) & 0x3) != 0x3) {
|
||||
/* clock until we get to known state */
|
||||
out8 (IIC_DIRECTCNTL, 0x8); /* clock lo */
|
||||
udelay (100); /* 100us */
|
||||
out8 (IIC_DIRECTCNTL, 0xC); /* clock hi */
|
||||
udelay (100); /* 100us */
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* send start condition */
|
||||
out8 (IIC_DIRECTCNTL, 0x4);
|
||||
udelay (1000); /* 1ms */
|
||||
/* send stop condition */
|
||||
out8 (IIC_DIRECTCNTL, 0xC);
|
||||
udelay (1000); /* 1ms */
|
||||
/* Unreset controller */
|
||||
out8 (IIC_XTCNTLSS, (status & ~IIC_XTCNTLSS_SRST));
|
||||
udelay (1000); /* 1ms */
|
||||
}
|
||||
|
||||
void i2c_init (int speed, int slaveadd)
|
||||
{
|
||||
sys_info_t sysInfo;
|
||||
unsigned long freqOPB;
|
||||
int val, divisor;
|
||||
|
||||
/* Handle possible failed I2C state */
|
||||
_i2c_bus_reset ();
|
||||
|
||||
/* clear lo master address */
|
||||
out8 (IIC_LMADR, 0);
|
||||
|
||||
/* clear hi master address */
|
||||
out8 (IIC_HMADR, 0);
|
||||
|
||||
/* clear lo slave address */
|
||||
out8 (IIC_LSADR, 0);
|
||||
|
||||
/* clear hi slave address */
|
||||
out8 (IIC_HSADR, 0);
|
||||
|
||||
/* Clock divide Register */
|
||||
/* get OPB frequency */
|
||||
get_sys_info (&sysInfo);
|
||||
freqOPB = sysInfo.freqPLB / sysInfo.pllOpbDiv;
|
||||
/* set divisor according to freqOPB */
|
||||
divisor = (freqOPB - 1) / 10000000;
|
||||
if (divisor == 0)
|
||||
divisor = 1;
|
||||
out8 (IIC_CLKDIV, divisor);
|
||||
|
||||
/* no interrupts */
|
||||
out8 (IIC_INTRMSK, 0);
|
||||
|
||||
/* clear transfer count */
|
||||
out8 (IIC_XFRCNT, 0);
|
||||
|
||||
/* clear extended control & stat */
|
||||
/* write 1 in SRC SRS SWC SWS to clear these fields */
|
||||
out8 (IIC_XTCNTLSS, 0xF0);
|
||||
|
||||
/* Mode Control Register
|
||||
Flush Slave/Master data buffer */
|
||||
out8 (IIC_MDCNTL, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
|
||||
__asm__ volatile ("eieio");
|
||||
|
||||
|
||||
val = in8(IIC_MDCNTL);
|
||||
__asm__ volatile ("eieio");
|
||||
|
||||
/* Ignore General Call, slave transfers are ignored,
|
||||
disable interrupts, exit unknown bus state, enable hold
|
||||
SCL
|
||||
100kHz normaly or FastMode for 400kHz and above
|
||||
*/
|
||||
|
||||
val |= IIC_MDCNTL_EUBS|IIC_MDCNTL_HSCL;
|
||||
if( speed >= 400000 ){
|
||||
val |= IIC_MDCNTL_FSM;
|
||||
}
|
||||
out8 (IIC_MDCNTL, val);
|
||||
|
||||
/* clear control reg */
|
||||
out8 (IIC_CNTL, 0x00);
|
||||
__asm__ volatile ("eieio");
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
This code tries to use the features of the 405GP i2c
|
||||
controller. It will transfer up to 4 bytes in one pass
|
||||
on the loop. It only does out8(lbz) to the buffer when it
|
||||
is possible to do out16(lhz) transfers.
|
||||
|
||||
cmd_type is 0 for write 1 for read.
|
||||
|
||||
addr_len can take any value from 0-255, it is only limited
|
||||
by the char, we could make it larger if needed. If it is
|
||||
0 we skip the address write cycle.
|
||||
|
||||
Typical case is a Write of an addr followd by a Read. The
|
||||
IBM FAQ does not cover this. On the last byte of the write
|
||||
we don't set the creg CHT bit, and on the first bytes of the
|
||||
read we set the RPST bit.
|
||||
|
||||
It does not support address only transfers, there must be
|
||||
a data part. If you want to write the address yourself, put
|
||||
it in the data pointer.
|
||||
|
||||
It does not support transfer to/from address 0.
|
||||
|
||||
It does not check XFRCNT.
|
||||
*/
|
||||
static
|
||||
int i2c_transfer(unsigned char cmd_type,
|
||||
unsigned char chip,
|
||||
unsigned char addr[],
|
||||
unsigned char addr_len,
|
||||
unsigned char data[],
|
||||
unsigned short data_len )
|
||||
{
|
||||
unsigned char* ptr;
|
||||
int reading;
|
||||
int tran,cnt;
|
||||
int result;
|
||||
int status;
|
||||
int i;
|
||||
uchar creg;
|
||||
|
||||
if( data == 0 || data_len == 0 ){
|
||||
/*Don't support data transfer of no length or to address 0*/
|
||||
printf( "i2c_transfer: bad call\n" );
|
||||
return IIC_NOK;
|
||||
}
|
||||
if( addr && addr_len ){
|
||||
ptr = addr;
|
||||
cnt = addr_len;
|
||||
reading = 0;
|
||||
}else{
|
||||
ptr = data;
|
||||
cnt = data_len;
|
||||
reading = cmd_type;
|
||||
}
|
||||
|
||||
/*Clear Stop Complete Bit*/
|
||||
out8(IIC_STS,IIC_STS_SCMP);
|
||||
/* Check init */
|
||||
i=10;
|
||||
do {
|
||||
/* Get status */
|
||||
status = in8(IIC_STS);
|
||||
__asm__ volatile("eieio");
|
||||
i--;
|
||||
} while ((status & IIC_STS_PT) && (i>0));
|
||||
|
||||
if (status & IIC_STS_PT) {
|
||||
result = IIC_NOK_TOUT;
|
||||
return(result);
|
||||
}
|
||||
/*flush the Master/Slave Databuffers*/
|
||||
out8(IIC_MDCNTL, ((in8(IIC_MDCNTL))|IIC_MDCNTL_FMDB|IIC_MDCNTL_FSDB));
|
||||
/*need to wait 4 OPB clocks? code below should take that long*/
|
||||
|
||||
/* 7-bit adressing */
|
||||
out8(IIC_HMADR,0);
|
||||
out8(IIC_LMADR, chip);
|
||||
__asm__ volatile("eieio");
|
||||
|
||||
tran = 0;
|
||||
result = IIC_OK;
|
||||
creg = 0;
|
||||
|
||||
while ( tran != cnt && (result == IIC_OK)) {
|
||||
int bc,j;
|
||||
|
||||
/* Control register =
|
||||
Normal transfer, 7-bits adressing, Transfer up to bc bytes, Normal start,
|
||||
Transfer is a sequence of transfers
|
||||
*/
|
||||
creg |= IIC_CNTL_PT;
|
||||
|
||||
bc = (cnt - tran) > 4 ? 4 :
|
||||
cnt - tran;
|
||||
creg |= (bc-1)<<4;
|
||||
/* if the real cmd type is write continue trans*/
|
||||
if ( (!cmd_type && (ptr == addr)) || ((tran+bc) != cnt) )
|
||||
creg |= IIC_CNTL_CHT;
|
||||
|
||||
if (reading)
|
||||
creg |= IIC_CNTL_READ;
|
||||
else {
|
||||
for(j=0; j<bc; j++) {
|
||||
/* Set buffer */
|
||||
out8(IIC_MDBUF,ptr[tran+j]);
|
||||
__asm__ volatile("eieio");
|
||||
}
|
||||
}
|
||||
out8(IIC_CNTL, creg );
|
||||
__asm__ volatile("eieio");
|
||||
|
||||
/* Transfer is in progress
|
||||
we have to wait for upto 5 bytes of data
|
||||
1 byte chip address+r/w bit then bc bytes
|
||||
of data.
|
||||
udelay(10) is 1 bit time at 100khz
|
||||
Doubled for slop. 20 is too small.
|
||||
*/
|
||||
i=2*5*8;
|
||||
do {
|
||||
/* Get status */
|
||||
status = in8(IIC_STS);
|
||||
__asm__ volatile("eieio");
|
||||
udelay (10);
|
||||
i--;
|
||||
} while ((status & IIC_STS_PT) && !(status & IIC_STS_ERR)
|
||||
&& (i>0));
|
||||
|
||||
if (status & IIC_STS_ERR) {
|
||||
result = IIC_NOK;
|
||||
status = in8 (IIC_EXTSTS);
|
||||
/* Lost arbitration? */
|
||||
if (status & IIC_EXTSTS_LA)
|
||||
result = IIC_NOK_LA;
|
||||
/* Incomplete transfer? */
|
||||
if (status & IIC_EXTSTS_ICT)
|
||||
result = IIC_NOK_ICT;
|
||||
/* Transfer aborted? */
|
||||
if (status & IIC_EXTSTS_XFRA)
|
||||
result = IIC_NOK_XFRA;
|
||||
} else if ( status & IIC_STS_PT) {
|
||||
result = IIC_NOK_TOUT;
|
||||
}
|
||||
/* Command is reading => get buffer */
|
||||
if ((reading) && (result == IIC_OK)) {
|
||||
/* Are there data in buffer */
|
||||
if (status & IIC_STS_MDBS) {
|
||||
/*
|
||||
even if we have data we have to wait 4OPB clocks
|
||||
for it to hit the front of the FIFO, after that
|
||||
we can just read. We should check XFCNT here and
|
||||
if the FIFO is full there is no need to wait.
|
||||
*/
|
||||
udelay (1);
|
||||
for(j=0;j<bc;j++) {
|
||||
ptr[tran+j] = in8(IIC_MDBUF);
|
||||
__asm__ volatile("eieio");
|
||||
}
|
||||
} else
|
||||
result = IIC_NOK_DATA;
|
||||
}
|
||||
creg = 0;
|
||||
tran+=bc;
|
||||
if( ptr == addr && tran == cnt ) {
|
||||
ptr = data;
|
||||
cnt = data_len;
|
||||
tran = 0;
|
||||
reading = cmd_type;
|
||||
if( reading )
|
||||
creg = IIC_CNTL_RPST;
|
||||
}
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
int i2c_probe (uchar chip)
|
||||
{
|
||||
uchar buf[1];
|
||||
|
||||
buf[0] = 0;
|
||||
|
||||
/*
|
||||
* What is needed is to send the chip address and verify that the
|
||||
* address was <ACK>ed (i.e. there was a chip at that address which
|
||||
* drove the data line low).
|
||||
*/
|
||||
return(i2c_transfer (1, chip << 1, 0,0, buf, 1) != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
|
||||
{
|
||||
uchar xaddr[4];
|
||||
int ret;
|
||||
|
||||
if ( alen > 4 ) {
|
||||
printf ("I2C read: addr len %d not supported\n", alen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( alen > 0 ) {
|
||||
xaddr[0] = (addr >> 24) & 0xFF;
|
||||
xaddr[1] = (addr >> 16) & 0xFF;
|
||||
xaddr[2] = (addr >> 8) & 0xFF;
|
||||
xaddr[3] = addr & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
|
||||
/*
|
||||
* EEPROM chips that implement "address overflow" are ones
|
||||
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
|
||||
* address and the extra bits end up in the "chip address"
|
||||
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
|
||||
* four 256 byte chips.
|
||||
*
|
||||
* Note that we consider the length of the address field to
|
||||
* still be one byte because the extra address bits are
|
||||
* hidden in the chip address.
|
||||
*/
|
||||
if( alen > 0 )
|
||||
chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
|
||||
#endif
|
||||
if( (ret = i2c_transfer( 1, chip<<1, &xaddr[4-alen], alen, buffer, len )) != 0) {
|
||||
printf( "I2c read: failed %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
|
||||
{
|
||||
uchar xaddr[4];
|
||||
|
||||
if ( alen > 4 ) {
|
||||
printf ("I2C write: addr len %d not supported\n", alen);
|
||||
return 1;
|
||||
|
||||
}
|
||||
if ( alen > 0 ) {
|
||||
xaddr[0] = (addr >> 24) & 0xFF;
|
||||
xaddr[1] = (addr >> 16) & 0xFF;
|
||||
xaddr[2] = (addr >> 8) & 0xFF;
|
||||
xaddr[3] = addr & 0xFF;
|
||||
}
|
||||
|
||||
#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
|
||||
/*
|
||||
* EEPROM chips that implement "address overflow" are ones
|
||||
* like Catalyst 24WC04/08/16 which has 9/10/11 bits of
|
||||
* address and the extra bits end up in the "chip address"
|
||||
* bit slots. This makes a 24WC08 (1Kbyte) chip look like
|
||||
* four 256 byte chips.
|
||||
*
|
||||
* Note that we consider the length of the address field to
|
||||
* still be one byte because the extra address bits are
|
||||
* hidden in the chip address.
|
||||
*/
|
||||
if( alen > 0 )
|
||||
chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
|
||||
#endif
|
||||
|
||||
return (i2c_transfer( 0, chip<<1, &xaddr[4-alen], alen, buffer, len ) != 0);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HARD_I2C */
|
||||
191
cpu/ppc4xx/sdram.c
Normal file
191
cpu/ppc4xx/sdram.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
#include <pci.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_SDRAM_BANK0
|
||||
|
||||
|
||||
#define MAGIC0 0x00000000
|
||||
#define MAGIC1 0x11111111
|
||||
#define MAGIC2 0x22222222
|
||||
#define MAGIC3 0x33333333
|
||||
#define MAGIC4 0x44444444
|
||||
|
||||
#define ADDR_ZERO 0x00000000
|
||||
#define ADDR_400 0x00000400
|
||||
#define ADDR_08MB 0x00800000
|
||||
#define ADDR_16MB 0x01000000
|
||||
#define ADDR_32MB 0x02000000
|
||||
#define ADDR_64MB 0x04000000
|
||||
|
||||
#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data)
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
*/
|
||||
void sdram_init(void)
|
||||
{
|
||||
ulong speed;
|
||||
ulong sdtr1;
|
||||
ulong rtr;
|
||||
|
||||
/*
|
||||
* Determine SDRAM speed
|
||||
*/
|
||||
speed = get_bus_freq(0); /* parameter not used on ppc4xx */
|
||||
|
||||
/*
|
||||
* Support for 100MHz and 133MHz SDRAM
|
||||
*/
|
||||
if (speed > 100000000) {
|
||||
/*
|
||||
* 133 MHz SDRAM
|
||||
*/
|
||||
sdtr1 = 0x01074015;
|
||||
rtr = 0x07f00000;
|
||||
} else {
|
||||
/*
|
||||
* default: 100 MHz SDRAM
|
||||
*/
|
||||
sdtr1 = 0x0086400d;
|
||||
rtr = 0x05f00000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set MB0CF for bank 0. (0-64MB) Address Mode 3 since 13x9(4)
|
||||
*/
|
||||
mtsdram0(mem_mb0cf, 0x00084001);
|
||||
|
||||
mtsdram0(mem_sdtr1, sdtr1);
|
||||
mtsdram0(mem_rtr, rtr);
|
||||
|
||||
/*
|
||||
* Wait for 200us
|
||||
*/
|
||||
udelay(200);
|
||||
|
||||
/*
|
||||
* Set memory controller options reg, MCOPT1.
|
||||
* Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
|
||||
* read/prefetch.
|
||||
*/
|
||||
mtsdram0(mem_mcopt1, 0x80800000);
|
||||
|
||||
/*
|
||||
* Wait for 10ms
|
||||
*/
|
||||
udelay(10000);
|
||||
|
||||
/*
|
||||
* Test if 64 MByte are equipped (mirror test)
|
||||
*/
|
||||
*(volatile ulong *)ADDR_ZERO = MAGIC0;
|
||||
*(volatile ulong *)ADDR_08MB = MAGIC1;
|
||||
*(volatile ulong *)ADDR_16MB = MAGIC2;
|
||||
*(volatile ulong *)ADDR_32MB = MAGIC3;
|
||||
|
||||
if ((*(volatile ulong *)ADDR_ZERO == MAGIC0) &&
|
||||
(*(volatile ulong *)ADDR_08MB == MAGIC1) &&
|
||||
(*(volatile ulong *)ADDR_16MB == MAGIC2)) {
|
||||
/*
|
||||
* OK, 64MB detected -> all done
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now test for 32 MByte...
|
||||
*/
|
||||
|
||||
/*
|
||||
* Disable memory controller.
|
||||
*/
|
||||
mtsdram0(mem_mcopt1, 0x00000000);
|
||||
|
||||
/*
|
||||
* Set MB0CF for bank 0. (0-32MB) Address Mode 2 since 12x9(4)
|
||||
*/
|
||||
mtsdram0(mem_mb0cf, 0x00062001);
|
||||
|
||||
/*
|
||||
* Set memory controller options reg, MCOPT1.
|
||||
* Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
|
||||
* read/prefetch.
|
||||
*/
|
||||
mtsdram0(mem_mcopt1, 0x80800000);
|
||||
|
||||
/*
|
||||
* Wait for 10ms
|
||||
*/
|
||||
udelay(10000);
|
||||
|
||||
/*
|
||||
* Test if 32 MByte are equipped (mirror test)
|
||||
*/
|
||||
*(volatile ulong *)ADDR_ZERO = MAGIC0;
|
||||
*(volatile ulong *)ADDR_400 = MAGIC1;
|
||||
*(volatile ulong *)ADDR_08MB = MAGIC2;
|
||||
*(volatile ulong *)ADDR_16MB = MAGIC3;
|
||||
|
||||
if ((*(volatile ulong *)ADDR_ZERO == MAGIC0) &&
|
||||
(*(volatile ulong *)ADDR_400 == MAGIC1) &&
|
||||
(*(volatile ulong *)ADDR_08MB == MAGIC2)) {
|
||||
/*
|
||||
* OK, 32MB detected -> all done
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup for 16 MByte...
|
||||
*/
|
||||
|
||||
/*
|
||||
* Disable memory controller.
|
||||
*/
|
||||
mtsdram0(mem_mcopt1, 0x00000000);
|
||||
|
||||
/*
|
||||
* Set MB0CF for bank 0. (0-16MB) Address Mode 4 since 12x8(4)
|
||||
*/
|
||||
mtsdram0(mem_mb0cf, 0x00046001);
|
||||
|
||||
/*
|
||||
* Set memory controller options reg, MCOPT1.
|
||||
* Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst
|
||||
* read/prefetch.
|
||||
*/
|
||||
mtsdram0(mem_mcopt1, 0x80800000);
|
||||
|
||||
/*
|
||||
* Wait for 10ms
|
||||
*/
|
||||
udelay(10000);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SDRAM_BANK0 */
|
||||
308
cpu/ppc4xx/speed.c
Normal file
308
cpu/ppc4xx/speed.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <ppc_asm.tmpl>
|
||||
#include <ppc4xx.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define ONE_BILLION 1000000000
|
||||
|
||||
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
|
||||
|
||||
void get_sys_info (PPC405_SYS_INFO * sysInfo)
|
||||
{
|
||||
unsigned long pllmr;
|
||||
unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
|
||||
uint pvr = get_pvr();
|
||||
unsigned long psr;
|
||||
unsigned long m;
|
||||
|
||||
/*
|
||||
* Read PLL Mode register
|
||||
*/
|
||||
pllmr = mfdcr (pllmd);
|
||||
|
||||
/*
|
||||
* Read Pin Strapping register
|
||||
*/
|
||||
psr = mfdcr (strap);
|
||||
|
||||
/*
|
||||
* Determine FWD_DIV.
|
||||
*/
|
||||
sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
|
||||
|
||||
/*
|
||||
* Determine FBK_DIV.
|
||||
*/
|
||||
sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
|
||||
if (sysInfo->pllFbkDiv == 0) {
|
||||
sysInfo->pllFbkDiv = 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine PLB_DIV.
|
||||
*/
|
||||
sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
|
||||
|
||||
/*
|
||||
* Determine PCI_DIV.
|
||||
*/
|
||||
sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
|
||||
|
||||
/*
|
||||
* Determine EXTBUS_DIV.
|
||||
*/
|
||||
sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
|
||||
|
||||
/*
|
||||
* Determine OPB_DIV.
|
||||
*/
|
||||
sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
|
||||
|
||||
/*
|
||||
* Check if PPC405GPr used (mask minor revision field)
|
||||
*/
|
||||
if ((pvr & 0xfffffff0) == (PVR_405GPR_RA & 0xfffffff0)) {
|
||||
/*
|
||||
* Determine FWD_DIV B (only PPC405GPr with new mode strapping).
|
||||
*/
|
||||
sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
|
||||
|
||||
/*
|
||||
* Determine factor m depending on PLL feedback clock source
|
||||
*/
|
||||
if (!(psr & PSR_PCI_ASYNC_EN)) {
|
||||
if (psr & PSR_NEW_MODE_EN) {
|
||||
/*
|
||||
* sync pci clock used as feedback (new mode)
|
||||
*/
|
||||
m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
|
||||
} else {
|
||||
/*
|
||||
* sync pci clock used as feedback (legacy mode)
|
||||
*/
|
||||
m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
|
||||
}
|
||||
} else if (psr & PSR_NEW_MODE_EN) {
|
||||
if (psr & PSR_PERCLK_SYNC_MODE_EN) {
|
||||
/*
|
||||
* PerClk used as feedback (new mode)
|
||||
*/
|
||||
m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
|
||||
} else {
|
||||
/*
|
||||
* CPU clock used as feedback (new mode)
|
||||
*/
|
||||
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
|
||||
}
|
||||
} else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
|
||||
/*
|
||||
* PerClk used as feedback (legacy mode)
|
||||
*/
|
||||
m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
|
||||
} else {
|
||||
/*
|
||||
* PLB clock used as feedback (legacy mode)
|
||||
*/
|
||||
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
|
||||
}
|
||||
|
||||
sysInfo->freqVCOMhz = (1000000 * m) / sysClkPeriodPs;
|
||||
sysInfo->freqProcessor = (sysInfo->freqVCOMhz * 1000000) / sysInfo->pllFwdDiv;
|
||||
sysInfo->freqPLB = (sysInfo->freqVCOMhz * 1000000) /
|
||||
(sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
|
||||
} else {
|
||||
/*
|
||||
* Check pllFwdDiv to see if running in bypass mode where the CPU speed
|
||||
* is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
|
||||
* to make sure it is within the proper range.
|
||||
* spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
|
||||
* Note freqVCO is calculated in Mhz to avoid errors introduced by rounding.
|
||||
*/
|
||||
if (sysInfo->pllFwdDiv == 1) {
|
||||
sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
|
||||
sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
|
||||
} else {
|
||||
sysInfo->freqVCOMhz = ( 1000000 *
|
||||
sysInfo->pllFwdDiv *
|
||||
sysInfo->pllFbkDiv *
|
||||
sysInfo->pllPlbDiv
|
||||
) / sysClkPeriodPs;
|
||||
if (sysInfo->freqVCOMhz >= VCO_MIN
|
||||
&& sysInfo->freqVCOMhz <= VCO_MAX) {
|
||||
sysInfo->freqPLB = (ONE_BILLION /
|
||||
((sysClkPeriodPs * 10) /
|
||||
sysInfo->pllFbkDiv)) * 10000;
|
||||
sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
|
||||
} else {
|
||||
printf ("\nInvalid VCO frequency calculated : %ld MHz \a\n",
|
||||
sysInfo->freqVCOMhz);
|
||||
printf ("It must be between %d-%d MHz \a\n",
|
||||
VCO_MIN, VCO_MAX);
|
||||
printf ("PLL Mode reg : %8.8lx\a\n",
|
||||
pllmr);
|
||||
hang ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* get_OPB_freq
|
||||
* return OPB bus freq in Hz
|
||||
*********************************************/
|
||||
ulong get_OPB_freq (void)
|
||||
{
|
||||
ulong val = 0;
|
||||
|
||||
PPC405_SYS_INFO sys_info;
|
||||
|
||||
get_sys_info (&sys_info);
|
||||
val = sys_info.freqPLB / sys_info.pllOpbDiv;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* get_PCI_freq
|
||||
* return PCI bus freq in Hz
|
||||
*********************************************/
|
||||
ulong get_PCI_freq (void)
|
||||
{
|
||||
ulong val;
|
||||
PPC405_SYS_INFO sys_info;
|
||||
|
||||
get_sys_info (&sys_info);
|
||||
val = sys_info.freqPLB / sys_info.pllPciDiv;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(CONFIG_440)
|
||||
void get_sys_info (sys_info_t * sysInfo)
|
||||
{
|
||||
unsigned long strp0;
|
||||
unsigned long temp;
|
||||
unsigned long m;
|
||||
|
||||
/* Extract configured divisors */
|
||||
strp0 = mfdcr( cpc0_strp0 );
|
||||
sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
|
||||
sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
|
||||
temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
|
||||
sysInfo->pllFbkDiv = temp ? temp : 16;
|
||||
sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
|
||||
sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
|
||||
|
||||
/* Calculate 'M' based on feedback source */
|
||||
if( strp0 & PLLSYS0_EXTSL_MASK )
|
||||
m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
|
||||
else
|
||||
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
|
||||
|
||||
/* Now calculate the individual clocks */
|
||||
sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
|
||||
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
|
||||
sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
|
||||
if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
|
||||
sysInfo->freqPLB >>= 1;
|
||||
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
|
||||
sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
|
||||
|
||||
}
|
||||
|
||||
ulong get_OPB_freq (void)
|
||||
{
|
||||
|
||||
sys_info_t sys_info;
|
||||
get_sys_info (&sys_info);
|
||||
return sys_info.freqOPB;
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_405)
|
||||
|
||||
void get_sys_info (sys_info_t * sysInfo) {
|
||||
|
||||
sysInfo->freqVCOMhz=3125000;
|
||||
sysInfo->freqProcessor=12*1000*1000;
|
||||
sysInfo->freqPLB=50*1000*1000;
|
||||
sysInfo->freqPCI=66*1000*1000;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int get_clocks (void)
|
||||
{
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405)
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
sys_info_t sys_info;
|
||||
|
||||
get_sys_info (&sys_info);
|
||||
gd->cpu_clk = sys_info.freqProcessor;
|
||||
gd->bus_clk = sys_info.freqPLB;
|
||||
|
||||
#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
|
||||
|
||||
#ifdef CONFIG_IOP480
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
gd->cpu_clk = 66000000;
|
||||
gd->bus_clk = 66000000;
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* get_bus_freq
|
||||
* return PLB bus freq in Hz
|
||||
*********************************************/
|
||||
ulong get_bus_freq (ulong dummy)
|
||||
{
|
||||
ulong val;
|
||||
|
||||
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_440)
|
||||
sys_info_t sys_info;
|
||||
|
||||
get_sys_info (&sys_info);
|
||||
val = sys_info.freqPLB;
|
||||
|
||||
#elif defined(CONFIG_IOP480)
|
||||
|
||||
val = 66;
|
||||
|
||||
#else
|
||||
# error get_bus_freq() not implemented
|
||||
#endif
|
||||
|
||||
return val;
|
||||
}
|
||||
100
cpu/ppc4xx/vecnum.h
Normal file
100
cpu/ppc4xx/vecnum.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Scott McNutt <smcnutt@artesyncp.com>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interrupt vector number definitions to ease the
|
||||
* 405 -- 440 porting pain ;-)
|
||||
*
|
||||
* NOTE: They're not all here yet ... update as needed.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VECNUMS_H_
|
||||
#define _VECNUMS_H_
|
||||
|
||||
#if defined(CONFIG_440)
|
||||
|
||||
/* UIC 0 */
|
||||
#define VECNUM_U0 0 /* UART0 */
|
||||
#define VECNUM_U1 1 /* UART1 */
|
||||
#define VECNUM_IIC0 2 /* IIC0 */
|
||||
#define VECNUM_IIC1 3 /* IIC1 */
|
||||
#define VECNUM_PIM 4 /* PCI inbound message */
|
||||
#define VECNUM_PCRW 5 /* PCI command reg write */
|
||||
#define VECNUM_PPM 6 /* PCI power management */
|
||||
#define VECNUM_MSI0 7 /* PCI MSI level 0 */
|
||||
#define VECNUM_MSI1 8 /* PCI MSI level 0 */
|
||||
#define VECNUM_MSI2 9 /* PCI MSI level 0 */
|
||||
#define VECNUM_MTE 10 /* MAL TXEOB */
|
||||
#define VECNUM_MRE 11 /* MAL RXEOB */
|
||||
#define VECNUM_D0 12 /* DMA channel 0 */
|
||||
#define VECNUM_D1 13 /* DMA channel 1 */
|
||||
#define VECNUM_D2 14 /* DMA channel 2 */
|
||||
#define VECNUM_D3 15 /* DMA channel 3 */
|
||||
#define VECNUM_CT0 18 /* GPT compare timer 0 */
|
||||
#define VECNUM_CT1 19 /* GPT compare timer 1 */
|
||||
#define VECNUM_CT2 20 /* GPT compare timer 2 */
|
||||
#define VECNUM_CT3 21 /* GPT compare timer 3 */
|
||||
#define VECNUM_CT4 22 /* GPT compare timer 4 */
|
||||
#define VECNUM_EIR0 23 /* External interrupt 0 */
|
||||
#define VECNUM_EIR1 24 /* External interrupt 1 */
|
||||
#define VECNUM_EIR2 25 /* External interrupt 2 */
|
||||
#define VECNUM_EIR3 26 /* External interrupt 3 */
|
||||
#define VECNUM_EIR4 27 /* External interrupt 4 */
|
||||
#define VECNUM_EIR5 28 /* External interrupt 5 */
|
||||
#define VECNUM_EIR6 29 /* External interrupt 6 */
|
||||
#define VECNUM_UIC1NC 30 /* UIC1 non-critical interrupt */
|
||||
#define VECNUM_UIC1C 31 /* UIC1 critical interrupt */
|
||||
|
||||
/* UIC 1 */
|
||||
#define VECNUM_MS (32 + 0 ) /* MAL SERR */
|
||||
#define VECNUM_TXDE (32 + 1 ) /* MAL TXDE */
|
||||
#define VECNUM_RXDE (32 + 2 ) /* MAL RXDE */
|
||||
#define VECNUM_ETH0 (32 + 28) /* Ethernet 0 interrupt status */
|
||||
#define VECNUM_EWU0 (32 + 29) /* Ethernet 0 wakeup */
|
||||
|
||||
#else /* !defined(CONFIG_440) */
|
||||
|
||||
#define VECNUM_U0 0 /* UART0 */
|
||||
#define VECNUM_U1 1 /* UART1 */
|
||||
#define VECNUM_D0 5 /* DMA channel 0 */
|
||||
#define VECNUM_D1 6 /* DMA channel 1 */
|
||||
#define VECNUM_D2 7 /* DMA channel 2 */
|
||||
#define VECNUM_D3 8 /* DMA channel 3 */
|
||||
#define VECNUM_EWU0 9 /* Ethernet wakeup */
|
||||
#define VECNUM_MS 10 /* MAL SERR */
|
||||
#define VECNUM_MTE 11 /* MAL TXEOB */
|
||||
#define VECNUM_MRE 12 /* MAL RXEOB */
|
||||
#define VECNUM_TXDE 13 /* MAL TXDE */
|
||||
#define VECNUM_RXDE 14 /* MAL RXDE */
|
||||
#define VECNUM_ETH0 15 /* Ethernet interrupt status */
|
||||
#define VECNUM_EIR0 25 /* External interrupt 0 */
|
||||
#define VECNUM_EIR1 26 /* External interrupt 1 */
|
||||
#define VECNUM_EIR2 27 /* External interrupt 2 */
|
||||
#define VECNUM_EIR3 28 /* External interrupt 3 */
|
||||
#define VECNUM_EIR4 29 /* External interrupt 4 */
|
||||
#define VECNUM_EIR5 30 /* External interrupt 5 */
|
||||
#define VECNUM_EIR6 31 /* External interrupt 6 */
|
||||
|
||||
#endif /* defined(CONFIG_440) */
|
||||
|
||||
#endif /* _VECNUMS_H_ */
|
||||
43
cpu/sa1100/Makefile
Normal file
43
cpu/sa1100/Makefile
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# (C) Copyright 2000
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# See file CREDITS for list of people who contributed to this
|
||||
# project.
|
||||
#
|
||||
# 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 program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
# MA 02111-1307 USA
|
||||
#
|
||||
|
||||
include $(TOPDIR)/config.mk
|
||||
|
||||
LIB = lib$(CPU).a
|
||||
|
||||
START = start.o
|
||||
OBJS = serial.o interrupts.o cpu.o
|
||||
|
||||
all: .depend $(START) $(LIB)
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) crv $@ $(OBJS)
|
||||
|
||||
#########################################################################
|
||||
|
||||
.depend: Makefile $(START:.o=.S) $(OBJS:.o=.c)
|
||||
$(CC) -M $(CFLAGS) $(START:.o=.S) $(OBJS:.o=.c) > $@
|
||||
|
||||
sinclude .depend
|
||||
|
||||
#########################################################################
|
||||
143
cpu/xscale/serial.c
Normal file
143
cpu/xscale/serial.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
|
||||
void serial_setbrg (void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
unsigned int quot = 0;
|
||||
|
||||
if (gd->baudrate == 1200)
|
||||
quot = 192;
|
||||
else if (gd->baudrate == 9600)
|
||||
quot = 96;
|
||||
else if (gd->baudrate == 19200)
|
||||
quot = 48;
|
||||
else if (gd->baudrate == 38400)
|
||||
quot = 24;
|
||||
else if (gd->baudrate == 57600)
|
||||
quot = 16;
|
||||
else if (gd->baudrate == 115200)
|
||||
quot = 8;
|
||||
else
|
||||
hang ();
|
||||
|
||||
#ifdef CONFIG_FFUART
|
||||
|
||||
CKEN |= CKEN6_FFUART;
|
||||
|
||||
FFIER = 0; /* Disable for now */
|
||||
FFFCR = 0; /* No fifos enabled */
|
||||
|
||||
/* set baud rate */
|
||||
FFLCR = LCR_WLS0 | LCR_WLS1 | LCR_DLAB;
|
||||
FFDLL = quot & 0xff;
|
||||
FFDLH = quot >> 8;
|
||||
FFLCR = LCR_WLS0 | LCR_WLS1;
|
||||
|
||||
FFIER = IER_UUE; /* Enable FFUART */
|
||||
|
||||
#elif CONFIG_STUART
|
||||
#error "Bad: not implemented yet!"
|
||||
#else
|
||||
#error "Bad: you didn't configured serial ..."
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*
|
||||
*/
|
||||
int serial_init (void)
|
||||
{
|
||||
serial_setbrg ();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Output a single byte to the serial port.
|
||||
*/
|
||||
void serial_putc (const char c)
|
||||
{
|
||||
#ifdef CONFIG_FFUART
|
||||
/* wait for room in the tx FIFO on FFUART */
|
||||
while ((FFLSR & LSR_TEMT) == 0);
|
||||
|
||||
FFTHR = c;
|
||||
#elif CONFIG_STUART
|
||||
#endif
|
||||
|
||||
/* If \n, also do \r */
|
||||
if (c == '\n')
|
||||
serial_putc ('\r');
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a single byte from the serial port. Returns 1 on success, 0
|
||||
* otherwise. When the function is succesfull, the character read is
|
||||
* written into its argument c.
|
||||
*/
|
||||
int serial_tstc (void)
|
||||
{
|
||||
#ifdef CONFIG_FFUART
|
||||
return FFLSR & LSR_DR;
|
||||
#elif CONFIG_STUART
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a single byte from the serial port. Returns 1 on success, 0
|
||||
* otherwise. When the function is succesfull, the character read is
|
||||
* written into its argument c.
|
||||
*/
|
||||
int serial_getc (void)
|
||||
{
|
||||
#ifdef CONFIG_FFUART
|
||||
while (!(FFLSR & LSR_DR));
|
||||
|
||||
return (char) FFRBR & 0xff;
|
||||
#elif CONFIG_STUART
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
serial_puts (const char *s)
|
||||
{
|
||||
while (*s) {
|
||||
serial_putc (*s++);
|
||||
}
|
||||
}
|
||||
412
cpu/xscale/start.S
Normal file
412
cpu/xscale/start.S
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* armboot - Startup Code for XScale
|
||||
*
|
||||
* Copyright (C) 1998 Dan Malek <dmalek@jlc.net>
|
||||
* Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
|
||||
* Copyright (C) 2000 Wolfgang Denk <wd@denx.de>
|
||||
* Copyright (c) 2001 Alex Z<EFBFBD>pke <azu@sysgo.de>
|
||||
* Copyright (c) 2002 Kyle Harris <kharris@nexus-tech.net>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <version.h>
|
||||
|
||||
.globl _start
|
||||
_start: b reset
|
||||
ldr pc, _undefined_instruction
|
||||
ldr pc, _software_interrupt
|
||||
ldr pc, _prefetch_abort
|
||||
ldr pc, _data_abort
|
||||
ldr pc, _not_used
|
||||
ldr pc, _irq
|
||||
ldr pc, _fiq
|
||||
|
||||
_undefined_instruction: .word undefined_instruction
|
||||
_software_interrupt: .word software_interrupt
|
||||
_prefetch_abort: .word prefetch_abort
|
||||
_data_abort: .word data_abort
|
||||
_not_used: .word not_used
|
||||
_irq: .word irq
|
||||
_fiq: .word fiq
|
||||
|
||||
.balignl 16,0xdeadbeef
|
||||
|
||||
|
||||
/*
|
||||
* Startup Code (reset vector)
|
||||
*
|
||||
* do important init only if we don't start from memory!
|
||||
* - relocate armboot to ram
|
||||
* - setup stack
|
||||
* - jump to second stage
|
||||
*/
|
||||
|
||||
/*
|
||||
* CFG_MEM_END is in the board dependent config-file (configs/config_BOARD.h)
|
||||
*/
|
||||
_TEXT_BASE:
|
||||
.word TEXT_BASE
|
||||
|
||||
.globl _armboot_start
|
||||
_armboot_start:
|
||||
.word _start
|
||||
|
||||
/*
|
||||
* Note: _armboot_end_data and _armboot_end are defined
|
||||
* by the (board-dependent) linker script.
|
||||
* _armboot_end_data is the first usable FLASH address after armboot
|
||||
*/
|
||||
.globl _armboot_end_data
|
||||
_armboot_end_data:
|
||||
.word armboot_end_data
|
||||
.globl _armboot_end
|
||||
_armboot_end:
|
||||
.word armboot_end
|
||||
|
||||
/*
|
||||
* _armboot_real_end is the first usable RAM address behind armboot
|
||||
* and the various stacks
|
||||
*/
|
||||
.globl _armboot_real_end
|
||||
_armboot_real_end:
|
||||
.word 0x0badc0de
|
||||
|
||||
/*
|
||||
* We relocate uboot to this address (end of RAM - 128 KiB)
|
||||
*/
|
||||
.globl _uboot_reloc
|
||||
_uboot_reloc:
|
||||
.word CFG_DRAM_BASE + CFG_DRAM_SIZE - CFG_MONITOR_LEN
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
/* IRQ stack memory (calculated at run-time) */
|
||||
.globl IRQ_STACK_START
|
||||
IRQ_STACK_START:
|
||||
.word 0x0badc0de
|
||||
|
||||
/* IRQ stack memory (calculated at run-time) */
|
||||
.globl FIQ_STACK_START
|
||||
FIQ_STACK_START:
|
||||
.word 0x0badc0de
|
||||
#endif
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* */
|
||||
/* the actual reset code */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
|
||||
reset:
|
||||
mrs r0,cpsr /* set the cpu to SVC32 mode */
|
||||
bic r0,r0,#0x1f /* (superviser mode, M=10011) */
|
||||
orr r0,r0,#0x13
|
||||
msr cpsr,r0
|
||||
|
||||
bl cpu_init_crit /* we do sys-critical inits */
|
||||
|
||||
relocate: /* relocate U-Boot to RAM */
|
||||
adr r0, _start /* r0 <- current position of code */
|
||||
ldr r2, _armboot_start
|
||||
ldr r3, _armboot_end
|
||||
sub r2, r3, r2 /* r2 <- size of armboot */
|
||||
/* ldr r1, _uboot_reloc / * r1 <- destination address */
|
||||
ldr r1, _TEXT_BASE
|
||||
add r2, r0, r2 /* r2 <- source end address */
|
||||
|
||||
copy_loop:
|
||||
ldmia r0!, {r3-r10} /* copy from source address [r0] */
|
||||
stmia r1!, {r3-r10} /* copy to target address [r1] */
|
||||
cmp r0, r2 /* until source end addreee [r2] */
|
||||
ble copy_loop
|
||||
|
||||
/* Set up the stack */
|
||||
ldr r0, _uboot_reloc /* upper 128 KiB: relocated uboot */
|
||||
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
|
||||
/* FIXME: bdinfo should be here */
|
||||
sub sp, r0, #12 /* leave 3 words for abort-stack */
|
||||
|
||||
ldr pc, _start_armboot
|
||||
|
||||
_start_armboot: .word start_armboot
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* */
|
||||
/* CPU_init_critical registers */
|
||||
/* */
|
||||
/* - setup important registers */
|
||||
/* - setup memory timing */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
|
||||
/* Interrupt-Controller base address */
|
||||
IC_BASE: .word 0x40d00000
|
||||
#define ICMR 0x04
|
||||
|
||||
/* Reset-Controller */
|
||||
RST_BASE: .word 0x40f00030
|
||||
#define RCSR 0x00
|
||||
|
||||
|
||||
/* Clock Manager Registers */
|
||||
CC_BASE: .word 0x41300000
|
||||
#define CCCR 0x00
|
||||
cpuspeed: .word CFG_CPUSPEED
|
||||
|
||||
/* RS: ??? */
|
||||
.macro CPWAIT
|
||||
mrc p15,0,r0,c2,c0,0
|
||||
mov r0,r0
|
||||
sub pc,pc,#4
|
||||
.endm
|
||||
|
||||
|
||||
cpu_init_crit:
|
||||
|
||||
/* mask all IRQs */
|
||||
ldr r0, IC_BASE
|
||||
mov r1, #0x00
|
||||
str r1, [r0, #ICMR]
|
||||
|
||||
/* set clock speed */
|
||||
ldr r0, CC_BASE
|
||||
ldr r1, cpuspeed
|
||||
str r1, [r0, #CCCR]
|
||||
|
||||
/*
|
||||
* before relocating, we have to setup RAM timing
|
||||
* because memory timing is board-dependend, you will
|
||||
* find a memsetup.S in your board directory.
|
||||
*/
|
||||
mov ip, lr
|
||||
bl memsetup
|
||||
mov lr, ip
|
||||
|
||||
/* Memory interfaces are working. Disable MMU and enable I-cache. */
|
||||
|
||||
ldr r0, =0x2001 /* enable access to all coproc. */
|
||||
mcr p15, 0, r0, c15, c1, 0
|
||||
CPWAIT
|
||||
|
||||
mcr p15, 0, r0, c7, c10, 4 /* drain the write & fill buffers */
|
||||
CPWAIT
|
||||
|
||||
mcr p15, 0, r0, c7, c7, 0 /* flush Icache, Dcache and BTB */
|
||||
CPWAIT
|
||||
|
||||
mcr p15, 0, r0, c8, c7, 0 /* flush instuction and data TLBs */
|
||||
CPWAIT
|
||||
|
||||
/* Enable the Icache */
|
||||
/*
|
||||
mrc p15, 0, r0, c1, c0, 0
|
||||
orr r0, r0, #0x1800
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
CPWAIT
|
||||
*/
|
||||
mov pc, lr
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* */
|
||||
/* Interrupt handling */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
|
||||
/* IRQ stack frame */
|
||||
|
||||
#define S_FRAME_SIZE 72
|
||||
|
||||
#define S_OLD_R0 68
|
||||
#define S_PSR 64
|
||||
#define S_PC 60
|
||||
#define S_LR 56
|
||||
#define S_SP 52
|
||||
|
||||
#define S_IP 48
|
||||
#define S_FP 44
|
||||
#define S_R10 40
|
||||
#define S_R9 36
|
||||
#define S_R8 32
|
||||
#define S_R7 28
|
||||
#define S_R6 24
|
||||
#define S_R5 20
|
||||
#define S_R4 16
|
||||
#define S_R3 12
|
||||
#define S_R2 8
|
||||
#define S_R1 4
|
||||
#define S_R0 0
|
||||
|
||||
#define MODE_SVC 0x13
|
||||
|
||||
/* use bad_save_user_regs for abort/prefetch/undef/swi ... */
|
||||
|
||||
.macro bad_save_user_regs
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
stmia sp, {r0 - r12} /* Calling r0-r12 */
|
||||
add r8, sp, #S_PC
|
||||
|
||||
ldr r2, _armboot_end
|
||||
add r2, r2, #CONFIG_STACKSIZE
|
||||
sub r2, r2, #8
|
||||
ldmia r2, {r2 - r4} /* get pc, cpsr, old_r0 */
|
||||
add r0, sp, #S_FRAME_SIZE /* restore sp_SVC */
|
||||
|
||||
add r5, sp, #S_SP
|
||||
mov r1, lr
|
||||
stmia r5, {r0 - r4} /* save sp_SVC, lr_SVC, pc, cpsr, old_r */
|
||||
mov r0, sp
|
||||
.endm
|
||||
|
||||
|
||||
/* use irq_save_user_regs / irq_restore_user_regs for */
|
||||
/* IRQ/FIQ handling */
|
||||
|
||||
.macro irq_save_user_regs
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
stmia sp, {r0 - r12} /* Calling r0-r12 */
|
||||
add r8, sp, #S_PC
|
||||
stmdb r8, {sp, lr}^ /* Calling SP, LR */
|
||||
str lr, [r8, #0] /* Save calling PC */
|
||||
mrs r6, spsr
|
||||
str r6, [r8, #4] /* Save CPSR */
|
||||
str r0, [r8, #8] /* Save OLD_R0 */
|
||||
mov r0, sp
|
||||
.endm
|
||||
|
||||
.macro irq_restore_user_regs
|
||||
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
|
||||
mov r0, r0
|
||||
ldr lr, [sp, #S_PC] @ Get PC
|
||||
add sp, sp, #S_FRAME_SIZE
|
||||
subs pc, lr, #4 @ return & move spsr_svc into cpsr
|
||||
.endm
|
||||
|
||||
.macro get_bad_stack
|
||||
ldr r13, _armboot_end @ setup our mode stack
|
||||
add r13, r13, #CONFIG_STACKSIZE @ resides at top of normal stack
|
||||
sub r13, r13, #8
|
||||
|
||||
str lr, [r13] @ save caller lr / spsr
|
||||
mrs lr, spsr
|
||||
str lr, [r13, #4]
|
||||
|
||||
mov r13, #MODE_SVC @ prepare SVC-Mode
|
||||
msr spsr_c, r13
|
||||
mov lr, pc
|
||||
movs pc, lr
|
||||
.endm
|
||||
|
||||
.macro get_irq_stack @ setup IRQ stack
|
||||
ldr sp, IRQ_STACK_START
|
||||
.endm
|
||||
|
||||
.macro get_fiq_stack @ setup FIQ stack
|
||||
ldr sp, FIQ_STACK_START
|
||||
.endm
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* */
|
||||
/* exception handlers */
|
||||
/* */
|
||||
/****************************************************************************/
|
||||
|
||||
.align 5
|
||||
undefined_instruction:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_undefined_instruction
|
||||
|
||||
.align 5
|
||||
software_interrupt:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_software_interrupt
|
||||
|
||||
.align 5
|
||||
prefetch_abort:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_prefetch_abort
|
||||
|
||||
.align 5
|
||||
data_abort:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_data_abort
|
||||
|
||||
.align 5
|
||||
not_used:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_not_used
|
||||
|
||||
#ifdef CONFIG_USE_IRQ
|
||||
|
||||
.align 5
|
||||
irq:
|
||||
get_irq_stack
|
||||
irq_save_user_regs
|
||||
bl do_irq
|
||||
irq_restore_user_regs
|
||||
|
||||
.align 5
|
||||
fiq:
|
||||
get_fiq_stack
|
||||
irq_save_user_regs /* someone ought to write a more */
|
||||
bl do_fiq /* effiction fiq_save_user_regs */
|
||||
irq_restore_user_regs
|
||||
|
||||
#else
|
||||
|
||||
.align 5
|
||||
irq:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_irq
|
||||
|
||||
.align 5
|
||||
fiq:
|
||||
get_bad_stack
|
||||
bad_save_user_regs
|
||||
bl do_fiq
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FIXME How do we reset??? Watchdog timeout??
|
||||
*/
|
||||
.align 5
|
||||
.globl reset_cpu
|
||||
reset_cpu:
|
||||
/*
|
||||
ldr r0, RST_BASE
|
||||
mov r1, #0x0 @ set bit 3-0 ...
|
||||
str r1, [r0, #RCSR] @ ... to clear in RCSR
|
||||
mov r1, #0x1
|
||||
str r1, [r0, #RCSR] @ and perform reset
|
||||
*/
|
||||
b reset_cpu @ silly, but repeat endlessly
|
||||
|
||||
Reference in New Issue
Block a user