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

savagefb-i2c.c (5691B)


      1/*
      2 * linux/drivers/video/savage/savagefb-i2c.c - S3 Savage DDC2
      3 *
      4 * Copyright 2004 Antonino A. Daplas <adaplas @pol.net>
      5 *
      6 * Based partly on rivafb-i2c.c
      7 *
      8 * This file is subject to the terms and conditions of the GNU General Public
      9 * License.  See the file COPYING in the main directory of this archive
     10 * for more details.
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/kernel.h>
     15#include <linux/delay.h>
     16#include <linux/gfp.h>
     17#include <linux/pci.h>
     18#include <linux/fb.h>
     19
     20#include <asm/io.h>
     21#include "savagefb.h"
     22
     23#define SAVAGE_DDC 	0x50
     24
     25#define VGA_CR_IX	0x3d4
     26#define VGA_CR_DATA	0x3d5
     27
     28#define CR_SERIAL1	0xa0	/* I2C serial communications interface */
     29#define MM_SERIAL1	0xff20
     30#define CR_SERIAL2	0xb1	/* DDC2 monitor communications interface */
     31
     32/* based on vt8365 documentation */
     33#define PROSAVAGE_I2C_ENAB	0x10
     34#define PROSAVAGE_I2C_SCL_OUT	0x01
     35#define PROSAVAGE_I2C_SDA_OUT	0x02
     36#define PROSAVAGE_I2C_SCL_IN	0x04
     37#define PROSAVAGE_I2C_SDA_IN	0x08
     38
     39#define SAVAGE4_I2C_ENAB	0x00000020
     40#define SAVAGE4_I2C_SCL_OUT	0x00000001
     41#define SAVAGE4_I2C_SDA_OUT	0x00000002
     42#define SAVAGE4_I2C_SCL_IN	0x00000008
     43#define SAVAGE4_I2C_SDA_IN	0x00000010
     44
     45static void savage4_gpio_setscl(void *data, int val)
     46{
     47	struct savagefb_i2c_chan *chan = data;
     48	unsigned int r;
     49
     50	r = readl(chan->ioaddr + chan->reg);
     51	if(val)
     52		r |= SAVAGE4_I2C_SCL_OUT;
     53	else
     54		r &= ~SAVAGE4_I2C_SCL_OUT;
     55	writel(r, chan->ioaddr + chan->reg);
     56	readl(chan->ioaddr + chan->reg);	/* flush posted write */
     57}
     58
     59static void savage4_gpio_setsda(void *data, int val)
     60{
     61	struct savagefb_i2c_chan *chan = data;
     62
     63	unsigned int r;
     64	r = readl(chan->ioaddr + chan->reg);
     65	if(val)
     66		r |= SAVAGE4_I2C_SDA_OUT;
     67	else
     68		r &= ~SAVAGE4_I2C_SDA_OUT;
     69	writel(r, chan->ioaddr + chan->reg);
     70	readl(chan->ioaddr + chan->reg);	/* flush posted write */
     71}
     72
     73static int savage4_gpio_getscl(void *data)
     74{
     75	struct savagefb_i2c_chan *chan = data;
     76
     77	return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SCL_IN));
     78}
     79
     80static int savage4_gpio_getsda(void *data)
     81{
     82	struct savagefb_i2c_chan *chan = data;
     83
     84	return (0 != (readl(chan->ioaddr + chan->reg) & SAVAGE4_I2C_SDA_IN));
     85}
     86
     87static void prosavage_gpio_setscl(void* data, int val)
     88{
     89	struct savagefb_i2c_chan *chan = data;
     90	u32			  r;
     91
     92	r = VGArCR(chan->reg, chan->par);
     93	r |= PROSAVAGE_I2C_ENAB;
     94	if (val) {
     95		r |= PROSAVAGE_I2C_SCL_OUT;
     96	} else {
     97		r &= ~PROSAVAGE_I2C_SCL_OUT;
     98	}
     99
    100	VGAwCR(chan->reg, r, chan->par);
    101}
    102
    103static void prosavage_gpio_setsda(void* data, int val)
    104{
    105	struct savagefb_i2c_chan *chan = data;
    106	unsigned int r;
    107
    108	r = VGArCR(chan->reg, chan->par);
    109	r |= PROSAVAGE_I2C_ENAB;
    110	if (val) {
    111		r |= PROSAVAGE_I2C_SDA_OUT;
    112	} else {
    113		r &= ~PROSAVAGE_I2C_SDA_OUT;
    114	}
    115
    116	VGAwCR(chan->reg, r, chan->par);
    117}
    118
    119static int prosavage_gpio_getscl(void* data)
    120{
    121	struct savagefb_i2c_chan *chan = data;
    122
    123	return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SCL_IN) ? 1 : 0;
    124}
    125
    126static int prosavage_gpio_getsda(void* data)
    127{
    128	struct savagefb_i2c_chan *chan = data;
    129
    130	return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SDA_IN) ? 1 : 0;
    131}
    132
    133static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
    134				const char *name)
    135{
    136	int rc = 0;
    137
    138	if (chan->par) {
    139		strcpy(chan->adapter.name, name);
    140		chan->adapter.owner		= THIS_MODULE;
    141		chan->adapter.algo_data		= &chan->algo;
    142		chan->adapter.dev.parent	= &chan->par->pcidev->dev;
    143		chan->algo.udelay		= 10;
    144		chan->algo.timeout		= 20;
    145		chan->algo.data 		= chan;
    146
    147		i2c_set_adapdata(&chan->adapter, chan);
    148
    149		/* Raise SCL and SDA */
    150		chan->algo.setsda(chan, 1);
    151		chan->algo.setscl(chan, 1);
    152		udelay(20);
    153
    154		rc = i2c_bit_add_bus(&chan->adapter);
    155
    156		if (rc == 0)
    157			dev_dbg(&chan->par->pcidev->dev,
    158				"I2C bus %s registered.\n", name);
    159		else
    160			dev_warn(&chan->par->pcidev->dev,
    161				 "Failed to register I2C bus %s.\n", name);
    162	}
    163
    164	return rc;
    165}
    166
    167void savagefb_create_i2c_busses(struct fb_info *info)
    168{
    169	struct savagefb_par *par = info->par;
    170	par->chan.par	= par;
    171
    172	switch (par->chip) {
    173	case S3_PROSAVAGE:
    174	case S3_PROSAVAGEDDR:
    175	case S3_TWISTER:
    176		par->chan.reg         = CR_SERIAL2;
    177		par->chan.ioaddr      = par->mmio.vbase;
    178		par->chan.algo.setsda = prosavage_gpio_setsda;
    179		par->chan.algo.setscl = prosavage_gpio_setscl;
    180		par->chan.algo.getsda = prosavage_gpio_getsda;
    181		par->chan.algo.getscl = prosavage_gpio_getscl;
    182		break;
    183	case S3_SAVAGE4:
    184		par->chan.reg = CR_SERIAL1;
    185		if (par->pcidev->revision > 1 && !(VGArCR(0xa6, par) & 0x40))
    186			par->chan.reg = CR_SERIAL2;
    187		par->chan.ioaddr      = par->mmio.vbase;
    188		par->chan.algo.setsda = prosavage_gpio_setsda;
    189		par->chan.algo.setscl = prosavage_gpio_setscl;
    190		par->chan.algo.getsda = prosavage_gpio_getsda;
    191		par->chan.algo.getscl = prosavage_gpio_getscl;
    192		break;
    193	case S3_SAVAGE2000:
    194		par->chan.reg         = MM_SERIAL1;
    195		par->chan.ioaddr      = par->mmio.vbase;
    196		par->chan.algo.setsda = savage4_gpio_setsda;
    197		par->chan.algo.setscl = savage4_gpio_setscl;
    198		par->chan.algo.getsda = savage4_gpio_getsda;
    199		par->chan.algo.getscl = savage4_gpio_getscl;
    200		break;
    201	default:
    202		par->chan.par = NULL;
    203	}
    204
    205	savage_setup_i2c_bus(&par->chan, "SAVAGE DDC2");
    206}
    207
    208void savagefb_delete_i2c_busses(struct fb_info *info)
    209{
    210	struct savagefb_par *par = info->par;
    211
    212	if (par->chan.par)
    213		i2c_del_adapter(&par->chan.adapter);
    214
    215	par->chan.par = NULL;
    216}
    217
    218int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid)
    219{
    220	struct savagefb_par *par = info->par;
    221	u8 *edid;
    222
    223	if (par->chan.par)
    224		edid = fb_ddc_read(&par->chan.adapter);
    225	else
    226		edid = NULL;
    227
    228	if (!edid) {
    229		/* try to get from firmware */
    230		const u8 *e = fb_firmware_edid(info->device);
    231
    232		if (e)
    233			edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
    234	}
    235
    236	*out_edid = edid;
    237
    238	return (edid) ? 0 : 1;
    239}
    240
    241MODULE_LICENSE("GPL");