/* Read dataset array member with the index number */ static ssize_t tpdm_simple_dataset_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); struct tpdm_dataset_attribute *tpdm_attr =
container_of(attr, struct tpdm_dataset_attribute, attr);
switch (tpdm_attr->mem) { case DSB_EDGE_CTRL: if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCR) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->edge_ctrl[tpdm_attr->idx]); case DSB_EDGE_CTRL_MASK: if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCMR) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->edge_ctrl_mask[tpdm_attr->idx]); case DSB_TRIG_PATT: if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->trig_patt[tpdm_attr->idx]); case DSB_TRIG_PATT_MASK: if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->trig_patt_mask[tpdm_attr->idx]); case DSB_PATT: if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->patt_val[tpdm_attr->idx]); case DSB_PATT_MASK: if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->patt_mask[tpdm_attr->idx]); case DSB_MSR: if (tpdm_attr->idx >= drvdata->dsb_msr_num) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->dsb->msr[tpdm_attr->idx]); case CMB_TRIG_PATT: if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->cmb->trig_patt[tpdm_attr->idx]); case CMB_TRIG_PATT_MASK: if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->cmb->trig_patt_mask[tpdm_attr->idx]); case CMB_PATT: if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->cmb->patt_val[tpdm_attr->idx]); case CMB_PATT_MASK: if (tpdm_attr->idx >= TPDM_CMB_MAX_PATT) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->cmb->patt_mask[tpdm_attr->idx]); case CMB_MSR: if (tpdm_attr->idx >= drvdata->cmb_msr_num) return -EINVAL; return sysfs_emit(buf, "0x%x\n",
drvdata->cmb->msr[tpdm_attr->idx]);
} return -EINVAL;
}
/* Write dataset array member with the index number */ static ssize_t tpdm_simple_dataset_store(struct device *dev, struct device_attribute *attr, constchar *buf,
size_t size)
{ unsignedlong val;
ssize_t ret = -EINVAL;
/* Set the test accurate mode */
mode = TPDM_DSB_MODE_TEST(drvdata->dsb->mode);
*val &= ~TPDM_DSB_CR_TEST_MODE;
*val |= FIELD_PREP(TPDM_DSB_CR_TEST_MODE, mode);
/* Set the byte lane for high-performance mode */
mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode);
*val &= ~TPDM_DSB_CR_HPSEL;
*val |= FIELD_PREP(TPDM_DSB_CR_HPSEL, mode);
/* Set the performance mode */ if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF)
*val |= TPDM_DSB_CR_MODE; else
*val &= ~TPDM_DSB_CR_MODE;
}
val = readl_relaxed(drvdata->base + TPDM_DSB_TIER);
/* Clear all relevant fields */
val &= ~(TPDM_DSB_TIER_PATT_TSENAB | TPDM_DSB_TIER_PATT_TYPE |
TPDM_DSB_TIER_XTRIG_TSENAB);
/* Set pattern timestamp type and enablement */ if (drvdata->dsb->patt_ts) {
val |= TPDM_DSB_TIER_PATT_TSENAB; if (drvdata->dsb->patt_type)
val |= TPDM_DSB_TIER_PATT_TYPE; else
val &= ~TPDM_DSB_TIER_PATT_TYPE;
} else {
val &= ~TPDM_DSB_TIER_PATT_TSENAB;
}
/* Set trigger timestamp */ if (drvdata->dsb->trig_ts)
val |= TPDM_DSB_TIER_XTRIG_TSENAB; else
val &= ~TPDM_DSB_TIER_XTRIG_TSENAB;
for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
writel_relaxed(drvdata->dsb->edge_ctrl[i],
drvdata->base + TPDM_DSB_EDCR(i)); for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)
writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],
drvdata->base + TPDM_DSB_EDCMR(i)); for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
writel_relaxed(drvdata->dsb->patt_val[i],
drvdata->base + TPDM_DSB_TPR(i));
writel_relaxed(drvdata->dsb->patt_mask[i],
drvdata->base + TPDM_DSB_TPMR(i));
writel_relaxed(drvdata->dsb->trig_patt[i],
drvdata->base + TPDM_DSB_XPR(i));
writel_relaxed(drvdata->dsb->trig_patt_mask[i],
drvdata->base + TPDM_DSB_XPMR(i));
}
set_dsb_tier(drvdata);
set_dsb_msr(drvdata);
val = readl_relaxed(drvdata->base + TPDM_DSB_CR); /* Set the mode of DSB dataset */
set_dsb_mode(drvdata, &val); /* Set trigger type */ if (drvdata->dsb->trig_type)
val |= TPDM_DSB_CR_TRIG_TYPE; else
val &= ~TPDM_DSB_CR_TRIG_TYPE; /* Set the enable bit of DSB control register to 1 */
val |= TPDM_DSB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
}
val = readl_relaxed(drvdata->base + TPDM_CMB_CR); /* * Set to 0 for continuous CMB collection mode, * 1 for trace-on-change CMB collection mode.
*/ if (drvdata->cmb->trace_mode)
val |= TPDM_CMB_CR_MODE; else
val &= ~TPDM_CMB_CR_MODE;
if (tpdm_has_mcmb_dataset(drvdata)) {
val &= ~TPDM_CMB_CR_XTRIG_LNSEL; /* Set the lane participates in the output pattern */
val |= FIELD_PREP(TPDM_CMB_CR_XTRIG_LNSEL,
drvdata->cmb->mcmb.trig_lane);
/* Set the enablement of the lane */
val &= ~TPDM_CMB_CR_E_LN;
val |= FIELD_PREP(TPDM_CMB_CR_E_LN,
drvdata->cmb->mcmb.lane_select);
}
/* Set the enable bit of CMB control register to 1 */
val |= TPDM_CMB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
}
/* * TPDM enable operations * The TPDM or Monitor serves as data collection component for various * dataset types. It covers Basic Counts(BC), Tenure Counts(TC), * Continuous Multi-Bit(CMB), Multi-lane CMB(MCMB) and Discrete Single * Bit(DSB). This function will initialize the configuration according * to the dataset type supported by the TPDM.
*/ staticvoid __tpdm_enable(struct tpdm_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
/* Set the enable bit of DSB control register to 0 */
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
val &= ~TPDM_DSB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
}
val = readl_relaxed(drvdata->base + TPDM_CMB_CR); /* Set the enable bit of CMB control register to 0 */
val &= ~TPDM_CMB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_CMB_CR);
}
/* * value 1: 64 bits test data * value 2: 32 bits test data
*/ static ssize_t integration_test_store(struct device *dev, struct device_attribute *attr, constchar *buf,
size_t size)
{ int i, ret = 0; unsignedlong val; struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
ret = kstrtoul(buf, 10, &val); if (ret) return ret;
if (val != 1 && val != 2) return -EINVAL;
if (!drvdata->enable) return -EINVAL;
if (val == 1)
val = ATBCNTRL_VAL_64; else
val = ATBCNTRL_VAL_32;
CS_UNLOCK(drvdata->base);
writel_relaxed(0x1, drvdata->base + TPDM_ITCNTRL);
for (i = 0; i < INTEGRATION_TEST_CYCLE; i++)
writel_relaxed(val, drvdata->base + TPDM_ITATBCNTRL);
/* * The EDCR registers can include up to 16 32-bit registers, and each * one can be configured to control up to 16 edge detections(2 bits * control one edge detection). So a total 256 edge detections can be * configured. This function provides a way to set the index number of * the edge detection which needs to be configured.
*/ static ssize_t ctrl_idx_store(struct device *dev, struct device_attribute *attr, constchar *buf,
size_t size)
{ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); unsignedlong val;
if ((kstrtoul(buf, 0, &val)) || (val >= TPDM_DSB_MAX_LINES)) return -EINVAL;
/* * This function is used to control the edge detection according * to the index number that has been set. * "edge_ctrl" should be one of the following values. * 0 - Rising edge detection * 1 - Falling edge detection * 2 - Rising and falling edge detection (toggle detection)
*/ static ssize_t ctrl_val_store(struct device *dev, struct device_attribute *attr, constchar *buf,
size_t size)
{ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); unsignedlong val, edge_ctrl; int reg;
if ((kstrtoul(buf, 0, &edge_ctrl)) || (edge_ctrl > 0x2)) return -EINVAL;
spin_lock(&drvdata->spinlock); /* * There are 2 bit per DSB Edge Control line. * Thus we have 16 lines in a 32bit word.
*/
reg = EDCR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
val = drvdata->dsb->edge_ctrl[reg];
val &= ~EDCR_TO_WORD_MASK(drvdata->dsb->edge_ctrl_idx);
val |= EDCR_TO_WORD_VAL(edge_ctrl, drvdata->dsb->edge_ctrl_idx);
drvdata->dsb->edge_ctrl[reg] = val;
spin_unlock(&drvdata->spinlock);
if ((kstrtoul(buf, 0, &val)) || (val & ~1UL)) return -EINVAL;
spin_lock(&drvdata->spinlock); /* * There is 1 bit per DSB Edge Control Mark line. * Thus we have 32 lines in a 32bit word.
*/
reg = EDCMR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
set = drvdata->dsb->edge_ctrl_mask[reg]; if (val)
set |= BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx)); else
set &= ~BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));
drvdata->dsb->edge_ctrl_mask[reg] = set;
spin_unlock(&drvdata->spinlock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.