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

hibmc_drm_i2c.c (2624B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* Hisilicon Hibmc SoC drm driver
      3 *
      4 * Based on the bochs drm driver.
      5 *
      6 * Copyright (c) 2016 Huawei Limited.
      7 *
      8 * Author:
      9 *      Tian Tao <tiantao6@hisilicon.com>
     10 */
     11
     12#include <linux/delay.h>
     13#include <linux/pci.h>
     14
     15#include <drm/drm_atomic_helper.h>
     16#include <drm/drm_probe_helper.h>
     17
     18#include "hibmc_drm_drv.h"
     19
     20#define GPIO_DATA		0x0802A0
     21#define GPIO_DATA_DIRECTION	0x0802A4
     22
     23#define I2C_SCL_MASK		BIT(0)
     24#define I2C_SDA_MASK		BIT(1)
     25
     26static void hibmc_set_i2c_signal(void *data, u32 mask, int value)
     27{
     28	struct hibmc_connector *hibmc_connector = data;
     29	struct hibmc_drm_private *priv = to_hibmc_drm_private(hibmc_connector->base.dev);
     30	u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
     31
     32	if (value) {
     33		tmp_dir &= ~mask;
     34		writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
     35	} else {
     36		u32 tmp_data = readl(priv->mmio + GPIO_DATA);
     37
     38		tmp_data &= ~mask;
     39		writel(tmp_data, priv->mmio + GPIO_DATA);
     40
     41		tmp_dir |= mask;
     42		writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
     43	}
     44}
     45
     46static int hibmc_get_i2c_signal(void *data, u32 mask)
     47{
     48	struct hibmc_connector *hibmc_connector = data;
     49	struct hibmc_drm_private *priv = to_hibmc_drm_private(hibmc_connector->base.dev);
     50	u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
     51
     52	if ((tmp_dir & mask) != mask) {
     53		tmp_dir &= ~mask;
     54		writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
     55	}
     56
     57	return (readl(priv->mmio + GPIO_DATA) & mask) ? 1 : 0;
     58}
     59
     60static void hibmc_ddc_setsda(void *data, int state)
     61{
     62	hibmc_set_i2c_signal(data, I2C_SDA_MASK, state);
     63}
     64
     65static void hibmc_ddc_setscl(void *data, int state)
     66{
     67	hibmc_set_i2c_signal(data, I2C_SCL_MASK, state);
     68}
     69
     70static int hibmc_ddc_getsda(void *data)
     71{
     72	return hibmc_get_i2c_signal(data, I2C_SDA_MASK);
     73}
     74
     75static int hibmc_ddc_getscl(void *data)
     76{
     77	return hibmc_get_i2c_signal(data, I2C_SCL_MASK);
     78}
     79
     80int hibmc_ddc_create(struct drm_device *drm_dev,
     81		     struct hibmc_connector *connector)
     82{
     83	connector->adapter.owner = THIS_MODULE;
     84	connector->adapter.class = I2C_CLASS_DDC;
     85	snprintf(connector->adapter.name, I2C_NAME_SIZE, "HIS i2c bit bus");
     86	connector->adapter.dev.parent = drm_dev->dev;
     87	i2c_set_adapdata(&connector->adapter, connector);
     88	connector->adapter.algo_data = &connector->bit_data;
     89
     90	connector->bit_data.udelay = 20;
     91	connector->bit_data.timeout = usecs_to_jiffies(2000);
     92	connector->bit_data.data = connector;
     93	connector->bit_data.setsda = hibmc_ddc_setsda;
     94	connector->bit_data.setscl = hibmc_ddc_setscl;
     95	connector->bit_data.getsda = hibmc_ddc_getsda;
     96	connector->bit_data.getscl = hibmc_ddc_getscl;
     97
     98	return i2c_bit_add_bus(&connector->adapter);
     99}