~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-versatile/spc.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Versatile Express Serial Power Controller (SPC) support
  4  *
  5  * Copyright (C) 2013 ARM Ltd.
  6  *
  7  * Authors: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
  8  *          Achin Gupta           <achin.gupta@arm.com>
  9  *          Lorenzo Pieralisi     <lorenzo.pieralisi@arm.com>
 10  */
 11 
 12 #include <linux/clk-provider.h>
 13 #include <linux/clkdev.h>
 14 #include <linux/cpu.h>
 15 #include <linux/delay.h>
 16 #include <linux/err.h>
 17 #include <linux/interrupt.h>
 18 #include <linux/io.h>
 19 #include <linux/platform_device.h>
 20 #include <linux/pm_opp.h>
 21 #include <linux/slab.h>
 22 #include <linux/semaphore.h>
 23 
 24 #include <asm/cacheflush.h>
 25 
 26 #include "spc.h"
 27 
 28 #define SPCLOG "vexpress-spc: "
 29 
 30 #define PERF_LVL_A15            0x00
 31 #define PERF_REQ_A15            0x04
 32 #define PERF_LVL_A7             0x08
 33 #define PERF_REQ_A7             0x0c
 34 #define COMMS                   0x10
 35 #define COMMS_REQ               0x14
 36 #define PWC_STATUS              0x18
 37 #define PWC_FLAG                0x1c
 38 
 39 /* SPC wake-up IRQs status and mask */
 40 #define WAKE_INT_MASK           0x24
 41 #define WAKE_INT_RAW            0x28
 42 #define WAKE_INT_STAT           0x2c
 43 /* SPC power down registers */
 44 #define A15_PWRDN_EN            0x30
 45 #define A7_PWRDN_EN             0x34
 46 /* SPC per-CPU mailboxes */
 47 #define A15_BX_ADDR0            0x68
 48 #define A7_BX_ADDR0             0x78
 49 
 50 /* SPC CPU/cluster reset statue */
 51 #define STANDBYWFI_STAT         0x3c
 52 #define STANDBYWFI_STAT_A15_CPU_MASK(cpu)       (1 << (cpu))
 53 #define STANDBYWFI_STAT_A7_CPU_MASK(cpu)        (1 << (3 + (cpu)))
 54 
 55 /* SPC system config interface registers */
 56 #define SYSCFG_WDATA            0x70
 57 #define SYSCFG_RDATA            0x74
 58 
 59 /* A15/A7 OPP virtual register base */
 60 #define A15_PERFVAL_BASE        0xC10
 61 #define A7_PERFVAL_BASE         0xC30
 62 
 63 /* Config interface control bits */
 64 #define SYSCFG_START            BIT(31)
 65 #define SYSCFG_SCC              (6 << 20)
 66 #define SYSCFG_STAT             (14 << 20)
 67 
 68 /* wake-up interrupt masks */
 69 #define GBL_WAKEUP_INT_MSK      (0x3 << 10)
 70 
 71 /* TC2 static dual-cluster configuration */
 72 #define MAX_CLUSTERS            2
 73 
 74 /*
 75  * Even though the SPC takes max 3-5 ms to complete any OPP/COMMS
 76  * operation, the operation could start just before jiffie is about
 77  * to be incremented. So setting timeout value of 20ms = 2jiffies@100Hz
 78  */
 79 #define TIMEOUT_US      20000
 80 
 81 #define MAX_OPPS        8
 82 #define CA15_DVFS       0
 83 #define CA7_DVFS        1
 84 #define SPC_SYS_CFG     2
 85 #define STAT_COMPLETE(type)     ((1 << 0) << (type << 2))
 86 #define STAT_ERR(type)          ((1 << 1) << (type << 2))
 87 #define RESPONSE_MASK(type)     (STAT_COMPLETE(type) | STAT_ERR(type))
 88 
 89 struct ve_spc_opp {
 90         unsigned long freq;
 91         unsigned long u_volt;
 92 };
 93 
 94 struct ve_spc_drvdata {
 95         void __iomem *baseaddr;
 96         /*
 97          * A15s cluster identifier
 98          * It corresponds to A15 processors MPIDR[15:8] bitfield
 99          */
100         u32 a15_clusid;
101         uint32_t cur_rsp_mask;
102         uint32_t cur_rsp_stat;
103         struct semaphore sem;
104         struct completion done;
105         struct ve_spc_opp *opps[MAX_CLUSTERS];
106         int num_opps[MAX_CLUSTERS];
107 };
108 
109 static struct ve_spc_drvdata *info;
110 
111 static inline bool cluster_is_a15(u32 cluster)
112 {
113         return cluster == info->a15_clusid;
114 }
115 
116 /**
117  * ve_spc_global_wakeup_irq() - sets/clears global wakeup IRQs
118  *
119  * @set: if true, global wake-up IRQs are set, if false they are cleared
120  *
121  * Function to set/clear global wakeup IRQs. Not protected by locking since
122  * it might be used in code paths where normal cacheable locks are not
123  * working. Locking must be provided by the caller to ensure atomicity.
124  */
125 void ve_spc_global_wakeup_irq(bool set)
126 {
127         u32 reg;
128 
129         reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK);
130 
131         if (set)
132                 reg |= GBL_WAKEUP_INT_MSK;
133         else
134                 reg &= ~GBL_WAKEUP_INT_MSK;
135 
136         writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK);
137 }
138 
139 /**
140  * ve_spc_cpu_wakeup_irq() - sets/clears per-CPU wake-up IRQs
141  *
142  * @cluster: mpidr[15:8] bitfield describing cluster affinity level
143  * @cpu: mpidr[7:0] bitfield describing cpu affinity level
144  * @set: if true, wake-up IRQs are set, if false they are cleared
145  *
146  * Function to set/clear per-CPU wake-up IRQs. Not protected by locking since
147  * it might be used in code paths where normal cacheable locks are not
148  * working. Locking must be provided by the caller to ensure atomicity.
149  */
150 void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set)
151 {
152         u32 mask, reg;
153 
154         if (cluster >= MAX_CLUSTERS)
155                 return;
156 
157         mask = BIT(cpu);
158 
159         if (!cluster_is_a15(cluster))
160                 mask <<= 4;
161 
162         reg = readl_relaxed(info->baseaddr + WAKE_INT_MASK);
163 
164         if (set)
165                 reg |= mask;
166         else
167                 reg &= ~mask;
168 
169         writel_relaxed(reg, info->baseaddr + WAKE_INT_MASK);
170 }
171 
172 /**
173  * ve_spc_set_resume_addr() - set the jump address used for warm boot
174  *
175  * @cluster: mpidr[15:8] bitfield describing cluster affinity level
176  * @cpu: mpidr[7:0] bitfield describing cpu affinity level
177  * @addr: physical resume address
178  */
179 void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr)
180 {
181         void __iomem *baseaddr;
182 
183         if (cluster >= MAX_CLUSTERS)
184                 return;
185 
186         if (cluster_is_a15(cluster))
187                 baseaddr = info->baseaddr + A15_BX_ADDR0 + (cpu << 2);
188         else
189                 baseaddr = info->baseaddr + A7_BX_ADDR0 + (cpu << 2);
190 
191         writel_relaxed(addr, baseaddr);
192 }
193 
194 /**
195  * ve_spc_powerdown() - enables/disables cluster powerdown
196  *
197  * @cluster: mpidr[15:8] bitfield describing cluster affinity level
198  * @enable: if true enables powerdown, if false disables it
199  *
200  * Function to enable/disable cluster powerdown. Not protected by locking
201  * since it might be used in code paths where normal cacheable locks are not
202  * working. Locking must be provided by the caller to ensure atomicity.
203  */
204 void ve_spc_powerdown(u32 cluster, bool enable)
205 {
206         u32 pwdrn_reg;
207 
208         if (cluster >= MAX_CLUSTERS)
209                 return;
210 
211         pwdrn_reg = cluster_is_a15(cluster) ? A15_PWRDN_EN : A7_PWRDN_EN;
212         writel_relaxed(enable, info->baseaddr + pwdrn_reg);
213 }
214 
215 static u32 standbywfi_cpu_mask(u32 cpu, u32 cluster)
216 {
217         return cluster_is_a15(cluster) ?
218                   STANDBYWFI_STAT_A15_CPU_MASK(cpu)
219                 : STANDBYWFI_STAT_A7_CPU_MASK(cpu);
220 }
221 
222 /**
223  * ve_spc_cpu_in_wfi() - Checks if the specified CPU is in WFI or not
224  *
225  * @cpu: mpidr[7:0] bitfield describing CPU affinity level within cluster
226  * @cluster: mpidr[15:8] bitfield describing cluster affinity level
227  *
228  * @return: non-zero if and only if the specified CPU is in WFI
229  *
230  * Take care when interpreting the result of this function: a CPU might
231  * be in WFI temporarily due to idle, and is not necessarily safely
232  * parked.
233  */
234 int ve_spc_cpu_in_wfi(u32 cpu, u32 cluster)
235 {
236         int ret;
237         u32 mask = standbywfi_cpu_mask(cpu, cluster);
238 
239         if (cluster >= MAX_CLUSTERS)
240                 return 1;
241 
242         ret = readl_relaxed(info->baseaddr + STANDBYWFI_STAT);
243 
244         pr_debug("%s: PCFGREG[0x%X] = 0x%08X, mask = 0x%X\n",
245                  __func__, STANDBYWFI_STAT, ret, mask);
246 
247         return ret & mask;
248 }
249 
250 static int ve_spc_get_performance(int cluster, u32 *freq)
251 {
252         struct ve_spc_opp *opps = info->opps[cluster];
253         u32 perf_cfg_reg = 0;
254         u32 perf;
255 
256         perf_cfg_reg = cluster_is_a15(cluster) ? PERF_LVL_A15 : PERF_LVL_A7;
257 
258         perf = readl_relaxed(info->baseaddr + perf_cfg_reg);
259         if (perf >= info->num_opps[cluster])
260                 return -EINVAL;
261 
262         opps += perf;
263         *freq = opps->freq;
264 
265         return 0;
266 }
267 
268 /* find closest match to given frequency in OPP table */
269 static int ve_spc_round_performance(int cluster, u32 freq)
270 {
271         int idx, max_opp = info->num_opps[cluster];
272         struct ve_spc_opp *opps = info->opps[cluster];
273         u32 fmin = 0, fmax = ~0, ftmp;
274 
275         freq /= 1000; /* OPP entries in kHz */
276         for (idx = 0; idx < max_opp; idx++, opps++) {
277                 ftmp = opps->freq;
278                 if (ftmp >= freq) {
279                         if (ftmp <= fmax)
280                                 fmax = ftmp;
281                 } else {
282                         if (ftmp >= fmin)
283                                 fmin = ftmp;
284                 }
285         }
286         if (fmax != ~0)
287                 return fmax * 1000;
288         else
289                 return fmin * 1000;
290 }
291 
292 static int ve_spc_find_performance_index(int cluster, u32 freq)
293 {
294         int idx, max_opp = info->num_opps[cluster];
295         struct ve_spc_opp *opps = info->opps[cluster];
296 
297         for (idx = 0; idx < max_opp; idx++, opps++)
298                 if (opps->freq == freq)
299                         break;
300         return (idx == max_opp) ? -EINVAL : idx;
301 }
302 
303 static int ve_spc_waitforcompletion(int req_type)
304 {
305         int ret = wait_for_completion_interruptible_timeout(
306                         &info->done, usecs_to_jiffies(TIMEOUT_US));
307         if (ret == 0)
308                 ret = -ETIMEDOUT;
309         else if (ret > 0)
310                 ret = info->cur_rsp_stat & STAT_COMPLETE(req_type) ? 0 : -EIO;
311         return ret;
312 }
313 
314 static int ve_spc_set_performance(int cluster, u32 freq)
315 {
316         u32 perf_cfg_reg;
317         int ret, perf, req_type;
318 
319         if (cluster_is_a15(cluster)) {
320                 req_type = CA15_DVFS;
321                 perf_cfg_reg = PERF_LVL_A15;
322         } else {
323                 req_type = CA7_DVFS;
324                 perf_cfg_reg = PERF_LVL_A7;
325         }
326 
327         perf = ve_spc_find_performance_index(cluster, freq);
328 
329         if (perf < 0)
330                 return perf;
331 
332         if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US)))
333                 return -ETIME;
334 
335         init_completion(&info->done);
336         info->cur_rsp_mask = RESPONSE_MASK(req_type);
337 
338         writel(perf, info->baseaddr + perf_cfg_reg);
339         ret = ve_spc_waitforcompletion(req_type);
340 
341         info->cur_rsp_mask = 0;
342         up(&info->sem);
343 
344         return ret;
345 }
346 
347 static int ve_spc_read_sys_cfg(int func, int offset, uint32_t *data)
348 {
349         int ret;
350 
351         if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US)))
352                 return -ETIME;
353 
354         init_completion(&info->done);
355         info->cur_rsp_mask = RESPONSE_MASK(SPC_SYS_CFG);
356 
357         /* Set the control value */
358         writel(SYSCFG_START | func | offset >> 2, info->baseaddr + COMMS);
359         ret = ve_spc_waitforcompletion(SPC_SYS_CFG);
360 
361         if (ret == 0)
362                 *data = readl(info->baseaddr + SYSCFG_RDATA);
363 
364         info->cur_rsp_mask = 0;
365         up(&info->sem);
366 
367         return ret;
368 }
369 
370 static irqreturn_t ve_spc_irq_handler(int irq, void *data)
371 {
372         struct ve_spc_drvdata *drv_data = data;
373         uint32_t status = readl_relaxed(drv_data->baseaddr + PWC_STATUS);
374 
375         if (info->cur_rsp_mask & status) {
376                 info->cur_rsp_stat = status;
377                 complete(&drv_data->done);
378         }
379 
380         return IRQ_HANDLED;
381 }
382 
383 /*
384  *  +--------------------------+
385  *  | 31      20 | 19        0 |
386  *  +--------------------------+
387  *  |   m_volt   |  freq(kHz)  |
388  *  +--------------------------+
389  */
390 #define MULT_FACTOR     20
391 #define VOLT_SHIFT      20
392 #define FREQ_MASK       (0xFFFFF)
393 static int ve_spc_populate_opps(uint32_t cluster)
394 {
395         uint32_t data = 0, off, ret, idx;
396         struct ve_spc_opp *opps;
397 
398         opps = kcalloc(MAX_OPPS, sizeof(*opps), GFP_KERNEL);
399         if (!opps)
400                 return -ENOMEM;
401 
402         info->opps[cluster] = opps;
403 
404         off = cluster_is_a15(cluster) ? A15_PERFVAL_BASE : A7_PERFVAL_BASE;
405         for (idx = 0; idx < MAX_OPPS; idx++, off += 4, opps++) {
406                 ret = ve_spc_read_sys_cfg(SYSCFG_SCC, off, &data);
407                 if (!ret) {
408                         opps->freq = (data & FREQ_MASK) * MULT_FACTOR;
409                         opps->u_volt = (data >> VOLT_SHIFT) * 1000;
410                 } else {
411                         break;
412                 }
413         }
414         info->num_opps[cluster] = idx;
415 
416         return ret;
417 }
418 
419 static int ve_init_opp_table(struct device *cpu_dev)
420 {
421         int cluster;
422         int idx, ret = 0, max_opp;
423         struct ve_spc_opp *opps;
424 
425         cluster = topology_physical_package_id(cpu_dev->id);
426         cluster = cluster < 0 ? 0 : cluster;
427 
428         max_opp = info->num_opps[cluster];
429         opps = info->opps[cluster];
430 
431         for (idx = 0; idx < max_opp; idx++, opps++) {
432                 ret = dev_pm_opp_add(cpu_dev, opps->freq * 1000, opps->u_volt);
433                 if (ret) {
434                         dev_warn(cpu_dev, "failed to add opp %lu %lu\n",
435                                  opps->freq, opps->u_volt);
436                         return ret;
437                 }
438         }
439         return ret;
440 }
441 
442 int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid, int irq)
443 {
444         int ret;
445         info = kzalloc(sizeof(*info), GFP_KERNEL);
446         if (!info)
447                 return -ENOMEM;
448 
449         info->baseaddr = baseaddr;
450         info->a15_clusid = a15_clusid;
451 
452         if (irq <= 0) {
453                 pr_err(SPCLOG "Invalid IRQ %d\n", irq);
454                 kfree(info);
455                 return -EINVAL;
456         }
457 
458         init_completion(&info->done);
459 
460         readl_relaxed(info->baseaddr + PWC_STATUS);
461 
462         ret = request_irq(irq, ve_spc_irq_handler, IRQF_TRIGGER_HIGH
463                                 | IRQF_ONESHOT, "vexpress-spc", info);
464         if (ret) {
465                 pr_err(SPCLOG "IRQ %d request failed\n", irq);
466                 kfree(info);
467                 return -ENODEV;
468         }
469 
470         sema_init(&info->sem, 1);
471         /*
472          * Multi-cluster systems may need this data when non-coherent, during
473          * cluster power-up/power-down. Make sure driver info reaches main
474          * memory.
475          */
476         sync_cache_w(info);
477         sync_cache_w(&info);
478 
479         return 0;
480 }
481 
482 struct clk_spc {
483         struct clk_hw hw;
484         int cluster;
485 };
486 
487 #define to_clk_spc(spc) container_of(spc, struct clk_spc, hw)
488 static unsigned long spc_recalc_rate(struct clk_hw *hw,
489                 unsigned long parent_rate)
490 {
491         struct clk_spc *spc = to_clk_spc(hw);
492         u32 freq;
493 
494         if (ve_spc_get_performance(spc->cluster, &freq))
495                 return -EIO;
496 
497         return freq * 1000;
498 }
499 
500 static long spc_round_rate(struct clk_hw *hw, unsigned long drate,
501                 unsigned long *parent_rate)
502 {
503         struct clk_spc *spc = to_clk_spc(hw);
504 
505         return ve_spc_round_performance(spc->cluster, drate);
506 }
507 
508 static int spc_set_rate(struct clk_hw *hw, unsigned long rate,
509                 unsigned long parent_rate)
510 {
511         struct clk_spc *spc = to_clk_spc(hw);
512 
513         return ve_spc_set_performance(spc->cluster, rate / 1000);
514 }
515 
516 static struct clk_ops clk_spc_ops = {
517         .recalc_rate = spc_recalc_rate,
518         .round_rate = spc_round_rate,
519         .set_rate = spc_set_rate,
520 };
521 
522 static struct clk *ve_spc_clk_register(struct device *cpu_dev)
523 {
524         struct clk_init_data init;
525         struct clk_spc *spc;
526 
527         spc = kzalloc(sizeof(*spc), GFP_KERNEL);
528         if (!spc)
529                 return ERR_PTR(-ENOMEM);
530 
531         spc->hw.init = &init;
532         spc->cluster = topology_physical_package_id(cpu_dev->id);
533 
534         spc->cluster = spc->cluster < 0 ? 0 : spc->cluster;
535 
536         init.name = dev_name(cpu_dev);
537         init.ops = &clk_spc_ops;
538         init.flags = CLK_GET_RATE_NOCACHE;
539         init.num_parents = 0;
540 
541         return devm_clk_register(cpu_dev, &spc->hw);
542 }
543 
544 static int __init ve_spc_clk_init(void)
545 {
546         int cpu, cluster;
547         struct clk *clk;
548         bool init_opp_table[MAX_CLUSTERS] = { false };
549 
550         if (!info)
551                 return 0; /* Continue only if SPC is initialised */
552 
553         if (ve_spc_populate_opps(0) || ve_spc_populate_opps(1)) {
554                 pr_err("failed to build OPP table\n");
555                 return -ENODEV;
556         }
557 
558         for_each_possible_cpu(cpu) {
559                 struct device *cpu_dev = get_cpu_device(cpu);
560                 if (!cpu_dev) {
561                         pr_warn("failed to get cpu%d device\n", cpu);
562                         continue;
563                 }
564                 clk = ve_spc_clk_register(cpu_dev);
565                 if (IS_ERR(clk)) {
566                         pr_warn("failed to register cpu%d clock\n", cpu);
567                         continue;
568                 }
569                 if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) {
570                         pr_warn("failed to register cpu%d clock lookup\n", cpu);
571                         continue;
572                 }
573 
574                 cluster = topology_physical_package_id(cpu_dev->id);
575                 if (cluster < 0 || init_opp_table[cluster])
576                         continue;
577 
578                 if (ve_init_opp_table(cpu_dev))
579                         pr_warn("failed to initialise cpu%d opp table\n", cpu);
580                 else if (dev_pm_opp_set_sharing_cpus(cpu_dev,
581                          topology_core_cpumask(cpu_dev->id)))
582                         pr_warn("failed to mark OPPs shared for cpu%d\n", cpu);
583                 else
584                         init_opp_table[cluster] = true;
585         }
586 
587         platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0);
588         return 0;
589 }
590 device_initcall(ve_spc_clk_init);
591 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php