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

cb_pcidda.c (12186B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * comedi/drivers/cb_pcidda.c
      4 * Driver for the ComputerBoards / MeasurementComputing PCI-DDA series.
      5 *
      6 * Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com>
      7 * Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>
      8 *
      9 * COMEDI - Linux Control and Measurement Device Interface
     10 * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
     11 */
     12
     13/*
     14 * Driver: cb_pcidda
     15 * Description: MeasurementComputing PCI-DDA series
     16 * Devices: [Measurement Computing] PCI-DDA08/12 (pci-dda08/12),
     17 *   PCI-DDA04/12 (pci-dda04/12), PCI-DDA02/12 (pci-dda02/12),
     18 *   PCI-DDA08/16 (pci-dda08/16), PCI-DDA04/16 (pci-dda04/16),
     19 *   PCI-DDA02/16 (pci-dda02/16)
     20 * Author: Ivan Martinez <ivanmr@altavista.com>
     21 *	   Frank Mori Hess <fmhess@users.sourceforge.net>
     22 * Status: works
     23 *
     24 * Configuration options: not applicable, uses PCI auto config
     25 *
     26 * Only simple analog output writing is supported.
     27 */
     28
     29#include <linux/module.h>
     30#include <linux/comedi/comedi_pci.h>
     31#include <linux/comedi/comedi_8255.h>
     32
     33#define EEPROM_SIZE	128	/*  number of entries in eeprom */
     34/* maximum number of ao channels for supported boards */
     35#define MAX_AO_CHANNELS 8
     36
     37/* Digital I/O registers */
     38#define CB_DDA_DIO0_8255_BASE		0x00
     39#define CB_DDA_DIO1_8255_BASE		0x04
     40
     41/* DAC registers */
     42#define CB_DDA_DA_CTRL_REG		0x00	   /* D/A Control Register  */
     43#define CB_DDA_DA_CTRL_SU		BIT(0)   /*  Simultaneous update  */
     44#define CB_DDA_DA_CTRL_EN		BIT(1)   /*  Enable specified DAC */
     45#define CB_DDA_DA_CTRL_DAC(x)		((x) << 2) /*  Specify DAC channel  */
     46#define CB_DDA_DA_CTRL_RANGE2V5		(0 << 6)   /*  2.5V range           */
     47#define CB_DDA_DA_CTRL_RANGE5V		(2 << 6)   /*  5V range             */
     48#define CB_DDA_DA_CTRL_RANGE10V		(3 << 6)   /*  10V range            */
     49#define CB_DDA_DA_CTRL_UNIP		BIT(8)   /*  Unipolar range       */
     50
     51#define DACALIBRATION1	4	/*  D/A CALIBRATION REGISTER 1 */
     52/* write bits */
     53/* serial data input for eeprom, caldacs, reference dac */
     54#define SERIAL_IN_BIT   0x1
     55#define	CAL_CHANNEL_MASK	(0x7 << 1)
     56#define	CAL_CHANNEL_BITS(channel)	(((channel) << 1) & CAL_CHANNEL_MASK)
     57/* read bits */
     58#define	CAL_COUNTER_MASK	0x1f
     59/* calibration counter overflow status bit */
     60#define CAL_COUNTER_OVERFLOW_BIT        0x20
     61/* analog output is less than reference dac voltage */
     62#define AO_BELOW_REF_BIT        0x40
     63#define	SERIAL_OUT_BIT	0x80	/*  serial data out, for reading from eeprom */
     64
     65#define DACALIBRATION2	6	/*  D/A CALIBRATION REGISTER 2 */
     66#define	SELECT_EEPROM_BIT	0x1	/*  send serial data in to eeprom */
     67/* don't send serial data to MAX542 reference dac */
     68#define DESELECT_REF_DAC_BIT    0x2
     69/* don't send serial data to caldac n */
     70#define DESELECT_CALDAC_BIT(n)  (0x4 << (n))
     71/* manual says to set this bit with no explanation */
     72#define DUMMY_BIT       0x40
     73
     74#define CB_DDA_DA_DATA_REG(x)		(0x08 + ((x) * 2))
     75
     76/* Offsets for the caldac channels */
     77#define CB_DDA_CALDAC_FINE_GAIN		0
     78#define CB_DDA_CALDAC_COURSE_GAIN	1
     79#define CB_DDA_CALDAC_COURSE_OFFSET	2
     80#define CB_DDA_CALDAC_FINE_OFFSET	3
     81
     82static const struct comedi_lrange cb_pcidda_ranges = {
     83	6, {
     84		BIP_RANGE(10),
     85		BIP_RANGE(5),
     86		BIP_RANGE(2.5),
     87		UNI_RANGE(10),
     88		UNI_RANGE(5),
     89		UNI_RANGE(2.5)
     90	}
     91};
     92
     93enum cb_pcidda_boardid {
     94	BOARD_DDA02_12,
     95	BOARD_DDA04_12,
     96	BOARD_DDA08_12,
     97	BOARD_DDA02_16,
     98	BOARD_DDA04_16,
     99	BOARD_DDA08_16,
    100};
    101
    102struct cb_pcidda_board {
    103	const char *name;
    104	int ao_chans;
    105	int ao_bits;
    106};
    107
    108static const struct cb_pcidda_board cb_pcidda_boards[] = {
    109	[BOARD_DDA02_12] = {
    110		.name		= "pci-dda02/12",
    111		.ao_chans	= 2,
    112		.ao_bits	= 12,
    113	},
    114	[BOARD_DDA04_12] = {
    115		.name		= "pci-dda04/12",
    116		.ao_chans	= 4,
    117		.ao_bits	= 12,
    118	},
    119	[BOARD_DDA08_12] = {
    120		.name		= "pci-dda08/12",
    121		.ao_chans	= 8,
    122		.ao_bits	= 12,
    123	},
    124	[BOARD_DDA02_16] = {
    125		.name		= "pci-dda02/16",
    126		.ao_chans	= 2,
    127		.ao_bits	= 16,
    128	},
    129	[BOARD_DDA04_16] = {
    130		.name		= "pci-dda04/16",
    131		.ao_chans	= 4,
    132		.ao_bits	= 16,
    133	},
    134	[BOARD_DDA08_16] = {
    135		.name		= "pci-dda08/16",
    136		.ao_chans	= 8,
    137		.ao_bits	= 16,
    138	},
    139};
    140
    141struct cb_pcidda_private {
    142	unsigned long daqio;
    143	/* bits last written to da calibration register 1 */
    144	unsigned int dac_cal1_bits;
    145	/* current range settings for output channels */
    146	unsigned int ao_range[MAX_AO_CHANNELS];
    147	u16 eeprom_data[EEPROM_SIZE];	/*  software copy of board's eeprom */
    148};
    149
    150/* lowlevel read from eeprom */
    151static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
    152{
    153	struct cb_pcidda_private *devpriv = dev->private;
    154	unsigned int value = 0;
    155	int i;
    156	const int value_width = 16;	/*  number of bits wide values are */
    157
    158	for (i = 1; i <= value_width; i++) {
    159		/*  read bits most significant bit first */
    160		if (inw_p(devpriv->daqio + DACALIBRATION1) & SERIAL_OUT_BIT)
    161			value |= 1 << (value_width - i);
    162	}
    163
    164	return value;
    165}
    166
    167/* lowlevel write to eeprom/dac */
    168static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
    169				 unsigned int num_bits)
    170{
    171	struct cb_pcidda_private *devpriv = dev->private;
    172	int i;
    173
    174	for (i = 1; i <= num_bits; i++) {
    175		/*  send bits most significant bit first */
    176		if (value & (1 << (num_bits - i)))
    177			devpriv->dac_cal1_bits |= SERIAL_IN_BIT;
    178		else
    179			devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;
    180		outw_p(devpriv->dac_cal1_bits, devpriv->daqio + DACALIBRATION1);
    181	}
    182}
    183
    184/* reads a 16 bit value from board's eeprom */
    185static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
    186					  unsigned int address)
    187{
    188	struct cb_pcidda_private *devpriv = dev->private;
    189	unsigned int i;
    190	unsigned int cal2_bits;
    191	unsigned int value;
    192	/* one caldac for every two dac channels */
    193	const int max_num_caldacs = 4;
    194	/* bits to send to tell eeprom we want to read */
    195	const int read_instruction = 0x6;
    196	const int instruction_length = 3;
    197	const int address_length = 8;
    198
    199	/*  send serial output stream to eeprom */
    200	cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT;
    201	/*  deactivate caldacs (one caldac for every two channels) */
    202	for (i = 0; i < max_num_caldacs; i++)
    203		cal2_bits |= DESELECT_CALDAC_BIT(i);
    204	outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
    205
    206	/*  tell eeprom we want to read */
    207	cb_pcidda_serial_out(dev, read_instruction, instruction_length);
    208	/*  send address we want to read from */
    209	cb_pcidda_serial_out(dev, address, address_length);
    210
    211	value = cb_pcidda_serial_in(dev);
    212
    213	/*  deactivate eeprom */
    214	cal2_bits &= ~SELECT_EEPROM_BIT;
    215	outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
    216
    217	return value;
    218}
    219
    220/* writes to 8 bit calibration dacs */
    221static void cb_pcidda_write_caldac(struct comedi_device *dev,
    222				   unsigned int caldac, unsigned int channel,
    223				   unsigned int value)
    224{
    225	struct cb_pcidda_private *devpriv = dev->private;
    226	unsigned int cal2_bits;
    227	unsigned int i;
    228	/* caldacs use 3 bit channel specification */
    229	const int num_channel_bits = 3;
    230	const int num_caldac_bits = 8;	/*  8 bit calibration dacs */
    231	/* one caldac for every two dac channels */
    232	const int max_num_caldacs = 4;
    233
    234	/* write 3 bit channel */
    235	cb_pcidda_serial_out(dev, channel, num_channel_bits);
    236	/*  write 8 bit caldac value */
    237	cb_pcidda_serial_out(dev, value, num_caldac_bits);
    238
    239/*
    240 * latch stream into appropriate caldac deselect reference dac
    241 */
    242	cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT;
    243	/*  deactivate caldacs (one caldac for every two channels) */
    244	for (i = 0; i < max_num_caldacs; i++)
    245		cal2_bits |= DESELECT_CALDAC_BIT(i);
    246	/*  activate the caldac we want */
    247	cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
    248	outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
    249	/*  deactivate caldac */
    250	cal2_bits |= DESELECT_CALDAC_BIT(caldac);
    251	outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
    252}
    253
    254/* set caldacs to eeprom values for given channel and range */
    255static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
    256				unsigned int range)
    257{
    258	struct cb_pcidda_private *devpriv = dev->private;
    259	unsigned int caldac = channel / 2;	/* two caldacs per channel */
    260	unsigned int chan = 4 * (channel % 2);	/* caldac channel base */
    261	unsigned int index = 2 * range + 12 * channel;
    262	unsigned int offset;
    263	unsigned int gain;
    264
    265	/* save range so we can tell when we need to readjust calibration */
    266	devpriv->ao_range[channel] = range;
    267
    268	/* get values from eeprom data */
    269	offset = devpriv->eeprom_data[0x7 + index];
    270	gain = devpriv->eeprom_data[0x8 + index];
    271
    272	/* set caldacs */
    273	cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_OFFSET,
    274			       (offset >> 8) & 0xff);
    275	cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_OFFSET,
    276			       offset & 0xff);
    277	cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_GAIN,
    278			       (gain >> 8) & 0xff);
    279	cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_GAIN,
    280			       gain & 0xff);
    281}
    282
    283static int cb_pcidda_ao_insn_write(struct comedi_device *dev,
    284				   struct comedi_subdevice *s,
    285				   struct comedi_insn *insn,
    286				   unsigned int *data)
    287{
    288	struct cb_pcidda_private *devpriv = dev->private;
    289	unsigned int channel = CR_CHAN(insn->chanspec);
    290	unsigned int range = CR_RANGE(insn->chanspec);
    291	unsigned int ctrl;
    292	unsigned int i;
    293
    294	if (range != devpriv->ao_range[channel])
    295		cb_pcidda_calibrate(dev, channel, range);
    296
    297	ctrl = CB_DDA_DA_CTRL_EN | CB_DDA_DA_CTRL_DAC(channel);
    298
    299	switch (range) {
    300	case 0:
    301	case 3:
    302		ctrl |= CB_DDA_DA_CTRL_RANGE10V;
    303		break;
    304	case 1:
    305	case 4:
    306		ctrl |= CB_DDA_DA_CTRL_RANGE5V;
    307		break;
    308	case 2:
    309	case 5:
    310		ctrl |= CB_DDA_DA_CTRL_RANGE2V5;
    311		break;
    312	}
    313
    314	if (range > 2)
    315		ctrl |= CB_DDA_DA_CTRL_UNIP;
    316
    317	outw(ctrl, devpriv->daqio + CB_DDA_DA_CTRL_REG);
    318
    319	for (i = 0; i < insn->n; i++)
    320		outw(data[i], devpriv->daqio + CB_DDA_DA_DATA_REG(channel));
    321
    322	return insn->n;
    323}
    324
    325static int cb_pcidda_auto_attach(struct comedi_device *dev,
    326				 unsigned long context)
    327{
    328	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
    329	const struct cb_pcidda_board *board = NULL;
    330	struct cb_pcidda_private *devpriv;
    331	struct comedi_subdevice *s;
    332	int i;
    333	int ret;
    334
    335	if (context < ARRAY_SIZE(cb_pcidda_boards))
    336		board = &cb_pcidda_boards[context];
    337	if (!board)
    338		return -ENODEV;
    339	dev->board_ptr = board;
    340	dev->board_name = board->name;
    341
    342	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
    343	if (!devpriv)
    344		return -ENOMEM;
    345
    346	ret = comedi_pci_enable(dev);
    347	if (ret)
    348		return ret;
    349	dev->iobase = pci_resource_start(pcidev, 2);
    350	devpriv->daqio = pci_resource_start(pcidev, 3);
    351
    352	ret = comedi_alloc_subdevices(dev, 3);
    353	if (ret)
    354		return ret;
    355
    356	s = &dev->subdevices[0];
    357	/* analog output subdevice */
    358	s->type = COMEDI_SUBD_AO;
    359	s->subdev_flags = SDF_WRITABLE;
    360	s->n_chan = board->ao_chans;
    361	s->maxdata = (1 << board->ao_bits) - 1;
    362	s->range_table = &cb_pcidda_ranges;
    363	s->insn_write = cb_pcidda_ao_insn_write;
    364
    365	/* two 8255 digital io subdevices */
    366	for (i = 0; i < 2; i++) {
    367		s = &dev->subdevices[1 + i];
    368		ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
    369		if (ret)
    370			return ret;
    371	}
    372
    373	/* Read the caldac eeprom data */
    374	for (i = 0; i < EEPROM_SIZE; i++)
    375		devpriv->eeprom_data[i] = cb_pcidda_read_eeprom(dev, i);
    376
    377	/*  set calibrations dacs */
    378	for (i = 0; i < board->ao_chans; i++)
    379		cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]);
    380
    381	return 0;
    382}
    383
    384static struct comedi_driver cb_pcidda_driver = {
    385	.driver_name	= "cb_pcidda",
    386	.module		= THIS_MODULE,
    387	.auto_attach	= cb_pcidda_auto_attach,
    388	.detach		= comedi_pci_detach,
    389};
    390
    391static int cb_pcidda_pci_probe(struct pci_dev *dev,
    392			       const struct pci_device_id *id)
    393{
    394	return comedi_pci_auto_config(dev, &cb_pcidda_driver,
    395				      id->driver_data);
    396}
    397
    398static const struct pci_device_id cb_pcidda_pci_table[] = {
    399	{ PCI_VDEVICE(CB, 0x0020), BOARD_DDA02_12 },
    400	{ PCI_VDEVICE(CB, 0x0021), BOARD_DDA04_12 },
    401	{ PCI_VDEVICE(CB, 0x0022), BOARD_DDA08_12 },
    402	{ PCI_VDEVICE(CB, 0x0023), BOARD_DDA02_16 },
    403	{ PCI_VDEVICE(CB, 0x0024), BOARD_DDA04_16 },
    404	{ PCI_VDEVICE(CB, 0x0025), BOARD_DDA08_16 },
    405	{ 0 }
    406};
    407MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
    408
    409static struct pci_driver cb_pcidda_pci_driver = {
    410	.name		= "cb_pcidda",
    411	.id_table	= cb_pcidda_pci_table,
    412	.probe		= cb_pcidda_pci_probe,
    413	.remove		= comedi_pci_auto_unconfig,
    414};
    415module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver);
    416
    417MODULE_AUTHOR("Comedi https://www.comedi.org");
    418MODULE_DESCRIPTION("Comedi low-level driver");
    419MODULE_LICENSE("GPL");