Commit 29052d81 authored by Linus Torvalds's avatar Linus Torvalds

Merge PPC update

parents 12a981f8 4d41d245
...@@ -30,6 +30,10 @@ config PPC32 ...@@ -30,6 +30,10 @@ config PPC32
bool bool
default y default y
# All PPCs use generic nvram driver through ppc_md
config GENERIC_NVRAM
bool
default y
source "init/Kconfig" source "init/Kconfig"
...@@ -989,8 +993,6 @@ config HOTPLUG ...@@ -989,8 +993,6 @@ config HOTPLUG
source "drivers/pcmcia/Kconfig" source "drivers/pcmcia/Kconfig"
source "drivers/parport/Kconfig"
endmenu endmenu
menu "Advanced setup" menu "Advanced setup"
...@@ -1088,179 +1090,10 @@ config PIN_TLB ...@@ -1088,179 +1090,10 @@ config PIN_TLB
depends on ADVANCED_OPTIONS && 8xx depends on ADVANCED_OPTIONS && 8xx
endmenu endmenu
source "drivers/base/Kconfig" source "drivers/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/pnp/Kconfig"
source "drivers/block/Kconfig"
source "drivers/md/Kconfig"
source "drivers/ide/Kconfig"
source "drivers/scsi/Kconfig"
source "drivers/message/fusion/Kconfig"
source "drivers/ieee1394/Kconfig"
source "drivers/message/i2o/Kconfig"
source "net/Kconfig"
source "drivers/isdn/Kconfig"
source "drivers/video/Kconfig"
source "drivers/cdrom/Kconfig"
source "drivers/input/Kconfig"
menu "Macintosh device drivers"
# we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU
config ADB_CUDA
bool "Support for CUDA based PowerMacs"
depends on PPC_PMAC
help
This provides support for CUDA based Power Macintosh systems. This
includes most OldWorld PowerMacs, the first generation iMacs, the
Blue&White G3 and the "Yikes" G4 (PCI Graphics). All later models
should use CONFIG_ADB_PMU instead. It is safe to say Y here even if
your machine doesn't have a CUDA.
If unsure say Y.
config ADB_PMU
bool "Support for PMU based PowerMacs"
depends on PPC_PMAC
help
On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
PMU is an embedded microprocessor whose primary function is to
control system power, and battery charging on the portable models.
The PMU also controls the ADB (Apple Desktop Bus) which connects to
the keyboard and mouse on some machines, as well as the non-volatile
RAM and the RTC (real time clock) chip. Say Y to enable support for
this device; you should do so if your machine is one of those
mentioned above.
config PMAC_PBOOK
bool "Power management support for PowerBooks"
depends on ADB_PMU
---help---
This provides support for putting a PowerBook to sleep; it also
enables media bay support. Power management works on the
PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
the Titanium Powerbook G4, as well as the iBooks. You should get
the power management daemon, pmud, to make it work and you must have
the /dev/pmu device (see the pmud README).
Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
If you have a PowerBook, you should say Y here.
You may also want to compile the dma sound driver as a module and
have it autoloaded. The act of removing the module shuts down the
sound hardware for more power savings.
config PM
bool
depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
default y
config PMAC_APM_EMU
tristate "APM emulation"
depends on PMAC_PBOOK
# made a separate option since backlight may end up beeing used
# on non-powerbook machines (but only on PMU based ones AFAIK)
config PMAC_BACKLIGHT
bool "Backlight control for LCD screens"
depends on ADB_PMU
help
Say Y here to build in code to manage the LCD backlight on a
Macintosh PowerBook. With this code, the backlight will be turned
on and off appropriately on power-management and lid-open/lid-closed
events; also, the PowerBook button device will be enabled so you can
change the screen brightness.
config MAC_FLOPPY
bool "Support for PowerMac floppy"
depends on PPC_PMAC
help
If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
floppy controller, say Y here. Most commonly found in PowerMacs.
config MAC_SERIAL
tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
depends on PPC_PMAC
help
This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
"Character devices --> Serial drivers --> PowerMac z85c30" option.
config ADB
bool "Apple Desktop Bus (ADB) support"
depends on PPC_PMAC
help
Apple Desktop Bus (ADB) support is for support of devices which
are connected to an ADB port. ADB devices tend to have 4 pins.
If you have an Apple Macintosh prior to the iMac, an iBook or
PowerBook, or a "Blue and White G3", you probably want to say Y
here. Otherwise say N.
config ADB_MACIO
bool "Include MacIO (CHRP) ADB driver"
depends on ADB
help
Say Y here to include direct support for the ADB controller in the
Hydra chip used on PowerPC Macintoshes of the CHRP type. (The Hydra
also includes a MESH II SCSI controller, DBDMA controller, VIA chip,
OpenPIC controller and two RS422/Geoports.)
config INPUT_ADBHID
bool "Support for ADB input devices (keyboard, mice, ...)"
depends on ADB && INPUT=y
help
Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
such as keyboards, mice, joysticks, trackpads or graphic tablets
handled by the input layer. If you say Y here, make sure to say Y to
the corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
"Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
support" (CONFIG_INPUT_EVDEV) as well.
If unsure, say Y.
config MAC_EMUMOUSEBTN
bool "Support for mouse button 2+3 emulation"
depends on INPUT_ADBHID
help
This provides generic support for emulating the 2nd and 3rd mouse
button with keypresses. If you say Y here, the emulation is still
disabled by default. The emulation is controlled by these sysctl
entries:
/proc/sys/dev/mac_hid/mouse_button_emulation
/proc/sys/dev/mac_hid/mouse_button2_keycode
/proc/sys/dev/mac_hid/mouse_button3_keycode
If you have an Apple machine with a 1-button mouse, say Y here.
config ANSLCD
bool "Support for ANS LCD display"
depends on ADB_CUDA
endmenu
source "drivers/char/Kconfig"
source "drivers/media/Kconfig"
source "fs/Kconfig" source "fs/Kconfig"
source "sound/Kconfig"
source "arch/ppc/8xx_io/Kconfig" source "arch/ppc/8xx_io/Kconfig"
source "arch/ppc/8260_io/Kconfig" source "arch/ppc/8260_io/Kconfig"
...@@ -1285,8 +1118,6 @@ config SERIAL_SICC_CONSOLE ...@@ -1285,8 +1118,6 @@ config SERIAL_SICC_CONSOLE
endmenu endmenu
source "drivers/usb/Kconfig"
source "lib/Kconfig" source "lib/Kconfig"
......
...@@ -22,11 +22,12 @@ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ ...@@ -22,11 +22,12 @@ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
semaphore.o syscalls.o setup.o \ semaphore.o syscalls.o setup.o \
cputable.o ppc_htab.o cputable.o ppc_htab.o
obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o
obj-$(CONFIG_POWER4) += cpu_setup_power4.o
obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o
obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_PCI) += pci-dma.o obj-$(CONFIG_PCI) += pci-dma.o
obj-$(CONFIG_KGDB) += ppc-stub.o obj-$(CONFIG_KGDB) += ppc-stub.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o smp-tbsync.o
obj-$(CONFIG_TAU) += temp.o obj-$(CONFIG_TAU) += temp.o
ifdef CONFIG_MATH_EMULATION ifdef CONFIG_MATH_EMULATION
......
...@@ -142,7 +142,7 @@ setup_7410_workarounds: ...@@ -142,7 +142,7 @@ setup_7410_workarounds:
sync sync
isync isync
blr blr
/* 740/750/7400/7410 /* 740/750/7400/7410
* Enable Store Gathering (SGE), Address Brodcast (ABE), * Enable Store Gathering (SGE), Address Brodcast (ABE),
* Branch History Table (BHTE), Branch Target ICache (BTIC) * Branch History Table (BHTE), Branch Target ICache (BTIC)
...@@ -213,7 +213,7 @@ setup_745x_specifics: ...@@ -213,7 +213,7 @@ setup_745x_specifics:
li r7,CPU_FTR_CAN_NAP li r7,CPU_FTR_CAN_NAP
andc r6,r6,r7 andc r6,r6,r7
stw r6,CPU_SPEC_FEATURES(r5) stw r6,CPU_SPEC_FEATURES(r5)
1: 1:
mfspr r11,HID0 mfspr r11,HID0
/* All of the bits we have to set..... /* All of the bits we have to set.....
...@@ -248,20 +248,21 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) ...@@ -248,20 +248,21 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
/* Definitions for the table use to save CPU states */ /* Definitions for the table use to save CPU states */
#define CS_HID0 0 #define CS_HID0 0
#define CS_HID1 4 #define CS_HID1 4
#define CS_MSSCR0 8 #define CS_HID2 8
#define CS_MSSSR0 12 #define CS_MSSCR0 12
#define CS_ICTRL 16 #define CS_MSSSR0 16
#define CS_LDSTCR 20 #define CS_ICTRL 20
#define CS_LDSTDB 24 #define CS_LDSTCR 24
#define CS_SIZE 28 #define CS_LDSTDB 28
#define CS_SIZE 32
.data .data
.balign L1_CACHE_LINE_SIZE .balign L1_CACHE_LINE_SIZE
cpu_state_storage: cpu_state_storage:
.space CS_SIZE .space CS_SIZE
.balign L1_CACHE_LINE_SIZE,0 .balign L1_CACHE_LINE_SIZE,0
.text .text
/* Called in normal context to backup CPU 0 state. This /* Called in normal context to backup CPU 0 state. This
* does not include cache settings. This function is also * does not include cache settings. This function is also
* called for machine sleep. This does not include the MMU * called for machine sleep. This does not include the MMU
...@@ -311,11 +312,18 @@ _GLOBAL(__save_cpu_setup) ...@@ -311,11 +312,18 @@ _GLOBAL(__save_cpu_setup)
stw r4,CS_LDSTCR(r5) stw r4,CS_LDSTCR(r5)
mfspr r4,SPRN_LDSTDB mfspr r4,SPRN_LDSTDB
stw r4,CS_LDSTDB(r5) stw r4,CS_LDSTDB(r5)
1: 1:
bne cr5,1f bne cr5,1f
/* Backup 750FX specific registers */ /* Backup 750FX specific registers */
mfspr r4,SPRN_HID1 mfspr r4,SPRN_HID1
stw r4,CS_HID1(r5) stw r4,CS_HID1(r5)
/* If rev 2.x, backup HID2 */
mfspr r3,PVR
andi. r3,r3,0xff00
cmpi cr0,r3,0x0200
bne 1f
mfspr r4,SPRN_HID2
stw r4,CS_HID2(r5)
1: 1:
mtcr r7 mtcr r7
blr blr
...@@ -395,9 +403,19 @@ _GLOBAL(__restore_cpu_setup) ...@@ -395,9 +403,19 @@ _GLOBAL(__restore_cpu_setup)
sync sync
2: bne cr5,1f 2: bne cr5,1f
/* Restore 750FX specific registers /* Restore 750FX specific registers
* that is restore PLL config & switch * that is restore HID2 on rev 2.x and PLL config & switch
* to PLL 0 * to PLL 0 on all
*/ */
/* If rev 2.x, restore HID2 with low voltage bit cleared */
mfspr r3,PVR
andi. r3,r3,0xff00
cmpi cr0,r3,0x0200
bne 4f
lwz r4,CS_HID2(r5)
rlwinm r4,r4,0,19,17
mtspr SPRN_HID2,r4
sync
4:
lwz r4,CS_HID1(r5) lwz r4,CS_HID1(r5)
rlwinm r5,r4,0,16,14 rlwinm r5,r4,0,16,14
mtspr SPRN_HID1,r5 mtspr SPRN_HID1,r5
......
/*
* This file contains low level CPU setup functions.
* Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
*
* 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 <asm/processor.h>
#include <asm/page.h>
#include <asm/ppc_asm.h>
#include <asm/cputable.h>
#include <asm/ppc_asm.h>
#include <asm/offsets.h>
#include <asm/cache.h>
_GLOBAL(__power4_cpu_preinit)
/*
* 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
bnelr
li r0,0
sync
mtspr SPRN_HID4,r0
isync
sync
mtspr SPRN_HID5,r0
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 SPRN_HIOR,0 /* Clear interrupt prefix */
isync
blr
_GLOBAL(__setup_cpu_power4)
blr
_GLOBAL(__setup_cpu_ppc970)
mfspr r0,SPRN_HID0
li r11,5 /* clear DOZE and SLEEP */
rldimi r0,r11,52,8 /* set NAP and 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
blr
/* Definitions for the table use to save CPU states */
#define CS_HID0 0
#define CS_HID1 8
#define CS_HID4 16
#define CS_HID5 24
#define CS_SIZE 32
.data
.balign L1_CACHE_LINE_SIZE
cpu_state_storage:
.space CS_SIZE
.balign L1_CACHE_LINE_SIZE,0
.text
/* Called in normal context to backup CPU 0 state. This
* does not include cache settings. This function is also
* called for machine sleep. This does not include the MMU
* setup, BATs, etc... but rather the "special" registers
* like HID0, HID1, HID4, etc...
*/
_GLOBAL(__save_cpu_setup)
/* Some CR fields are volatile, we back it up all */
mfcr r7
/* Get storage ptr */
lis r5,cpu_state_storage@h
ori r5,r5,cpu_state_storage@l
/* We only deal with 970 for now */
mfspr r0,SPRN_PVR
srwi r0,r0,16
cmpwi r0,0x39
bne 1f
/* Save HID0,1,4 and 5 */
mfspr r3,SPRN_HID0
std r3,CS_HID0(r5)
mfspr r3,SPRN_HID1
std r3,CS_HID1(r5)
mfspr r3,SPRN_HID4
std r3,CS_HID4(r5)
mfspr r3,SPRN_HID5
std r3,CS_HID5(r5)
1:
mtcr r7
blr
/* Called with no MMU context (typically MSR:IR/DR off) to
* restore CPU state as backed up by the previous
* function. This does not include cache setting
*/
_GLOBAL(__restore_cpu_setup)
/* Some CR fields are volatile, we back it up all */
mfcr r7
/* Get storage ptr */
lis r5,(cpu_state_storage-KERNELBASE)@h
ori r5,r5,cpu_state_storage@l
/* We only deal with 970 for now */
mfspr r0,SPRN_PVR
srwi r0,r0,16
cmpwi r0,0x39
bne 1f
/* Clear interrupt prefix */
li r0,0
sync
mtspr SPRN_HIOR,0
isync
/* Restore HID0 */
ld r3,CS_HID0(r5)
sync
isync
mtspr SPRN_HID0,r3
mfspr r3,SPRN_HID0
mfspr r3,SPRN_HID0
mfspr r3,SPRN_HID0
mfspr r3,SPRN_HID0
mfspr r3,SPRN_HID0
mfspr r3,SPRN_HID0
sync
isync
/* Restore HID1 */
ld r3,CS_HID1(r5)
sync
isync
mtspr SPRN_HID1,r3
mtspr SPRN_HID1,r3
sync
isync
/* Restore HID4 */
ld r3,CS_HID4(r5)
sync
isync
mtspr SPRN_HID4,r3
sync
isync
/* Restore HID5 */
ld r3,CS_HID5(r5)
sync
isync
mtspr SPRN_HID5,r3
sync
isync
1:
mtcr r7
blr
...@@ -141,17 +141,6 @@ __start: ...@@ -141,17 +141,6 @@ __start:
mr r27,r7 mr r27,r7
li r24,0 /* cpu # */ 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 * early_init() does the early machine identification and does
* the necessary low-level setup and clears the BSS * the necessary low-level setup and clears the BSS
...@@ -159,6 +148,14 @@ __start: ...@@ -159,6 +148,14 @@ __start:
*/ */
bl early_init bl early_init
/*
* On POWER4, we first need to tweak some CPU configuration registers
* like real mode cache inhibit or exception base
*/
#ifdef CONFIG_POWER4
bl __power4_cpu_preinit
#endif /* CONFIG_POWER4 */
#ifdef CONFIG_APUS #ifdef CONFIG_APUS
/* On APUS the __va/__pa constants need to be set to the correct /* On APUS the __va/__pa constants need to be set to the correct
* values before continuing. * values before continuing.
...@@ -1216,7 +1213,7 @@ __secondary_start_psurge99: ...@@ -1216,7 +1213,7 @@ __secondary_start_psurge99:
__secondary_start: __secondary_start:
#ifdef CONFIG_PPC64BRIDGE #ifdef CONFIG_PPC64BRIDGE
mfmsr r0 mfmsr r0
clrldi r0,r0,1 /* make sure it's in 32-bit mode */ clrldi r0,r0,1 /* make sure it's in 32-bit mode */
SYNC SYNC
MTMSRD(r0) MTMSRD(r0)
isync isync
...@@ -1278,26 +1275,15 @@ __secondary_start: ...@@ -1278,26 +1275,15 @@ __secondary_start:
*/ */
_GLOBAL(__setup_cpu_power3) _GLOBAL(__setup_cpu_power3)
blr blr
_GLOBAL(__setup_cpu_power4)
blr
_GLOBAL(__setup_cpu_ppc970)
blr
_GLOBAL(__setup_cpu_generic) _GLOBAL(__setup_cpu_generic)
blr blr
#ifndef CONFIG_6xx #if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4)
_GLOBAL(__save_cpu_setup) _GLOBAL(__save_cpu_setup)
blr blr
_GLOBAL(__restore_cpu_setup) _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 blr
#endif /* CONFIG_6xx */ #endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */
/* /*
...@@ -1633,10 +1619,14 @@ initial_mm_power4: ...@@ -1633,10 +1619,14 @@ initial_mm_power4:
lis r4,0x2000 /* set pseudo-segment reg 12 */ lis r4,0x2000 /* set pseudo-segment reg 12 */
ori r5,r4,0x0ccc ori r5,r4,0x0ccc
mtsr 12,r5 mtsr 12,r5
#if 0
ori r5,r4,0x0888 /* set pseudo-segment reg 8 */ ori r5,r4,0x0888 /* set pseudo-segment reg 8 */
mtsr 8,r5 /* (for access to serial port) */ mtsr 8,r5 /* (for access to serial port) */
ori r5,r4,0x0999 /* set pseudo-segment reg 8 */ #endif
#ifdef CONFIG_BOOTX_TEXT
ori r5,r4,0x0999 /* set pseudo-segment reg 9 */
mtsr 9,r5 /* (for access to screen) */ mtsr 9,r5 /* (for access to screen) */
#endif
mfmsr r0 mfmsr r0
clrldi r0,r0,1 clrldi r0,r0,1
sync sync
...@@ -1644,43 +1634,8 @@ initial_mm_power4: ...@@ -1644,43 +1634,8 @@ initial_mm_power4:
isync isync
blr blr
/*
* On 970 (G5), we pre-set a few bits in HID0 & HID1
*/
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 */ #endif /* CONFIG_POWER4 */
#ifdef CONFIG_8260 #ifdef CONFIG_8260
/* Jump into the system reset for the rom. /* Jump into the system reset for the rom.
* We first disable the MMU, and then jump to the ROM reset address. * We first disable the MMU, and then jump to the ROM reset address.
......
...@@ -28,17 +28,11 @@ ...@@ -28,17 +28,11 @@
/* /*
* Init idle, called at early CPU setup time from head.S for each CPU * 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 * So nothing for now. Called with r24 containing CPU number and r3
* values for some CPU specific registers. Called with r24 * reloc offset
* containing CPU number and r3 reloc offset
*/ */
.globl init_idle_power4 .globl init_idle_power4
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 blr
/* /*
...@@ -48,10 +42,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) ...@@ -48,10 +42,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
*/ */
.globl power4_idle .globl power4_idle
power4_idle: power4_idle:
/* Check if we can nap or doze, put HID0 mask in r3
*/
lis r3, 0
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
blr
END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
/* We must dynamically check for the NAP feature as it /* We must dynamically check for the NAP feature as it
* can be cleared by CPU init after the fixups are done * can be cleared by CPU init after the fixups are done
*/ */
...@@ -59,16 +52,11 @@ BEGIN_FTR_SECTION ...@@ -59,16 +52,11 @@ BEGIN_FTR_SECTION
lwz r4,cur_cpu_spec@l(r4) lwz r4,cur_cpu_spec@l(r4)
lwz r4,CPU_SPEC_FEATURES(r4) lwz r4,CPU_SPEC_FEATURES(r4)
andi. r0,r4,CPU_FTR_CAN_NAP andi. r0,r4,CPU_FTR_CAN_NAP
beq 1f beqlr
/* Now check if user or arch enabled NAP mode */ /* Now check if user or arch enabled NAP mode */
lis r4,powersave_nap@ha lis r4,powersave_nap@ha
lwz r4,powersave_nap@l(r4) lwz r4,powersave_nap@l(r4)
cmpi 0,r4,0 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 beqlr
/* Clear MSR:EE */ /* Clear MSR:EE */
...@@ -85,18 +73,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) ...@@ -85,18 +73,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
blr blr
1: 1:
/* Go to NAP now */ /* 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 BEGIN_FTR_SECTION
DSSALL DSSALL
sync sync
......
...@@ -201,7 +201,7 @@ _GLOBAL(call_setup_cpu) ...@@ -201,7 +201,7 @@ _GLOBAL(call_setup_cpu)
mr r4,r24 mr r4,r24
bctr bctr
#ifdef CONFIG_CPU_FREQ_PMAC #if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx)
/* This gets called by via-pmu.c to switch the PLL selection /* This gets called by via-pmu.c to switch the PLL selection
* on 750fx CPU. This function should really be moved to some * on 750fx CPU. This function should really be moved to some
...@@ -253,7 +253,7 @@ _GLOBAL(low_choose_750fx_pll) ...@@ -253,7 +253,7 @@ _GLOBAL(low_choose_750fx_pll)
mtmsr r7 mtmsr r7
blr blr
#endif /* CONFIG_CPU_FREQ_PMAC */ #endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */
/* void local_save_flags_ptr(unsigned long *flags) */ /* void local_save_flags_ptr(unsigned long *flags) */
_GLOBAL(local_save_flags_ptr) _GLOBAL(local_save_flags_ptr)
......
...@@ -46,7 +46,9 @@ static int reparent_resources(struct resource *parent, struct resource *res); ...@@ -46,7 +46,9 @@ static int reparent_resources(struct resource *parent, struct resource *res);
static void fixup_rev1_53c810(struct pci_dev* dev); static void fixup_rev1_53c810(struct pci_dev* dev);
static void fixup_cpc710_pci64(struct pci_dev* dev); static void fixup_cpc710_pci64(struct pci_dev* dev);
#ifdef CONFIG_PPC_PMAC #ifdef CONFIG_PPC_PMAC
static void pcibios_fixup_cardbus(struct pci_dev* dev); extern void pmac_pci_fixup_cardbus(struct pci_dev* dev);
extern void pmac_pci_fixup_pciata(struct pci_dev* dev);
extern void pmac_pci_fixup_k2_sata(struct pci_dev* dev);
#endif #endif
#ifdef CONFIG_PPC_OF #ifdef CONFIG_PPC_OF
static u8* pci_to_OF_bus_map; static u8* pci_to_OF_bus_map;
...@@ -69,7 +71,9 @@ struct pci_fixup pcibios_fixups[] = { ...@@ -69,7 +71,9 @@ struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources },
#ifdef CONFIG_PPC_PMAC #ifdef CONFIG_PPC_PMAC
/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus },
{ PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata },
#endif /* CONFIG_PPC_PMAC */ #endif /* CONFIG_PPC_PMAC */
{ 0 } { 0 }
}; };
...@@ -155,42 +159,6 @@ pcibios_fixup_resources(struct pci_dev *dev) ...@@ -155,42 +159,6 @@ pcibios_fixup_resources(struct pci_dev *dev)
ppc_md.pcibios_fixup_resources(dev); ppc_md.pcibios_fixup_resources(dev);
} }
#ifdef CONFIG_PPC_PMAC
static void
pcibios_fixup_cardbus(struct pci_dev* dev)
{
if (_machine != _MACH_Pmac)
return;
/*
* Fix the interrupt routing on the various cardbus bridges
* used on powerbooks
*/
if (dev->vendor != PCI_VENDOR_ID_TI)
return;
if (dev->device == PCI_DEVICE_ID_TI_1130 ||
dev->device == PCI_DEVICE_ID_TI_1131) {
u8 val;
/* Enable PCI interrupt */
if (pci_read_config_byte(dev, 0x91, &val) == 0)
pci_write_config_byte(dev, 0x91, val | 0x30);
/* Disable ISA interrupt mode */
if (pci_read_config_byte(dev, 0x92, &val) == 0)
pci_write_config_byte(dev, 0x92, val & ~0x06);
}
if (dev->device == PCI_DEVICE_ID_TI_1210 ||
dev->device == PCI_DEVICE_ID_TI_1211 ||
dev->device == PCI_DEVICE_ID_TI_1410) {
u8 val;
/* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
signal out the MFUNC0 pin */
if (pci_read_config_byte(dev, 0x8c, &val) == 0)
pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
/* Disable ISA interrupt mode */
if (pci_read_config_byte(dev, 0x92, &val) == 0)
pci_write_config_byte(dev, 0x92, val & ~0x06);
}
}
#endif /* CONFIG_PPC_PMAC */
void void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
...@@ -832,6 +800,17 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) ...@@ -832,6 +800,17 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
return NULL; return NULL;
/* Fixup bus number according to what OF think it is. */ /* Fixup bus number according to what OF think it is. */
#ifdef CONFIG_PPC_PMAC
/* The G5 need a special case here. Basically, we don't remap all
* busses on it so we don't create the pci-OF-map. However, we do
* remap the AGP bus and so have to deal with it. A future better
* fix has to be done by making the remapping per-host and always
* filling the pci_to_OF map. --BenH
*/
if (_machine == _MACH_Pmac && busnr >= 0xf0)
busnr -= 0xf0;
else
#endif
if (pci_to_OF_bus_map) if (pci_to_OF_bus_map)
busnr = pci_to_OF_bus_map[busnr]; busnr = pci_to_OF_bus_map[busnr];
if (busnr == 0xff) if (busnr == 0xff)
...@@ -922,9 +901,10 @@ void __init ...@@ -922,9 +901,10 @@ void __init
pci_process_bridge_OF_ranges(struct pci_controller *hose, pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary) struct device_node *dev, int primary)
{ {
unsigned int *ranges, *prev; static unsigned int static_lc_ranges[256] __initdata;
unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
unsigned int size; unsigned int size;
int rlen = 0; int rlen = 0, orig_rlen;
int memno = 0; int memno = 0;
struct resource *res; struct resource *res;
int np, na = prom_n_addr_cells(dev); int np, na = prom_n_addr_cells(dev);
...@@ -934,7 +914,22 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, ...@@ -934,7 +914,22 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
* that can have more than 3 ranges, fortunately using contiguous * that can have more than 3 ranges, fortunately using contiguous
* addresses -- BenH * addresses -- BenH
*/ */
ranges = (unsigned int *) get_property(dev, "ranges", &rlen); dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
if (!dt_ranges)
return;
/* Sanity check, though hopefully that never happens */
if (rlen > sizeof(static_lc_ranges)) {
printk(KERN_WARNING "OF ranges property too large !\n");
rlen = sizeof(static_lc_ranges);
}
lc_ranges = static_lc_ranges;
memcpy(lc_ranges, dt_ranges, rlen);
orig_rlen = rlen;
/* Let's work on a copy of the "ranges" property instead of damaging
* the device-tree image in memory
*/
ranges = lc_ranges;
prev = NULL; prev = NULL;
while ((rlen -= np * sizeof(unsigned int)) >= 0) { while ((rlen -= np * sizeof(unsigned int)) >= 0) {
if (prev) { if (prev) {
...@@ -959,10 +954,9 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose, ...@@ -959,10 +954,9 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
* (size depending on dev->n_addr_cells) * (size depending on dev->n_addr_cells)
* cells 4+5 or 5+6: the size of the range * cells 4+5 or 5+6: the size of the range
*/ */
rlen = 0; ranges = lc_ranges;
hose->io_base_phys = 0; rlen = orig_rlen;
ranges = (unsigned int *) get_property(dev, "ranges", &rlen); while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
while ((rlen -= np * sizeof(unsigned int)) >= 0) {
res = NULL; res = NULL;
size = ranges[na+4]; size = ranges[na+4];
switch (ranges[0] >> 24) { switch (ranges[0] >> 24) {
...@@ -1059,7 +1053,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga) ...@@ -1059,7 +1053,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
res = *(bus->resource[0]); res = *(bus->resource[0]);
DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->name); DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->slot_name);
res.start -= ((unsigned long) hose->io_base_virt - isa_io_base); res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
res.end -= ((unsigned long) hose->io_base_virt - isa_io_base); res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
DBG(" IO window: %08lx-%08lx\n", res.start, res.end); DBG(" IO window: %08lx-%08lx\n", res.start, res.end);
...@@ -1662,12 +1656,23 @@ pci_bus_to_phys(unsigned int ba, int busnr) ...@@ -1662,12 +1656,23 @@ pci_bus_to_phys(unsigned int ba, int busnr)
* Note that the returned IO or memory base is a physical address * Note that the returned IO or memory base is a physical address
*/ */
long long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
{ {
struct pci_controller* hose = pci_bus_to_hose(bus); struct pci_controller* hose;
long result = -EOPNOTSUPP; long result = -EOPNOTSUPP;
/* Argh ! Please forgive me for that hack, but that's the
* simplest way to get existing XFree to not lockup on some
* G5 machines... So when something asks for bus 0 io base
* (bus 0 is HT root), we return the AGP one instead.
*/
#ifdef CONFIG_PPC_PMAC
if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4"))
if (bus == 0)
bus = 0xf0;
#endif /* CONFIG_PPC_PMAC */
hose = pci_bus_to_hose(bus);
if (!hose) if (!hose)
return -ENODEV; return -ENODEV;
......
...@@ -75,6 +75,7 @@ int abs(int); ...@@ -75,6 +75,7 @@ int abs(int);
extern unsigned long mm_ptov (unsigned long paddr); extern unsigned long mm_ptov (unsigned long paddr);
EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(clear_user_page);
EXPORT_SYMBOL(do_signal); EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(do_syscall_trace); EXPORT_SYMBOL(do_syscall_trace);
EXPORT_SYMBOL(transfer_to_handler); EXPORT_SYMBOL(transfer_to_handler);
...@@ -236,12 +237,6 @@ EXPORT_SYMBOL(adb_try_handler_change); ...@@ -236,12 +237,6 @@ EXPORT_SYMBOL(adb_try_handler_change);
EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_request);
EXPORT_SYMBOL(cuda_poll); EXPORT_SYMBOL(cuda_poll);
#endif /* CONFIG_ADB_CUDA */ #endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_PMAC_BACKLIGHT
EXPORT_SYMBOL(get_backlight_level);
EXPORT_SYMBOL(set_backlight_level);
EXPORT_SYMBOL(set_backlight_enable);
EXPORT_SYMBOL(register_backlight_controller);
#endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PPC_MULTIPLATFORM #ifdef CONFIG_PPC_MULTIPLATFORM
EXPORT_SYMBOL(_machine); EXPORT_SYMBOL(_machine);
#endif #endif
...@@ -282,14 +277,6 @@ EXPORT_SYMBOL(note_scsi_host); ...@@ -282,14 +277,6 @@ EXPORT_SYMBOL(note_scsi_host);
#ifdef CONFIG_VT #ifdef CONFIG_VT
EXPORT_SYMBOL(kd_mksound); EXPORT_SYMBOL(kd_mksound);
#endif #endif
#ifdef CONFIG_NVRAM
EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
#ifdef CONFIG_PPC_PMAC
EXPORT_SYMBOL(pmac_xpram_read);
EXPORT_SYMBOL(pmac_xpram_write);
#endif
#endif /* CONFIG_NVRAM */
EXPORT_SYMBOL(to_tm); EXPORT_SYMBOL(to_tm);
EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(pm_power_off);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/pmac_feature.h> #include <asm/pmac_feature.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/nvram.h>
#include <asm/xmon.h> #include <asm/xmon.h>
#if defined CONFIG_KGDB #if defined CONFIG_KGDB
...@@ -111,6 +112,9 @@ struct screen_info screen_info = { ...@@ -111,6 +112,9 @@ struct screen_info screen_info = {
void machine_restart(char *cmd) void machine_restart(char *cmd)
{ {
#ifdef CONFIG_NVRAM
nvram_sync();
#endif
ppc_md.restart(cmd); ppc_md.restart(cmd);
} }
...@@ -118,6 +122,9 @@ EXPORT_SYMBOL(machine_restart); ...@@ -118,6 +122,9 @@ EXPORT_SYMBOL(machine_restart);
void machine_power_off(void) void machine_power_off(void)
{ {
#ifdef CONFIG_NVRAM
nvram_sync();
#endif
ppc_md.power_off(); ppc_md.power_off();
} }
...@@ -125,6 +132,9 @@ EXPORT_SYMBOL(machine_power_off); ...@@ -125,6 +132,9 @@ EXPORT_SYMBOL(machine_power_off);
void machine_halt(void) void machine_halt(void)
{ {
#ifdef CONFIG_NVRAM
nvram_sync();
#endif
ppc_md.halt(); ppc_md.halt();
} }
...@@ -558,24 +568,30 @@ int __init ppc_setup_l2cr(char *str) ...@@ -558,24 +568,30 @@ int __init ppc_setup_l2cr(char *str)
__setup("l2cr=", ppc_setup_l2cr); __setup("l2cr=", ppc_setup_l2cr);
#ifdef CONFIG_NVRAM #ifdef CONFIG_NVRAM
/* Generic nvram hooks we now look into ppc_md.nvram_read_val
* on pmac too ;) /* Generic nvram hooks used by drivers/char/gen_nvram.c */
* //XX Those 2 could be moved to headers unsigned char nvram_read_byte(int addr)
*/
unsigned char
nvram_read_byte(int addr)
{ {
if (ppc_md.nvram_read_val) if (ppc_md.nvram_read_val)
return ppc_md.nvram_read_val(addr); return ppc_md.nvram_read_val(addr);
return 0xff; return 0xff;
} }
EXPORT_SYMBOL(nvram_read_byte);
void void nvram_write_byte(unsigned char val, int addr)
nvram_write_byte(unsigned char val, int addr)
{ {
if (ppc_md.nvram_write_val) if (ppc_md.nvram_write_val)
ppc_md.nvram_write_val(val, addr); ppc_md.nvram_write_val(addr, val);
}
EXPORT_SYMBOL(nvram_write_byte);
void nvram_sync(void)
{
if (ppc_md.nvram_sync)
ppc_md.nvram_sync();
} }
EXPORT_SYMBOL(nvram_sync);
#endif /* CONFIG_NVRAM */ #endif /* CONFIG_NVRAM */
static struct cpu cpu_devices[NR_CPUS]; static struct cpu cpu_devices[NR_CPUS];
......
/*
* Smp timebase synchronization for ppc.
*
* Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/unistd.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <asm/smp.h>
#include <asm/time.h>
#define NUM_ITER 300
enum {
kExit=0, kSetAndTest, kTest
};
static struct {
volatile int tbu;
volatile int tbl;
volatile int mark;
volatile int cmd;
volatile int handshake;
int filler[3];
volatile int ack;
int filler2[7];
volatile int race_result;
} *tbsync;
static volatile int running;
static void __devinit
enter_contest( int mark, int add )
{
while( (int)(get_tbl() - mark) < 0 )
tbsync->race_result = add;
}
void __devinit
smp_generic_take_timebase( void )
{
int cmd, tbl, tbu;
local_irq_disable();
while( !running )
;
rmb();
for( ;; ) {
tbsync->ack = 1;
while( !tbsync->handshake )
;
rmb();
cmd = tbsync->cmd;
tbl = tbsync->tbl;
tbu = tbsync->tbu;
tbsync->ack = 0;
if( cmd == kExit )
return;
if( cmd == kSetAndTest ) {
while( tbsync->handshake )
;
asm volatile ("mttbl %0" :: "r" (tbl) );
asm volatile ("mttbu %0" :: "r" (tbu) );
} else {
while( tbsync->handshake )
;
}
enter_contest( tbsync->mark, -1 );
}
local_irq_enable();
}
static int __devinit
start_contest( int cmd, int offset, int num )
{
int i, tbu, tbl, mark, score=0;
tbsync->cmd = cmd;
local_irq_disable();
for( i=-3; i<num; ) {
tbl = get_tbl() + 400;
tbsync->tbu = tbu = get_tbu();
tbsync->tbl = tbl + offset;
tbsync->mark = mark = tbl + 400;
wmb();
tbsync->handshake = 1;
while( tbsync->ack )
;
while( (int)(get_tbl() - tbl) <= 0 )
;
tbsync->handshake = 0;
enter_contest( mark, 1 );
while( !tbsync->ack )
;
if( tbsync->tbu != get_tbu() || ((tbsync->tbl ^ get_tbl()) & 0x80000000) )
continue;
if( i++ > 0 )
score += tbsync->race_result;
}
local_irq_enable();
return score;
}
void __devinit
smp_generic_give_timebase( void )
{
int i, score, score2, old, min=0, max=5000, offset=1000;
printk("Synchronizing timebase\n");
/* if this fails then this kernel won't work anyway... */
tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL );
memset( tbsync, 0, sizeof(*tbsync) );
mb();
running = 1;
while( !tbsync->ack )
;
/* binary search */
for( old=-1 ; old != offset ; offset=(min+max)/2 ) {
score = start_contest( kSetAndTest, offset, NUM_ITER );
printk("score %d, offset %d\n", score, offset );
if( score > 0 )
max = offset;
else
min = offset;
old = offset;
}
score = start_contest( kSetAndTest, min, NUM_ITER );
score2 = start_contest( kSetAndTest, max, NUM_ITER );
printk( "Min %d (score %d), Max %d (score %d)\n", min, score, max, score2 );
score = abs( score );
score2 = abs( score2 );
offset = (score < score2) ? min : max;
/* guard against inaccurate mttb */
for( i=0; i<10; i++ ) {
start_contest( kSetAndTest, offset, NUM_ITER/10 );
if( (score2=start_contest(kTest, offset, NUM_ITER)) < 0 )
score2 = -score2;
if( score2 <= score || score2 < 20 )
break;
}
printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
/* exiting */
tbsync->cmd = kExit;
wmb();
tbsync->handshake = 1;
while( tbsync->ack )
;
tbsync->handshake = 0;
kfree( tbsync );
tbsync = NULL;
running = 0;
/* all done */
smp_tb_synchronized = 1;
}
...@@ -61,10 +61,6 @@ static struct smp_ops_t *smp_ops; ...@@ -61,10 +61,6 @@ static struct smp_ops_t *smp_ops;
/* all cpu mappings are 1-1 -- Cort */ /* all cpu mappings are 1-1 -- Cort */
volatile unsigned long cpu_callin_map[NR_CPUS]; volatile unsigned long cpu_callin_map[NR_CPUS];
#define TB_SYNC_PASSES 4
volatile unsigned long __initdata tb_sync_flag = 0;
volatile unsigned long __initdata tb_offset = 0;
int start_secondary(void *); int start_secondary(void *);
extern int cpu_idle(void *unused); extern int cpu_idle(void *unused);
void smp_call_function_interrupt(void); void smp_call_function_interrupt(void);
...@@ -83,11 +79,14 @@ extern void __save_cpu_setup(void); ...@@ -83,11 +79,14 @@ extern void __save_cpu_setup(void);
#define PPC_MSG_INVALIDATE_TLB 2 #define PPC_MSG_INVALIDATE_TLB 2
#define PPC_MSG_XMON_BREAK 3 #define PPC_MSG_XMON_BREAK 3
#define smp_message_pass(t,m,d,w) \ static inline void
do { if (smp_ops) \ smp_message_pass(int target, int msg, unsigned long data, int wait)
atomic_inc(&ipi_sent); \ {
smp_ops->message_pass((t),(m),(d),(w)); \ if (smp_ops){
} while(0) atomic_inc(&ipi_sent);
smp_ops->message_pass(target,msg,data,wait);
}
}
/* /*
* Common functions * Common functions
...@@ -291,41 +290,6 @@ void smp_call_function_interrupt(void) ...@@ -291,41 +290,6 @@ void smp_call_function_interrupt(void)
atomic_inc(&call_data->finished); atomic_inc(&call_data->finished);
} }
/* FIXME: Do this properly for all archs --RR */
static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
static unsigned int timebase_upper = 0, timebase_lower = 0;
void __devinit
smp_generic_give_timebase(void)
{
spin_lock(&timebase_lock);
do {
timebase_upper = get_tbu();
timebase_lower = get_tbl();
} while (timebase_upper != get_tbu());
spin_unlock(&timebase_lock);
while (timebase_upper || timebase_lower)
rmb();
}
void __devinit
smp_generic_take_timebase(void)
{
int done = 0;
while (!done) {
spin_lock(&timebase_lock);
if (timebase_upper || timebase_lower) {
set_tb(timebase_upper, timebase_lower);
timebase_upper = 0;
timebase_lower = 0;
done = 1;
}
spin_unlock(&timebase_lock);
}
}
static void __devinit smp_store_cpu_info(int id) static void __devinit smp_store_cpu_info(int id)
{ {
struct cpuinfo_PPC *c = &cpu_data[id]; struct cpuinfo_PPC *c = &cpu_data[id];
......
...@@ -36,6 +36,32 @@ ...@@ -36,6 +36,32 @@
.comm mmu_hash_lock,4 .comm mmu_hash_lock,4
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/*
* Sync CPUs with hash_page taking & releasing the hash
* table lock
*/
#ifdef CONFIG_SMP
.text
_GLOBAL(hash_page_sync)
lis r8,mmu_hash_lock@h
ori r8,r8,mmu_hash_lock@l
lis r0,0x0fff
b 10f
11: lwz r6,0(r8)
cmpwi 0,r6,0
bne 11b
10: lwarx r6,0,r8
cmpwi 0,r6,0
bne- 11b
stwcx. r0,0,r8
bne- 10b
isync
eieio
li r0,0
stw r0,0(r8)
blr
#endif
/* /*
* Load a PTE into the hash table, if possible. * Load a PTE into the hash table, if possible.
* The address is in r4, and r3 contains an access flag: * The address is in r4, and r3 contains an access flag:
...@@ -417,21 +443,6 @@ _GLOBAL(hash_page_patch_C) ...@@ -417,21 +443,6 @@ _GLOBAL(hash_page_patch_C)
lwz r6,next_slot@l(r4) lwz r6,next_slot@l(r4)
addi r6,r6,PTE_SIZE addi r6,r6,PTE_SIZE
andi. r6,r6,7*PTE_SIZE andi. r6,r6,7*PTE_SIZE
#ifdef CONFIG_POWER4
/*
* Since we don't have BATs on POWER4, we rely on always having
* PTEs in the hash table to map the hash table and the code
* that manipulates it in virtual mode, namely flush_hash_page and
* flush_hash_segments. Otherwise we can get a DSI inside those
* routines which leads to a deadlock on the hash_table_lock on
* SMP machines. We avoid this by never overwriting the first
* PTE of each PTEG if it is already valid.
* -- paulus.
*/
bne 102f
li r6,PTE_SIZE
102:
#endif /* CONFIG_POWER4 */
stw r6,next_slot@l(r4) stw r6,next_slot@l(r4)
add r4,r3,r6 add r4,r3,r6
......
...@@ -291,6 +291,8 @@ void __init MMU_init(void) ...@@ -291,6 +291,8 @@ void __init MMU_init(void)
ppc_md.progress("MMU:exit", 0x211); ppc_md.progress("MMU:exit", 0x211);
#ifdef CONFIG_BOOTX_TEXT #ifdef CONFIG_BOOTX_TEXT
/* By default, we are no longer mapped */
boot_text_mapped = 0;
/* Must be done last, or ppc_md.progress will die. */ /* Must be done last, or ppc_md.progress will die. */
map_boot_text(); map_boot_text();
#endif #endif
......
...@@ -44,6 +44,10 @@ int io_bat_index; ...@@ -44,6 +44,10 @@ int io_bat_index;
extern char etext[], _stext[]; extern char etext[], _stext[];
#ifdef CONFIG_SMP
extern void hash_page_sync(void);
#endif
#ifdef HAVE_BATS #ifdef HAVE_BATS
extern unsigned long v_mapped_by_bats(unsigned long va); extern unsigned long v_mapped_by_bats(unsigned long va);
extern unsigned long p_mapped_by_bats(unsigned long pa); extern unsigned long p_mapped_by_bats(unsigned long pa);
...@@ -109,11 +113,17 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) ...@@ -109,11 +113,17 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
void pte_free_kernel(pte_t *pte) void pte_free_kernel(pte_t *pte)
{ {
#ifdef CONFIG_SMP
hash_page_sync();
#endif
free_page((unsigned long)pte); free_page((unsigned long)pte);
} }
void pte_free(struct page *pte) void pte_free(struct page *pte)
{ {
#ifdef CONFIG_SMP
hash_page_sync();
#endif
__free_page(pte); __free_page(pte);
} }
......
...@@ -83,6 +83,9 @@ unsigned long p_mapped_by_bats(unsigned long pa) ...@@ -83,6 +83,9 @@ unsigned long p_mapped_by_bats(unsigned long pa)
unsigned long __init mmu_mapin_ram(void) unsigned long __init mmu_mapin_ram(void)
{ {
#ifdef CONFIG_POWER4
return 0;
#else
unsigned long tot, bl, done; unsigned long tot, bl, done;
unsigned long max_size = (256<<20); unsigned long max_size = (256<<20);
unsigned long align; unsigned long align;
...@@ -119,6 +122,7 @@ unsigned long __init mmu_mapin_ram(void) ...@@ -119,6 +122,7 @@ unsigned long __init mmu_mapin_ram(void)
} }
return done; return done;
#endif
} }
/* /*
...@@ -244,9 +248,10 @@ void __init MMU_init_hw(void) ...@@ -244,9 +248,10 @@ void __init MMU_init_hw(void)
Hash = mem_pieces_find(Hash_size, Hash_size); Hash = mem_pieces_find(Hash_size, Hash_size);
cacheable_memzero(Hash, Hash_size); cacheable_memzero(Hash, Hash_size);
_SDR1 = __pa(Hash) | SDR1_LOW_BITS; _SDR1 = __pa(Hash) | SDR1_LOW_BITS;
Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
#endif /* CONFIG_POWER4 */ #endif /* CONFIG_POWER4 */
Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n", printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
total_memory >> 20, Hash_size >> 10, Hash); total_memory >> 20, Hash_size >> 10, Hash);
......
...@@ -46,6 +46,26 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr) ...@@ -46,6 +46,26 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
} }
} }
/*
* Called by ptep_test_and_clear_young()
*/
void flush_hash_one_pte(pte_t *ptep)
{
struct page *ptepage;
struct mm_struct *mm;
unsigned long ptephys;
unsigned long addr;
if (Hash == 0)
return;
ptepage = virt_to_page(ptep);
mm = (struct mm_struct *) ptepage->mapping;
ptephys = __pa(ptep) & PAGE_MASK;
addr = ptepage->index + (((unsigned long)ptep & ~PAGE_MASK) << 9);
flush_hash_pages(mm->context, addr, ptephys, 1);
}
/* /*
* Called at the end of a mmu_gather operation to make sure the * Called at the end of a mmu_gather operation to make sure the
* TLB flush is completely done. * TLB flush is completely done.
......
...@@ -17,7 +17,8 @@ ifeq ($(CONFIG_APUS),y) ...@@ -17,7 +17,8 @@ ifeq ($(CONFIG_APUS),y)
obj-$(CONFIG_PCI) += apus_pci.o obj-$(CONFIG_PCI) += apus_pci.o
endif endif
obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \
pmac_feature.o pmac_pci.o pmac_sleep.o pmac_feature.o pmac_pci.o pmac_sleep.o \
pmac_low_i2c.o
obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o
obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_time.o prep_setup.o obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_time.o prep_setup.o
ifeq ($(CONFIG_PPC_PMAC),y) ifeq ($(CONFIG_PPC_PMAC),y)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/nvram.h> #include <linux/nvram.h>
...@@ -37,6 +38,10 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c ...@@ -37,6 +38,10 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c
char *prop; char *prop;
int valid = 0; int valid = 0;
/* There's already a matching controller, bail out */
if (backlighter != NULL)
return;
bk_node = find_devices("backlight"); bk_node = find_devices("backlight");
#ifdef CONFIG_ADB_PMU #ifdef CONFIG_ADB_PMU
...@@ -84,6 +89,7 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c ...@@ -84,6 +89,7 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c
printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n", printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
type, backlight_level); type, backlight_level);
} }
EXPORT_SYMBOL(register_backlight_controller);
void __pmac void __pmac
unregister_backlight_controller(struct backlight_controller *ctrler, void *data) unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
...@@ -92,6 +98,7 @@ unregister_backlight_controller(struct backlight_controller *ctrler, void *data) ...@@ -92,6 +98,7 @@ unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
if (ctrler == backlighter && data == backlighter_data) if (ctrler == backlighter && data == backlighter_data)
backlighter = NULL; backlighter = NULL;
} }
EXPORT_SYMBOL(unregister_backlight_controller);
int __pmac int __pmac
set_backlight_enable(int enable) set_backlight_enable(int enable)
...@@ -105,6 +112,7 @@ set_backlight_enable(int enable) ...@@ -105,6 +112,7 @@ set_backlight_enable(int enable)
backlight_enabled = enable; backlight_enabled = enable;
return rc; return rc;
} }
EXPORT_SYMBOL(set_backlight_enable);
int __pmac int __pmac
get_backlight_enable(void) get_backlight_enable(void)
...@@ -113,6 +121,7 @@ get_backlight_enable(void) ...@@ -113,6 +121,7 @@ get_backlight_enable(void)
return -ENODEV; return -ENODEV;
return backlight_enabled; return backlight_enabled;
} }
EXPORT_SYMBOL(get_backlight_enable);
int __pmac int __pmac
set_backlight_level(int level) set_backlight_level(int level)
...@@ -137,6 +146,7 @@ set_backlight_level(int level) ...@@ -137,6 +146,7 @@ set_backlight_level(int level)
} }
return rc; return rc;
} }
EXPORT_SYMBOL(set_backlight_level);
int __pmac int __pmac
get_backlight_level(void) get_backlight_level(void)
...@@ -145,3 +155,4 @@ get_backlight_level(void) ...@@ -145,3 +155,4 @@ get_backlight_level(void)
return -ENODEV; return -ENODEV;
return backlight_level; return backlight_level;
} }
EXPORT_SYMBOL(get_backlight_level);
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sysdev.h> #include <linux/sysdev.h>
#include <linux/i2c.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -38,6 +39,14 @@ ...@@ -38,6 +39,14 @@
*/ */
#undef DEBUG_FREQ #undef DEBUG_FREQ
/*
* There is a problem with the core cpufreq code on SMP kernels,
* it won't recalculate the Bogomips properly
*/
#ifdef CONFIG_SMP
#warning "WARNING, CPUFREQ not recommended on SMP kernels"
#endif
extern void low_choose_750fx_pll(int pll); extern void low_choose_750fx_pll(int pll);
extern void low_sleep_handler(void); extern void low_sleep_handler(void);
extern void openpic_suspend(struct sys_device *sysdev, u32 state); extern void openpic_suspend(struct sys_device *sysdev, u32 state);
...@@ -48,7 +57,14 @@ extern void enable_kernel_fp(void); ...@@ -48,7 +57,14 @@ extern void enable_kernel_fp(void);
static unsigned int low_freq; static unsigned int low_freq;
static unsigned int hi_freq; static unsigned int hi_freq;
static unsigned int cur_freq; static unsigned int cur_freq;
/* Clean that up some day ... use a func ptr or at least an enum... */
static int cpufreq_uses_pmu; static int cpufreq_uses_pmu;
static int cpufreq_uses_gpios;
static u32 voltage_gpio;
static u32 frequency_gpio;
static u32 slew_done_gpio;
#define PMAC_CPU_LOW_SPEED 1 #define PMAC_CPU_LOW_SPEED 1
#define PMAC_CPU_HIGH_SPEED 0 #define PMAC_CPU_HIGH_SPEED 0
...@@ -65,8 +81,7 @@ static struct cpufreq_frequency_table pmac_cpu_freqs[] = { ...@@ -65,8 +81,7 @@ static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
{0, CPUFREQ_TABLE_END}, {0, CPUFREQ_TABLE_END},
}; };
static inline void static inline void wakeup_decrementer(void)
wakeup_decrementer(void)
{ {
set_dec(tb_ticks_per_jiffy); set_dec(tb_ticks_per_jiffy);
/* No currently-supported powerbook has a 601, /* No currently-supported powerbook has a 601,
...@@ -76,8 +91,7 @@ wakeup_decrementer(void) ...@@ -76,8 +91,7 @@ wakeup_decrementer(void)
} }
#ifdef DEBUG_FREQ #ifdef DEBUG_FREQ
static inline void static inline void debug_calc_bogomips(void)
debug_calc_bogomips(void)
{ {
/* This will cause a recalc of bogomips and display the /* This will cause a recalc of bogomips and display the
* result. We backup/restore the value to avoid affecting the * result. We backup/restore the value to avoid affecting the
...@@ -89,17 +103,18 @@ debug_calc_bogomips(void) ...@@ -89,17 +103,18 @@ debug_calc_bogomips(void)
calibrate_delay(); calibrate_delay();
loops_per_jiffy = save_lpj; loops_per_jiffy = save_lpj;
} }
#endif #endif /* DEBUG_FREQ */
/* Switch CPU speed under 750FX CPU control /* Switch CPU speed under 750FX CPU control
*/ */
static int __pmac static int __pmac cpu_750fx_cpu_speed(int low_speed)
cpu_750fx_cpu_speed(int low_speed)
{ {
#ifdef DEBUG_FREQ #ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
#endif #endif
#ifdef CONFIG_6xx
low_choose_750fx_pll(low_speed); low_choose_750fx_pll(low_speed);
#endif
#ifdef DEBUG_FREQ #ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
debug_calc_bogomips(); debug_calc_bogomips();
...@@ -108,15 +123,54 @@ cpu_750fx_cpu_speed(int low_speed) ...@@ -108,15 +123,54 @@ cpu_750fx_cpu_speed(int low_speed)
return 0; return 0;
} }
/* Switch CPU speed using slewing GPIOs
*/
static int __pmac gpios_set_cpu_speed(unsigned int low_speed)
{
int gpio;
/* If ramping up, set voltage first */
if (low_speed == 0) {
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
/* Delay is way too big but it's ok, we schedule */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
}
/* Set frequency */
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, low_speed ? 0x04 : 0x05);
udelay(200);
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);
} while((gpio & 0x02) == 0);
/* If ramping down, set voltage last */
if (low_speed == 1) {
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
/* Delay is way too big but it's ok, we schedule */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/100);
}
#ifdef DEBUG_FREQ
debug_calc_bogomips();
#endif
return 0;
}
/* Switch CPU speed under PMU control /* Switch CPU speed under PMU control
*/ */
static int __pmac static int __pmac pmu_set_cpu_speed(unsigned int low_speed)
pmu_set_cpu_speed(unsigned int low_speed)
{ {
struct adb_request req; struct adb_request req;
unsigned long save_l2cr; unsigned long save_l2cr;
unsigned long save_l3cr; unsigned long save_l3cr;
preempt_disable();
#ifdef DEBUG_FREQ #ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
#endif #endif
...@@ -197,11 +251,12 @@ pmu_set_cpu_speed(unsigned int low_speed) ...@@ -197,11 +251,12 @@ pmu_set_cpu_speed(unsigned int low_speed)
debug_calc_bogomips(); debug_calc_bogomips();
#endif #endif
preempt_enable();
return 0; return 0;
} }
static int __pmac static int __pmac do_set_cpu_speed(int speed_mode)
do_set_cpu_speed(int speed_mode)
{ {
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
int rc; int rc;
...@@ -216,6 +271,8 @@ do_set_cpu_speed(int speed_mode) ...@@ -216,6 +271,8 @@ do_set_cpu_speed(int speed_mode)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (cpufreq_uses_pmu) if (cpufreq_uses_pmu)
rc = pmu_set_cpu_speed(speed_mode); rc = pmu_set_cpu_speed(speed_mode);
else if (cpufreq_uses_gpios)
rc = gpios_set_cpu_speed(speed_mode);
else else
rc = cpu_750fx_cpu_speed(speed_mode); rc = cpu_750fx_cpu_speed(speed_mode);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
...@@ -224,16 +281,14 @@ do_set_cpu_speed(int speed_mode) ...@@ -224,16 +281,14 @@ do_set_cpu_speed(int speed_mode)
return rc; return rc;
} }
static int __pmac static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy)
pmac_cpufreq_verify(struct cpufreq_policy *policy)
{ {
return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs); return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
} }
static int __pmac static int __pmac pmac_cpufreq_target( struct cpufreq_policy *policy,
pmac_cpufreq_target( struct cpufreq_policy *policy, unsigned int target_freq,
unsigned int target_freq, unsigned int relation)
unsigned int relation)
{ {
unsigned int newstate = 0; unsigned int newstate = 0;
...@@ -244,15 +299,13 @@ pmac_cpufreq_target( struct cpufreq_policy *policy, ...@@ -244,15 +299,13 @@ pmac_cpufreq_target( struct cpufreq_policy *policy,
return do_set_cpu_speed(newstate); return do_set_cpu_speed(newstate);
} }
unsigned int __pmac unsigned int __pmac pmac_get_one_cpufreq(int i)
pmac_get_one_cpufreq(int i)
{ {
/* Supports only one CPU for now */ /* Supports only one CPU for now */
return (i == 0) ? cur_freq : 0; return (i == 0) ? cur_freq : 0;
} }
static int __pmac static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
{ {
if (policy->cpu != 0) if (policy->cpu != 0)
return -ENODEV; return -ENODEV;
...@@ -264,6 +317,18 @@ pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -264,6 +317,18 @@ pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]); return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]);
} }
static u32 __pmac read_gpio(struct device_node *np)
{
u32 *reg = (u32 *)get_property(np, "reg", NULL);
if (reg == NULL)
return 0;
/* That works for all keylargos but shall be fixed properly
* some day...
*/
return 0x50 + (*reg);
}
static struct cpufreq_driver pmac_cpufreq_driver = { static struct cpufreq_driver pmac_cpufreq_driver = {
.verify = pmac_cpufreq_verify, .verify = pmac_cpufreq_verify,
.target = pmac_cpufreq_target, .target = pmac_cpufreq_target,
...@@ -272,15 +337,17 @@ static struct cpufreq_driver pmac_cpufreq_driver = { ...@@ -272,15 +337,17 @@ static struct cpufreq_driver pmac_cpufreq_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
/* Currently, we support the following machines: /* Currently, we support the following machines:
* *
* - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz)
* - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz)
* - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz)
* - iBook2 500 (PMU based, 400Mhz & 500Mhz) * - iBook2 500 (PMU based, 400Mhz & 500Mhz)
* - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
* - Recent MacRISC3 machines
*/ */
static int __init static int __init pmac_cpufreq_setup(void)
pmac_cpufreq_setup(void)
{ {
struct device_node *cpunode; struct device_node *cpunode;
u32 *value; u32 *value;
...@@ -304,6 +371,74 @@ pmac_cpufreq_setup(void) ...@@ -304,6 +371,74 @@ pmac_cpufreq_setup(void)
if (machine_is_compatible("PowerBook3,4") || if (machine_is_compatible("PowerBook3,4") ||
machine_is_compatible("PowerBook3,5") || machine_is_compatible("PowerBook3,5") ||
machine_is_compatible("MacRISC3")) { machine_is_compatible("MacRISC3")) {
struct device_node *volt_gpio_np = of_find_node_by_name(NULL, "voltage-gpio");
struct device_node *freq_gpio_np = of_find_node_by_name(NULL, "frequency-gpio");
struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, "slewing-done");
/*
* Check to see if it's GPIO driven or PMU only
*
* The way we extract the GPIO address is slightly hackish, but it
* works well enough for now. We need to abstract the whole GPIO
* stuff sooner or later anyway
*/
if (volt_gpio_np)
voltage_gpio = read_gpio(volt_gpio_np);
if (freq_gpio_np)
frequency_gpio = read_gpio(freq_gpio_np);
if (slew_done_gpio_np)
slew_done_gpio = read_gpio(slew_done_gpio_np);
/* If we use the frequency GPIOs, calculate the min/max speeds based
* on the bus frequencies
*/
if (frequency_gpio && slew_done_gpio) {
int lenp, rc;
u32 *freqs, *ratio;
freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp);
lenp /= sizeof(u32);
if (freqs == NULL || lenp != 2) {
printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
goto out;
}
ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL);
if (ratio == NULL) {
printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
goto out;
}
/* Get the min/max bus frequencies */
low_freq = min(freqs[0], freqs[1]);
hi_freq = max(freqs[0], freqs[1]);
/* Grrrr.. It _seems_ that the device-tree is lying on the low bus
* frequency, it claims it to be around 84Mhz on some models while
* it appears to be approx. 101Mhz on all. Let's hack around here...
* fortunately, we don't need to be too precise
*/
if (low_freq < 98000000)
low_freq = 101000000;
/* Convert those to CPU core clocks */
low_freq = (low_freq * (*ratio)) / 2000;
hi_freq = (hi_freq * (*ratio)) / 2000;
/* Now we get the frequencies, we read the GPIO to see what is out current
* speed
*/
rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
cur_freq = (rc & 0x01) ? hi_freq : low_freq;
has_freq_ctl = 1;
cpufreq_uses_gpios = 1;
goto out;
}
/* If we use the PMU, look for the min & max frequencies in the
* device-tree
*/
value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL);
if (!value) if (!value)
goto out; goto out;
...@@ -359,6 +494,11 @@ pmac_cpufreq_setup(void) ...@@ -359,6 +494,11 @@ pmac_cpufreq_setup(void)
pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz, switch method: %s\n",
low_freq/1000, hi_freq/1000, cur_freq/1000,
cpufreq_uses_pmu ? "PMU" : (cpufreq_uses_gpios ? "GPIOs" : "CPU"));
return cpufreq_register_driver(&pmac_cpufreq_driver); return cpufreq_register_driver(&pmac_cpufreq_driver);
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <asm/time.h> #include <asm/time.h>
#include <asm/open_pic.h> #include <asm/open_pic.h>
#include <asm/xmon.h> #include <asm/xmon.h>
#include <asm/pmac_feature.h>
#include "pmac_pic.h" #include "pmac_pic.h"
...@@ -363,32 +364,76 @@ static int __init enable_second_ohare(void) ...@@ -363,32 +364,76 @@ static int __init enable_second_ohare(void)
return irqctrler->intrs[0].line; return irqctrler->intrs[0].line;
} }
void __init #ifdef CONFIG_POWER4
pmac_pic_init(void) static irqreturn_t k2u3_action(int cpl, void *dev_id, struct pt_regs *regs)
{
int irq;
irq = openpic2_get_irq(regs);
if (irq != -1)
ppc_irq_dispatch_handler(regs, irq);
return IRQ_HANDLED;
}
#endif /* CONFIG_POWER4 */
void __init pmac_pic_init(void)
{ {
int i; int i;
struct device_node *irqctrler; struct device_node *irqctrler = NULL;
struct device_node *irqctrler2 = NULL;
struct device_node *np;
unsigned long addr; unsigned long addr;
int irq_cascade = -1; int irq_cascade = -1;
/* We first try to detect Apple's new Core99 chipset, since mac-io /* We first try to detect Apple's new Core99 chipset, since mac-io
* is quite different on those machines and contains an IBM MPIC2. * is quite different on those machines and contains an IBM MPIC2.
*/ */
irqctrler = find_type_devices("open-pic"); np = find_type_devices("open-pic");
while(np) {
if (np->parent && !strcmp(np->parent->name, "u3"))
irqctrler2 = np;
else
irqctrler = np;
np = np->next;
}
if (irqctrler != NULL) if (irqctrler != NULL)
{ {
printk("PowerMac using OpenPIC irq controller\n");
if (irqctrler->n_addrs > 0) if (irqctrler->n_addrs > 0)
{ {
unsigned char senses[NR_IRQS]; unsigned char senses[128];
printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
irqctrler->addrs[0].address);
prom_get_irq_senses(senses, 0, NR_IRQS); prom_get_irq_senses(senses, 0, 128);
OpenPIC_InitSenses = senses; OpenPIC_InitSenses = senses;
OpenPIC_NumInitSenses = NR_IRQS; OpenPIC_NumInitSenses = 128;
ppc_md.get_irq = openpic_get_irq; ppc_md.get_irq = openpic_get_irq;
pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
OpenPIC_Addr = ioremap(irqctrler->addrs[0].address, OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
irqctrler->addrs[0].size); irqctrler->addrs[0].size);
openpic_init(0); openpic_init(0);
#ifdef CONFIG_POWER4
if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
irqctrler2->n_addrs > 0) {
printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
irqctrler2->addrs[0].address,
irqctrler2->intrs[0].line);
pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address,
irqctrler2->addrs[0].size);
prom_get_irq_senses(senses, PMAC_OPENPIC2_OFFSET,
PMAC_OPENPIC2_OFFSET+128);
OpenPIC_InitSenses = senses;
OpenPIC_NumInitSenses = 128;
openpic2_init(PMAC_OPENPIC2_OFFSET);
if (request_irq(irqctrler2->intrs[0].line, k2u3_action, 0,
"U3->K2 Cascade", NULL))
printk("Unable to get OpenPIC IRQ for cascade\n");
}
#endif /* CONFIG_POWER4 */
#ifdef CONFIG_XMON #ifdef CONFIG_XMON
{ {
struct device_node* pswitch; struct device_node* pswitch;
......
...@@ -332,7 +332,7 @@ pmac_setup_arch(void) ...@@ -332,7 +332,7 @@ pmac_setup_arch(void)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* Check for Core99 */ /* Check for Core99 */
if (find_devices("uni-n")) if (find_devices("uni-n") || find_devices("u3"))
ppc_md.smp_ops = &core99_smp_ops; ppc_md.smp_ops = &core99_smp_ops;
else else
ppc_md.smp_ops = &psurge_smp_ops; ppc_md.smp_ops = &psurge_smp_ops;
...@@ -469,10 +469,6 @@ pmac_restart(char *cmd) ...@@ -469,10 +469,6 @@ pmac_restart(char *cmd)
struct adb_request req; struct adb_request req;
#endif /* CONFIG_ADB_CUDA */ #endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_NVRAM
pmac_nvram_update();
#endif
switch (sys_ctrler) { switch (sys_ctrler) {
#ifdef CONFIG_ADB_CUDA #ifdef CONFIG_ADB_CUDA
case SYS_CTRLER_CUDA: case SYS_CTRLER_CUDA:
...@@ -498,10 +494,6 @@ pmac_power_off(void) ...@@ -498,10 +494,6 @@ pmac_power_off(void)
struct adb_request req; struct adb_request req;
#endif /* CONFIG_ADB_CUDA */ #endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_NVRAM
pmac_nvram_update();
#endif
switch (sys_ctrler) { switch (sys_ctrler) {
#ifdef CONFIG_ADB_CUDA #ifdef CONFIG_ADB_CUDA
case SYS_CTRLER_CUDA: case SYS_CTRLER_CUDA:
...@@ -637,11 +629,6 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ...@@ -637,11 +629,6 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.get_rtc_time = pmac_get_rtc_time;
ppc_md.calibrate_decr = pmac_calibrate_decr; ppc_md.calibrate_decr = pmac_calibrate_decr;
#ifdef CONFIG_NVRAM
ppc_md.nvram_read_val = pmac_nvram_read_byte;
ppc_md.nvram_write_val = pmac_nvram_write_byte;
#endif
ppc_md.find_end_of_memory = pmac_find_end_of_memory; ppc_md.find_end_of_memory = pmac_find_end_of_memory;
ppc_md.feature_call = pmac_do_feature_call; ppc_md.feature_call = pmac_do_feature_call;
...@@ -685,6 +672,14 @@ pmac_declare_of_platform_devices(void) ...@@ -685,6 +672,14 @@ pmac_declare_of_platform_devices(void)
break; break;
} }
} }
np = find_devices("u3");
if (np) {
for (np = np->child; np != NULL; np = np->sibling)
if (strncmp(np->name, "i2c", 3) == 0) {
of_platform_device_create(np, "u3-i2c");
break;
}
}
np = find_devices("valkyrie"); np = find_devices("valkyrie");
if (np) if (np)
......
This diff is collapsed.
...@@ -266,6 +266,14 @@ pmac_calibrate_decr(void) ...@@ -266,6 +266,14 @@ pmac_calibrate_decr(void)
if (via_calibrate_decr()) if (via_calibrate_decr())
return; return;
/* Special case: QuickSilver G4s seem to have a badly calibrated
* timebase-frequency in OF, VIA is much better on these. We should
* probably implement calibration based on the KL timer on these
* machines anyway... -BenH
*/
if (machine_is_compatible("PowerMac3,5"))
if (via_calibrate_decr())
return;
/* /*
* The cpu node should have a timebase-frequency property * The cpu node should have a timebase-frequency property
* to tell us the rate at which the decrementer counts. * to tell us the rate at which the decrementer counts.
......
...@@ -31,6 +31,7 @@ obj-$(CONFIG_PCI) += qspan_pci.o i8259.o ...@@ -31,6 +31,7 @@ obj-$(CONFIG_PCI) += qspan_pci.o i8259.o
endif endif
obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o
obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o
obj-$(CONFIG_POWER4) += open_pic2.o
obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o
obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o
obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \ obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \
......
...@@ -183,6 +183,7 @@ void of_release_dev(struct device *dev) ...@@ -183,6 +183,7 @@ void of_release_dev(struct device *dev)
struct of_device *ofdev; struct of_device *ofdev;
ofdev = to_of_device(dev); ofdev = to_of_device(dev);
of_node_put(ofdev->node);
kfree(ofdev); kfree(ofdev);
} }
...@@ -242,7 +243,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char * ...@@ -242,7 +243,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char *
return NULL; return NULL;
memset(dev, 0, sizeof(*dev)); memset(dev, 0, sizeof(*dev));
dev->node = np; dev->node = of_node_get(np);
dev->dma_mask = 0xffffffffUL; dev->dma_mask = 0xffffffffUL;
dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_mask = &dev->dma_mask;
dev->dev.parent = NULL; dev->dev.parent = NULL;
......
...@@ -610,12 +610,15 @@ void openpic_request_IPIs(void) ...@@ -610,12 +610,15 @@ void openpic_request_IPIs(void)
void __devinit do_openpic_setup_cpu(void) void __devinit do_openpic_setup_cpu(void)
{ {
#ifdef CONFIG_IRQ_ALL_CPUS
int i; int i;
u32 msk = 1 << smp_hw_index[smp_processor_id()]; u32 msk;
#endif
spin_lock(&openpic_setup_lock); spin_lock(&openpic_setup_lock);
#ifdef CONFIG_IRQ_ALL_CPUS #ifdef CONFIG_IRQ_ALL_CPUS
msk = 1 << smp_hw_index[smp_processor_id()];
/* let the openpic know we want intrs. default affinity /* let the openpic know we want intrs. default affinity
* is 0xffffffff until changed via /proc * is 0xffffffff until changed via /proc
* That's how it's done on x86. If we want it differently, then * That's how it's done on x86. If we want it differently, then
...@@ -788,15 +791,25 @@ static void openpic_set_sense(u_int irq, int sense) ...@@ -788,15 +791,25 @@ static void openpic_set_sense(u_int irq, int sense)
*/ */
static void openpic_ack_irq(unsigned int irq_nr) static void openpic_ack_irq(unsigned int irq_nr)
{ {
#ifdef __SLOW_VERSION__
openpic_disable_irq(irq_nr); openpic_disable_irq(irq_nr);
openpic_eoi(); openpic_eoi();
#else
if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
openpic_eoi();
#endif
} }
static void openpic_end_irq(unsigned int irq_nr) static void openpic_end_irq(unsigned int irq_nr)
{ {
#ifdef __SLOW_VERSION__
if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
&& irq_desc[irq_nr].action) && irq_desc[irq_nr].action)
openpic_enable_irq(irq_nr); openpic_enable_irq(irq_nr);
#else
if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
openpic_eoi();
#endif
} }
static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask) static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment