1/* 2 * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support 3 * 4 * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd. 5 * 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. 10 * 11 * This driver is based on drivers/devfreq/exynos/exynos_ppmu.c 12 */ 13 14#include <linux/clk.h> 15#include <linux/io.h> 16#include <linux/kernel.h> 17#include <linux/module.h> 18#include <linux/mutex.h> 19#include <linux/of_address.h> 20#include <linux/platform_device.h> 21#include <linux/suspend.h> 22#include <linux/devfreq-event.h> 23 24#include "exynos-ppmu.h" 25 26struct exynos_ppmu_data { 27 void __iomem *base; 28 struct clk *clk; 29}; 30 31struct exynos_ppmu { 32 struct devfreq_event_dev **edev; 33 struct devfreq_event_desc *desc; 34 unsigned int num_events; 35 36 struct device *dev; 37 struct mutex lock; 38 39 struct exynos_ppmu_data ppmu; 40}; 41 42#define PPMU_EVENT(name) \ 43 { "ppmu-event0-"#name, PPMU_PMNCNT0 }, \ 44 { "ppmu-event1-"#name, PPMU_PMNCNT1 }, \ 45 { "ppmu-event2-"#name, PPMU_PMNCNT2 }, \ 46 { "ppmu-event3-"#name, PPMU_PMNCNT3 } 47 48struct __exynos_ppmu_events { 49 char *name; 50 int id; 51} ppmu_events[] = { 52 /* For Exynos3250, Exynos4 and Exynos5260 */ 53 PPMU_EVENT(g3d), 54 PPMU_EVENT(fsys), 55 56 /* For Exynos4 SoCs and Exynos3250 */ 57 PPMU_EVENT(dmc0), 58 PPMU_EVENT(dmc1), 59 PPMU_EVENT(cpu), 60 PPMU_EVENT(rightbus), 61 PPMU_EVENT(leftbus), 62 PPMU_EVENT(lcd0), 63 PPMU_EVENT(camif), 64 65 /* Only for Exynos3250 and Exynos5260 */ 66 PPMU_EVENT(mfc), 67 68 /* Only for Exynos4 SoCs */ 69 PPMU_EVENT(mfc-left), 70 PPMU_EVENT(mfc-right), 71 72 /* Only for Exynos5260 SoCs */ 73 PPMU_EVENT(drex0-s0), 74 PPMU_EVENT(drex0-s1), 75 PPMU_EVENT(drex1-s0), 76 PPMU_EVENT(drex1-s1), 77 PPMU_EVENT(eagle), 78 PPMU_EVENT(kfc), 79 PPMU_EVENT(isp), 80 PPMU_EVENT(fimc), 81 PPMU_EVENT(gscl), 82 PPMU_EVENT(mscl), 83 PPMU_EVENT(fimd0x), 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 94 { /* sentinel */ }, 95}; 96 97static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) 98{ 99 int i; 100 101 for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) 102 if (!strcmp(edev->desc->name, ppmu_events[i].name)) 103 return ppmu_events[i].id; 104 105 return -EINVAL; 106} 107 108/* 109 * The devfreq-event ops structure for PPMU v1.1 110 */ 111static int exynos_ppmu_disable(struct devfreq_event_dev *edev) 112{ 113 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 114 u32 pmnc; 115 116 /* Disable all counters */ 117 __raw_writel(PPMU_CCNT_MASK | 118 PPMU_PMCNT0_MASK | 119 PPMU_PMCNT1_MASK | 120 PPMU_PMCNT2_MASK | 121 PPMU_PMCNT3_MASK, 122 info->ppmu.base + PPMU_CNTENC); 123 124 /* Disable PPMU */ 125 pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); 126 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 127 __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); 128 129 return 0; 130} 131 132static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) 133{ 134 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 135 int id = exynos_ppmu_find_ppmu_id(edev); 136 u32 pmnc, cntens; 137 138 if (id < 0) 139 return id; 140 141 /* Enable specific counter */ 142 cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS); 143 cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 144 __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS); 145 146 /* Set the event of Read/Write data count */ 147 __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT, 148 info->ppmu.base + PPMU_BEVTxSEL(id)); 149 150 /* Reset cycle counter/performance counter and enable PPMU */ 151 pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); 152 pmnc &= ~(PPMU_PMNC_ENABLE_MASK 153 | PPMU_PMNC_COUNTER_RESET_MASK 154 | PPMU_PMNC_CC_RESET_MASK); 155 pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); 156 pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); 157 pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); 158 __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); 159 160 return 0; 161} 162 163static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, 164 struct devfreq_event_data *edata) 165{ 166 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 167 int id = exynos_ppmu_find_ppmu_id(edev); 168 u32 pmnc, cntenc; 169 170 if (id < 0) 171 return -EINVAL; 172 173 /* Disable PPMU */ 174 pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); 175 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 176 __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); 177 178 /* Read cycle count */ 179 edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT); 180 181 /* Read performance count */ 182 switch (id) { 183 case PPMU_PMNCNT0: 184 case PPMU_PMNCNT1: 185 case PPMU_PMNCNT2: 186 edata->load_count 187 = __raw_readl(info->ppmu.base + PPMU_PMNCT(id)); 188 break; 189 case PPMU_PMNCNT3: 190 edata->load_count = 191 ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8) 192 | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW)); 193 break; 194 default: 195 return -EINVAL; 196 } 197 198 /* Disable specific counter */ 199 cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC); 200 cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 201 __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC); 202 203 dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, 204 edata->load_count, edata->total_count); 205 206 return 0; 207} 208 209static const struct devfreq_event_ops exynos_ppmu_ops = { 210 .disable = exynos_ppmu_disable, 211 .set_event = exynos_ppmu_set_event, 212 .get_event = exynos_ppmu_get_event, 213}; 214 215/* 216 * The devfreq-event ops structure for PPMU v2.0 217 */ 218static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) 219{ 220 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 221 u32 pmnc, clear; 222 223 /* Disable all counters */ 224 clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK 225 | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); 226 227 __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG); 228 __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC); 229 __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC); 230 __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET); 231 232 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0); 233 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1); 234 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2); 235 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT); 236 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO); 237 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE); 238 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE); 239 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE); 240 __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE); 241 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V); 242 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A); 243 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V); 244 __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A); 245 __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET); 246 247 /* Disable PPMU */ 248 pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); 249 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 250 __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); 251 252 return 0; 253} 254 255static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) 256{ 257 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 258 int id = exynos_ppmu_find_ppmu_id(edev); 259 u32 pmnc, cntens; 260 261 /* Enable all counters */ 262 cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS); 263 cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 264 __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS); 265 266 /* Set the event of Read/Write data count */ 267 switch (id) { 268 case PPMU_PMNCNT0: 269 case PPMU_PMNCNT1: 270 case PPMU_PMNCNT2: 271 __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT, 272 info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); 273 break; 274 case PPMU_PMNCNT3: 275 __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT, 276 info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); 277 break; 278 } 279 280 /* Reset cycle counter/performance counter and enable PPMU */ 281 pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); 282 pmnc &= ~(PPMU_PMNC_ENABLE_MASK 283 | PPMU_PMNC_COUNTER_RESET_MASK 284 | PPMU_PMNC_CC_RESET_MASK 285 | PPMU_PMNC_CC_DIVIDER_MASK 286 | PPMU_V2_PMNC_START_MODE_MASK); 287 pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); 288 pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); 289 pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); 290 pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); 291 __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); 292 293 return 0; 294} 295 296static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, 297 struct devfreq_event_data *edata) 298{ 299 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 300 int id = exynos_ppmu_find_ppmu_id(edev); 301 u32 pmnc, cntenc; 302 u32 pmcnt_high, pmcnt_low; 303 u64 load_count = 0; 304 305 /* Disable PPMU */ 306 pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); 307 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 308 __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); 309 310 /* Read cycle count and performance count */ 311 edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT); 312 313 switch (id) { 314 case PPMU_PMNCNT0: 315 case PPMU_PMNCNT1: 316 case PPMU_PMNCNT2: 317 load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id)); 318 break; 319 case PPMU_PMNCNT3: 320 pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); 321 pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); 322 load_count = ((u64)((pmcnt_high & 0xff)) << 32) 323 + (u64)pmcnt_low; 324 break; 325 } 326 edata->load_count = load_count; 327 328 /* Disable all counters */ 329 cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC); 330 cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 331 __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC); 332 333 dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, 334 edata->load_count, edata->total_count); 335 return 0; 336} 337 338static const struct devfreq_event_ops exynos_ppmu_v2_ops = { 339 .disable = exynos_ppmu_v2_disable, 340 .set_event = exynos_ppmu_v2_set_event, 341 .get_event = exynos_ppmu_v2_get_event, 342}; 343 344static const struct of_device_id exynos_ppmu_id_match[] = { 345 { 346 .compatible = "samsung,exynos-ppmu", 347 .data = (void *)&exynos_ppmu_ops, 348 }, { 349 .compatible = "samsung,exynos-ppmu-v2", 350 .data = (void *)&exynos_ppmu_v2_ops, 351 }, 352 { /* sentinel */ }, 353}; 354 355static struct devfreq_event_ops *exynos_bus_get_ops(struct device_node *np) 356{ 357 const struct of_device_id *match; 358 359 match = of_match_node(exynos_ppmu_id_match, np); 360 return (struct devfreq_event_ops *)match->data; 361} 362 363static int of_get_devfreq_events(struct device_node *np, 364 struct exynos_ppmu *info) 365{ 366 struct devfreq_event_desc *desc; 367 struct devfreq_event_ops *event_ops; 368 struct device *dev = info->dev; 369 struct device_node *events_np, *node; 370 int i, j, count; 371 372 events_np = of_get_child_by_name(np, "events"); 373 if (!events_np) { 374 dev_err(dev, 375 "failed to get child node of devfreq-event devices\n"); 376 return -EINVAL; 377 } 378 event_ops = exynos_bus_get_ops(np); 379 380 count = of_get_child_count(events_np); 381 desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); 382 if (!desc) 383 return -ENOMEM; 384 info->num_events = count; 385 386 j = 0; 387 for_each_child_of_node(events_np, node) { 388 for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) { 389 if (!ppmu_events[i].name) 390 continue; 391 392 if (!of_node_cmp(node->name, ppmu_events[i].name)) 393 break; 394 } 395 396 if (i == ARRAY_SIZE(ppmu_events)) { 397 dev_warn(dev, 398 "don't know how to configure events : %s\n", 399 node->name); 400 continue; 401 } 402 403 desc[j].ops = event_ops; 404 desc[j].driver_data = info; 405 406 of_property_read_string(node, "event-name", &desc[j].name); 407 408 j++; 409 410 of_node_put(node); 411 } 412 info->desc = desc; 413 414 of_node_put(events_np); 415 416 return 0; 417} 418 419static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) 420{ 421 struct device *dev = info->dev; 422 struct device_node *np = dev->of_node; 423 int ret = 0; 424 425 if (!np) { 426 dev_err(dev, "failed to find devicetree node\n"); 427 return -EINVAL; 428 } 429 430 /* Maps the memory mapped IO to control PPMU register */ 431 info->ppmu.base = of_iomap(np, 0); 432 if (IS_ERR_OR_NULL(info->ppmu.base)) { 433 dev_err(dev, "failed to map memory region\n"); 434 return -ENOMEM; 435 } 436 437 info->ppmu.clk = devm_clk_get(dev, "ppmu"); 438 if (IS_ERR(info->ppmu.clk)) { 439 info->ppmu.clk = NULL; 440 dev_warn(dev, "cannot get PPMU clock\n"); 441 } 442 443 ret = of_get_devfreq_events(np, info); 444 if (ret < 0) { 445 dev_err(dev, "failed to parse exynos ppmu dt node\n"); 446 goto err; 447 } 448 449 return 0; 450 451err: 452 iounmap(info->ppmu.base); 453 454 return ret; 455} 456 457static int exynos_ppmu_probe(struct platform_device *pdev) 458{ 459 struct exynos_ppmu *info; 460 struct devfreq_event_dev **edev; 461 struct devfreq_event_desc *desc; 462 int i, ret = 0, size; 463 464 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 465 if (!info) 466 return -ENOMEM; 467 468 mutex_init(&info->lock); 469 info->dev = &pdev->dev; 470 471 /* Parse dt data to get resource */ 472 ret = exynos_ppmu_parse_dt(info); 473 if (ret < 0) { 474 dev_err(&pdev->dev, 475 "failed to parse devicetree for resource\n"); 476 return ret; 477 } 478 desc = info->desc; 479 480 size = sizeof(struct devfreq_event_dev *) * info->num_events; 481 info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); 482 if (!info->edev) { 483 dev_err(&pdev->dev, 484 "failed to allocate memory devfreq-event devices\n"); 485 return -ENOMEM; 486 } 487 edev = info->edev; 488 platform_set_drvdata(pdev, info); 489 490 for (i = 0; i < info->num_events; i++) { 491 edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]); 492 if (IS_ERR(edev[i])) { 493 ret = PTR_ERR(edev[i]); 494 dev_err(&pdev->dev, 495 "failed to add devfreq-event device\n"); 496 goto err; 497 } 498 } 499 500 clk_prepare_enable(info->ppmu.clk); 501 502 return 0; 503err: 504 iounmap(info->ppmu.base); 505 506 return ret; 507} 508 509static int exynos_ppmu_remove(struct platform_device *pdev) 510{ 511 struct exynos_ppmu *info = platform_get_drvdata(pdev); 512 513 clk_disable_unprepare(info->ppmu.clk); 514 iounmap(info->ppmu.base); 515 516 return 0; 517} 518 519static struct platform_driver exynos_ppmu_driver = { 520 .probe = exynos_ppmu_probe, 521 .remove = exynos_ppmu_remove, 522 .driver = { 523 .name = "exynos-ppmu", 524 .of_match_table = exynos_ppmu_id_match, 525 }, 526}; 527module_platform_driver(exynos_ppmu_driver); 528 529MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver"); 530MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); 531MODULE_LICENSE("GPL"); 532