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

ddbridge-ci.c (9390B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * ddbridge-ci.c: Digital Devices bridge CI (DuoFlex, CI Bridge) support
      4 *
      5 * Copyright (C) 2010-2017 Digital Devices GmbH
      6 *                         Marcus Metzler <mocm@metzlerbros.de>
      7 *                         Ralph Metzler <rjkm@metzlerbros.de>
      8 *
      9 * This program is free software; you can redistribute it and/or
     10 * modify it under the terms of the GNU General Public License
     11 * version 2 only, as published by the Free Software Foundation.
     12 *
     13 * This program is distributed in the hope that it will be useful,
     14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 * GNU General Public License for more details.
     17 */
     18
     19#include "ddbridge.h"
     20#include "ddbridge-regs.h"
     21#include "ddbridge-ci.h"
     22#include "ddbridge-io.h"
     23#include "ddbridge-i2c.h"
     24
     25#include "cxd2099.h"
     26
     27/* Octopus CI internal CI interface */
     28
     29static int wait_ci_ready(struct ddb_ci *ci)
     30{
     31	u32 count = 10;
     32
     33	ndelay(500);
     34	do {
     35		if (ddbreadl(ci->port->dev,
     36			     CI_CONTROL(ci->nr)) & CI_READY)
     37			break;
     38		usleep_range(1, 2);
     39		if ((--count) == 0)
     40			return -1;
     41	} while (1);
     42	return 0;
     43}
     44
     45static int read_attribute_mem(struct dvb_ca_en50221 *ca,
     46			      int slot, int address)
     47{
     48	struct ddb_ci *ci = ca->data;
     49	u32 val, off = (address >> 1) & (CI_BUFFER_SIZE - 1);
     50
     51	if (address > CI_BUFFER_SIZE)
     52		return -1;
     53	ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address,
     54		  CI_DO_READ_ATTRIBUTES(ci->nr));
     55	wait_ci_ready(ci);
     56	val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off);
     57	return val;
     58}
     59
     60static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot,
     61			       int address, u8 value)
     62{
     63	struct ddb_ci *ci = ca->data;
     64
     65	ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
     66		  CI_DO_ATTRIBUTE_RW(ci->nr));
     67	wait_ci_ready(ci);
     68	return 0;
     69}
     70
     71static int read_cam_control(struct dvb_ca_en50221 *ca,
     72			    int slot, u8 address)
     73{
     74	u32 count = 100;
     75	struct ddb_ci *ci = ca->data;
     76	u32 res;
     77
     78	ddbwritel(ci->port->dev, CI_READ_CMD | address,
     79		  CI_DO_IO_RW(ci->nr));
     80	ndelay(500);
     81	do {
     82		res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr));
     83		if (res & CI_READY)
     84			break;
     85		usleep_range(1, 2);
     86		if ((--count) == 0)
     87			return -1;
     88	} while (1);
     89	return 0xff & res;
     90}
     91
     92static int write_cam_control(struct dvb_ca_en50221 *ca, int slot,
     93			     u8 address, u8 value)
     94{
     95	struct ddb_ci *ci = ca->data;
     96
     97	ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address,
     98		  CI_DO_IO_RW(ci->nr));
     99	wait_ci_ready(ci);
    100	return 0;
    101}
    102
    103static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
    104{
    105	struct ddb_ci *ci = ca->data;
    106
    107	ddbwritel(ci->port->dev, CI_POWER_ON,
    108		  CI_CONTROL(ci->nr));
    109	msleep(100);
    110	ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM,
    111		  CI_CONTROL(ci->nr));
    112	ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM,
    113		  CI_CONTROL(ci->nr));
    114	usleep_range(20, 25);
    115	ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON,
    116		  CI_CONTROL(ci->nr));
    117	return 0;
    118}
    119
    120static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
    121{
    122	struct ddb_ci *ci = ca->data;
    123
    124	ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr));
    125	msleep(300);
    126	return 0;
    127}
    128
    129static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
    130{
    131	struct ddb_ci *ci = ca->data;
    132	u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
    133
    134	ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE,
    135		  CI_CONTROL(ci->nr));
    136	return 0;
    137}
    138
    139static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
    140{
    141	struct ddb_ci *ci = ca->data;
    142	u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr));
    143	int stat = 0;
    144
    145	if (val & CI_CAM_DETECT)
    146		stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
    147	if (val & CI_CAM_READY)
    148		stat |= DVB_CA_EN50221_POLL_CAM_READY;
    149	return stat;
    150}
    151
    152static struct dvb_ca_en50221 en_templ = {
    153	.read_attribute_mem  = read_attribute_mem,
    154	.write_attribute_mem = write_attribute_mem,
    155	.read_cam_control    = read_cam_control,
    156	.write_cam_control   = write_cam_control,
    157	.slot_reset          = slot_reset,
    158	.slot_shutdown       = slot_shutdown,
    159	.slot_ts_enable      = slot_ts_enable,
    160	.poll_slot_status    = poll_slot_status,
    161};
    162
    163static void ci_attach(struct ddb_port *port)
    164{
    165	struct ddb_ci *ci;
    166
    167	ci = kzalloc(sizeof(*ci), GFP_KERNEL);
    168	if (!ci)
    169		return;
    170	memcpy(&ci->en, &en_templ, sizeof(en_templ));
    171	ci->en.data = ci;
    172	port->en = &ci->en;
    173	port->en_freedata = 1;
    174	ci->port = port;
    175	ci->nr = port->nr - 2;
    176}
    177
    178/* DuoFlex Dual CI support */
    179
    180static int write_creg(struct ddb_ci *ci, u8 data, u8 mask)
    181{
    182	struct i2c_adapter *i2c = &ci->port->i2c->adap;
    183	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
    184
    185	ci->port->creg = (ci->port->creg & ~mask) | data;
    186	return i2c_write_reg(i2c, adr, 0x02, ci->port->creg);
    187}
    188
    189static int read_attribute_mem_xo2(struct dvb_ca_en50221 *ca,
    190				  int slot, int address)
    191{
    192	struct ddb_ci *ci = ca->data;
    193	struct i2c_adapter *i2c = &ci->port->i2c->adap;
    194	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
    195	int res;
    196	u8 val;
    197
    198	res = i2c_read_reg16(i2c, adr, 0x8000 | address, &val);
    199	return res ? res : val;
    200}
    201
    202static int write_attribute_mem_xo2(struct dvb_ca_en50221 *ca, int slot,
    203				   int address, u8 value)
    204{
    205	struct ddb_ci *ci = ca->data;
    206	struct i2c_adapter *i2c = &ci->port->i2c->adap;
    207	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
    208
    209	return i2c_write_reg16(i2c, adr, 0x8000 | address, value);
    210}
    211
    212static int read_cam_control_xo2(struct dvb_ca_en50221 *ca,
    213				int slot, u8 address)
    214{
    215	struct ddb_ci *ci = ca->data;
    216	struct i2c_adapter *i2c = &ci->port->i2c->adap;
    217	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
    218	u8 val;
    219	int res;
    220
    221	res = i2c_read_reg(i2c, adr, 0x20 | (address & 3), &val);
    222	return res ? res : val;
    223}
    224
    225static int write_cam_control_xo2(struct dvb_ca_en50221 *ca, int slot,
    226				 u8 address, u8 value)
    227{
    228	struct ddb_ci *ci = ca->data;
    229	struct i2c_adapter *i2c = &ci->port->i2c->adap;
    230	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
    231
    232	return i2c_write_reg(i2c, adr, 0x20 | (address & 3), value);
    233}
    234
    235static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot)
    236{
    237	struct ddb_ci *ci = ca->data;
    238
    239	dev_dbg(ci->port->dev->dev, "%s\n", __func__);
    240	write_creg(ci, 0x01, 0x01);
    241	write_creg(ci, 0x04, 0x04);
    242	msleep(20);
    243	write_creg(ci, 0x02, 0x02);
    244	write_creg(ci, 0x00, 0x04);
    245	write_creg(ci, 0x18, 0x18);
    246	return 0;
    247}
    248
    249static int slot_shutdown_xo2(struct dvb_ca_en50221 *ca, int slot)
    250{
    251	struct ddb_ci *ci = ca->data;
    252
    253	dev_dbg(ci->port->dev->dev, "%s\n", __func__);
    254	write_creg(ci, 0x10, 0xff);
    255	write_creg(ci, 0x08, 0x08);
    256	return 0;
    257}
    258
    259static int slot_ts_enable_xo2(struct dvb_ca_en50221 *ca, int slot)
    260{
    261	struct ddb_ci *ci = ca->data;
    262
    263	dev_dbg(ci->port->dev->dev, "%s\n", __func__);
    264	write_creg(ci, 0x00, 0x10);
    265	return 0;
    266}
    267
    268static int poll_slot_status_xo2(struct dvb_ca_en50221 *ca, int slot, int open)
    269{
    270	struct ddb_ci *ci = ca->data;
    271	struct i2c_adapter *i2c = &ci->port->i2c->adap;
    272	u8 adr = (ci->port->type == DDB_CI_EXTERNAL_XO2) ? 0x12 : 0x13;
    273	u8 val = 0;
    274	int stat = 0;
    275
    276	i2c_read_reg(i2c, adr, 0x01, &val);
    277
    278	if (val & 2)
    279		stat |= DVB_CA_EN50221_POLL_CAM_PRESENT;
    280	if (val & 1)
    281		stat |= DVB_CA_EN50221_POLL_CAM_READY;
    282	return stat;
    283}
    284
    285static struct dvb_ca_en50221 en_xo2_templ = {
    286	.read_attribute_mem  = read_attribute_mem_xo2,
    287	.write_attribute_mem = write_attribute_mem_xo2,
    288	.read_cam_control    = read_cam_control_xo2,
    289	.write_cam_control   = write_cam_control_xo2,
    290	.slot_reset          = slot_reset_xo2,
    291	.slot_shutdown       = slot_shutdown_xo2,
    292	.slot_ts_enable      = slot_ts_enable_xo2,
    293	.poll_slot_status    = poll_slot_status_xo2,
    294};
    295
    296static void ci_xo2_attach(struct ddb_port *port)
    297{
    298	struct ddb_ci *ci;
    299
    300	ci = kzalloc(sizeof(*ci), GFP_KERNEL);
    301	if (!ci)
    302		return;
    303	memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ));
    304	ci->en.data = ci;
    305	port->en = &ci->en;
    306	port->en_freedata = 1;
    307	ci->port = port;
    308	ci->nr = port->nr - 2;
    309	ci->port->creg = 0;
    310	write_creg(ci, 0x10, 0xff);
    311	write_creg(ci, 0x08, 0x08);
    312}
    313
    314static const struct cxd2099_cfg cxd_cfgtmpl = {
    315	.bitrate =  72000,
    316	.polarity = 1,
    317	.clock_mode = 1,
    318	.max_i2c = 512,
    319};
    320
    321static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate)
    322{
    323	struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl;
    324	struct i2c_client *client;
    325
    326	cxd_cfg.bitrate = bitrate;
    327	cxd_cfg.en = &port->en;
    328
    329	client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap,
    330				  0x40, &cxd_cfg);
    331	if (!client)
    332		goto err;
    333
    334	port->dvb[0].i2c_client[0] = client;
    335	port->en_freedata = 0;
    336	return 0;
    337
    338err:
    339	dev_err(port->dev->dev, "CXD2099AR attach failed\n");
    340	return -ENODEV;
    341}
    342
    343int ddb_ci_attach(struct ddb_port *port, u32 bitrate)
    344{
    345	int ret;
    346
    347	switch (port->type) {
    348	case DDB_CI_EXTERNAL_SONY:
    349		ret = ci_cxd2099_attach(port, bitrate);
    350		if (ret)
    351			return -ENODEV;
    352		break;
    353	case DDB_CI_EXTERNAL_XO2:
    354	case DDB_CI_EXTERNAL_XO2_B:
    355		ci_xo2_attach(port);
    356		break;
    357	case DDB_CI_INTERNAL:
    358		ci_attach(port);
    359		break;
    360	default:
    361		return -ENODEV;
    362	}
    363
    364	if (!port->en)
    365		return -ENODEV;
    366	dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1);
    367	return 0;
    368}
    369
    370void ddb_ci_detach(struct ddb_port *port)
    371{
    372	if (port->dvb[0].dev)
    373		dvb_unregister_device(port->dvb[0].dev);
    374	if (port->en) {
    375		dvb_ca_en50221_release(port->en);
    376
    377		dvb_module_release(port->dvb[0].i2c_client[0]);
    378		port->dvb[0].i2c_client[0] = NULL;
    379
    380		/* free alloc'ed memory if needed */
    381		if (port->en_freedata)
    382			kfree(port->en->data);
    383
    384		port->en = NULL;
    385	}
    386}