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-nvidia-gpu.c (9732B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Nvidia GPU I2C controller Driver
      4 *
      5 * Copyright (C) 2018 NVIDIA Corporation. All rights reserved.
      6 * Author: Ajay Gupta <ajayg@nvidia.com>
      7 */
      8#include <linux/delay.h>
      9#include <linux/i2c.h>
     10#include <linux/interrupt.h>
     11#include <linux/iopoll.h>
     12#include <linux/module.h>
     13#include <linux/pci.h>
     14#include <linux/platform_device.h>
     15#include <linux/pm.h>
     16#include <linux/pm_runtime.h>
     17
     18#include <asm/unaligned.h>
     19
     20#include "i2c-ccgx-ucsi.h"
     21
     22/* I2C definitions */
     23#define I2C_MST_CNTL				0x00
     24#define I2C_MST_CNTL_GEN_START			BIT(0)
     25#define I2C_MST_CNTL_GEN_STOP			BIT(1)
     26#define I2C_MST_CNTL_CMD_READ			(1 << 2)
     27#define I2C_MST_CNTL_CMD_WRITE			(2 << 2)
     28#define I2C_MST_CNTL_BURST_SIZE_SHIFT		6
     29#define I2C_MST_CNTL_GEN_NACK			BIT(28)
     30#define I2C_MST_CNTL_STATUS			GENMASK(30, 29)
     31#define I2C_MST_CNTL_STATUS_OKAY		(0 << 29)
     32#define I2C_MST_CNTL_STATUS_NO_ACK		(1 << 29)
     33#define I2C_MST_CNTL_STATUS_TIMEOUT		(2 << 29)
     34#define I2C_MST_CNTL_STATUS_BUS_BUSY		(3 << 29)
     35#define I2C_MST_CNTL_CYCLE_TRIGGER		BIT(31)
     36
     37#define I2C_MST_ADDR				0x04
     38
     39#define I2C_MST_I2C0_TIMING				0x08
     40#define I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ		0x10e
     41#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT		16
     42#define I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX		255
     43#define I2C_MST_I2C0_TIMING_TIMEOUT_CHECK		BIT(24)
     44
     45#define I2C_MST_DATA					0x0c
     46
     47#define I2C_MST_HYBRID_PADCTL				0x20
     48#define I2C_MST_HYBRID_PADCTL_MODE_I2C			BIT(0)
     49#define I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV		BIT(14)
     50#define I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV		BIT(15)
     51
     52struct gpu_i2c_dev {
     53	struct device *dev;
     54	void __iomem *regs;
     55	struct i2c_adapter adapter;
     56	struct i2c_board_info *gpu_ccgx_ucsi;
     57	struct i2c_client *ccgx_client;
     58};
     59
     60static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
     61{
     62	u32 val;
     63
     64	/* enable I2C */
     65	val = readl(i2cd->regs + I2C_MST_HYBRID_PADCTL);
     66	val |= I2C_MST_HYBRID_PADCTL_MODE_I2C |
     67		I2C_MST_HYBRID_PADCTL_I2C_SCL_INPUT_RCV |
     68		I2C_MST_HYBRID_PADCTL_I2C_SDA_INPUT_RCV;
     69	writel(val, i2cd->regs + I2C_MST_HYBRID_PADCTL);
     70
     71	/* enable 100KHZ mode */
     72	val = I2C_MST_I2C0_TIMING_SCL_PERIOD_100KHZ;
     73	val |= (I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT_MAX
     74	    << I2C_MST_I2C0_TIMING_TIMEOUT_CLK_CNT);
     75	val |= I2C_MST_I2C0_TIMING_TIMEOUT_CHECK;
     76	writel(val, i2cd->regs + I2C_MST_I2C0_TIMING);
     77}
     78
     79static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)
     80{
     81	u32 val;
     82	int ret;
     83
     84	ret = readl_poll_timeout(i2cd->regs + I2C_MST_CNTL, val,
     85				 !(val & I2C_MST_CNTL_CYCLE_TRIGGER) ||
     86				 (val & I2C_MST_CNTL_STATUS) != I2C_MST_CNTL_STATUS_BUS_BUSY,
     87				 500, 1000 * USEC_PER_MSEC);
     88
     89	if (ret) {
     90		dev_err(i2cd->dev, "i2c timeout error %x\n", val);
     91		return -ETIMEDOUT;
     92	}
     93
     94	val = readl(i2cd->regs + I2C_MST_CNTL);
     95	switch (val & I2C_MST_CNTL_STATUS) {
     96	case I2C_MST_CNTL_STATUS_OKAY:
     97		return 0;
     98	case I2C_MST_CNTL_STATUS_NO_ACK:
     99		return -ENXIO;
    100	case I2C_MST_CNTL_STATUS_TIMEOUT:
    101		return -ETIMEDOUT;
    102	default:
    103		return 0;
    104	}
    105}
    106
    107static int gpu_i2c_read(struct gpu_i2c_dev *i2cd, u8 *data, u16 len)
    108{
    109	int status;
    110	u32 val;
    111
    112	val = I2C_MST_CNTL_GEN_START | I2C_MST_CNTL_CMD_READ |
    113		(len << I2C_MST_CNTL_BURST_SIZE_SHIFT) |
    114		I2C_MST_CNTL_CYCLE_TRIGGER | I2C_MST_CNTL_GEN_NACK;
    115	writel(val, i2cd->regs + I2C_MST_CNTL);
    116
    117	status = gpu_i2c_check_status(i2cd);
    118	if (status < 0)
    119		return status;
    120
    121	val = readl(i2cd->regs + I2C_MST_DATA);
    122	switch (len) {
    123	case 1:
    124		data[0] = val;
    125		break;
    126	case 2:
    127		put_unaligned_be16(val, data);
    128		break;
    129	case 3:
    130		put_unaligned_be24(val, data);
    131		break;
    132	case 4:
    133		put_unaligned_be32(val, data);
    134		break;
    135	default:
    136		break;
    137	}
    138	return status;
    139}
    140
    141static int gpu_i2c_start(struct gpu_i2c_dev *i2cd)
    142{
    143	writel(I2C_MST_CNTL_GEN_START, i2cd->regs + I2C_MST_CNTL);
    144	return gpu_i2c_check_status(i2cd);
    145}
    146
    147static int gpu_i2c_stop(struct gpu_i2c_dev *i2cd)
    148{
    149	writel(I2C_MST_CNTL_GEN_STOP, i2cd->regs + I2C_MST_CNTL);
    150	return gpu_i2c_check_status(i2cd);
    151}
    152
    153static int gpu_i2c_write(struct gpu_i2c_dev *i2cd, u8 data)
    154{
    155	u32 val;
    156
    157	writel(data, i2cd->regs + I2C_MST_DATA);
    158
    159	val = I2C_MST_CNTL_CMD_WRITE | (1 << I2C_MST_CNTL_BURST_SIZE_SHIFT);
    160	writel(val, i2cd->regs + I2C_MST_CNTL);
    161
    162	return gpu_i2c_check_status(i2cd);
    163}
    164
    165static int gpu_i2c_master_xfer(struct i2c_adapter *adap,
    166			       struct i2c_msg *msgs, int num)
    167{
    168	struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap);
    169	int status, status2;
    170	bool send_stop = true;
    171	int i, j;
    172
    173	/*
    174	 * The controller supports maximum 4 byte read due to known
    175	 * limitation of sending STOP after every read.
    176	 */
    177	pm_runtime_get_sync(i2cd->dev);
    178	for (i = 0; i < num; i++) {
    179		if (msgs[i].flags & I2C_M_RD) {
    180			/* program client address before starting read */
    181			writel(msgs[i].addr, i2cd->regs + I2C_MST_ADDR);
    182			/* gpu_i2c_read has implicit start */
    183			status = gpu_i2c_read(i2cd, msgs[i].buf, msgs[i].len);
    184			if (status < 0)
    185				goto exit;
    186		} else {
    187			u8 addr = i2c_8bit_addr_from_msg(msgs + i);
    188
    189			status = gpu_i2c_start(i2cd);
    190			if (status < 0) {
    191				if (i == 0)
    192					send_stop = false;
    193				goto exit;
    194			}
    195
    196			status = gpu_i2c_write(i2cd, addr);
    197			if (status < 0)
    198				goto exit;
    199
    200			for (j = 0; j < msgs[i].len; j++) {
    201				status = gpu_i2c_write(i2cd, msgs[i].buf[j]);
    202				if (status < 0)
    203					goto exit;
    204			}
    205		}
    206	}
    207	send_stop = false;
    208	status = gpu_i2c_stop(i2cd);
    209	if (status < 0)
    210		goto exit;
    211
    212	status = i;
    213exit:
    214	if (send_stop) {
    215		status2 = gpu_i2c_stop(i2cd);
    216		if (status2 < 0)
    217			dev_err(i2cd->dev, "i2c stop failed %d\n", status2);
    218	}
    219	pm_runtime_mark_last_busy(i2cd->dev);
    220	pm_runtime_put_autosuspend(i2cd->dev);
    221	return status;
    222}
    223
    224static const struct i2c_adapter_quirks gpu_i2c_quirks = {
    225	.max_read_len = 4,
    226	.max_comb_2nd_msg_len = 4,
    227	.flags = I2C_AQ_COMB_WRITE_THEN_READ,
    228};
    229
    230static u32 gpu_i2c_functionality(struct i2c_adapter *adap)
    231{
    232	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
    233}
    234
    235static const struct i2c_algorithm gpu_i2c_algorithm = {
    236	.master_xfer	= gpu_i2c_master_xfer,
    237	.functionality	= gpu_i2c_functionality,
    238};
    239
    240/*
    241 * This driver is for Nvidia GPU cards with USB Type-C interface.
    242 * We want to identify the cards using vendor ID and class code only
    243 * to avoid dependency of adding product id for any new card which
    244 * requires this driver.
    245 * Currently there is no class code defined for UCSI device over PCI
    246 * so using UNKNOWN class for now and it will be updated when UCSI
    247 * over PCI gets a class code.
    248 * There is no other NVIDIA cards with UNKNOWN class code. Even if the
    249 * driver gets loaded for an undesired card then eventually i2c_read()
    250 * (initiated from UCSI i2c_client) will timeout or UCSI commands will
    251 * timeout.
    252 */
    253#define PCI_CLASS_SERIAL_UNKNOWN	0x0c80
    254static const struct pci_device_id gpu_i2c_ids[] = {
    255	{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
    256		PCI_CLASS_SERIAL_UNKNOWN << 8, 0xffffff00},
    257	{ }
    258};
    259MODULE_DEVICE_TABLE(pci, gpu_i2c_ids);
    260
    261static const struct property_entry ccgx_props[] = {
    262	/* Use FW built for NVIDIA (nv) only */
    263	PROPERTY_ENTRY_U16("ccgx,firmware-build", ('n' << 8) | 'v'),
    264	{ }
    265};
    266
    267static const struct software_node ccgx_node = {
    268	.properties = ccgx_props,
    269};
    270
    271static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id)
    272{
    273	struct device *dev = &pdev->dev;
    274	struct gpu_i2c_dev *i2cd;
    275	int status;
    276
    277	i2cd = devm_kzalloc(dev, sizeof(*i2cd), GFP_KERNEL);
    278	if (!i2cd)
    279		return -ENOMEM;
    280
    281	i2cd->dev = dev;
    282	dev_set_drvdata(dev, i2cd);
    283
    284	status = pcim_enable_device(pdev);
    285	if (status < 0)
    286		return dev_err_probe(dev, status, "pcim_enable_device failed\n");
    287
    288	pci_set_master(pdev);
    289
    290	i2cd->regs = pcim_iomap(pdev, 0, 0);
    291	if (!i2cd->regs)
    292		return dev_err_probe(dev, -ENOMEM, "pcim_iomap failed\n");
    293
    294	status = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
    295	if (status < 0)
    296		return dev_err_probe(dev, status, "pci_alloc_irq_vectors err\n");
    297
    298	gpu_enable_i2c_bus(i2cd);
    299
    300	i2c_set_adapdata(&i2cd->adapter, i2cd);
    301	i2cd->adapter.owner = THIS_MODULE;
    302	strlcpy(i2cd->adapter.name, "NVIDIA GPU I2C adapter",
    303		sizeof(i2cd->adapter.name));
    304	i2cd->adapter.algo = &gpu_i2c_algorithm;
    305	i2cd->adapter.quirks = &gpu_i2c_quirks;
    306	i2cd->adapter.dev.parent = dev;
    307	status = i2c_add_adapter(&i2cd->adapter);
    308	if (status < 0)
    309		goto free_irq_vectors;
    310
    311	i2cd->ccgx_client = i2c_new_ccgx_ucsi(&i2cd->adapter, pdev->irq, &ccgx_node);
    312	if (IS_ERR(i2cd->ccgx_client)) {
    313		status = dev_err_probe(dev, PTR_ERR(i2cd->ccgx_client), "register UCSI failed\n");
    314		goto del_adapter;
    315	}
    316
    317	pm_runtime_set_autosuspend_delay(dev, 3000);
    318	pm_runtime_use_autosuspend(dev);
    319	pm_runtime_put_autosuspend(dev);
    320	pm_runtime_allow(dev);
    321
    322	return 0;
    323
    324del_adapter:
    325	i2c_del_adapter(&i2cd->adapter);
    326free_irq_vectors:
    327	pci_free_irq_vectors(pdev);
    328	return status;
    329}
    330
    331static void gpu_i2c_remove(struct pci_dev *pdev)
    332{
    333	struct gpu_i2c_dev *i2cd = pci_get_drvdata(pdev);
    334
    335	pm_runtime_get_noresume(i2cd->dev);
    336	i2c_del_adapter(&i2cd->adapter);
    337	pci_free_irq_vectors(pdev);
    338}
    339
    340#define gpu_i2c_suspend NULL
    341
    342static __maybe_unused int gpu_i2c_resume(struct device *dev)
    343{
    344	struct gpu_i2c_dev *i2cd = dev_get_drvdata(dev);
    345
    346	gpu_enable_i2c_bus(i2cd);
    347	/*
    348	 * Runtime resume ccgx client so that it can see for any
    349	 * connector change event. Old ccg firmware has known
    350	 * issue of not triggering interrupt when a device is
    351	 * connected to runtime resume the controller.
    352	 */
    353	pm_request_resume(&i2cd->ccgx_client->dev);
    354	return 0;
    355}
    356
    357static UNIVERSAL_DEV_PM_OPS(gpu_i2c_driver_pm, gpu_i2c_suspend, gpu_i2c_resume,
    358			    NULL);
    359
    360static struct pci_driver gpu_i2c_driver = {
    361	.name		= "nvidia-gpu",
    362	.id_table	= gpu_i2c_ids,
    363	.probe		= gpu_i2c_probe,
    364	.remove		= gpu_i2c_remove,
    365	.driver		= {
    366		.pm	= &gpu_i2c_driver_pm,
    367	},
    368};
    369
    370module_pci_driver(gpu_i2c_driver);
    371
    372MODULE_AUTHOR("Ajay Gupta <ajayg@nvidia.com>");
    373MODULE_DESCRIPTION("Nvidia GPU I2C controller Driver");
    374MODULE_LICENSE("GPL v2");