hc
2024-02-19 1c055e55a242a33e574e48be530e06770a210dcd
kernel/drivers/devfreq/event/exynos-ppmu.c
....@@ -1,12 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
2
- * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support
3
+ * exynos_ppmu.c - Exynos PPMU (Platform Performance Monitoring Unit) support
34 *
45 * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
56 * Author : Chanwoo Choi <cw00.choi@samsung.com>
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License version 2 as
9
- * published by the Free Software Foundation.
107 *
118 * This driver is based on drivers/devfreq/exynos/exynos_ppmu.c
129 */
....@@ -16,12 +13,18 @@
1613 #include <linux/kernel.h>
1714 #include <linux/module.h>
1815 #include <linux/of_address.h>
16
+#include <linux/of_device.h>
1917 #include <linux/platform_device.h>
2018 #include <linux/regmap.h>
2119 #include <linux/suspend.h>
2220 #include <linux/devfreq-event.h>
2321
2422 #include "exynos-ppmu.h"
23
+
24
+enum exynos_ppmu_type {
25
+ EXYNOS_TYPE_PPMU,
26
+ EXYNOS_TYPE_PPMU_V2,
27
+};
2528
2629 struct exynos_ppmu_data {
2730 struct clk *clk;
....@@ -36,6 +39,7 @@
3639 struct regmap *regmap;
3740
3841 struct exynos_ppmu_data ppmu;
42
+ enum exynos_ppmu_type ppmu_type;
3943 };
4044
4145 #define PPMU_EVENT(name) \
....@@ -89,17 +93,28 @@
8993 PPMU_EVENT(d1-cpu),
9094 PPMU_EVENT(d1-general),
9195 PPMU_EVENT(d1-rt),
96
+
97
+ /* For Exynos5422 SoC */
98
+ PPMU_EVENT(dmc0_0),
99
+ PPMU_EVENT(dmc0_1),
100
+ PPMU_EVENT(dmc1_0),
101
+ PPMU_EVENT(dmc1_1),
92102 };
93103
94
-static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
104
+static int __exynos_ppmu_find_ppmu_id(const char *edev_name)
95105 {
96106 int i;
97107
98108 for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
99
- if (!strcmp(edev->desc->name, ppmu_events[i].name))
109
+ if (!strcmp(edev_name, ppmu_events[i].name))
100110 return ppmu_events[i].id;
101111
102112 return -EINVAL;
113
+}
114
+
115
+static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
116
+{
117
+ return __exynos_ppmu_find_ppmu_id(edev->desc->name);
103118 }
104119
105120 /*
....@@ -154,9 +169,9 @@
154169 if (ret < 0)
155170 return ret;
156171
157
- /* Set the event of Read/Write data count */
172
+ /* Set the event of proper data type monitoring */
158173 ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id),
159
- PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT);
174
+ edev->desc->event_type);
160175 if (ret < 0)
161176 return ret;
162177
....@@ -368,23 +383,11 @@
368383 if (ret < 0)
369384 return ret;
370385
371
- /* Set the event of Read/Write data count */
372
- switch (id) {
373
- case PPMU_PMNCNT0:
374
- case PPMU_PMNCNT1:
375
- case PPMU_PMNCNT2:
376
- ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
377
- PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT);
378
- if (ret < 0)
379
- return ret;
380
- break;
381
- case PPMU_PMNCNT3:
382
- ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
383
- PPMU_V2_EVT3_RW_DATA_CNT);
384
- if (ret < 0)
385
- return ret;
386
- break;
387
- }
386
+ /* Set the event of proper data type monitoring */
387
+ ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
388
+ edev->desc->event_type);
389
+ if (ret < 0)
390
+ return ret;
388391
389392 /* Reset cycle counter/performance counter and enable PPMU */
390393 ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
....@@ -483,31 +486,24 @@
483486 static const struct of_device_id exynos_ppmu_id_match[] = {
484487 {
485488 .compatible = "samsung,exynos-ppmu",
486
- .data = (void *)&exynos_ppmu_ops,
489
+ .data = (void *)EXYNOS_TYPE_PPMU,
487490 }, {
488491 .compatible = "samsung,exynos-ppmu-v2",
489
- .data = (void *)&exynos_ppmu_v2_ops,
492
+ .data = (void *)EXYNOS_TYPE_PPMU_V2,
490493 },
491494 { /* sentinel */ },
492495 };
493496 MODULE_DEVICE_TABLE(of, exynos_ppmu_id_match);
494497
495
-static struct devfreq_event_ops *exynos_bus_get_ops(struct device_node *np)
496
-{
497
- const struct of_device_id *match;
498
-
499
- match = of_match_node(exynos_ppmu_id_match, np);
500
- return (struct devfreq_event_ops *)match->data;
501
-}
502
-
503498 static int of_get_devfreq_events(struct device_node *np,
504499 struct exynos_ppmu *info)
505500 {
506501 struct devfreq_event_desc *desc;
507
- struct devfreq_event_ops *event_ops;
508502 struct device *dev = info->dev;
509503 struct device_node *events_np, *node;
510504 int i, j, count;
505
+ const struct of_device_id *of_id;
506
+ int ret;
511507
512508 events_np = of_get_child_by_name(np, "events");
513509 if (!events_np) {
....@@ -515,13 +511,22 @@
515511 "failed to get child node of devfreq-event devices\n");
516512 return -EINVAL;
517513 }
518
- event_ops = exynos_bus_get_ops(np);
519514
520515 count = of_get_child_count(events_np);
521516 desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
522
- if (!desc)
517
+ if (!desc) {
518
+ of_node_put(events_np);
523519 return -ENOMEM;
520
+ }
524521 info->num_events = count;
522
+
523
+ of_id = of_match_device(exynos_ppmu_id_match, dev);
524
+ if (of_id)
525
+ info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
526
+ else {
527
+ of_node_put(events_np);
528
+ return -EINVAL;
529
+ }
525530
526531 j = 0;
527532 for_each_child_of_node(events_np, node) {
....@@ -529,21 +534,60 @@
529534 if (!ppmu_events[i].name)
530535 continue;
531536
532
- if (!of_node_cmp(node->name, ppmu_events[i].name))
537
+ if (of_node_name_eq(node, ppmu_events[i].name))
533538 break;
534539 }
535540
536541 if (i == ARRAY_SIZE(ppmu_events)) {
537542 dev_warn(dev,
538
- "don't know how to configure events : %s\n",
539
- node->name);
543
+ "don't know how to configure events : %pOFn\n",
544
+ node);
540545 continue;
541546 }
542547
543
- desc[j].ops = event_ops;
548
+ switch (info->ppmu_type) {
549
+ case EXYNOS_TYPE_PPMU:
550
+ desc[j].ops = &exynos_ppmu_ops;
551
+ break;
552
+ case EXYNOS_TYPE_PPMU_V2:
553
+ desc[j].ops = &exynos_ppmu_v2_ops;
554
+ break;
555
+ }
556
+
544557 desc[j].driver_data = info;
545558
546559 of_property_read_string(node, "event-name", &desc[j].name);
560
+ ret = of_property_read_u32(node, "event-data-type",
561
+ &desc[j].event_type);
562
+ if (ret) {
563
+ /* Set the event of proper data type counting.
564
+ * Check if the data type has been defined in DT,
565
+ * use default if not.
566
+ */
567
+ if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) {
568
+ int id;
569
+ /* Not all registers take the same value for
570
+ * read+write data count.
571
+ */
572
+ id = __exynos_ppmu_find_ppmu_id(desc[j].name);
573
+
574
+ switch (id) {
575
+ case PPMU_PMNCNT0:
576
+ case PPMU_PMNCNT1:
577
+ case PPMU_PMNCNT2:
578
+ desc[j].event_type = PPMU_V2_RO_DATA_CNT
579
+ | PPMU_V2_WO_DATA_CNT;
580
+ break;
581
+ case PPMU_PMNCNT3:
582
+ desc[j].event_type =
583
+ PPMU_V2_EVT3_RW_DATA_CNT;
584
+ break;
585
+ }
586
+ } else {
587
+ desc[j].event_type = PPMU_RO_DATA_CNT |
588
+ PPMU_WO_DATA_CNT;
589
+ }
590
+ }
547591
548592 j++;
549593 }
....@@ -636,7 +680,6 @@
636680 for (i = 0; i < info->num_events; i++) {
637681 edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]);
638682 if (IS_ERR(edev[i])) {
639
- ret = PTR_ERR(edev[i]);
640683 dev_err(&pdev->dev,
641684 "failed to add devfreq-event device\n");
642685 return PTR_ERR(edev[i]);