1015 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2018 Linaro Limited, All rights reserved.4 * Author: Mike Leach <mike.leach@linaro.org>5 */6 7#include <linux/amba/bus.h>8#include <linux/atomic.h>9#include <linux/bits.h>10#include <linux/coresight.h>11#include <linux/cpu_pm.h>12#include <linux/cpuhotplug.h>13#include <linux/device.h>14#include <linux/io.h>15#include <linux/kernel.h>16#include <linux/list.h>17#include <linux/mutex.h>18#include <linux/pm_runtime.h>19#include <linux/property.h>20#include <linux/spinlock.h>21 22#include "coresight-priv.h"23#include "coresight-cti.h"24 25/*26 * CTI devices can be associated with a PE, or be connected to CoreSight27 * hardware. We have a list of all CTIs irrespective of CPU bound or28 * otherwise.29 *30 * We assume that the non-CPU CTIs are always powered as we do with sinks etc.31 *32 * We leave the client to figure out if all the CTIs are interconnected with33 * the same CTM, in general this is the case but does not always have to be.34 */35 36/* net of CTI devices connected via CTM */37static LIST_HEAD(ect_net);38 39/* protect the list */40static DEFINE_MUTEX(ect_mutex);41 42#define csdev_to_cti_drvdata(csdev) \43 dev_get_drvdata(csdev->dev.parent)44 45/* power management handling */46static int nr_cti_cpu;47 48/* quick lookup list for CPU bound CTIs when power handling */49static struct cti_drvdata *cti_cpu_drvdata[NR_CPUS];50 51/*52 * CTI naming. CTI bound to cores will have the name cti_cpu<N> where53 * N is the CPU ID. System CTIs will have the name cti_sys<I> where I54 * is an index allocated by order of discovery.55 *56 * CTI device name list - for CTI not bound to cores.57 */58DEFINE_CORESIGHT_DEVLIST(cti_sys_devs, "cti_sys");59 60/* write set of regs to hardware - call with spinlock claimed */61void cti_write_all_hw_regs(struct cti_drvdata *drvdata)62{63 struct cti_config *config = &drvdata->config;64 int i;65 66 CS_UNLOCK(drvdata->base);67 68 /* disable CTI before writing registers */69 writel_relaxed(0, drvdata->base + CTICONTROL);70 71 /* write the CTI trigger registers */72 for (i = 0; i < config->nr_trig_max; i++) {73 writel_relaxed(config->ctiinen[i], drvdata->base + CTIINEN(i));74 writel_relaxed(config->ctiouten[i],75 drvdata->base + CTIOUTEN(i));76 }77 78 /* other regs */79 writel_relaxed(config->ctigate, drvdata->base + CTIGATE);80 writel_relaxed(config->asicctl, drvdata->base + ASICCTL);81 writel_relaxed(config->ctiappset, drvdata->base + CTIAPPSET);82 83 /* re-enable CTI */84 writel_relaxed(1, drvdata->base + CTICONTROL);85 86 CS_LOCK(drvdata->base);87}88 89/* write regs to hardware and enable */90static int cti_enable_hw(struct cti_drvdata *drvdata)91{92 struct cti_config *config = &drvdata->config;93 unsigned long flags;94 int rc = 0;95 96 spin_lock_irqsave(&drvdata->spinlock, flags);97 98 /* no need to do anything if enabled or unpowered*/99 if (config->hw_enabled || !config->hw_powered)100 goto cti_state_unchanged;101 102 /* claim the device */103 rc = coresight_claim_device(drvdata->csdev);104 if (rc)105 goto cti_err_not_enabled;106 107 cti_write_all_hw_regs(drvdata);108 109 config->hw_enabled = true;110 drvdata->config.enable_req_count++;111 spin_unlock_irqrestore(&drvdata->spinlock, flags);112 return rc;113 114cti_state_unchanged:115 drvdata->config.enable_req_count++;116 117 /* cannot enable due to error */118cti_err_not_enabled:119 spin_unlock_irqrestore(&drvdata->spinlock, flags);120 return rc;121}122 123/* re-enable CTI on CPU when using CPU hotplug */124static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)125{126 struct cti_config *config = &drvdata->config;127 128 spin_lock(&drvdata->spinlock);129 config->hw_powered = true;130 131 /* no need to do anything if no enable request */132 if (!drvdata->config.enable_req_count)133 goto cti_hp_not_enabled;134 135 /* try to claim the device */136 if (coresight_claim_device(drvdata->csdev))137 goto cti_hp_not_enabled;138 139 cti_write_all_hw_regs(drvdata);140 config->hw_enabled = true;141 spin_unlock(&drvdata->spinlock);142 return;143 144 /* did not re-enable due to no claim / no request */145cti_hp_not_enabled:146 spin_unlock(&drvdata->spinlock);147}148 149/* disable hardware */150static int cti_disable_hw(struct cti_drvdata *drvdata)151{152 struct cti_config *config = &drvdata->config;153 struct coresight_device *csdev = drvdata->csdev;154 int ret = 0;155 156 spin_lock(&drvdata->spinlock);157 158 /* don't allow negative refcounts, return an error */159 if (!drvdata->config.enable_req_count) {160 ret = -EINVAL;161 goto cti_not_disabled;162 }163 164 /* check refcount - disable on 0 */165 if (--drvdata->config.enable_req_count > 0)166 goto cti_not_disabled;167 168 /* no need to do anything if disabled or cpu unpowered */169 if (!config->hw_enabled || !config->hw_powered)170 goto cti_not_disabled;171 172 CS_UNLOCK(drvdata->base);173 174 /* disable CTI */175 writel_relaxed(0, drvdata->base + CTICONTROL);176 config->hw_enabled = false;177 178 coresight_disclaim_device_unlocked(csdev);179 CS_LOCK(drvdata->base);180 spin_unlock(&drvdata->spinlock);181 return ret;182 183 /* not disabled this call */184cti_not_disabled:185 spin_unlock(&drvdata->spinlock);186 return ret;187}188 189void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value)190{191 CS_UNLOCK(drvdata->base);192 writel_relaxed(value, drvdata->base + offset);193 CS_LOCK(drvdata->base);194}195 196void cti_write_intack(struct device *dev, u32 ackval)197{198 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);199 struct cti_config *config = &drvdata->config;200 201 spin_lock(&drvdata->spinlock);202 /* write if enabled */203 if (cti_active(config))204 cti_write_single_reg(drvdata, CTIINTACK, ackval);205 spin_unlock(&drvdata->spinlock);206}207 208/*209 * Look at the HW DEVID register for some of the HW settings.210 * DEVID[15:8] - max number of in / out triggers.211 */212#define CTI_DEVID_MAXTRIGS(devid_val) ((int) BMVAL(devid_val, 8, 15))213 214/* DEVID[19:16] - number of CTM channels */215#define CTI_DEVID_CTMCHANNELS(devid_val) ((int) BMVAL(devid_val, 16, 19))216 217static void cti_set_default_config(struct device *dev,218 struct cti_drvdata *drvdata)219{220 struct cti_config *config = &drvdata->config;221 u32 devid;222 223 devid = readl_relaxed(drvdata->base + CORESIGHT_DEVID);224 config->nr_trig_max = CTI_DEVID_MAXTRIGS(devid);225 226 /*227 * no current hardware should exceed this, but protect the driver228 * in case of fault / out of spec hw229 */230 if (config->nr_trig_max > CTIINOUTEN_MAX) {231 dev_warn_once(dev,232 "Limiting HW MaxTrig value(%d) to driver max(%d)\n",233 config->nr_trig_max, CTIINOUTEN_MAX);234 config->nr_trig_max = CTIINOUTEN_MAX;235 }236 237 config->nr_ctm_channels = CTI_DEVID_CTMCHANNELS(devid);238 239 /* Most regs default to 0 as zalloc'ed except...*/240 config->trig_filter_enable = true;241 config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);242 config->enable_req_count = 0;243}244 245/*246 * Add a connection entry to the list of connections for this247 * CTI device.248 */249int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,250 struct cti_trig_con *tc,251 struct coresight_device *csdev,252 const char *assoc_dev_name)253{254 struct cti_device *cti_dev = &drvdata->ctidev;255 256 tc->con_dev = csdev;257 /*258 * Prefer actual associated CS device dev name to supplied value -259 * which is likely to be node name / other conn name.260 */261 if (csdev)262 tc->con_dev_name = dev_name(&csdev->dev);263 else if (assoc_dev_name != NULL) {264 tc->con_dev_name = devm_kstrdup(dev,265 assoc_dev_name, GFP_KERNEL);266 if (!tc->con_dev_name)267 return -ENOMEM;268 }269 list_add_tail(&tc->node, &cti_dev->trig_cons);270 cti_dev->nr_trig_con++;271 272 /* add connection usage bit info to overall info */273 drvdata->config.trig_in_use |= tc->con_in->used_mask;274 drvdata->config.trig_out_use |= tc->con_out->used_mask;275 276 return 0;277}278 279/* create a trigger connection with appropriately sized signal groups */280struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,281 int out_sigs)282{283 struct cti_trig_con *tc = NULL;284 struct cti_trig_grp *in = NULL, *out = NULL;285 286 tc = devm_kzalloc(dev, sizeof(struct cti_trig_con), GFP_KERNEL);287 if (!tc)288 return tc;289 290 in = devm_kzalloc(dev,291 offsetof(struct cti_trig_grp, sig_types[in_sigs]),292 GFP_KERNEL);293 if (!in)294 return NULL;295 296 out = devm_kzalloc(dev,297 offsetof(struct cti_trig_grp, sig_types[out_sigs]),298 GFP_KERNEL);299 if (!out)300 return NULL;301 302 tc->con_in = in;303 tc->con_out = out;304 tc->con_in->nr_sigs = in_sigs;305 tc->con_out->nr_sigs = out_sigs;306 return tc;307}308 309/*310 * Add a default connection if nothing else is specified.311 * single connection based on max in/out info, no assoc device312 */313int cti_add_default_connection(struct device *dev, struct cti_drvdata *drvdata)314{315 int ret = 0;316 int n_trigs = drvdata->config.nr_trig_max;317 u32 n_trig_mask = GENMASK(n_trigs - 1, 0);318 struct cti_trig_con *tc = NULL;319 320 /*321 * Assume max trigs for in and out,322 * all used, default sig types allocated323 */324 tc = cti_allocate_trig_con(dev, n_trigs, n_trigs);325 if (!tc)326 return -ENOMEM;327 328 tc->con_in->used_mask = n_trig_mask;329 tc->con_out->used_mask = n_trig_mask;330 ret = cti_add_connection_entry(dev, drvdata, tc, NULL, "default");331 return ret;332}333 334/** cti channel api **/335/* attach/detach channel from trigger - write through if enabled. */336int cti_channel_trig_op(struct device *dev, enum cti_chan_op op,337 enum cti_trig_dir direction, u32 channel_idx,338 u32 trigger_idx)339{340 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);341 struct cti_config *config = &drvdata->config;342 u32 trig_bitmask;343 u32 chan_bitmask;344 u32 reg_value;345 int reg_offset;346 347 /* ensure indexes in range */348 if ((channel_idx >= config->nr_ctm_channels) ||349 (trigger_idx >= config->nr_trig_max))350 return -EINVAL;351 352 trig_bitmask = BIT(trigger_idx);353 354 /* ensure registered triggers and not out filtered */355 if (direction == CTI_TRIG_IN) {356 if (!(trig_bitmask & config->trig_in_use))357 return -EINVAL;358 } else {359 if (!(trig_bitmask & config->trig_out_use))360 return -EINVAL;361 362 if ((config->trig_filter_enable) &&363 (config->trig_out_filter & trig_bitmask))364 return -EINVAL;365 }366 367 /* update the local register values */368 chan_bitmask = BIT(channel_idx);369 reg_offset = (direction == CTI_TRIG_IN ? CTIINEN(trigger_idx) :370 CTIOUTEN(trigger_idx));371 372 spin_lock(&drvdata->spinlock);373 374 /* read - modify write - the trigger / channel enable value */375 reg_value = direction == CTI_TRIG_IN ? config->ctiinen[trigger_idx] :376 config->ctiouten[trigger_idx];377 if (op == CTI_CHAN_ATTACH)378 reg_value |= chan_bitmask;379 else380 reg_value &= ~chan_bitmask;381 382 /* write local copy */383 if (direction == CTI_TRIG_IN)384 config->ctiinen[trigger_idx] = reg_value;385 else386 config->ctiouten[trigger_idx] = reg_value;387 388 /* write through if enabled */389 if (cti_active(config))390 cti_write_single_reg(drvdata, reg_offset, reg_value);391 spin_unlock(&drvdata->spinlock);392 return 0;393}394 395int cti_channel_gate_op(struct device *dev, enum cti_chan_gate_op op,396 u32 channel_idx)397{398 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);399 struct cti_config *config = &drvdata->config;400 u32 chan_bitmask;401 u32 reg_value;402 int err = 0;403 404 if (channel_idx >= config->nr_ctm_channels)405 return -EINVAL;406 407 chan_bitmask = BIT(channel_idx);408 409 spin_lock(&drvdata->spinlock);410 reg_value = config->ctigate;411 switch (op) {412 case CTI_GATE_CHAN_ENABLE:413 reg_value |= chan_bitmask;414 break;415 416 case CTI_GATE_CHAN_DISABLE:417 reg_value &= ~chan_bitmask;418 break;419 420 default:421 err = -EINVAL;422 break;423 }424 if (err == 0) {425 config->ctigate = reg_value;426 if (cti_active(config))427 cti_write_single_reg(drvdata, CTIGATE, reg_value);428 }429 spin_unlock(&drvdata->spinlock);430 return err;431}432 433int cti_channel_setop(struct device *dev, enum cti_chan_set_op op,434 u32 channel_idx)435{436 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);437 struct cti_config *config = &drvdata->config;438 u32 chan_bitmask;439 u32 reg_value;440 u32 reg_offset;441 int err = 0;442 443 if (channel_idx >= config->nr_ctm_channels)444 return -EINVAL;445 446 chan_bitmask = BIT(channel_idx);447 448 spin_lock(&drvdata->spinlock);449 reg_value = config->ctiappset;450 switch (op) {451 case CTI_CHAN_SET:452 config->ctiappset |= chan_bitmask;453 reg_value = config->ctiappset;454 reg_offset = CTIAPPSET;455 break;456 457 case CTI_CHAN_CLR:458 config->ctiappset &= ~chan_bitmask;459 reg_value = chan_bitmask;460 reg_offset = CTIAPPCLEAR;461 break;462 463 case CTI_CHAN_PULSE:464 config->ctiappset &= ~chan_bitmask;465 reg_value = chan_bitmask;466 reg_offset = CTIAPPPULSE;467 break;468 469 default:470 err = -EINVAL;471 break;472 }473 474 if ((err == 0) && cti_active(config))475 cti_write_single_reg(drvdata, reg_offset, reg_value);476 spin_unlock(&drvdata->spinlock);477 478 return err;479}480 481static bool cti_add_sysfs_link(struct cti_drvdata *drvdata,482 struct cti_trig_con *tc)483{484 struct coresight_sysfs_link link_info;485 int link_err = 0;486 487 link_info.orig = drvdata->csdev;488 link_info.orig_name = tc->con_dev_name;489 link_info.target = tc->con_dev;490 link_info.target_name = dev_name(&drvdata->csdev->dev);491 492 link_err = coresight_add_sysfs_link(&link_info);493 if (link_err)494 dev_warn(&drvdata->csdev->dev,495 "Failed to set CTI sysfs link %s<=>%s\n",496 link_info.orig_name, link_info.target_name);497 return !link_err;498}499 500static void cti_remove_sysfs_link(struct cti_drvdata *drvdata,501 struct cti_trig_con *tc)502{503 struct coresight_sysfs_link link_info;504 505 link_info.orig = drvdata->csdev;506 link_info.orig_name = tc->con_dev_name;507 link_info.target = tc->con_dev;508 link_info.target_name = dev_name(&drvdata->csdev->dev);509 coresight_remove_sysfs_link(&link_info);510}511 512/*513 * Look for a matching connection device name in the list of connections.514 * If found then swap in the csdev name, set trig con association pointer515 * and return found.516 */517static bool518cti_match_fixup_csdev(struct cti_device *ctidev, const char *node_name,519 struct coresight_device *csdev)520{521 struct cti_trig_con *tc;522 struct cti_drvdata *drvdata = container_of(ctidev, struct cti_drvdata,523 ctidev);524 525 list_for_each_entry(tc, &ctidev->trig_cons, node) {526 if (tc->con_dev_name) {527 if (!strcmp(node_name, tc->con_dev_name)) {528 /* match: so swap in csdev name & dev */529 tc->con_dev_name = dev_name(&csdev->dev);530 tc->con_dev = csdev;531 /* try to set sysfs link */532 if (cti_add_sysfs_link(drvdata, tc))533 return true;534 /* link failed - remove CTI reference */535 tc->con_dev = NULL;536 break;537 }538 }539 }540 return false;541}542 543/*544 * Search the cti list to add an associated CTI into the supplied CS device545 * This will set the association if CTI declared before the CS device.546 * (called from coresight_register() without coresight_mutex locked).547 */548static void cti_add_assoc_to_csdev(struct coresight_device *csdev)549{550 struct cti_drvdata *ect_item;551 struct cti_device *ctidev;552 const char *node_name = NULL;553 554 /* protect the list */555 mutex_lock(&ect_mutex);556 557 /* exit if current is an ECT device.*/558 if ((csdev->type == CORESIGHT_DEV_TYPE_HELPER &&559 csdev->subtype.helper_subtype ==560 CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI) ||561 list_empty(&ect_net))562 goto cti_add_done;563 564 /* if we didn't find the csdev previously we used the fwnode name */565 node_name = cti_plat_get_node_name(dev_fwnode(csdev->dev.parent));566 if (!node_name)567 goto cti_add_done;568 569 /* for each CTI in list... */570 list_for_each_entry(ect_item, &ect_net, node) {571 ctidev = &ect_item->ctidev;572 if (cti_match_fixup_csdev(ctidev, node_name, csdev)) {573 /*574 * if we found a matching csdev then update the ECT575 * association pointer for the device with this CTI.576 */577 coresight_add_helper(csdev, ect_item->csdev);578 break;579 }580 }581cti_add_done:582 mutex_unlock(&ect_mutex);583}584 585/*586 * Removing the associated devices is easier.587 */588static void cti_remove_assoc_from_csdev(struct coresight_device *csdev)589{590 struct cti_drvdata *ctidrv;591 struct cti_trig_con *tc;592 struct cti_device *ctidev;593 union coresight_dev_subtype cti_subtype = {594 .helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI595 };596 struct coresight_device *cti_csdev = coresight_find_output_type(597 csdev->pdata, CORESIGHT_DEV_TYPE_HELPER, cti_subtype);598 599 if (!cti_csdev)600 return;601 602 mutex_lock(&ect_mutex);603 ctidrv = csdev_to_cti_drvdata(cti_csdev);604 ctidev = &ctidrv->ctidev;605 list_for_each_entry(tc, &ctidev->trig_cons, node) {606 if (tc->con_dev == csdev) {607 cti_remove_sysfs_link(ctidrv, tc);608 tc->con_dev = NULL;609 break;610 }611 }612 mutex_unlock(&ect_mutex);613}614 615/*616 * Operations to add and remove associated CTI.617 * Register to coresight core driver as call back function.618 */619static struct cti_assoc_op cti_assoc_ops = {620 .add = cti_add_assoc_to_csdev,621 .remove = cti_remove_assoc_from_csdev622};623 624/*625 * Update the cross references where the associated device was found626 * while we were building the connection info. This will occur if the627 * assoc device was registered before the CTI.628 */629static void cti_update_conn_xrefs(struct cti_drvdata *drvdata)630{631 struct cti_trig_con *tc;632 struct cti_device *ctidev = &drvdata->ctidev;633 634 list_for_each_entry(tc, &ctidev->trig_cons, node) {635 if (tc->con_dev) {636 /* if we can set the sysfs link */637 if (cti_add_sysfs_link(drvdata, tc))638 /* set the CTI/csdev association */639 coresight_add_helper(tc->con_dev,640 drvdata->csdev);641 else642 /* otherwise remove reference from CTI */643 tc->con_dev = NULL;644 }645 }646}647 648static void cti_remove_conn_xrefs(struct cti_drvdata *drvdata)649{650 struct cti_trig_con *tc;651 struct cti_device *ctidev = &drvdata->ctidev;652 653 list_for_each_entry(tc, &ctidev->trig_cons, node) {654 if (tc->con_dev) {655 cti_remove_sysfs_link(drvdata, tc);656 tc->con_dev = NULL;657 }658 }659}660 661/** cti PM callbacks **/662static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,663 void *v)664{665 struct cti_drvdata *drvdata;666 struct coresight_device *csdev;667 unsigned int cpu = smp_processor_id();668 int notify_res = NOTIFY_OK;669 670 if (!cti_cpu_drvdata[cpu])671 return NOTIFY_OK;672 673 drvdata = cti_cpu_drvdata[cpu];674 csdev = drvdata->csdev;675 676 if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu))677 return NOTIFY_BAD;678 679 spin_lock(&drvdata->spinlock);680 681 switch (cmd) {682 case CPU_PM_ENTER:683 /* CTI regs all static - we have a copy & nothing to save */684 drvdata->config.hw_powered = false;685 if (drvdata->config.hw_enabled)686 coresight_disclaim_device(csdev);687 break;688 689 case CPU_PM_ENTER_FAILED:690 drvdata->config.hw_powered = true;691 if (drvdata->config.hw_enabled) {692 if (coresight_claim_device(csdev))693 drvdata->config.hw_enabled = false;694 }695 break;696 697 case CPU_PM_EXIT:698 /* write hardware registers to re-enable. */699 drvdata->config.hw_powered = true;700 drvdata->config.hw_enabled = false;701 702 /* check enable reference count to enable HW */703 if (drvdata->config.enable_req_count) {704 /* check we can claim the device as we re-power */705 if (coresight_claim_device(csdev))706 goto cti_notify_exit;707 708 drvdata->config.hw_enabled = true;709 cti_write_all_hw_regs(drvdata);710 }711 break;712 713 default:714 notify_res = NOTIFY_DONE;715 break;716 }717 718cti_notify_exit:719 spin_unlock(&drvdata->spinlock);720 return notify_res;721}722 723static struct notifier_block cti_cpu_pm_nb = {724 .notifier_call = cti_cpu_pm_notify,725};726 727/* CPU HP handlers */728static int cti_starting_cpu(unsigned int cpu)729{730 struct cti_drvdata *drvdata = cti_cpu_drvdata[cpu];731 732 if (!drvdata)733 return 0;734 735 cti_cpuhp_enable_hw(drvdata);736 return 0;737}738 739static int cti_dying_cpu(unsigned int cpu)740{741 struct cti_drvdata *drvdata = cti_cpu_drvdata[cpu];742 743 if (!drvdata)744 return 0;745 746 spin_lock(&drvdata->spinlock);747 drvdata->config.hw_powered = false;748 if (drvdata->config.hw_enabled)749 coresight_disclaim_device(drvdata->csdev);750 spin_unlock(&drvdata->spinlock);751 return 0;752}753 754static int cti_pm_setup(struct cti_drvdata *drvdata)755{756 int ret;757 758 if (drvdata->ctidev.cpu == -1)759 return 0;760 761 if (nr_cti_cpu)762 goto done;763 764 cpus_read_lock();765 ret = cpuhp_setup_state_nocalls_cpuslocked(766 CPUHP_AP_ARM_CORESIGHT_CTI_STARTING,767 "arm/coresight_cti:starting",768 cti_starting_cpu, cti_dying_cpu);769 if (ret) {770 cpus_read_unlock();771 return ret;772 }773 774 ret = cpu_pm_register_notifier(&cti_cpu_pm_nb);775 cpus_read_unlock();776 if (ret) {777 cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING);778 return ret;779 }780 781done:782 nr_cti_cpu++;783 cti_cpu_drvdata[drvdata->ctidev.cpu] = drvdata;784 785 return 0;786}787 788/* release PM registrations */789static void cti_pm_release(struct cti_drvdata *drvdata)790{791 if (drvdata->ctidev.cpu == -1)792 return;793 794 cti_cpu_drvdata[drvdata->ctidev.cpu] = NULL;795 if (--nr_cti_cpu == 0) {796 cpu_pm_unregister_notifier(&cti_cpu_pm_nb);797 cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING);798 }799}800 801/** cti ect operations **/802int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data)803{804 struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);805 806 return cti_enable_hw(drvdata);807}808 809int cti_disable(struct coresight_device *csdev, void *data)810{811 struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);812 813 return cti_disable_hw(drvdata);814}815 816static const struct coresight_ops_helper cti_ops_ect = {817 .enable = cti_enable,818 .disable = cti_disable,819};820 821static const struct coresight_ops cti_ops = {822 .helper_ops = &cti_ops_ect,823};824 825/*826 * Free up CTI specific resources827 * called by dev->release, need to call down to underlying csdev release.828 */829static void cti_device_release(struct device *dev)830{831 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);832 struct cti_drvdata *ect_item, *ect_tmp;833 834 mutex_lock(&ect_mutex);835 cti_pm_release(drvdata);836 837 /* remove from the list */838 list_for_each_entry_safe(ect_item, ect_tmp, &ect_net, node) {839 if (ect_item == drvdata) {840 list_del(&ect_item->node);841 break;842 }843 }844 mutex_unlock(&ect_mutex);845 846 if (drvdata->csdev_release)847 drvdata->csdev_release(dev);848}849static void cti_remove(struct amba_device *adev)850{851 struct cti_drvdata *drvdata = dev_get_drvdata(&adev->dev);852 853 mutex_lock(&ect_mutex);854 cti_remove_conn_xrefs(drvdata);855 mutex_unlock(&ect_mutex);856 857 coresight_unregister(drvdata->csdev);858}859 860static int cti_probe(struct amba_device *adev, const struct amba_id *id)861{862 int ret = 0;863 void __iomem *base;864 struct device *dev = &adev->dev;865 struct cti_drvdata *drvdata = NULL;866 struct coresight_desc cti_desc;867 struct coresight_platform_data *pdata = NULL;868 struct resource *res = &adev->res;869 870 /* driver data*/871 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);872 if (!drvdata)873 return -ENOMEM;874 875 /* Validity for the resource is already checked by the AMBA core */876 base = devm_ioremap_resource(dev, res);877 if (IS_ERR(base))878 return PTR_ERR(base);879 880 drvdata->base = base;881 cti_desc.access = CSDEV_ACCESS_IOMEM(base);882 883 dev_set_drvdata(dev, drvdata);884 885 /* default CTI device info */886 drvdata->ctidev.cpu = -1;887 drvdata->ctidev.nr_trig_con = 0;888 drvdata->ctidev.ctm_id = 0;889 INIT_LIST_HEAD(&drvdata->ctidev.trig_cons);890 891 spin_lock_init(&drvdata->spinlock);892 893 /* initialise CTI driver config values */894 cti_set_default_config(dev, drvdata);895 896 pdata = coresight_cti_get_platform_data(dev);897 if (IS_ERR(pdata)) {898 dev_err(dev, "coresight_cti_get_platform_data err\n");899 return PTR_ERR(pdata);900 }901 902 /* default to powered - could change on PM notifications */903 drvdata->config.hw_powered = true;904 905 /* set up device name - will depend if cpu bound or otherwise */906 if (drvdata->ctidev.cpu >= 0)907 cti_desc.name = devm_kasprintf(dev, GFP_KERNEL, "cti_cpu%d",908 drvdata->ctidev.cpu);909 else910 cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev);911 if (!cti_desc.name)912 return -ENOMEM;913 914 /* setup CPU power management handling for CPU bound CTI devices. */915 ret = cti_pm_setup(drvdata);916 if (ret)917 return ret;918 919 /* create dynamic attributes for connections */920 ret = cti_create_cons_sysfs(dev, drvdata);921 if (ret) {922 dev_err(dev, "%s: create dynamic sysfs entries failed\n",923 cti_desc.name);924 goto pm_release;925 }926 927 /* set up coresight component description */928 cti_desc.pdata = pdata;929 cti_desc.type = CORESIGHT_DEV_TYPE_HELPER;930 cti_desc.subtype.helper_subtype = CORESIGHT_DEV_SUBTYPE_HELPER_ECT_CTI;931 cti_desc.ops = &cti_ops;932 cti_desc.groups = drvdata->ctidev.con_groups;933 cti_desc.dev = dev;934 drvdata->csdev = coresight_register(&cti_desc);935 if (IS_ERR(drvdata->csdev)) {936 ret = PTR_ERR(drvdata->csdev);937 goto pm_release;938 }939 940 /* add to list of CTI devices */941 mutex_lock(&ect_mutex);942 list_add(&drvdata->node, &ect_net);943 /* set any cross references */944 cti_update_conn_xrefs(drvdata);945 mutex_unlock(&ect_mutex);946 947 /* set up release chain */948 drvdata->csdev_release = drvdata->csdev->dev.release;949 drvdata->csdev->dev.release = cti_device_release;950 951 /* all done - dec pm refcount */952 pm_runtime_put(&adev->dev);953 dev_info(&drvdata->csdev->dev, "CTI initialized\n");954 return 0;955 956pm_release:957 cti_pm_release(drvdata);958 return ret;959}960 961static struct amba_cs_uci_id uci_id_cti[] = {962 {963 /* CTI UCI data */964 .devarch = 0x47701a14, /* CTI v2 */965 .devarch_mask = 0xfff0ffff,966 .devtype = 0x00000014, /* maj(0x4-debug) min(0x1-ECT) */967 }968};969 970static const struct amba_id cti_ids[] = {971 CS_AMBA_ID(0x000bb906), /* Coresight CTI (SoC 400), C-A72, C-A57 */972 CS_AMBA_ID(0x000bb922), /* CTI - C-A8 */973 CS_AMBA_ID(0x000bb9a8), /* CTI - C-A53 */974 CS_AMBA_ID(0x000bb9aa), /* CTI - C-A73 */975 CS_AMBA_UCI_ID(0x000bb9da, uci_id_cti), /* CTI - C-A35 */976 CS_AMBA_UCI_ID(0x000bb9ed, uci_id_cti), /* Coresight CTI (SoC 600) */977 { 0, 0, NULL },978};979 980MODULE_DEVICE_TABLE(amba, cti_ids);981 982static struct amba_driver cti_driver = {983 .drv = {984 .name = "coresight-cti",985 .suppress_bind_attrs = true,986 },987 .probe = cti_probe,988 .remove = cti_remove,989 .id_table = cti_ids,990};991 992static int __init cti_init(void)993{994 int ret;995 996 ret = amba_driver_register(&cti_driver);997 if (ret)998 pr_info("Error registering cti driver\n");999 coresight_set_cti_ops(&cti_assoc_ops);1000 return ret;1001}1002 1003static void __exit cti_exit(void)1004{1005 coresight_remove_cti_ops();1006 amba_driver_unregister(&cti_driver);1007}1008 1009module_init(cti_init);1010module_exit(cti_exit);1011 1012MODULE_AUTHOR("Mike Leach <mike.leach@linaro.org>");1013MODULE_DESCRIPTION("Arm CoreSight CTI Driver");1014MODULE_LICENSE("GPL v2");1015