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

Merge PPC update

parents 12a981f8 4d41d245
......@@ -30,6 +30,10 @@ config PPC32
bool
default y
# All PPCs use generic nvram driver through ppc_md
config GENERIC_NVRAM
bool
default y
source "init/Kconfig"
......@@ -989,8 +993,6 @@ config HOTPLUG
source "drivers/pcmcia/Kconfig"
source "drivers/parport/Kconfig"
endmenu
menu "Advanced setup"
......@@ -1088,179 +1090,10 @@ config PIN_TLB
depends on ADVANCED_OPTIONS && 8xx
endmenu
source "drivers/base/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 "drivers/Kconfig"
source "fs/Kconfig"
source "sound/Kconfig"
source "arch/ppc/8xx_io/Kconfig"
source "arch/ppc/8260_io/Kconfig"
......@@ -1285,8 +1118,6 @@ config SERIAL_SICC_CONSOLE
endmenu
source "drivers/usb/Kconfig"
source "lib/Kconfig"
......
......@@ -22,11 +22,12 @@ obj-y := entry.o traps.o irq.o idle.o time.o misc.o \
semaphore.o syscalls.o setup.o \
cputable.o ppc_htab.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_PCI) += pci.o
obj-$(CONFIG_PCI) += pci-dma.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
ifdef CONFIG_MATH_EMULATION
......
......@@ -248,12 +248,13 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
/* Definitions for the table use to save CPU states */
#define CS_HID0 0
#define CS_HID1 4
#define CS_MSSCR0 8
#define CS_MSSSR0 12
#define CS_ICTRL 16
#define CS_LDSTCR 20
#define CS_LDSTDB 24
#define CS_SIZE 28
#define CS_HID2 8
#define CS_MSSCR0 12
#define CS_MSSSR0 16
#define CS_ICTRL 20
#define CS_LDSTCR 24
#define CS_LDSTDB 28
#define CS_SIZE 32
.data
.balign L1_CACHE_LINE_SIZE
......@@ -316,6 +317,13 @@ _GLOBAL(__save_cpu_setup)
/* Backup 750FX specific registers */
mfspr r4,SPRN_HID1
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:
mtcr r7
blr
......@@ -395,9 +403,19 @@ _GLOBAL(__restore_cpu_setup)
sync
2: bne cr5,1f
/* Restore 750FX specific registers
* that is restore PLL config & switch
* to PLL 0
* that is restore HID2 on rev 2.x and PLL config & switch
* 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)
rlwinm r5,r4,0,16,14
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:
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
......@@ -159,6 +148,14 @@ __start:
*/
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
/* On APUS the __va/__pa constants need to be set to the correct
* values before continuing.
......@@ -1278,26 +1275,15 @@ __secondary_start:
*/
_GLOBAL(__setup_cpu_power3)
blr
_GLOBAL(__setup_cpu_power4)
blr
_GLOBAL(__setup_cpu_ppc970)
blr
_GLOBAL(__setup_cpu_generic)
blr
#ifndef CONFIG_6xx
#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4)
_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 */
#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */
/*
......@@ -1633,10 +1619,14 @@ initial_mm_power4:
lis r4,0x2000 /* set pseudo-segment reg 12 */
ori r5,r4,0x0ccc
mtsr 12,r5
#if 0
ori r5,r4,0x0888 /* set pseudo-segment reg 8 */
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) */
#endif
mfmsr r0
clrldi r0,r0,1
sync
......@@ -1644,41 +1634,6 @@ initial_mm_power4:
isync
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 */
#ifdef CONFIG_8260
......
......@@ -28,17 +28,11 @@
/*
* 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
* So nothing for now. 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
/*
......@@ -48,10 +42,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
*/
.globl power4_idle
power4_idle:
/* Check if we can nap or doze, put HID0 mask in r3
*/
lis r3, 0
BEGIN_FTR_SECTION
blr
END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
/* We must dynamically check for the NAP feature as it
* can be cleared by CPU init after the fixups are done
*/
......@@ -59,16 +52,11 @@ BEGIN_FTR_SECTION
lwz r4,cur_cpu_spec@l(r4)
lwz r4,CPU_SPEC_FEATURES(r4)
andi. r0,r4,CPU_FTR_CAN_NAP
beq 1f
beqlr
/* 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 */
......@@ -85,18 +73,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
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
......
......@@ -201,7 +201,7 @@ _GLOBAL(call_setup_cpu)
mr r4,r24
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
* on 750fx CPU. This function should really be moved to some
......@@ -253,7 +253,7 @@ _GLOBAL(low_choose_750fx_pll)
mtmsr r7
blr
#endif /* CONFIG_CPU_FREQ_PMAC */
#endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */
/* void local_save_flags_ptr(unsigned long *flags) */
_GLOBAL(local_save_flags_ptr)
......
......@@ -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_cpc710_pci64(struct pci_dev* dev);
#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
#ifdef CONFIG_PPC_OF
static u8* pci_to_OF_bus_map;
......@@ -69,7 +71,9 @@ struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources },
#ifdef CONFIG_PPC_PMAC
/* 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 */
{ 0 }
};
......@@ -155,42 +159,6 @@ pcibios_fixup_resources(struct pci_dev *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
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)
return NULL;
/* 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)
busnr = pci_to_OF_bus_map[busnr];
if (busnr == 0xff)
......@@ -922,9 +901,10 @@ void __init
pci_process_bridge_OF_ranges(struct pci_controller *hose,
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;
int rlen = 0;
int rlen = 0, orig_rlen;
int memno = 0;
struct resource *res;
int np, na = prom_n_addr_cells(dev);
......@@ -934,7 +914,22 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
* that can have more than 3 ranges, fortunately using contiguous
* 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;
while ((rlen -= np * sizeof(unsigned int)) >= 0) {
if (prev) {
......@@ -959,10 +954,9 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
* (size depending on dev->n_addr_cells)
* cells 4+5 or 5+6: the size of the range
*/
rlen = 0;
hose->io_base_phys = 0;
ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
while ((rlen -= np * sizeof(unsigned int)) >= 0) {
ranges = lc_ranges;
rlen = orig_rlen;
while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
res = NULL;
size = ranges[na+4];
switch (ranges[0] >> 24) {
......@@ -1059,7 +1053,7 @@ do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
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.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
DBG(" IO window: %08lx-%08lx\n", res.start, res.end);
......@@ -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
*/
long
sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
long 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;
/* 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)
return -ENODEV;
......
......@@ -75,6 +75,7 @@ int abs(int);
extern unsigned long mm_ptov (unsigned long paddr);
EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(clear_user_page);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(do_syscall_trace);
EXPORT_SYMBOL(transfer_to_handler);
......@@ -236,12 +237,6 @@ EXPORT_SYMBOL(adb_try_handler_change);
EXPORT_SYMBOL(cuda_request);
EXPORT_SYMBOL(cuda_poll);
#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
EXPORT_SYMBOL(_machine);
#endif
......@@ -282,14 +277,6 @@ EXPORT_SYMBOL(note_scsi_host);
#ifdef CONFIG_VT
EXPORT_SYMBOL(kd_mksound);
#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(pm_power_off);
......
......@@ -35,6 +35,7 @@
#include <asm/system.h>
#include <asm/pmac_feature.h>
#include <asm/sections.h>
#include <asm/nvram.h>
#include <asm/xmon.h>
#if defined CONFIG_KGDB
......@@ -111,6 +112,9 @@ struct screen_info screen_info = {
void machine_restart(char *cmd)
{
#ifdef CONFIG_NVRAM
nvram_sync();
#endif
ppc_md.restart(cmd);
}
......@@ -118,6 +122,9 @@ EXPORT_SYMBOL(machine_restart);
void machine_power_off(void)
{
#ifdef CONFIG_NVRAM
nvram_sync();
#endif
ppc_md.power_off();
}
......@@ -125,6 +132,9 @@ EXPORT_SYMBOL(machine_power_off);
void machine_halt(void)
{
#ifdef CONFIG_NVRAM
nvram_sync();
#endif
ppc_md.halt();
}
......@@ -558,24 +568,30 @@ int __init ppc_setup_l2cr(char *str)
__setup("l2cr=", ppc_setup_l2cr);
#ifdef CONFIG_NVRAM
/* Generic nvram hooks we now look into ppc_md.nvram_read_val
* on pmac too ;)
* //XX Those 2 could be moved to headers
*/
unsigned char
nvram_read_byte(int addr)
/* Generic nvram hooks used by drivers/char/gen_nvram.c */
unsigned char nvram_read_byte(int addr)
{
if (ppc_md.nvram_read_val)
return ppc_md.nvram_read_val(addr);
return 0xff;
}
EXPORT_SYMBOL(nvram_read_byte);
void
nvram_write_byte(unsigned char val, int addr)
void nvram_write_byte(unsigned char val, int addr)
{
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 */
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;
/* all cpu mappings are 1-1 -- Cort */
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 *);
extern int cpu_idle(void *unused);
void smp_call_function_interrupt(void);
......@@ -83,11 +79,14 @@ extern void __save_cpu_setup(void);
#define PPC_MSG_INVALIDATE_TLB 2
#define PPC_MSG_XMON_BREAK 3
#define smp_message_pass(t,m,d,w) \
do { if (smp_ops) \
atomic_inc(&ipi_sent); \
smp_ops->message_pass((t),(m),(d),(w)); \
} while(0)
static inline void
smp_message_pass(int target, int msg, unsigned long data, int wait)
{
if (smp_ops){
atomic_inc(&ipi_sent);
smp_ops->message_pass(target,msg,data,wait);
}
}
/*
* Common functions
......@@ -291,41 +290,6 @@ void smp_call_function_interrupt(void)
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)
{
struct cpuinfo_PPC *c = &cpu_data[id];
......
......@@ -36,6 +36,32 @@
.comm mmu_hash_lock,4
#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.
* The address is in r4, and r3 contains an access flag:
......@@ -417,21 +443,6 @@ _GLOBAL(hash_page_patch_C)
lwz r6,next_slot@l(r4)
addi r6,r6,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)
add r4,r3,r6
......
......@@ -291,6 +291,8 @@ void __init MMU_init(void)
ppc_md.progress("MMU:exit", 0x211);
#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. */
map_boot_text();
#endif
......
......@@ -44,6 +44,10 @@ int io_bat_index;
extern char etext[], _stext[];
#ifdef CONFIG_SMP
extern void hash_page_sync(void);
#endif
#ifdef HAVE_BATS
extern unsigned long v_mapped_by_bats(unsigned long va);
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)
void pte_free_kernel(pte_t *pte)
{
#ifdef CONFIG_SMP
hash_page_sync();
#endif
free_page((unsigned long)pte);
}
void pte_free(struct page *pte)
{
#ifdef CONFIG_SMP
hash_page_sync();
#endif
__free_page(pte);
}
......
......@@ -83,6 +83,9 @@ unsigned long p_mapped_by_bats(unsigned long pa)
unsigned long __init mmu_mapin_ram(void)
{
#ifdef CONFIG_POWER4
return 0;
#else
unsigned long tot, bl, done;
unsigned long max_size = (256<<20);
unsigned long align;
......@@ -119,6 +122,7 @@ unsigned long __init mmu_mapin_ram(void)
}
return done;
#endif
}
/*
......@@ -244,9 +248,10 @@ void __init MMU_init_hw(void)
Hash = mem_pieces_find(Hash_size, Hash_size);
cacheable_memzero(Hash, Hash_size);
_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
#endif /* CONFIG_POWER4 */
Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
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)
}
}
/*
* 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
* TLB flush is completely done.
......
......@@ -17,7 +17,8 @@ ifeq ($(CONFIG_APUS),y)
obj-$(CONFIG_PCI) += apus_pci.o
endif
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_PREP) += prep_pci.o prep_time.o prep_setup.o
ifeq ($(CONFIG_PPC_PMAC),y)
......
......@@ -8,6 +8,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/reboot.h>
#include <linux/nvram.h>
......@@ -37,6 +38,10 @@ register_backlight_controller(struct backlight_controller *ctrler, void *data, c
char *prop;
int valid = 0;
/* There's already a matching controller, bail out */
if (backlighter != NULL)
return;
bk_node = find_devices("backlight");
#ifdef CONFIG_ADB_PMU
......@@ -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",
type, backlight_level);
}
EXPORT_SYMBOL(register_backlight_controller);
void __pmac
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)
backlighter = NULL;
}
EXPORT_SYMBOL(unregister_backlight_controller);
int __pmac
set_backlight_enable(int enable)
......@@ -105,6 +112,7 @@ set_backlight_enable(int enable)
backlight_enabled = enable;
return rc;
}
EXPORT_SYMBOL(set_backlight_enable);
int __pmac
get_backlight_enable(void)
......@@ -113,6 +121,7 @@ get_backlight_enable(void)
return -ENODEV;
return backlight_enabled;
}
EXPORT_SYMBOL(get_backlight_enable);
int __pmac
set_backlight_level(int level)
......@@ -137,6 +146,7 @@ set_backlight_level(int level)
}
return rc;
}
EXPORT_SYMBOL(set_backlight_level);
int __pmac
get_backlight_level(void)
......@@ -145,3 +155,4 @@ get_backlight_level(void)
return -ENODEV;
return backlight_level;
}
EXPORT_SYMBOL(get_backlight_level);
......@@ -22,6 +22,7 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/i2c.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/irq.h>
......@@ -38,6 +39,14 @@
*/
#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_sleep_handler(void);
extern void openpic_suspend(struct sys_device *sysdev, u32 state);
......@@ -48,7 +57,14 @@ extern void enable_kernel_fp(void);
static unsigned int low_freq;
static unsigned int hi_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_gpios;
static u32 voltage_gpio;
static u32 frequency_gpio;
static u32 slew_done_gpio;
#define PMAC_CPU_LOW_SPEED 1
#define PMAC_CPU_HIGH_SPEED 0
......@@ -65,8 +81,7 @@ static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
{0, CPUFREQ_TABLE_END},
};
static inline void
wakeup_decrementer(void)
static inline void wakeup_decrementer(void)
{
set_dec(tb_ticks_per_jiffy);
/* No currently-supported powerbook has a 601,
......@@ -76,8 +91,7 @@ wakeup_decrementer(void)
}
#ifdef DEBUG_FREQ
static inline void
debug_calc_bogomips(void)
static inline void debug_calc_bogomips(void)
{
/* This will cause a recalc of bogomips and display the
* result. We backup/restore the value to avoid affecting the
......@@ -89,17 +103,18 @@ debug_calc_bogomips(void)
calibrate_delay();
loops_per_jiffy = save_lpj;
}
#endif
#endif /* DEBUG_FREQ */
/* Switch CPU speed under 750FX CPU control
*/
static int __pmac
cpu_750fx_cpu_speed(int low_speed)
static int __pmac cpu_750fx_cpu_speed(int low_speed)
{
#ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
#endif
#ifdef CONFIG_6xx
low_choose_750fx_pll(low_speed);
#endif
#ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
debug_calc_bogomips();
......@@ -108,15 +123,54 @@ cpu_750fx_cpu_speed(int low_speed)
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
*/
static int __pmac
pmu_set_cpu_speed(unsigned int low_speed)
static int __pmac pmu_set_cpu_speed(unsigned int low_speed)
{
struct adb_request req;
unsigned long save_l2cr;
unsigned long save_l3cr;
preempt_disable();
#ifdef DEBUG_FREQ
printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
#endif
......@@ -197,11 +251,12 @@ pmu_set_cpu_speed(unsigned int low_speed)
debug_calc_bogomips();
#endif
preempt_enable();
return 0;
}
static int __pmac
do_set_cpu_speed(int speed_mode)
static int __pmac do_set_cpu_speed(int speed_mode)
{
struct cpufreq_freqs freqs;
int rc;
......@@ -216,6 +271,8 @@ do_set_cpu_speed(int speed_mode)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (cpufreq_uses_pmu)
rc = pmu_set_cpu_speed(speed_mode);
else if (cpufreq_uses_gpios)
rc = gpios_set_cpu_speed(speed_mode);
else
rc = cpu_750fx_cpu_speed(speed_mode);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
......@@ -224,14 +281,12 @@ do_set_cpu_speed(int speed_mode)
return rc;
}
static int __pmac
pmac_cpufreq_verify(struct cpufreq_policy *policy)
static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
}
static int __pmac
pmac_cpufreq_target( struct cpufreq_policy *policy,
static int __pmac pmac_cpufreq_target( struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
......@@ -244,15 +299,13 @@ pmac_cpufreq_target( struct cpufreq_policy *policy,
return do_set_cpu_speed(newstate);
}
unsigned int __pmac
pmac_get_one_cpufreq(int i)
unsigned int __pmac pmac_get_one_cpufreq(int i)
{
/* Supports only one CPU for now */
return (i == 0) ? cur_freq : 0;
}
static int __pmac
pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
if (policy->cpu != 0)
return -ENODEV;
......@@ -264,6 +317,18 @@ pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
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 = {
.verify = pmac_cpufreq_verify,
.target = pmac_cpufreq_target,
......@@ -272,15 +337,17 @@ static struct cpufreq_driver pmac_cpufreq_driver = {
.owner = THIS_MODULE,
};
/* Currently, we support the following machines:
*
* - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz)
* - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz)
* - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz)
* - iBook2 500 (PMU based, 400Mhz & 500Mhz)
* - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
* - Recent MacRISC3 machines
*/
static int __init
pmac_cpufreq_setup(void)
static int __init pmac_cpufreq_setup(void)
{
struct device_node *cpunode;
u32 *value;
......@@ -304,6 +371,74 @@ pmac_cpufreq_setup(void)
if (machine_is_compatible("PowerBook3,4") ||
machine_is_compatible("PowerBook3,5") ||
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);
if (!value)
goto out;
......@@ -359,6 +494,11 @@ pmac_cpufreq_setup(void)
pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_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);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -34,6 +34,7 @@
#include <asm/time.h>
#include <asm/open_pic.h>
#include <asm/xmon.h>
#include <asm/pmac_feature.h>
#include "pmac_pic.h"
......@@ -363,32 +364,76 @@ static int __init enable_second_ohare(void)
return irqctrler->intrs[0].line;
}
void __init
pmac_pic_init(void)
#ifdef CONFIG_POWER4
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;
struct device_node *irqctrler;
struct device_node *irqctrler = NULL;
struct device_node *irqctrler2 = NULL;
struct device_node *np;
unsigned long addr;
int irq_cascade = -1;
/* We first try to detect Apple's new Core99 chipset, since mac-io
* 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)
{
printk("PowerMac using OpenPIC irq controller\n");
if (irqctrler->n_addrs > 0)
{
unsigned char senses[NR_IRQS];
unsigned char senses[128];
prom_get_irq_senses(senses, 0, NR_IRQS);
printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
irqctrler->addrs[0].address);
prom_get_irq_senses(senses, 0, 128);
OpenPIC_InitSenses = senses;
OpenPIC_NumInitSenses = NR_IRQS;
OpenPIC_NumInitSenses = 128;
ppc_md.get_irq = openpic_get_irq;
pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
irqctrler->addrs[0].size);
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
{
struct device_node* pswitch;
......
......@@ -332,7 +332,7 @@ pmac_setup_arch(void)
#ifdef CONFIG_SMP
/* Check for Core99 */
if (find_devices("uni-n"))
if (find_devices("uni-n") || find_devices("u3"))
ppc_md.smp_ops = &core99_smp_ops;
else
ppc_md.smp_ops = &psurge_smp_ops;
......@@ -469,10 +469,6 @@ pmac_restart(char *cmd)
struct adb_request req;
#endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_NVRAM
pmac_nvram_update();
#endif
switch (sys_ctrler) {
#ifdef CONFIG_ADB_CUDA
case SYS_CTRLER_CUDA:
......@@ -498,10 +494,6 @@ pmac_power_off(void)
struct adb_request req;
#endif /* CONFIG_ADB_CUDA */
#ifdef CONFIG_NVRAM
pmac_nvram_update();
#endif
switch (sys_ctrler) {
#ifdef CONFIG_ADB_CUDA
case SYS_CTRLER_CUDA:
......@@ -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.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.feature_call = pmac_do_feature_call;
......@@ -685,6 +672,14 @@ pmac_declare_of_platform_devices(void)
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");
if (np)
......
......@@ -119,8 +119,7 @@ static unsigned int core99_tb_gpio;
/* Sync flag for HW tb sync */
static volatile int sec_tb_reset = 0;
static void __init
core99_init_caches(int cpu)
static void __init core99_init_caches(int cpu)
{
if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
return;
......@@ -188,8 +187,7 @@ static inline void psurge_clr_ipi(int cpu)
*/
static unsigned long psurge_smp_message[NR_CPUS];
void __pmac
psurge_smp_message_recv(struct pt_regs *regs)
void __pmac psurge_smp_message_recv(struct pt_regs *regs)
{
int cpu = smp_processor_id();
int msg;
......@@ -206,15 +204,14 @@ psurge_smp_message_recv(struct pt_regs *regs)
smp_message_recv(msg, regs);
}
irqreturn_t __pmac
psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
irqreturn_t __pmac psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
{
psurge_smp_message_recv(regs);
return IRQ_HANDLED;
}
static void __pmac
smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
static void __pmac smp_psurge_message_pass(int target, int msg, unsigned long data,
int wait)
{
int i;
......@@ -410,8 +407,7 @@ static void __init psurge_dual_sync_tb(int cpu_nr)
smp_tb_synchronized = 1;
}
static void __init
smp_psurge_setup_cpu(int cpu_nr)
static void __init smp_psurge_setup_cpu(int cpu_nr)
{
if (cpu_nr == 0) {
......@@ -435,41 +431,54 @@ smp_psurge_setup_cpu(int cpu_nr)
psurge_dual_sync_tb(cpu_nr);
}
void __init
smp_psurge_take_timebase(void)
void __init smp_psurge_take_timebase(void)
{
/* Dummy implementation */
}
void __init
smp_psurge_give_timebase(void)
void __init smp_psurge_give_timebase(void)
{
/* Dummy implementation */
}
static int __init
smp_core99_probe(void)
static int __init smp_core99_probe(void)
{
#ifdef CONFIG_6xx
extern int powersave_nap;
struct device_node *cpus;
int i, ncpus = 1;
#endif
struct device_node *cpus, *firstcpu;
int i, ncpus = 0, boot_cpu = -1;
u32 *tbprop;
if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
cpus = find_type_devices("cpu");
if (cpus == NULL)
return 0;
cpus = firstcpu = find_type_devices("cpu");
while(cpus != NULL) {
u32 *regprop = (u32 *)get_property(cpus, "reg", NULL);
char *stateprop = (char *)get_property(cpus, "state", NULL);
if (regprop != NULL && stateprop != NULL &&
!strncmp(stateprop, "running", 7))
boot_cpu = *regprop;
++ncpus;
cpus = cpus->next;
}
if (boot_cpu == -1)
printk(KERN_WARNING "Couldn't detect boot CPU !\n");
if (boot_cpu != 0)
printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu);
tbprop = (u32 *)get_property(cpus, "timebase-enable", NULL);
if (machine_is_compatible("MacRISC4")) {
extern struct smp_ops_t core99_smp_ops;
core99_smp_ops.take_timebase = smp_generic_take_timebase;
core99_smp_ops.give_timebase = smp_generic_give_timebase;
} else {
if (firstcpu != NULL)
tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL);
if (tbprop)
core99_tb_gpio = *tbprop;
else
core99_tb_gpio = KL_GPIO_TB_ENABLE;
while ((cpus = cpus->next) != NULL)
++ncpus;
printk("smp_core99_probe: found %d cpus\n", ncpus);
}
if (ncpus > 1) {
openpic_request_IPIs();
......@@ -484,8 +493,7 @@ smp_core99_probe(void)
return ncpus;
}
static void __init
smp_core99_kick_cpu(int nr)
static void __init smp_core99_kick_cpu(int nr)
{
unsigned long save_vector, new_vector;
unsigned long flags;
......@@ -539,23 +547,31 @@ smp_core99_kick_cpu(int nr)
if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
}
static void __init
smp_core99_setup_cpu(int cpu_nr)
static void __init smp_core99_setup_cpu(int cpu_nr)
{
/* Setup some registers */
/* Setup L2/L3 */
if (cpu_nr != 0)
core99_init_caches(cpu_nr);
/* Setup openpic */
do_openpic_setup_cpu();
/* Setup L2/L3 */
if (cpu_nr == 0)
if (cpu_nr == 0) {
#ifdef CONFIG_POWER4
extern void g5_phy_disable_cpu1(void);
/* If we didn't start the second CPU, we must take
* it off the bus
*/
if (machine_is_compatible("MacRISC4") &&
num_online_cpus() < 2)
g5_phy_disable_cpu1();
#endif /* CONFIG_POWER4 */
if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
}
}
void __init
smp_core99_take_timebase(void)
void __init smp_core99_take_timebase(void)
{
/* Secondary processor "takes" the timebase by freezing
* it, resetting its local TB and telling CPU 0 to go on
......@@ -572,8 +588,7 @@ smp_core99_take_timebase(void)
sec_tb_reset = 1;
}
void __init
smp_core99_give_timebase(void)
void __init smp_core99_give_timebase(void)
{
unsigned int t;
......
......@@ -266,6 +266,14 @@ pmac_calibrate_decr(void)
if (via_calibrate_decr())
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
* to tell us the rate at which the decrementer counts.
......
......@@ -31,6 +31,7 @@ obj-$(CONFIG_PCI) += qspan_pci.o i8259.o
endif
obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.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_PREP) += open_pic.o indirect_pci.o i8259.o
obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \
......
......@@ -183,6 +183,7 @@ void of_release_dev(struct device *dev)
struct of_device *ofdev;
ofdev = to_of_device(dev);
of_node_put(ofdev->node);
kfree(ofdev);
}
......@@ -242,7 +243,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char *
return NULL;
memset(dev, 0, sizeof(*dev));
dev->node = np;
dev->node = of_node_get(np);
dev->dma_mask = 0xffffffffUL;
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.parent = NULL;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -26,6 +26,8 @@ source "drivers/ieee1394/Kconfig"
source "drivers/message/i2o/Kconfig"
source "drivers/macintosh/Kconfig"
source "net/Kconfig"
source "drivers/isdn/Kconfig"
......
This diff is collapsed.
......@@ -57,7 +57,9 @@ obj-$(CONFIG_SONYPI) += sonypi.o
obj-$(CONFIG_RTC) += rtc.o
obj-$(CONFIG_GEN_RTC) += genrtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
ifeq ($(CONFIG_PPC),)
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
obj-$(CONFIG_NVRAM) += nvram.o
endif
obj-$(CONFIG_TOSHIBA) += toshiba.o
......
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