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

matrox_w1.c (4755B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	matrox_w1.c
      4 *
      5 * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
      6 */
      7
      8#include <asm/types.h>
      9#include <linux/atomic.h>
     10#include <asm/io.h>
     11
     12#include <linux/delay.h>
     13#include <linux/kernel.h>
     14#include <linux/module.h>
     15#include <linux/list.h>
     16#include <linux/interrupt.h>
     17#include <linux/spinlock.h>
     18#include <linux/timer.h>
     19#include <linux/slab.h>
     20#include <linux/pci_ids.h>
     21#include <linux/pci.h>
     22
     23#include <linux/w1.h>
     24
     25/*
     26 * Matrox G400 DDC registers.
     27 */
     28
     29#define MATROX_G400_DDC_CLK		(1<<4)
     30#define MATROX_G400_DDC_DATA		(1<<1)
     31
     32#define MATROX_BASE			0x3C00
     33#define MATROX_STATUS			0x1e14
     34
     35#define MATROX_PORT_INDEX_OFFSET	0x00
     36#define MATROX_PORT_DATA_OFFSET		0x0A
     37
     38#define MATROX_GET_CONTROL		0x2A
     39#define MATROX_GET_DATA			0x2B
     40#define MATROX_CURSOR_CTL		0x06
     41
     42struct matrox_device
     43{
     44	void __iomem *base_addr;
     45	void __iomem *port_index;
     46	void __iomem *port_data;
     47	u8 data_mask;
     48
     49	unsigned long phys_addr;
     50	void __iomem *virt_addr;
     51	unsigned long found;
     52
     53	struct w1_bus_master *bus_master;
     54};
     55
     56/*
     57 * These functions read and write DDC Data bit.
     58 *
     59 * Using tristate pins, since i can't find any open-drain pin in whole motherboard.
     60 * Unfortunately we can't connect to Intel's 82801xx IO controller
     61 * since we don't know motherboard schema, which has pretty unused(may be not) GPIO.
     62 *
     63 * I've heard that PIIX also has open drain pin.
     64 *
     65 * Port mapping.
     66 */
     67static __inline__ u8 matrox_w1_read_reg(struct matrox_device *dev, u8 reg)
     68{
     69	u8 ret;
     70
     71	writeb(reg, dev->port_index);
     72	ret = readb(dev->port_data);
     73	barrier();
     74
     75	return ret;
     76}
     77
     78static __inline__ void matrox_w1_write_reg(struct matrox_device *dev, u8 reg, u8 val)
     79{
     80	writeb(reg, dev->port_index);
     81	writeb(val, dev->port_data);
     82	wmb();
     83}
     84
     85static void matrox_w1_write_ddc_bit(void *data, u8 bit)
     86{
     87	u8 ret;
     88	struct matrox_device *dev = data;
     89
     90	if (bit)
     91		bit = 0;
     92	else
     93		bit = dev->data_mask;
     94
     95	ret = matrox_w1_read_reg(dev, MATROX_GET_CONTROL);
     96	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, ((ret & ~dev->data_mask) | bit));
     97	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0x00);
     98}
     99
    100static u8 matrox_w1_read_ddc_bit(void *data)
    101{
    102	u8 ret;
    103	struct matrox_device *dev = data;
    104
    105	ret = matrox_w1_read_reg(dev, MATROX_GET_DATA);
    106
    107	return ret;
    108}
    109
    110static void matrox_w1_hw_init(struct matrox_device *dev)
    111{
    112	matrox_w1_write_reg(dev, MATROX_GET_DATA, 0xFF);
    113	matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00);
    114}
    115
    116static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
    117{
    118	struct matrox_device *dev;
    119	int err;
    120
    121	if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
    122		return -ENODEV;
    123
    124	dev = kzalloc(sizeof(struct matrox_device) +
    125		       sizeof(struct w1_bus_master), GFP_KERNEL);
    126	if (!dev) {
    127		dev_err(&pdev->dev,
    128			"%s: Failed to create new matrox_device object.\n",
    129			__func__);
    130		return -ENOMEM;
    131	}
    132
    133
    134	dev->bus_master = (struct w1_bus_master *)(dev + 1);
    135
    136	/*
    137	 * True for G400, for some other we need resource 0, see drivers/video/matrox/matroxfb_base.c
    138	 */
    139
    140	dev->phys_addr = pci_resource_start(pdev, 1);
    141
    142	dev->virt_addr = ioremap(dev->phys_addr, 16384);
    143	if (!dev->virt_addr) {
    144		dev_err(&pdev->dev, "%s: failed to ioremap(0x%lx, %d).\n",
    145			__func__, dev->phys_addr, 16384);
    146		err = -EIO;
    147		goto err_out_free_device;
    148	}
    149
    150	dev->base_addr = dev->virt_addr + MATROX_BASE;
    151	dev->port_index = dev->base_addr + MATROX_PORT_INDEX_OFFSET;
    152	dev->port_data = dev->base_addr + MATROX_PORT_DATA_OFFSET;
    153	dev->data_mask = (MATROX_G400_DDC_DATA);
    154
    155	matrox_w1_hw_init(dev);
    156
    157	dev->bus_master->data = dev;
    158	dev->bus_master->read_bit = &matrox_w1_read_ddc_bit;
    159	dev->bus_master->write_bit = &matrox_w1_write_ddc_bit;
    160
    161	err = w1_add_master_device(dev->bus_master);
    162	if (err)
    163		goto err_out_free_device;
    164
    165	pci_set_drvdata(pdev, dev);
    166
    167	dev->found = 1;
    168
    169	dev_info(&pdev->dev, "Matrox G400 GPIO transport layer for 1-wire.\n");
    170
    171	return 0;
    172
    173err_out_free_device:
    174	if (dev->virt_addr)
    175		iounmap(dev->virt_addr);
    176	kfree(dev);
    177
    178	return err;
    179}
    180
    181static void matrox_w1_remove(struct pci_dev *pdev)
    182{
    183	struct matrox_device *dev = pci_get_drvdata(pdev);
    184
    185	if (dev->found) {
    186		w1_remove_master_device(dev->bus_master);
    187		iounmap(dev->virt_addr);
    188	}
    189	kfree(dev);
    190}
    191
    192static struct pci_device_id matrox_w1_tbl[] = {
    193	{ PCI_DEVICE(PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G400) },
    194	{ },
    195};
    196MODULE_DEVICE_TABLE(pci, matrox_w1_tbl);
    197
    198static struct pci_driver matrox_w1_pci_driver = {
    199	.name = "matrox_w1",
    200	.id_table = matrox_w1_tbl,
    201	.probe = matrox_w1_probe,
    202	.remove = matrox_w1_remove,
    203};
    204module_pci_driver(matrox_w1_pci_driver);
    205
    206MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
    207MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire protocol) over VGA DDC(matrox gpio).");
    208MODULE_LICENSE("GPL");