1 /* 2 * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support 3 * 4 * Copyright (c) 2014 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 26 struct exynos_ppmu_data { 27 void __iomem *base; 28 struct clk *clk; 29 }; 30 31 struct 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 48 struct __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 { /* sentinel */ }, 86 }; 87 88 static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) 89 { 90 int i; 91 92 for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) 93 if (!strcmp(edev->desc->name, ppmu_events[i].name)) 94 return ppmu_events[i].id; 95 96 return -EINVAL; 97 } 98 99 static int exynos_ppmu_disable(struct devfreq_event_dev *edev) 100 { 101 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 102 u32 pmnc; 103 104 /* Disable all counters */ 105 __raw_writel(PPMU_CCNT_MASK | 106 PPMU_PMCNT0_MASK | 107 PPMU_PMCNT1_MASK | 108 PPMU_PMCNT2_MASK | 109 PPMU_PMCNT3_MASK, 110 info->ppmu.base + PPMU_CNTENC); 111 112 /* Disable PPMU */ 113 pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); 114 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 115 __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); 116 117 return 0; 118 } 119 120 static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) 121 { 122 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 123 int id = exynos_ppmu_find_ppmu_id(edev); 124 u32 pmnc, cntens; 125 126 if (id < 0) 127 return id; 128 129 /* Enable specific counter */ 130 cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS); 131 cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 132 __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS); 133 134 /* Set the event of Read/Write data count */ 135 __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT, 136 info->ppmu.base + PPMU_BEVTxSEL(id)); 137 138 /* Reset cycle counter/performance counter and enable PPMU */ 139 pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); 140 pmnc &= ~(PPMU_PMNC_ENABLE_MASK 141 | PPMU_PMNC_COUNTER_RESET_MASK 142 | PPMU_PMNC_CC_RESET_MASK); 143 pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); 144 pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); 145 pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); 146 __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); 147 148 return 0; 149 } 150 151 static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, 152 struct devfreq_event_data *edata) 153 { 154 struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); 155 int id = exynos_ppmu_find_ppmu_id(edev); 156 u32 pmnc, cntenc; 157 158 if (id < 0) 159 return -EINVAL; 160 161 /* Disable PPMU */ 162 pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); 163 pmnc &= ~PPMU_PMNC_ENABLE_MASK; 164 __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); 165 166 /* Read cycle count */ 167 edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT); 168 169 /* Read performance count */ 170 switch (id) { 171 case PPMU_PMNCNT0: 172 case PPMU_PMNCNT1: 173 case PPMU_PMNCNT2: 174 edata->load_count 175 = __raw_readl(info->ppmu.base + PPMU_PMNCT(id)); 176 break; 177 case PPMU_PMNCNT3: 178 edata->load_count = 179 ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8) 180 | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW)); 181 break; 182 default: 183 return -EINVAL; 184 } 185 186 /* Disable specific counter */ 187 cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC); 188 cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); 189 __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC); 190 191 dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, 192 edata->load_count, edata->total_count); 193 194 return 0; 195 } 196 197 static const struct devfreq_event_ops exynos_ppmu_ops = { 198 .disable = exynos_ppmu_disable, 199 .set_event = exynos_ppmu_set_event, 200 .get_event = exynos_ppmu_get_event, 201 }; 202 203 static int of_get_devfreq_events(struct device_node *np, 204 struct exynos_ppmu *info) 205 { 206 struct devfreq_event_desc *desc; 207 struct device *dev = info->dev; 208 struct device_node *events_np, *node; 209 int i, j, count; 210 211 events_np = of_get_child_by_name(np, "events"); 212 if (!events_np) { 213 dev_err(dev, 214 "failed to get child node of devfreq-event devices\n"); 215 return -EINVAL; 216 } 217 218 count = of_get_child_count(events_np); 219 desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL); 220 if (!desc) 221 return -ENOMEM; 222 info->num_events = count; 223 224 j = 0; 225 for_each_child_of_node(events_np, node) { 226 for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) { 227 if (!ppmu_events[i].name) 228 continue; 229 230 if (!of_node_cmp(node->name, ppmu_events[i].name)) 231 break; 232 } 233 234 if (i == ARRAY_SIZE(ppmu_events)) { 235 dev_warn(dev, 236 "don't know how to configure events : %s\n", 237 node->name); 238 continue; 239 } 240 241 desc[j].ops = &exynos_ppmu_ops; 242 desc[j].driver_data = info; 243 244 of_property_read_string(node, "event-name", &desc[j].name); 245 246 j++; 247 248 of_node_put(node); 249 } 250 info->desc = desc; 251 252 of_node_put(events_np); 253 254 return 0; 255 } 256 257 static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) 258 { 259 struct device *dev = info->dev; 260 struct device_node *np = dev->of_node; 261 int ret = 0; 262 263 if (!np) { 264 dev_err(dev, "failed to find devicetree node\n"); 265 return -EINVAL; 266 } 267 268 /* Maps the memory mapped IO to control PPMU register */ 269 info->ppmu.base = of_iomap(np, 0); 270 if (IS_ERR_OR_NULL(info->ppmu.base)) { 271 dev_err(dev, "failed to map memory region\n"); 272 return -ENOMEM; 273 } 274 275 info->ppmu.clk = devm_clk_get(dev, "ppmu"); 276 if (IS_ERR(info->ppmu.clk)) { 277 info->ppmu.clk = NULL; 278 dev_warn(dev, "cannot get PPMU clock\n"); 279 } 280 281 ret = of_get_devfreq_events(np, info); 282 if (ret < 0) { 283 dev_err(dev, "failed to parse exynos ppmu dt node\n"); 284 goto err; 285 } 286 287 return 0; 288 289 err: 290 iounmap(info->ppmu.base); 291 292 return ret; 293 } 294 295 static int exynos_ppmu_probe(struct platform_device *pdev) 296 { 297 struct exynos_ppmu *info; 298 struct devfreq_event_dev **edev; 299 struct devfreq_event_desc *desc; 300 int i, ret = 0, size; 301 302 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 303 if (!info) 304 return -ENOMEM; 305 306 mutex_init(&info->lock); 307 info->dev = &pdev->dev; 308 309 /* Parse dt data to get resource */ 310 ret = exynos_ppmu_parse_dt(info); 311 if (ret < 0) { 312 dev_err(&pdev->dev, 313 "failed to parse devicetree for resource\n"); 314 return ret; 315 } 316 desc = info->desc; 317 318 size = sizeof(struct devfreq_event_dev *) * info->num_events; 319 info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); 320 if (!info->edev) { 321 dev_err(&pdev->dev, 322 "failed to allocate memory devfreq-event devices\n"); 323 return -ENOMEM; 324 } 325 edev = info->edev; 326 platform_set_drvdata(pdev, info); 327 328 for (i = 0; i < info->num_events; i++) { 329 edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]); 330 if (IS_ERR(edev[i])) { 331 ret = PTR_ERR(edev[i]); 332 dev_err(&pdev->dev, 333 "failed to add devfreq-event device\n"); 334 goto err; 335 } 336 } 337 338 clk_prepare_enable(info->ppmu.clk); 339 340 return 0; 341 err: 342 iounmap(info->ppmu.base); 343 344 return ret; 345 } 346 347 static int exynos_ppmu_remove(struct platform_device *pdev) 348 { 349 struct exynos_ppmu *info = platform_get_drvdata(pdev); 350 351 clk_disable_unprepare(info->ppmu.clk); 352 iounmap(info->ppmu.base); 353 354 return 0; 355 } 356 357 static struct of_device_id exynos_ppmu_id_match[] = { 358 { .compatible = "samsung,exynos-ppmu", }, 359 { /* sentinel */ }, 360 }; 361 362 static struct platform_driver exynos_ppmu_driver = { 363 .probe = exynos_ppmu_probe, 364 .remove = exynos_ppmu_remove, 365 .driver = { 366 .name = "exynos-ppmu", 367 .of_match_table = exynos_ppmu_id_match, 368 }, 369 }; 370 module_platform_driver(exynos_ppmu_driver); 371 372 MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver"); 373 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); 374 MODULE_LICENSE("GPL"); 375