diff --git a/src/arch/ppc/include/bsp.h b/src/arch/ppc/include/bsp.h new file mode 100644 index 0000000000..f14cbf16dd --- /dev/null +++ b/src/arch/ppc/include/bsp.h @@ -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 diff --git a/src/arch/ppc/include/ppc.h b/src/arch/ppc/include/ppc.h new file mode 100644 index 0000000000..fe4aa1654b --- /dev/null +++ b/src/arch/ppc/include/ppc.h @@ -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 diff --git a/src/arch/ppc/include/ppc_asm.tmpl b/src/arch/ppc/include/ppc_asm.tmpl new file mode 100644 index 0000000000..da1f7f7782 --- /dev/null +++ b/src/arch/ppc/include/ppc_asm.tmpl @@ -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__ */ diff --git a/src/arch/ppc/include/ppcreg.h b/src/arch/ppc/include/ppcreg.h new file mode 100644 index 0000000000..5ec0dd9417 --- /dev/null +++ b/src/arch/ppc/include/ppcreg.h @@ -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 + diff --git a/src/arch/ppc/include/timer.h b/src/arch/ppc/include/timer.h new file mode 100644 index 0000000000..85bf1b81f4 --- /dev/null +++ b/src/arch/ppc/include/timer.h @@ -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 diff --git a/src/arch/ppc/lib/c_start.S b/src/arch/ppc/lib/c_start.S new file mode 100644 index 0000000000..1719fd7103 --- /dev/null +++ b/src/arch/ppc/lib/c_start.S @@ -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 + +.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 diff --git a/src/arch/ppc/lib/floats.S b/src/arch/ppc/lib/floats.S new file mode 100644 index 0000000000..57b38cb9c3 --- /dev/null +++ b/src/arch/ppc/lib/floats.S @@ -0,0 +1,45 @@ +/* $Id$ */ +/* Copyright 1999-2000 AG Electronics Ltd. */ +/* This code is distributed without warranty under the GPL v2 (see COPYING) */ + +#include + + .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 + diff --git a/src/arch/ppc/lib/floats.inc b/src/arch/ppc/lib/floats.inc new file mode 100644 index 0000000000..5c366af63f --- /dev/null +++ b/src/arch/ppc/lib/floats.inc @@ -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 + diff --git a/src/arch/ppc/lib/id.c b/src/arch/ppc/lib/id.c new file mode 100644 index 0000000000..58ca6a6256 --- /dev/null +++ b/src/arch/ppc/lib/id.c @@ -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 + +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); +} + diff --git a/src/arch/ppc/lib/setup.c b/src/arch/ppc/lib/setup.c new file mode 100644 index 0000000000..000a4b15a9 --- /dev/null +++ b/src/arch/ppc/lib/setup.c @@ -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)); + } +} diff --git a/src/arch/ppc/lib/timebase.S b/src/arch/ppc/lib/timebase.S new file mode 100644 index 0000000000..48171db498 --- /dev/null +++ b/src/arch/ppc/lib/timebase.S @@ -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 diff --git a/src/arch/ppc/lib/timer.c b/src/arch/ppc/lib/timer.c new file mode 100644 index 0000000000..316e78224e --- /dev/null +++ b/src/arch/ppc/lib/timer.c @@ -0,0 +1,31 @@ +/* $Id$ */ +/* Copyright 2000 AG Electronics Ltd. */ +/* This code is distributed without warranty under the GPL v2 (see COPYING) */ + +#include +#include + +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); +} diff --git a/src/northbridge/motorola/mpc107/Config b/src/northbridge/motorola/mpc107/Config new file mode 100644 index 0000000000..112a147110 --- /dev/null +++ b/src/northbridge/motorola/mpc107/Config @@ -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 diff --git a/src/northbridge/motorola/mpc107/i2c.c b/src/northbridge/motorola/mpc107/i2c.c new file mode 100644 index 0000000000..4ead02331b --- /dev/null +++ b/src/northbridge/motorola/mpc107/i2c.c @@ -0,0 +1,99 @@ +/* $Id$ + * (C) Copyright 2002 + * Humboldt Solutions Ltd, + * + * 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 +#include +#include +#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); +} + diff --git a/src/northbridge/motorola/mpc107/i2c.h b/src/northbridge/motorola/mpc107/i2c.h new file mode 100644 index 0000000000..868c94a082 --- /dev/null +++ b/src/northbridge/motorola/mpc107/i2c.h @@ -0,0 +1,57 @@ +/* $Id$ + * (C) Copyright 2002 + * Humboldt Solutions Ltd, + * + * 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 diff --git a/src/northbridge/motorola/mpc107/meminfo.c b/src/northbridge/motorola/mpc107/meminfo.c new file mode 100644 index 0000000000..7245fc419d --- /dev/null +++ b/src/northbridge/motorola/mpc107/meminfo.c @@ -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 +#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"); +} diff --git a/src/northbridge/motorola/mpc107/mpc107.c b/src/northbridge/motorola/mpc107/mpc107.c new file mode 100644 index 0000000000..51d6397a4d --- /dev/null +++ b/src/northbridge/motorola/mpc107/mpc107.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include "i2c.h" +#include "mpc107.h" +#include + +#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); +} diff --git a/src/northbridge/motorola/mpc107/mpc107.h b/src/northbridge/motorola/mpc107/mpc107.h new file mode 100644 index 0000000000..d9da776857 --- /dev/null +++ b/src/northbridge/motorola/mpc107/mpc107.h @@ -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 diff --git a/src/northbridge/motorola/mpc107/mpc107_init.S b/src/northbridge/motorola/mpc107/mpc107_init.S new file mode 100644 index 0000000000..d327807e94 --- /dev/null +++ b/src/northbridge/motorola/mpc107/mpc107_init.S @@ -0,0 +1,85 @@ +/* $Id$ */ +/* Copyright 2000 AG Electronics Ltd. */ +/* This code is distributed without warranty under the GPL v2 (see COPYING) */ + +#include + + +.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 + diff --git a/src/northbridge/motorola/mpc107/mpc107_init.inc b/src/northbridge/motorola/mpc107/mpc107_init.inc new file mode 100644 index 0000000000..086dea1249 --- /dev/null +++ b/src/northbridge/motorola/mpc107/mpc107_init.inc @@ -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 + diff --git a/src/northbridge/motorola/mpc107/mpc107_pci.c b/src/northbridge/motorola/mpc107/mpc107_pci.c new file mode 100644 index 0000000000..fc5873ddcf --- /dev/null +++ b/src/northbridge/motorola/mpc107/mpc107_pci.c @@ -0,0 +1,62 @@ +/* $Id$ */ +/* Copyright 2000 AG Electronics Ltd. */ +/* This code is distributed without warranty under the GPL v2 (see COPYING) */ + +#include +#include + +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 +}; + diff --git a/src/northbridge/motorola/mpc107/mpc107_utils.S b/src/northbridge/motorola/mpc107/mpc107_utils.S new file mode 100644 index 0000000000..a1c1dbea4b --- /dev/null +++ b/src/northbridge/motorola/mpc107/mpc107_utils.S @@ -0,0 +1,162 @@ +/* $Id$ */ +/* Copyright 2000 AG Electronics Ltd. */ +/* This code is distributed without warranty under the GPL v2 (see COPYING) */ + +#include + + .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 diff --git a/src/northbridge/motorola/mpc107/mpc107_utils.inc b/src/northbridge/motorola/mpc107/mpc107_utils.inc new file mode 100644 index 0000000000..5914125a44 --- /dev/null +++ b/src/northbridge/motorola/mpc107/mpc107_utils.inc @@ -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