Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2013 Imagination Technologies
0004  * Author: Paul Burton <paul.burton@mips.com>
0005  */
0006 
0007 #include <linux/bitfield.h>
0008 #include <linux/errno.h>
0009 #include <linux/percpu.h>
0010 #include <linux/of.h>
0011 #include <linux/of_address.h>
0012 #include <linux/spinlock.h>
0013 
0014 #include <asm/mips-cps.h>
0015 
0016 void __iomem *mips_cpc_base;
0017 
0018 static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock);
0019 
0020 static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags);
0021 
0022 phys_addr_t __weak mips_cpc_default_phys_base(void)
0023 {
0024     struct device_node *cpc_node;
0025     struct resource res;
0026     int err;
0027 
0028     cpc_node = of_find_compatible_node(of_root, NULL, "mti,mips-cpc");
0029     if (cpc_node) {
0030         err = of_address_to_resource(cpc_node, 0, &res);
0031         of_node_put(cpc_node);
0032         if (!err)
0033             return res.start;
0034     }
0035 
0036     return 0;
0037 }
0038 
0039 /**
0040  * mips_cpc_phys_base - retrieve the physical base address of the CPC
0041  *
0042  * This function returns the physical base address of the Cluster Power
0043  * Controller memory mapped registers, or 0 if no Cluster Power Controller
0044  * is present.
0045  */
0046 static phys_addr_t mips_cpc_phys_base(void)
0047 {
0048     unsigned long cpc_base;
0049 
0050     if (!mips_cm_present())
0051         return 0;
0052 
0053     if (!(read_gcr_cpc_status() & CM_GCR_CPC_STATUS_EX))
0054         return 0;
0055 
0056     /* If the CPC is already enabled, leave it so */
0057     cpc_base = read_gcr_cpc_base();
0058     if (cpc_base & CM_GCR_CPC_BASE_CPCEN)
0059         return cpc_base & CM_GCR_CPC_BASE_CPCBASE;
0060 
0061     /* Otherwise, use the default address */
0062     cpc_base = mips_cpc_default_phys_base();
0063     if (!cpc_base)
0064         return cpc_base;
0065 
0066     /* Enable the CPC, mapped at the default address */
0067     write_gcr_cpc_base(cpc_base | CM_GCR_CPC_BASE_CPCEN);
0068     return cpc_base;
0069 }
0070 
0071 int mips_cpc_probe(void)
0072 {
0073     phys_addr_t addr;
0074     unsigned int cpu;
0075 
0076     for_each_possible_cpu(cpu)
0077         spin_lock_init(&per_cpu(cpc_core_lock, cpu));
0078 
0079     addr = mips_cpc_phys_base();
0080     if (!addr)
0081         return -ENODEV;
0082 
0083     mips_cpc_base = ioremap(addr, 0x8000);
0084     if (!mips_cpc_base)
0085         return -ENXIO;
0086 
0087     return 0;
0088 }
0089 
0090 void mips_cpc_lock_other(unsigned int core)
0091 {
0092     unsigned int curr_core;
0093 
0094     if (mips_cm_revision() >= CM_REV_CM3)
0095         /* Systems with CM >= 3 lock the CPC via mips_cm_lock_other */
0096         return;
0097 
0098     preempt_disable();
0099     curr_core = cpu_core(&current_cpu_data);
0100     spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core),
0101               per_cpu(cpc_core_lock_flags, curr_core));
0102     write_cpc_cl_other(FIELD_PREP(CPC_Cx_OTHER_CORENUM, core));
0103 
0104     /*
0105      * Ensure the core-other region reflects the appropriate core &
0106      * VP before any accesses to it occur.
0107      */
0108     mb();
0109 }
0110 
0111 void mips_cpc_unlock_other(void)
0112 {
0113     unsigned int curr_core;
0114 
0115     if (mips_cm_revision() >= CM_REV_CM3)
0116         /* Systems with CM >= 3 lock the CPC via mips_cm_lock_other */
0117         return;
0118 
0119     curr_core = cpu_core(&current_cpu_data);
0120     spin_unlock_irqrestore(&per_cpu(cpc_core_lock, curr_core),
0121                    per_cpu(cpc_core_lock_flags, curr_core));
0122     preempt_enable();
0123 }