root/drivers/hwtracing/coresight/coresight-tpdm.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#ifndef _CORESIGHT_CORESIGHT_TPDM_H
#define _CORESIGHT_CORESIGHT_TPDM_H

/* The max number of the datasets that TPDM supports */
#define TPDM_DATASETS       7

/* CMB/MCMB Subunit Registers */
#define TPDM_CMB_CR             (0xA00)
/* CMB subunit timestamp insertion enable register */
#define TPDM_CMB_TIER           (0xA04)
/* CMB subunit timestamp pattern registers */
#define TPDM_CMB_TPR(n)         (0xA08 + (n * 4))
/* CMB subunit timestamp pattern mask registers */
#define TPDM_CMB_TPMR(n)        (0xA10 + (n * 4))
/* CMB subunit trigger pattern registers */
#define TPDM_CMB_XPR(n)         (0xA18 + (n * 4))
/* CMB subunit trigger pattern mask registers */
#define TPDM_CMB_XPMR(n)        (0xA20 + (n * 4))
/* CMB MSR register */
#define TPDM_CMB_MSR(n)         (0xA80 + (n * 4))

/* Enable bit for CMB subunit */
#define TPDM_CMB_CR_ENA         BIT(0)
/* Trace collection mode for CMB subunit */
#define TPDM_CMB_CR_MODE        BIT(1)
/* MCMB trigger lane select */
#define TPDM_CMB_CR_XTRIG_LNSEL         GENMASK(20, 18)
/* MCMB lane enablement */
#define TPDM_CMB_CR_E_LN                GENMASK(17, 10)
/* Timestamp control for pattern match */
#define TPDM_CMB_TIER_PATT_TSENAB       BIT(0)
/* CMB CTI timestamp request */
#define TPDM_CMB_TIER_XTRIG_TSENAB      BIT(1)
/* For timestamp fo all trace */
#define TPDM_CMB_TIER_TS_ALL            BIT(2)

/* Patten register number */
#define TPDM_CMB_MAX_PATT               2

/* MAX number of DSB MSR */
#define TPDM_CMB_MAX_MSR 32

/* MAX lanes in the output pattern for MCMB configurations*/
#define TPDM_MCMB_MAX_LANES 8

/* Filter bit 0~7 from the value for CR_E_LN */
#define TPDM_MCMB_E_LN_MASK             GENMASK(7, 0)

/* DSB Subunit Registers */
#define TPDM_DSB_CR             (0x780)
#define TPDM_DSB_TIER           (0x784)
#define TPDM_DSB_TPR(n)         (0x788 + (n * 4))
#define TPDM_DSB_TPMR(n)        (0x7A8 + (n * 4))
#define TPDM_DSB_XPR(n)         (0x7C8 + (n * 4))
#define TPDM_DSB_XPMR(n)        (0x7E8 + (n * 4))
#define TPDM_DSB_EDCR(n)        (0x808 + (n * 4))
#define TPDM_DSB_EDCMR(n)       (0x848 + (n * 4))
#define TPDM_DSB_MSR(n)         (0x980 + (n * 4))

/* Enable bit for DSB subunit */
#define TPDM_DSB_CR_ENA         BIT(0)
/* Enable bit for DSB subunit perfmance mode */
#define TPDM_DSB_CR_MODE                BIT(1)
/* Enable bit for DSB subunit trigger type */
#define TPDM_DSB_CR_TRIG_TYPE           BIT(12)
/* Data bits for DSB high performace mode */
#define TPDM_DSB_CR_HPSEL               GENMASK(6, 2)
/* Data bits for DSB test mode */
#define TPDM_DSB_CR_TEST_MODE           GENMASK(10, 9)

/* Enable bit for DSB subunit pattern timestamp */
#define TPDM_DSB_TIER_PATT_TSENAB               BIT(0)
/* Enable bit for DSB subunit trigger timestamp */
#define TPDM_DSB_TIER_XTRIG_TSENAB              BIT(1)
/* Bit for DSB subunit pattern type */
#define TPDM_DSB_TIER_PATT_TYPE                 BIT(2)

/* DSB programming modes */
/* DSB mode bits mask */
#define TPDM_DSB_MODE_MASK                      GENMASK(8, 0)
/* Test mode control bit*/
#define TPDM_DSB_MODE_TEST(val) (val & GENMASK(1, 0))
/* Performance mode */
#define TPDM_DSB_MODE_PERF              BIT(3)
/* High performance mode */
#define TPDM_DSB_MODE_HPBYTESEL(val)    (val & GENMASK(8, 4))

#define EDCRS_PER_WORD                  16
#define EDCR_TO_WORD_IDX(r)             ((r) / EDCRS_PER_WORD)
#define EDCR_TO_WORD_SHIFT(r)           ((r % EDCRS_PER_WORD) * 2)
#define EDCR_TO_WORD_VAL(val, r)        (val << EDCR_TO_WORD_SHIFT(r))
#define EDCR_TO_WORD_MASK(r)            EDCR_TO_WORD_VAL(0x3, r)

#define EDCMRS_PER_WORD                         32
#define EDCMR_TO_WORD_IDX(r)            ((r) / EDCMRS_PER_WORD)
#define EDCMR_TO_WORD_SHIFT(r)          ((r) % EDCMRS_PER_WORD)

/* TPDM integration test registers */
#define TPDM_ITATBCNTRL         (0xEF0)
#define TPDM_ITCNTRL            (0xF00)

/* Register value for integration test */
#define ATBCNTRL_VAL_32         0xC00F1409
#define ATBCNTRL_VAL_64         0xC01F1409

/*
 * Number of cycles to write value when
 * integration test.
 */
#define INTEGRATION_TEST_CYCLE  10

/**
 * The bits of PERIPHIDR0 register.
 * The fields [6:0] of PERIPHIDR0 are used to determine what
 * interfaces and subunits are present on a given TPDM.
 *
 * PERIPHIDR0[0] : Fix to 1 if ImplDef subunit present, else 0
 * PERIPHIDR0[1] : Fix to 1 if DSB subunit present, else 0
 * PERIPHIDR0[2] : Fix to 1 if CMB subunit present, else 0
 * PERIPHIDR0[6] : Fix to 1 if MCMB subunit present, else 0
 */

#define TPDM_PIDR0_DS_IMPDEF    BIT(0)
#define TPDM_PIDR0_DS_DSB       BIT(1)
#define TPDM_PIDR0_DS_CMB       BIT(2)
#define TPDM_PIDR0_DS_MCMB      BIT(6)

#define TPDM_DSB_MAX_LINES      256
/* MAX number of EDCR registers */
#define TPDM_DSB_MAX_EDCR       16
/* MAX number of EDCMR registers */
#define TPDM_DSB_MAX_EDCMR      8
/* MAX number of DSB pattern */
#define TPDM_DSB_MAX_PATT       8
/* MAX number of DSB MSR */
#define TPDM_DSB_MAX_MSR 32

#define tpdm_simple_dataset_ro(name, mem, idx)                  \
        (&((struct tpdm_dataset_attribute[]) {                  \
           {                                                            \
                __ATTR(name, 0444, tpdm_simple_dataset_show, NULL),     \
                mem,                                                    \
                idx,                                                    \
           }                                                            \
        })[0].attr.attr)

#define tpdm_simple_dataset_rw(name, mem, idx)                  \
        (&((struct tpdm_dataset_attribute[]) {                  \
           {                                                            \
                __ATTR(name, 0644, tpdm_simple_dataset_show,            \
                tpdm_simple_dataset_store),             \
                mem,                                                    \
                idx,                                                    \
           }                                                            \
        })[0].attr.attr)

#define tpdm_patt_enable_ts(name, mem)                          \
        (&((struct tpdm_dataset_attribute[]) {                  \
           {                                                    \
                __ATTR(name, 0644, enable_ts_show,              \
                enable_ts_store),               \
                mem,                                            \
                0,                                              \
           }                                                    \
        })[0].attr.attr)

#define DSB_EDGE_CTRL_ATTR(nr)                                  \
                tpdm_simple_dataset_ro(edcr##nr,                \
                DSB_EDGE_CTRL, nr)

#define DSB_EDGE_CTRL_MASK_ATTR(nr)                             \
                tpdm_simple_dataset_ro(edcmr##nr,               \
                DSB_EDGE_CTRL_MASK, nr)

#define DSB_TRIG_PATT_ATTR(nr)                                  \
                tpdm_simple_dataset_rw(xpr##nr,                 \
                DSB_TRIG_PATT, nr)

#define DSB_TRIG_PATT_MASK_ATTR(nr)                             \
                tpdm_simple_dataset_rw(xpmr##nr,                \
                DSB_TRIG_PATT_MASK, nr)

#define DSB_PATT_ATTR(nr)                                       \
                tpdm_simple_dataset_rw(tpr##nr,                 \
                DSB_PATT, nr)

#define DSB_PATT_MASK_ATTR(nr)                                  \
                tpdm_simple_dataset_rw(tpmr##nr,                \
                DSB_PATT_MASK, nr)

#define DSB_PATT_ENABLE_TS                                      \
                tpdm_patt_enable_ts(enable_ts,                  \
                DSB_PATT)

#define DSB_MSR_ATTR(nr)                                        \
                tpdm_simple_dataset_rw(msr##nr,                 \
                DSB_MSR, nr)

#define CMB_TRIG_PATT_ATTR(nr)                                  \
                tpdm_simple_dataset_rw(xpr##nr,                 \
                CMB_TRIG_PATT, nr)

#define CMB_TRIG_PATT_MASK_ATTR(nr)                             \
                tpdm_simple_dataset_rw(xpmr##nr,                \
                CMB_TRIG_PATT_MASK, nr)

#define CMB_PATT_ATTR(nr)                                       \
                tpdm_simple_dataset_rw(tpr##nr,                 \
                CMB_PATT, nr)

#define CMB_PATT_MASK_ATTR(nr)                                  \
                tpdm_simple_dataset_rw(tpmr##nr,                \
                CMB_PATT_MASK, nr)

#define CMB_PATT_ENABLE_TS                                      \
                tpdm_patt_enable_ts(enable_ts,                  \
                CMB_PATT)

#define CMB_MSR_ATTR(nr)                                        \
                tpdm_simple_dataset_rw(msr##nr,                 \
                CMB_MSR, nr)

/**
 * struct dsb_dataset - specifics associated to dsb dataset
 * @mode:             DSB programming mode
 * @edge_ctrl_idx     Index number of the edge control
 * @edge_ctrl:        Save value for edge control
 * @edge_ctrl_mask:   Save value for edge control mask
 * @patt_val:         Save value for pattern
 * @patt_mask:        Save value for pattern mask
 * @trig_patt:        Save value for trigger pattern
 * @trig_patt_mask:   Save value for trigger pattern mask
 * @msr               Save value for MSR
 * @patt_ts:          Enable/Disable pattern timestamp
 * @patt_type:        Set pattern type
 * @trig_ts:          Enable/Disable trigger timestamp.
 * @trig_type:        Enable/Disable trigger type.
 */
struct dsb_dataset {
        u32                     mode;
        u32                     edge_ctrl_idx;
        u32                     edge_ctrl[TPDM_DSB_MAX_EDCR];
        u32                     edge_ctrl_mask[TPDM_DSB_MAX_EDCMR];
        u32                     patt_val[TPDM_DSB_MAX_PATT];
        u32                     patt_mask[TPDM_DSB_MAX_PATT];
        u32                     trig_patt[TPDM_DSB_MAX_PATT];
        u32                     trig_patt_mask[TPDM_DSB_MAX_PATT];
        u32                     msr[TPDM_DSB_MAX_MSR];
        bool                    patt_ts;
        bool                    patt_type;
        bool                    trig_ts;
        bool                    trig_type;
};

/**
 * struct cmb_dataset
 * @trace_mode:       Dataset collection mode
 * @patt_val:         Save value for pattern
 * @patt_mask:        Save value for pattern mask
 * @trig_patt:        Save value for trigger pattern
 * @trig_patt_mask:   Save value for trigger pattern mask
 * @msr               Save value for MSR
 * @patt_ts:          Indicates if pattern match for timestamp is enabled.
 * @trig_ts:          Indicates if CTI trigger for timestamp is enabled.
 * @ts_all:           Indicates if timestamp is enabled for all packets.
 * struct mcmb_dataset
 * @mcmb_trig_lane:       Save data for trigger lane
 * @mcmb_lane_select:     Save data for lane enablement
 */
struct cmb_dataset {
        u32                     trace_mode;
        u32                     patt_val[TPDM_CMB_MAX_PATT];
        u32                     patt_mask[TPDM_CMB_MAX_PATT];
        u32                     trig_patt[TPDM_CMB_MAX_PATT];
        u32                     trig_patt_mask[TPDM_CMB_MAX_PATT];
        u32                     msr[TPDM_CMB_MAX_MSR];
        bool                    patt_ts;
        bool                    trig_ts;
        bool                    ts_all;
        struct {
                u8              trig_lane;
                u8              lane_select;
        } mcmb;
};

/**
 * struct tpdm_drvdata - specifics associated to an TPDM component
 * @base:       memory mapped base address for this component.
 * @dev:        The device entity associated to this component.
 * @csdev:      component vitals needed by the framework.
 * @spinlock:   lock for the drvdata value.
 * @enable:     enable status of the component.
 * @datasets:   The datasets types present of the TPDM.
 * @dsb         Specifics associated to TPDM DSB.
 * @cmb         Specifics associated to TPDM CMB.
 * @dsb_msr_num Number of MSR supported by DSB TPDM
 * @cmb_msr_num Number of MSR supported by CMB TPDM
 */

struct tpdm_drvdata {
        void __iomem            *base;
        struct device           *dev;
        struct coresight_device *csdev;
        spinlock_t              spinlock;
        bool                    enable;
        unsigned long           datasets;
        struct dsb_dataset      *dsb;
        struct cmb_dataset      *cmb;
        u32                     dsb_msr_num;
        u32                     cmb_msr_num;
};

/* Enumerate members of various datasets */
enum dataset_mem {
        DSB_EDGE_CTRL,
        DSB_EDGE_CTRL_MASK,
        DSB_TRIG_PATT,
        DSB_TRIG_PATT_MASK,
        DSB_PATT,
        DSB_PATT_MASK,
        DSB_MSR,
        CMB_TRIG_PATT,
        CMB_TRIG_PATT_MASK,
        CMB_PATT,
        CMB_PATT_MASK,
        CMB_MSR
};

/**
 * struct tpdm_dataset_attribute - Record the member variables and
 * index number of datasets that need to be operated by sysfs file
 * @attr:       The device attribute
 * @mem:        The member in the dataset data structure
 * @idx:        The index number of the array data
 */
struct tpdm_dataset_attribute {
        struct device_attribute attr;
        enum dataset_mem mem;
        u32 idx;
};

static inline bool coresight_device_is_tpdm(struct coresight_device *csdev)
{
        return (coresight_is_device_source(csdev)) &&
                (csdev->subtype.source_subtype ==
                        CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
}

static inline bool coresight_is_static_tpdm(struct coresight_device *csdev)
{
        return (coresight_device_is_tpdm(csdev) && !csdev->access.base);
}
#endif  /* _CORESIGHT_CORESIGHT_TPDM_H */