^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * exynos_ppmu.c - Exynos PPMU (Platform Performance Monitoring Unit) support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author : Chanwoo Choi <cw00.choi@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This driver is based on drivers/devfreq/exynos/exynos_ppmu.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/suspend.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/devfreq-event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "exynos-ppmu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) enum exynos_ppmu_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) EXYNOS_TYPE_PPMU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) EXYNOS_TYPE_PPMU_V2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct exynos_ppmu_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct exynos_ppmu {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct devfreq_event_dev **edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct devfreq_event_desc *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned int num_events;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct exynos_ppmu_data ppmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) enum exynos_ppmu_type ppmu_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define PPMU_EVENT(name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { "ppmu-event0-"#name, PPMU_PMNCNT0 }, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) { "ppmu-event1-"#name, PPMU_PMNCNT1 }, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) { "ppmu-event2-"#name, PPMU_PMNCNT2 }, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) { "ppmu-event3-"#name, PPMU_PMNCNT3 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static struct __exynos_ppmu_events {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) } ppmu_events[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* For Exynos3250, Exynos4 and Exynos5260 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) PPMU_EVENT(g3d),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) PPMU_EVENT(fsys),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) /* For Exynos4 SoCs and Exynos3250 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) PPMU_EVENT(dmc0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) PPMU_EVENT(dmc1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) PPMU_EVENT(cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) PPMU_EVENT(rightbus),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) PPMU_EVENT(leftbus),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) PPMU_EVENT(lcd0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) PPMU_EVENT(camif),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Only for Exynos3250 and Exynos5260 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) PPMU_EVENT(mfc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Only for Exynos4 SoCs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) PPMU_EVENT(mfc-left),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) PPMU_EVENT(mfc-right),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Only for Exynos5260 SoCs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) PPMU_EVENT(drex0-s0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) PPMU_EVENT(drex0-s1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) PPMU_EVENT(drex1-s0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) PPMU_EVENT(drex1-s1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) PPMU_EVENT(eagle),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) PPMU_EVENT(kfc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) PPMU_EVENT(isp),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) PPMU_EVENT(fimc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) PPMU_EVENT(gscl),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) PPMU_EVENT(mscl),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) PPMU_EVENT(fimd0x),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) PPMU_EVENT(fimd1x),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* Only for Exynos5433 SoCs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) PPMU_EVENT(d0-cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) PPMU_EVENT(d0-general),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) PPMU_EVENT(d0-rt),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) PPMU_EVENT(d1-cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) PPMU_EVENT(d1-general),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) PPMU_EVENT(d1-rt),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* For Exynos5422 SoC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) PPMU_EVENT(dmc0_0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) PPMU_EVENT(dmc0_1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) PPMU_EVENT(dmc1_0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) PPMU_EVENT(dmc1_1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) static int __exynos_ppmu_find_ppmu_id(const char *edev_name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (!strcmp(edev_name, ppmu_events[i].name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return ppmu_events[i].id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return __exynos_ppmu_find_ppmu_id(edev->desc->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * The devfreq-event ops structure for PPMU v1.1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int exynos_ppmu_disable(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) u32 pmnc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* Disable all counters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) ret = regmap_write(info->regmap, PPMU_CNTENC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) PPMU_CCNT_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) PPMU_PMCNT0_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) PPMU_PMCNT1_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) PPMU_PMCNT2_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) PPMU_PMCNT3_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* Disable PPMU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) pmnc &= ~PPMU_PMNC_ENABLE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static int exynos_ppmu_set_event(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int id = exynos_ppmu_find_ppmu_id(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) u32 pmnc, cntens;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (id < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* Enable specific counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ret = regmap_write(info->regmap, PPMU_CNTENS, cntens);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* Set the event of proper data type monitoring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) edev->desc->event_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* Reset cycle counter/performance counter and enable PPMU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) pmnc &= ~(PPMU_PMNC_ENABLE_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) | PPMU_PMNC_COUNTER_RESET_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) | PPMU_PMNC_CC_RESET_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) static int exynos_ppmu_get_event(struct devfreq_event_dev *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct devfreq_event_data *edata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) int id = exynos_ppmu_find_ppmu_id(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) unsigned int total_count, load_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) unsigned int pmcnt3_high, pmcnt3_low;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) unsigned int pmnc, cntenc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (id < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) /* Disable PPMU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) pmnc &= ~PPMU_PMNC_ENABLE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ret = regmap_write(info->regmap, PPMU_PMNC, pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /* Read cycle count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ret = regmap_read(info->regmap, PPMU_CCNT, &total_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) edata->total_count = total_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* Read performance count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) case PPMU_PMNCNT0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) case PPMU_PMNCNT1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) case PPMU_PMNCNT2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) edata->load_count = load_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) case PPMU_PMNCNT3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /* Disable specific counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) edata->load_count, edata->total_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static const struct devfreq_event_ops exynos_ppmu_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) .disable = exynos_ppmu_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) .set_event = exynos_ppmu_set_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) .get_event = exynos_ppmu_get_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * The devfreq-event ops structure for PPMU v2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) u32 pmnc, clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* Disable all counters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) /* Disable PPMU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) pmnc &= ~PPMU_PMNC_ENABLE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) unsigned int pmnc, cntens;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) int id = exynos_ppmu_find_ppmu_id(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /* Enable all counters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /* Set the event of proper data type monitoring */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) edev->desc->event_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) /* Reset cycle counter/performance counter and enable PPMU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) pmnc &= ~(PPMU_PMNC_ENABLE_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) | PPMU_PMNC_COUNTER_RESET_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) | PPMU_PMNC_CC_RESET_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) | PPMU_PMNC_CC_DIVIDER_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) | PPMU_V2_PMNC_START_MODE_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct devfreq_event_data *edata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) int id = exynos_ppmu_find_ppmu_id(edev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) unsigned int pmnc, cntenc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) unsigned int pmcnt_high, pmcnt_low;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) unsigned int total_count, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) unsigned long load_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /* Disable PPMU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) pmnc &= ~PPMU_PMNC_ENABLE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* Read cycle count and performance count */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) edata->total_count = total_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) case PPMU_PMNCNT0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) case PPMU_PMNCNT1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) case PPMU_PMNCNT2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) load_count = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) case PPMU_PMNCNT3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) &pmcnt_high);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) edata->load_count = load_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /* Disable all counters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) edata->load_count, edata->total_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) static const struct devfreq_event_ops exynos_ppmu_v2_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) .disable = exynos_ppmu_v2_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) .set_event = exynos_ppmu_v2_set_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) .get_event = exynos_ppmu_v2_get_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static const struct of_device_id exynos_ppmu_id_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) .compatible = "samsung,exynos-ppmu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) .data = (void *)EXYNOS_TYPE_PPMU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) .compatible = "samsung,exynos-ppmu-v2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) .data = (void *)EXYNOS_TYPE_PPMU_V2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) { /* sentinel */ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) MODULE_DEVICE_TABLE(of, exynos_ppmu_id_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) static int of_get_devfreq_events(struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) struct exynos_ppmu *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) struct devfreq_event_desc *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) struct device *dev = info->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) struct device_node *events_np, *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) int i, j, count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) const struct of_device_id *of_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) events_np = of_get_child_by_name(np, "events");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (!events_np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dev_err(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) "failed to get child node of devfreq-event devices\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) count = of_get_child_count(events_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (!desc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) info->num_events = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) of_id = of_match_device(exynos_ppmu_id_match, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (of_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) j = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) for_each_child_of_node(events_np, node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (!ppmu_events[i].name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (of_node_name_eq(node, ppmu_events[i].name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) if (i == ARRAY_SIZE(ppmu_events)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) dev_warn(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) "don't know how to configure events : %pOFn\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) switch (info->ppmu_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) case EXYNOS_TYPE_PPMU:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) desc[j].ops = &exynos_ppmu_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) case EXYNOS_TYPE_PPMU_V2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) desc[j].ops = &exynos_ppmu_v2_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) desc[j].driver_data = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) of_property_read_string(node, "event-name", &desc[j].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) ret = of_property_read_u32(node, "event-data-type",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) &desc[j].event_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /* Set the event of proper data type counting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) * Check if the data type has been defined in DT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * use default if not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) /* Not all registers take the same value for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) * read+write data count.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) id = __exynos_ppmu_find_ppmu_id(desc[j].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) case PPMU_PMNCNT0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) case PPMU_PMNCNT1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) case PPMU_PMNCNT2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) desc[j].event_type = PPMU_V2_RO_DATA_CNT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) | PPMU_V2_WO_DATA_CNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) case PPMU_PMNCNT3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) desc[j].event_type =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) PPMU_V2_EVT3_RW_DATA_CNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) desc[j].event_type = PPMU_RO_DATA_CNT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) PPMU_WO_DATA_CNT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) j++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) info->desc = desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) of_node_put(events_np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) static struct regmap_config exynos_ppmu_regmap_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) .reg_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) .val_bits = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) .reg_stride = 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) static int exynos_ppmu_parse_dt(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) struct exynos_ppmu *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct device *dev = info->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) struct device_node *np = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (!np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) dev_err(dev, "failed to find devicetree node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) /* Maps the memory mapped IO to control PPMU register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) base = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (IS_ERR(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return PTR_ERR(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) exynos_ppmu_regmap_config.max_register = resource_size(res) - 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) info->regmap = devm_regmap_init_mmio(dev, base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) &exynos_ppmu_regmap_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) if (IS_ERR(info->regmap)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) dev_err(dev, "failed to initialize regmap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return PTR_ERR(info->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) info->ppmu.clk = devm_clk_get(dev, "ppmu");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (IS_ERR(info->ppmu.clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) info->ppmu.clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) dev_warn(dev, "cannot get PPMU clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) ret = of_get_devfreq_events(np, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) dev_err(dev, "failed to parse exynos ppmu dt node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) static int exynos_ppmu_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) struct exynos_ppmu *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) struct devfreq_event_dev **edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) struct devfreq_event_desc *desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) int i, ret = 0, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /* Parse dt data to get resource */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) ret = exynos_ppmu_parse_dt(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) "failed to parse devicetree for resource\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) desc = info->desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) size = sizeof(struct devfreq_event_dev *) * info->num_events;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (!info->edev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) edev = info->edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) for (i = 0; i < info->num_events; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (IS_ERR(edev[i])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) dev_err(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) "failed to add devfreq-event device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return PTR_ERR(edev[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) dev_name(&pdev->dev), desc[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) ret = clk_prepare_enable(info->ppmu.clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) dev_err(&pdev->dev, "failed to prepare ppmu clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static int exynos_ppmu_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) struct exynos_ppmu *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) clk_disable_unprepare(info->ppmu.clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) static struct platform_driver exynos_ppmu_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) .probe = exynos_ppmu_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) .remove = exynos_ppmu_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) .name = "exynos-ppmu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) .of_match_table = exynos_ppmu_id_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) module_platform_driver(exynos_ppmu_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) MODULE_LICENSE("GPL");