]> git.hungrycats.org Git - linux/commitdiff
Support for POWER4 & GPUL (G5) CPUs
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 18 Sep 2003 00:17:27 +0000 (02:17 +0200)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 18 Sep 2003 00:17:27 +0000 (02:17 +0200)
arch/ppc/Kconfig
arch/ppc/Makefile
arch/ppc/kernel/Makefile
arch/ppc/kernel/cputable.c
arch/ppc/kernel/head.S
arch/ppc/kernel/idle_power4.S [new file with mode: 0644]
arch/ppc/kernel/setup.c
arch/ppc/kernel/traps.c
arch/ppc/platforms/pmac_sleep.S
arch/ppc/syslib/prom_init.c

index 24717a89723048ead4a85f36c4a30ee0a121eed8..1a883bba7de2aa2a510a564e5b433f6cadf525c3 100644 (file)
@@ -45,12 +45,13 @@ config 6xx
          There are four types of PowerPC chips supported.  The more common
          types (601, 603, 604, 740, 750, 7400), the Motorola embedded
          versions (821, 823, 850, 855, 860, 8260), the IBM embedded versions
-         (403 and 405) and the high end 64 bit Power processors (POWER 3)
+         (403 and 405) and the high end 64 bit Power processors (POWER 3,
+         POWER4, and IBM 970 also known as G5)
          Unless you are building a kernel for one of the embedded processor
-         systems, or a 64 bit IBM RS/6000, choose 6xx.  Note that the kernel
-         runs in 32-bit mode even on 64-bit chips.  Also note that because
-         the 82xx family has a 603e core, specific support for that chipset
-         is asked later on.
+         systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx.
+         Note that the kernel runs in 32-bit mode even on 64-bit chips.
+         Also note that because the 82xx family has a 603e core, specific
+         support for that chipset is asked later on.
 
 config 40x
        bool "40x"
@@ -61,6 +62,9 @@ config 44x
 config POWER3
        bool "POWER3"
 
+config POWER4
+       bool "POWER4 and 970 (G5)"
+
 config 8xx
        bool "8xx"
 
@@ -73,7 +77,8 @@ config PTE_64BIT
 
 config ALTIVEC
        bool "AltiVec Support"
-       depends on 6xx && !8260
+       depends on 6xx || POWER4
+       depends on !8260
        ---help---
          This option enables kernel support for the Altivec extensions to the
          PowerPC processor. The kernel currently supports saving and restoring
@@ -200,7 +205,7 @@ config CPU_FREQ_PMAC
 
 config PPC601_SYNC_FIX
        bool "Workarounds for PPC601 bugs"
-       depends on 6xx && !POWER3
+       depends on 6xx
        help
          Some versions of the PPC601 (the first PowerPC chip) have bugs which
          mean that extra synchronization instructions are required near
@@ -216,12 +221,12 @@ source arch/ppc/platforms/4xx/Kconfig
 
 config PPC64BRIDGE
        bool
-       depends on POWER3
+       depends on POWER3 || POWER4
        default y
 
 config PPC_STD_MMU
        bool
-       depends on 6xx || POWER3
+       depends on 6xx || POWER3 || POWER4
        default y
 
 config NOT_COHERENT_CACHE
@@ -459,7 +464,7 @@ endchoice
 
 choice
        prompt "Machine Type"
-       depends on 6xx || POWER3
+       depends on 6xx || POWER3 || POWER4
        default PPC_MULTIPLATFORM
        ---help---
          Linux currently supports several different kinds of PowerPC-based
@@ -952,7 +957,7 @@ config ISA
 
 config GENERIC_ISA_DMA
        bool
-       depends on POWER3 || 6xx && !8260
+       depends on POWER3 || POWER4 || 6xx && !8260
        default y
 
 config EISA
index 91f33f83d2fe012dc355cf31b52944fb5f96b6e2..fb92850643bcf0c9aa7ad9c1817789a3be5e4449 100644 (file)
@@ -32,6 +32,7 @@ head-$(CONFIG_4xx)            := arch/ppc/kernel/head_4xx.o
 head-$(CONFIG_44x)             := arch/ppc/kernel/head_44x.o
 
 head-$(CONFIG_6xx)             += arch/ppc/kernel/idle_6xx.o
+head-$(CONFIG_POWER4)          += arch/ppc/kernel/idle_power4.o
 
 core-y                         += arch/ppc/kernel/ arch/ppc/platforms/ \
                                   arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/
index e360f447c6dc52a567a67168bf5b2b13f3d74427..80489f0648f27b4f3388aa6c40612f6de0d7e2d0 100644 (file)
@@ -15,6 +15,7 @@ extra-$(CONFIG_40x)           := head_4xx.o
 extra-$(CONFIG_44x)            := head_44x.o
 extra-$(CONFIG_8xx)            := head_8xx.o
 extra-$(CONFIG_6xx)            += idle_6xx.o
+extra-$(CONFIG_POWER4)         += idle_power4.o
 extra-y                                += vmlinux.lds.s
 
 obj-y                          := entry.o traps.o irq.o idle.o time.o misc.o \
index 60f8629e32d0f70a90d74786a46a4dc569650fd3..2ac528f70446d019e1c76693651c4290400022f6 100644 (file)
@@ -28,11 +28,13 @@ extern void __setup_cpu_7400(unsigned long offset, int cpu_nr, struct cpu_spec*
 extern void __setup_cpu_7410(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_745x(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_power3(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_power4(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
+extern void __setup_cpu_ppc970(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_8xx(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 
 #define CLASSIC_PPC (!defined(CONFIG_8xx) && !defined(CONFIG_4xx) && \
-                    !defined(CONFIG_POWER3))
+                    !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4))
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -44,9 +46,11 @@ extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spe
  * support
  */
 #ifdef CONFIG_ALTIVEC
-#define CPU_FTR_ALTIVEC_COMP   CPU_FTR_ALTIVEC
+#define CPU_FTR_ALTIVEC_COMP           CPU_FTR_ALTIVEC
+#define PPC_FEATURE_ALTIVEC_COMP       PPC_FEATURE_HAS_ALTIVEC  
 #else
-#define CPU_FTR_ALTIVEC_COMP   0
+#define CPU_FTR_ALTIVEC_COMP           0
+#define PPC_FEATURE_ALTIVEC_COMP               0
 #endif
 
 struct cpu_spec        cpu_specs[] = {
@@ -195,7 +199,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
        CPU_FTR_CAN_NAP,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP,
        32, 32,
        __setup_cpu_7400
     },
@@ -204,7 +208,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
        CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
        CPU_FTR_CAN_NAP,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP
        32, 32,
        __setup_cpu_7400
     },
@@ -213,7 +217,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
        CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE |
        CPU_FTR_CAN_NAP,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP
        32, 32,
        __setup_cpu_7410
     },
@@ -222,7 +226,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
        CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP
        32, 32,
        __setup_cpu_745x
     },
@@ -232,7 +236,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
        CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
        CPU_FTR_L3_DISABLE_NAP,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP,
        32, 32,
        __setup_cpu_745x
     },
@@ -241,7 +245,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_CAN_NAP |
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
        CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP
        32, 32,
        __setup_cpu_745x
     },
@@ -250,7 +254,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB |
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
        CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP
        32, 32,
        __setup_cpu_745x
     },
@@ -260,7 +264,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
        CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
        CPU_FTR_L3_DISABLE_NAP | CPU_FTR_HAS_HIGH_BATS,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP
        32, 32,
        __setup_cpu_745x
     },
@@ -270,7 +274,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
        CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
        CPU_FTR_HAS_HIGH_BATS,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP
        32, 32,
        __setup_cpu_745x
     },
@@ -280,7 +284,7 @@ struct cpu_spec     cpu_specs[] = {
        CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR |
        CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_NAP_DISABLE_L2_PR |
        CPU_FTR_HAS_HIGH_BATS,
-       COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+       COMMON_PPC | PPC_FEATURE_ALTIVEC_COMP,
        32, 32,
        __setup_cpu_745x
     },
@@ -329,6 +333,23 @@ struct cpu_spec    cpu_specs[] = {
                __setup_cpu_power3
        },
 #endif /* CONFIG_PPC64BRIDGE */
+#ifdef CONFIG_POWER4
+    {  /* Power4 */
+       0xffff0000, 0x00350000, "Power4",
+       CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
+       COMMON_PPC | PPC_FEATURE_64,
+       128, 128,
+       __setup_cpu_power4
+    },
+    {  /* PPC970 */
+       0xffff0000, 0x00390000, "PPC970",
+       CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+       CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP,
+       COMMON_PPC | PPC_FEATURE_64 | PPC_FEATURE_ALTIVEC_COMP,
+       128, 128,
+       __setup_cpu_ppc970
+    },
+#endif /* CONFIG_POWER4 */
 #ifdef CONFIG_8xx
     {  /* 8xx */
        0xffff0000, 0x00500000, "8xx",
index 3c36a5860c9a860a5969081584cae1b8b66df2e8..57cc4f4261cc7d855f4215bd245949ea53920590 100644 (file)
@@ -140,6 +140,18 @@ __start:
        mr      r28,r6
        mr      r27,r7
        li      r24,0                   /* cpu # */
+
+#ifdef CONFIG_POWER4
+/*
+ * On the PPC970, we have to turn off real-mode cache inhibit
+ * early, before we first turn the MMU off.
+ */
+       mfspr   r0,SPRN_PVR
+       srwi    r0,r0,16
+       cmpwi   r0,0x39
+       beql    ppc970_setup_hid
+#endif /* CONFIG_POWER4 */
+
 /*
  * early_init() does the early machine identification and does
  * the necessary low-level setup and clears the BSS
@@ -160,6 +172,7 @@ __start:
  */
        bl      mmu_off
 __after_mmu_off:
+#ifndef CONFIG_POWER4
        bl      clear_bats
        bl      flush_tlbs
 
@@ -167,6 +180,28 @@ __after_mmu_off:
 #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
        bl      setup_disp_bat
 #endif
+#else /* CONFIG_POWER4 */
+/*
+ * Load up the SDR1 and segment register values now
+ * since we don't have the BATs.
+ * Also make sure we are running in 32-bit mode.
+ */
+       bl      reloc_offset
+       addis   r14,r3,_SDR1@ha         /* get the value from _SDR1 */
+       lwz     r14,_SDR1@l(r14)        /* assume hash table below 4GB */
+       mtspr   SDR1,r14
+       slbia
+       lis     r4,0x2000               /* set pseudo-segment reg 12 */
+       ori     r5,r4,0x0ccc
+       mtsr    12,r5
+       ori     r4,r4,0x0888            /* set pseudo-segment reg 8 */
+       mtsr    8,r4                    /* (for access to serial port) */
+       mfmsr   r0
+       clrldi  r0,r0,1
+       sync
+       mtmsr   r0
+       isync
+#endif /* CONFIG_POWER4 */
 
 /*
  * Call setup_cpu for CPU 0 and initialize 6xx Idle
@@ -178,6 +213,10 @@ __after_mmu_off:
        bl      reloc_offset
        bl      init_idle_6xx
 #endif /* CONFIG_6xx */
+#ifdef CONFIG_POWER4
+       bl      reloc_offset
+       bl      init_idle_power4
+#endif /* CONFIG_POWER4 */
 
 
 #ifndef CONFIG_APUS
@@ -683,12 +722,21 @@ DataStoreTLBMiss:
        mtcrf   0x80,r3
        rfi
 
+#ifndef CONFIG_ALTIVEC
+#define AltivecAssistException UnknownException
+#endif
        EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, EXC_XFER_EE)
        EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE)
        EXCEPTION(0x1500, Trap_15, UnknownException, EXC_XFER_EE)
+#ifdef CONFIG_POWER4
        EXCEPTION(0x1600, Trap_16, UnknownException, EXC_XFER_EE)
+       EXCEPTION(0x1700, Trap_17, AltivecAssistException, EXC_XFER_EE)
+       EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD)
+#else /* !CONFIG_POWER4 */
+       EXCEPTION(0x1600, Trap_16, AltivecAssistException, EXC_XFER_EE)
        EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD)
        EXCEPTION(0x1800, Trap_18, UnknownException, EXC_XFER_EE)
+#endif /* CONFIG_POWER4 */
        EXCEPTION(0x1900, Trap_19, UnknownException, EXC_XFER_EE)
        EXCEPTION(0x1a00, Trap_1a, UnknownException, EXC_XFER_EE)
        EXCEPTION(0x1b00, Trap_1b, UnknownException, EXC_XFER_EE)
@@ -1199,6 +1247,10 @@ __secondary_start:
        lis     r3,-KERNELBASE@h
        bl      init_idle_6xx
 #endif /* CONFIG_6xx */
+#ifdef CONFIG_POWER4
+       lis     r3,-KERNELBASE@h
+       bl      init_idle_power4
+#endif /* CONFIG_POWER4 */
 
        /* get current_thread_info and current */
        lis     r1,secondary_ti@ha
@@ -1226,6 +1278,7 @@ __secondary_start:
 
        /* enable MMU and jump to start_secondary */
        li      r4,MSR_KERNEL
+       FIX_SRR1(r4,r5)
        lis     r3,start_secondary@h
        ori     r3,r3,start_secondary@l
        mtspr   SRR0,r3
@@ -1240,6 +1293,10 @@ __secondary_start:
  */
 _GLOBAL(__setup_cpu_power3)
        blr
+_GLOBAL(__setup_cpu_power4)
+       blr
+_GLOBAL(__setup_cpu_ppc970)
+       blr
 _GLOBAL(__setup_cpu_generic)
        blr
 
@@ -1247,6 +1304,13 @@ _GLOBAL(__setup_cpu_generic)
 _GLOBAL(__save_cpu_setup)
        blr
 _GLOBAL(__restore_cpu_setup)
+#ifdef CONFIG_POWER4
+       /* turn off real-mode cache inhibit on the PPC970 */
+       mfspr   r0,SPRN_PVR
+       srwi    r0,r0,16
+       cmpwi   r0,0x39
+       beq     ppc970_setup_hid
+#endif
        blr
 #endif /* CONFIG_6xx */
 
@@ -1256,6 +1320,11 @@ _GLOBAL(__restore_cpu_setup)
  * IR=0 and DR=0.
  */
 load_up_mmu:
+       sync                    /* Force all PTE updates to finish */
+       isync
+       tlbia                   /* Clear all TLB entries */
+       sync                    /* wait for tlbia/tlbie to finish */
+       TLBSYNC                 /* ... on all CPUs */
        /* Load the SDR1 register (hash table base & size) */
        lis     r6,_SDR1@ha
        tophys(r6,r6)
@@ -1274,6 +1343,7 @@ load_up_mmu:
        addi    r3,r3,0x111     /* increment VSID */
        addis   r4,r4,0x1000    /* address of next segment */
        bdnz    3b
+#ifndef CONFIG_POWER4
 /* Load the BAT registers with the values set up by MMU_init.
    MMU_init takes care of whether we're on a 601 or not. */
        mfpvr   r3
@@ -1286,6 +1356,7 @@ load_up_mmu:
        LOAD_BAT(1,r3,r4,r5)
        LOAD_BAT(2,r3,r4,r5)
        LOAD_BAT(3,r3,r4,r5)
+#endif /* CONFIG_POWER4 */
        blr
 
 /*
@@ -1349,15 +1420,9 @@ start_here:
        SYNC
        RFI
 /* Load up the kernel context */
-2:
-       sync                    /* Force all PTE updates to finish */
-       ISYNC_601
-       tlbia                   /* Clear all TLB entries */
-       sync                    /* wait for tlbia/tlbie to finish */
-       TLBSYNC                 /* ... on all CPUs */
-
-       bl      load_up_mmu
+2:     bl      load_up_mmu
 
+#ifdef CONFIG_BDI_SWITCH
        /* Add helper information for the Abatron bdiGDB debugger.
         * We do this here because we know the mmu is disabled, and
         * will be enabled for real in just a few instructions.
@@ -1369,6 +1434,7 @@ start_here:
        ori     r6, r6, swapper_pg_dir@l
        tophys(r5, r5)
        stw     r6, 0(r5)
+#endif /* CONFIG_BDI_SWITCH */
 
 /* Now turn on the MMU for real! */
        li      r4,MSR_KERNEL
@@ -1493,6 +1559,7 @@ mmu_off:
        sync
        RFI
 
+#ifndef CONFIG_POWER4
 /*
  * Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.  From this point on we can't safely
@@ -1566,6 +1633,41 @@ setup_disp_bat:
 
 #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
 
+#else /* CONFIG_POWER4 */
+ppc970_setup_hid:
+       li      r0,0
+       sync
+       mtspr   0x3f4,r0
+       isync
+       sync
+       mtspr   0x3f6,r0
+       isync
+       mfspr   r0,SPRN_HID0
+       li      r11,1                   /* clear DOZE, NAP and SLEEP */
+       rldimi  r0,r11,52,8             /* set DPM */
+       mtspr   SPRN_HID0,r0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       sync
+       isync
+       mfspr   r0,SPRN_HID1
+       li      r11,0x1200              /* enable i-fetch cacheability */
+       sldi    r11,r11,44              /* and prefetch */
+       or      r0,r0,r11
+       mtspr   SPRN_HID1,r0
+       mtspr   SPRN_HID1,r0
+       isync
+       li      r0,0
+       sync
+       mtspr   0x137,0
+       isync
+       blr
+#endif /* CONFIG_POWER4 */
+
 #ifdef CONFIG_8260
 /* Jump into the system reset for the rom.
  * We first disable the MMU, and then jump to the ROM reset address.
diff --git a/arch/ppc/kernel/idle_power4.S b/arch/ppc/kernel/idle_power4.S
new file mode 100644 (file)
index 0000000..f02c12f
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  This file contains the power_save function for 6xx & 7xxx CPUs
+ *  rewritten in assembler
+ *
+ *  Warning ! This code assumes that if your machine has a 750fx
+ *  it will have PLL 1 set to low speed mode (used during NAP/DOZE).
+ *  if this is not the case some additional changes will have to
+ *  be done to check a runtime var (a bit like powersave-nap)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+#undef DEBUG
+
+       .text
+
+/*
+ * Init idle, called at early CPU setup time from head.S for each CPU
+ * Make sure no rest of NAP mode remains in HID0, save default
+ * values for some CPU specific registers. Called with r24
+ * containing CPU number and r3 reloc offset
+ */
+       .globl  init_idle_power4
+init_idle_power4:
+BEGIN_FTR_SECTION
+       mfspr   r4,SPRN_HID0
+       rlwinm  r4,r4,0,10,8    /* Clear NAP */
+       mtspr   SPRN_HID0, r4
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
+       blr
+
+/*
+ * Here is the power_save_6xx function. This could eventually be
+ * split into several functions & changing the function pointer
+ * depending on the various features.
+ */
+       .globl  power4_idle
+power4_idle:
+       /* Check if we can nap or doze, put HID0 mask in r3
+        */
+       lis     r3, 0
+BEGIN_FTR_SECTION
+       /* We must dynamically check for the NAP feature as it
+        * can be cleared by CPU init after the fixups are done
+        */
+       lis     r4,cur_cpu_spec@ha
+       lwz     r4,cur_cpu_spec@l(r4)
+       lwz     r4,CPU_SPEC_FEATURES(r4)
+       andi.   r0,r4,CPU_FTR_CAN_NAP
+       beq     1f
+       /* Now check if user or arch enabled NAP mode */
+       lis     r4,powersave_nap@ha
+       lwz     r4,powersave_nap@l(r4)
+       cmpi    0,r4,0
+       beq     1f
+       lis     r3,HID0_NAP@h
+1:     
+END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
+       cmpi    0,r3,0
+       beqlr
+
+       /* Clear MSR:EE */
+       mfmsr   r7
+       rlwinm  r0,r7,0,17,15
+       mtmsr   r0
+
+       /* Check current_thread_info()->flags */
+       rlwinm  r4,r1,0,0,18
+       lwz     r4,TI_FLAGS(r4)
+       andi.   r0,r4,_TIF_NEED_RESCHED
+       beq     1f
+       mtmsr   r7      /* out of line this ? */
+       blr
+1:     
+       /* Go to NAP now */     
+       mfspr   r4,SPRN_HID0
+       lis     r5,(HID0_NAP|HID0_SLEEP)@h
+       andc    r4,r4,r5
+       or      r4,r4,r3
+       oris    r4,r4,HID0_DPM@h        /* that should be done once for all  */
+       mtspr   SPRN_HID0,r4
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+       mfspr   r0,SPRN_HID0
+BEGIN_FTR_SECTION
+       DSSALL
+       sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+       ori     r7,r7,MSR_EE /* Could be ommited (already set) */
+       oris    r7,r7,MSR_POW@h
+       sync
+       isync
+       mtmsr   r7
+       isync
+       sync
+       blr
+       
+       .globl powersave_nap
+powersave_nap:
+       .long   0
index e27e08215a32eadc06b91bb578b67ef4dbb69a28..7b399de14a8522530c5693f96207dbe0c46810a9 100644 (file)
@@ -54,6 +54,7 @@ extern void kgdb_map_scc(void);
 #endif
 
 extern void ppc6xx_idle(void);
+extern void power4_idle(void);
 
 extern boot_infos_t *boot_infos;
 char saved_command_line[256];
@@ -529,9 +530,12 @@ machine_init(unsigned long r3, unsigned long r4, unsigned long r5,
        strcpy(cmd_line, CONFIG_CMDLINE);
 #endif /* CONFIG_CMDLINE */
 
-#if defined(CONFIG_6xx)
+#ifdef CONFIG_6xx
        ppc_md.power_save = ppc6xx_idle;
 #endif
+#ifdef CONFIG_POWER4
+       ppc_md.power_save = power4_idle;
+#endif
 
        platform_init(r3, r4, r5, r6, r7);
 
index 1f1304c15b6477e82eface04ee269c9244bdd361..12964a53af85d8de3da93580a4b2a91ed5fc37c8 100644 (file)
@@ -577,6 +577,17 @@ TAUException(struct pt_regs *regs)
 }
 #endif /* CONFIG_INT_TAU */
 
+#ifdef CONFIG_ALTIVEC
+void
+AltivecAssistException(struct pt_regs *regs)
+{
+       if (regs->msr & MSR_VEC)
+               giveup_altivec(current);
+       /* XXX quick hack for now: set the non-Java bit in the VSCR */
+       current->thread.vscr.u[3] |= 0x10000;
+}
+#endif /* CONFIG_ALTIVEC */
+
 void __init trap_init(void)
 {
 }
index f1a8f8ec1300e2b8885ad67137a9568d921e23d8..76bf8cc342a811a93e1a2f958881196c283cd0de 100644 (file)
@@ -54,6 +54,9 @@
  * vector that will be called by the ROM on wakeup
  */
 _GLOBAL(low_sleep_handler)
+#ifndef CONFIG_6xx
+       blr
+#else
        mflr    r0
        stw     r0,4(r1)
        stwu    r1,-SL_SIZE(r1)
@@ -381,4 +384,6 @@ turn_on_mmu:
 sleep_storage:
        .long 0
        .balign L1_CACHE_LINE_SIZE, 0
+
+#endif /* CONFIG_6xx */
        .section .text
index 2e4467bcf31e33aab4a9239c33021e0e82cd1cfa..cda239c9b344ec42f85ed3f1d631157d0732ae49 100644 (file)
@@ -434,9 +434,14 @@ setup_disp_fake_bi(ihandle dp)
        if (strcmp(name, "valkyrie") == 0)
                address += 0x1000;
 
+#ifdef CONFIG_POWER4
+       extern int boot_text_mapped;
+       btext_setup_display(width, height, depth, pitch, address);
+       boot_text_mapped = 0;
+#else
        btext_setup_display(width, height, depth, pitch, address);
-
        btext_prepare_BAT();
+#endif
 #endif /* CONFIG_BOOTX_TEXT */
 }
 
@@ -644,6 +649,72 @@ prom_hold_cpus(unsigned long mem)
        }
 }
 
+#ifdef CONFIG_POWER4
+/*
+ * Set up a hash table with a set of entries in it to map the
+ * first 64MB of RAM.  This is used on 64-bit machines since
+ * some of them don't have BATs.
+ * We assume the PTE will fit in the primary PTEG.
+ */
+
+static inline void make_pte(unsigned long htab, unsigned int hsize,
+                           unsigned int va, unsigned int pa, int mode)
+{
+       unsigned int *pteg;
+       unsigned int hash, i, vsid;
+
+       vsid = ((va >> 28) * 0x111) << 12;
+       hash = ((va ^ vsid) >> 5) & 0x7fff80;
+       pteg = (unsigned int *)(htab + (hash & (hsize - 1)));
+       for (i = 0; i < 8; ++i, pteg += 4) {
+               if ((pteg[1] & 1) == 0) {
+                       pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;
+                       pteg[3] = pa | mode;
+                       break;
+               }
+       }
+}
+
+extern unsigned long _SDR1;
+extern PTE *Hash;
+extern unsigned long Hash_size;
+
+static void __init
+prom_alloc_htab(void)
+{
+       unsigned int hsize;
+       unsigned long htab;
+       unsigned int addr;
+
+       /*
+        * Because of OF bugs we can't use the "claim" client
+        * interface to allocate memory for the hash table.
+        * This code is only used on 64-bit PPCs, and the only
+        * 64-bit PPCs at the moment are RS/6000s, and their
+        * OF is based at 0xc00000 (the 12M point), so we just
+        * arbitrarily use the 0x800000 - 0xc00000 region for the
+        * hash table.
+        *  -- paulus.
+        */
+       hsize = 4 << 20;        /* POWER4 has no BATs */
+       htab = (8 << 20);
+       call_prom("claim", 3, 1, htab, hsize, 0);
+       Hash = (void *)(htab + KERNELBASE);
+       Hash_size = hsize;
+       _SDR1 = htab + __ilog2(hsize) - 18;
+
+       /*
+        * Put in PTEs for the first 64MB of RAM
+        */
+       cacheable_memzero((void *)htab, hsize);
+       for (addr = 0; addr < 0x4000000; addr += 0x1000)
+               make_pte(htab, hsize, addr + KERNELBASE, addr,
+                        _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);
+       make_pte(htab, hsize, 0x80013000, 0x80013000,
+                _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);
+}
+#endif /* CONFIG_POWER4 */
+
 static void __init
 prom_instantiate_rtas(void)
 {
@@ -745,6 +816,13 @@ prom_init(int r3, int r4, prom_entry pp)
 
        prom_instantiate_rtas();
 
+#ifdef CONFIG_POWER4
+       /*
+        * Find out how much memory we have and allocate a
+        * suitably-sized hash table.
+        */
+       prom_alloc_htab();
+#endif
        mem = check_display(mem);
 
        prom_print("copying OF device tree...");