mp_cpudep.c revision 215197
1218887Sdim/*- 2218887Sdim * Copyright (c) 2008 Marcel Moolenaar 3218887Sdim * All rights reserved. 4218887Sdim * 5218887Sdim * Redistribution and use in source and binary forms, with or without 6218887Sdim * modification, are permitted provided that the following conditions 7218887Sdim * are met: 8218887Sdim * 9218887Sdim * 1. Redistributions of source code must retain the above copyright 10218887Sdim * notice, this list of conditions and the following disclaimer. 11218887Sdim * 2. Redistributions in binary form must reproduce the above copyright 12218887Sdim * notice, this list of conditions and the following disclaimer in the 13218887Sdim * documentation and/or other materials provided with the distribution. 14218887Sdim * 15218887Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16218887Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17218887Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18218887Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19218887Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20218887Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21218887Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22218887Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23218887Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24218887Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25218887Sdim */ 26218887Sdim 27218887Sdim#include <sys/cdefs.h> 28218887Sdim__FBSDID("$FreeBSD: head/sys/powerpc/aim/mp_cpudep.c 215197 2010-11-12 20:26:34Z nwhitehorn $"); 29218887Sdim 30218887Sdim#include <sys/param.h> 31218887Sdim#include <sys/systm.h> 32218887Sdim#include <sys/kernel.h> 33218887Sdim#include <sys/bus.h> 34218887Sdim#include <sys/pcpu.h> 35218887Sdim#include <sys/proc.h> 36218887Sdim#include <sys/smp.h> 37218887Sdim 38218887Sdim#include <machine/bus.h> 39218887Sdim#include <machine/cpu.h> 40218887Sdim#include <machine/hid.h> 41218887Sdim#include <machine/intr_machdep.h> 42218887Sdim#include <machine/pcb.h> 43218887Sdim#include <machine/psl.h> 44218887Sdim#include <machine/smp.h> 45218887Sdim#include <machine/spr.h> 46218887Sdim#include <machine/trap_aim.h> 47218887Sdim 48218887Sdim#include <dev/ofw/openfirm.h> 49218887Sdim#include <machine/ofw_machdep.h> 50218887Sdim 51218887Sdimvoid *ap_pcpu; 52218887Sdim 53218887Sdimstatic register_t bsp_state[8] __aligned(8); 54218887Sdim 55218887Sdimstatic void cpudep_save_config(void *dummy); 56218887SdimSYSINIT(cpu_save_config, SI_SUB_CPU, SI_ORDER_ANY, cpudep_save_config, NULL); 57218887Sdim 58218887Sdimvoid 59218887Sdimcpudep_ap_early_bootstrap(void) 60218887Sdim{ 61218887Sdim register_t reg; 62218887Sdim 63218887Sdim __asm __volatile("mtsprg 0, %0" :: "r"(ap_pcpu)); 64218887Sdim powerpc_sync(); 65218887Sdim 66218887Sdim switch (mfpvr() >> 16) { 67218887Sdim case IBM970: 68218887Sdim case IBM970FX: 69218887Sdim case IBM970MP: 70218887Sdim /* Restore HID4 and HID5, which are necessary for the MMU */ 71218887Sdim 72218887Sdim __asm __volatile("ld %0, 16(%2); sync; isync; \ 73218887Sdim mtspr %1, %0; sync; isync;" 74218887Sdim : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state)); 75218887Sdim __asm __volatile("ld %0, 24(%2); sync; isync; \ 76218887Sdim mtspr %1, %0; sync; isync;" 77218887Sdim : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state)); 78218887Sdim powerpc_sync(); 79218887Sdim break; 80218887Sdim } 81218887Sdim} 82218887Sdim 83218887Sdimuintptr_t 84218887Sdimcpudep_ap_bootstrap(void) 85218887Sdim{ 86218887Sdim register_t msr, sp; 87218887Sdim 88218887Sdim msr = PSL_KERNSET & ~PSL_EE; 89218887Sdim mtmsr(msr); 90218887Sdim isync(); 91218887Sdim 92218887Sdim pcpup->pc_curthread = pcpup->pc_idlethread; 93218887Sdim pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; 94218887Sdim sp = pcpup->pc_curpcb->pcb_sp; 95218887Sdim 96218887Sdim return (sp); 97218887Sdim} 98218887Sdim 99218887Sdimstatic register_t 100218887Sdimmpc74xx_l2_enable(register_t l2cr_config) 101218887Sdim{ 102218887Sdim register_t ccr, bit; 103218887Sdim uint16_t vers; 104218887Sdim 105218887Sdim vers = mfpvr() >> 16; 106218887Sdim switch (vers) { 107218887Sdim case MPC7400: 108218887Sdim case MPC7410: 109218887Sdim bit = L2CR_L2IP; 110218887Sdim break; 111218887Sdim default: 112218887Sdim bit = L2CR_L2I; 113218887Sdim break; 114218887Sdim } 115218887Sdim 116218887Sdim ccr = mfspr(SPR_L2CR); 117218887Sdim if (ccr & L2CR_L2E) 118218887Sdim return (ccr); 119218887Sdim 120218887Sdim /* Configure L2 cache. */ 121218887Sdim ccr = l2cr_config & ~L2CR_L2E; 122218887Sdim mtspr(SPR_L2CR, ccr | L2CR_L2I); 123218887Sdim do { 124218887Sdim ccr = mfspr(SPR_L2CR); 125218887Sdim } while (ccr & bit); 126218887Sdim powerpc_sync(); 127218887Sdim mtspr(SPR_L2CR, l2cr_config); 128218887Sdim powerpc_sync(); 129218887Sdim 130218887Sdim return (l2cr_config); 131218887Sdim} 132218887Sdim 133218887Sdimstatic register_t 134218887Sdimmpc745x_l3_enable(register_t l3cr_config) 135218887Sdim{ 136218887Sdim register_t ccr; 137218887Sdim 138218887Sdim ccr = mfspr(SPR_L3CR); 139218887Sdim if (ccr & L3CR_L3E) 140218887Sdim return (ccr); 141218887Sdim 142218887Sdim /* Configure L3 cache. */ 143218887Sdim ccr = l3cr_config & ~(L3CR_L3E | L3CR_L3I | L3CR_L3PE | L3CR_L3CLKEN); 144218887Sdim mtspr(SPR_L3CR, ccr); 145218887Sdim ccr |= 0x4000000; /* Magic, but documented. */ 146218887Sdim mtspr(SPR_L3CR, ccr); 147218887Sdim ccr |= L3CR_L3CLKEN; 148218887Sdim mtspr(SPR_L3CR, ccr); 149218887Sdim mtspr(SPR_L3CR, ccr | L3CR_L3I); 150218887Sdim while (mfspr(SPR_L3CR) & L3CR_L3I) 151218887Sdim ; 152218887Sdim mtspr(SPR_L3CR, ccr & ~L3CR_L3CLKEN); 153218887Sdim powerpc_sync(); 154218887Sdim DELAY(100); 155218887Sdim mtspr(SPR_L3CR, ccr); 156218887Sdim powerpc_sync(); 157218887Sdim DELAY(100); 158218887Sdim ccr |= L3CR_L3E; 159218887Sdim mtspr(SPR_L3CR, ccr); 160218887Sdim powerpc_sync(); 161218887Sdim 162218887Sdim return(ccr); 163218887Sdim} 164218887Sdim 165218887Sdimstatic register_t 166218887Sdimmpc74xx_l1d_enable(void) 167218887Sdim{ 168218887Sdim register_t hid; 169218887Sdim 170221345Sdim hid = mfspr(SPR_HID0); 171218887Sdim if (hid & HID0_DCE) 172218887Sdim return (hid); 173218887Sdim 174218887Sdim /* Enable L1 D-cache */ 175218887Sdim hid |= HID0_DCE; 176218887Sdim powerpc_sync(); 177218887Sdim mtspr(SPR_HID0, hid | HID0_DCFI); 178218887Sdim powerpc_sync(); 179218887Sdim 180218887Sdim return (hid); 181218887Sdim} 182218887Sdim 183218887Sdimstatic register_t 184218887Sdimmpc74xx_l1i_enable(void) 185218887Sdim{ 186218887Sdim register_t hid; 187218887Sdim 188218887Sdim hid = mfspr(SPR_HID0); 189218887Sdim if (hid & HID0_ICE) 190218887Sdim return (hid); 191218887Sdim 192218887Sdim /* Enable L1 I-cache */ 193218887Sdim hid |= HID0_ICE; 194218887Sdim isync(); 195218887Sdim mtspr(SPR_HID0, hid | HID0_ICFI); 196218887Sdim isync(); 197218887Sdim 198218887Sdim return (hid); 199218887Sdim} 200218887Sdim 201218887Sdimstatic void 202218887Sdimcpudep_save_config(void *dummy) 203218887Sdim{ 204218887Sdim uint16_t vers; 205218887Sdim 206218887Sdim vers = mfpvr() >> 16; 207218887Sdim 208218887Sdim switch(vers) { 209218887Sdim case IBM970: 210218887Sdim case IBM970FX: 211218887Sdim case IBM970MP: 212218887Sdim #ifdef __powerpc64__ 213218887Sdim bsp_state[0] = mfspr(SPR_HID0); 214218887Sdim bsp_state[1] = mfspr(SPR_HID1); 215218887Sdim bsp_state[2] = mfspr(SPR_HID4); 216218887Sdim bsp_state[3] = mfspr(SPR_HID5); 217218887Sdim #else 218218887Sdim __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 219218887Sdim : "=r" (bsp_state[0]),"=r" (bsp_state[1]) : "K" (SPR_HID0)); 220218887Sdim __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 221218887Sdim : "=r" (bsp_state[2]),"=r" (bsp_state[3]) : "K" (SPR_HID1)); 222218887Sdim __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 223218887Sdim : "=r" (bsp_state[4]),"=r" (bsp_state[5]) : "K" (SPR_HID4)); 224218887Sdim __asm __volatile ("mfspr %0,%2; mr %1,%0; srdi %0,%0,32" 225218887Sdim : "=r" (bsp_state[6]),"=r" (bsp_state[7]) : "K" (SPR_HID5)); 226218887Sdim #endif 227218887Sdim 228218887Sdim powerpc_sync(); 229218887Sdim 230218887Sdim break; 231218887Sdim case IBMCELLBE: 232218887Sdim #ifdef NOTYET /* Causes problems if in instruction stream on 970 */ 233218887Sdim if (mfmsr() & PSL_HV) { 234218887Sdim bsp_state[0] = mfspr(SPR_HID0); 235218887Sdim bsp_state[1] = mfspr(SPR_HID1); 236218887Sdim bsp_state[2] = mfspr(SPR_HID4); 237218887Sdim bsp_state[3] = mfspr(SPR_HID6); 238218887Sdim 239218887Sdim bsp_state[4] = mfspr(SPR_CELL_TSCR); 240218887Sdim } 241218887Sdim #endif 242218887Sdim 243218887Sdim bsp_state[5] = mfspr(SPR_CELL_TSRL); 244218887Sdim 245218887Sdim break; 246218887Sdim case MPC7450: 247218887Sdim case MPC7455: 248218887Sdim case MPC7457: 249218887Sdim /* Only MPC745x CPUs have an L3 cache. */ 250218887Sdim bsp_state[3] = mfspr(SPR_L3CR); 251218887Sdim 252218887Sdim /* Fallthrough */ 253218887Sdim case MPC7400: 254218887Sdim case MPC7410: 255218887Sdim case MPC7447A: 256218887Sdim case MPC7448: 257218887Sdim bsp_state[2] = mfspr(SPR_L2CR); 258218887Sdim bsp_state[1] = mfspr(SPR_HID1); 259218887Sdim bsp_state[0] = mfspr(SPR_HID0); 260218887Sdim break; 261218887Sdim } 262218887Sdim} 263218887Sdim 264218887Sdimvoid 265218887Sdimcpudep_ap_setup() 266218887Sdim{ 267218887Sdim register_t reg; 268218887Sdim uint16_t vers; 269218887Sdim 270218887Sdim vers = mfpvr() >> 16; 271218887Sdim 272218887Sdim switch(vers) { 273218887Sdim case IBM970: 274218887Sdim case IBM970FX: 275218887Sdim case IBM970MP: 276218887Sdim /* Set HIOR to 0 */ 277218887Sdim __asm __volatile("mtspr 311,%0" :: "r"(0)); 278218887Sdim powerpc_sync(); 279218887Sdim 280218887Sdim /* 281218887Sdim * The 970 has strange rules about how to update HID registers. 282218887Sdim * See Table 2-3, 970MP manual 283218887Sdim */ 284218887Sdim 285218887Sdim __asm __volatile("mtasr %0; sync" :: "r"(0)); 286218887Sdim __asm __volatile(" \ 287218887Sdim ld %0,0(%2); \ 288218887Sdim sync; isync; \ 289218887Sdim mtspr %1, %0; \ 290218887Sdim mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 291218887Sdim mfspr %0, %1; mfspr %0, %1; mfspr %0, %1; \ 292218887Sdim sync; isync" 293218887Sdim : "=r"(reg) : "K"(SPR_HID0), "r"(bsp_state)); 294218887Sdim __asm __volatile("ld %0, 8(%2); sync; isync; \ 295218887Sdim mtspr %1, %0; mtspr %1, %0; sync; isync" 296218887Sdim : "=r"(reg) : "K"(SPR_HID1), "r"(bsp_state)); 297218887Sdim __asm __volatile("ld %0, 16(%2); sync; isync; \ 298218887Sdim mtspr %1, %0; sync; isync;" 299218887Sdim : "=r"(reg) : "K"(SPR_HID4), "r"(bsp_state)); 300218887Sdim __asm __volatile("ld %0, 24(%2); sync; isync; \ 301218887Sdim mtspr %1, %0; sync; isync;" 302218887Sdim : "=r"(reg) : "K"(SPR_HID5), "r"(bsp_state)); 303218887Sdim 304218887Sdim powerpc_sync(); 305218887Sdim break; 306218887Sdim case IBMCELLBE: 307218887Sdim #ifdef NOTYET /* Causes problems if in instruction stream on 970 */ 308218887Sdim if (mfmsr() & PSL_HV) { 309218887Sdim mtspr(SPR_HID0, bsp_state[0]); 310218887Sdim mtspr(SPR_HID1, bsp_state[1]); 311218887Sdim mtspr(SPR_HID4, bsp_state[2]); 312218887Sdim mtspr(SPR_HID6, bsp_state[3]); 313218887Sdim 314218887Sdim mtspr(SPR_CELL_TSCR, bsp_state[4]); 315218887Sdim } 316218887Sdim #endif 317218887Sdim 318218887Sdim mtspr(SPR_CELL_TSRL, bsp_state[5]); 319218887Sdim 320218887Sdim break; 321218887Sdim case MPC7450: 322218887Sdim case MPC7455: 323218887Sdim case MPC7457: 324218887Sdim /* Only MPC745x CPUs have an L3 cache. */ 325218887Sdim reg = mpc745x_l3_enable(bsp_state[3]); 326218887Sdim 327218887Sdim /* Fallthrough */ 328218887Sdim case MPC7400: 329218887Sdim case MPC7410: 330218887Sdim case MPC7447A: 331218887Sdim case MPC7448: 332218887Sdim /* XXX: Program the CPU ID into PIR */ 333218887Sdim __asm __volatile("mtspr 1023,%0" :: "r"(PCPU_GET(cpuid))); 334218887Sdim 335218887Sdim powerpc_sync(); 336218887Sdim isync(); 337218887Sdim 338218887Sdim mtspr(SPR_HID0, bsp_state[0]); isync(); 339218887Sdim mtspr(SPR_HID1, bsp_state[1]); isync(); 340218887Sdim 341218887Sdim reg = mpc74xx_l2_enable(bsp_state[2]); 342218887Sdim reg = mpc74xx_l1d_enable(); 343218887Sdim reg = mpc74xx_l1i_enable(); 344218887Sdim 345218887Sdim break; 346218887Sdim default: 347218887Sdim printf("WARNING: Unknown CPU type. Cache performace may be " 348218887Sdim "suboptimal.\n"); 349218887Sdim break; 350218887Sdim } 351218887Sdim} 352218887Sdim 353218887Sdim