1/* 2 * Copyright (C) 2013 Imagination Technologies 3 * Author: Paul Burton <paul.burton@imgtec.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the 7 * Free Software Foundation; either version 2 of the License, or (at your 8 * option) any later version. 9 */ 10 11#include <linux/errno.h> 12 13#include <asm/mips-cm.h> 14#include <asm/mipsregs.h> 15 16void __iomem *mips_cm_base; 17void __iomem *mips_cm_l2sync_base; 18 19phys_addr_t __mips_cm_phys_base(void) 20{ 21 u32 config3 = read_c0_config3(); 22 u32 cmgcr; 23 24 /* Check the CMGCRBase register is implemented */ 25 if (!(config3 & MIPS_CONF3_CMGCR)) 26 return 0; 27 28 /* Read the address from CMGCRBase */ 29 cmgcr = read_c0_cmgcrbase(); 30 return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); 31} 32 33phys_addr_t mips_cm_phys_base(void) 34 __attribute__((weak, alias("__mips_cm_phys_base"))); 35 36phys_addr_t __mips_cm_l2sync_phys_base(void) 37{ 38 u32 base_reg; 39 40 /* 41 * If the L2-only sync region is already enabled then leave it at it's 42 * current location. 43 */ 44 base_reg = read_gcr_l2_only_sync_base(); 45 if (base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK) 46 return base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK; 47 48 /* Default to following the CM */ 49 return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; 50} 51 52phys_addr_t mips_cm_l2sync_phys_base(void) 53 __attribute__((weak, alias("__mips_cm_l2sync_phys_base"))); 54 55static void mips_cm_probe_l2sync(void) 56{ 57 unsigned major_rev; 58 phys_addr_t addr; 59 60 /* L2-only sync was introduced with CM major revision 6 */ 61 major_rev = (read_gcr_rev() & CM_GCR_REV_MAJOR_MSK) >> 62 CM_GCR_REV_MAJOR_SHF; 63 if (major_rev < 6) 64 return; 65 66 /* Find a location for the L2 sync region */ 67 addr = mips_cm_l2sync_phys_base(); 68 BUG_ON((addr & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE_MSK) != addr); 69 if (!addr) 70 return; 71 72 /* Set the region base address & enable it */ 73 write_gcr_l2_only_sync_base(addr | CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN_MSK); 74 75 /* Map the region */ 76 mips_cm_l2sync_base = ioremap_nocache(addr, MIPS_CM_L2SYNC_SIZE); 77} 78 79int mips_cm_probe(void) 80{ 81 phys_addr_t addr; 82 u32 base_reg; 83 84 addr = mips_cm_phys_base(); 85 BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr); 86 if (!addr) 87 return -ENODEV; 88 89 mips_cm_base = ioremap_nocache(addr, MIPS_CM_GCR_SIZE); 90 if (!mips_cm_base) 91 return -ENXIO; 92 93 /* sanity check that we're looking at a CM */ 94 base_reg = read_gcr_base(); 95 if ((base_reg & CM_GCR_BASE_GCRBASE_MSK) != addr) { 96 pr_err("GCRs appear to have been moved (expected them at 0x%08lx)!\n", 97 (unsigned long)addr); 98 mips_cm_base = NULL; 99 return -ENODEV; 100 } 101 102 /* set default target to memory */ 103 base_reg &= ~CM_GCR_BASE_CMDEFTGT_MSK; 104 base_reg |= CM_GCR_BASE_CMDEFTGT_MEM; 105 write_gcr_base(base_reg); 106 107 /* disable CM regions */ 108 write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR_MSK); 109 write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK); 110 write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR_MSK); 111 write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK); 112 write_gcr_reg2_base(CM_GCR_REGn_BASE_BASEADDR_MSK); 113 write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK); 114 write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR_MSK); 115 write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK_MSK); 116 117 /* probe for an L2-only sync region */ 118 mips_cm_probe_l2sync(); 119 120 return 0; 121} 122