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

sp2.c (8984B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver
      4 *
      5 * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi>
      6 *
      7 * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual
      8 * DVB-S2 CI card (cimax2) with following copyrights:
      9 *
     10 *  Copyright (C) 2009 NetUP Inc.
     11 *  Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
     12 *  Copyright (C) 2009 Abylay Ospan <aospan@netup.ru>
     13 */
     14
     15#include "sp2_priv.h"
     16
     17static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
     18{
     19	int ret;
     20	struct i2c_client *client = s->client;
     21	struct i2c_adapter *adap = client->adapter;
     22	struct i2c_msg msg[] = {
     23		{
     24			.addr = client->addr,
     25			.flags = 0,
     26			.buf = &reg,
     27			.len = 1
     28		}, {
     29			.addr = client->addr,
     30			.flags	= I2C_M_RD,
     31			.buf = buf,
     32			.len = len
     33		}
     34	};
     35
     36	ret = i2c_transfer(adap, msg, 2);
     37
     38	if (ret != 2) {
     39		dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n",
     40				reg, ret);
     41		if (ret < 0)
     42			return ret;
     43		else
     44			return -EIO;
     45	}
     46
     47	dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n",
     48				client->addr, reg, buf[0]);
     49
     50	return 0;
     51}
     52
     53static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
     54{
     55	int ret;
     56	u8 buffer[35];
     57	struct i2c_client *client = s->client;
     58	struct i2c_adapter *adap = client->adapter;
     59	struct i2c_msg msg = {
     60		.addr = client->addr,
     61		.flags = 0,
     62		.buf = &buffer[0],
     63		.len = len + 1
     64	};
     65
     66	if ((len + 1) > sizeof(buffer)) {
     67		dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n",
     68				reg, len);
     69		return -EINVAL;
     70	}
     71
     72	buffer[0] = reg;
     73	memcpy(&buffer[1], buf, len);
     74
     75	ret = i2c_transfer(adap, &msg, 1);
     76
     77	if (ret != 1) {
     78		dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n",
     79				reg, ret);
     80		if (ret < 0)
     81			return ret;
     82		else
     83			return -EIO;
     84	}
     85
     86	dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %*ph\n",
     87				client->addr, reg, len, buf);
     88
     89	return 0;
     90}
     91
     92static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
     93			u8 read, int addr, u8 data)
     94{
     95	struct sp2 *s = en50221->data;
     96	u8 store;
     97	int mem, ret;
     98	int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control;
     99
    100	if (slot != 0)
    101		return -EINVAL;
    102
    103	/*
    104	 * change module access type between IO space and attribute memory
    105	 * when needed
    106	 */
    107	if (s->module_access_type != acs) {
    108		ret = sp2_read_i2c(s, 0x00, &store, 1);
    109
    110		if (ret)
    111			return ret;
    112
    113		store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0);
    114		store |= acs;
    115
    116		ret = sp2_write_i2c(s, 0x00, &store, 1);
    117		if (ret)
    118			return ret;
    119	}
    120
    121	s->module_access_type = acs;
    122
    123	/* implementation of ci_op_cam is device specific */
    124	if (ci_op_cam) {
    125		ret = ci_op_cam(s->priv, read, addr, data, &mem);
    126	} else {
    127		dev_err(&s->client->dev, "callback not defined");
    128		return -EINVAL;
    129	}
    130
    131	if (ret)
    132		return ret;
    133
    134	dev_dbg(&s->client->dev, "%s: slot=%d, addr=0x%04x, %s, data=%x",
    135			(read) ? "read" : "write", slot, addr,
    136			(acs == SP2_CI_ATTR_ACS) ? "attr" : "io",
    137			(read) ? mem : data);
    138
    139	if (read)
    140		return mem;
    141	else
    142		return 0;
    143
    144}
    145
    146int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
    147				int slot, int addr)
    148{
    149	return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
    150			SP2_CI_RD, addr, 0);
    151}
    152
    153int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221,
    154				int slot, int addr, u8 data)
    155{
    156	return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS,
    157			SP2_CI_WR, addr, data);
    158}
    159
    160int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221,
    161				int slot, u8 addr)
    162{
    163	return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
    164			SP2_CI_RD, addr, 0);
    165}
    166
    167int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221,
    168				int slot, u8 addr, u8 data)
    169{
    170	return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS,
    171			SP2_CI_WR, addr, data);
    172}
    173
    174int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot)
    175{
    176	struct sp2 *s = en50221->data;
    177	u8 buf;
    178	int ret;
    179
    180	dev_dbg(&s->client->dev, "slot: %d\n", slot);
    181
    182	if (slot != 0)
    183		return -EINVAL;
    184
    185	/* RST on */
    186	buf = SP2_MOD_CTL_RST;
    187	ret = sp2_write_i2c(s, 0x00, &buf, 1);
    188
    189	if (ret)
    190		return ret;
    191
    192	usleep_range(500, 600);
    193
    194	/* RST off */
    195	buf = 0x00;
    196	ret = sp2_write_i2c(s, 0x00, &buf, 1);
    197
    198	if (ret)
    199		return ret;
    200
    201	msleep(1000);
    202
    203	return 0;
    204}
    205
    206int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot)
    207{
    208	struct sp2 *s = en50221->data;
    209
    210	dev_dbg(&s->client->dev, "slot:%d\n", slot);
    211
    212	/* not implemented */
    213	return 0;
    214}
    215
    216int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot)
    217{
    218	struct sp2 *s = en50221->data;
    219	u8 buf;
    220
    221	dev_dbg(&s->client->dev, "slot:%d\n", slot);
    222
    223	if (slot != 0)
    224		return -EINVAL;
    225
    226	sp2_read_i2c(s, 0x00, &buf, 1);
    227
    228	/* disable bypass and enable TS */
    229	buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN);
    230	return sp2_write_i2c(s, 0, &buf, 1);
    231}
    232
    233int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221,
    234				int slot, int open)
    235{
    236	struct sp2 *s = en50221->data;
    237	u8 buf[2];
    238	int ret;
    239
    240	dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open);
    241
    242	/*
    243	 * CAM module INSERT/REMOVE processing. Slow operation because of i2c
    244	 * transfers. Throttle read to one per sec.
    245	 */
    246	if (time_after(jiffies, s->next_status_checked_time)) {
    247		ret = sp2_read_i2c(s, 0x00, buf, 1);
    248		s->next_status_checked_time = jiffies +	msecs_to_jiffies(1000);
    249
    250		if (ret)
    251			return 0;
    252
    253		if (buf[0] & SP2_MOD_CTL_DET)
    254			s->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
    255					DVB_CA_EN50221_POLL_CAM_READY;
    256		else
    257			s->status = 0;
    258	}
    259
    260	return s->status;
    261}
    262
    263static int sp2_init(struct sp2 *s)
    264{
    265	int ret = 0;
    266	u8 buf;
    267	u8 cimax_init[34] = {
    268		0x00, /* module A control*/
    269		0x00, /* auto select mask high A */
    270		0x00, /* auto select mask low A */
    271		0x00, /* auto select pattern high A */
    272		0x00, /* auto select pattern low A */
    273		0x44, /* memory access time A, 600 ns */
    274		0x00, /* invert input A */
    275		0x00, /* RFU */
    276		0x00, /* RFU */
    277		0x00, /* module B control*/
    278		0x00, /* auto select mask high B */
    279		0x00, /* auto select mask low B */
    280		0x00, /* auto select pattern high B */
    281		0x00, /* auto select pattern low B */
    282		0x44, /* memory access time B, 600 ns */
    283		0x00, /* invert input B */
    284		0x00, /* RFU */
    285		0x00, /* RFU */
    286		0x00, /* auto select mask high Ext */
    287		0x00, /* auto select mask low Ext */
    288		0x00, /* auto select pattern high Ext */
    289		0x00, /* auto select pattern low Ext */
    290		0x00, /* RFU */
    291		0x02, /* destination - module A */
    292		0x01, /* power control reg, VCC power on */
    293		0x00, /* RFU */
    294		0x00, /* int status read only */
    295		0x00, /* Interrupt Mask Register */
    296		0x05, /* EXTINT=active-high, INT=push-pull */
    297		0x00, /* USCG1 */
    298		0x04, /* ack active low */
    299		0x00, /* LOCK = 0 */
    300		0x22, /* unknown */
    301		0x00, /* synchronization? */
    302	};
    303
    304	dev_dbg(&s->client->dev, "\n");
    305
    306	s->ca.owner = THIS_MODULE;
    307	s->ca.read_attribute_mem = sp2_ci_read_attribute_mem;
    308	s->ca.write_attribute_mem = sp2_ci_write_attribute_mem;
    309	s->ca.read_cam_control = sp2_ci_read_cam_control;
    310	s->ca.write_cam_control = sp2_ci_write_cam_control;
    311	s->ca.slot_reset = sp2_ci_slot_reset;
    312	s->ca.slot_shutdown = sp2_ci_slot_shutdown;
    313	s->ca.slot_ts_enable = sp2_ci_slot_ts_enable;
    314	s->ca.poll_slot_status = sp2_ci_poll_slot_status;
    315	s->ca.data = s;
    316	s->module_access_type = 0;
    317
    318	/* initialize all regs */
    319	ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34);
    320	if (ret)
    321		goto err;
    322
    323	/* lock registers */
    324	buf = 1;
    325	ret = sp2_write_i2c(s, 0x1f, &buf, 1);
    326	if (ret)
    327		goto err;
    328
    329	/* power on slots */
    330	ret = sp2_write_i2c(s, 0x18, &buf, 1);
    331	if (ret)
    332		goto err;
    333
    334	ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1);
    335	if (ret)
    336		goto err;
    337
    338	return 0;
    339
    340err:
    341	dev_dbg(&s->client->dev, "init failed=%d\n", ret);
    342	return ret;
    343}
    344
    345static int sp2_exit(struct i2c_client *client)
    346{
    347	struct sp2 *s;
    348
    349	dev_dbg(&client->dev, "\n");
    350
    351	if (!client)
    352		return 0;
    353
    354	s = i2c_get_clientdata(client);
    355	if (!s)
    356		return 0;
    357
    358	if (!s->ca.data)
    359		return 0;
    360
    361	dvb_ca_en50221_release(&s->ca);
    362
    363	return 0;
    364}
    365
    366static int sp2_probe(struct i2c_client *client,
    367		const struct i2c_device_id *id)
    368{
    369	struct sp2_config *cfg = client->dev.platform_data;
    370	struct sp2 *s;
    371	int ret;
    372
    373	dev_dbg(&client->dev, "\n");
    374
    375	s = kzalloc(sizeof(*s), GFP_KERNEL);
    376	if (!s) {
    377		ret = -ENOMEM;
    378		goto err;
    379	}
    380
    381	s->client = client;
    382	s->dvb_adap = cfg->dvb_adap;
    383	s->priv = cfg->priv;
    384	s->ci_control = cfg->ci_control;
    385
    386	i2c_set_clientdata(client, s);
    387
    388	ret = sp2_init(s);
    389	if (ret)
    390		goto err;
    391
    392	dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n");
    393	return 0;
    394err:
    395	dev_dbg(&client->dev, "init failed=%d\n", ret);
    396	kfree(s);
    397
    398	return ret;
    399}
    400
    401static int sp2_remove(struct i2c_client *client)
    402{
    403	struct sp2 *s = i2c_get_clientdata(client);
    404
    405	dev_dbg(&client->dev, "\n");
    406	sp2_exit(client);
    407	kfree(s);
    408	return 0;
    409}
    410
    411static const struct i2c_device_id sp2_id[] = {
    412	{"sp2", 0},
    413	{}
    414};
    415MODULE_DEVICE_TABLE(i2c, sp2_id);
    416
    417static struct i2c_driver sp2_driver = {
    418	.driver = {
    419		.name	= "sp2",
    420	},
    421	.probe		= sp2_probe,
    422	.remove		= sp2_remove,
    423	.id_table	= sp2_id,
    424};
    425
    426module_i2c_driver(sp2_driver);
    427
    428MODULE_DESCRIPTION("CIMaX SP2/HF CI driver");
    429MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>");
    430MODULE_LICENSE("GPL");