diff -Nur --exclude=RCS --exclude=CVS --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.4/arch/ppc/8xx_io/Config.in linux-2.4-intracom/arch/ppc/8xx_io/Config.in --- linux-2.4/arch/ppc/8xx_io/Config.in 2004-09-02 16:17:52 +03:00 +++ linux-2.4-intracom/arch/ppc/8xx_io/Config.in 2004-10-19 12:57:51 +03:00 @@ -4,10 +4,17 @@ mainmenu_option next_comment comment 'MPC8xx Options' +if [ "$CONFIG_8xx_SMC1" = "y" -o "$CONFIG_8xx_SMC2" = "y" -o \ + "$CONFIG_8xx_SCC1" = "y" -o "$CONFIG_8xx_SCC2" = "y" -o \ + "$CONFIG_8xx_SCC3" = "y" -o "$CONFIG_8xx_SCC4" = "y" ]; then + define_bool CONFIG_8xx_STD_SERIAL y +fi + comment 'Generic MPC8xx Options' bool 'Copy-Back Data Cache (else Writethrough)' CONFIG_8xx_COPYBACK bool 'CPU6 Silicon Errata (860 Pre Rev. C)' CONFIG_8xx_CPU6 bool 'I2C/SPI Microcode Patch' CONFIG_UCODE_PATCH +bool 'DUET support (87x/88x)' CONFIG_DUET comment 'MPC8xx CPM Options' if [ "$CONFIG_NET_ETHERNET" = "y" ]; then diff -Nur --exclude=RCS --exclude=CVS --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.4/arch/ppc/config.in linux-2.4-intracom/arch/ppc/config.in --- linux-2.4/arch/ppc/config.in 2004-09-02 16:17:52 +03:00 +++ linux-2.4-intracom/arch/ppc/config.in 2004-12-01 17:06:52 +02:00 @@ -55,6 +55,21 @@ define_bool CONFIG_PPC_STD_MMU y fi +if [ "$CONFIG_8xx" = "y" ]; then + bool 'MPC8xx CPU Idle Support' CONFIG_8xx_IDLE + if [ "$CONFIG_8xx_IDLE" = "y" ]; then + if [ "$CONFIG_DUET" != "y" ]; then + choice 'Idle method' \ + "Normal-Low CONFIG_8xx_IDLE_NORMAL_LOW \ + Doze-High CONFIG_8xx_IDLE_DOZE_HIGH \ + Doze-Low CONFIG_8xx_IDLE_DOZE_LOW" CONFIG_8xx_IDLE_NORMAL_LOW + else + # DUET only supports NORMAL_LOW mode + define_bool CONFIG_8xx_IDLE_NORMAL_LOW y + fi + fi +fi + if [ "$CONFIG_8260" = "y" ]; then define_bool CONFIG_SERIAL_CONSOLE y define_bool CONFIG_CPM2 y diff -Nur --exclude=RCS --exclude=CVS --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.4/arch/ppc/kernel/Makefile linux-2.4-intracom/arch/ppc/kernel/Makefile --- linux-2.4/arch/ppc/kernel/Makefile 2004-09-02 16:17:53 +03:00 +++ linux-2.4-intracom/arch/ppc/kernel/Makefile 2004-11-19 11:12:59 +02:00 @@ -40,7 +40,11 @@ semaphore.o syscalls.o setup.o \ cputable.o ppc_htab.o ifneq ($(CONFIG_6xx),y) -obj-y += idle_gen.o + ifeq ($(CONFIG_8xx_IDLE),y) + obj-y += idle_8xx.o + else + obj-y += idle_gen.o + endif endif obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_MODULES) += ppc_ksyms.o @@ -102,6 +106,7 @@ head_44x.o: head_44x.S ppc_defs.h head_8xx.o: head_8xx.S ppc_defs.h idle_6xx.o: idle_6xx.S ppc_defs.h +idle_8xx.o: idle_8xx.S ppc_defs.h ppc_defs.h: mk_defs.c ppc_defs.head \ $(TOPDIR)/include/asm/mmu.h \ diff -Nur --exclude=RCS --exclude=CVS --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.4/arch/ppc/kernel/cputable.c linux-2.4-intracom/arch/ppc/kernel/cputable.c --- linux-2.4/arch/ppc/kernel/cputable.c 2004-10-19 09:29:02 +03:00 +++ linux-2.4-intracom/arch/ppc/kernel/cputable.c 2004-12-01 18:24:13 +02:00 @@ -408,7 +408,11 @@ { /* 8xx */ 0xffff0000, 0x00500000, "8xx", /* CPU_FTR_CAN_DOZE is possible, if the 8xx code is there.... */ - CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB, + CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB +#ifdef CONFIG_8xx_IDLE + | CPU_FTR_CAN_DOZE +#endif + , PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, 16, 16, __setup_cpu_8xx /* Empty */ diff -Nur --exclude=RCS --exclude=CVS --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.4/arch/ppc/kernel/head_8xx.S linux-2.4-intracom/arch/ppc/kernel/head_8xx.S --- linux-2.4/arch/ppc/kernel/head_8xx.S 2004-09-02 16:17:53 +03:00 +++ linux-2.4-intracom/arch/ppc/kernel/head_8xx.S 2004-12-01 18:24:13 +02:00 @@ -667,11 +667,11 @@ SAVE_8GPRS(24, r21) andi. r23,r23,MSR_PR mfspr r23,SPRG3 /* if from user, fix up THREAD.regs */ - beq 2f + addi r2,r23,-THREAD /* set r2 to current */ + beq 0f addi r24,r1,STACK_FRAME_OVERHEAD stw r24,PT_REGS(r23) -2: addi r2,r23,-THREAD /* set r2 to current */ - tovirt(r2,r2) +0: tovirt(r2,r2) mflr r23 andi. r24,r23,0x3f00 /* get vector offset */ stw r24,TRAP(r21) @@ -683,7 +683,13 @@ cmplw 1,r1,r24 crand 1,1,4 bgt- stack_ovf /* if r2 < r1 < r2+TASK_STRUCT_SIZE */ + lwz r24,0(r23) /* virtual address of handler */ +#ifdef CONFIG_8xx_IDLE + mtctr r24 /* save to ctr */ + lis r24,power_save_8xx_restore@h + ori r24,r24,power_save_8xx_restore@l +#endif lwz r23,4(r23) /* where to go when done */ mtspr SRR0,r24 mtspr SRR1,r20 diff -Nur --exclude=RCS --exclude=CVS --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.4/arch/ppc/kernel/idle_8xx.S linux-2.4-intracom/arch/ppc/kernel/idle_8xx.S --- linux-2.4/arch/ppc/kernel/idle_8xx.S 1970-01-01 02:00:00 +02:00 +++ linux-2.4-intracom/arch/ppc/kernel/idle_8xx.S 2004-12-01 17:06:52 +02:00 @@ -0,0 +1,114 @@ +/* + * This file contains the power_save function for 8xx CPUs + * rewritten in assembler + * + * 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 +#include +#include +#include +#include +#include +#include "ppc_defs.h" + + .text + +#define CSRC 21 +#define LPM1 22 +#define LPM0 23 + +#define CSRCM (1 << (31 - CSRC)) +#define LPM1M (1 << (31 - LPM1)) +#define LPM0M (1 << (31 - LPM0)) + +#if defined(CONFIG_8xx_IDLE_NORMAL_LOW) +#define SETMSK CSRCM +#elif defined(CONFIG_8xx_IDLE_DOZE_HIGH) +#define SETMSK LPM0M +#elif defined(CONFIG_8xx_IDLE_DOZE_LOW) +#define SETMSK (LPM0M | CSRCM) +#else +#error Not supported mode. +#endif + +#define PLPRCRK 0x0384 +#define PLPRCR 0x0284 + +/* + * Here is the power_save function. This could eventually be + * split into several functions & changing the function pointer + * depending on the various features. + */ + .globl power_save +power_save: + mfspr r5, IMMR + rlwinm r5, r5,0,0,15 /* only high 16 bits count */ + + /* Clear MSR:EE */ + mfmsr r7 + rlwinm r0,r7,0,17,15 +2: mtmsr r0 + + /* Check current->need_resched */ + lwz r4,NEED_RESCHED(r2) + cmpi 0,r4,0 + bne- 1f + + /* enter low power */ + lwz r4,PLPRCR(r5) /* load PLPRCR */ + andi. r4,r4,SETMSK + bne 0f + lis r4,0x55cc /* load key */ + ori r4,r4,0xaa33 + stw r4,PLPRCRK(r5) /* unlock PLPRCR register */ + lwz r4,PLPRCR(r5) /* load PLPRCR */ + rlwinm r24,r24,0,23+1,16-1 + ori r4,r4,SETMSK /* set these bits */ + stw r4,PLPRCR(r5) /* store PLPRCR */ + li r4,0 + stw r4,PLPRCRK(r5) /* lock PLPRCR register */ + +0: mtmsr r7 /* enable interrupts */ + b 2b /* and test again */ + + /* leave low power */ +1: lwz r4,PLPRCR(r5) /* load PLPRCR */ + andi. r4,r4,SETMSK /* test if already out */ + beq 0f + lis r4,0x55cc /* load key */ + ori r4,r4,0xaa33 + stw r4,PLPRCRK(r5) /* unlock PLPRCR register */ + lwz r4,PLPRCR(r5) /* load PLPRCR */ + rlwinm r24,r24,0,23+1,16-1 + stw r4,PLPRCR(r5) /* store PLPRCR */ + li r4,0 + stw r4,PLPRCRK(r5) /* lock PLPRCR register */ + + /* and we're out */ +0: mtmsr r7 + blr + + /**************************************/ + + .globl power_save_8xx_restore +power_save_8xx_restore: + mfspr r20,IMMR + rlwinm r20,r20,0,0,15 /* only high 16 bits count */ + lwz r24,PLPRCR(r20) /* load PLPRCR */ + andi. r24,r24,SETMSK + beqctr /* jump if not low power */ + lis r24,0x55cc /* load key */ + ori r24,r24,0xaa33 + stw r24,PLPRCRK(r20)/* unlock PLPRCR register */ + lwz r24,PLPRCR(r20) /* load PLPRCR */ + rlwinm r24,r24,0,23+1,16-1 + stw r24,PLPRCR(r20) /* store PLPRCR */ + li r24,0 + stw r24,PLPRCRK(r20)/* lock PLPRCR register */ + bctr /* jump to handler */ + diff -Nur --exclude=RCS --exclude=CVS --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.4/arch/ppc/kernel/m8xx_setup.c linux-2.4-intracom/arch/ppc/kernel/m8xx_setup.c --- linux-2.4/arch/ppc/kernel/m8xx_setup.c 2004-09-02 16:17:53 +03:00 +++ linux-2.4-intracom/arch/ppc/kernel/m8xx_setup.c 2004-12-01 18:24:13 +02:00 @@ -118,6 +118,73 @@ printk ("timebase_interrupt()\n"); } +#ifdef CONFIG_8xx_IDLE + +/* these are the DUET defines */ +#define PLPRCR_MFN_MSK 0xF8000000 /* Multiplication factor numerator bits */ +#define PLPRCR_MFN_SHIFT 27 /* Multiplication factor numerator shift*/ +#define PLPRCR_MFD_MSK 0x07C00000 /* Multiplication factor denominator bits */ +#define PLPRCR_MFD_SHIFT 22 /* Multiplication factor denominator shift*/ +#define PLPRCR_S_MSK 0x00300000 /* Multiplication factor integer bits */ +#define PLPRCR_S_SHIFT 20 /* Multiplication factor integer shift */ +#define PLPRCR_MFI_MSK 0x000F0000 /* Multiplication factor integer bits */ +#define PLPRCR_MFI_SHIFT 16 /* Multiplication factor integer shift */ + +#define PLPRCR_PDF_MSK 0x0000001E /* Predivision Factor bits */ +#define PLPRCR_PDF_SHIFT 1 /* Predivision Factor shift value */ + +#define PLPRCR_val(a) ((((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr & \ + PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT) + +/* max GCLK as of this writing */ +#define MAX_GCLK 133333333 +#define MAX_MULT (((unsigned int)-1) / MAX_GCLK) +#define RPREC 2 /* bits of rounding precision */ +#define RPRECHALF (1 << (RPREC - 1)) + +#ifdef CONFIG_DUET + +/* XXX it could overflow; be sure to check */ +int get_tbclk(int gclk) +{ + unsigned int xin, mfi, mfd, mfn, s, pdf, mult; + unsigned int num, denum; + + mfi = PLPRCR_val(MFI); + mfd = PLPRCR_val(MFD); + mfn = PLPRCR_val(MFN); + s = PLPRCR_val(S); + pdf = PLPRCR_val(PDF); + + if (mfn == 0) { + mult = (pdf + 1) << s; + denum = mfi; + } else { + mult = ((mfd + 1) * (pdf + 1)) << s; + denum = (mfi * mfd + mfi + mfn); + } + + /* printk(KERN_INFO "gclk = %u, pdf=%u, mfi=%u, mfd=%u, mfn=%u, s=%u\n", + gclk, pdf, mfi, mfd, mfn, s); */ + + num = gclk * mult; + xin = (((num << RPREC) / denum) + RPRECHALF) >> RPREC; + + printk(KERN_INFO "Calculated XIN %u\n", xin); + + if (gclk >= 66666666) + return xin / 4; + return xin / 16; +} + +#else + +#error Supply the get_tbclk clock function + +#endif + +#endif + /* The decrementer counts at the system (internal) clock frequency divided by * sixteen, or external oscillator divided by four. We force the processor * to use system clock divided by sixteen. @@ -125,22 +192,30 @@ void __init m8xx_calibrate_decr(void) { bd_t *binfo = (bd_t *)__res; + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; int freq, fp, divisor; /* Unlock the SCCR. */ - ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY; + imap->im_clkrstk.cark_sccrk = ~KAPWR_KEY; + imap->im_clkrstk.cark_sccrk = KAPWR_KEY; +#ifndef CONFIG_8xx_IDLE /* Force all 8xx processors to use divide by 16 processor clock. */ - ((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000; + imap->im_clkrst.car_sccr |= 0x02000000; /* Processor frequency is MHz. * The value 'fp' is the number of decrementer ticks per second. */ fp = binfo->bi_intfreq / 16; - freq = fp*60; /* try to make freq/1e6 an integer */ +#else + /* we must use the XIN freq as base */ + imap->im_clkrst.car_sccr = (imap->im_clkrst.car_sccr & ~0x02000000) | 0x00800000; + fp = get_tbclk(binfo->bi_intfreq); +#endif + + freq = fp * 60; /* try to make freq/1e6 an integer */ divisor = 60; - printk("Decrementer Frequency = %d/%d\n", freq, divisor); + printk(KERN_INFO "Decrementer Frequency = %d/%d\n", freq, divisor); tb_ticks_per_jiffy = freq / HZ / divisor; tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); @@ -159,28 +234,24 @@ * we guarantee the registers are locked, then we unlock them * for our use. */ - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = ~KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = KAPWR_KEY; + imap->im_sitk.sitk_tbscrk = ~KAPWR_KEY; + imap->im_sitk.sitk_rtcsck = ~KAPWR_KEY; + imap->im_sitk.sitk_tbk = ~KAPWR_KEY; + imap->im_sitk.sitk_tbscrk = KAPWR_KEY; + imap->im_sitk.sitk_rtcsck = KAPWR_KEY; + imap->im_sitk.sitk_tbk = KAPWR_KEY; /* Disable the RTC one second and alarm interrupts. */ - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &= - ~(RTCSC_SIE | RTCSC_ALE); + imap->im_sit.sit_rtcsc &= ~(RTCSC_SIE | RTCSC_ALE); /* Enable the RTC */ - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc |= - (RTCSC_RTF | RTCSC_RTE); + imap->im_sit.sit_rtcsc |= (RTCSC_RTF | RTCSC_RTE); /* Enabling the decrementer also enables the timebase interrupts * (or from the other point of view, to get decrementer interrupts * we have to enable the timebase). The decrementer interrupt * is wired into the vector table, nothing to do here for that. */ - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr = - ((mk_int_int_mask(DEC_INTERRUPT) << 8) | - (TBSCR_TBF | TBSCR_TBE)); + imap->im_sit.sit_tbscr = ((mk_int_int_mask(DEC_INTERRUPT) << 8) | (TBSCR_TBF | TBSCR_TBE)); if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0) @@ -201,9 +272,11 @@ static int m8xx_set_rtc_time(unsigned long time) { - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; + + imap->im_sitk.sitk_rtck = KAPWR_KEY; + imap->im_sit.sit_rtc = time; + imap->im_sitk.sitk_rtck = ~KAPWR_KEY; return(0); } @@ -218,10 +291,14 @@ m8xx_restart(char *cmd) { __volatile__ unsigned char dummy; + volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; uint msr; cli(); - ((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080; + + /* someone must unlock */ + imap->im_clkrstk.cark_plprcrk = KAPWR_KEY; + imap->im_clkrst.car_plprcr |= 0x00000080; /* Clear the ME bit in MSR to cause checkstop on machine check */ @@ -229,7 +306,7 @@ msr &= ~0x1000; __asm__("mtmsr %0" : : "r" (msr) ); - dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0]; + dummy = imap->im_clkrst.res[0]; printk("Restart failed\n"); while(1); } @@ -246,7 +323,6 @@ m8xx_restart(NULL); } - static int m8xx_show_percpuinfo(struct seq_file *m, int i) { @@ -254,9 +330,16 @@ bp = (bd_t *)__res; - seq_printf(m, "clock\t\t: %dMHz\n" - "bus clock\t: %dMHz\n", + seq_printf(m, "clock\t\t: %ldMHz\n" + "bus clock\t: %ldMHz\n", bp->bi_intfreq / 1000000, bp->bi_busfreq / 1000000); + seq_printf(m, "features\t:"); +#ifdef CONFIG_8xx_IDLE + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_CAN_DOZE) + seq_printf(m, " CAN_DOZE"); +#endif + seq_printf(m, "\n"); + return 0; }