cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xilinx-xadc-events.c (5829B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Xilinx XADC driver
      4 *
      5 * Copyright 2013 Analog Devices Inc.
      6 *  Author: Lars-Peter Clausen <lars@metafoo.de>
      7 */
      8
      9#include <linux/iio/events.h>
     10#include <linux/iio/iio.h>
     11#include <linux/kernel.h>
     12
     13#include "xilinx-xadc.h"
     14
     15static const struct iio_chan_spec *xadc_event_to_channel(
     16	struct iio_dev *indio_dev, unsigned int event)
     17{
     18	switch (event) {
     19	case XADC_THRESHOLD_OT_MAX:
     20	case XADC_THRESHOLD_TEMP_MAX:
     21		return &indio_dev->channels[0];
     22	case XADC_THRESHOLD_VCCINT_MAX:
     23	case XADC_THRESHOLD_VCCAUX_MAX:
     24		return &indio_dev->channels[event];
     25	default:
     26		return &indio_dev->channels[event-1];
     27	}
     28}
     29
     30static void xadc_handle_event(struct iio_dev *indio_dev, unsigned int event)
     31{
     32	const struct iio_chan_spec *chan;
     33
     34	/* Temperature threshold error, we don't handle this yet */
     35	if (event == 0)
     36		return;
     37
     38	chan = xadc_event_to_channel(indio_dev, event);
     39
     40	if (chan->type == IIO_TEMP) {
     41		/*
     42		 * The temperature channel only supports over-temperature
     43		 * events.
     44		 */
     45		iio_push_event(indio_dev,
     46			IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
     47				IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
     48			iio_get_time_ns(indio_dev));
     49	} else {
     50		/*
     51		 * For other channels we don't know whether it is a upper or
     52		 * lower threshold event. Userspace will have to check the
     53		 * channel value if it wants to know.
     54		 */
     55		iio_push_event(indio_dev,
     56			IIO_UNMOD_EVENT_CODE(chan->type, chan->channel,
     57				IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER),
     58			iio_get_time_ns(indio_dev));
     59	}
     60}
     61
     62void xadc_handle_events(struct iio_dev *indio_dev, unsigned long events)
     63{
     64	unsigned int i;
     65
     66	for_each_set_bit(i, &events, 8)
     67		xadc_handle_event(indio_dev, i);
     68}
     69
     70static unsigned int xadc_get_threshold_offset(const struct iio_chan_spec *chan,
     71	enum iio_event_direction dir)
     72{
     73	unsigned int offset;
     74
     75	if (chan->type == IIO_TEMP) {
     76		offset = XADC_THRESHOLD_OT_MAX;
     77	} else {
     78		if (chan->channel < 2)
     79			offset = chan->channel + 1;
     80		else
     81			offset = chan->channel + 6;
     82	}
     83
     84	if (dir == IIO_EV_DIR_FALLING)
     85		offset += 4;
     86
     87	return offset;
     88}
     89
     90static unsigned int xadc_get_alarm_mask(const struct iio_chan_spec *chan)
     91{
     92	if (chan->type == IIO_TEMP)
     93		return XADC_ALARM_OT_MASK;
     94	switch (chan->channel) {
     95	case 0:
     96		return XADC_ALARM_VCCINT_MASK;
     97	case 1:
     98		return XADC_ALARM_VCCAUX_MASK;
     99	case 2:
    100		return XADC_ALARM_VCCBRAM_MASK;
    101	case 3:
    102		return XADC_ALARM_VCCPINT_MASK;
    103	case 4:
    104		return XADC_ALARM_VCCPAUX_MASK;
    105	case 5:
    106		return XADC_ALARM_VCCODDR_MASK;
    107	default:
    108		/* We will never get here */
    109		return 0;
    110	}
    111}
    112
    113int xadc_read_event_config(struct iio_dev *indio_dev,
    114	const struct iio_chan_spec *chan, enum iio_event_type type,
    115	enum iio_event_direction dir)
    116{
    117	struct xadc *xadc = iio_priv(indio_dev);
    118
    119	return (bool)(xadc->alarm_mask & xadc_get_alarm_mask(chan));
    120}
    121
    122int xadc_write_event_config(struct iio_dev *indio_dev,
    123	const struct iio_chan_spec *chan, enum iio_event_type type,
    124	enum iio_event_direction dir, int state)
    125{
    126	unsigned int alarm = xadc_get_alarm_mask(chan);
    127	struct xadc *xadc = iio_priv(indio_dev);
    128	uint16_t cfg, old_cfg;
    129	int ret;
    130
    131	mutex_lock(&xadc->mutex);
    132
    133	if (state)
    134		xadc->alarm_mask |= alarm;
    135	else
    136		xadc->alarm_mask &= ~alarm;
    137
    138	xadc->ops->update_alarm(xadc, xadc->alarm_mask);
    139
    140	ret = _xadc_read_adc_reg(xadc, XADC_REG_CONF1, &cfg);
    141	if (ret)
    142		goto err_out;
    143
    144	old_cfg = cfg;
    145	cfg |= XADC_CONF1_ALARM_MASK;
    146	cfg &= ~((xadc->alarm_mask & 0xf0) << 4); /* bram, pint, paux, ddr */
    147	cfg &= ~((xadc->alarm_mask & 0x08) >> 3); /* ot */
    148	cfg &= ~((xadc->alarm_mask & 0x07) << 1); /* temp, vccint, vccaux */
    149	if (old_cfg != cfg)
    150		ret = _xadc_write_adc_reg(xadc, XADC_REG_CONF1, cfg);
    151
    152err_out:
    153	mutex_unlock(&xadc->mutex);
    154
    155	return ret;
    156}
    157
    158int xadc_read_event_value(struct iio_dev *indio_dev,
    159	const struct iio_chan_spec *chan, enum iio_event_type type,
    160	enum iio_event_direction dir, enum iio_event_info info,
    161	int *val, int *val2)
    162{
    163	unsigned int offset = xadc_get_threshold_offset(chan, dir);
    164	struct xadc *xadc = iio_priv(indio_dev);
    165
    166	switch (info) {
    167	case IIO_EV_INFO_VALUE:
    168		*val = xadc->threshold[offset];
    169		break;
    170	case IIO_EV_INFO_HYSTERESIS:
    171		*val = xadc->temp_hysteresis;
    172		break;
    173	default:
    174		return -EINVAL;
    175	}
    176
    177	/* MSB aligned */
    178	*val >>= 16 - chan->scan_type.realbits;
    179
    180	return IIO_VAL_INT;
    181}
    182
    183int xadc_write_event_value(struct iio_dev *indio_dev,
    184	const struct iio_chan_spec *chan, enum iio_event_type type,
    185	enum iio_event_direction dir, enum iio_event_info info,
    186	int val, int val2)
    187{
    188	unsigned int offset = xadc_get_threshold_offset(chan, dir);
    189	struct xadc *xadc = iio_priv(indio_dev);
    190	int ret = 0;
    191
    192	/* MSB aligned */
    193	val <<= 16 - chan->scan_type.realbits;
    194
    195	if (val < 0 || val > 0xffff)
    196		return -EINVAL;
    197
    198	mutex_lock(&xadc->mutex);
    199
    200	switch (info) {
    201	case IIO_EV_INFO_VALUE:
    202		xadc->threshold[offset] = val;
    203		break;
    204	case IIO_EV_INFO_HYSTERESIS:
    205		xadc->temp_hysteresis = val;
    206		break;
    207	default:
    208		mutex_unlock(&xadc->mutex);
    209		return -EINVAL;
    210	}
    211
    212	if (chan->type == IIO_TEMP) {
    213		/*
    214		 * According to the datasheet we need to set the lower 4 bits to
    215		 * 0x3, otherwise 125 degree celsius will be used as the
    216		 * threshold.
    217		 */
    218		val |= 0x3;
    219
    220		/*
    221		 * Since we store the hysteresis as relative (to the threshold)
    222		 * value, but the hardware expects an absolute value we need to
    223		 * recalcualte this value whenever the hysteresis or the
    224		 * threshold changes.
    225		 */
    226		if (xadc->threshold[offset] < xadc->temp_hysteresis)
    227			xadc->threshold[offset + 4] = 0;
    228		else
    229			xadc->threshold[offset + 4] = xadc->threshold[offset] -
    230					xadc->temp_hysteresis;
    231		ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset + 4),
    232			xadc->threshold[offset + 4]);
    233		if (ret)
    234			goto out_unlock;
    235	}
    236
    237	if (info == IIO_EV_INFO_VALUE)
    238		ret = _xadc_write_adc_reg(xadc, XADC_REG_THRESHOLD(offset), val);
    239
    240out_unlock:
    241	mutex_unlock(&xadc->mutex);
    242
    243	return ret;
    244}