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-matroxfb.c (6408B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
      5 *
      6 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
      7 *
      8 * Version: 1.64 2002/06/10
      9 *
     10 * See matroxfb_base.c for contributors.
     11 *
     12 */
     13
     14#include "matroxfb_base.h"
     15#include "matroxfb_maven.h"
     16#include <linux/i2c.h>
     17#include <linux/slab.h>
     18#include <linux/i2c-algo-bit.h>
     19
     20/* MGA-TVO I2C for G200, G400 */
     21#define MAT_CLK		0x20
     22#define MAT_DATA	0x10
     23/* primary head DDC for Mystique(?), G100, G200, G400 */
     24#define DDC1_CLK	0x08
     25#define DDC1_DATA	0x02
     26/* primary head DDC for Millennium, Millennium II */
     27#define DDC1B_CLK	0x10
     28#define DDC1B_DATA	0x04
     29/* secondary head DDC for G400 */
     30#define DDC2_CLK	0x04
     31#define DDC2_DATA	0x01
     32
     33/******************************************************/
     34
     35struct matroxfb_dh_maven_info {
     36	struct i2c_bit_adapter	maven;
     37	struct i2c_bit_adapter	ddc1;
     38	struct i2c_bit_adapter	ddc2;
     39};
     40
     41static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
     42	unsigned long flags;
     43	int v;
     44
     45	matroxfb_DAC_lock_irqsave(flags);
     46	v = matroxfb_DAC_in(minfo, DAC_XGENIODATA);
     47	matroxfb_DAC_unlock_irqrestore(flags);
     48	return v;
     49}
     50
     51static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
     52	unsigned long flags;
     53	int v;
     54
     55	matroxfb_DAC_lock_irqsave(flags);
     56	v = (matroxfb_DAC_in(minfo, DAC_XGENIOCTRL) & mask) | val;
     57	matroxfb_DAC_out(minfo, DAC_XGENIOCTRL, v);
     58	/* We must reset GENIODATA very often... XFree plays with this register */
     59	matroxfb_DAC_out(minfo, DAC_XGENIODATA, 0x00);
     60	matroxfb_DAC_unlock_irqrestore(flags);
     61}
     62
     63/* software I2C functions */
     64static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
     65	if (state)
     66		state = 0;
     67	else
     68		state = mask;
     69	matroxfb_set_gpio(minfo, ~mask, state);
     70}
     71
     72static void matroxfb_gpio_setsda(void* data, int state) {
     73	struct i2c_bit_adapter* b = data;
     74	matroxfb_i2c_set(b->minfo, b->mask.data, state);
     75}
     76
     77static void matroxfb_gpio_setscl(void* data, int state) {
     78	struct i2c_bit_adapter* b = data;
     79	matroxfb_i2c_set(b->minfo, b->mask.clock, state);
     80}
     81
     82static int matroxfb_gpio_getsda(void* data) {
     83	struct i2c_bit_adapter* b = data;
     84	return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
     85}
     86
     87static int matroxfb_gpio_getscl(void* data) {
     88	struct i2c_bit_adapter* b = data;
     89	return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
     90}
     91
     92static const struct i2c_algo_bit_data matrox_i2c_algo_template =
     93{
     94	.setsda		= matroxfb_gpio_setsda,
     95	.setscl		= matroxfb_gpio_setscl,
     96	.getsda		= matroxfb_gpio_getsda,
     97	.getscl		= matroxfb_gpio_getscl,
     98	.udelay		= 10,
     99	.timeout	= 100,
    100};
    101
    102static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, 
    103		unsigned int data, unsigned int clock, const char *name,
    104		int class)
    105{
    106	int err;
    107
    108	b->minfo = minfo;
    109	b->mask.data = data;
    110	b->mask.clock = clock;
    111	b->adapter.owner = THIS_MODULE;
    112	snprintf(b->adapter.name, sizeof(b->adapter.name), name,
    113		minfo->fbcon.node);
    114	i2c_set_adapdata(&b->adapter, b);
    115	b->adapter.class = class;
    116	b->adapter.algo_data = &b->bac;
    117	b->adapter.dev.parent = &minfo->pcidev->dev;
    118	b->bac = matrox_i2c_algo_template;
    119	b->bac.data = b;
    120	err = i2c_bit_add_bus(&b->adapter);
    121	b->initialized = !err;
    122	return err;
    123}
    124
    125static void i2c_bit_bus_del(struct i2c_bit_adapter* b) {
    126	if (b->initialized) {
    127		i2c_del_adapter(&b->adapter);
    128		b->initialized = 0;
    129	}
    130}
    131
    132static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
    133	i2c_bit_bus_del(&minfo2->maven);
    134}
    135
    136static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
    137	i2c_bit_bus_del(&minfo2->ddc1);
    138}
    139
    140static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
    141	i2c_bit_bus_del(&minfo2->ddc2);
    142}
    143
    144static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
    145	int err;
    146	unsigned long flags;
    147	struct matroxfb_dh_maven_info* m2info;
    148
    149	m2info = kzalloc(sizeof(*m2info), GFP_KERNEL);
    150	if (!m2info)
    151		return NULL;
    152
    153	matroxfb_DAC_lock_irqsave(flags);
    154	matroxfb_DAC_out(minfo, DAC_XGENIODATA, 0xFF);
    155	matroxfb_DAC_out(minfo, DAC_XGENIOCTRL, 0x00);
    156	matroxfb_DAC_unlock_irqrestore(flags);
    157
    158	switch (minfo->chip) {
    159		case MGA_2064:
    160		case MGA_2164:
    161			err = i2c_bus_reg(&m2info->ddc1, minfo,
    162					  DDC1B_DATA, DDC1B_CLK,
    163					  "DDC:fb%u #0", I2C_CLASS_DDC);
    164			break;
    165		default:
    166			err = i2c_bus_reg(&m2info->ddc1, minfo,
    167					  DDC1_DATA, DDC1_CLK,
    168					  "DDC:fb%u #0", I2C_CLASS_DDC);
    169			break;
    170	}
    171	if (err)
    172		goto fail_ddc1;
    173	if (minfo->devflags.dualhead) {
    174		err = i2c_bus_reg(&m2info->ddc2, minfo,
    175				  DDC2_DATA, DDC2_CLK,
    176				  "DDC:fb%u #1", I2C_CLASS_DDC);
    177		if (err == -ENODEV) {
    178			printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
    179		} else if (err)
    180			printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
    181		/* Register maven bus even on G450/G550 */
    182		err = i2c_bus_reg(&m2info->maven, minfo,
    183				  MAT_DATA, MAT_CLK, "MAVEN:fb%u", 0);
    184		if (err)
    185			printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
    186		else {
    187			struct i2c_board_info maven_info = {
    188				I2C_BOARD_INFO("maven", 0x1b),
    189			};
    190			unsigned short const addr_list[2] = {
    191				0x1b, I2C_CLIENT_END
    192			};
    193
    194			i2c_new_scanned_device(&m2info->maven.adapter,
    195					       &maven_info, addr_list, NULL);
    196		}
    197	}
    198	return m2info;
    199fail_ddc1:;
    200	kfree(m2info);
    201	printk(KERN_ERR "i2c-matroxfb: Could not register primary adapter DDC bus.\n");
    202	return NULL;
    203}
    204
    205static void i2c_matroxfb_remove(struct matrox_fb_info* minfo, void* data) {
    206	struct matroxfb_dh_maven_info* m2info = data;
    207
    208	i2c_maven_done(m2info);
    209	i2c_ddc2_done(m2info);
    210	i2c_ddc1_done(m2info);
    211	kfree(m2info);
    212}
    213
    214static struct matroxfb_driver i2c_matroxfb = {
    215	.node =		LIST_HEAD_INIT(i2c_matroxfb.node),
    216	.name =		"i2c-matroxfb",
    217	.probe = 	i2c_matroxfb_probe,
    218	.remove =	i2c_matroxfb_remove,
    219};
    220
    221static int __init i2c_matroxfb_init(void) {
    222	if (matroxfb_register_driver(&i2c_matroxfb)) {
    223		printk(KERN_ERR "i2c-matroxfb: failed to register driver\n");
    224		return -ENXIO;
    225	}
    226	return 0;
    227}
    228
    229static void __exit i2c_matroxfb_exit(void) {
    230	matroxfb_unregister_driver(&i2c_matroxfb);
    231}
    232
    233MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
    234MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
    235
    236module_init(i2c_matroxfb_init);
    237module_exit(i2c_matroxfb_exit);
    238/* no __setup required */
    239MODULE_LICENSE("GPL");