This commit is contained in:
Ronald G. Minnich 2003-04-15 18:29:12 +00:00
commit 2041c328cd
23 changed files with 2666 additions and 0 deletions

View file

@ -0,0 +1,43 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#ifndef _BSP_H
#define _BSP_H
/* This function is called very early on, and may not have a functioning
stack. It should be careful not to touch memory until it has enabled
memory accesses. */
void bsp_init_mp107(void);
/* Called early to initialize i/o for logging */
void bsp_init_io(void);
/* Called to relocate data */
void bsp_relocate(void);
/* Called before the relocation jump - data has been relocated. */
unsigned bsp_init_memory(unsigned offset);
/* This function is called immediately after relocation. Do whatever
is necessary to perform printf. */
void bsp_init_post_reloc(unsigned memory);
/* Called after the first print to the outside world */
void bsp_init_post_hello(void);
/* Called if things have failed very, very badly. */
void bsp_indicate_dead(void);
/* Prints out a BSP description */
void bsp_identify(void);
/* BSP primary clock */
unsigned bsp_clock_speed(void);
/* Memory regions - all of memory runs from memory_base to top. */
extern unsigned long memory_base;
extern unsigned long memory_top;
extern unsigned long physical_memory_size;
#endif

View file

@ -0,0 +1,21 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#ifndef _PPC_H
#define _PPC_H
#define BIG_ENDIAN
#define RODATA __attribute__ ((__section__ (".rodata")))
/* Do CPU specific setup, with optional icache */
void ppc_setup_cpu(int icache);
void ppc_enable_dcache(void);
void ppc_disable_dcache(void);
void ppc_enable_mmu(void);
/* Describe which sort of ppc CPU I am */
void ppc_identify(void);
#endif

View file

@ -0,0 +1,293 @@
/*
* (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
*/
/*
* This file contains all the macros and symbols which define
* a PowerPC assembly language environment.
*/
#ifndef __PPC_ASM_TMPL__
#define __PPC_ASM_TMPL__
/***************************************************************************
*
* These definitions simplify the ugly declarations necessary for GOT
* definitions.
*
* Stolen from prepboot/bootldr.h, (C) 1998 Gabriel Paubert, paubert@iram.es
*
* Uses r14 to access the GOT
*/
#define START_GOT \
.section ".got2","aw"; \
.LCTOC1 = .+32768
#define END_GOT \
.text
#define GET_GOT \
bl 1f ; \
.text 2 ; \
0: .long .LCTOC1-1f ; \
.text ; \
1: mflr r14 ; \
lwz r0,0b-1b(r14) ; \
add r14,r0,r14 ;
#define GOT_ENTRY(NAME) .L_ ## NAME = . - .LCTOC1 ; .long NAME
#define GOT(NAME) .L_ ## NAME (r14)
/***************************************************************************
* Register names
*/
#define r0 0
#define r1 1
#define r2 2
#define r3 3
#define r4 4
#define r5 5
#define r6 6
#define r7 7
#define r8 8
#define r9 9
#define r10 10
#define r11 11
#define r12 12
#define r13 13
#define r14 14
#define r15 15
#define r16 16
#define r17 17
#define r18 18
#define r19 19
#define r20 20
#define r21 21
#define r22 22
#define r23 23
#define r24 24
#define r25 25
#define r26 26
#define r27 27
#define r28 28
#define r29 29
#define r30 30
#define r31 31
/*
* FP register names
*/
#define fr0 0
#define fr1 1
#define fr2 2
#define fr3 3
#define fr4 4
#define fr5 5
#define fr6 6
#define fr7 7
#define fr8 8
#define fr9 9
#define fr10 10
#define fr11 11
#define fr12 12
#define fr13 13
#define fr14 14
#define fr15 15
#define fr16 16
#define fr17 17
#define fr18 18
#define fr19 19
#define fr20 20
#define fr21 21
#define fr22 22
#define fr23 23
#define fr24 24
#define fr25 25
#define fr26 26
#define fr27 27
#define fr28 28
#define fr29 29
#define fr30 30
#define fr31 31
/* Some special registers */
#define TBRU 269 /* Time base Upper/Lower (Reading) */
#define TBRL 268
#define TBWU 284 /* Time base Upper/Lower (Writing) */
#define TBWL 285
#define XER 1
#define LR 8
#define CTR 9
#define HID0 1008 /* Hardware Implementation */
#define PVR 287 /* Processor Version */
#define SDR1 25 /* MMU hash base register */
#define DAR 19 /* Data Address Register */
#define SPR0 272 /* Supervisor Private Registers */
#define SPRG0 272
#define SPR1 273
#define SPRG1 273
#define SPR2 274
#define SPRG2 274
#define SPR3 275
#define SPRG3 275
#define DSISR 18
#define SRR0 26 /* Saved Registers (exception) */
#define SRR1 27
#define DEC 22 /* Decrementer */
#define EAR 282 /* External Address Register */
#define ICR 148 /* Interrupt Cause Register (37-44) */
#define DER 149
#define COUNTA 150 /* Breakpoint Counter (37-44) */
#define COUNTB 151 /* Breakpoint Counter (37-44) */
#define LCTRL1 156 /* Load/Store Support (37-40) */
#define LCTRL2 157 /* Load/Store Support (37-41) */
#define ICTRL 158
/* Registers in the processor's internal memory map that we use.
*/
#define IMMR 0xff000000
#define SYPCR 0x00000004
#define BR0 0x00000100
#define OR0 0x00000104
#define BR1 0x00000108
#define OR1 0x0000010c
#define BR2 0x00000110
#define OR2 0x00000114
#define BR3 0x00000118
#define OR3 0x0000011c
#define BR4 0x00000120
#define OR4 0x00000124
#define MAR 0x00000164
#define MCR 0x00000168
#define MAMR 0x00000170
#define MBMR 0x00000174
#define MSTAT 0x00000178
#define MPTPR 0x0000017a
#define MDR 0x0000017c
#define TBSCR 0x00000200
#define TBREFF0 0x00000204
#define PLPRCR 0x00000284
#define curptr r2
#define SYNC \
sync; \
isync
/*
* Macros for storing registers into and loading registers from
* exception frames.
*/
#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
/*
* GCC sometimes accesses words at negative offsets from the stack
* pointer, although the SysV ABI says it shouldn't. To cope with
* this, we leave this much untouched space on the stack on exception
* entry.
*/
#define STACK_UNDERHEAD 64
#if 0 /* we don't use virtual addresses in PPCBOOT */
#define tophys(rd,rs,rt) addis rd,rs,-KERNELBASE@h
#define tovirt(rd,rs,rt) addis rd,rs,KERNELBASE@h
#else
#define tophys(rd,rs,rt) mr rd,rs
#define tovirt(rd,rs,rt) mr rd,rs
#endif
/*
* Exception entry code. This code runs with address translation
* turned off, i.e. using physical addresses.
* We assume sprg3 has the physical address of the current
* task's thread_struct.
*/
#define EXCEPTION_PROLOG \
mtspr SPRG0,r20; \
mtspr SPRG1,r21; \
mfcr r20; \
tophys(r21,r1,r21); /* use tophys(kernel sp) otherwise */ \
subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
1: stw r20,_CCR(r21); /* save registers */ \
stw r22,GPR22(r21); \
stw r23,GPR23(r21); \
mfspr r20,SPRG0; \
stw r20,GPR20(r21); \
mfspr r22,SPRG1; \
stw r22,GPR21(r21); \
mflr r20; \
stw r20,_LINK(r21); \
mfctr r22; \
stw r22,_CTR(r21); \
mfspr r20,XER; \
stw r20,_XER(r21); \
mfspr r22,SRR0; \
mfspr r23,SRR1; \
stw r0,GPR0(r21); \
stw r1,GPR1(r21); \
stw r2,GPR2(r21); \
stw r1,0(r21); \
tovirt(r1,r21,r1); /* set new kernel sp */ \
SAVE_4GPRS(3, r21);
/*
* Note: code which follows this uses cr0.eq (set if from kernel),
* r21, r22 (SRR0), and r23 (SRR1).
*/
/*
* Exception vectors.
*
* The data words for `hdlr' and `int_return' are initialized with
* OFFSET values only; they must be relocated first before they can
* be used!
*/
#define STD_EXCEPTION(n, label, hdlr) \
. = n; \
label: \
EXCEPTION_PROLOG; \
lwz r3,GOT(transfer_to_handler); \
mtlr r3; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
li r20,MSR_KERNEL; \
blrl ; \
.L_ ## label : \
.long hdlr - _start + EXC_OFF_SYS_RESET; \
.long int_return - _start + EXC_OFF_SYS_RESET
#endif /* __PPC_ASM_TMPL__ */

View file

@ -0,0 +1,128 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
/* In the MSR, not all bits are interesting to us
13 - POW - Power management
14 - TGPR - temporary registers for page table routines
15 - ILE - Exception little endian
16 - EE - External interrupts
17 - PR - Privilege level
18 - FP - Floating Point available
19 - ME - Machine check exception enable
20 - FE0 - Floating exception mode 0
21 - SE - Single step trace mode
22 - BE - Branch trace enable
23 - FE1 - Floating exception mode 1
25 - IP - Exception prefix
26 - IR - Instruction address translation
27 - DR - Data address translation
30 - RI - Recoverable exception
31 - LE - Little endian mode
MSR_MASK is the bits we do not change.
*/
#define MSR_MASK 0xfff8008c
#define MSR_POW 0x00040000
#define MSR_TGPR 0x00020000
#define MSR_ILE 0x00010000
#define MSR_EE 0x00008000
#define MSR_PR 0x00004000
#define MSR_FP 0x00002000
#define MSR_ME 0x00001000
#define MSR_FE0 0x00000800
#define MSR_SE 0x00000400
#define MSR_BE 0x00000200
#define MSR_FE1 0x00000100
#define MSR_IP 0x00000040
#define MSR_IR 0x00000020
#define MSR_DR 0x00000010
#define MSR_RI 0x00000002
#define MSR_LE 0x00000001
#define MSR_DEFAULT (MSR_FP | MSR_IR | MSR_DR)
/* We are interested in the following hid0 bits:
6 - ECLK - Enable external test clock (603 only)
11 - DPM - Turn on dynamic power management (603 only)
15 - NHR - Not hard reset
16 - ICE - Instruction cache enable
17 - DCE - Data cache enable
18 - ILOCK - Instruction cache lock
19 - DLOCK - Data cache lock
20 - ICFI - Instruction cache invalidate
21 - DCFI - Data cache invalidate
24 - NOSER - Serial execution disable (604 only - turbo mode)
24 - SGE - Store gathering enable (7410 only)
29 - BHT - Branch history table (604 only)
I made up the tags for the 604 specific bits, as they aren't
named in the 604 book. The 603 book calls the invalidate bits
ICFI and DCI, and I have no idea why it isn't DCFI. Maybe IBM named
one, and Motorola named the other. */
#define HID0_ECLK 0x02000000
#define HID0_DPM 0x00100000
#define HID0_NHR 0x00010000
#define HID0_ICE 0x00008000
#define HID0_DCE 0x00004000
#define HID0_ILOCK 0x00002000
#define HID0_DLOCK 0x00001000
#define HID0_ICFI 0x00000800
#define HID0_DCFI 0x00000400
#define HID0_NOSER 0x00000080
#define HID0_SGE 0x00000080
#define HID0_BTIC 0x00000020
#define HID0_BHT 0x00000004
/*
* BAT defines
*/
/*
* BL field in upper BAT register
*/
#define BAT_BL_128K 0x00000000
#define BAT_BL_256K 0x00000004
#define BAT_BL_512K 0x0000000C
#define BAT_BL_1M 0x0000001C
#define BAT_BL_2M 0x0000003C
#define BAT_BL_4M 0x0000007C
#define BAT_BL_8M 0x000000FC
#define BAT_BL_16M 0x000001FC
#define BAT_BL_32M 0x000003FC
#define BAT_BL_64M 0x000007FC
#define BAT_BL_128M 0x00000FFC
#define BAT_BL_256M 0x00001FFC
/*
* Supervisor/user valid mode in upper BAT register
*/
#define BAT_VALID_SUPERVISOR 0x00000002
#define BAT_VALID_USER 0x00000001
#define BAT_INVALID 0x00000000
/*
* WIMG bit setting in lower BAT register
*/
#define BAT_WRITE_THROUGH 0x00000040
#define BAT_CACHE_INHIBITED 0x00000020
#define BAT_COHERENT 0x00000010
#define BAT_GUARDED 0x00000008
/*
* Protection bits in lower BAT register
*/
#define BAT_NO_ACCESS 0x00000000
#define BAT_READ_ONLY 0x00000001
#define BAT_READ_WRITE 0x00000002
#ifndef ASM
unsigned __getmsr(void);
void __setmsr(unsigned value);
unsigned __gethid0(void);
unsigned __gethid1(void);
void __sethid0(unsigned value);
unsigned __getpvr(void);
#endif

View file

@ -0,0 +1,12 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#ifndef _TIMER_H
#define __TIMER_H
unsigned get_hz(void);
unsigned ticks_since_boot(void);
void sleep_ticks(unsigned);
#endif

109
src/arch/ppc/lib/c_start.S Normal file
View file

@ -0,0 +1,109 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
/*
* The assumption is that we're located in ROM and we have a fake stack
* located in cache. Our task is to turn on memory proper, the finish
* configuring the machine.
*/
#define ASM
#include "ppcreg.h"
#include <ppc_asm.tmpl>
.section ".text"
.globl _start
_start:
/*
* init stack pointer to real ram now that memory is on
*/
lis r1, _estack@ha
addi r1, r1, _estack@l
stwu r0,-64(r1)
stwu r1,-24(r1)
/*
* Clear stack
*/
lis r4, _stack@ha
addi r4, r4, _stack@l
lis r7, _estack@ha
addi r7, r7, _estack@l
lis r5, 0
1: stwx r5, 0, r4
addi r4, r4, 4
cmp 0, 0, r4, r7
ble 1b
sync
/*
* Clear bss
*/
lis r4, _bss@ha
addi r4, r4, _bss@l
lis r7, _ebss@ha
addi r7, r7, _ebss@l
lis r5, 0
1: stwx r5, 0, r4
addi r4, r4, 4
cmp 0, 0, r4, r7
ble 1b
sync
/*
* Set up the EABI pointers, before we enter any C code
*/
lis r13, _SDA_BASE_@ha
addi r13, r13, _SDA_BASE_@l
lis r2, _SDA2_BASE_@ha
addi r2, r2, _SDA2_BASE_@l
/*
* load start address into SRR0 for rfi
*/
lis r3, hardwaremain@ha
addi r3, r3, hardwaremain@l
mtspr SRR0, r3
/*
* load the current MSR into SRR1 so that it will be copied
* back into MSR on rfi
*/
mfmsr r4
mtspr SRR1, r4 // load SRR1 with r4
/*
* If something returns after rfi then die
*/
lis r3, dead@ha
addi r3, r3, dead@l
mtlr r3
/*
* Complete rest of initialization in C (hardwaremain)
*/
rfi
/*
* Stop here if something goes wrong
*/
dead:
b dead
/*NOTREACHED*/
/* Remove need for ecrti.o and ectrn.o */
.globl __init
__init:
.globl __fini
__fini:
.globl __CTOR_LIST__
__CTOR_LIST__:
.globl __CTOR_END__
__CTOR_END__:
.globl __DTOR_LIST__
__DTOR_LIST__:
.globl __DTOR_END__
__DTOR_END__:
blr

45
src/arch/ppc/lib/floats.S Normal file
View file

@ -0,0 +1,45 @@
/* $Id$ */
/* Copyright 1999-2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include <ppc_asm.tmpl>
.globl _init_float_registers
_init_float_registers:
lfd fr0, 0(r3)
lfd fr1, 0(r3)
lfd fr2, 0(r3)
lfd fr3, 0(r3)
lfd fr4, 0(r3)
lfd fr5, 0(r3)
lfd fr6, 0(r3)
lfd fr7, 0(r3)
lfd fr8, 0(r3)
lfd fr9, 0(r3)
lfd fr10, 0(r3)
lfd fr11, 0(r3)
lfd fr12, 0(r3)
lfd fr13, 0(r3)
lfd fr14, 0(r3)
lfd fr15, 0(r3)
lfd fr16, 0(r3)
lfd fr17, 0(r3)
lfd fr18, 0(r3)
lfd fr19, 0(r3)
lfd fr20, 0(r3)
lfd fr21, 0(r3)
lfd fr22, 0(r3)
lfd fr23, 0(r3)
lfd fr24, 0(r3)
lfd fr25, 0(r3)
lfd fr26, 0(r3)
lfd fr27, 0(r3)
lfd fr28, 0(r3)
lfd fr29, 0(r3)
lfd fr30, 0(r3)
lfd fr31, 0(r3)
blr
.end

View file

@ -0,0 +1,43 @@
/* $Id$ */
/* Copyright 1999-2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
/* .text*/
.globl _init_float_registers
_init_float_registers:
lfd 0, 0(3)
lfd 1, 0(3)
lfd 2, 0(3)
lfd 3, 0(3)
lfd 4, 0(3)
lfd 5, 0(3)
lfd 6, 0(3)
lfd 7, 0(3)
lfd 8, 0(3)
lfd 9, 0(3)
lfd 10, 0(3)
lfd 11, 0(3)
lfd 12, 0(3)
lfd 13, 0(3)
lfd 14, 0(3)
lfd 15, 0(3)
lfd 16, 0(3)
lfd 17, 0(3)
lfd 18, 0(3)
lfd 19, 0(3)
lfd 20, 0(3)
lfd 21, 0(3)
lfd 22, 0(3)
lfd 23, 0(3)
lfd 24, 0(3)
lfd 25, 0(3)
lfd 26, 0(3)
lfd 27, 0(3)
lfd 28, 0(3)
lfd 29, 0(3)
lfd 30, 0(3)
lfd 31, 0(3)
blr
.end

58
src/arch/ppc/lib/id.c Normal file
View file

@ -0,0 +1,58 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include "ppc.h"
#include "ppcreg.h"
#include <printk.h>
void ppc_identify(void)
{
unsigned type = __getpvr() >> 16;
unsigned version = __getpvr() & 0xffff;
const char *cpu_string = 0;
switch(type) {
case 1:
cpu_string = "601";
break;
case 3:
cpu_string = "603";
break;
case 4:
cpu_string = "604";
break;
case 6:
cpu_string = "603e";
break;
case 7:
cpu_string = "603ev";
break;
case 8:
cpu_string = "750";
break;
case 9:
cpu_string = "604e";
break;
case 10:
cpu_string = "604ev5 (MachV)";
break;
case 12:
cpu_string = "7400";
break;
case 50:
cpu_string = "821";
break;
case 80:
cpu_string = "860";
break;
case 0x800c:
cpu_string = "7410";
break;
}
if (cpu_string)
printk_info("PowerPC %s", cpu_string);
else
printk_info("PowerPC unknown (0x%x)", type);
printk_info(" CPU, version %d.%d\n", version >> 8, version & 0xff);
}

130
src/arch/ppc/lib/setup.c Normal file
View file

@ -0,0 +1,130 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include "ppc.h"
#include "ppcreg.h"
unsigned __getmsr(void)
{
unsigned result;
__asm__ volatile ("mfmsr %0" : "=r" (result));
return result;
}
unsigned __gethid0(void)
{
unsigned result;
__asm__ volatile ("mfspr %0,1008" : "=r" (result));
return result;
}
unsigned __gethid1(void)
{
unsigned result;
__asm__ volatile ("mfspr %0,1009" : "=r" (result));
return result;
}
void __sethid0(unsigned value)
{
__asm__ volatile ("mtspr 1008,%0" : : "r" (value));
}
unsigned __getpvr(void)
{
int result;
__asm__("mfspr %0, 287" : "=r" (result));
return result;
}
void __setmsr(unsigned value)
{
__asm__ volatile ("mtmsr %0; sync" :: "r" (value));
}
void __set1015(unsigned value)
{
__asm__ volatile ("mtspr 1015,%0" : : "r" (value));
}
extern void _init_float_registers(const double *);
/*RODATA static const double dummy_float = 1.0;*/
static const double dummy_float = 1.0;
#define HID0_DCACHE HID0_DCE
#define MSR_DATA MSR_DR
void ppc_setup_cpu(int icache)
{
int type = __getpvr() >> 16;
int version = __getpvr() & 0xffff;
if (type == 0xc)
{
if (version == 0x0200)
__set1015(0x19000004);
else if (((version & 0xff00) == 0x0200) &&
(version != 0x0209))
__set1015(0x01000000);
}
if (icache)
{
__sethid0(HID0_NHR | HID0_BHT | HID0_ICE | HID0_ICFI | HID0_BTIC
| HID0_DCACHE);
__sethid0(HID0_DPM | HID0_NHR | HID0_BHT | HID0_ICE | HID0_BTIC
| HID0_DCACHE);
}
else
{
__sethid0(HID0_DPM | HID0_NHR | HID0_BHT | HID0_BTIC | HID0_DCACHE);
}
#if 1
/* if (type == 8 || type == 12) */
{
__setmsr(MSR_FP | MSR_DATA);
_init_float_registers(&dummy_float);
}
#endif
}
void ppc_enable_dcache(void)
{
/*
* Already enabled in crt0.S
*/
#if 0
unsigned hid0 = __gethid0();
__sethid0(hid0 | HID0_DCFI | HID0_DCE);
__sethid0(hid0 | HID0_DCE);
#endif
}
void ppc_disable_dcache(void)
{
unsigned hid0 = __gethid0();
__sethid0(hid0 & ~HID0_DCE);
}
void ppc_enable_mmu(void)
{
unsigned msr = __getmsr();
__setmsr(msr | MSR_DR | MSR_IR);
}
void make_coherent(void *base, unsigned length)
{
unsigned hid0 = __gethid0();
if (hid0 & HID0_DCE)
{
unsigned i;
unsigned offset = 0x1f & (unsigned) base;
unsigned adjusted_base = (unsigned) base & ~0x1f;
for(i = 0; i < length + offset; i+= 32)
__asm__ volatile ("dcbf %1,%0" : : "r" (adjusted_base), "r" (i));
if (hid0 & HID0_ICE)
for(i = 0; i < length + offset; i+= 32)
__asm__ volatile ("icbi %1,%0" : : "r" (adjusted_base), "r" (i));
}
}

View file

@ -0,0 +1,13 @@
/* $Id$ */
/* Copyright 1999-2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
.text
.globl _timebase
_timebase:
mftbu 3
mftb 4
mftbu 5
cmpw 3, 5
bne _timebase
blr

31
src/arch/ppc/lib/timer.c Normal file
View file

@ -0,0 +1,31 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include <timer.h>
#include <bsp.h>
unsigned get_hz(void)
{
return bsp_clock_speed() >> 16;
}
unsigned ticks_since_boot(void)
{
extern unsigned long long _timebase(void);
return (unsigned) (_timebase() >> 16);
}
void sleep_ticks(unsigned ticks)
{
unsigned then = ticks + ticks_since_boot();
while(ticks_since_boot() < then)
;
}
void udelay(int usecs)
{
unsigned ticksperusec = get_hz() / 1000000;
sleep_ticks(ticksperusec * usecs);
}

View file

@ -0,0 +1,14 @@
#
# Objects linked with linuxbios
#
object i2c.o
object mpc107_pci.o
object meminfo.o
object mpc107.o
object mpc107_utils.S
#
# Included in crt0.S
#
mainboardinit northbridge/motorola/mpc107/mpc107_init.inc
mainboardinit northbridge/motorola/mpc107/mpc107_utils.inc

View file

@ -0,0 +1,99 @@
/* $Id$
* (C) Copyright 2002
* Humboldt Solutions Ltd, <adrian@humboldt.co.uk>
*
* 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 <types.h>
#include <stdlib.h>
#include <string.h>
#include "i2c.h"
static i2c_bus *first_i2c = NULL;
#if 0
int register_i2c_bus(const i2c_fn *fn, char *tag, void *data)
{
i2c_bus *bus = malloc (sizeof (i2c_bus));
if (bus)
{
bus->fn = fn;
bus->tag = tag;
bus->data = data;
bus->next = first_i2c;
first_i2c = bus;
return 0;
}
return -1;
}
#endif
i2c_bus *find_i2c_bus(const char *name)
{
int len;
if (! name)
return first_i2c;
if (first_i2c)
{
i2c_bus *i2c;
len = strlen(name);
for (i2c = first_i2c; i2c; i2c = i2c->next)
if (strlen(i2c->tag) == len && memcmp (name, i2c->tag, len) == 0)
return i2c;
}
return NULL;
}
void i2c_start(struct i2c_bus *bus)
{
if (! bus)
bus = first_i2c;
bus->fn->start(bus);
}
void i2c_stop(struct i2c_bus *bus)
{
if (! bus)
bus = first_i2c;
bus->fn->stop(bus);
}
int i2c_master_write(struct i2c_bus *bus, int target, int address,
const u8 *data, int length)
{
if (! bus)
bus = first_i2c;
return bus->fn->master_write(bus, target, address, data, length);
}
int i2c_master_read(struct i2c_bus *bus, int target, int address,
u8 *data, int length)
{
if (! bus)
bus = first_i2c;
return bus->fn->master_read(bus, target, address, data, length);
}

View file

@ -0,0 +1,57 @@
/* $Id$
* (C) Copyright 2002
* Humboldt Solutions Ltd, <adrian@humboldt.co.uk>
*
* 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
*/
#ifndef _I2C_H
#define _I2C_H
struct i2c_bus;
typedef struct i2c_fn
{
void (* start)(struct i2c_bus *bus);
void (* stop)(struct i2c_bus *bus);
int (* master_write)(struct i2c_bus *bus, int target, int address,
const u8 *data, int length);
int (* master_read)(struct i2c_bus *bus, int target, int address,
u8 *data, int length);
} i2c_fn;
typedef struct i2c_bus
{
const i2c_fn *fn;
char *tag;
void *data;
struct i2c_bus *next;
} i2c_bus;
i2c_bus *find_i2c_bus(const char *name);
int register_i2c_bus(const i2c_fn *fn, char *tag, void *data);
void i2c_start(struct i2c_bus *bus);
void i2c_stop(struct i2c_bus *bus);
int i2c_master_write(struct i2c_bus *bus, int target, int address,
const u8 *data, int length);
int i2c_master_read(struct i2c_bus *bus, int target, int address,
u8 *data, int length);
void init_i2c_nvram(const char *i2c_tag);
extern i2c_fn mpc107_i2c_fn;
#endif

View file

@ -0,0 +1,202 @@
/*
* (C) Copyright 2001
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
*
* 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 <printk.h>
#include "mpc107.h"
void
sdram_dimm_to_bank_info(const char *data, sdram_dimm_info *dimm, int verbose)
{
sdram_bank_info *bank1 = dimm->bank1;
sdram_bank_info *bank2 = dimm->bank2;
unsigned char csum = 0;
unsigned char x;
int i;
int no_cas_latencies = 0;
char latency[3];
/* Mark banks initially broken */
bank1->size = 0;
bank2->size = 0;
if (data[0] < 64)
{
if (verbose)
printk_info("SPD data too short\n");
return;
}
for(i = 0; i < 63; i++)
csum += data[i];
if (csum != data[63])
{
if (verbose)
printk_info("Broken checksum\n");
return;
}
if (data[2] != 0x04)
{
if (verbose)
printk_info("SDRAM Only\n");
return;
}
bank1->row_bits = data[3] & 0x0f;
if (data[3] >> 4)
bank2->row_bits = data[3] >> 4;
else
bank2->row_bits = bank1->row_bits;
bank1->internal_banks = bank2->internal_banks = data[17];
bank1->col_bits = data[4] & 0x0f;
if (data[4] >> 4)
bank2->col_bits = data[4] >> 4;
else
bank2->col_bits = bank1->col_bits;
if (data[7] || (data[6] != 80 && data[6] != 72 && data[6] != 64))
{
if (verbose)
printk_info("Data width incorrect\n");
return;
}
if (data[8] != 0x01)
{
if (verbose)
printk_info("3.3V TTL DIMMS only\n");
return;
}
/* Extract CAS latencies in reverse order, as we only get info on
the highest ones. */
x = data[18];
for(i = 7; i > 0; i--)
{
if (x & 0x40)
{
if (no_cas_latencies < 3)
latency[no_cas_latencies] = i;
no_cas_latencies++;
}
x <<= 1;
}
/* Now fill in other timings - we're most interested in the lowest
CAS latency, so we shuffle data to put that first. */
for(i = no_cas_latencies; i >= 0; i--)
bank1->cas_latency[no_cas_latencies - i - 1] =
bank2->cas_latency[no_cas_latencies - i - 1] =
latency[i];
for(i = no_cas_latencies; i < 3; i++)
bank1->cas_latency[i] = bank2->cas_latency[i] = 0;
/* Store values for the highest cas latency */
bank1->cycle_time[no_cas_latencies - 1] =
bank2->cycle_time[no_cas_latencies- 1] =
100 * (data[9] >> 4) + 10 * (data[9] & 0xf);
bank1->access_time[no_cas_latencies - 1] =
bank2->access_time[no_cas_latencies - 1] =
100 * (data[10] >> 4) + 10 * (data[10] & 0xf);
/* Then the second highest */
if (no_cas_latencies > 1)
{
bank1->cycle_time[no_cas_latencies - 2] =
bank2->cycle_time[no_cas_latencies- 2] =
100 * (data[23] >> 4) + 10 * (data[23] & 0xf);
bank1->access_time[no_cas_latencies - 2] =
bank2->access_time[no_cas_latencies - 2] =
100 * (data[24] >> 4) + 10 * (data[24] & 0xf);
}
/* Then the third highest */
if (no_cas_latencies > 2)
{
bank1->cycle_time[no_cas_latencies - 3] =
bank2->cycle_time[no_cas_latencies- 3] =
100 * (data[25] >> 2) + 25 * (data[25] & 0x3);
bank1->access_time[no_cas_latencies - 3] =
bank2->access_time[no_cas_latencies - 3] =
100 * (data[26] >> 2) + 25 * (data[26] & 0x3);
}
if (verbose)
for(i = 0; i < no_cas_latencies; i++)
printk_info("CL %d: cycle %dns access %dns\n",
bank1->cas_latency[i], bank1->cycle_time[i] / 100,
bank1->access_time[i] / 100);
/* Other timings */
bank1->min_back_to_back = bank2->min_back_to_back = data[15];
bank1->min_row_precharge = bank2->min_row_precharge = data[27];
bank1->min_active_to_active = bank2->min_active_to_active = data[28];
bank1->min_ras_to_cas = bank2->min_ras_to_cas = data[29];
bank1->min_ras = bank2->min_ras = data[30];
/* Error detection type */
bank1->error_detect = bank2->error_detect = data[11];
/* Crucial row sizes - these mark the data as valid */
for(i = 7; i >= 0; i--)
{
if (data[31] & (1 << i))
{
bank1->size = (4*1024*1024) << i;
break;
}
}
if (data[5] > 1)
{
for(i-- ; i >= 0; i--)
{
if (data[31] & (1 << i))
{
bank2->size = (4*1024*1024) << i;
break;
}
}
if (! bank2->size)
bank2->size = bank1->size;
}
dimm->size = bank1->size + bank2->size;
}
void
print_sdram_bank_info(const sdram_bank_info *bank)
{
printk_info("Bank %d: %dMB\n", bank->number, bank->size / (1024*1024));
}
static const char *error_types[] = {"", "Parity ", "ECC "};
void
print_sdram_dimm_info(const sdram_dimm_info *dimm)
{
printk_info("Dimm %d: ", dimm->number);
if (dimm->size)
printk_info("%dMB CL%d (%s): Running at CL%d %s\n",
dimm->size / (1024*1024), dimm->bank1->cas_latency[0],
dimm->part_number,
dimm->bank1->actual_cas,
error_types[dimm->bank1->actual_detect]);
else
printk_info("(none)\n");
}

View file

@ -0,0 +1,509 @@
/*
* (C) Copyright 2001
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
*
* 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 <bsp.h>
#include <ppc.h>
#include <pci.h>
#include <mem.h>
#include <types.h>
#include <string.h>
#include <printk.h>
#include <arch/io.h>
#include "i2c.h"
#include "mpc107.h"
#include <timer.h>
#define NUM_DIMMS 1
#define NUM_BANKS 2
extern struct pci_ops pci_direct_ppc;
struct mem_range *
getmeminfo(void)
{
int i;
sdram_dimm_info dimm[NUM_DIMMS];
sdram_bank_info bank[NUM_BANKS];
static struct mem_range meminfo;
hostbridge_probe_dimms(NUM_DIMMS, dimm, bank);
meminfo.basek = 0;
meminfo.sizek = 0;
for (i = 0; i < NUM_BANKS; i++) {
meminfo.sizek += bank[i].size;
}
meminfo.sizek >>= 10;
return &meminfo;
}
/*
* Memory is already turned on, but with pessimistic settings. Now
* we optimize settings to the actual memory configuration.
*/
unsigned
mpc107_config_memory(void)
{
sdram_dimm_info sdram_dimms[NUM_DIMMS];
sdram_bank_info sdram_banks[NUM_BANKS];
hostbridge_probe_dimms(NUM_DIMMS, sdram_dimms, sdram_banks);
return hostbridge_config_memory(NUM_BANKS, sdram_banks, 2);
}
/*
* Configure memory settings.
*/
unsigned long
hostbridge_config_memory(int no_banks, sdram_bank_info * bank, int for_real)
{
int i, j;
char ignore[8];
/* Convert bus clock to cycle time in 100ns units */
unsigned cycle_time = 10 * (2500000000U / bsp_clock_speed());
/* Approximate */
unsigned access_time = cycle_time - 300;
unsigned cas_latency = 0;
unsigned rdlat;
unsigned refint;
unsigned refrec;
unsigned acttorw, acttopre;
unsigned pretoact, bstopre;
enum sdram_error_detect error_detect;
u32 mccr1;
u32 mccr2;
u32 mccr3;
u32 mccr4;
u8 bank_enable;
u32 memstart1, memstart2;
u32 extmemstart1, extmemstart2;
u32 memend1, memend2;
u32 extmemend1, extmemend2;
u32 address;
/* Set up the ignore mask */
for(i = 0; i < no_banks; i++)
ignore[i] = (bank[i].size == 0);
/* Pick best CAS latency possible */
for (i = 0; i < no_banks; i++)
{
if (! ignore[i])
{
for (j = 0; j < 3; j++)
{
if (cycle_time >= bank[i].cycle_time[j] &&
access_time >= bank[i].access_time[j])
{
cas_latency = bank[i].cas_latency[j];
break;
}
}
}
}
if (!cas_latency)
return 0;
/* For various parameters there is a risk of clashing between banks */
error_detect = (for_real > 1) ? ERRORS_ECC : ERRORS_NONE;
for (i = 0; i < no_banks; i++)
{
if (! ignore[i])
{
{
for (j = 0; j < 3; j++)
if (bank[i].cas_latency[j] == cas_latency)
break;
if (j == 3)
{
ignore[i] = 1;
if (! for_real)
printk_info("Disabling memory bank %d (cas latency)\n", i);
}
if (bank[i].error_detect < error_detect)
error_detect = bank[i].error_detect;
}
}
}
/* Read in configuration of port X */
pci_direct_ppc.read_dword(0, 0, 0xf0, &mccr1);
pci_direct_ppc.read_dword(0, 0, 0xf4, &mccr2);
pci_direct_ppc.read_dword(0, 0, 0xfc, &mccr4);
mccr1 &= 0xfff00000;
mccr2 &= 0xffe00000;
mccr3 = 0;
mccr4 &= 0x00230000;
pretoact = 0;
acttorw = 0;
acttopre = 0;
for (i = 0; i < no_banks; i++)
if (! ignore[i])
{
int rowcode = -1;
if (for_real)
{
bank[i].actual_detect = error_detect;
bank[i].actual_cas = cas_latency;
}
switch (bank[i].row_bits) {
case 13:
if (bank[i].internal_banks == 4)
rowcode = 2;
else if (bank[i].internal_banks == 2)
rowcode = 1;
break;
case 12:
if (bank[i].internal_banks == 4)
rowcode = 0;
else if (bank[i].internal_banks == 2)
rowcode = 1;
break;
case 11:
if (bank[i].internal_banks == 4)
rowcode = 0;
else if (bank[i].internal_banks == 2)
rowcode = 3;
break;
}
if (rowcode == -1) {
ignore[i] = 1;
if (! for_real)
printk_info("Memory bank %d disabled: row bits %d and banks %d not supported\n", i, bank[i].row_bits, bank[i].internal_banks);
} else
mccr1 |= rowcode << (2 * i);
/* Update worst case settings */
if (! ignore[i]) {
if (bank[i].min_row_precharge > pretoact)
pretoact = bank[i].min_row_precharge;
if (bank[i].min_ras_to_cas > acttorw)
acttorw = bank[i].min_ras_to_cas;
if (bank[i].min_ras > acttopre)
acttopre = bank[i].min_ras;
}
}
/* Now convert to clock cycles, rounding up */
pretoact = (100 * pretoact + cycle_time - 1) / cycle_time;
acttopre = (100 * acttopre + cycle_time - 1) / cycle_time;
acttorw = (100 * acttorw + cycle_time - 1) / cycle_time;
refrec = acttopre;
bstopre = 0x240; /* Set conservative values, because we can't derive */
refint = 1000;
if (error_detect == ERRORS_ECC)
{
rdlat = cas_latency + 2;
mccr4 |= 0x00400000;
mccr2 |= 0x000c0001;
}
else
{
rdlat = cas_latency + 1;
mccr4 |= 0x00100000;
}
if (pretoact > 16 || acttopre > 16 || acttorw > 16)
if (! for_real)
printk_info("Timings out of range\n");
mccr4 |= ((pretoact & 0x0f) << 28) | ((acttopre & 0xf) << 24) |
((acttorw & 0x0f) << 4) |
((bstopre & 0x003) << 18) | ((bstopre & 0x3c0) >> 6) |
(cas_latency << 12) | 0x00000200 /* burst length */ ;
mccr3 |= ((bstopre & 0x03c) << 26) |
((refrec & 0x0f) << 24) | (rdlat << 20);
mccr2 |= refint << 2;
mccr1 |= 0x00080000; /* memgo */
address = 0;
memstart1 = memstart2 = 0;
extmemstart1 = extmemstart2 = 0;
memend1 = memend2 = 0;
extmemend1 = extmemend2 = 0;
bank_enable = 0;
for (i = 0; i < no_banks; i++) {
if (! ignore[i]) {
u32 end = address + bank[i].size - 1;
bank_enable |= 1 << i;
if (i < 4) {
memstart1 |= ((address >> 20) & 0xff) << (8 * i);
extmemstart1 |= ((address >> 28) & 0x03) << (8 * i);
memend1 |= ((end >> 20) & 0xff) << (8 * i);
extmemend1 |= ((end >> 28) & 0x03) << (8 * i);
} else {
int k = i - 4;
memstart2 |= ((address >> 20) & 0xff) << (8 * k);
extmemstart2 |= ((address >> 28) & 0x03) << (8 * k);
memend2 |= ((end >> 20) & 0xff) << (8 * k);
extmemend2 |= ((end >> 28) & 0x03) << (8 * k);
}
address += bank[i].size;
}
}
if (for_real)
{
pci_direct_ppc.write_byte(0, 0, 0xa0, bank_enable);
pci_direct_ppc.write_dword(0, 0, 0x80, memstart1);
pci_direct_ppc.write_dword(0, 0, 0x84, memstart2);
pci_direct_ppc.write_dword(0, 0, 0x88, extmemstart1);
pci_direct_ppc.write_dword(0, 0, 0x8c, extmemstart2);
pci_direct_ppc.write_dword(0, 0, 0x90, memend1);
pci_direct_ppc.write_dword(0, 0, 0x94, memend2);
pci_direct_ppc.write_dword(0, 0, 0x98, extmemend1);
pci_direct_ppc.write_dword(0, 0, 0x9c, extmemend2);
pci_direct_ppc.write_dword(0, 0, 0xfc, mccr4);
pci_direct_ppc.write_dword(0, 0, 0xf8, mccr3);
pci_direct_ppc.write_dword(0, 0, 0xf4, mccr2);
pci_direct_ppc.write_dword(0, 0, 0xf0, mccr1);
}
return address;
}
#define MPC107_I2CADDR 0x00
#define MPC107_I2CFDR 0x04
#define MPC107_I2CCR 0x08
#define MPC107_I2CSR 0x0c
#define MPC107_I2CDR 0x10
#define MPC107_CCR_MEN 0x80
#define MPC107_CCR_MSTA 0x20
#define MPC107_CCR_MTX 0x10
#define MPC107_CCR_TXAK 0x08
#define MPC107_CCR_RSTA 0x04
#define MPC107_CSR_MCF 0x80
#define MPC107_CSR_MAAS 0x40
#define MPC107_CSR_MBB 0x20
#define MPC107_CSR_MAL 0x10
#define MPC107_CSR_SRW 0x04
#define MPC107_CSR_MIF 0x02
#define MPC107_CSR_RXAK 0x01
#define i2c_base 0xfc003000
static int
i2c_wait(unsigned timeout, int writing)
{
u32 x;
while (((x = readl(i2c_base + MPC107_I2CSR)) & (MPC107_CSR_MCF | MPC107_CSR_MIF))
!= (MPC107_CSR_MCF | MPC107_CSR_MIF)) {
if (ticks_since_boot() > timeout)
return -1;
}
if (x & MPC107_CSR_MAL) {
return -1;
}
if (writing && (x & MPC107_CSR_RXAK)) {
printk_info("No RXAK\n");
/* generate stop */
writel(MPC107_CCR_MEN, i2c_base + MPC107_I2CCR);
return -1;
}
writel(0, i2c_base + MPC107_I2CSR);
return 0;
}
static void
mpc107_i2c_start(struct i2c_bus *bus)
{
/* Set clock */
writel(0x1031, i2c_base + MPC107_I2CFDR);
/* Clear arbitration */
writel(0, i2c_base + MPC107_I2CSR);
}
static void
mpc107_i2c_stop(struct i2c_bus *bus)
{
/* After last DIMM shut down I2C */
writel(0x0, i2c_base + MPC107_I2CCR);
}
static int
mpc107_i2c_byte_write(struct i2c_bus *bus, int target, int address, u8 data)
{
unsigned timeout = ticks_since_boot() + 3 * get_hz();
/* Must wait here for clocks to start */
sleep_ticks(get_hz() / 40);
/* Start with MEN */
writel(MPC107_CCR_MEN, i2c_base + MPC107_I2CCR);
/* Start as master */
writel(MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX, i2c_base + MPC107_I2CCR);
/* Write target byte */
writel(target, i2c_base + MPC107_I2CDR);
if (i2c_wait(timeout, 1) < 0)
return -1;
/* Write data address byte */
writel(address, i2c_base + MPC107_I2CDR);
if (i2c_wait(timeout, 1) < 0)
return -1;
/* Write data byte */
writel(data, i2c_base + MPC107_I2CDR);
if (i2c_wait(timeout, 1) < 0)
return -1;
/* generate stop */
writel(MPC107_CCR_MEN, i2c_base + MPC107_I2CCR);
return 0;
}
static int
mpc107_i2c_master_write(struct i2c_bus *bus, int target, int address, const u8 *data, int length)
{
unsigned count;
for(count = 0; count < length; count++)
{
if (mpc107_i2c_byte_write(bus, target, address, data[count]) < 0)
return -1;
}
return count;
}
#define DIMM_LENGTH 0xfff
static int
mpc107_i2c_master_read(struct i2c_bus *bus, int target, int address,
u8 *data, int length)
{
unsigned timeout = ticks_since_boot() + 3 * get_hz();
unsigned count;
/* Must wait here for clocks to start */
sleep_ticks(get_hz() / 40);
/* Start with MEN */
writel(MPC107_CCR_MEN, i2c_base + MPC107_I2CCR);
/* Start as master */
writel(MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX, i2c_base + MPC107_I2CCR);
/* Write target byte */
writel(target, i2c_base + MPC107_I2CDR);
if (i2c_wait(timeout, 1) < 0)
return -1;
/* Write data address byte */
writel(address, i2c_base + MPC107_I2CDR);
if (i2c_wait(timeout, 1) < 0)
return -1;
/* Switch to read - restart */
writel(MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_MTX | MPC107_CCR_RSTA, i2c_base + MPC107_I2CCR);
/* Write target address byte - this time with the read flag set */
writel(target | 1, i2c_base + MPC107_I2CDR);
if (i2c_wait(timeout, 0) < 0)
return -1;
if (length == 1)
writel(MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_TXAK, i2c_base + MPC107_I2CCR);
else
writel(MPC107_CCR_MEN | MPC107_CCR_MSTA, i2c_base + MPC107_I2CCR);
/* Dummy read */
readl(i2c_base + MPC107_I2CDR);
count = 0;
while (count < length) {
if (i2c_wait(timeout, 0) < 0)
return -1;
/* Generate txack on next to last byte */
if (count == length - 2)
writel(MPC107_CCR_MEN | MPC107_CCR_MSTA | MPC107_CCR_TXAK, i2c_base + MPC107_I2CCR);
/* Generate stop on last byte */
if (count == length - 1)
writel(MPC107_CCR_MEN | MPC107_CCR_TXAK, i2c_base + MPC107_I2CCR);
data[count] = readl(i2c_base + MPC107_I2CDR);
if (count == 0 && length == DIMM_LENGTH) {
if (data[0] == 0xff) {
printk_debug("I2C device not present\n");
length = 3;
} else {
length = data[0];
if (length < 3)
length = 3;
}
}
count++;
}
/* Finish with disable master */
writel(MPC107_CCR_MEN, i2c_base + MPC107_I2CCR);
return length;
}
i2c_fn mpc107_i2c_fn = {
mpc107_i2c_start, mpc107_i2c_stop,
mpc107_i2c_master_write, mpc107_i2c_master_read
};
/*
* Find dimm information.
*/
void
hostbridge_probe_dimms(int no_dimms, sdram_dimm_info *dimms, sdram_bank_info * bank)
{
unsigned char data[256];
unsigned dimm;
printk_debug("i2c testing\n");
mpc107_i2c_start(NULL);
for(dimm = 0; dimm < no_dimms; dimm++)
{
dimms[dimm].number = dimm;
dimms[dimm].bank1 = bank + dimm*2;
dimms[dimm].bank2 = bank + dimm*2 + 1;
bank[dimm*2].size = 0;
bank[dimm*2+1].size = 0;
bank[dimm*2].number = 0;
bank[dimm*2+1].number = 1;
}
for (dimm = 0; dimm < no_dimms; dimm ++) {
unsigned limit = mpc107_i2c_master_read(NULL, 0xa0 + 2*dimm, 0,
data, DIMM_LENGTH);
if (limit > 3) {
sdram_dimm_to_bank_info(data, dimms + dimm, 0);
memcpy(dimms[dimm].part_number, data + 73, 18);
dimms[dimm].part_number[18] = 0;
printk_debug("Part Number: %s\n", dimms[dimm].part_number);
}
}
mpc107_i2c_stop(NULL);
}

View file

@ -0,0 +1,79 @@
/*
* (C) Copyright 2001
* Humboldt Solutions Ltd, adrian@humboldt.co.uk.
*
* 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
*/
#ifndef _MPC107_H
#define _MPC107_H
#ifdef ASM
#define BMC_BASE 0x8000 /* Bridge memory controller base address */
#else
enum sdram_error_detect {
ERRORS_NONE, ERRORS_PARITY, ERRORS_ECC
};
typedef struct sdram_dimm_info
{
unsigned size;
unsigned number;
char part_number[20];
struct sdram_bank_info *bank1;
struct sdram_bank_info *bank2;
} sdram_dimm_info;
typedef struct sdram_bank_info
{
unsigned number;
unsigned char row_bits;
unsigned char internal_banks;
unsigned char col_bits;
unsigned char data_width;
/* Cycle and access times are stored with lowest CAS latency first. Units
are 0.01ns */
unsigned short cycle_time[3];
unsigned short access_time[3];
/* Best CAS latencies */
unsigned char cas_latency[3];
unsigned char cs_latency;
unsigned char we_latency;
unsigned char min_back_to_back;
unsigned char min_row_precharge;
unsigned char min_active_to_active;
unsigned char min_ras_to_cas;
unsigned char min_ras;
unsigned char burst_mask;
enum sdram_error_detect error_detect;
/* Bank size */
unsigned size;
unsigned long start;
unsigned long end;
enum sdram_error_detect actual_detect;
unsigned char actual_cas;
} sdram_bank_info;
void sdram_dimm_to_bank_info(const char *dimm_data, sdram_dimm_info *dimm, int verbose);
void print_sdram_dimm_info(const sdram_dimm_info *dimm);
void print_sdram_bank_info(const sdram_bank_info *bank);
unsigned long hostbridge_config_memory(int no_banks, sdram_bank_info *bank, int for_real);
void hostbridge_probe_dimms(int no_dimms, sdram_dimm_info *dimm, sdram_bank_info * bank);
unsigned mpc107_config_memory(void);
#endif
#endif

View file

@ -0,0 +1,85 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include <ppc_asm.tmpl>
.globl bsp_init_northbridge
bsp_init_northbridge:
mflr r11
lis r10, 0x8000
/* PCI Cmd */
li r4, 6
ori r3, r10, 4
bl __pci_config_write_16
/* PCI Stat */
ori r3, r10, 6
bl __pci_config_read_16
ori r4, r4, 0xffff
ori r3, r10, 6
bl __pci_config_write_16
/* CLK Drive */
ori r4, r10, 0xfc01 /* Top bit will be ignored */
ori r3, r10, 0x74
bl __pci_config_write_16
/* EUMBBAR */
lis r4, 0xfc00
ori r3, r10, 0x78
bl __pci_config_write_32
/* Page CTR */
li r4, 0x32
ori r3, r10, 0xa3
lis r7, 1
mtctr r7
bl __pci_config_write_8
/* PICR1 */
lis r4, 0xff04
ori r4, r4, 0x1a18
ori r3, r10, 0xa8
bl __pci_config_write_32
/* PICR2 */
lis r4, 0x0404
ori r4, r4, 0x0004
ori r3, r10, 0xac
bl __pci_config_write_32
/* Preserve memgo bit */
/* MCCR1 */
ori r3, r10, 0xf0
bl __pci_config_read_32
lis r7, 0x0008
and r4, r7, r3
oris r4, r4, 0x75e0
ori r3, r10, 0xf0
bl __pci_config_write_32
/* MCCR4 */
ori r3, r10, 0xfc
bl __pci_config_read_32
lis r7, 0x0050
and r4, r7, r3
oris r4, r4, 0x3522
ori r3, r10, 0xfc
bl __pci_config_write_32
/* MCCR2 */
ori r3, r10, 0xf4
bl __pci_config_read_32
lis r7, 0x000f
ori r7, r7, 0x0001
and r4, r3, r7
oris r4, r4, 0x0440
ori r3, r10, 0xf4
bl __pci_config_write_32
mtlr r11
blr

View file

@ -0,0 +1,311 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
.globl bsp_init_northbridge
#define ASM
#include "mpc107.h"
bsp_init_northbridge:
mflr r11
lis r10, BMC_BASE
/*
* PCI Cmd
*/
li r4, 0x0006
ori r3, r10, 0x04
bl __pci_config_write_16
/*
* PCI Stat
*/
ori r3, r10, 0x06
bl __pci_config_read_16
ori r4, r4, 0xffff
ori r3, r10, 0x06
bl __pci_config_write_16
/*
* PICR1
*/
ori r3, r10, 0xa8
bl __pci_config_read_32
/*
* Preserve RCS0/Addr Map bits
*/
lis r0, 0x0011
and r4, r4, r0
lis r0, 0xff00
// oris r0, r0, 0x0040 /* burst read wait states = 1 */
oris r0, r0, 0x0004 /* processor type = 603/750 */
// ori r0, r0, 0x2000 /* enable LocalBusSlave */
ori r0, r0, 0x1000 /* enable Flash write */
ori r0, r0, 0x0800 /* enable MCP* assertion */
// ori r0, r0, 0x0400 /* enable TEA* assertion */
ori r0, r0, 0x0200 /* enable data bus parking */
// ori r0, r0, 0x0040 /* enable PCI store gathering */
ori r0, r0, 0x0010 /* enable loop-snoop */
ori r0, r0, 0x0008 /* enable address bus parking */
// ori r0, r0, 0x0004 /* enable speculative PCI reads */
or r4, r4, r0
ori r3, r10, 0xa8
bl __pci_config_write_32
/*
* PICR2
*/
lis r4, 0x0000
// oris r4, r4, 0x2000 /* no Serialize Config cycles */
// oris r4, r4, 0x0800 /* No PCI Snoop cycles */
oris r4, r4, 0x0400 /* FF0 is Local ROM */
// oris r4, r4, 0x0200 /* Flash write lockout */
// oris r4, r4, 0x0000 /* snoop wt states = 0 */
oris r4, r4, 0x0004 /* snoop wt states = 1 */
// oris r4, r4, 0x0008 /* snoop wt states = 2 */
// oris r4, r4, 0x000c /* snoop wt states = 3 */
// ori r4, r4, 0x0000 /* addr phase wt states = 0 */
ori r4, r4, 0x0004 /* addr phase wt states = 1 */
// ori r4, r4, 0x0008 /* addr phase wt states = 2 */
// ori r4, r4, 0x000c /* addr phase wt states = 3 */
ori r3, r10, 0xac
bl __pci_config_write_32
/*
* EUMBBAR
*/
lis r4, 0xfc00
ori r3, r10, 0x78
bl __pci_config_write_32
/*
* MCCR1 - Set MEMGO bit later!
*/
ori r3, r10, 0xf0
bl __pci_config_read_32
lis r7, 0x0008 /* Preserve MEMGO bit in case we're in RAM */
and r4, r7, r3
// lis r4, 0x0000 /* Rom speed @100MHz (10ns) */
oris r4, r4, 0x7580 /* Safe local ROM = 10+3 clocks */
// oris r4, r4, 0x7380 /* Fast local ROM = 7+3 clocks */
// oris r4, r4, 0x0010 /* Burst ROM/Flash enable */
// oris r4, r4, 0x0004 /* Self-refresh enable */
// oris r4, r4, 0x0002 /* EDO/FP enable (else SDRAM) */
// oris r4, r4, 0x0001 /* Parity check */
// ori r4, r4, 0xFFFF /* 16Mbit/2 bank SDRAM */
// ori r4, r4, 0x5555 /* 64Mbit/2 bank SDRAM */
ori r4, r4, 0x0000 /* 64Mbit/4 bank SDRAM */
ori r3, r10, 0xf0
bl __pci_config_write_32
/*
* MCCR2
*/
lis r4, 0x0000
// oris r4, r4, 0x4000 /* TS_WAIT_TIMER = 3 clocks */
oris r4, r4, 0x0400 /* ASRISE = 2 clocks */
oris r4, r4, 0x0040 /* ASFALL = 2 clocks */
// oris r4, r4, 0x0010 /* SDRAM parity (else ECC) */
// oris r4, r4, 0x0008 /* SDRAM inline writes */
// oris r4, r4, 0x0004 /* SDRAM inline reads */
// oris r4, r4, 0x0002 /* ECC enable */
// oris r4, r4, 0x0001 /* EDO (else FP) */
// ori r4, r4, 0x06b8 /* Refresh 33MHz bus */
// ori r4, r4, 0x035c /* Refresh 66MHz bus */
ori r4, r4, 0x023c /* Refresh 100MHz bus */
// ori r4, r4, 0x01ac /* Refresh 133MHz bus */
// ori r4, r4, 0x0002 /* Reserve a page */
// ori r4, r4, 0x0001 /* RWM parity */
ori r3, r10, 0xf4
bl __pci_config_write_32
/*
* MCCR3
*/
lis r4, 0x7000 /* BSTOPRE_M = 7 */
oris r4, r4, 0x0800 /* REFREC = 8 clocks */
oris r4, r4, 0x0040 /* RDLAT = 4 clocks */
// oris r4, r4, 0x0030 /* RDLAT = 3 clocks */
ori r3, r10, 0xf8
bl __pci_config_write_32
/*
* MCCR4
*/
lis r4, 0x3000 /* PRETOACT = 3 clocks */
oris r4, r4, 0x0500 /* ACTOPRE = 5 clocks */
// oris r4, r4, 0x0080 /* Enable 8-beat burst (32-bit bus) */
// oris r4, r4, 0x0040 /* Enable Inline ECC/Parity */
oris r4, r4, 0x0020 /* Enable Extended ROM (RCS2/RCS3) */
oris r4, r4, 0x0010 /* Registered buffers */
oris r4, r4, 0x0000 /* BSTOPRE_U = 0 */
oris r4, r4, 0x0002 /* Change RCS1 to 8-bit mode */
// ori r4, r4, 0x8000 /* Registered DIMMs */
ori r4, r4, 0x3000 /* CAS Latencey (CL=3) */
// ori r4, r4, 0x2000 /* CAS Latencey (CL=2) */
ori r4, r4, 0x0200 /* Sequential wrap/4-beat burst */
ori r4, r4, 0x0030 /* Reserve a page */
ori r4, r4, 0x0009 /* RWM parity */
ori r3, r10, 0xfc
bl __pci_config_write_32
/*
* MSAR1/MSAR2/MESAR1/MESAR2
*/
lis r4, 0x6040
ori r4, r4, 0x2000
ori r3, r10, 0x80
bl __pci_config_write_32
lis r4, 0xe0c0
ori r4, r4, 0xa080
ori r3, r10, 0x84
bl __pci_config_write_32
lis r4, 0x0000
ori r4, r4, 0x0000
ori r3, r10, 0x88
bl __pci_config_write_32
lis r4, 0x0000
ori r4, r4, 0x0000
ori r3, r10, 0x8c
bl __pci_config_write_32
/*
* MEAR1/MEAR2/MEEAR1/MEEAR2
*/
lis r4, 0x7f5f
ori r4, r4, 0x3f1f
ori r3, r10, 0x90
bl __pci_config_write_32
lis r4, 0xffdf
ori r4, r4, 0xbf9f
ori r3, r10, 0x94
bl __pci_config_write_32
lis r4, 0x0000
ori r4, r4, 0x0000
ori r3, r10, 0x98
bl __pci_config_write_32
lis r4, 0x0000
ori r4, r4, 0x0000
ori r3, r10, 0x9c
bl __pci_config_write_32
/*
* ODCR
*/
li r4, 0
ori r4, r4, 0x80 /* PCI I/O 50 ohms */
ori r4, r4, 0x40 /* CPU I/O 50 ohms */
// ori r4, r4, 0x30 /* Mem I/O 8 ohms */
// ori r4, r4, 0x20 /* Mem I/O 13 ohms */
// ori r4, r4, 0x10 /* Mem I/O 20 ohms */
ori r4, r4, 0x00 /* Mem I/O 40 ohms */
// ori r4, r4, 0x0c /* PCIClk 8 ohms */
// ori r4, r4, 0x08 /* PCIClk 13 ohms */
// ori r4, r4, 0x04 /* PCIClk 20 ohms */
ori r4, r4, 0x00 /* PCIClk 40 ohms */
// ori r4, r4, 0x03 /* MemClk 8 ohms */
// ori r4, r4, 0x02 /* MemClk 13.3 ohms */
// ori r4, r4, 0x01 /* MemClk 20 ohms */
ori r4, r4, 0x00 /* MemClk 40 ohms */
ori r3, r10, 0x73
bl __pci_config_write_8
/* CDCR */
li r4, 0x7fff
addi r4, r4, 1 /* PCI_SYNC_OUT disabled */
ori r4, r4, 0x7c00 /* PCI_CLK disabled */
// ori r4, r4, 0x0300 /* CPU_CLK 8 ohms */
// ori r4, r4, 0x0200 /* CPU_CLK 13 ohms */
// ori r4, r4, 0x0100 /* CPU_CLK 20 ohms */
// ori r4, r4, 0x0000 /* CPU_CLK 40 ohms */
// ori r4, r4, 0x0080 /* SDRAM_SYNC_OUT disabled */
// ori r4, r4, 0x0078 /* SDRAM_CLK disabled */
// ori r4, r4, 0x0004 /* CPU_CLK0 disabled */
// ori r4, r4, 0x0002 /* CPU_CLK1 disabled */
ori r4, r4, 0x0001 /* CPU_CLK2 disabled */
ori r3, r10, 0x74
bl __pci_config_write_16
/*
* MDCR
*/
li r4, 0x00
// ori r4, r4, 0x80 /* MCP 1=open-drain, 0=output */
ori r4, r4, 0x40 /* SRESET 1=open-drain, 0=output */
ori r4, r4, 0x20 /* QACK 1=high-Z, 0=output */
ori r3, r10, 0x76
bl __pci_config_write_8
/*
* MBEN
*/
li r4, 0x03 /* Enable banks 0 and 1 */
ori r3, r10, 0xa0
bl __pci_config_write_8
/*
* PGMAX
*/
li r4, 0x32 /* 33MHz value w/ROMFAL=8 */
ori r3, r10, 0xa3
bl __pci_config_write_8
/*
* Wait 200us
*/
lis r7, 0x0001
mtctr r7
wait1:
bdnz wait1
/*
* Now set memgo bit in MCCR1
*/
ori r3, r10, 0xf0
bl __pci_config_read_32
lis r7, 0x0008 /* MEMGO=1 */
or r4, r7, r3
ori r3, r10, 0xf0
bl __pci_config_write_32
/*
* Wait again
*/
lis r7, 0x002
ori r7, r7, 0xffff
mtctr r7
wait2:
bdnz wait2
mtlr r11
blr

View file

@ -0,0 +1,62 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include <pci.h>
#include <bsp.h>
unsigned __pci_config_read_32(unsigned address);
unsigned __pci_config_read_16(unsigned address);
unsigned __pci_config_read_8(unsigned address);
void __pci_config_write_32(unsigned address, unsigned data);
void __pci_config_write_16(unsigned address, unsigned short data);
void __pci_config_write_8(unsigned address, unsigned char data);
#define CONFIG_CMD(bus,devfn,where) (bus << 16 | devfn << 8 | where | 0x80000000)
static int pci_ppc_read_config_dword(unsigned char bus, int devfn, int where, u32 *data)
{
*data = __pci_config_read_32(CONFIG_CMD(bus, devfn, where));
return 0;
}
static int pci_ppc_read_config_word(unsigned char bus, int devfn, int where, u16 *data)
{
*data = __pci_config_read_16(CONFIG_CMD(bus, devfn, where));
return 0;
}
static int pci_ppc_read_config_byte(unsigned char bus, int devfn, int where, u8 *data)
{
*data = __pci_config_read_8(CONFIG_CMD(bus, devfn, where));
return 0;
}
static int pci_ppc_write_config_dword(unsigned char bus, int devfn, int where, u32 data)
{
__pci_config_write_32(CONFIG_CMD(bus, devfn, where), data);
return 0;
}
static int pci_ppc_write_config_word(unsigned char bus, int devfn, int where, u16 data)
{
__pci_config_write_16(CONFIG_CMD(bus, devfn, where), data);
return 0;
}
static int pci_ppc_write_config_byte(unsigned char bus, int devfn, int where, u8 data)
{
__pci_config_write_8(CONFIG_CMD(bus, devfn, where), data);
return 0;
}
struct pci_ops pci_direct_ppc =
{
pci_ppc_read_config_byte,
pci_ppc_read_config_word,
pci_ppc_read_config_dword,
pci_ppc_write_config_byte,
pci_ppc_write_config_word,
pci_ppc_write_config_dword
};

View file

@ -0,0 +1,162 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
#include <ppc_asm.tmpl>
.globl __pci_config_read_32
__pci_config_read_32:
lis r4, 0xfec0
stwbrx r3, 0, r4
sync
lis r4, 0xfee0
lwbrx r3, 0, r4
blr
.globl __pci_config_read_16
__pci_config_read_16:
lis r4, 0xfec0
andi. r5, r3, 2
stwbrx r3, 0, r4
sync
oris r4, r5, 0xfee0
lhbrx r3, 0, r4
blr
.globl __pci_config_read_8
__pci_config_read_8:
lis r4, 0xfec0
andi. r5, r3, 3
stwbrx r3, 0, r4
sync
oris r4, r5, 0xfee0
lbz r3, 0(r4)
blr
.globl __pci_config_write_32
__pci_config_write_32:
lis r5, 0xfec0
stwbrx r3, r0, r5
sync
lis r5, 0xfee0
stwbrx r4, r0, r5
sync
blr
.globl __pci_config_write_16
__pci_config_write_16:
lis r5, 0xfec0
andi. r6, r3, 2
stwbrx r3, r0, 5
sync
oris r5, r6, 0xfee0
sthbrx r4, r0, r5
sync
blr
.globl __pci_config_write_8
__pci_config_write_8:
lis r5, 0xfec0
andi. r6, r3, 3
stwbrx r3, r0, r5
sync
oris r5, r6, 0xfee0
stb r4, 0(r5)
sync
blr
.globl in_8
in_8:
oris r3, r3, 0xfe00
lbz r3,0(r3)
blr
.globl in_16
in_16:
oris r3, r3, 0xfe00
lhbrx r3, 0, r3
blr
.globl in_16_ne
in_16_ne:
oris r3, r3, 0xfe00
lhzx r3, 0, r3
blr
.globl in_32
in_32:
oris r3, r3, 0xfe00
lwbrx r3, 0, r3
blr
.globl out_8
out_8:
oris r3, r3, 0xfe00
stb r4, 0(r3)
eieio
blr
.globl out_16
out_16:
oris r3, r3, 0xfe00
sthbrx r4, 0, r3
eieio
blr
.globl out_16_ne
out_16_ne:
oris r3, r3, 0xfe00
sth r4, 0(r3)
eieio
blr
.globl out_32
out_32:
oris r3, r3, 0xfe00
stwbrx r4, 0, r3
eieio
blr
.globl read_8
read_8:
lbz r3,0(r3)
blr
.globl read_16
read_16:
lhbrx r3, 0, r3
blr
.globl read_32
read_32:
lwbrx r3, 0, r3
blr
.globl read_32_ne
read_32_ne:
lwz r3, 0(r3)
blr
.globl write_8
write_8:
stb r4, 0(r3)
eieio
blr
.globl write_16
write_16:
sthbrx r4, 0, r3
eieio
blr
.globl write_32
write_32:
stwbrx r4, 0, r3
eieio
blr
.globl write_32_ne
write_32_ne:
stw r4, 0(r3)
eieio
blr

View file

@ -0,0 +1,160 @@
/* $Id$ */
/* Copyright 2000 AG Electronics Ltd. */
/* This code is distributed without warranty under the GPL v2 (see COPYING) */
.globl __pci_config_read_32
__pci_config_read_32:
lis r4, 0xfec0
stwbrx r3, r0, r4
sync
lis r4, 0xfee0
lwbrx r3, 0, r4
blr
.globl __pci_config_read_16
__pci_config_read_16:
lis r4, 0xfec0
andi. r5, r3, 2
stwbrx r3, r0, r4
sync
oris r4, r5, 0xfee0
lhbrx r3, r0, r4
blr
.globl __pci_config_read_8
__pci_config_read_8:
lis r4, 0xfec0
andi. r5, r3, 3
stwbrx r3, r0, r4
sync
oris r4, r5, 0xfee0
lbz r3, 0(r4)
blr
.globl __pci_config_write_32
__pci_config_write_32:
lis r5, 0xfec0
stwbrx r3, r0, r5
sync
lis r5, 0xfee0
stwbrx r4, r0, r5
sync
blr
.globl __pci_config_write_16
__pci_config_write_16:
lis r5, 0xfec0
andi. r6, r3, 2
stwbrx r3, r0, 5
sync
oris r5, r6, 0xfee0
sthbrx r4, r0, r5
sync
blr
.globl __pci_config_write_8
__pci_config_write_8:
lis r5, 0xfec0
andi. r6, r3, 3
stwbrx r3, r0, r5
sync
oris r5, r6, 0xfee0
stb r4, 0(r5)
sync
blr
.globl in_8
in_8:
oris r3, r3, 0xfe00
lbz r3,0(r3)
blr
.globl in_16
in_16:
oris r3, r3, 0xfe00
lhbrx r3, 0, r3
blr
.globl in_16_ne
in_16_ne:
oris r3, r3, 0xfe00
lhzx r3, 0, r3
blr
.globl in_32
in_32:
oris r3, r3, 0xfe00
lwbrx r3, 0, r3
blr
.globl out_8
out_8:
oris r3, r3, 0xfe00
stb r4, 0(r3)
eieio
blr
.globl out_16
out_16:
oris r3, r3, 0xfe00
sthbrx r4, 0, r3
eieio
blr
.globl out_16_ne
out_16_ne:
oris r3, r3, 0xfe00
sth r4, 0(r3)
eieio
blr
.globl out_32
out_32:
oris r3, r3, 0xfe00
stwbrx r4, 0, r3
eieio
blr
.globl read_8
read_8:
lbz r3,0(r3)
blr
.globl read_16
read_16:
lhbrx r3, 0, r3
blr
.globl read_32
read_32:
lwbrx r3, 0, r3
blr
.globl read_32_ne
read_32_ne:
lwz r3, 0(r3)
blr
.globl write_8
write_8:
stb r4, 0(r3)
eieio
blr
.globl write_16
write_16:
sthbrx r4, 0, r3
eieio
blr
.globl write_32
write_32:
stwbrx r4, 0, r3
eieio
blr
.globl write_32_ne
write_32_ne:
stw r4, 0(r3)
eieio
blr