1188 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2019 Linaro Limited, All rights reserved.4 * Author: Mike Leach <mike.leach@linaro.org>5 */6 7#include <linux/atomic.h>8#include <linux/coresight.h>9#include <linux/device.h>10#include <linux/io.h>11#include <linux/kernel.h>12#include <linux/spinlock.h>13#include <linux/sysfs.h>14 15#include "coresight-cti.h"16 17/*18 * Declare the number of static declared attribute groups19 * Value includes groups + NULL value at end of table.20 */21#define CORESIGHT_CTI_STATIC_GROUPS_MAX 522 23/*24 * List of trigger signal type names. Match the constants declared in25 * include\dt-bindings\arm\coresight-cti-dt.h26 */27static const char * const sig_type_names[] = {28 "genio", /* GEN_IO */29 "intreq", /* GEN_INTREQ */30 "intack", /* GEN_INTACK */31 "haltreq", /* GEN_HALTREQ */32 "restartreq", /* GEN_RESTARTREQ */33 "pe_edbgreq", /* PE_EDBGREQ */34 "pe_dbgrestart",/* PE_DBGRESTART */35 "pe_ctiirq", /* PE_CTIIRQ */36 "pe_pmuirq", /* PE_PMUIRQ */37 "pe_dbgtrigger",/* PE_DBGTRIGGER */38 "etm_extout", /* ETM_EXTOUT */39 "etm_extin", /* ETM_EXTIN */40 "snk_full", /* SNK_FULL */41 "snk_acqcomp", /* SNK_ACQCOMP */42 "snk_flushcomp",/* SNK_FLUSHCOMP */43 "snk_flushin", /* SNK_FLUSHIN */44 "snk_trigin", /* SNK_TRIGIN */45 "stm_asyncout", /* STM_ASYNCOUT */46 "stm_tout_spte",/* STM_TOUT_SPTE */47 "stm_tout_sw", /* STM_TOUT_SW */48 "stm_tout_hete",/* STM_TOUT_HETE */49 "stm_hwevent", /* STM_HWEVENT */50 "ela_tstart", /* ELA_TSTART */51 "ela_tstop", /* ELA_TSTOP */52 "ela_dbgreq", /* ELA_DBGREQ */53};54 55/* Show function pointer used in the connections dynamic declared attributes*/56typedef ssize_t (*p_show_fn)(struct device *dev, struct device_attribute *attr,57 char *buf);58 59/* Connection attribute types */60enum cti_conn_attr_type {61 CTI_CON_ATTR_NAME,62 CTI_CON_ATTR_TRIGIN_SIG,63 CTI_CON_ATTR_TRIGOUT_SIG,64 CTI_CON_ATTR_TRIGIN_TYPES,65 CTI_CON_ATTR_TRIGOUT_TYPES,66 CTI_CON_ATTR_MAX,67};68 69/* Names for the connection attributes */70static const char * const con_attr_names[CTI_CON_ATTR_MAX] = {71 "name",72 "in_signals",73 "out_signals",74 "in_types",75 "out_types",76};77 78/* basic attributes */79static ssize_t enable_show(struct device *dev,80 struct device_attribute *attr,81 char *buf)82{83 int enable_req;84 bool enabled, powered;85 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);86 87 spin_lock(&drvdata->spinlock);88 enable_req = drvdata->config.enable_req_count;89 powered = drvdata->config.hw_powered;90 enabled = drvdata->config.hw_enabled;91 spin_unlock(&drvdata->spinlock);92 93 if (powered)94 return sprintf(buf, "%d\n", enabled);95 else96 return sprintf(buf, "%d\n", !!enable_req);97}98 99static ssize_t enable_store(struct device *dev,100 struct device_attribute *attr,101 const char *buf, size_t size)102{103 int ret = 0;104 unsigned long val;105 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);106 107 ret = kstrtoul(buf, 0, &val);108 if (ret)109 return ret;110 111 if (val) {112 ret = pm_runtime_resume_and_get(dev->parent);113 if (ret)114 return ret;115 ret = cti_enable(drvdata->csdev, CS_MODE_SYSFS, NULL);116 if (ret)117 pm_runtime_put(dev->parent);118 } else {119 ret = cti_disable(drvdata->csdev, NULL);120 if (!ret)121 pm_runtime_put(dev->parent);122 }123 124 if (ret)125 return ret;126 return size;127}128static DEVICE_ATTR_RW(enable);129 130static ssize_t powered_show(struct device *dev,131 struct device_attribute *attr,132 char *buf)133{134 bool powered;135 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);136 137 spin_lock(&drvdata->spinlock);138 powered = drvdata->config.hw_powered;139 spin_unlock(&drvdata->spinlock);140 141 return sprintf(buf, "%d\n", powered);142}143static DEVICE_ATTR_RO(powered);144 145static ssize_t ctmid_show(struct device *dev,146 struct device_attribute *attr, char *buf)147{148 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);149 150 return sprintf(buf, "%d\n", drvdata->ctidev.ctm_id);151}152static DEVICE_ATTR_RO(ctmid);153 154static ssize_t nr_trigger_cons_show(struct device *dev,155 struct device_attribute *attr,156 char *buf)157{158 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);159 160 return sprintf(buf, "%d\n", drvdata->ctidev.nr_trig_con);161}162static DEVICE_ATTR_RO(nr_trigger_cons);163 164/* attribute and group sysfs tables. */165static struct attribute *coresight_cti_attrs[] = {166 &dev_attr_enable.attr,167 &dev_attr_powered.attr,168 &dev_attr_ctmid.attr,169 &dev_attr_nr_trigger_cons.attr,170 NULL,171};172 173/* register based attributes */174 175/* Read registers with power check only (no enable check). */176static ssize_t coresight_cti_reg_show(struct device *dev,177 struct device_attribute *attr, char *buf)178{179 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);180 struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);181 u32 val = 0;182 183 pm_runtime_get_sync(dev->parent);184 spin_lock(&drvdata->spinlock);185 if (drvdata->config.hw_powered)186 val = readl_relaxed(drvdata->base + cti_attr->off);187 spin_unlock(&drvdata->spinlock);188 pm_runtime_put_sync(dev->parent);189 return sysfs_emit(buf, "0x%x\n", val);190}191 192/* Write registers with power check only (no enable check). */193static __maybe_unused ssize_t coresight_cti_reg_store(struct device *dev,194 struct device_attribute *attr,195 const char *buf, size_t size)196{197 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);198 struct cs_off_attribute *cti_attr = container_of(attr, struct cs_off_attribute, attr);199 unsigned long val = 0;200 201 if (kstrtoul(buf, 0, &val))202 return -EINVAL;203 204 pm_runtime_get_sync(dev->parent);205 spin_lock(&drvdata->spinlock);206 if (drvdata->config.hw_powered)207 cti_write_single_reg(drvdata, cti_attr->off, val);208 spin_unlock(&drvdata->spinlock);209 pm_runtime_put_sync(dev->parent);210 return size;211}212 213#define coresight_cti_reg(name, offset) \214 (&((struct cs_off_attribute[]) { \215 { \216 __ATTR(name, 0444, coresight_cti_reg_show, NULL), \217 offset \218 } \219 })[0].attr.attr)220 221#define coresight_cti_reg_rw(name, offset) \222 (&((struct cs_off_attribute[]) { \223 { \224 __ATTR(name, 0644, coresight_cti_reg_show, \225 coresight_cti_reg_store), \226 offset \227 } \228 })[0].attr.attr)229 230#define coresight_cti_reg_wo(name, offset) \231 (&((struct cs_off_attribute[]) { \232 { \233 __ATTR(name, 0200, NULL, coresight_cti_reg_store), \234 offset \235 } \236 })[0].attr.attr)237 238/* coresight management registers */239static struct attribute *coresight_cti_mgmt_attrs[] = {240 coresight_cti_reg(devaff0, CTIDEVAFF0),241 coresight_cti_reg(devaff1, CTIDEVAFF1),242 coresight_cti_reg(authstatus, CORESIGHT_AUTHSTATUS),243 coresight_cti_reg(devarch, CORESIGHT_DEVARCH),244 coresight_cti_reg(devid, CORESIGHT_DEVID),245 coresight_cti_reg(devtype, CORESIGHT_DEVTYPE),246 coresight_cti_reg(pidr0, CORESIGHT_PERIPHIDR0),247 coresight_cti_reg(pidr1, CORESIGHT_PERIPHIDR1),248 coresight_cti_reg(pidr2, CORESIGHT_PERIPHIDR2),249 coresight_cti_reg(pidr3, CORESIGHT_PERIPHIDR3),250 coresight_cti_reg(pidr4, CORESIGHT_PERIPHIDR4),251 NULL,252};253 254/* CTI low level programming registers */255 256/*257 * Show a simple 32 bit value if enabled and powered.258 * If inaccessible & pcached_val not NULL then show cached value.259 */260static ssize_t cti_reg32_show(struct device *dev, char *buf,261 u32 *pcached_val, int reg_offset)262{263 u32 val = 0;264 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);265 struct cti_config *config = &drvdata->config;266 267 spin_lock(&drvdata->spinlock);268 if ((reg_offset >= 0) && cti_active(config)) {269 CS_UNLOCK(drvdata->base);270 val = readl_relaxed(drvdata->base + reg_offset);271 if (pcached_val)272 *pcached_val = val;273 CS_LOCK(drvdata->base);274 } else if (pcached_val) {275 val = *pcached_val;276 }277 spin_unlock(&drvdata->spinlock);278 return sprintf(buf, "%#x\n", val);279}280 281/*282 * Store a simple 32 bit value.283 * If pcached_val not NULL, then copy to here too,284 * if reg_offset >= 0 then write through if enabled.285 */286static ssize_t cti_reg32_store(struct device *dev, const char *buf,287 size_t size, u32 *pcached_val, int reg_offset)288{289 unsigned long val;290 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);291 struct cti_config *config = &drvdata->config;292 293 if (kstrtoul(buf, 0, &val))294 return -EINVAL;295 296 spin_lock(&drvdata->spinlock);297 /* local store */298 if (pcached_val)299 *pcached_val = (u32)val;300 301 /* write through if offset and enabled */302 if ((reg_offset >= 0) && cti_active(config))303 cti_write_single_reg(drvdata, reg_offset, val);304 spin_unlock(&drvdata->spinlock);305 return size;306}307 308/* Standard macro for simple rw cti config registers */309#define cti_config_reg32_rw(name, cfgname, offset) \310static ssize_t name##_show(struct device *dev, \311 struct device_attribute *attr, \312 char *buf) \313{ \314 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \315 return cti_reg32_show(dev, buf, \316 &drvdata->config.cfgname, offset); \317} \318 \319static ssize_t name##_store(struct device *dev, \320 struct device_attribute *attr, \321 const char *buf, size_t size) \322{ \323 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent); \324 return cti_reg32_store(dev, buf, size, \325 &drvdata->config.cfgname, offset); \326} \327static DEVICE_ATTR_RW(name)328 329static ssize_t inout_sel_show(struct device *dev,330 struct device_attribute *attr,331 char *buf)332{333 u32 val;334 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);335 336 val = (u32)drvdata->config.ctiinout_sel;337 return sprintf(buf, "%d\n", val);338}339 340static ssize_t inout_sel_store(struct device *dev,341 struct device_attribute *attr,342 const char *buf, size_t size)343{344 unsigned long val;345 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);346 347 if (kstrtoul(buf, 0, &val))348 return -EINVAL;349 if (val > (CTIINOUTEN_MAX - 1))350 return -EINVAL;351 352 spin_lock(&drvdata->spinlock);353 drvdata->config.ctiinout_sel = val;354 spin_unlock(&drvdata->spinlock);355 return size;356}357static DEVICE_ATTR_RW(inout_sel);358 359static ssize_t inen_show(struct device *dev,360 struct device_attribute *attr,361 char *buf)362{363 unsigned long val;364 int index;365 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);366 367 spin_lock(&drvdata->spinlock);368 index = drvdata->config.ctiinout_sel;369 val = drvdata->config.ctiinen[index];370 spin_unlock(&drvdata->spinlock);371 return sprintf(buf, "%#lx\n", val);372}373 374static ssize_t inen_store(struct device *dev,375 struct device_attribute *attr,376 const char *buf, size_t size)377{378 unsigned long val;379 int index;380 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);381 struct cti_config *config = &drvdata->config;382 383 if (kstrtoul(buf, 0, &val))384 return -EINVAL;385 386 spin_lock(&drvdata->spinlock);387 index = config->ctiinout_sel;388 config->ctiinen[index] = val;389 390 /* write through if enabled */391 if (cti_active(config))392 cti_write_single_reg(drvdata, CTIINEN(index), val);393 spin_unlock(&drvdata->spinlock);394 return size;395}396static DEVICE_ATTR_RW(inen);397 398static ssize_t outen_show(struct device *dev,399 struct device_attribute *attr,400 char *buf)401{402 unsigned long val;403 int index;404 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);405 406 spin_lock(&drvdata->spinlock);407 index = drvdata->config.ctiinout_sel;408 val = drvdata->config.ctiouten[index];409 spin_unlock(&drvdata->spinlock);410 return sprintf(buf, "%#lx\n", val);411}412 413static ssize_t outen_store(struct device *dev,414 struct device_attribute *attr,415 const char *buf, size_t size)416{417 unsigned long val;418 int index;419 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);420 struct cti_config *config = &drvdata->config;421 422 if (kstrtoul(buf, 0, &val))423 return -EINVAL;424 425 spin_lock(&drvdata->spinlock);426 index = config->ctiinout_sel;427 config->ctiouten[index] = val;428 429 /* write through if enabled */430 if (cti_active(config))431 cti_write_single_reg(drvdata, CTIOUTEN(index), val);432 spin_unlock(&drvdata->spinlock);433 return size;434}435static DEVICE_ATTR_RW(outen);436 437static ssize_t intack_store(struct device *dev,438 struct device_attribute *attr,439 const char *buf, size_t size)440{441 unsigned long val;442 443 if (kstrtoul(buf, 0, &val))444 return -EINVAL;445 446 cti_write_intack(dev, val);447 return size;448}449static DEVICE_ATTR_WO(intack);450 451cti_config_reg32_rw(gate, ctigate, CTIGATE);452cti_config_reg32_rw(asicctl, asicctl, ASICCTL);453cti_config_reg32_rw(appset, ctiappset, CTIAPPSET);454 455static ssize_t appclear_store(struct device *dev,456 struct device_attribute *attr,457 const char *buf, size_t size)458{459 unsigned long val;460 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);461 struct cti_config *config = &drvdata->config;462 463 if (kstrtoul(buf, 0, &val))464 return -EINVAL;465 466 spin_lock(&drvdata->spinlock);467 468 /* a 1'b1 in appclr clears down the same bit in appset*/469 config->ctiappset &= ~val;470 471 /* write through if enabled */472 if (cti_active(config))473 cti_write_single_reg(drvdata, CTIAPPCLEAR, val);474 spin_unlock(&drvdata->spinlock);475 return size;476}477static DEVICE_ATTR_WO(appclear);478 479static ssize_t apppulse_store(struct device *dev,480 struct device_attribute *attr,481 const char *buf, size_t size)482{483 unsigned long val;484 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);485 struct cti_config *config = &drvdata->config;486 487 if (kstrtoul(buf, 0, &val))488 return -EINVAL;489 490 spin_lock(&drvdata->spinlock);491 492 /* write through if enabled */493 if (cti_active(config))494 cti_write_single_reg(drvdata, CTIAPPPULSE, val);495 spin_unlock(&drvdata->spinlock);496 return size;497}498static DEVICE_ATTR_WO(apppulse);499 500/*501 * Define CONFIG_CORESIGHT_CTI_INTEGRATION_REGS to enable the access to the502 * integration control registers. Normally only used to investigate connection503 * data.504 */505static struct attribute *coresight_cti_regs_attrs[] = {506 &dev_attr_inout_sel.attr,507 &dev_attr_inen.attr,508 &dev_attr_outen.attr,509 &dev_attr_gate.attr,510 &dev_attr_asicctl.attr,511 &dev_attr_intack.attr,512 &dev_attr_appset.attr,513 &dev_attr_appclear.attr,514 &dev_attr_apppulse.attr,515 coresight_cti_reg(triginstatus, CTITRIGINSTATUS),516 coresight_cti_reg(trigoutstatus, CTITRIGOUTSTATUS),517 coresight_cti_reg(chinstatus, CTICHINSTATUS),518 coresight_cti_reg(choutstatus, CTICHOUTSTATUS),519#ifdef CONFIG_CORESIGHT_CTI_INTEGRATION_REGS520 coresight_cti_reg_rw(itctrl, CORESIGHT_ITCTRL),521 coresight_cti_reg(ittrigin, ITTRIGIN),522 coresight_cti_reg(itchin, ITCHIN),523 coresight_cti_reg_rw(ittrigout, ITTRIGOUT),524 coresight_cti_reg_rw(itchout, ITCHOUT),525 coresight_cti_reg(itchoutack, ITCHOUTACK),526 coresight_cti_reg(ittrigoutack, ITTRIGOUTACK),527 coresight_cti_reg_wo(ittriginack, ITTRIGINACK),528 coresight_cti_reg_wo(itchinack, ITCHINACK),529#endif530 NULL,531};532 533/* CTI channel x-trigger programming */534static int535cti_trig_op_parse(struct device *dev, enum cti_chan_op op,536 enum cti_trig_dir dir, const char *buf, size_t size)537{538 u32 chan_idx;539 u32 trig_idx;540 int items, err = -EINVAL;541 542 /* extract chan idx and trigger idx */543 items = sscanf(buf, "%d %d", &chan_idx, &trig_idx);544 if (items == 2) {545 err = cti_channel_trig_op(dev, op, dir, chan_idx, trig_idx);546 if (!err)547 err = size;548 }549 return err;550}551 552static ssize_t trigin_attach_store(struct device *dev,553 struct device_attribute *attr,554 const char *buf, size_t size)555{556 return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_IN,557 buf, size);558}559static DEVICE_ATTR_WO(trigin_attach);560 561static ssize_t trigin_detach_store(struct device *dev,562 struct device_attribute *attr,563 const char *buf, size_t size)564{565 return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_IN,566 buf, size);567}568static DEVICE_ATTR_WO(trigin_detach);569 570static ssize_t trigout_attach_store(struct device *dev,571 struct device_attribute *attr,572 const char *buf, size_t size)573{574 return cti_trig_op_parse(dev, CTI_CHAN_ATTACH, CTI_TRIG_OUT,575 buf, size);576}577static DEVICE_ATTR_WO(trigout_attach);578 579static ssize_t trigout_detach_store(struct device *dev,580 struct device_attribute *attr,581 const char *buf, size_t size)582{583 return cti_trig_op_parse(dev, CTI_CHAN_DETACH, CTI_TRIG_OUT,584 buf, size);585}586static DEVICE_ATTR_WO(trigout_detach);587 588 589static ssize_t chan_gate_enable_store(struct device *dev,590 struct device_attribute *attr,591 const char *buf, size_t size)592{593 int err = 0, channel = 0;594 595 if (kstrtoint(buf, 0, &channel))596 return -EINVAL;597 598 err = cti_channel_gate_op(dev, CTI_GATE_CHAN_ENABLE, channel);599 return err ? err : size;600}601 602static ssize_t chan_gate_enable_show(struct device *dev,603 struct device_attribute *attr,604 char *buf)605{606 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);607 struct cti_config *cfg = &drvdata->config;608 unsigned long ctigate_bitmask = cfg->ctigate;609 int size = 0;610 611 if (cfg->ctigate == 0)612 size = sprintf(buf, "\n");613 else614 size = bitmap_print_to_pagebuf(true, buf, &ctigate_bitmask,615 cfg->nr_ctm_channels);616 return size;617}618static DEVICE_ATTR_RW(chan_gate_enable);619 620static ssize_t chan_gate_disable_store(struct device *dev,621 struct device_attribute *attr,622 const char *buf, size_t size)623{624 int err = 0, channel = 0;625 626 if (kstrtoint(buf, 0, &channel))627 return -EINVAL;628 629 err = cti_channel_gate_op(dev, CTI_GATE_CHAN_DISABLE, channel);630 return err ? err : size;631}632static DEVICE_ATTR_WO(chan_gate_disable);633 634static int635chan_op_parse(struct device *dev, enum cti_chan_set_op op, const char *buf)636{637 int err = 0, channel = 0;638 639 if (kstrtoint(buf, 0, &channel))640 return -EINVAL;641 642 err = cti_channel_setop(dev, op, channel);643 return err;644 645}646 647static ssize_t chan_set_store(struct device *dev,648 struct device_attribute *attr,649 const char *buf, size_t size)650{651 int err = chan_op_parse(dev, CTI_CHAN_SET, buf);652 653 return err ? err : size;654}655static DEVICE_ATTR_WO(chan_set);656 657static ssize_t chan_clear_store(struct device *dev,658 struct device_attribute *attr,659 const char *buf, size_t size)660{661 int err = chan_op_parse(dev, CTI_CHAN_CLR, buf);662 663 return err ? err : size;664}665static DEVICE_ATTR_WO(chan_clear);666 667static ssize_t chan_pulse_store(struct device *dev,668 struct device_attribute *attr,669 const char *buf, size_t size)670{671 int err = chan_op_parse(dev, CTI_CHAN_PULSE, buf);672 673 return err ? err : size;674}675static DEVICE_ATTR_WO(chan_pulse);676 677static ssize_t trig_filter_enable_show(struct device *dev,678 struct device_attribute *attr,679 char *buf)680{681 u32 val;682 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);683 684 spin_lock(&drvdata->spinlock);685 val = drvdata->config.trig_filter_enable;686 spin_unlock(&drvdata->spinlock);687 return sprintf(buf, "%d\n", val);688}689 690static ssize_t trig_filter_enable_store(struct device *dev,691 struct device_attribute *attr,692 const char *buf, size_t size)693{694 unsigned long val;695 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);696 697 if (kstrtoul(buf, 0, &val))698 return -EINVAL;699 700 spin_lock(&drvdata->spinlock);701 drvdata->config.trig_filter_enable = !!val;702 spin_unlock(&drvdata->spinlock);703 return size;704}705static DEVICE_ATTR_RW(trig_filter_enable);706 707static ssize_t trigout_filtered_show(struct device *dev,708 struct device_attribute *attr,709 char *buf)710{711 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);712 struct cti_config *cfg = &drvdata->config;713 int size = 0, nr_trig_max = cfg->nr_trig_max;714 unsigned long mask = cfg->trig_out_filter;715 716 if (mask)717 size = bitmap_print_to_pagebuf(true, buf, &mask, nr_trig_max);718 return size;719}720static DEVICE_ATTR_RO(trigout_filtered);721 722/* clear all xtrigger / channel programming */723static ssize_t chan_xtrigs_reset_store(struct device *dev,724 struct device_attribute *attr,725 const char *buf, size_t size)726{727 int i;728 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);729 struct cti_config *config = &drvdata->config;730 731 spin_lock(&drvdata->spinlock);732 733 /* clear the CTI trigger / channel programming registers */734 for (i = 0; i < config->nr_trig_max; i++) {735 config->ctiinen[i] = 0;736 config->ctiouten[i] = 0;737 }738 739 /* clear the other regs */740 config->ctigate = GENMASK(config->nr_ctm_channels - 1, 0);741 config->asicctl = 0;742 config->ctiappset = 0;743 config->ctiinout_sel = 0;744 config->xtrig_rchan_sel = 0;745 746 /* if enabled then write through */747 if (cti_active(config))748 cti_write_all_hw_regs(drvdata);749 750 spin_unlock(&drvdata->spinlock);751 return size;752}753static DEVICE_ATTR_WO(chan_xtrigs_reset);754 755/*756 * Write to select a channel to view, read to display the757 * cross triggers for the selected channel.758 */759static ssize_t chan_xtrigs_sel_store(struct device *dev,760 struct device_attribute *attr,761 const char *buf, size_t size)762{763 unsigned long val;764 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);765 766 if (kstrtoul(buf, 0, &val))767 return -EINVAL;768 if (val > (drvdata->config.nr_ctm_channels - 1))769 return -EINVAL;770 771 spin_lock(&drvdata->spinlock);772 drvdata->config.xtrig_rchan_sel = val;773 spin_unlock(&drvdata->spinlock);774 return size;775}776 777static ssize_t chan_xtrigs_sel_show(struct device *dev,778 struct device_attribute *attr,779 char *buf)780{781 unsigned long val;782 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);783 784 spin_lock(&drvdata->spinlock);785 val = drvdata->config.xtrig_rchan_sel;786 spin_unlock(&drvdata->spinlock);787 788 return sprintf(buf, "%ld\n", val);789}790static DEVICE_ATTR_RW(chan_xtrigs_sel);791 792static ssize_t chan_xtrigs_in_show(struct device *dev,793 struct device_attribute *attr,794 char *buf)795{796 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);797 struct cti_config *cfg = &drvdata->config;798 int used = 0, reg_idx;799 int nr_trig_max = drvdata->config.nr_trig_max;800 u32 chan_mask = BIT(cfg->xtrig_rchan_sel);801 802 for (reg_idx = 0; reg_idx < nr_trig_max; reg_idx++) {803 if (chan_mask & cfg->ctiinen[reg_idx])804 used += sprintf(buf + used, "%d ", reg_idx);805 }806 807 used += sprintf(buf + used, "\n");808 return used;809}810static DEVICE_ATTR_RO(chan_xtrigs_in);811 812static ssize_t chan_xtrigs_out_show(struct device *dev,813 struct device_attribute *attr,814 char *buf)815{816 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);817 struct cti_config *cfg = &drvdata->config;818 int used = 0, reg_idx;819 int nr_trig_max = drvdata->config.nr_trig_max;820 u32 chan_mask = BIT(cfg->xtrig_rchan_sel);821 822 for (reg_idx = 0; reg_idx < nr_trig_max; reg_idx++) {823 if (chan_mask & cfg->ctiouten[reg_idx])824 used += sprintf(buf + used, "%d ", reg_idx);825 }826 827 used += sprintf(buf + used, "\n");828 return used;829}830static DEVICE_ATTR_RO(chan_xtrigs_out);831 832static ssize_t print_chan_list(struct device *dev,833 char *buf, bool inuse)834{835 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);836 struct cti_config *config = &drvdata->config;837 int size, i;838 unsigned long inuse_bits = 0, chan_mask;839 840 /* scan regs to get bitmap of channels in use. */841 spin_lock(&drvdata->spinlock);842 for (i = 0; i < config->nr_trig_max; i++) {843 inuse_bits |= config->ctiinen[i];844 inuse_bits |= config->ctiouten[i];845 }846 spin_unlock(&drvdata->spinlock);847 848 /* inverse bits if printing free channels */849 if (!inuse)850 inuse_bits = ~inuse_bits;851 852 /* list of channels, or 'none' */853 chan_mask = GENMASK(config->nr_ctm_channels - 1, 0);854 if (inuse_bits & chan_mask)855 size = bitmap_print_to_pagebuf(true, buf, &inuse_bits,856 config->nr_ctm_channels);857 else858 size = sprintf(buf, "\n");859 return size;860}861 862static ssize_t chan_inuse_show(struct device *dev,863 struct device_attribute *attr,864 char *buf)865{866 return print_chan_list(dev, buf, true);867}868static DEVICE_ATTR_RO(chan_inuse);869 870static ssize_t chan_free_show(struct device *dev,871 struct device_attribute *attr,872 char *buf)873{874 return print_chan_list(dev, buf, false);875}876static DEVICE_ATTR_RO(chan_free);877 878static struct attribute *coresight_cti_channel_attrs[] = {879 &dev_attr_trigin_attach.attr,880 &dev_attr_trigin_detach.attr,881 &dev_attr_trigout_attach.attr,882 &dev_attr_trigout_detach.attr,883 &dev_attr_trig_filter_enable.attr,884 &dev_attr_trigout_filtered.attr,885 &dev_attr_chan_gate_enable.attr,886 &dev_attr_chan_gate_disable.attr,887 &dev_attr_chan_set.attr,888 &dev_attr_chan_clear.attr,889 &dev_attr_chan_pulse.attr,890 &dev_attr_chan_inuse.attr,891 &dev_attr_chan_free.attr,892 &dev_attr_chan_xtrigs_sel.attr,893 &dev_attr_chan_xtrigs_in.attr,894 &dev_attr_chan_xtrigs_out.attr,895 &dev_attr_chan_xtrigs_reset.attr,896 NULL,897};898 899/* Create the connections trigger groups and attrs dynamically */900/*901 * Each connection has dynamic group triggers<N> + name, trigin/out sigs/types902 * attributes, + each device has static nr_trigger_cons giving the number903 * of groups. e.g. in sysfs:-904 * /cti_<name>/triggers0905 * /cti_<name>/triggers1906 * /cti_<name>/nr_trigger_cons907 * where nr_trigger_cons = 2908 */909static ssize_t con_name_show(struct device *dev,910 struct device_attribute *attr,911 char *buf)912{913 struct dev_ext_attribute *ext_attr =914 container_of(attr, struct dev_ext_attribute, attr);915 struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;916 917 return sprintf(buf, "%s\n", con->con_dev_name);918}919 920static ssize_t trigin_sig_show(struct device *dev,921 struct device_attribute *attr,922 char *buf)923{924 struct dev_ext_attribute *ext_attr =925 container_of(attr, struct dev_ext_attribute, attr);926 struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;927 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);928 struct cti_config *cfg = &drvdata->config;929 unsigned long mask = con->con_in->used_mask;930 931 return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);932}933 934static ssize_t trigout_sig_show(struct device *dev,935 struct device_attribute *attr,936 char *buf)937{938 struct dev_ext_attribute *ext_attr =939 container_of(attr, struct dev_ext_attribute, attr);940 struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;941 struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);942 struct cti_config *cfg = &drvdata->config;943 unsigned long mask = con->con_out->used_mask;944 945 return bitmap_print_to_pagebuf(true, buf, &mask, cfg->nr_trig_max);946}947 948/* convert a sig type id to a name */949static const char *950cti_sig_type_name(struct cti_trig_con *con, int used_count, bool in)951{952 int idx = 0;953 struct cti_trig_grp *grp = in ? con->con_in : con->con_out;954 955 if (used_count < grp->nr_sigs)956 idx = grp->sig_types[used_count];957 return sig_type_names[idx];958}959 960static ssize_t trigin_type_show(struct device *dev,961 struct device_attribute *attr,962 char *buf)963{964 struct dev_ext_attribute *ext_attr =965 container_of(attr, struct dev_ext_attribute, attr);966 struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;967 int sig_idx, used = 0;968 const char *name;969 970 for (sig_idx = 0; sig_idx < con->con_in->nr_sigs; sig_idx++) {971 name = cti_sig_type_name(con, sig_idx, true);972 used += sprintf(buf + used, "%s ", name);973 }974 used += sprintf(buf + used, "\n");975 return used;976}977 978static ssize_t trigout_type_show(struct device *dev,979 struct device_attribute *attr,980 char *buf)981{982 struct dev_ext_attribute *ext_attr =983 container_of(attr, struct dev_ext_attribute, attr);984 struct cti_trig_con *con = (struct cti_trig_con *)ext_attr->var;985 int sig_idx, used = 0;986 const char *name;987 988 for (sig_idx = 0; sig_idx < con->con_out->nr_sigs; sig_idx++) {989 name = cti_sig_type_name(con, sig_idx, false);990 used += sprintf(buf + used, "%s ", name);991 }992 used += sprintf(buf + used, "\n");993 return used;994}995 996/*997 * Array of show function names declared above to allow selection998 * for the connection attributes999 */1000static p_show_fn show_fns[CTI_CON_ATTR_MAX] = {1001 con_name_show,1002 trigin_sig_show,1003 trigout_sig_show,1004 trigin_type_show,1005 trigout_type_show,1006};1007 1008static int cti_create_con_sysfs_attr(struct device *dev,1009 struct cti_trig_con *con,1010 enum cti_conn_attr_type attr_type,1011 int attr_idx)1012{1013 struct dev_ext_attribute *eattr;1014 char *name;1015 1016 eattr = devm_kzalloc(dev, sizeof(struct dev_ext_attribute),1017 GFP_KERNEL);1018 if (eattr) {1019 name = devm_kstrdup(dev, con_attr_names[attr_type],1020 GFP_KERNEL);1021 if (name) {1022 /* fill out the underlying attribute struct */1023 eattr->attr.attr.name = name;1024 eattr->attr.attr.mode = 0444;1025 1026 /* now the device_attribute struct */1027 eattr->attr.show = show_fns[attr_type];1028 } else {1029 return -ENOMEM;1030 }1031 } else {1032 return -ENOMEM;1033 }1034 eattr->var = con;1035 con->con_attrs[attr_idx] = &eattr->attr.attr;1036 /*1037 * Initialize the dynamically allocated attribute1038 * to avoid LOCKDEP splat. See include/linux/sysfs.h1039 * for more details.1040 */1041 sysfs_attr_init(con->con_attrs[attr_idx]);1042 1043 return 0;1044}1045 1046static struct attribute_group *1047cti_create_con_sysfs_group(struct device *dev, struct cti_device *ctidev,1048 int con_idx, struct cti_trig_con *tc)1049{1050 struct attribute_group *group = NULL;1051 int grp_idx;1052 1053 group = devm_kzalloc(dev, sizeof(struct attribute_group), GFP_KERNEL);1054 if (!group)1055 return NULL;1056 1057 group->name = devm_kasprintf(dev, GFP_KERNEL, "triggers%d", con_idx);1058 if (!group->name)1059 return NULL;1060 1061 grp_idx = con_idx + CORESIGHT_CTI_STATIC_GROUPS_MAX - 1;1062 ctidev->con_groups[grp_idx] = group;1063 tc->attr_group = group;1064 return group;1065}1066 1067/* create a triggers connection group and the attributes for that group */1068static int cti_create_con_attr_set(struct device *dev, int con_idx,1069 struct cti_device *ctidev,1070 struct cti_trig_con *tc)1071{1072 struct attribute_group *attr_group = NULL;1073 int attr_idx = 0;1074 int err = -ENOMEM;1075 1076 attr_group = cti_create_con_sysfs_group(dev, ctidev, con_idx, tc);1077 if (!attr_group)1078 return -ENOMEM;1079 1080 /* allocate NULL terminated array of attributes */1081 tc->con_attrs = devm_kcalloc(dev, CTI_CON_ATTR_MAX + 1,1082 sizeof(struct attribute *), GFP_KERNEL);1083 if (!tc->con_attrs)1084 return -ENOMEM;1085 1086 err = cti_create_con_sysfs_attr(dev, tc, CTI_CON_ATTR_NAME,1087 attr_idx++);1088 if (err)1089 return err;1090 1091 if (tc->con_in->nr_sigs > 0) {1092 err = cti_create_con_sysfs_attr(dev, tc,1093 CTI_CON_ATTR_TRIGIN_SIG,1094 attr_idx++);1095 if (err)1096 return err;1097 1098 err = cti_create_con_sysfs_attr(dev, tc,1099 CTI_CON_ATTR_TRIGIN_TYPES,1100 attr_idx++);1101 if (err)1102 return err;1103 }1104 1105 if (tc->con_out->nr_sigs > 0) {1106 err = cti_create_con_sysfs_attr(dev, tc,1107 CTI_CON_ATTR_TRIGOUT_SIG,1108 attr_idx++);1109 if (err)1110 return err;1111 1112 err = cti_create_con_sysfs_attr(dev, tc,1113 CTI_CON_ATTR_TRIGOUT_TYPES,1114 attr_idx++);1115 if (err)1116 return err;1117 }1118 attr_group->attrs = tc->con_attrs;1119 return 0;1120}1121 1122/* create the array of group pointers for the CTI sysfs groups */1123static int cti_create_cons_groups(struct device *dev, struct cti_device *ctidev)1124{1125 int nr_groups;1126 1127 /* nr groups = dynamic + static + NULL terminator */1128 nr_groups = ctidev->nr_trig_con + CORESIGHT_CTI_STATIC_GROUPS_MAX;1129 ctidev->con_groups = devm_kcalloc(dev, nr_groups,1130 sizeof(struct attribute_group *),1131 GFP_KERNEL);1132 if (!ctidev->con_groups)1133 return -ENOMEM;1134 return 0;1135}1136 1137int cti_create_cons_sysfs(struct device *dev, struct cti_drvdata *drvdata)1138{1139 struct cti_device *ctidev = &drvdata->ctidev;1140 int err, con_idx = 0, i;1141 struct cti_trig_con *tc;1142 1143 err = cti_create_cons_groups(dev, ctidev);1144 if (err)1145 return err;1146 1147 /* populate first locations with the static set of groups */1148 for (i = 0; i < (CORESIGHT_CTI_STATIC_GROUPS_MAX - 1); i++)1149 ctidev->con_groups[i] = coresight_cti_groups[i];1150 1151 /* add dynamic set for each connection */1152 list_for_each_entry(tc, &ctidev->trig_cons, node) {1153 err = cti_create_con_attr_set(dev, con_idx++, ctidev, tc);1154 if (err)1155 break;1156 }1157 return err;1158}1159 1160/* attribute and group sysfs tables. */1161static const struct attribute_group coresight_cti_group = {1162 .attrs = coresight_cti_attrs,1163};1164 1165static const struct attribute_group coresight_cti_mgmt_group = {1166 .attrs = coresight_cti_mgmt_attrs,1167 .name = "mgmt",1168};1169 1170static const struct attribute_group coresight_cti_regs_group = {1171 .attrs = coresight_cti_regs_attrs,1172 .name = "regs",1173};1174 1175static const struct attribute_group coresight_cti_channels_group = {1176 .attrs = coresight_cti_channel_attrs,1177 .name = "channels",1178};1179 1180const struct attribute_group *1181coresight_cti_groups[CORESIGHT_CTI_STATIC_GROUPS_MAX] = {1182 &coresight_cti_group,1183 &coresight_cti_mgmt_group,1184 &coresight_cti_regs_group,1185 &coresight_cti_channels_group,1186 NULL,1187};1188