diff options
Diffstat (limited to 'arch/powerpc/platforms/52xx')
-rw-r--r-- | arch/powerpc/platforms/52xx/Kconfig | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/Makefile | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/efika.c | 32 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/lite5200.c | 121 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/lite5200_pm.c | 213 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/lite5200_sleep.S | 412 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_common.c | 38 | ||||
-rw-r--r-- | arch/powerpc/platforms/52xx/mpc52xx_pic.c | 22 |
8 files changed, 708 insertions, 135 deletions
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 3ffaa066c2c8..2938d4927b83 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig @@ -1,6 +1,7 @@ config PPC_MPC52xx bool select FSL_SOC + select PPC_CLOCK default n config PPC_MPC5200 @@ -30,6 +31,7 @@ config PPC_EFIKA config PPC_LITE5200 bool "Freescale Lite5200 Eval Board" depends on PPC_MULTIPLATFORM && PPC32 + select WANT_DEVICE_TREE select PPC_MPC5200 default n diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index b91e39c84d46..307dbc178091 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile @@ -10,3 +10,6 @@ obj-$(CONFIG_PPC_EFIKA) += efika.o obj-$(CONFIG_PPC_LITE5200) += lite5200.o obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o +ifeq ($(CONFIG_PPC_LITE5200),y) + obj-$(CONFIG_PM) += lite5200_sleep.o lite5200_pm.o +endif diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index 4be6e7a17b66..a0da70c8b502 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c @@ -9,33 +9,16 @@ * kind, whether express or implied. */ -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/reboot.h> #include <linux/init.h> #include <linux/utsrelease.h> -#include <linux/seq_file.h> -#include <linux/string.h> -#include <linux/root_dev.h> -#include <linux/initrd.h> -#include <linux/timer.h> #include <linux/pci.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/sections.h> -#include <asm/pci-bridge.h> -#include <asm/pgtable.h> +#include <linux/of.h> #include <asm/prom.h> #include <asm/time.h> #include <asm/machdep.h> #include <asm/rtas.h> -#include <asm/of_device.h> -#include <asm/of_platform.h> #include <asm/mpc52xx.h> - #define EFIKA_PLATFORM_NAME "Efika" @@ -78,8 +61,8 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, } static struct pci_ops rtas_pci_ops = { - rtas_read_config, - rtas_write_config + .read = rtas_read_config, + .write = rtas_write_config, }; @@ -197,15 +180,6 @@ static void __init efika_setup_arch(void) { rtas_initialize(); -#ifdef CONFIG_BLK_DEV_INITRD - initrd_below_start_ok = 1; - - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif - ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ - efika_pcisetup(); #ifdef CONFIG_PM diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 5c46e898fd45..0caa3d955c3b 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c @@ -15,33 +15,13 @@ #undef DEBUG -#include <linux/stddef.h> -#include <linux/kernel.h> #include <linux/init.h> -#include <linux/errno.h> -#include <linux/reboot.h> #include <linux/pci.h> -#include <linux/kdev_t.h> -#include <linux/major.h> -#include <linux/console.h> -#include <linux/delay.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/initrd.h> - -#include <asm/system.h> -#include <asm/atomic.h> +#include <linux/of.h> #include <asm/time.h> #include <asm/io.h> #include <asm/machdep.h> -#include <asm/ipic.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> #include <asm/prom.h> -#include <asm/udbg.h> -#include <sysdev/fsl_soc.h> -#include <asm/of_platform.h> - #include <asm/mpc52xx.h> /* ************************************************************************ @@ -50,19 +30,56 @@ * */ +/* + * Fix clock configuration. + * + * Firmware is supposed to be responsible for this. If you are creating a + * new board port, do *NOT* duplicate this code. Fix your boot firmware + * to set it correctly in the first place + */ +static void __init +lite5200_fix_clock_config(void) +{ + struct mpc52xx_cdm __iomem *cdm; + + /* Map zones */ + cdm = mpc52xx_find_and_map("mpc5200-cdm"); + if (!cdm) { + printk(KERN_ERR "%s() failed; expect abnormal behaviour\n", + __FUNCTION__); + return; + } + + /* Use internal 48 Mhz */ + out_8(&cdm->ext_48mhz_en, 0x00); + out_8(&cdm->fd_enable, 0x01); + if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ + out_be16(&cdm->fd_counters, 0x0001); + else + out_be16(&cdm->fd_counters, 0x5555); + + /* Unmap the regs */ + iounmap(cdm); +} + +/* + * Fix setting of port_config register. + * + * Firmware is supposed to be responsible for this. If you are creating a + * new board port, do *NOT* duplicate this code. Fix your boot firmware + * to set it correctly in the first place + */ static void __init -lite5200_setup_cpu(void) +lite5200_fix_port_config(void) { struct mpc52xx_gpio __iomem *gpio; u32 port_config; - /* Map zones */ gpio = mpc52xx_find_and_map("mpc5200-gpio"); if (!gpio) { - printk(KERN_ERR __FILE__ ": " - "Error while mapping GPIO register for port config. " - "Expect some abnormal behavior\n"); - goto error; + printk(KERN_ERR "%s() failed. expect abnormal behavior\n", + __FUNCTION__); + return; } /* Set port config */ @@ -81,12 +98,10 @@ lite5200_setup_cpu(void) out_be32(&gpio->port_config, port_config); /* Unmap zone */ -error: iounmap(gpio); } #ifdef CONFIG_PM -static u32 descr_a; static void lite5200_suspend_prepare(void __iomem *mbar) { u8 pin = 1; /* GPIO_WKUP_1 (GPIO_PSC2_4) */ @@ -97,42 +112,41 @@ static void lite5200_suspend_prepare(void __iomem *mbar) * power down usb port * this needs to be called before of-ohci suspend code */ - descr_a = in_be32(mbar + 0x1048); - out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100); + + /* set ports to "power switched" and "powered at the same time" + * USB Rh descriptor A: NPS = 0, PSM = 0 */ + out_be32(mbar + 0x1048, in_be32(mbar + 0x1048) & ~0x300); + /* USB Rh status: LPS = 1 - turn off power */ + out_be32(mbar + 0x1050, 0x00000001); } static void lite5200_resume_finish(void __iomem *mbar) { - out_be32(mbar + 0x1048, descr_a); + /* USB Rh status: LPSC = 1 - turn on power */ + out_be32(mbar + 0x1050, 0x00010000); } #endif static void __init lite5200_setup_arch(void) { +#ifdef CONFIG_PCI struct device_node *np; +#endif if (ppc_md.progress) ppc_md.progress("lite5200_setup_arch()", 0); - np = of_find_node_by_type(NULL, "cpu"); - if (np) { - const unsigned int *fp = - of_get_property(np, "clock-frequency", NULL); - if (fp != 0) - loops_per_jiffy = *fp / HZ; - else - loops_per_jiffy = 50000000 / HZ; - of_node_put(np); - } + /* Fix things that firmware should have done. */ + lite5200_fix_clock_config(); + lite5200_fix_port_config(); - /* CPU & Port mux setup */ - mpc52xx_setup_cpu(); /* Generic */ - lite5200_setup_cpu(); /* Platorm specific */ + /* Some mpc5200 & mpc5200b related configuration */ + mpc5200_setup_xlb_arbiter(); #ifdef CONFIG_PM mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; mpc52xx_suspend.board_resume_finish = lite5200_resume_finish; - mpc52xx_pm_init(); + lite5200_pm_init(); #endif #ifdef CONFIG_PCI @@ -156,20 +170,6 @@ static void __init lite5200_setup_arch(void) } -static void lite5200_show_cpuinfo(struct seq_file *m) -{ - struct device_node* np = of_find_all_nodes(NULL); - const char *model = NULL; - - if (np) - model = of_get_property(np, "model", NULL); - - seq_printf(m, "vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "machine\t\t: %s\n", model ? model : "unknown"); - - of_node_put(np); -} - /* * Called very early, MMU is off, device-tree isn't unflattened */ @@ -193,6 +193,5 @@ define_machine(lite5200) { .init = mpc52xx_declare_of_platform_devices, .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, - .show_cpuinfo = lite5200_show_cpuinfo, .calibrate_decr = generic_calibrate_decr, }; diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c new file mode 100644 index 000000000000..f26afcd41757 --- /dev/null +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c @@ -0,0 +1,213 @@ +#include <linux/init.h> +#include <linux/pm.h> +#include <asm/io.h> +#include <asm/time.h> +#include <asm/mpc52xx.h> +#include "mpc52xx_pic.h" + +/* defined in lite5200_sleep.S and only used here */ +extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar); + +static struct mpc52xx_cdm __iomem *cdm; +static struct mpc52xx_intr __iomem *pic; +static struct mpc52xx_sdma __iomem *bes; +static struct mpc52xx_xlb __iomem *xlb; +static struct mpc52xx_gpio __iomem *gps; +static struct mpc52xx_gpio_wkup __iomem *gpw; +static void __iomem *sram; +static const int sram_size = 0x4000; /* 16 kBytes */ +static void __iomem *mbar; + +static int lite5200_pm_valid(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + return 1; + default: + return 0; + } +} + +static int lite5200_pm_prepare(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) + return mpc52xx_pm_prepare(state); + + if (state != PM_SUSPEND_MEM) + return -EINVAL; + + /* map registers */ + mbar = mpc52xx_find_and_map("mpc5200"); + if (!mbar) { + printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); + return -ENOSYS; + } + + cdm = mbar + 0x200; + pic = mbar + 0x500; + gps = mbar + 0xb00; + gpw = mbar + 0xc00; + bes = mbar + 0x1200; + xlb = mbar + 0x1f00; + sram = mbar + 0x8000; + + return 0; +} + +/* save and restore registers not bound to any real devices */ +static struct mpc52xx_cdm scdm; +static struct mpc52xx_intr spic; +static struct mpc52xx_sdma sbes; +static struct mpc52xx_xlb sxlb; +static struct mpc52xx_gpio sgps; +static struct mpc52xx_gpio_wkup sgpw; + +static void lite5200_save_regs(void) +{ + _memcpy_fromio(&spic, pic, sizeof(*pic)); + _memcpy_fromio(&sbes, bes, sizeof(*bes)); + _memcpy_fromio(&scdm, cdm, sizeof(*cdm)); + _memcpy_fromio(&sxlb, xlb, sizeof(*xlb)); + _memcpy_fromio(&sgps, gps, sizeof(*gps)); + _memcpy_fromio(&sgpw, gpw, sizeof(*gpw)); + + _memcpy_fromio(saved_sram, sram, sram_size); +} + +static void lite5200_restore_regs(void) +{ + int i; + _memcpy_toio(sram, saved_sram, sram_size); + + + /* + * GPIOs. Interrupt Master Enable has higher address then other + * registers, so just memcpy is ok. + */ + _memcpy_toio(gpw, &sgpw, sizeof(*gpw)); + _memcpy_toio(gps, &sgps, sizeof(*gps)); + + + /* XLB Arbitrer */ + out_be32(&xlb->snoop_window, sxlb.snoop_window); + out_be32(&xlb->master_priority, sxlb.master_priority); + out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable); + + /* enable */ + out_be32(&xlb->int_enable, sxlb.int_enable); + out_be32(&xlb->config, sxlb.config); + + + /* CDM - Clock Distribution Module */ + out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel); + out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel); + + out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en); + out_8(&cdm->fd_enable, scdm.fd_enable); + out_be16(&cdm->fd_counters, scdm.fd_counters); + + out_be32(&cdm->clk_enables, scdm.clk_enables); + + out_8(&cdm->osc_disable, scdm.osc_disable); + + out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1); + out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2); + out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3); + out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6); + + + /* BESTCOMM */ + out_be32(&bes->taskBar, sbes.taskBar); + out_be32(&bes->currentPointer, sbes.currentPointer); + out_be32(&bes->endPointer, sbes.endPointer); + out_be32(&bes->variablePointer, sbes.variablePointer); + + out_8(&bes->IntVect1, sbes.IntVect1); + out_8(&bes->IntVect2, sbes.IntVect2); + out_be16(&bes->PtdCntrl, sbes.PtdCntrl); + + for (i=0; i<32; i++) + out_8(&bes->ipr[i], sbes.ipr[i]); + + out_be32(&bes->cReqSelect, sbes.cReqSelect); + out_be32(&bes->task_size0, sbes.task_size0); + out_be32(&bes->task_size1, sbes.task_size1); + out_be32(&bes->MDEDebug, sbes.MDEDebug); + out_be32(&bes->ADSDebug, sbes.ADSDebug); + out_be32(&bes->Value1, sbes.Value1); + out_be32(&bes->Value2, sbes.Value2); + out_be32(&bes->Control, sbes.Control); + out_be32(&bes->Status, sbes.Status); + out_be32(&bes->PTDDebug, sbes.PTDDebug); + + /* restore tasks */ + for (i=0; i<16; i++) + out_be16(&bes->tcr[i], sbes.tcr[i]); + + /* enable interrupts */ + out_be32(&bes->IntPend, sbes.IntPend); + out_be32(&bes->IntMask, sbes.IntMask); + + + /* PIC */ + out_be32(&pic->per_pri1, spic.per_pri1); + out_be32(&pic->per_pri2, spic.per_pri2); + out_be32(&pic->per_pri3, spic.per_pri3); + + out_be32(&pic->main_pri1, spic.main_pri1); + out_be32(&pic->main_pri2, spic.main_pri2); + + out_be32(&pic->enc_status, spic.enc_status); + + /* unmask and enable interrupts */ + out_be32(&pic->per_mask, spic.per_mask); + out_be32(&pic->main_mask, spic.main_mask); + out_be32(&pic->ctrl, spic.ctrl); +} + +static int lite5200_pm_enter(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) { + return mpc52xx_pm_enter(state); + } + + lite5200_save_regs(); + + /* effectively save FP regs */ + enable_kernel_fp(); + + lite5200_low_power(sram, mbar); + + lite5200_restore_regs(); + + /* restart jiffies */ + wakeup_decrementer(); + + iounmap(mbar); + return 0; +} + +static int lite5200_pm_finish(suspend_state_t state) +{ + /* deep sleep? let mpc52xx code handle that */ + if (state == PM_SUSPEND_STANDBY) { + return mpc52xx_pm_finish(state); + } + return 0; +} + +static struct pm_ops lite5200_pm_ops = { + .valid = lite5200_pm_valid, + .prepare = lite5200_pm_prepare, + .enter = lite5200_pm_enter, + .finish = lite5200_pm_finish, +}; + +int __init lite5200_pm_init(void) +{ + pm_set_ops(&lite5200_pm_ops); + return 0; +} diff --git a/arch/powerpc/platforms/52xx/lite5200_sleep.S b/arch/powerpc/platforms/52xx/lite5200_sleep.S new file mode 100644 index 000000000000..08ab6fefcf7a --- /dev/null +++ b/arch/powerpc/platforms/52xx/lite5200_sleep.S @@ -0,0 +1,412 @@ +#include <asm/reg.h> +#include <asm/ppc_asm.h> +#include <asm/processor.h> +#include <asm/cache.h> + + +#define SDRAM_CTRL 0x104 +#define SC_MODE_EN (1<<31) +#define SC_CKE (1<<30) +#define SC_REF_EN (1<<28) +#define SC_SOFT_PRE (1<<1) + +#define GPIOW_GPIOE 0xc00 +#define GPIOW_DDR 0xc08 +#define GPIOW_DVO 0xc0c + +#define CDM_CE 0x214 +#define CDM_SDRAM (1<<3) + + +/* helpers... beware: r10 and r4 are overwritten */ +#define SAVE_SPRN(reg, addr) \ + mfspr r10, SPRN_##reg; \ + stw r10, ((addr)*4)(r4); + +#define LOAD_SPRN(reg, addr) \ + lwz r10, ((addr)*4)(r4); \ + mtspr SPRN_##reg, r10; \ + sync; \ + isync; + + + .data +registers: + .space 0x5c*4 + .text + +/* ---------------------------------------------------------------------- */ +/* low-power mode with help of M68HLC908QT1 */ + + .globl lite5200_low_power +lite5200_low_power: + + mr r7, r3 /* save SRAM va */ + mr r8, r4 /* save MBAR va */ + + /* setup wakeup address for u-boot at physical location 0x0 */ + lis r3, CONFIG_KERNEL_START@h + lis r4, lite5200_wakeup@h + ori r4, r4, lite5200_wakeup@l + sub r4, r4, r3 + stw r4, 0(r3) + + + /* + * save stuff BDI overwrites + * 0xf0 (0xe0->0x100 gets overwritten when BDI connected; + * even when CONFIG_BDI* is disabled and MMU XLAT commented; heisenbug?)) + * WARNING: self-refresh doesn't seem to work when BDI2000 is connected, + * possibly because BDI sets SDRAM registers before wakeup code does + */ + lis r4, registers@h + ori r4, r4, registers@l + lwz r10, 0xf0(r3) + stw r10, (0x1d*4)(r4) + + /* save registers to r4 [destroys r10] */ + SAVE_SPRN(LR, 0x1c) + bl save_regs + + /* flush caches [destroys r3, r4] */ + bl flush_data_cache + + + /* copy code to sram */ + mr r4, r7 + li r3, (sram_code_end - sram_code)/4 + mtctr r3 + lis r3, sram_code@h + ori r3, r3, sram_code@l +1: + lwz r5, 0(r3) + stw r5, 0(r4) + addi r3, r3, 4 + addi r4, r4, 4 + bdnz 1b + + /* get tb_ticks_per_usec */ + lis r3, tb_ticks_per_usec@h + lwz r11, tb_ticks_per_usec@l(r3) + + /* disable I and D caches */ + mfspr r3, SPRN_HID0 + ori r3, r3, HID0_ICE | HID0_DCE + xori r3, r3, HID0_ICE | HID0_DCE + sync; isync; + mtspr SPRN_HID0, r3 + sync; isync; + + /* jump to sram */ + mtlr r7 + blrl + /* doesn't return */ + + +sram_code: + /* self refresh */ + lwz r4, SDRAM_CTRL(r8) + + /* send NOP (precharge) */ + oris r4, r4, SC_MODE_EN@h /* mode_en */ + stw r4, SDRAM_CTRL(r8) + sync + + ori r4, r4, SC_SOFT_PRE /* soft_pre */ + stw r4, SDRAM_CTRL(r8) + sync + xori r4, r4, SC_SOFT_PRE + + xoris r4, r4, SC_MODE_EN@h /* !mode_en */ + stw r4, SDRAM_CTRL(r8) + sync + + /* delay (for NOP to finish) */ + li r12, 1 + bl udelay + + /* + * mode_en must not be set when enabling self-refresh + * send AR with CKE low (self-refresh) + */ + oris r4, r4, (SC_REF_EN | SC_CKE)@h + xoris r4, r4, (SC_CKE)@h /* ref_en !cke */ + stw r4, SDRAM_CTRL(r8) + sync + + /* delay (after !CKE there should be two cycles) */ + li r12, 1 + bl udelay + + /* disable clock */ + lwz r4, CDM_CE(r8) + ori r4, r4, CDM_SDRAM + xori r4, r4, CDM_SDRAM + stw r4, CDM_CE(r8) + sync + + /* delay a bit */ + li r12, 1 + bl udelay + + + /* turn off with QT chip */ + li r4, 0x02 + stb r4, GPIOW_GPIOE(r8) /* enable gpio_wkup1 */ + sync + + stb r4, GPIOW_DVO(r8) /* "output" high */ + sync + stb r4, GPIOW_DDR(r8) /* output */ + sync + stb r4, GPIOW_DVO(r8) /* output high */ + sync + + /* 10uS delay */ + li r12, 10 + bl udelay + + /* turn off */ + li r4, 0 + stb r4, GPIOW_DVO(r8) /* output low */ + sync + + /* wait until we're offline */ + 1: + b 1b + + + /* local udelay in sram is needed */ + udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */ + mullw r12, r12, r11 + mftb r13 /* start */ + addi r12, r13, r12 /* end */ + 1: + mftb r13 /* current */ + cmp cr0, r13, r12 + blt 1b + blr + +sram_code_end: + + + +/* uboot jumps here on resume */ +lite5200_wakeup: + bl restore_regs + + + /* HIDs, MSR */ + LOAD_SPRN(HID1, 0x19) + LOAD_SPRN(HID2, 0x1a) + + + /* address translation is tricky (see turn_on_mmu) */ + mfmsr r10 + ori r10, r10, MSR_DR | MSR_IR + + + mtspr SPRN_SRR1, r10 + lis r10, mmu_on@h + ori r10, r10, mmu_on@l + mtspr SPRN_SRR0, r10 + sync + rfi +mmu_on: + /* kernel offset (r4 is still set from restore_registers) */ + addis r4, r4, CONFIG_KERNEL_START@h + + + /* restore MSR */ + lwz r10, (4*0x1b)(r4) + mtmsr r10 + sync; isync; + + /* invalidate caches */ + mfspr r10, SPRN_HID0 + ori r5, r10, HID0_ICFI | HID0_DCI + mtspr SPRN_HID0, r5 /* invalidate caches */ + sync; isync; + mtspr SPRN_HID0, r10 + sync; isync; + + /* enable caches */ + lwz r10, (4*0x18)(r4) + mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */ + /* ^ this has to be after address translation set in MSR */ + sync + isync + + + /* restore 0xf0 (BDI2000) */ + lis r3, CONFIG_KERNEL_START@h + lwz r10, (0x1d*4)(r4) + stw r10, 0xf0(r3) + + LOAD_SPRN(LR, 0x1c) + + + blr + + +/* ---------------------------------------------------------------------- */ +/* boring code: helpers */ + +/* save registers */ +#define SAVE_BAT(n, addr) \ + SAVE_SPRN(DBAT##n##L, addr); \ + SAVE_SPRN(DBAT##n##U, addr+1); \ + SAVE_SPRN(IBAT##n##L, addr+2); \ + SAVE_SPRN(IBAT##n##U, addr+3); + +#define SAVE_SR(n, addr) \ + mfsr r10, n; \ + stw r10, ((addr)*4)(r4); + +#define SAVE_4SR(n, addr) \ + SAVE_SR(n, addr); \ + SAVE_SR(n+1, addr+1); \ + SAVE_SR(n+2, addr+2); \ + SAVE_SR(n+3, addr+3); + +save_regs: + stw r0, 0(r4) + stw r1, 0x4(r4) + stw r2, 0x8(r4) + stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */ + + SAVE_SPRN(HID0, 0x18) + SAVE_SPRN(HID1, 0x19) + SAVE_SPRN(HID2, 0x1a) + mfmsr r10 + stw r10, (4*0x1b)(r4) + /*SAVE_SPRN(LR, 0x1c) have to save it before the call */ + /* 0x1d reserved by 0xf0 */ + SAVE_SPRN(RPA, 0x1e) + SAVE_SPRN(SDR1, 0x1f) + + /* save MMU regs */ + SAVE_BAT(0, 0x20) + SAVE_BAT(1, 0x24) + SAVE_BAT(2, 0x28) + SAVE_BAT(3, 0x2c) + SAVE_BAT(4, 0x30) + SAVE_BAT(5, 0x34) + SAVE_BAT(6, 0x38) + SAVE_BAT(7, 0x3c) + + SAVE_4SR(0, 0x40) + SAVE_4SR(4, 0x44) + SAVE_4SR(8, 0x48) + SAVE_4SR(12, 0x4c) + + SAVE_SPRN(SPRG0, 0x50) + SAVE_SPRN(SPRG1, 0x51) + SAVE_SPRN(SPRG2, 0x52) + SAVE_SPRN(SPRG3, 0x53) + SAVE_SPRN(SPRG4, 0x54) + SAVE_SPRN(SPRG5, 0x55) + SAVE_SPRN(SPRG6, 0x56) + SAVE_SPRN(SPRG7, 0x57) + + SAVE_SPRN(IABR, 0x58) + SAVE_SPRN(DABR, 0x59) + SAVE_SPRN(TBRL, 0x5a) + SAVE_SPRN(TBRU, 0x5b) + + blr + + +/* restore registers */ +#define LOAD_BAT(n, addr) \ + LOAD_SPRN(DBAT##n##L, addr); \ + LOAD_SPRN(DBAT##n##U, addr+1); \ + LOAD_SPRN(IBAT##n##L, addr+2); \ + LOAD_SPRN(IBAT##n##U, addr+3); + +#define LOAD_SR(n, addr) \ + lwz r10, ((addr)*4)(r4); \ + mtsr n, r10; + +#define LOAD_4SR(n, addr) \ + LOAD_SR(n, addr); \ + LOAD_SR(n+1, addr+1); \ + LOAD_SR(n+2, addr+2); \ + LOAD_SR(n+3, addr+3); + +restore_regs: + lis r4, registers@h + ori r4, r4, registers@l + + /* MMU is not up yet */ + subis r4, r4, CONFIG_KERNEL_START@h + + lwz r0, 0(r4) + lwz r1, 0x4(r4) + lwz r2, 0x8(r4) + lmw r11, 0xc(r4) + + /* + * these are a bit tricky + * + * 0x18 - HID0 + * 0x19 - HID1 + * 0x1a - HID2 + * 0x1b - MSR + * 0x1c - LR + * 0x1d - reserved by 0xf0 (BDI2000) + */ + LOAD_SPRN(RPA, 0x1e); + LOAD_SPRN(SDR1, 0x1f); + + /* restore MMU regs */ + LOAD_BAT(0, 0x20) + LOAD_BAT(1, 0x24) + LOAD_BAT(2, 0x28) + LOAD_BAT(3, 0x2c) + LOAD_BAT(4, 0x30) + LOAD_BAT(5, 0x34) + LOAD_BAT(6, 0x38) + LOAD_BAT(7, 0x3c) + + LOAD_4SR(0, 0x40) + LOAD_4SR(4, 0x44) + LOAD_4SR(8, 0x48) + LOAD_4SR(12, 0x4c) + + /* rest of regs */ + LOAD_SPRN(SPRG0, 0x50); + LOAD_SPRN(SPRG1, 0x51); + LOAD_SPRN(SPRG2, 0x52); + LOAD_SPRN(SPRG3, 0x53); + LOAD_SPRN(SPRG4, 0x54); + LOAD_SPRN(SPRG5, 0x55); + LOAD_SPRN(SPRG6, 0x56); + LOAD_SPRN(SPRG7, 0x57); + + LOAD_SPRN(IABR, 0x58); + LOAD_SPRN(DABR, 0x59); + LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */ + LOAD_SPRN(TBWU, 0x5b); + + blr + + + +/* cache flushing code. copied from arch/ppc/boot/util.S */ +#define NUM_CACHE_LINES (128*8) + +/* + * Flush data cache + * Do this by just reading lots of stuff into the cache. + */ +flush_data_cache: + lis r3,CONFIG_KERNEL_START@h + ori r3,r3,CONFIG_KERNEL_START@l + li r4,NUM_CACHE_LINES + mtctr r4 +1: + lwz r4,0(r3) + addi r3,r3,L1_CACHE_BYTES /* Next line, please */ + bdnz 1b + blr diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 2dd415ff55a9..3bc201e07e6b 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -13,10 +13,9 @@ #undef DEBUG #include <linux/kernel.h> - +#include <linux/of_platform.h> #include <asm/io.h> #include <asm/prom.h> -#include <asm/of_platform.h> #include <asm/mpc52xx.h> @@ -76,44 +75,33 @@ mpc52xx_find_ipb_freq(struct device_node *node) EXPORT_SYMBOL(mpc52xx_find_ipb_freq); +/* + * Configure the XLB arbiter settings to match what Linux expects. + */ void __init -mpc52xx_setup_cpu(void) +mpc5200_setup_xlb_arbiter(void) { - struct mpc52xx_cdm __iomem *cdm; struct mpc52xx_xlb __iomem *xlb; - /* Map zones */ - cdm = mpc52xx_find_and_map("mpc5200-cdm"); xlb = mpc52xx_find_and_map("mpc5200-xlb"); - - if (!cdm || !xlb) { + if (!xlb) { printk(KERN_ERR __FILE__ ": " - "Error while mapping CDM/XLB during mpc52xx_setup_cpu. " + "Error mapping XLB in mpc52xx_setup_cpu(). " "Expect some abnormal behavior\n"); - goto unmap_regs; + return; } - /* Use internal 48 Mhz */ - out_8(&cdm->ext_48mhz_en, 0x00); - out_8(&cdm->fd_enable, 0x01); - if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ - out_be16(&cdm->fd_counters, 0x0001); - else - out_be16(&cdm->fd_counters, 0x5555); - /* Configure the XLB Arbiter priorities */ out_be32(&xlb->master_pri_enable, 0xff); out_be32(&xlb->master_priority, 0x11111111); - /* Disable XLB pipelining */ - /* (cfr errate 292. We could do this only just before ATA PIO - transaction and re-enable it afterwards ...) */ + /* Disable XLB pipelining + * (cfr errate 292. We could do this only just before ATA PIO + * transaction and re-enable it afterwards ...) + */ out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS); - /* Unmap zones */ -unmap_regs: - if (cdm) iounmap(cdm); - if (xlb) iounmap(xlb); + iounmap(xlb); } void __init diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index fbfff95b4437..61100f270c68 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c @@ -18,19 +18,9 @@ #undef DEBUG -#include <linux/stddef.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/stddef.h> -#include <linux/delay.h> #include <linux/irq.h> -#include <linux/hardirq.h> - +#include <linux/of.h> #include <asm/io.h> -#include <asm/processor.h> -#include <asm/system.h> -#include <asm/irq.h> #include <asm/prom.h> #include <asm/mpc52xx.h> #include "mpc52xx_pic.h" @@ -242,12 +232,6 @@ static struct irq_chip mpc52xx_sdma_irqchip = { * irq_host */ -static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node) -{ - pr_debug("%s: node=%p\n", __func__, node); - return mpc52xx_irqhost->host_data == node; -} - static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, u32 * intspec, unsigned int intsize, irq_hw_number_t * out_hwirq, @@ -368,7 +352,6 @@ static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, } static struct irq_host_ops mpc52xx_irqhost_ops = { - .match = mpc52xx_irqhost_match, .xlate = mpc52xx_irqhost_xlate, .map = mpc52xx_irqhost_map, }; @@ -420,14 +403,13 @@ void __init mpc52xx_init_irq(void) * hw irq information provided by the ofw to linux virq */ - mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, + mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ, &mpc52xx_irqhost_ops, -1); if (!mpc52xx_irqhost) panic(__FILE__ ": Cannot allocate the IRQ host\n"); - mpc52xx_irqhost->host_data = picnode; printk(KERN_INFO "MPC52xx PIC is up and running!\n"); } |