1178596Sraj/*- 2178596Sraj * Copyright (C) 2008 Semihalf, Rafal Jaworowski 3178596Sraj * All rights reserved. 4178596Sraj * 5178596Sraj * Redistribution and use in source and binary forms, with or without 6178596Sraj * modification, are permitted provided that the following conditions 7178596Sraj * are met: 8178596Sraj * 1. Redistributions of source code must retain the above copyright 9178596Sraj * notice, this list of conditions and the following disclaimer. 10178596Sraj * 2. Redistributions in binary form must reproduce the above copyright 11178596Sraj * notice, this list of conditions and the following disclaimer in the 12178596Sraj * documentation and/or other materials provided with the distribution. 13178596Sraj * 14178596Sraj * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15178596Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16178596Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17178596Sraj * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18178596Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19178596Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20178596Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21178596Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22178596Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23178596Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24178596Sraj * SUCH DAMAGE. 25178596Sraj */ 26178596Sraj 27178596Sraj#include <sys/cdefs.h> 28178596Sraj__FBSDID("$FreeBSD: releng/11.0/sys/powerpc/mpc85xx/mpc85xx.c 295908 2016-02-23 02:28:19Z jhibbits $"); 29178596Sraj 30291008Sjhibbits#include "opt_platform.h" 31178596Sraj#include <sys/param.h> 32178596Sraj#include <sys/systm.h> 33209908Sraj#include <sys/lock.h> 34209908Sraj#include <sys/mutex.h> 35292903Sjhibbits#include <sys/reboot.h> 36209908Sraj#include <sys/rman.h> 37178596Sraj 38178597Sraj#include <vm/vm.h> 39178597Sraj#include <vm/vm_param.h> 40292903Sjhibbits#include <vm/pmap.h> 41178597Sraj 42178596Sraj#include <machine/cpu.h> 43178596Sraj#include <machine/cpufunc.h> 44292903Sjhibbits#include <machine/machdep.h> 45234609Snwhitehorn#include <machine/pio.h> 46178596Sraj#include <machine/spr.h> 47178596Sraj 48257178Snwhitehorn#include <dev/fdt/fdt_common.h> 49257178Snwhitehorn 50292903Sjhibbits#include <dev/fdt/fdt_common.h> 51292903Sjhibbits#include <dev/ofw/ofw_bus.h> 52292903Sjhibbits#include <dev/ofw/ofw_bus_subr.h> 53292903Sjhibbits#include <dev/ofw/openfirm.h> 54292903Sjhibbits 55186227Sraj#include <powerpc/mpc85xx/mpc85xx.h> 56178597Sraj 57291008Sjhibbits 58178596Sraj/* 59178596Sraj * MPC85xx system specific routines 60178596Sraj */ 61178596Sraj 62186227Srajuint32_t 63186227Srajccsr_read4(uintptr_t addr) 64186227Sraj{ 65186227Sraj volatile uint32_t *ptr = (void *)addr; 66186227Sraj 67186227Sraj return (*ptr); 68186227Sraj} 69186227Sraj 70178596Srajvoid 71186227Srajccsr_write4(uintptr_t addr, uint32_t val) 72178596Sraj{ 73186227Sraj volatile uint32_t *ptr = (void *)addr; 74178596Sraj 75186227Sraj *ptr = val; 76234579Snwhitehorn powerpc_iomb(); 77186227Sraj} 78186227Sraj 79189757Srajint 80186288Srajlaw_getmax(void) 81186288Sraj{ 82186288Sraj uint32_t ver; 83291008Sjhibbits int law_max; 84186288Sraj 85186288Sraj ver = SVR_VER(mfspr(SPR_SVR)); 86291008Sjhibbits switch (ver) { 87291008Sjhibbits case SVR_MPC8555: 88291008Sjhibbits case SVR_MPC8555E: 89291008Sjhibbits law_max = 8; 90291008Sjhibbits break; 91291008Sjhibbits case SVR_MPC8533: 92291008Sjhibbits case SVR_MPC8533E: 93291008Sjhibbits case SVR_MPC8548: 94291008Sjhibbits case SVR_MPC8548E: 95291008Sjhibbits law_max = 10; 96291008Sjhibbits break; 97291008Sjhibbits case SVR_P5020: 98291008Sjhibbits case SVR_P5020E: 99291008Sjhibbits law_max = 32; 100291008Sjhibbits break; 101291008Sjhibbits default: 102291008Sjhibbits law_max = 8; 103291008Sjhibbits } 104222428Smarcel 105291008Sjhibbits return (law_max); 106186288Sraj} 107186288Sraj 108291008Sjhibbitsstatic inline void 109291008Sjhibbitslaw_write(uint32_t n, uint64_t bar, uint32_t sr) 110291008Sjhibbits{ 111291008Sjhibbits#if defined(QORIQ_DPAA) 112291008Sjhibbits ccsr_write4(OCP85XX_LAWBARH(n), bar >> 32); 113291008Sjhibbits ccsr_write4(OCP85XX_LAWBARL(n), bar); 114291008Sjhibbits#else 115291008Sjhibbits ccsr_write4(OCP85XX_LAWBAR(n), bar >> 12); 116291008Sjhibbits#endif 117291008Sjhibbits ccsr_write4(OCP85XX_LAWSR(n), sr); 118291008Sjhibbits 119291008Sjhibbits /* 120291008Sjhibbits * The last write to LAWAR should be followed by a read 121291008Sjhibbits * of LAWAR before any device try to use any of windows. 122291008Sjhibbits * What more the read of LAWAR should be followed by isync 123291008Sjhibbits * instruction. 124291008Sjhibbits */ 125291008Sjhibbits 126291008Sjhibbits ccsr_read4(OCP85XX_LAWSR(n)); 127291008Sjhibbits isync(); 128291008Sjhibbits} 129291008Sjhibbits 130291008Sjhibbitsstatic inline void 131291008Sjhibbitslaw_read(uint32_t n, uint64_t *bar, uint32_t *sr) 132291008Sjhibbits{ 133291008Sjhibbits#if defined(QORIQ_DPAA) 134291008Sjhibbits *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBARH(n)) << 32 | 135291008Sjhibbits ccsr_read4(OCP85XX_LAWBARL(n)); 136291008Sjhibbits#else 137291008Sjhibbits *bar = (uint64_t)ccsr_read4(OCP85XX_LAWBAR(n)) << 12; 138291008Sjhibbits#endif 139291008Sjhibbits *sr = ccsr_read4(OCP85XX_LAWSR(n)); 140291008Sjhibbits} 141291008Sjhibbits 142291008Sjhibbitsstatic int 143291008Sjhibbitslaw_find_free(void) 144291008Sjhibbits{ 145291008Sjhibbits uint32_t i,sr; 146291008Sjhibbits uint64_t bar; 147291008Sjhibbits int law_max; 148291008Sjhibbits 149291008Sjhibbits law_max = law_getmax(); 150291008Sjhibbits /* Find free LAW */ 151291008Sjhibbits for (i = 0; i < law_max; i++) { 152291008Sjhibbits law_read(i, &bar, &sr); 153291008Sjhibbits if ((sr & 0x80000000) == 0) 154291008Sjhibbits break; 155291008Sjhibbits } 156291008Sjhibbits 157291008Sjhibbits return (i); 158291008Sjhibbits} 159291008Sjhibbits 160295908Sjhibbits#define _LAW_SR(trgt,size) (0x80000000 | (trgt << 20) | \ 161295908Sjhibbits (flsl(size + (size - 1)) - 2)) 162186288Sraj 163186288Srajint 164291008Sjhibbitslaw_enable(int trgt, uint64_t bar, uint32_t size) 165186288Sraj{ 166291008Sjhibbits uint64_t bar_tmp; 167291008Sjhibbits uint32_t sr, sr_tmp; 168186288Sraj int i, law_max; 169186288Sraj 170235934Smarcel if (size == 0) 171235934Smarcel return (0); 172235934Smarcel 173186288Sraj law_max = law_getmax(); 174186288Sraj sr = _LAW_SR(trgt, size); 175186288Sraj 176186288Sraj /* Bail if already programmed. */ 177291008Sjhibbits for (i = 0; i < law_max; i++) { 178291008Sjhibbits law_read(i, &bar_tmp, &sr_tmp); 179291008Sjhibbits if (sr == sr_tmp && bar == bar_tmp) 180186288Sraj return (0); 181291008Sjhibbits } 182186288Sraj 183186288Sraj /* Find an unused access window. */ 184291008Sjhibbits i = law_find_free(); 185186288Sraj 186186288Sraj if (i == law_max) 187186288Sraj return (ENOSPC); 188186288Sraj 189291008Sjhibbits law_write(i, bar, sr); 190186288Sraj return (0); 191186288Sraj} 192186288Sraj 193186288Srajint 194291008Sjhibbitslaw_disable(int trgt, uint64_t bar, uint32_t size) 195186288Sraj{ 196291008Sjhibbits uint64_t bar_tmp; 197291008Sjhibbits uint32_t sr, sr_tmp; 198186288Sraj int i, law_max; 199186288Sraj 200186288Sraj law_max = law_getmax(); 201186288Sraj sr = _LAW_SR(trgt, size); 202186288Sraj 203186288Sraj /* Find and disable requested LAW. */ 204291008Sjhibbits for (i = 0; i < law_max; i++) { 205291008Sjhibbits law_read(i, &bar_tmp, &sr_tmp); 206291008Sjhibbits if (sr == sr_tmp && bar == bar_tmp) { 207291008Sjhibbits law_write(i, 0, 0); 208186288Sraj return (0); 209186288Sraj } 210291008Sjhibbits } 211186288Sraj 212186288Sraj return (ENOENT); 213186288Sraj} 214186288Sraj 215209908Srajint 216209908Srajlaw_pci_target(struct resource *res, int *trgt_mem, int *trgt_io) 217209908Sraj{ 218209908Sraj u_long start; 219209908Sraj uint32_t ver; 220209908Sraj int trgt, rv; 221209908Sraj 222209908Sraj ver = SVR_VER(mfspr(SPR_SVR)); 223209908Sraj 224209908Sraj start = rman_get_start(res) & 0xf000; 225209908Sraj 226209908Sraj rv = 0; 227209908Sraj trgt = -1; 228209908Sraj switch (start) { 229291008Sjhibbits case 0x0000: 230209908Sraj case 0x8000: 231209908Sraj trgt = 0; 232209908Sraj break; 233291008Sjhibbits case 0x1000: 234209908Sraj case 0x9000: 235209908Sraj trgt = 1; 236209908Sraj break; 237291008Sjhibbits case 0x2000: 238209908Sraj case 0xa000: 239222428Smarcel if (ver == SVR_MPC8548E || ver == SVR_MPC8548) 240222428Smarcel trgt = 3; 241222428Smarcel else 242209908Sraj trgt = 2; 243222428Smarcel break; 244291008Sjhibbits case 0x3000: 245222428Smarcel case 0xb000: 246222428Smarcel if (ver == SVR_MPC8548E || ver == SVR_MPC8548) 247222428Smarcel rv = EINVAL; 248209908Sraj else 249222428Smarcel trgt = 3; 250209908Sraj break; 251209908Sraj default: 252209908Sraj rv = ENXIO; 253209908Sraj } 254235934Smarcel if (rv == 0) { 255235934Smarcel *trgt_mem = trgt; 256235934Smarcel *trgt_io = trgt; 257235934Smarcel } 258209908Sraj return (rv); 259209908Sraj} 260209908Sraj 261292903Sjhibbitsstatic void 262292903Sjhibbitsl3cache_inval(void) 263292903Sjhibbits{ 264292903Sjhibbits 265292903Sjhibbits /* Flash invalidate the CPC and clear all the locks */ 266292903Sjhibbits ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_FI | 267292903Sjhibbits OCP85XX_CPC_CSR0_LFC); 268292903Sjhibbits while (ccsr_read4(OCP85XX_CPC_CSR0) & (OCP85XX_CPC_CSR0_FI | 269292903Sjhibbits OCP85XX_CPC_CSR0_LFC)) 270292903Sjhibbits ; 271292903Sjhibbits} 272292903Sjhibbits 273292903Sjhibbitsstatic void 274292903Sjhibbitsl3cache_enable(void) 275292903Sjhibbits{ 276292903Sjhibbits 277292903Sjhibbits ccsr_write4(OCP85XX_CPC_CSR0, OCP85XX_CPC_CSR0_CE | 278292903Sjhibbits OCP85XX_CPC_CSR0_PE); 279292903Sjhibbits /* Read back to sync write */ 280292903Sjhibbits ccsr_read4(OCP85XX_CPC_CSR0); 281292903Sjhibbits} 282292903Sjhibbits 283292903Sjhibbitsvoid 284292903Sjhibbitsmpc85xx_enable_l3_cache(void) 285292903Sjhibbits{ 286292903Sjhibbits uint32_t csr, size, ver; 287292903Sjhibbits 288292903Sjhibbits /* Enable L3 CoreNet Platform Cache (CPC) */ 289292903Sjhibbits ver = SVR_VER(mfspr(SPR_SVR)); 290292903Sjhibbits if (ver == SVR_P2041 || ver == SVR_P2041E || ver == SVR_P3041 || 291292903Sjhibbits ver == SVR_P3041E || ver == SVR_P5020 || ver == SVR_P5020E) { 292292903Sjhibbits csr = ccsr_read4(OCP85XX_CPC_CSR0); 293292903Sjhibbits if ((csr & OCP85XX_CPC_CSR0_CE) == 0) { 294292903Sjhibbits l3cache_inval(); 295292903Sjhibbits l3cache_enable(); 296292903Sjhibbits } 297292903Sjhibbits 298292903Sjhibbits csr = ccsr_read4(OCP85XX_CPC_CSR0); 299292903Sjhibbits if ((boothowto & RB_VERBOSE) != 0 || 300292903Sjhibbits (csr & OCP85XX_CPC_CSR0_CE) == 0) { 301292903Sjhibbits size = OCP85XX_CPC_CFG0_SZ_K(ccsr_read4(OCP85XX_CPC_CFG0)); 302292903Sjhibbits printf("L3 Corenet Platform Cache: %d KB %sabled\n", 303292903Sjhibbits size, (csr & OCP85XX_CPC_CSR0_CE) == 0 ? 304292903Sjhibbits "dis" : "en"); 305292903Sjhibbits } 306292903Sjhibbits } 307292903Sjhibbits} 308292903Sjhibbits 309292903Sjhibbitsstatic void 310292903Sjhibbitsmpc85xx_dataloss_erratum_spr976(void) 311292903Sjhibbits{ 312292903Sjhibbits uint32_t svr = SVR_VER(mfspr(SPR_SVR)); 313292903Sjhibbits 314292903Sjhibbits /* Ignore whether it's the E variant */ 315292903Sjhibbits svr &= ~0x8; 316292903Sjhibbits 317292903Sjhibbits if (svr != SVR_P3041 && svr != SVR_P4040 && 318292903Sjhibbits svr != SVR_P4080 && svr != SVR_P5020) 319292903Sjhibbits return; 320292903Sjhibbits 321292903Sjhibbits mb(); 322292903Sjhibbits isync(); 323292903Sjhibbits mtspr(976, (mfspr(976) & ~0x1f8) | 0x48); 324292903Sjhibbits isync(); 325292903Sjhibbits} 326292903Sjhibbits 327292903Sjhibbitsstatic vm_offset_t 328292903Sjhibbitsmpc85xx_map_dcsr(void) 329292903Sjhibbits{ 330292903Sjhibbits phandle_t node; 331292903Sjhibbits u_long b, s; 332292903Sjhibbits int err; 333292903Sjhibbits 334292903Sjhibbits /* 335292903Sjhibbits * Try to access the dcsr node directly i.e. through /aliases/. 336292903Sjhibbits */ 337292903Sjhibbits if ((node = OF_finddevice("dcsr")) != -1) 338292903Sjhibbits if (fdt_is_compatible_strict(node, "fsl,dcsr")) 339292903Sjhibbits goto moveon; 340292903Sjhibbits /* 341292903Sjhibbits * Find the node the long way. 342292903Sjhibbits */ 343292903Sjhibbits if ((node = OF_finddevice("/")) == -1) 344292903Sjhibbits return (ENXIO); 345292903Sjhibbits 346292903Sjhibbits if ((node = ofw_bus_find_compatible(node, "fsl,dcsr")) == 0) 347292903Sjhibbits return (ENXIO); 348292903Sjhibbits 349292903Sjhibbitsmoveon: 350292903Sjhibbits err = fdt_get_range(node, 0, &b, &s); 351292903Sjhibbits 352292903Sjhibbits if (err != 0) 353292903Sjhibbits return (err); 354292903Sjhibbits 355292903Sjhibbits#ifdef QORIQ_DPAA 356292903Sjhibbits law_enable(OCP85XX_TGTIF_DCSR, b, 0x400000); 357292903Sjhibbits#endif 358292903Sjhibbits return pmap_early_io_map(b, 0x400000); 359292903Sjhibbits} 360292903Sjhibbits 361292903Sjhibbits 362292903Sjhibbits 363292903Sjhibbitsvoid 364292903Sjhibbitsmpc85xx_fix_errata(vm_offset_t va_ccsr) 365292903Sjhibbits{ 366292903Sjhibbits uint32_t svr = SVR_VER(mfspr(SPR_SVR)); 367292903Sjhibbits vm_offset_t va_dcsr; 368292903Sjhibbits 369292903Sjhibbits /* Ignore whether it's the E variant */ 370292903Sjhibbits svr &= ~0x8; 371292903Sjhibbits 372292903Sjhibbits if (svr != SVR_P3041 && svr != SVR_P4040 && 373292903Sjhibbits svr != SVR_P4080 && svr != SVR_P5020) 374292903Sjhibbits return; 375292903Sjhibbits 376292903Sjhibbits if (mfmsr() & PSL_EE) 377292903Sjhibbits return; 378292903Sjhibbits 379292903Sjhibbits /* 380292903Sjhibbits * dcsr region need to be mapped thus patch can refer to. 381292903Sjhibbits * Align dcsr right after ccsbar. 382292903Sjhibbits */ 383292903Sjhibbits va_dcsr = mpc85xx_map_dcsr(); 384292903Sjhibbits if (va_dcsr == 0) 385292903Sjhibbits goto err; 386292903Sjhibbits 387292903Sjhibbits /* 388292903Sjhibbits * As A004510 errata specify, special purpose register 976 389292903Sjhibbits * SPR976[56:60] = 6'b001001 must be set. e500mc core reference manual 390292903Sjhibbits * does not document SPR976 register. 391292903Sjhibbits */ 392292903Sjhibbits mpc85xx_dataloss_erratum_spr976(); 393292903Sjhibbits 394292903Sjhibbits /* 395292903Sjhibbits * Specific settings in the CCF and core platform cache (CPC) 396292903Sjhibbits * are required to reconfigure the CoreNet coherency fabric. 397292903Sjhibbits * The register settings that should be updated are described 398292903Sjhibbits * in errata and relay on base address, offset and updated value. 399292903Sjhibbits * Special conditions must be used to update these registers correctly. 400292903Sjhibbits */ 401292903Sjhibbits dataloss_erratum_access(va_dcsr + 0xb0e08, 0xe0201800); 402292903Sjhibbits dataloss_erratum_access(va_dcsr + 0xb0e18, 0xe0201800); 403292903Sjhibbits dataloss_erratum_access(va_dcsr + 0xb0e38, 0xe0400000); 404292903Sjhibbits dataloss_erratum_access(va_dcsr + 0xb0008, 0x00900000); 405292903Sjhibbits dataloss_erratum_access(va_dcsr + 0xb0e40, 0xe00a0000); 406292903Sjhibbits 407292903Sjhibbits switch (svr) { 408292903Sjhibbits case SVR_P5020: 409292903Sjhibbits dataloss_erratum_access(va_ccsr + 0x18600, 0xc0000000); 410292903Sjhibbits break; 411292903Sjhibbits case SVR_P4040: 412292903Sjhibbits case SVR_P4080: 413292903Sjhibbits dataloss_erratum_access(va_ccsr + 0x18600, 0xff000000); 414292903Sjhibbits break; 415292903Sjhibbits case SVR_P3041: 416292903Sjhibbits dataloss_erratum_access(va_ccsr + 0x18600, 0xf0000000); 417292903Sjhibbits } 418292903Sjhibbits dataloss_erratum_access(va_ccsr + 0x10f00, 0x415e5000); 419292903Sjhibbits dataloss_erratum_access(va_ccsr + 0x11f00, 0x415e5000); 420292903Sjhibbits 421292903Sjhibbitserr: 422292903Sjhibbits return; 423292903Sjhibbits} 424