netup_unidvb_ci.c (7102B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * netup_unidvb_ci.c 4 * 5 * DVB CAM support for NetUP Universal Dual DVB-CI 6 * 7 * Copyright (C) 2014 NetUP Inc. 8 * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru> 9 * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> 10 */ 11 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/moduleparam.h> 15#include <linux/kmod.h> 16#include <linux/kernel.h> 17#include <linux/slab.h> 18#include <linux/interrupt.h> 19#include <linux/delay.h> 20#include "netup_unidvb.h" 21 22/* CI slot 0 base address */ 23#define CAM0_CONFIG 0x0 24#define CAM0_IO 0x8000 25#define CAM0_MEM 0x10000 26#define CAM0_SZ 32 27/* CI slot 1 base address */ 28#define CAM1_CONFIG 0x20000 29#define CAM1_IO 0x28000 30#define CAM1_MEM 0x30000 31#define CAM1_SZ 32 32/* ctrlstat registers */ 33#define CAM_CTRLSTAT_READ_SET 0x4980 34#define CAM_CTRLSTAT_CLR 0x4982 35/* register bits */ 36#define BIT_CAM_STCHG (1<<0) 37#define BIT_CAM_PRESENT (1<<1) 38#define BIT_CAM_RESET (1<<2) 39#define BIT_CAM_BYPASS (1<<3) 40#define BIT_CAM_READY (1<<4) 41#define BIT_CAM_ERROR (1<<5) 42#define BIT_CAM_OVERCURR (1<<6) 43/* BIT_CAM_BYPASS bit shift for SLOT 1 */ 44#define CAM1_SHIFT 8 45 46irqreturn_t netup_ci_interrupt(struct netup_unidvb_dev *ndev) 47{ 48 writew(0x101, ndev->bmmio0 + CAM_CTRLSTAT_CLR); 49 return IRQ_HANDLED; 50} 51 52static int netup_unidvb_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, 53 int slot) 54{ 55 struct netup_ci_state *state = en50221->data; 56 struct netup_unidvb_dev *dev = state->dev; 57 u16 shift = (state->nr == 1) ? CAM1_SHIFT : 0; 58 59 dev_dbg(&dev->pci_dev->dev, "%s(): CAM_CTRLSTAT=0x%x\n", 60 __func__, readw(dev->bmmio0 + CAM_CTRLSTAT_READ_SET)); 61 if (slot != 0) 62 return -EINVAL; 63 /* pass data to CAM module */ 64 writew(BIT_CAM_BYPASS << shift, dev->bmmio0 + CAM_CTRLSTAT_CLR); 65 dev_dbg(&dev->pci_dev->dev, "%s(): CAM_CTRLSTAT=0x%x done\n", 66 __func__, readw(dev->bmmio0 + CAM_CTRLSTAT_READ_SET)); 67 return 0; 68} 69 70static int netup_unidvb_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, 71 int slot) 72{ 73 struct netup_ci_state *state = en50221->data; 74 struct netup_unidvb_dev *dev = state->dev; 75 76 dev_dbg(&dev->pci_dev->dev, "%s()\n", __func__); 77 return 0; 78} 79 80static int netup_unidvb_ci_slot_reset(struct dvb_ca_en50221 *en50221, 81 int slot) 82{ 83 struct netup_ci_state *state = en50221->data; 84 struct netup_unidvb_dev *dev = state->dev; 85 unsigned long timeout = 0; 86 u16 shift = (state->nr == 1) ? CAM1_SHIFT : 0; 87 u16 ci_stat = 0; 88 int reset_counter = 3; 89 90 dev_dbg(&dev->pci_dev->dev, "%s(): CAM_CTRLSTAT_READ_SET=0x%x\n", 91 __func__, readw(dev->bmmio0 + CAM_CTRLSTAT_READ_SET)); 92reset: 93 timeout = jiffies + msecs_to_jiffies(5000); 94 /* start reset */ 95 writew(BIT_CAM_RESET << shift, dev->bmmio0 + CAM_CTRLSTAT_READ_SET); 96 dev_dbg(&dev->pci_dev->dev, "%s(): waiting for reset\n", __func__); 97 /* wait until reset done */ 98 while (time_before(jiffies, timeout)) { 99 ci_stat = readw(dev->bmmio0 + CAM_CTRLSTAT_READ_SET); 100 if (ci_stat & (BIT_CAM_READY << shift)) 101 break; 102 udelay(1000); 103 } 104 if (!(ci_stat & (BIT_CAM_READY << shift)) && reset_counter > 0) { 105 dev_dbg(&dev->pci_dev->dev, 106 "%s(): CAMP reset timeout! Will try again..\n", 107 __func__); 108 reset_counter--; 109 goto reset; 110 } 111 return 0; 112} 113 114static int netup_unidvb_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, 115 int slot, int open) 116{ 117 struct netup_ci_state *state = en50221->data; 118 struct netup_unidvb_dev *dev = state->dev; 119 u16 shift = (state->nr == 1) ? CAM1_SHIFT : 0; 120 u16 ci_stat = 0; 121 122 dev_dbg(&dev->pci_dev->dev, "%s(): CAM_CTRLSTAT_READ_SET=0x%x\n", 123 __func__, readw(dev->bmmio0 + CAM_CTRLSTAT_READ_SET)); 124 ci_stat = readw(dev->bmmio0 + CAM_CTRLSTAT_READ_SET); 125 if (ci_stat & (BIT_CAM_READY << shift)) { 126 state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | 127 DVB_CA_EN50221_POLL_CAM_READY; 128 } else if (ci_stat & (BIT_CAM_PRESENT << shift)) { 129 state->status = DVB_CA_EN50221_POLL_CAM_PRESENT; 130 } else { 131 state->status = 0; 132 } 133 return state->status; 134} 135 136static int netup_unidvb_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, 137 int slot, int addr) 138{ 139 struct netup_ci_state *state = en50221->data; 140 struct netup_unidvb_dev *dev = state->dev; 141 u8 val = *((u8 __force *)state->membase8_config + addr); 142 143 dev_dbg(&dev->pci_dev->dev, 144 "%s(): addr=0x%x val=0x%x\n", __func__, addr, val); 145 return val; 146} 147 148static int netup_unidvb_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, 149 int slot, int addr, u8 data) 150{ 151 struct netup_ci_state *state = en50221->data; 152 struct netup_unidvb_dev *dev = state->dev; 153 154 dev_dbg(&dev->pci_dev->dev, 155 "%s(): addr=0x%x data=0x%x\n", __func__, addr, data); 156 *((u8 __force *)state->membase8_config + addr) = data; 157 return 0; 158} 159 160static int netup_unidvb_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, 161 int slot, u8 addr) 162{ 163 struct netup_ci_state *state = en50221->data; 164 struct netup_unidvb_dev *dev = state->dev; 165 u8 val = *((u8 __force *)state->membase8_io + addr); 166 167 dev_dbg(&dev->pci_dev->dev, 168 "%s(): addr=0x%x val=0x%x\n", __func__, addr, val); 169 return val; 170} 171 172static int netup_unidvb_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, 173 int slot, u8 addr, u8 data) 174{ 175 struct netup_ci_state *state = en50221->data; 176 struct netup_unidvb_dev *dev = state->dev; 177 178 dev_dbg(&dev->pci_dev->dev, 179 "%s(): addr=0x%x data=0x%x\n", __func__, addr, data); 180 *((u8 __force *)state->membase8_io + addr) = data; 181 return 0; 182} 183 184int netup_unidvb_ci_register(struct netup_unidvb_dev *dev, 185 int num, struct pci_dev *pci_dev) 186{ 187 int result; 188 struct netup_ci_state *state; 189 190 if (num < 0 || num > 1) { 191 dev_err(&pci_dev->dev, "%s(): invalid CI adapter %d\n", 192 __func__, num); 193 return -EINVAL; 194 } 195 state = &dev->ci[num]; 196 state->nr = num; 197 state->membase8_config = dev->bmmio1 + 198 ((num == 0) ? CAM0_CONFIG : CAM1_CONFIG); 199 state->membase8_io = dev->bmmio1 + 200 ((num == 0) ? CAM0_IO : CAM1_IO); 201 state->dev = dev; 202 state->ca.owner = THIS_MODULE; 203 state->ca.read_attribute_mem = netup_unidvb_ci_read_attribute_mem; 204 state->ca.write_attribute_mem = netup_unidvb_ci_write_attribute_mem; 205 state->ca.read_cam_control = netup_unidvb_ci_read_cam_ctl; 206 state->ca.write_cam_control = netup_unidvb_ci_write_cam_ctl; 207 state->ca.slot_reset = netup_unidvb_ci_slot_reset; 208 state->ca.slot_shutdown = netup_unidvb_ci_slot_shutdown; 209 state->ca.slot_ts_enable = netup_unidvb_ci_slot_ts_ctl; 210 state->ca.poll_slot_status = netup_unidvb_poll_ci_slot_status; 211 state->ca.data = state; 212 result = dvb_ca_en50221_init(&dev->frontends[num].adapter, 213 &state->ca, 0, 1); 214 if (result < 0) { 215 dev_err(&pci_dev->dev, 216 "%s(): dvb_ca_en50221_init result %d\n", 217 __func__, result); 218 return result; 219 } 220 writew(NETUP_UNIDVB_IRQ_CI, dev->bmmio0 + REG_IMASK_SET); 221 dev_info(&pci_dev->dev, 222 "%s(): CI adapter %d init done\n", __func__, num); 223 return 0; 224} 225 226void netup_unidvb_ci_unregister(struct netup_unidvb_dev *dev, int num) 227{ 228 struct netup_ci_state *state; 229 230 dev_dbg(&dev->pci_dev->dev, "%s()\n", __func__); 231 if (num < 0 || num > 1) { 232 dev_err(&dev->pci_dev->dev, "%s(): invalid CI adapter %d\n", 233 __func__, num); 234 return; 235 } 236 state = &dev->ci[num]; 237 dvb_ca_en50221_release(&state->ca); 238} 239