// Original CPU and L2CR interpretation code licensed as: /* * Copyright (c) 1997 Per Fogelstrom * Copyright (c) 1997 RTMX Inc * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD for RTMX Inc * North Carolina, USA, by Per Fogelstrom, Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ // additional calculations of (HID0) CPU settings and speed licensed as /*- * Copyright (c) 2001 Matt Thomas. * Copyright (c) 2001 Tsubai Masanari. * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by * Internet Research Institute, Inc. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (C) 2003 Benno Rice. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * from $NetBSD: cpu_subr.c,v 1.1 2003/02/03 17:10:09 matt Exp $ * $FreeBSD: src/sys/powerpc/powerpc/cpu.c,v 1.5 2004/02/09 07:04:01 grehan Exp $ */ #include #include #include #include #include #include #include #include #define MPC601 1 #define MPC603 3 #define MPC604 4 #define MPC603e 6 #define MPC603ev 7 #define MPC750 8 #define MPC604ev 9 #define MPC7400 12 #define IBM750FX 0x7000 #define MPC7450 0x8000 #define MPC7455 0x8001 #define MPC7457 0x8002 #define MPC7410 0x800c struct cputab { const char *name; uint16_t version; uint16_t revfmt; }; #define REVFMT_MAJMIN 1 /* %u.%u */ #define REVFMT_HEX 2 /* 0x%04x */ #define REVFMT_DEC 3 /* %u */ static const struct cputab models[] = { { "Motorola PowerPC 601", MPC601, REVFMT_DEC }, // { "Motorola PowerPC 602", MPC602, REVFMT_DEC }, { "Motorola PowerPC 603", MPC603, REVFMT_MAJMIN }, { "Motorola PowerPC 603e", MPC603e, REVFMT_MAJMIN }, { "Motorola PowerPC 603ev", MPC603ev, REVFMT_MAJMIN }, { "Motorola PowerPC 604", MPC604, REVFMT_MAJMIN }, { "Motorola PowerPC 604ev", MPC604ev, REVFMT_MAJMIN }, // { "Motorola PowerPC 620", MPC620, REVFMT_HEX }, { "Motorola PowerPC 740/750 (G3 - Arthur)", MPC750, REVFMT_MAJMIN }, { "IBM PowerPC 750FX (G3)", IBM750FX, REVFMT_MAJMIN }, { "Motorola PowerPC 7400 (G4 - Typhoon)", MPC7400, REVFMT_MAJMIN }, { "Motorola PowerPC 7410 (G4 - Nitro)", MPC7410, REVFMT_MAJMIN }, { "Motorola PowerPC 7450 (G4+ - V'Ger)", MPC7450, REVFMT_MAJMIN }, { "Motorola PowerPC 7455 (G4+ - Apollo)", MPC7455, REVFMT_MAJMIN }, { "Motorola PowerPC 7457 (G4+)", MPC7457, REVFMT_MAJMIN }, // { "Motorola PowerPC 8240", MPC8240, REVFMT_MAJMIN }, { "Unknown PowerPC CPU", 0, REVFMT_HEX } // need G5 identifications... }; char cpu_model[80]; char machine[] = MACHINE; /* cpu architecture */ /* Definition of the driver for autoconfig. */ int cpumatch(struct device *, void *, void *); void cpuattach(struct device *, struct device *, void *); struct cfattach cpu_ca = { sizeof(struct device), cpumatch, cpuattach }; struct cfdriver cpu_cd = { NULL, "cpu", DV_DULL, NULL, 0 }; void config_l2cr(int cpu); uint32_t cpu_calculate_speed(void); int cpumatch(parent, cfdata, aux) struct device *parent; void *cfdata; void *aux; { struct confargs *ca = aux; /* make sure that we're looking for a CPU. */ if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0) return (0); return (1); } static u_int32_t ppc_curfreq; int ppc_cpuspeed(int *freq) { *freq = ppc_curfreq; return (0); } void cpuattach(parent, dev, aux) struct device *parent; struct device *dev; void *aux; { char name[32]; int qhandle, phandle; unsigned int clock_freq = 0; u_int32_t cpu, rev, revfmt; const struct cputab *cp; u_int pvr, maj, min, hid0; const char* cpu_name; char* bitmask; pvr = ppc_mfpvr(); cpu = pvr >> 16; rev = pvr; switch (cpu) { case MPC7410: min = (pvr >> 0) & 0xff; maj = min <= 4 ? 1 : 2; break; default: maj = (pvr >> 8) & 0xf; min = (pvr >> 0) & 0xf; } for (cp = models; cp->name[0] != '\0'; cp++) { if (cp->version == cpu) break; } revfmt = cp->revfmt; cpu_name = cp->name; if (rev == MPC750 && pvr == 15) { cpu_name = "Motorola MPC755"; revfmt = REVFMT_HEX; } printf(": %s Rev. ", cpu_name); switch (revfmt) { case REVFMT_MAJMIN: printf("%u.%u", maj, min); break; case REVFMT_HEX: printf("0x%04x", rev); break; case REVFMT_DEC: printf("%u", rev); break; } if (cpu > MPC603ev) { // use PMCs on CPU clock_freq = cpu_calculate_speed(); } else { /* This should only be executed on openfirmware systems... */ for (qhandle = OF_peer(0); qhandle; qhandle = phandle) { if (OF_getprop(qhandle, "device_type", name, sizeof name) >= 0 && !strcmp(name, "cpu") && OF_getprop(qhandle, "clock-frequency", &clock_freq , sizeof clock_freq ) >= 0) { break; } if ((phandle = OF_child(qhandle))) continue; while (qhandle) { if ((phandle = OF_peer(qhandle))) break; qhandle = OF_parent(qhandle); } } if (clock_freq != 0) { /* Openfirmware stores clock in Hz, not MHz */ clock_freq /= 1000000; // OF will report 195 for any unrecognized CPU //- no Mac ever shipped with this rating if (clock_freq == 195) // MMCR0 doesn't exist on 603 series and below if (cpu > MPC603ev) clock_freq = cpu_calculate_speed(); } } printf(": %d MHz", clock_freq); ppc_curfreq = clock_freq; /* power savings mode */ hid0 = ppc_mfhid0(); switch (cpu) { case MPC603: case MPC603e: case MPC603ev: case MPC604ev: case MPC750: case IBM750FX: case MPC7400: case MPC7410: // case MPC8240: // case MPC8245: /* Select DOZE mode. */ hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); hid0 |= HID0_DOZE | HID0_DPM; #ifdef notyet powersave = 1; #endif break; case MPC7457: case MPC7455: case MPC7450: /* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */ if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200) || (pvr >> 16) == MPC7457) hid0 &= ~HID0_BTIC; /* Select NAP mode. */ hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP); hid0 |= HID0_NAP | HID0_DPM; #ifdef notyet powersave = 0; /* but don't use it */ #endif break; default: /* No power-saving mode is available. */ ; } switch (cpu) { case IBM750FX: case MPC750: hid0 &= ~HID0_DBP; /* XXX correct? */ hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; break; case MPC7400: case MPC7410: hid0 &= ~HID0_SPD; hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT; hid0 |= HID0_EIEC; break; } ppc_mthid0(hid0); switch (cpu) { case MPC7450: case MPC7455: case MPC7457: bitmask = HID0_7450_BITMASK; break; default: bitmask = HID0_BITMASK; break; } printf(" HID0: %b\n", hid0, bitmask); // need these to ensure clean cache after L1 enabling // these should nop if no L2 present __asm __volatile ("isync"); __asm __volatile ("sync"); /* if processor is G3 or G4, configure l2 cache */ if ( (cpu == MPC750) || (cpu == MPC7400) || (cpu == IBM750FX) || (cpu == MPC7410) || (cpu == MPC7450) || (cpu == MPC7455)) { config_l2cr(cpu); } printf("\n"); } uint32_t cpu_calculate_speed(void) { uint64_t cps; uint32_t mHZ; // MMCR registers are 0->31 LSB left to right // the rest is just Tsubai's code // we use pmc2 for simplicity #define FREEZE (1 << 31) #define COUNT_CYCLES 1 ppc_mtmmcr0(FREEZE); ppc_mtpmc2(0); ppc_mtmmcr0(COUNT_CYCLES); DELAY(100000); cps = (ppc_mfpmc2() * 10) + 4999; // don't leave it running ppc_mtmmcr0(FREEZE); mHZ = cps / 1000000; return mHZ; } #define L2CR 1017 #define L2CR_L2E 0x80000000 /* 0: L2 enable */ #define L2CR_L2PE 0x40000000 /* 1: L2 data parity enable */ #define L2CR_L2SIZ 0x30000000 /* 2-3: L2 size */ #define L2SIZ_RESERVED 0x00000000 #define L2SIZ_256K 0x10000000 #define L2SIZ_512K 0x20000000 #define L2SIZ_1M 0x30000000 #define L2CR_L2CLK 0x0e000000 /* 4-6: L2 clock ratio */ #define L2CLK_DIS 0x00000000 /* disable L2 clock */ #define L2CLK_10 0x02000000 /* core clock / 1 */ #define L2CLK_15 0x04000000 /* / 1.5 */ #define L2CLK_20 0x08000000 /* / 2 */ #define L2CLK_25 0x0a000000 /* / 2.5 */ #define L2CLK_30 0x0c000000 /* / 3 */ #define L2CR_L2RAM 0x01800000 /* 7-8: L2 RAM type */ #define L2RAM_FLOWTHRU_BURST 0x00000000 #define L2RAM_PIPELINE_BURST 0x01000000 #define L2RAM_PIPELINE_LATE 0x01800000 #define L2CR_L2DO 0x00400000 /* 9: L2 data-only. Setting this bit disables instruction caching. */ #define L2CR_L2I 0x00200000 /* 10: L2 global invalidate. */ #define L2CR_L2CTL 0x00100000 /* 11: L2 RAM control (ZZ enable). Enables automatic operation of the L2ZZ (low-power mode) signal. */ #define L2CR_L2WT 0x00080000 /* 12: L2 write-through. */ #define L2CR_L2TS 0x00040000 /* 13: L2 test support. */ #define L2CR_L2OH 0x00030000 /* 14-15: L2 output hold. */ #define L2CR_L2SL 0x00008000 /* 16: L2 DLL slow. */ #define L2CR_L2DF 0x00004000 /* 17: L2 differential clock. */ #define L2CR_L2BYP 0x00002000 /* 18: L2 DLL bypass. */ #define L2CR_L2IP 0x00000001 /* 31: L2 global invalidate in progress (read only). */ #ifdef L2CR_CONFIG u_int l2cr_config = L2CR_CONFIG; #else u_int l2cr_config = 0; #endif #define SPR_L3CR 0x3fa /* .6. L3 Control Register */ #define L3CR_L3E 0x80000000 /* 0: L3 enable */ #define L3CR_L3SIZ 0x10000000 /* 3: L3 size (0=1MB, 1=2MB) */ void config_l2cr(int cpu) { u_int l2cr, x; l2cr = ppc_mfl2cr(); printf("l2cr value: %x", l2cr); /* * Configure L2 cache if not enabled. */ if ((l2cr & L2CR_L2E) == 0 && l2cr_config != 0) { l2cr = l2cr_config; ppc_mtl2cr(l2cr); /* Wait for L2 clock to be stable (640 L2 clocks). */ // not necessary - Motorola docs state global invalidate // always takes longer than DLL stabilization //delay(100); /* Invalidate all L2 contents. */ l2cr |= L2CR_L2I; ppc_mtl2cr(l2cr); do { x = ppc_mfl2cr(); } while (x & L2CR_L2IP); /* Enable L2 cache. */ l2cr &= ~L2CR_L2I; l2cr |= L2CR_L2E; ppc_mtl2cr(l2cr); // need a sync after enabling __asm __volatile ("isync"); __asm __volatile ("sync"); // and recover the value again so that // readout below reads the value from the L2CR // and not from how we set it l2cr = ppc_mfl2cr(); } if (l2cr & L2CR_L2E) { if (cpu == MPC7450 || cpu == MPC7455) { u_int l3cr; printf(": 256KB L2 cache"); l3cr = ppc_mfl3cr(); if (l3cr & L3CR_L3E) printf(", %cMB L3 cache", l3cr & L3CR_L3SIZ ? '2' : '1'); } else if (cpu == IBM750FX) printf(": 512KB L2 cache"); else { switch (l2cr & L2CR_L2SIZ) { case L2SIZ_RESERVED: if (cpu == MPC750) printf(": 0MB (MPC740)"); else printf(": 0MB (unknown processor)"); break; case L2SIZ_256K: printf(": 256KB"); break; case L2SIZ_512K: printf(": 512KB"); break; case L2SIZ_1M: printf(": 1MB"); break; default: printf(": unknown size"); } if ((l2cr & L2CR_L2SIZ) > 0) printf(" backside cache"); } #if 1 switch (l2cr & L2CR_L2RAM) { case L2RAM_FLOWTHRU_BURST: printf(" Flow-through synchronous burst SRAM"); break; case L2RAM_PIPELINE_BURST: printf(" Pipelined synchronous burst SRAM"); break; case L2RAM_PIPELINE_LATE: printf(" Pipelined synchronous late-write SRAM"); break; default: printf(" unknown type"); } if (l2cr & L2CR_L2PE) printf(" with parity"); #endif } else printf(": L2 cache not enabled"); }