1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ddbridge-mci.c: Digital Devices microcode interface 4 * 5 * Copyright (C) 2017-2018 Digital Devices GmbH 6 * Ralph Metzler <rjkm@metzlerbros.de> 7 * Marcus Metzler <mocm@metzlerbros.de> 8 */ 9 10 #include "ddbridge.h" 11 #include "ddbridge-io.h" 12 #include "ddbridge-mci.h" 13 14 static LIST_HEAD(mci_list); 15 16 static int mci_reset(struct mci *state) 17 { 18 struct ddb_link *link = state->base->link; 19 u32 status = 0; 20 u32 timeout = 40; 21 22 ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL); 23 ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */ 24 msleep(300); 25 ddblwritel(link, 0, MCI_CONTROL); 26 27 while (1) { 28 status = ddblreadl(link, MCI_CONTROL); 29 if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY) 30 break; 31 if (--timeout == 0) 32 break; 33 msleep(50); 34 } 35 if ((status & MCI_CONTROL_READY) == 0) 36 return -1; 37 if (link->ids.device == 0x0009) 38 ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG); 39 return 0; 40 } 41 42 int ddb_mci_config(struct mci *state, u32 config) 43 { 44 struct ddb_link *link = state->base->link; 45 46 if (link->ids.device != 0x0009) 47 return -EINVAL; 48 ddblwritel(link, config, SX8_TSCONFIG); 49 return 0; 50 } 51 52 static int _mci_cmd_unlocked(struct mci *state, 53 u32 *cmd, u32 cmd_len, 54 u32 *res, u32 res_len) 55 { 56 struct ddb_link *link = state->base->link; 57 u32 i, val; 58 unsigned long stat; 59 60 val = ddblreadl(link, MCI_CONTROL); 61 if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND)) 62 return -EIO; 63 if (cmd && cmd_len) 64 for (i = 0; i < cmd_len; i++) 65 ddblwritel(link, cmd[i], MCI_COMMAND + i * 4); 66 val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT); 67 ddblwritel(link, val, MCI_CONTROL); 68 69 stat = wait_for_completion_timeout(&state->base->completion, HZ); 70 if (stat == 0) { 71 dev_warn(state->base->dev, "MCI-%d: MCI timeout\n", state->nr); 72 return -EIO; 73 } 74 if (res && res_len) 75 for (i = 0; i < res_len; i++) 76 res[i] = ddblreadl(link, MCI_RESULT + i * 4); 77 return 0; 78 } 79 80 int ddb_mci_cmd(struct mci *state, 81 struct mci_command *command, 82 struct mci_result *result) 83 { 84 int stat; 85 86 mutex_lock(&state->base->mci_lock); 87 stat = _mci_cmd_unlocked(state, 88 (u32 *)command, sizeof(*command) / sizeof(u32), 89 (u32 *)result, sizeof(*result) / sizeof(u32)); 90 mutex_unlock(&state->base->mci_lock); 91 return stat; 92 } 93 94 static void mci_handler(void *priv) 95 { 96 struct mci_base *base = (struct mci_base *)priv; 97 98 complete(&base->completion); 99 } 100 101 static struct mci_base *match_base(void *key) 102 { 103 struct mci_base *p; 104 105 list_for_each_entry(p, &mci_list, mci_list) 106 if (p->key == key) 107 return p; 108 return NULL; 109 } 110 111 static int probe(struct mci *state) 112 { 113 mci_reset(state); 114 return 0; 115 } 116 117 struct dvb_frontend 118 *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, 119 int (**fn_set_input)(struct dvb_frontend *fe, int input)) 120 { 121 struct ddb_port *port = input->port; 122 struct ddb *dev = port->dev; 123 struct ddb_link *link = &dev->link[port->lnr]; 124 struct mci_base *base; 125 struct mci *state; 126 void *key = cfg->type ? (void *)port : (void *)link; 127 128 state = kzalloc(cfg->state_size, GFP_KERNEL); 129 if (!state) 130 return NULL; 131 132 base = match_base(key); 133 if (base) { 134 base->count++; 135 state->base = base; 136 } else { 137 base = kzalloc(cfg->base_size, GFP_KERNEL); 138 if (!base) 139 goto fail; 140 base->key = key; 141 base->count = 1; 142 base->link = link; 143 base->dev = dev->dev; 144 mutex_init(&base->mci_lock); 145 mutex_init(&base->tuner_lock); 146 ddb_irq_set(dev, link->nr, 0, mci_handler, base); 147 init_completion(&base->completion); 148 state->base = base; 149 if (probe(state) < 0) { 150 kfree(base); 151 goto fail; 152 } 153 list_add(&base->mci_list, &mci_list); 154 if (cfg->base_init) 155 cfg->base_init(base); 156 } 157 memcpy(&state->fe.ops, cfg->fe_ops, sizeof(struct dvb_frontend_ops)); 158 state->fe.demodulator_priv = state; 159 state->nr = nr; 160 *fn_set_input = cfg->set_input; 161 state->tuner = nr; 162 state->demod = nr; 163 if (cfg->init) 164 cfg->init(state); 165 return &state->fe; 166 fail: 167 kfree(state); 168 return NULL; 169 } 170