1 /* $NetBSD: cpu.c,v 1.7 2002/08/23 15:01:08 scw Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/properties.h> 42 43 #include <machine/cpu.h> 44 #include <powerpc/ibm4xx/dev/plbvar.h> 45 46 struct cputab { 47 int version; 48 char *name; 49 }; 50 static struct cputab models[] = { 51 { PVR_401A1 >> 16, "401A1" }, 52 { PVR_401B2 >> 16, "401B21" }, 53 { PVR_401C2 >> 16, "401C2" }, 54 { PVR_401D2 >> 16, "401D2" }, 55 { PVR_401E2 >> 16, "401E2" }, 56 { PVR_401F2 >> 16, "401F2" }, 57 { PVR_401G2 >> 16, "401G2" }, 58 { PVR_403 >> 16, "403" }, 59 { PVR_405GP >> 16, "405GP" }, 60 { 0, NULL } 61 }; 62 63 static int cpumatch(struct device *, struct cfdata *, void *); 64 static void cpuattach(struct device *, struct device *, void *); 65 66 struct cfattach cpu_ca = { 67 sizeof(struct device), cpumatch, cpuattach 68 }; 69 70 int ncpus; 71 72 struct cpu_info cpu_info_store; 73 74 int cpufound = 0; 75 76 static int 77 cpumatch(struct device *parent, struct cfdata *cf, void *aux) 78 { 79 struct plb_attach_args *paa = aux; 80 81 /* make sure that we're looking for a CPU */ 82 if (strcmp(paa->plb_name, cf->cf_driver->cd_name) != 0) 83 return (0); 84 85 return !cpufound; 86 } 87 88 static void 89 cpuattach(struct device *parent, struct device *self, void *aux) 90 { 91 int pvr, cpu; 92 int own, pcf, cas, pcl, aid; 93 struct cputab *cp = models; 94 unsigned int processor_freq; 95 96 if (board_info_get("processor-frequency", 97 &processor_freq, sizeof(processor_freq)) == -1) 98 panic("no processor-frequency"); 99 100 cpufound++; 101 ncpus++; 102 103 asm ("mfpvr %0" : "=r"(pvr)); 104 cpu = pvr >> 16; 105 106 /* Break PVR up into separate fields and print them out. */ 107 own = (pvr >> 20) & 0xfff; 108 pcf = (pvr >> 16) & 0xf; 109 cas = (pvr >> 10) & 0x3f; 110 pcl = (pvr >> 6) & 0xf; 111 aid = pvr & 0x3f; 112 113 while (cp->name) { 114 if (cp->version == cpu) 115 break; 116 cp++; 117 } 118 if (cp->name) 119 strcpy(cpu_model, cp->name); 120 else 121 sprintf(cpu_model, "Version 0x%x", cpu); 122 sprintf(cpu_model + strlen(cpu_model), " (Revision %d.%d)", 123 (pvr >> 8) & 0xff, pvr & 0xff); 124 125 #if 1 126 printf(": %dMHz %s\n", processor_freq / 1000 / 1000, 127 cpu_model); 128 #endif 129 130 cpu_probe_cache(); 131 132 printf("Instruction cache size %d line size %d\n", 133 curcpu()->ci_ci.icache_size, curcpu()->ci_ci.icache_line_size); 134 printf("Data cache size %d line size %d\n", 135 curcpu()->ci_ci.dcache_size, curcpu()->ci_ci.dcache_line_size); 136 137 #ifdef DEBUG 138 /* It sux that the cache info here is useless. */ 139 printf("PVR: owner %x core family %x cache %x version %x asic %x\n", 140 own, pcf, cas, pcl, aid); 141 #endif 142 } 143 144 /* 145 * This routine must be explicitly called to initialize the 146 * CPU cache information so cache flushe and memcpy operation 147 * work. 148 */ 149 void 150 cpu_probe_cache() 151 { 152 int version; 153 154 /* 155 * First we need to identify the cpu and determine the 156 * cache line size, or things like memset/memcpy may lose 157 * badly. 158 */ 159 __asm __volatile("mfpvr %0" : "=r" (version)); 160 switch (version & 0xffff0000) { 161 case PVR_401A1: 162 curcpu()->ci_ci.dcache_size = 1024; 163 curcpu()->ci_ci.dcache_line_size = 16; 164 curcpu()->ci_ci.icache_size = 2848; 165 curcpu()->ci_ci.icache_line_size = 16; 166 break; 167 case PVR_401B2: 168 curcpu()->ci_ci.dcache_size = 8192; 169 curcpu()->ci_ci.dcache_line_size = 16; 170 curcpu()->ci_ci.icache_size = 16384; 171 curcpu()->ci_ci.icache_line_size = 16; 172 break; 173 case PVR_401C2: 174 curcpu()->ci_ci.dcache_size = 8192; 175 curcpu()->ci_ci.dcache_line_size = 16; 176 curcpu()->ci_ci.icache_size = 0; 177 curcpu()->ci_ci.icache_line_size = 16; 178 break; 179 case PVR_401D2: 180 curcpu()->ci_ci.dcache_size = 2848; 181 curcpu()->ci_ci.dcache_line_size = 16; 182 curcpu()->ci_ci.icache_size = 4096; 183 curcpu()->ci_ci.icache_line_size = 16; 184 break; 185 case PVR_401E2: 186 curcpu()->ci_ci.dcache_size = 0; 187 curcpu()->ci_ci.dcache_line_size = 16; 188 curcpu()->ci_ci.icache_size = 0; 189 curcpu()->ci_ci.icache_line_size = 16; 190 break; 191 case PVR_401F2: 192 curcpu()->ci_ci.dcache_size = 2048; 193 curcpu()->ci_ci.dcache_line_size = 16; 194 curcpu()->ci_ci.icache_size = 2848; 195 curcpu()->ci_ci.icache_line_size = 16; 196 break; 197 case PVR_401G2: 198 curcpu()->ci_ci.dcache_size = 2848; 199 curcpu()->ci_ci.dcache_line_size = 16; 200 curcpu()->ci_ci.icache_size = 8192; 201 curcpu()->ci_ci.icache_line_size = 16; 202 break; 203 case PVR_403: 204 curcpu()->ci_ci.dcache_line_size = 16; 205 curcpu()->ci_ci.icache_line_size = 16; 206 break; 207 case PVR_405GP: 208 curcpu()->ci_ci.dcache_size = 8192; 209 curcpu()->ci_ci.dcache_line_size = 32; 210 curcpu()->ci_ci.icache_size = 8192; 211 curcpu()->ci_ci.icache_line_size = 32; 212 break; 213 default: 214 /* 215 * Unknown CPU type. For safety we'll specify a 216 * cache with a 4-byte line size. That way cache 217 * flush routines won't miss any lines. 218 */ 219 curcpu()->ci_ci.dcache_line_size = 4; 220 curcpu()->ci_ci.icache_line_size = 4; 221 break; 222 } 223 224 } 225 226 /* 227 * These small routines may have to be replaced, 228 * if/when we support processors other that the 604. 229 */ 230 231 void 232 dcache_flush_page(vaddr_t va) 233 { 234 int i; 235 236 if (curcpu()->ci_ci.dcache_line_size) 237 for (i = 0; i < NBPG; i += curcpu()->ci_ci.dcache_line_size) 238 asm volatile("dcbf %0,%1" : : "r" (va), "r" (i)); 239 asm volatile("sync;isync" : : ); 240 } 241 242 void 243 icache_flush_page(vaddr_t va) 244 { 245 int i; 246 247 if (curcpu()->ci_ci.icache_line_size) 248 for (i = 0; i < NBPG; i += curcpu()->ci_ci.icache_line_size) 249 asm volatile("icbi %0,%1" : : "r" (va), "r" (i)); 250 asm volatile("sync;isync" : : ); 251 } 252 253 void 254 dcache_flush(vaddr_t va, vsize_t len) 255 { 256 int i; 257 258 if (len == 0) 259 return; 260 261 /* Make sure we flush all cache lines */ 262 len += va & (curcpu()->ci_ci.dcache_line_size-1); 263 if (curcpu()->ci_ci.dcache_line_size) 264 for (i = 0; i < len; i += curcpu()->ci_ci.dcache_line_size) 265 asm volatile("dcbf %0,%1" : : "r" (va), "r" (i)); 266 asm volatile("sync;isync" : : ); 267 } 268 269 void 270 icache_flush(vaddr_t va, vsize_t len) 271 { 272 int i; 273 274 if (len == 0) 275 return; 276 277 /* Make sure we flush all cache lines */ 278 len += va & (curcpu()->ci_ci.icache_line_size-1); 279 if (curcpu()->ci_ci.icache_line_size) 280 for (i = 0; i < len; i += curcpu()->ci_ci.icache_line_size) 281 asm volatile("icbi %0,%1" : : "r" (va), "r" (i)); 282 asm volatile("sync;isync" : : ); 283 } 284