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

i2c-sis630.c (14233B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3    Copyright (c) 2002,2003 Alexander Malysh <amalysh@web.de>
      4
      5*/
      6
      7/*
      8   Status: beta
      9
     10   Supports:
     11	SIS 630
     12	SIS 730
     13	SIS 964
     14
     15   Notable differences between chips:
     16	+------------------------+--------------------+-------------------+
     17	|                        |     SIS630/730     |      SIS964       |
     18	+------------------------+--------------------+-------------------+
     19	| Clock                  | 14kHz/56kHz        | 55.56kHz/27.78kHz |
     20	| SMBus registers offset | 0x80               | 0xE0              |
     21	| SMB_CNT                | Bit 1 = Slave Busy | Bit 1 = Bus probe |
     22	|         (not used yet) | Bit 3 is reserved  | Bit 3 = Last byte |
     23	| SMB_PCOUNT		 | Offset + 0x06      | Offset + 0x14     |
     24	| SMB_COUNT              | 4:0 bits           | 5:0 bits          |
     25	+------------------------+--------------------+-------------------+
     26	(Other differences don't affect the functions provided by the driver)
     27
     28   Note: we assume there can only be one device, with one SMBus interface.
     29*/
     30
     31#include <linux/kernel.h>
     32#include <linux/module.h>
     33#include <linux/delay.h>
     34#include <linux/pci.h>
     35#include <linux/ioport.h>
     36#include <linux/i2c.h>
     37#include <linux/acpi.h>
     38#include <linux/io.h>
     39
     40/* SIS964 id is defined here as we are the only file using it */
     41#define PCI_DEVICE_ID_SI_964	0x0964
     42
     43/* SIS630/730/964 SMBus registers */
     44#define SMB_STS			0x00	/* status */
     45#define SMB_CNT			0x02	/* control */
     46#define SMBHOST_CNT		0x03	/* host control */
     47#define SMB_ADDR		0x04	/* address */
     48#define SMB_CMD			0x05	/* command */
     49#define SMB_COUNT		0x07	/* byte count */
     50#define SMB_BYTE		0x08	/* ~0x8F data byte field */
     51
     52/* SMB_STS register */
     53#define BYTE_DONE_STS		0x10	/* Byte Done Status / Block Array */
     54#define SMBCOL_STS		0x04	/* Collision */
     55#define SMBERR_STS		0x02	/* Device error */
     56
     57/* SMB_CNT register */
     58#define MSTO_EN			0x40	/* Host Master Timeout Enable */
     59#define SMBCLK_SEL		0x20	/* Host master clock selection */
     60#define SMB_PROBE		0x02	/* Bus Probe/Slave busy */
     61#define SMB_HOSTBUSY		0x01	/* Host Busy */
     62
     63/* SMBHOST_CNT register */
     64#define SMB_KILL		0x20	/* Kill */
     65#define SMB_START		0x10	/* Start */
     66
     67/* register count for request_region
     68 * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964
     69 */
     70#define SIS630_SMB_IOREGION	20
     71
     72/* PCI address constants */
     73/* acpi base address register  */
     74#define SIS630_ACPI_BASE_REG	0x74
     75/* bios control register */
     76#define SIS630_BIOS_CTL_REG	0x40
     77
     78/* Other settings */
     79#define MAX_TIMEOUT		500
     80
     81/* SIS630 constants */
     82#define SIS630_QUICK		0x00
     83#define SIS630_BYTE		0x01
     84#define SIS630_BYTE_DATA	0x02
     85#define SIS630_WORD_DATA	0x03
     86#define SIS630_PCALL		0x04
     87#define SIS630_BLOCK_DATA	0x05
     88
     89static struct pci_driver sis630_driver;
     90
     91/* insmod parameters */
     92static bool high_clock;
     93static bool force;
     94module_param(high_clock, bool, 0);
     95MODULE_PARM_DESC(high_clock,
     96	"Set Host Master Clock to 56KHz (default 14KHz) (SIS630/730 only).");
     97module_param(force, bool, 0);
     98MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
     99
    100/* SMBus base adress */
    101static unsigned short smbus_base;
    102
    103/* supported chips */
    104static int supported[] = {
    105	PCI_DEVICE_ID_SI_630,
    106	PCI_DEVICE_ID_SI_730,
    107	PCI_DEVICE_ID_SI_760,
    108	0 /* terminates the list */
    109};
    110
    111static inline u8 sis630_read(u8 reg)
    112{
    113	return inb(smbus_base + reg);
    114}
    115
    116static inline void sis630_write(u8 reg, u8 data)
    117{
    118	outb(data, smbus_base + reg);
    119}
    120
    121static int sis630_transaction_start(struct i2c_adapter *adap, int size,
    122				    u8 *oldclock)
    123{
    124	int temp;
    125
    126	/* Make sure the SMBus host is ready to start transmitting. */
    127	temp = sis630_read(SMB_CNT);
    128	if ((temp & (SMB_PROBE | SMB_HOSTBUSY)) != 0x00) {
    129		dev_dbg(&adap->dev, "SMBus busy (%02x). Resetting...\n", temp);
    130		/* kill smbus transaction */
    131		sis630_write(SMBHOST_CNT, SMB_KILL);
    132
    133		temp = sis630_read(SMB_CNT);
    134		if (temp & (SMB_PROBE | SMB_HOSTBUSY)) {
    135			dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
    136			return -EBUSY;
    137		} else {
    138			dev_dbg(&adap->dev, "Successful!\n");
    139		}
    140	}
    141
    142	/* save old clock, so we can prevent machine for hung */
    143	*oldclock = sis630_read(SMB_CNT);
    144
    145	dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock);
    146
    147	/* disable timeout interrupt,
    148	 * set Host Master Clock to 56KHz if requested */
    149	if (high_clock)
    150		sis630_write(SMB_CNT, SMBCLK_SEL);
    151	else
    152		sis630_write(SMB_CNT, (*oldclock & ~MSTO_EN));
    153
    154	/* clear all sticky bits */
    155	temp = sis630_read(SMB_STS);
    156	sis630_write(SMB_STS, temp & 0x1e);
    157
    158	/* start the transaction by setting bit 4 and size */
    159	sis630_write(SMBHOST_CNT, SMB_START | (size & 0x07));
    160
    161	return 0;
    162}
    163
    164static int sis630_transaction_wait(struct i2c_adapter *adap, int size)
    165{
    166	int temp, result = 0, timeout = 0;
    167
    168	/* We will always wait for a fraction of a second! */
    169	do {
    170		msleep(1);
    171		temp = sis630_read(SMB_STS);
    172		/* check if block transmitted */
    173		if (size == SIS630_BLOCK_DATA && (temp & BYTE_DONE_STS))
    174			break;
    175	} while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
    176
    177	/* If the SMBus is still busy, we give up */
    178	if (timeout > MAX_TIMEOUT) {
    179		dev_dbg(&adap->dev, "SMBus Timeout!\n");
    180		result = -ETIMEDOUT;
    181	}
    182
    183	if (temp & SMBERR_STS) {
    184		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
    185		result = -ENXIO;
    186	}
    187
    188	if (temp & SMBCOL_STS) {
    189		dev_err(&adap->dev, "Bus collision!\n");
    190		result = -EAGAIN;
    191	}
    192
    193	return result;
    194}
    195
    196static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock)
    197{
    198	/* clear all status "sticky" bits */
    199	sis630_write(SMB_STS, 0xFF);
    200
    201	dev_dbg(&adap->dev,
    202		"SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT));
    203
    204	/*
    205	 * restore old Host Master Clock if high_clock is set
    206	 * and oldclock was not 56KHz
    207	 */
    208	if (high_clock && !(oldclock & SMBCLK_SEL))
    209		sis630_write(SMB_CNT, sis630_read(SMB_CNT) & ~SMBCLK_SEL);
    210
    211	dev_dbg(&adap->dev,
    212		"SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT));
    213}
    214
    215static int sis630_transaction(struct i2c_adapter *adap, int size)
    216{
    217	int result = 0;
    218	u8 oldclock = 0;
    219
    220	result = sis630_transaction_start(adap, size, &oldclock);
    221	if (!result) {
    222		result = sis630_transaction_wait(adap, size);
    223		sis630_transaction_end(adap, oldclock);
    224	}
    225
    226	return result;
    227}
    228
    229static int sis630_block_data(struct i2c_adapter *adap,
    230			     union i2c_smbus_data *data, int read_write)
    231{
    232	int i, len = 0, rc = 0;
    233	u8 oldclock = 0;
    234
    235	if (read_write == I2C_SMBUS_WRITE) {
    236		len = data->block[0];
    237		if (len < 0)
    238			len = 0;
    239		else if (len > 32)
    240			len = 32;
    241		sis630_write(SMB_COUNT, len);
    242		for (i = 1; i <= len; i++) {
    243			dev_dbg(&adap->dev,
    244				"set data 0x%02x\n", data->block[i]);
    245			/* set data */
    246			sis630_write(SMB_BYTE + (i - 1) % 8, data->block[i]);
    247			if (i == 8 || (len < 8 && i == len)) {
    248				dev_dbg(&adap->dev,
    249					"start trans len=%d i=%d\n", len, i);
    250				/* first transaction */
    251				rc = sis630_transaction_start(adap,
    252						SIS630_BLOCK_DATA, &oldclock);
    253				if (rc)
    254					return rc;
    255			} else if ((i - 1) % 8 == 7 || i == len) {
    256				dev_dbg(&adap->dev,
    257					"trans_wait len=%d i=%d\n", len, i);
    258				if (i > 8) {
    259					dev_dbg(&adap->dev,
    260						"clear smbary_sts"
    261						" len=%d i=%d\n", len, i);
    262					/*
    263					   If this is not first transaction,
    264					   we must clear sticky bit.
    265					   clear SMBARY_STS
    266					*/
    267					sis630_write(SMB_STS, BYTE_DONE_STS);
    268				}
    269				rc = sis630_transaction_wait(adap,
    270						SIS630_BLOCK_DATA);
    271				if (rc) {
    272					dev_dbg(&adap->dev,
    273						"trans_wait failed\n");
    274					break;
    275				}
    276			}
    277		}
    278	} else {
    279		/* read request */
    280		data->block[0] = len = 0;
    281		rc = sis630_transaction_start(adap,
    282				SIS630_BLOCK_DATA, &oldclock);
    283		if (rc)
    284			return rc;
    285		do {
    286			rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA);
    287			if (rc) {
    288				dev_dbg(&adap->dev, "trans_wait failed\n");
    289				break;
    290			}
    291			/* if this first transaction then read byte count */
    292			if (len == 0)
    293				data->block[0] = sis630_read(SMB_COUNT);
    294
    295			/* just to be sure */
    296			if (data->block[0] > 32)
    297				data->block[0] = 32;
    298
    299			dev_dbg(&adap->dev,
    300				"block data read len=0x%x\n", data->block[0]);
    301
    302			for (i = 0; i < 8 && len < data->block[0]; i++, len++) {
    303				dev_dbg(&adap->dev,
    304					"read i=%d len=%d\n", i, len);
    305				data->block[len + 1] = sis630_read(SMB_BYTE +
    306								   i);
    307			}
    308
    309			dev_dbg(&adap->dev,
    310				"clear smbary_sts len=%d i=%d\n", len, i);
    311
    312			/* clear SMBARY_STS */
    313			sis630_write(SMB_STS, BYTE_DONE_STS);
    314		} while (len < data->block[0]);
    315	}
    316
    317	sis630_transaction_end(adap, oldclock);
    318
    319	return rc;
    320}
    321
    322/* Return negative errno on error. */
    323static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
    324			 unsigned short flags, char read_write,
    325			 u8 command, int size, union i2c_smbus_data *data)
    326{
    327	int status;
    328
    329	switch (size) {
    330	case I2C_SMBUS_QUICK:
    331		sis630_write(SMB_ADDR,
    332			     ((addr & 0x7f) << 1) | (read_write & 0x01));
    333		size = SIS630_QUICK;
    334		break;
    335	case I2C_SMBUS_BYTE:
    336		sis630_write(SMB_ADDR,
    337			     ((addr & 0x7f) << 1) | (read_write & 0x01));
    338		if (read_write == I2C_SMBUS_WRITE)
    339			sis630_write(SMB_CMD, command);
    340		size = SIS630_BYTE;
    341		break;
    342	case I2C_SMBUS_BYTE_DATA:
    343		sis630_write(SMB_ADDR,
    344			     ((addr & 0x7f) << 1) | (read_write & 0x01));
    345		sis630_write(SMB_CMD, command);
    346		if (read_write == I2C_SMBUS_WRITE)
    347			sis630_write(SMB_BYTE, data->byte);
    348		size = SIS630_BYTE_DATA;
    349		break;
    350	case I2C_SMBUS_PROC_CALL:
    351	case I2C_SMBUS_WORD_DATA:
    352		sis630_write(SMB_ADDR,
    353			     ((addr & 0x7f) << 1) | (read_write & 0x01));
    354		sis630_write(SMB_CMD, command);
    355		if (read_write == I2C_SMBUS_WRITE) {
    356			sis630_write(SMB_BYTE, data->word & 0xff);
    357			sis630_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
    358		}
    359		size = (size == I2C_SMBUS_PROC_CALL ?
    360			SIS630_PCALL : SIS630_WORD_DATA);
    361		break;
    362	case I2C_SMBUS_BLOCK_DATA:
    363		sis630_write(SMB_ADDR,
    364			     ((addr & 0x7f) << 1) | (read_write & 0x01));
    365		sis630_write(SMB_CMD, command);
    366		size = SIS630_BLOCK_DATA;
    367		return sis630_block_data(adap, data, read_write);
    368	default:
    369		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
    370		return -EOPNOTSUPP;
    371	}
    372
    373	status = sis630_transaction(adap, size);
    374	if (status)
    375		return status;
    376
    377	if ((size != SIS630_PCALL) &&
    378		((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) {
    379		return 0;
    380	}
    381
    382	switch (size) {
    383	case SIS630_BYTE:
    384	case SIS630_BYTE_DATA:
    385		data->byte = sis630_read(SMB_BYTE);
    386		break;
    387	case SIS630_PCALL:
    388	case SIS630_WORD_DATA:
    389		data->word = sis630_read(SMB_BYTE) +
    390			     (sis630_read(SMB_BYTE + 1) << 8);
    391		break;
    392	}
    393
    394	return 0;
    395}
    396
    397static u32 sis630_func(struct i2c_adapter *adapter)
    398{
    399	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
    400		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
    401		I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
    402}
    403
    404static int sis630_setup(struct pci_dev *sis630_dev)
    405{
    406	unsigned char b;
    407	struct pci_dev *dummy = NULL;
    408	int retval, i;
    409	/* acpi base address */
    410	unsigned short acpi_base;
    411
    412	/* check for supported SiS devices */
    413	for (i = 0; supported[i] > 0; i++) {
    414		dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy);
    415		if (dummy)
    416			break; /* found */
    417	}
    418
    419	if (dummy) {
    420		pci_dev_put(dummy);
    421	} else if (force) {
    422		dev_err(&sis630_dev->dev,
    423			"WARNING: Can't detect SIS630 compatible device, but "
    424			"loading because of force option enabled\n");
    425	} else {
    426		return -ENODEV;
    427	}
    428
    429	/*
    430	   Enable ACPI first , so we can accsess reg 74-75
    431	   in acpi io space and read acpi base addr
    432	*/
    433	if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, &b)) {
    434		dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
    435		retval = -ENODEV;
    436		goto exit;
    437	}
    438	/* if ACPI already enabled , do nothing */
    439	if (!(b & 0x80) &&
    440	    pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
    441		dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
    442		retval = -ENODEV;
    443		goto exit;
    444	}
    445
    446	/* Determine the ACPI base address */
    447	if (pci_read_config_word(sis630_dev,
    448				 SIS630_ACPI_BASE_REG, &acpi_base)) {
    449		dev_err(&sis630_dev->dev,
    450			"Error: Can't determine ACPI base address\n");
    451		retval = -ENODEV;
    452		goto exit;
    453	}
    454
    455	dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04hx\n", acpi_base);
    456
    457	if (supported[i] == PCI_DEVICE_ID_SI_760)
    458		smbus_base = acpi_base + 0xE0;
    459	else
    460		smbus_base = acpi_base + 0x80;
    461
    462	dev_dbg(&sis630_dev->dev, "SMBus base at 0x%04hx\n", smbus_base);
    463
    464	retval = acpi_check_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
    465				   sis630_driver.name);
    466	if (retval)
    467		goto exit;
    468
    469	/* Everything is happy, let's grab the memory and set things up. */
    470	if (!request_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
    471			    sis630_driver.name)) {
    472		dev_err(&sis630_dev->dev,
    473			"I/O Region 0x%04x-0x%04x for SMBus already in use.\n",
    474			smbus_base + SMB_STS,
    475			smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
    476		retval = -EBUSY;
    477		goto exit;
    478	}
    479
    480	retval = 0;
    481
    482exit:
    483	if (retval)
    484		smbus_base = 0;
    485	return retval;
    486}
    487
    488
    489static const struct i2c_algorithm smbus_algorithm = {
    490	.smbus_xfer	= sis630_access,
    491	.functionality	= sis630_func,
    492};
    493
    494static struct i2c_adapter sis630_adapter = {
    495	.owner		= THIS_MODULE,
    496	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
    497	.algo		= &smbus_algorithm,
    498	.retries	= 3
    499};
    500
    501static const struct pci_device_id sis630_ids[] = {
    502	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
    503	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
    504	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) },
    505	{ 0, }
    506};
    507
    508MODULE_DEVICE_TABLE(pci, sis630_ids);
    509
    510static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
    511{
    512	if (sis630_setup(dev)) {
    513		dev_err(&dev->dev,
    514			"SIS630 compatible bus not detected, "
    515			"module not inserted.\n");
    516		return -ENODEV;
    517	}
    518
    519	/* set up the sysfs linkage to our parent device */
    520	sis630_adapter.dev.parent = &dev->dev;
    521
    522	snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
    523		 "SMBus SIS630 adapter at %04x", smbus_base + SMB_STS);
    524
    525	return i2c_add_adapter(&sis630_adapter);
    526}
    527
    528static void sis630_remove(struct pci_dev *dev)
    529{
    530	if (smbus_base) {
    531		i2c_del_adapter(&sis630_adapter);
    532		release_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION);
    533		smbus_base = 0;
    534	}
    535}
    536
    537
    538static struct pci_driver sis630_driver = {
    539	.name		= "sis630_smbus",
    540	.id_table	= sis630_ids,
    541	.probe		= sis630_probe,
    542	.remove		= sis630_remove,
    543};
    544
    545module_pci_driver(sis630_driver);
    546
    547MODULE_LICENSE("GPL");
    548MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
    549MODULE_DESCRIPTION("SIS630 SMBus driver");