1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright(C) 2020 Linaro Limited. All rights reserved.
4 * Author: Mike Leach <mike.leach@linaro.org>
7 #include "coresight-etm4x.h"
8 #include "coresight-etm4x-cfg.h"
9 #include "coresight-priv.h"
10 #include "coresight-syscfg.h"
12 /* defines to associate register IDs with driver data locations */
13 #define CHECKREG(cval, elem) \
15 if (offset == cval) { \
16 reg_csdev->driver_regval = &drvcfg->elem; \
22 #define CHECKREGIDX(cval, elem, off_idx, mask) \
25 reg_csdev->driver_regval = &drvcfg->elem[off_idx]; \
32 * etm4_cfg_map_reg_offset - validate and map the register offset into a
33 * location in the driver config struct.
35 * Limits the number of registers that can be accessed and programmed in
36 * features, to those which are used to control the trace capture parameters.
38 * Omits or limits access to those which the driver must use exclusively.
40 * Invalid offsets will result in fail code return and feature load failure.
42 * @drvdata: driver data to map into.
43 * @reg_csdev: register to map.
44 * @offset: device offset for the register
46 static int etm4_cfg_map_reg_offset(struct etmv4_drvdata
*drvdata
,
47 struct cscfg_regval_csdev
*reg_csdev
, u32 offset
)
49 int err
= -EINVAL
, idx
;
50 struct etmv4_config
*drvcfg
= &drvdata
->config
;
53 if (((offset
>= TRCEVENTCTL0R
) && (offset
<= TRCVIPCSSCTLR
)) ||
54 ((offset
>= TRCSEQRSTEVR
) && (offset
<= TRCEXTINSELR
)) ||
55 ((offset
>= TRCCIDCCTLR0
) && (offset
<= TRCVMIDCCTLR1
))) {
57 CHECKREG(TRCEVENTCTL0R
, eventctrl0
);
58 CHECKREG(TRCEVENTCTL1R
, eventctrl1
);
59 CHECKREG(TRCSTALLCTLR
, stall_ctrl
);
60 CHECKREG(TRCTSCTLR
, ts_ctrl
);
61 CHECKREG(TRCSYNCPR
, syncfreq
);
62 CHECKREG(TRCCCCTLR
, ccctlr
);
63 CHECKREG(TRCBBCTLR
, bb_ctrl
);
64 CHECKREG(TRCVICTLR
, vinst_ctrl
);
65 CHECKREG(TRCVIIECTLR
, viiectlr
);
66 CHECKREG(TRCVISSCTLR
, vissctlr
);
67 CHECKREG(TRCVIPCSSCTLR
, vipcssctlr
);
68 CHECKREG(TRCSEQRSTEVR
, seq_rst
);
69 CHECKREG(TRCSEQSTR
, seq_state
);
70 CHECKREG(TRCEXTINSELR
, ext_inp
);
71 CHECKREG(TRCCIDCCTLR0
, ctxid_mask0
);
72 CHECKREG(TRCCIDCCTLR1
, ctxid_mask1
);
73 CHECKREG(TRCVMIDCCTLR0
, vmid_mask0
);
74 CHECKREG(TRCVMIDCCTLR1
, vmid_mask1
);
76 } else if ((offset
& GENMASK(11, 4)) == TRCSEQEVRn(0)) {
77 /* sequencer state control registers */
78 idx
= (offset
& GENMASK(3, 0)) / 4;
79 if (idx
< ETM_MAX_SEQ_STATES
) {
80 reg_csdev
->driver_regval
= &drvcfg
->seq_ctrl
[idx
];
83 } else if ((offset
>= TRCSSCCRn(0)) && (offset
<= TRCSSPCICRn(7))) {
84 /* 32 bit, 8 off indexed register sets */
85 idx
= (offset
& GENMASK(4, 0)) / 4;
86 off_mask
= (offset
& GENMASK(11, 5));
88 CHECKREGIDX(TRCSSCCRn(0), ss_ctrl
, idx
, off_mask
);
89 CHECKREGIDX(TRCSSCSRn(0), ss_status
, idx
, off_mask
);
90 CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp
, idx
, off_mask
);
92 } else if ((offset
>= TRCCIDCVRn(0)) && (offset
<= TRCVMIDCVRn(7))) {
93 /* 64 bit, 8 off indexed register sets */
94 idx
= (offset
& GENMASK(5, 0)) / 8;
95 off_mask
= (offset
& GENMASK(11, 6));
97 CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid
, idx
, off_mask
);
98 CHECKREGIDX(TRCVMIDCVRn(0), vmid_val
, idx
, off_mask
);
100 } else if ((offset
>= TRCRSCTLRn(2)) &&
101 (offset
<= TRCRSCTLRn((ETM_MAX_RES_SEL
- 1)))) {
102 /* 32 bit resource selection regs, 32 off, skip fixed 0,1 */
103 idx
= (offset
& GENMASK(6, 0)) / 4;
104 if (idx
< ETM_MAX_RES_SEL
) {
105 reg_csdev
->driver_regval
= &drvcfg
->res_ctrl
[idx
];
108 } else if ((offset
>= TRCACVRn(0)) &&
109 (offset
<= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP
- 1)))) {
110 /* 64 bit addr cmp regs, 16 off */
111 idx
= (offset
& GENMASK(6, 0)) / 8;
112 off_mask
= offset
& GENMASK(11, 7);
114 CHECKREGIDX(TRCACVRn(0), addr_val
, idx
, off_mask
);
115 CHECKREGIDX(TRCACATRn(0), addr_acc
, idx
, off_mask
);
117 } else if ((offset
>= TRCCNTRLDVRn(0)) &&
118 (offset
<= TRCCNTVRn((ETMv4_MAX_CNTR
- 1)))) {
119 /* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */
120 idx
= (offset
& GENMASK(3, 0)) / 4;
121 off_mask
= offset
& GENMASK(11, 4);
123 CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr
, idx
, off_mask
);
124 CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl
, idx
, off_mask
);
125 CHECKREGIDX(TRCCNTVRn(0), cntr_val
, idx
, off_mask
);
132 * etm4_cfg_load_feature - load a feature into a device instance.
134 * @csdev: An ETMv4 CoreSight device.
135 * @feat_csdev: The feature to be loaded.
137 * The function will load a feature instance into the device, checking that
138 * the register definitions are valid for the device.
140 * Parameter and register definitions will be converted into internal
141 * structures that are used to set the values in the driver when the
142 * feature is enabled for the device.
144 * The feature spinlock pointer is initialised to the same spinlock
145 * that the driver uses to protect the internal register values.
147 static int etm4_cfg_load_feature(struct coresight_device
*csdev
,
148 struct cscfg_feature_csdev
*feat_csdev
)
150 struct device
*dev
= csdev
->dev
.parent
;
151 struct etmv4_drvdata
*drvdata
= dev_get_drvdata(dev
);
152 const struct cscfg_feature_desc
*feat_desc
= feat_csdev
->feat_desc
;
157 * essential we set the device spinlock - this is used in the generic
158 * programming routines when copying values into the drvdata structures
159 * via the pointers setup in etm4_cfg_map_reg_offset().
161 feat_csdev
->drv_spinlock
= &drvdata
->spinlock
;
163 /* process the register descriptions */
164 for (i
= 0; i
< feat_csdev
->nr_regs
&& !err
; i
++) {
165 offset
= feat_desc
->regs_desc
[i
].offset
;
166 err
= etm4_cfg_map_reg_offset(drvdata
, &feat_csdev
->regs_csdev
[i
], offset
);
171 /* match information when loading configurations */
172 #define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \
173 CS_CFG_MATCH_CLASS_SRC_ETM4)
175 int etm4_cscfg_register(struct coresight_device
*csdev
)
177 struct cscfg_csdev_feat_ops ops
;
179 ops
.load_feat
= &etm4_cfg_load_feature
;
181 return cscfg_register_csdev(csdev
, CS_CFG_ETM4_MATCH_FLAGS
, &ops
);