| .. | .. |
|---|
| 5 | 5 | * Description: CoreSight Funnel driver |
|---|
| 6 | 6 | */ |
|---|
| 7 | 7 | |
|---|
| 8 | +#include <linux/acpi.h> |
|---|
| 8 | 9 | #include <linux/kernel.h> |
|---|
| 9 | 10 | #include <linux/init.h> |
|---|
| 10 | 11 | #include <linux/types.h> |
|---|
| .. | .. |
|---|
| 29 | 30 | #define FUNNEL_HOLDTIME (0x7 << FUNNEL_HOLDTIME_SHFT) |
|---|
| 30 | 31 | #define FUNNEL_ENSx_MASK 0xff |
|---|
| 31 | 32 | |
|---|
| 33 | +DEFINE_CORESIGHT_DEVLIST(funnel_devs, "funnel"); |
|---|
| 34 | + |
|---|
| 32 | 35 | /** |
|---|
| 33 | 36 | * struct funnel_drvdata - specifics associated to a funnel component |
|---|
| 34 | 37 | * @base: memory mapped base address for this component. |
|---|
| 35 | | - * @dev: the device entity associated to this component. |
|---|
| 36 | 38 | * @atclk: optional clock for the core parts of the funnel. |
|---|
| 37 | 39 | * @csdev: component vitals needed by the framework. |
|---|
| 38 | 40 | * @priority: port selection order. |
|---|
| .. | .. |
|---|
| 40 | 42 | */ |
|---|
| 41 | 43 | struct funnel_drvdata { |
|---|
| 42 | 44 | void __iomem *base; |
|---|
| 43 | | - struct device *dev; |
|---|
| 44 | 45 | struct clk *atclk; |
|---|
| 45 | 46 | struct coresight_device *csdev; |
|---|
| 46 | 47 | unsigned long priority; |
|---|
| .. | .. |
|---|
| 51 | 52 | { |
|---|
| 52 | 53 | u32 functl; |
|---|
| 53 | 54 | int rc = 0; |
|---|
| 55 | + struct coresight_device *csdev = drvdata->csdev; |
|---|
| 54 | 56 | |
|---|
| 55 | 57 | CS_UNLOCK(drvdata->base); |
|---|
| 56 | 58 | |
|---|
| 57 | 59 | functl = readl_relaxed(drvdata->base + FUNNEL_FUNCTL); |
|---|
| 58 | 60 | /* Claim the device only when we enable the first slave */ |
|---|
| 59 | 61 | if (!(functl & FUNNEL_ENSx_MASK)) { |
|---|
| 60 | | - rc = coresight_claim_device_unlocked(drvdata->base); |
|---|
| 62 | + rc = coresight_claim_device_unlocked(csdev); |
|---|
| 61 | 63 | if (rc) |
|---|
| 62 | 64 | goto done; |
|---|
| 63 | 65 | } |
|---|
| .. | .. |
|---|
| 92 | 94 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
|---|
| 93 | 95 | |
|---|
| 94 | 96 | if (first_enable) |
|---|
| 95 | | - dev_dbg(drvdata->dev, "FUNNEL inport %d enabled\n", inport); |
|---|
| 97 | + dev_dbg(&csdev->dev, "FUNNEL inport %d enabled\n", inport); |
|---|
| 96 | 98 | return rc; |
|---|
| 97 | 99 | } |
|---|
| 98 | 100 | |
|---|
| .. | .. |
|---|
| 100 | 102 | int inport) |
|---|
| 101 | 103 | { |
|---|
| 102 | 104 | u32 functl; |
|---|
| 105 | + struct coresight_device *csdev = drvdata->csdev; |
|---|
| 103 | 106 | |
|---|
| 104 | 107 | CS_UNLOCK(drvdata->base); |
|---|
| 105 | 108 | |
|---|
| .. | .. |
|---|
| 109 | 112 | |
|---|
| 110 | 113 | /* Disclaim the device if none of the slaves are now active */ |
|---|
| 111 | 114 | if (!(functl & FUNNEL_ENSx_MASK)) |
|---|
| 112 | | - coresight_disclaim_device_unlocked(drvdata->base); |
|---|
| 115 | + coresight_disclaim_device_unlocked(csdev); |
|---|
| 113 | 116 | |
|---|
| 114 | 117 | CS_LOCK(drvdata->base); |
|---|
| 115 | 118 | } |
|---|
| .. | .. |
|---|
| 130 | 133 | spin_unlock_irqrestore(&drvdata->spinlock, flags); |
|---|
| 131 | 134 | |
|---|
| 132 | 135 | if (last_disable) |
|---|
| 133 | | - dev_dbg(drvdata->dev, "FUNNEL inport %d disabled\n", inport); |
|---|
| 136 | + dev_dbg(&csdev->dev, "FUNNEL inport %d disabled\n", inport); |
|---|
| 134 | 137 | } |
|---|
| 135 | 138 | |
|---|
| 136 | 139 | static const struct coresight_ops_link funnel_link_ops = { |
|---|
| .. | .. |
|---|
| 185 | 188 | u32 val; |
|---|
| 186 | 189 | struct funnel_drvdata *drvdata = dev_get_drvdata(dev->parent); |
|---|
| 187 | 190 | |
|---|
| 188 | | - pm_runtime_get_sync(drvdata->dev); |
|---|
| 191 | + pm_runtime_get_sync(dev->parent); |
|---|
| 189 | 192 | |
|---|
| 190 | 193 | val = get_funnel_ctrl_hw(drvdata); |
|---|
| 191 | 194 | |
|---|
| 192 | | - pm_runtime_put(drvdata->dev); |
|---|
| 195 | + pm_runtime_put(dev->parent); |
|---|
| 193 | 196 | |
|---|
| 194 | 197 | return sprintf(buf, "%#x\n", val); |
|---|
| 195 | 198 | } |
|---|
| .. | .. |
|---|
| 209 | 212 | struct coresight_platform_data *pdata = NULL; |
|---|
| 210 | 213 | struct funnel_drvdata *drvdata; |
|---|
| 211 | 214 | struct coresight_desc desc = { 0 }; |
|---|
| 212 | | - struct device_node *np = dev->of_node; |
|---|
| 213 | 215 | |
|---|
| 214 | | - if (np) { |
|---|
| 215 | | - pdata = of_get_coresight_platform_data(dev, np); |
|---|
| 216 | | - if (IS_ERR(pdata)) |
|---|
| 217 | | - return PTR_ERR(pdata); |
|---|
| 218 | | - dev->platform_data = pdata; |
|---|
| 219 | | - } |
|---|
| 216 | + if (is_of_node(dev_fwnode(dev)) && |
|---|
| 217 | + of_device_is_compatible(dev->of_node, "arm,coresight-funnel")) |
|---|
| 218 | + dev_warn_once(dev, "Uses OBSOLETE CoreSight funnel binding\n"); |
|---|
| 220 | 219 | |
|---|
| 221 | | - if (of_device_is_compatible(np, "arm,coresight-funnel")) |
|---|
| 222 | | - pr_warn_once("Uses OBSOLETE CoreSight funnel binding\n"); |
|---|
| 220 | + desc.name = coresight_alloc_device_name(&funnel_devs, dev); |
|---|
| 221 | + if (!desc.name) |
|---|
| 222 | + return -ENOMEM; |
|---|
| 223 | 223 | |
|---|
| 224 | 224 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
|---|
| 225 | 225 | if (!drvdata) |
|---|
| 226 | 226 | return -ENOMEM; |
|---|
| 227 | 227 | |
|---|
| 228 | | - drvdata->dev = dev; |
|---|
| 229 | 228 | drvdata->atclk = devm_clk_get(dev, "atclk"); /* optional */ |
|---|
| 230 | 229 | if (!IS_ERR(drvdata->atclk)) { |
|---|
| 231 | 230 | ret = clk_prepare_enable(drvdata->atclk); |
|---|
| .. | .. |
|---|
| 245 | 244 | } |
|---|
| 246 | 245 | drvdata->base = base; |
|---|
| 247 | 246 | desc.groups = coresight_funnel_groups; |
|---|
| 247 | + desc.access = CSDEV_ACCESS_IOMEM(base); |
|---|
| 248 | 248 | } |
|---|
| 249 | 249 | |
|---|
| 250 | 250 | dev_set_drvdata(dev, drvdata); |
|---|
| 251 | + |
|---|
| 252 | + pdata = coresight_get_platform_data(dev); |
|---|
| 253 | + if (IS_ERR(pdata)) { |
|---|
| 254 | + ret = PTR_ERR(pdata); |
|---|
| 255 | + goto out_disable_clk; |
|---|
| 256 | + } |
|---|
| 257 | + dev->platform_data = pdata; |
|---|
| 251 | 258 | |
|---|
| 252 | 259 | spin_lock_init(&drvdata->spinlock); |
|---|
| 253 | 260 | desc.type = CORESIGHT_DEV_TYPE_LINK; |
|---|
| .. | .. |
|---|
| 268 | 275 | if (ret && !IS_ERR_OR_NULL(drvdata->atclk)) |
|---|
| 269 | 276 | clk_disable_unprepare(drvdata->atclk); |
|---|
| 270 | 277 | return ret; |
|---|
| 278 | +} |
|---|
| 279 | + |
|---|
| 280 | +static int funnel_remove(struct device *dev) |
|---|
| 281 | +{ |
|---|
| 282 | + struct funnel_drvdata *drvdata = dev_get_drvdata(dev); |
|---|
| 283 | + |
|---|
| 284 | + coresight_unregister(drvdata->csdev); |
|---|
| 285 | + |
|---|
| 286 | + return 0; |
|---|
| 271 | 287 | } |
|---|
| 272 | 288 | |
|---|
| 273 | 289 | #ifdef CONFIG_PM |
|---|
| .. | .. |
|---|
| 315 | 331 | return ret; |
|---|
| 316 | 332 | } |
|---|
| 317 | 333 | |
|---|
| 334 | +static int static_funnel_remove(struct platform_device *pdev) |
|---|
| 335 | +{ |
|---|
| 336 | + funnel_remove(&pdev->dev); |
|---|
| 337 | + pm_runtime_disable(&pdev->dev); |
|---|
| 338 | + return 0; |
|---|
| 339 | +} |
|---|
| 340 | + |
|---|
| 318 | 341 | static const struct of_device_id static_funnel_match[] = { |
|---|
| 319 | 342 | {.compatible = "arm,coresight-static-funnel"}, |
|---|
| 320 | 343 | {} |
|---|
| 321 | 344 | }; |
|---|
| 322 | 345 | |
|---|
| 346 | +MODULE_DEVICE_TABLE(of, static_funnel_match); |
|---|
| 347 | + |
|---|
| 348 | +#ifdef CONFIG_ACPI |
|---|
| 349 | +static const struct acpi_device_id static_funnel_ids[] = { |
|---|
| 350 | + {"ARMHC9FE", 0}, |
|---|
| 351 | + {}, |
|---|
| 352 | +}; |
|---|
| 353 | + |
|---|
| 354 | +MODULE_DEVICE_TABLE(acpi, static_funnel_ids); |
|---|
| 355 | +#endif |
|---|
| 356 | + |
|---|
| 323 | 357 | static struct platform_driver static_funnel_driver = { |
|---|
| 324 | 358 | .probe = static_funnel_probe, |
|---|
| 359 | + .remove = static_funnel_remove, |
|---|
| 325 | 360 | .driver = { |
|---|
| 326 | 361 | .name = "coresight-static-funnel", |
|---|
| 362 | + .owner = THIS_MODULE, |
|---|
| 327 | 363 | .of_match_table = static_funnel_match, |
|---|
| 364 | + .acpi_match_table = ACPI_PTR(static_funnel_ids), |
|---|
| 328 | 365 | .pm = &funnel_dev_pm_ops, |
|---|
| 329 | 366 | .suppress_bind_attrs = true, |
|---|
| 330 | 367 | }, |
|---|
| 331 | 368 | }; |
|---|
| 332 | | -builtin_platform_driver(static_funnel_driver); |
|---|
| 333 | 369 | |
|---|
| 334 | 370 | static int dynamic_funnel_probe(struct amba_device *adev, |
|---|
| 335 | 371 | const struct amba_id *id) |
|---|
| 336 | 372 | { |
|---|
| 337 | 373 | return funnel_probe(&adev->dev, &adev->res); |
|---|
| 374 | +} |
|---|
| 375 | + |
|---|
| 376 | +static void dynamic_funnel_remove(struct amba_device *adev) |
|---|
| 377 | +{ |
|---|
| 378 | + funnel_remove(&adev->dev); |
|---|
| 338 | 379 | } |
|---|
| 339 | 380 | |
|---|
| 340 | 381 | static const struct amba_id dynamic_funnel_ids[] = { |
|---|
| .. | .. |
|---|
| 350 | 391 | { 0, 0}, |
|---|
| 351 | 392 | }; |
|---|
| 352 | 393 | |
|---|
| 394 | +MODULE_DEVICE_TABLE(amba, dynamic_funnel_ids); |
|---|
| 395 | + |
|---|
| 353 | 396 | static struct amba_driver dynamic_funnel_driver = { |
|---|
| 354 | 397 | .drv = { |
|---|
| 355 | 398 | .name = "coresight-dynamic-funnel", |
|---|
| .. | .. |
|---|
| 358 | 401 | .suppress_bind_attrs = true, |
|---|
| 359 | 402 | }, |
|---|
| 360 | 403 | .probe = dynamic_funnel_probe, |
|---|
| 404 | + .remove = dynamic_funnel_remove, |
|---|
| 361 | 405 | .id_table = dynamic_funnel_ids, |
|---|
| 362 | 406 | }; |
|---|
| 363 | | -builtin_amba_driver(dynamic_funnel_driver); |
|---|
| 407 | + |
|---|
| 408 | +static int __init funnel_init(void) |
|---|
| 409 | +{ |
|---|
| 410 | + int ret; |
|---|
| 411 | + |
|---|
| 412 | + ret = platform_driver_register(&static_funnel_driver); |
|---|
| 413 | + if (ret) { |
|---|
| 414 | + pr_info("Error registering platform driver\n"); |
|---|
| 415 | + return ret; |
|---|
| 416 | + } |
|---|
| 417 | + |
|---|
| 418 | + ret = amba_driver_register(&dynamic_funnel_driver); |
|---|
| 419 | + if (ret) { |
|---|
| 420 | + pr_info("Error registering amba driver\n"); |
|---|
| 421 | + platform_driver_unregister(&static_funnel_driver); |
|---|
| 422 | + } |
|---|
| 423 | + |
|---|
| 424 | + return ret; |
|---|
| 425 | +} |
|---|
| 426 | + |
|---|
| 427 | +static void __exit funnel_exit(void) |
|---|
| 428 | +{ |
|---|
| 429 | + platform_driver_unregister(&static_funnel_driver); |
|---|
| 430 | + amba_driver_unregister(&dynamic_funnel_driver); |
|---|
| 431 | +} |
|---|
| 432 | + |
|---|
| 433 | +module_init(funnel_init); |
|---|
| 434 | +module_exit(funnel_exit); |
|---|
| 435 | + |
|---|
| 436 | +MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>"); |
|---|
| 437 | +MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>"); |
|---|
| 438 | +MODULE_DESCRIPTION("Arm CoreSight Funnel Driver"); |
|---|
| 439 | +MODULE_LICENSE("GPL v2"); |
|---|