1 /* 2 * Copyright (C) 2013 Imagination Technologies 3 * Author: Paul Burton <paul.burton@mips.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 #include <linux/percpu.h> 13 #include <linux/spinlock.h> 14 15 #include <asm/mips-cps.h> 16 17 void __iomem *mips_cpc_base; 18 19 static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); 20 21 static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); 22 23 phys_addr_t __weak mips_cpc_default_phys_base(void) 24 { 25 return 0; 26 } 27 28 /** 29 * mips_cpc_phys_base - retrieve the physical base address of the CPC 30 * 31 * This function returns the physical base address of the Cluster Power 32 * Controller memory mapped registers, or 0 if no Cluster Power Controller 33 * is present. 34 */ 35 static phys_addr_t mips_cpc_phys_base(void) 36 { 37 unsigned long cpc_base; 38 39 if (!mips_cm_present()) 40 return 0; 41 42 if (!(read_gcr_cpc_status() & CM_GCR_CPC_STATUS_EX)) 43 return 0; 44 45 /* If the CPC is already enabled, leave it so */ 46 cpc_base = read_gcr_cpc_base(); 47 if (cpc_base & CM_GCR_CPC_BASE_CPCEN) 48 return cpc_base & CM_GCR_CPC_BASE_CPCBASE; 49 50 /* Otherwise, use the default address */ 51 cpc_base = mips_cpc_default_phys_base(); 52 if (!cpc_base) 53 return cpc_base; 54 55 /* Enable the CPC, mapped at the default address */ 56 write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN); 57 return cpc_base; 58 } 59 60 int mips_cpc_probe(void) 61 { 62 phys_addr_t addr; 63 unsigned int cpu; 64 65 for_each_possible_cpu(cpu) 66 spin_lock_init(&per_cpu(cpc_core_lock, cpu)); 67 68 addr = mips_cpc_phys_base(); 69 if (!addr) 70 return -ENODEV; 71 72 mips_cpc_base = ioremap_nocache(addr, 0x8000); 73 if (!mips_cpc_base) 74 return -ENXIO; 75 76 return 0; 77 } 78 79 void mips_cpc_lock_other(unsigned int core) 80 { 81 unsigned int curr_core; 82 83 if (mips_cm_revision() >= CM_REV_CM3) 84 /* Systems with CM >= 3 lock the CPC via mips_cm_lock_other */ 85 return; 86 87 preempt_disable(); 88 curr_core = cpu_core(¤t_cpu_data); 89 spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core), 90 per_cpu(cpc_core_lock_flags, curr_core)); 91 write_cpc_cl_other(core << __ffs(CPC_Cx_OTHER_CORENUM)); 92 93 /* 94 * Ensure the core-other region reflects the appropriate core & 95 * VP before any accesses to it occur. 96 */ 97 mb(); 98 } 99 100 void mips_cpc_unlock_other(void) 101 { 102 unsigned int curr_core; 103 104 if (mips_cm_revision() >= CM_REV_CM3) 105 /* Systems with CM >= 3 lock the CPC via mips_cm_lock_other */ 106 return; 107 108 curr_core = cpu_core(¤t_cpu_data); 109 spin_unlock_irqrestore(&per_cpu(cpc_core_lock, curr_core), 110 per_cpu(cpc_core_lock_flags, curr_core)); 111 preempt_enable(); 112 } 113