Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM / devfreq: exynos-ppmu: Add the support of PPMUv2 for Exynos5433

This patch adds the support for PPMU (Platform Performance Monitoring Unit)
version 2.0 for Exynos5433 SoC. Exynos5433 SoC must need PPMUv2 which is
quite different from PPMUv1.1. The exynos-ppmu.c driver supports both PPMUv1.1
and PPMUv2.

Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>

authored by

Chanwoo Choi and committed by
MyungJoo Ham
77fe46a3 f47ff87f

+233 -7
+163 -7
drivers/devfreq/event/exynos-ppmu.c
··· 1 1 /* 2 2 * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support 3 3 * 4 - * Copyright (c) 2014 Samsung Electronics Co., Ltd. 4 + * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd. 5 5 * Author : Chanwoo Choi <cw00.choi@samsung.com> 6 6 * 7 7 * This program is free software; you can redistribute it and/or modify ··· 82 82 PPMU_EVENT(mscl), 83 83 PPMU_EVENT(fimd0x), 84 84 PPMU_EVENT(fimd1x), 85 + 86 + /* Only for Exynos5433 SoCs */ 87 + PPMU_EVENT(d0-cpu), 88 + PPMU_EVENT(d0-general), 89 + PPMU_EVENT(d0-rt), 90 + PPMU_EVENT(d1-cpu), 91 + PPMU_EVENT(d1-general), 92 + PPMU_EVENT(d1-rt), 93 + 85 94 { /* sentinel */ }, 86 95 }; 87 96 ··· 105 96 return -EINVAL; 106 97 } 107 98 99 + /* 100 + * The devfreq-event ops structure for PPMU v1.1 101 + */ 108 102 static int exynos_ppmu_disable(struct devfreq_event_dev *edev) 109 103 { 110 104 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); ··· 212 200 .get_event = exynos_ppmu_get_event, 213 201 }; 214 202 203 + /* 204 + * The devfreq-event ops structure for PPMU v2.0 205 + */ 206 + static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) 207 + { 208 + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 209 + u32 pmnc, clear; 210 + 211 + /* Disable all counters */ 212 + clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK 213 + | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); 214 + 215 + __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG); 216 + __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC); 217 + __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC); 218 + __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET); 219 + 220 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0); 221 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1); 222 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2); 223 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT); 224 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO); 225 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE); 226 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE); 227 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE); 228 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE); 229 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V); 230 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A); 231 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V); 232 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A); 233 + __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET); 234 + 235 + /* Disable PPMU */ 236 + pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); 237 + pmnc &= ~PPMU_PMNC_ENABLE_MASK; 238 + __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); 239 + 240 + return 0; 241 + } 242 + 243 + static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) 244 + { 245 + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 246 + int id = exynos_ppmu_find_ppmu_id(edev); 247 + u32 pmnc, cntens; 248 + 249 + /* Enable all counters */ 250 + cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS); 251 + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 252 + __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS); 253 + 254 + /* Set the event of Read/Write data count */ 255 + switch (id) { 256 + case PPMU_PMNCNT0: 257 + case PPMU_PMNCNT1: 258 + case PPMU_PMNCNT2: 259 + __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT, 260 + info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); 261 + break; 262 + case PPMU_PMNCNT3: 263 + __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT, 264 + info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); 265 + break; 266 + } 267 + 268 + /* Reset cycle counter/performance counter and enable PPMU */ 269 + pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); 270 + pmnc &= ~(PPMU_PMNC_ENABLE_MASK 271 + | PPMU_PMNC_COUNTER_RESET_MASK 272 + | PPMU_PMNC_CC_RESET_MASK 273 + | PPMU_PMNC_CC_DIVIDER_MASK 274 + | PPMU_V2_PMNC_START_MODE_MASK); 275 + pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); 276 + pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); 277 + pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); 278 + pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); 279 + __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); 280 + 281 + return 0; 282 + } 283 + 284 + static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, 285 + struct devfreq_event_data *edata) 286 + { 287 + struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 288 + int id = exynos_ppmu_find_ppmu_id(edev); 289 + u32 pmnc, cntenc; 290 + u32 pmcnt_high, pmcnt_low; 291 + u64 load_count = 0; 292 + 293 + /* Disable PPMU */ 294 + pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); 295 + pmnc &= ~PPMU_PMNC_ENABLE_MASK; 296 + __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); 297 + 298 + /* Read cycle count and performance count */ 299 + edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT); 300 + 301 + switch (id) { 302 + case PPMU_PMNCNT0: 303 + case PPMU_PMNCNT1: 304 + case PPMU_PMNCNT2: 305 + load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id)); 306 + break; 307 + case PPMU_PMNCNT3: 308 + pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); 309 + pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); 310 + load_count = (u64)((pmcnt_high & 0xff) << 32) + (u64)pmcnt_low; 311 + break; 312 + } 313 + edata->load_count = load_count; 314 + 315 + /* Disable all counters */ 316 + cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC); 317 + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 318 + __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC); 319 + 320 + dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, 321 + edata->load_count, edata->total_count); 322 + return 0; 323 + } 324 + 325 + static const struct devfreq_event_ops exynos_ppmu_v2_ops = { 326 + .disable = exynos_ppmu_v2_disable, 327 + .set_event = exynos_ppmu_v2_set_event, 328 + .get_event = exynos_ppmu_v2_get_event, 329 + }; 330 + 331 + static const struct of_device_id exynos_ppmu_id_match[] = { 332 + { 333 + .compatible = "samsung,exynos-ppmu", 334 + .data = (void *)&exynos_ppmu_ops, 335 + }, { 336 + .compatible = "samsung,exynos-ppmu-v2", 337 + .data = (void *)&exynos_ppmu_v2_ops, 338 + }, 339 + { /* sentinel */ }, 340 + }; 341 + 342 + static struct devfreq_event_ops *exynos_bus_get_ops(struct device_node *np) 343 + { 344 + const struct of_device_id *match; 345 + 346 + match = of_match_node(exynos_ppmu_id_match, np); 347 + return (struct devfreq_event_ops *)match->data; 348 + } 349 + 215 350 static int of_get_devfreq_events(struct device_node *np, 216 351 struct exynos_ppmu *info) 217 352 { 218 353 struct devfreq_event_desc *desc; 354 + struct devfreq_event_ops *event_ops; 219 355 struct device *dev = info->dev; 220 356 struct device_node *events_np, *node; 221 357 int i, j, count; ··· 374 214 "failed to get child node of devfreq-event devices\n"); 375 215 return -EINVAL; 376 216 } 217 + event_ops = exynos_bus_get_ops(np); 377 218 378 219 count = of_get_child_count(events_np); 379 220 desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); ··· 399 238 continue; 400 239 } 401 240 402 - desc[j].ops = &exynos_ppmu_ops; 241 + desc[j].ops = event_ops; 403 242 desc[j].driver_data = info; 404 243 405 244 of_property_read_string(node, "event-name", &desc[j].name); ··· 514 353 515 354 return 0; 516 355 } 517 - 518 - static struct of_device_id exynos_ppmu_id_match[] = { 519 - { .compatible = "samsung,exynos-ppmu", }, 520 - { /* sentinel */ }, 521 - }; 522 356 523 357 static struct platform_driver exynos_ppmu_driver = { 524 358 .probe = exynos_ppmu_probe,
+70
drivers/devfreq/event/exynos-ppmu.h
··· 26 26 PPMU_PMNCNT_MAX, 27 27 }; 28 28 29 + /*** 30 + * PPMUv1.1 Definitions 31 + */ 29 32 enum ppmu_event_type { 30 33 PPMU_RO_BUSY_CYCLE_CNT = 0x0, 31 34 PPMU_WO_BUSY_CYCLE_CNT = 0x1, ··· 92 89 /* PPMU_PMNCTx/PPMU_BETxSEL registers */ 93 90 #define PPMU_PMNCT(x) (PPMU_PMCNT0 + (0x10 * x)) 94 91 #define PPMU_BEVTxSEL(x) (PPMU_BEVT0SEL + (0x100 * x)) 92 + 93 + /*** 94 + * PPMU_V2.0 definitions 95 + */ 96 + enum ppmu_v2_mode { 97 + PPMU_V2_MODE_MANUAL = 0, 98 + PPMU_V2_MODE_AUTO = 1, 99 + PPMU_V2_MODE_CIG = 2, /* CIG (Conditional Interrupt Generation) */ 100 + }; 101 + 102 + enum ppmu_v2_event_type { 103 + PPMU_V2_RO_DATA_CNT = 0x4, 104 + PPMU_V2_WO_DATA_CNT = 0x5, 105 + 106 + PPMU_V2_EVT3_RW_DATA_CNT = 0x22, /* Only for Event3 */ 107 + }; 108 + 109 + enum ppmu_V2_reg { 110 + /* PPC control register */ 111 + PPMU_V2_PMNC = 0x04, 112 + PPMU_V2_CNTENS = 0x08, 113 + PPMU_V2_CNTENC = 0x0c, 114 + PPMU_V2_INTENS = 0x10, 115 + PPMU_V2_INTENC = 0x14, 116 + PPMU_V2_FLAG = 0x18, 117 + 118 + /* Cycle Counter and Performance Event Counter Register */ 119 + PPMU_V2_CCNT = 0x48, 120 + PPMU_V2_PMCNT0 = 0x34, 121 + PPMU_V2_PMCNT1 = 0x38, 122 + PPMU_V2_PMCNT2 = 0x3c, 123 + PPMU_V2_PMCNT3_LOW = 0x40, 124 + PPMU_V2_PMCNT3_HIGH = 0x44, 125 + 126 + /* Bus Event Generator */ 127 + PPMU_V2_CIG_CFG0 = 0x1c, 128 + PPMU_V2_CIG_CFG1 = 0x20, 129 + PPMU_V2_CIG_CFG2 = 0x24, 130 + PPMU_V2_CIG_RESULT = 0x28, 131 + PPMU_V2_CNT_RESET = 0x2c, 132 + PPMU_V2_CNT_AUTO = 0x30, 133 + PPMU_V2_CH_EV0_TYPE = 0x200, 134 + PPMU_V2_CH_EV1_TYPE = 0x204, 135 + PPMU_V2_CH_EV2_TYPE = 0x208, 136 + PPMU_V2_CH_EV3_TYPE = 0x20c, 137 + PPMU_V2_SM_ID_V = 0x220, 138 + PPMU_V2_SM_ID_A = 0x224, 139 + PPMU_V2_SM_OTHERS_V = 0x228, 140 + PPMU_V2_SM_OTHERS_A = 0x22c, 141 + PPMU_V2_INTERRUPT_RESET = 0x260, 142 + }; 143 + 144 + /* PMNC register */ 145 + #define PPMU_V2_PMNC_START_MODE_SHIFT 20 146 + #define PPMU_V2_PMNC_START_MODE_MASK (0x3 << PPMU_V2_PMNC_START_MODE_SHIFT) 147 + 148 + #define PPMU_PMNC_CC_RESET_SHIFT 2 149 + #define PPMU_PMNC_COUNTER_RESET_SHIFT 1 150 + #define PPMU_PMNC_ENABLE_SHIFT 0 151 + #define PPMU_PMNC_START_MODE_MASK BIT(16) 152 + #define PPMU_PMNC_CC_DIVIDER_MASK BIT(3) 153 + #define PPMU_PMNC_CC_RESET_MASK BIT(2) 154 + #define PPMU_PMNC_COUNTER_RESET_MASK BIT(1) 155 + #define PPMU_PMNC_ENABLE_MASK BIT(0) 156 + 157 + #define PPMU_V2_PMNCT(x) (PPMU_V2_PMCNT0 + (0x4 * x)) 158 + #define PPMU_V2_CH_EVx_TYPE(x) (PPMU_V2_CH_EV0_TYPE + (0x4 * x)) 95 159 96 160 #endif /* __EXYNOS_PPMU_H__ */