1 /* 2 * Copyright 2008-2014 Freescale Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 * 6 * Based on CAAM driver in drivers/crypto/caam in Linux 7 */ 8 9 #include <common.h> 10 #include <malloc.h> 11 #include "fsl_sec.h" 12 #include "jr.h" 13 14 #define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1)) 15 #define CIRC_SPACE(head, tail, size) CIRC_CNT((tail), (head) + 1, (size)) 16 17 struct jobring jr; 18 19 static inline void start_jr0(void) 20 { 21 ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR; 22 u32 ctpr_ms = sec_in32(&sec->ctpr_ms); 23 u32 scfgr = sec_in32(&sec->scfgr); 24 25 if (ctpr_ms & SEC_CTPR_MS_VIRT_EN_INCL) { 26 /* VIRT_EN_INCL = 1 & VIRT_EN_POR = 1 or 27 * VIRT_EN_INCL = 1 & VIRT_EN_POR = 0 & SEC_SCFGR_VIRT_EN = 1 28 */ 29 if ((ctpr_ms & SEC_CTPR_MS_VIRT_EN_POR) || 30 (!(ctpr_ms & SEC_CTPR_MS_VIRT_EN_POR) && 31 (scfgr & SEC_SCFGR_VIRT_EN))) 32 sec_out32(&sec->jrstartr, CONFIG_JRSTARTR_JR0); 33 } else { 34 /* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */ 35 if (ctpr_ms & SEC_CTPR_MS_VIRT_EN_POR) 36 sec_out32(&sec->jrstartr, CONFIG_JRSTARTR_JR0); 37 } 38 } 39 40 static inline void jr_reset_liodn(void) 41 { 42 ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR; 43 sec_out32(&sec->jrliodnr[0].ls, 0); 44 } 45 46 static inline void jr_disable_irq(void) 47 { 48 struct jr_regs *regs = (struct jr_regs *)CONFIG_SYS_FSL_JR0_ADDR; 49 uint32_t jrcfg = sec_in32(®s->jrcfg1); 50 51 jrcfg = jrcfg | JR_INTMASK; 52 53 sec_out32(®s->jrcfg1, jrcfg); 54 } 55 56 static void jr_initregs(void) 57 { 58 struct jr_regs *regs = (struct jr_regs *)CONFIG_SYS_FSL_JR0_ADDR; 59 phys_addr_t ip_base = virt_to_phys((void *)jr.input_ring); 60 phys_addr_t op_base = virt_to_phys((void *)jr.output_ring); 61 62 #ifdef CONFIG_PHYS_64BIT 63 sec_out32(®s->irba_h, ip_base >> 32); 64 #else 65 sec_out32(®s->irba_h, 0x0); 66 #endif 67 sec_out32(®s->irba_l, (uint32_t)ip_base); 68 #ifdef CONFIG_PHYS_64BIT 69 sec_out32(®s->orba_h, op_base >> 32); 70 #else 71 sec_out32(®s->orba_h, 0x0); 72 #endif 73 sec_out32(®s->orba_l, (uint32_t)op_base); 74 sec_out32(®s->ors, JR_SIZE); 75 sec_out32(®s->irs, JR_SIZE); 76 77 if (!jr.irq) 78 jr_disable_irq(); 79 } 80 81 static int jr_init(void) 82 { 83 memset(&jr, 0, sizeof(struct jobring)); 84 85 jr.jq_id = DEFAULT_JR_ID; 86 jr.irq = DEFAULT_IRQ; 87 88 #ifdef CONFIG_FSL_CORENET 89 jr.liodn = DEFAULT_JR_LIODN; 90 #endif 91 jr.size = JR_SIZE; 92 jr.input_ring = (dma_addr_t *)malloc(JR_SIZE * sizeof(dma_addr_t)); 93 if (!jr.input_ring) 94 return -1; 95 jr.output_ring = 96 (struct op_ring *)malloc(JR_SIZE * sizeof(struct op_ring)); 97 if (!jr.output_ring) 98 return -1; 99 100 memset(jr.input_ring, 0, JR_SIZE * sizeof(dma_addr_t)); 101 memset(jr.output_ring, 0, JR_SIZE * sizeof(struct op_ring)); 102 103 start_jr0(); 104 105 jr_initregs(); 106 107 return 0; 108 } 109 110 static int jr_sw_cleanup(void) 111 { 112 jr.head = 0; 113 jr.tail = 0; 114 jr.read_idx = 0; 115 jr.write_idx = 0; 116 memset(jr.info, 0, sizeof(jr.info)); 117 memset(jr.input_ring, 0, jr.size * sizeof(dma_addr_t)); 118 memset(jr.output_ring, 0, jr.size * sizeof(struct op_ring)); 119 120 return 0; 121 } 122 123 static int jr_hw_reset(void) 124 { 125 struct jr_regs *regs = (struct jr_regs *)CONFIG_SYS_FSL_JR0_ADDR; 126 uint32_t timeout = 100000; 127 uint32_t jrint, jrcr; 128 129 sec_out32(®s->jrcr, JRCR_RESET); 130 do { 131 jrint = sec_in32(®s->jrint); 132 } while (((jrint & JRINT_ERR_HALT_MASK) == 133 JRINT_ERR_HALT_INPROGRESS) && --timeout); 134 135 jrint = sec_in32(®s->jrint); 136 if (((jrint & JRINT_ERR_HALT_MASK) != 137 JRINT_ERR_HALT_INPROGRESS) && timeout == 0) 138 return -1; 139 140 timeout = 100000; 141 sec_out32(®s->jrcr, JRCR_RESET); 142 do { 143 jrcr = sec_in32(®s->jrcr); 144 } while ((jrcr & JRCR_RESET) && --timeout); 145 146 if (timeout == 0) 147 return -1; 148 149 return 0; 150 } 151 152 /* -1 --- error, can't enqueue -- no space available */ 153 static int jr_enqueue(uint32_t *desc_addr, 154 void (*callback)(uint32_t desc, uint32_t status, void *arg), 155 void *arg) 156 { 157 struct jr_regs *regs = (struct jr_regs *)CONFIG_SYS_FSL_JR0_ADDR; 158 int head = jr.head; 159 dma_addr_t desc_phys_addr = virt_to_phys(desc_addr); 160 161 if (sec_in32(®s->irsa) == 0 || 162 CIRC_SPACE(jr.head, jr.tail, jr.size) <= 0) 163 return -1; 164 165 jr.input_ring[head] = desc_phys_addr; 166 jr.info[head].desc_phys_addr = desc_phys_addr; 167 jr.info[head].desc_addr = (uint32_t)desc_addr; 168 jr.info[head].callback = (void *)callback; 169 jr.info[head].arg = arg; 170 jr.info[head].op_done = 0; 171 172 jr.head = (head + 1) & (jr.size - 1); 173 174 sec_out32(®s->irja, 1); 175 176 return 0; 177 } 178 179 static int jr_dequeue(void) 180 { 181 struct jr_regs *regs = (struct jr_regs *)CONFIG_SYS_FSL_JR0_ADDR; 182 int head = jr.head; 183 int tail = jr.tail; 184 int idx, i, found; 185 void (*callback)(uint32_t desc, uint32_t status, void *arg); 186 void *arg = NULL; 187 188 while (sec_in32(®s->orsf) && CIRC_CNT(jr.head, jr.tail, jr.size)) { 189 found = 0; 190 191 dma_addr_t op_desc = jr.output_ring[jr.tail].desc; 192 uint32_t status = jr.output_ring[jr.tail].status; 193 uint32_t desc_virt; 194 195 for (i = 0; CIRC_CNT(head, tail + i, jr.size) >= 1; i++) { 196 idx = (tail + i) & (jr.size - 1); 197 if (op_desc == jr.info[idx].desc_phys_addr) { 198 desc_virt = jr.info[idx].desc_addr; 199 found = 1; 200 break; 201 } 202 } 203 204 /* Error condition if match not found */ 205 if (!found) 206 return -1; 207 208 jr.info[idx].op_done = 1; 209 callback = (void *)jr.info[idx].callback; 210 arg = jr.info[idx].arg; 211 212 /* When the job on tail idx gets done, increment 213 * tail till the point where job completed out of oredr has 214 * been taken into account 215 */ 216 if (idx == tail) 217 do { 218 tail = (tail + 1) & (jr.size - 1); 219 } while (jr.info[tail].op_done); 220 221 jr.tail = tail; 222 jr.read_idx = (jr.read_idx + 1) & (jr.size - 1); 223 224 sec_out32(®s->orjr, 1); 225 jr.info[idx].op_done = 0; 226 227 callback(desc_virt, status, arg); 228 } 229 230 return 0; 231 } 232 233 static void desc_done(uint32_t desc, uint32_t status, void *arg) 234 { 235 struct result *x = arg; 236 x->status = status; 237 caam_jr_strstatus(status); 238 x->done = 1; 239 } 240 241 int run_descriptor_jr(uint32_t *desc) 242 { 243 unsigned long long timeval = get_ticks(); 244 unsigned long long timeout = usec2ticks(CONFIG_SEC_DEQ_TIMEOUT); 245 struct result op; 246 int ret = 0; 247 248 memset(&op, sizeof(op), 0); 249 250 ret = jr_enqueue(desc, desc_done, &op); 251 if (ret) { 252 debug("Error in SEC enq\n"); 253 ret = JQ_ENQ_ERR; 254 goto out; 255 } 256 257 timeval = get_ticks(); 258 timeout = usec2ticks(CONFIG_SEC_DEQ_TIMEOUT); 259 while (op.done != 1) { 260 ret = jr_dequeue(); 261 if (ret) { 262 debug("Error in SEC deq\n"); 263 ret = JQ_DEQ_ERR; 264 goto out; 265 } 266 267 if ((get_ticks() - timeval) > timeout) { 268 debug("SEC Dequeue timed out\n"); 269 ret = JQ_DEQ_TO_ERR; 270 goto out; 271 } 272 } 273 274 if (!op.status) { 275 debug("Error %x\n", op.status); 276 ret = op.status; 277 } 278 out: 279 return ret; 280 } 281 282 int jr_reset(void) 283 { 284 if (jr_hw_reset() < 0) 285 return -1; 286 287 /* Clean up the jobring structure maintained by software */ 288 jr_sw_cleanup(); 289 290 return 0; 291 } 292 293 int sec_reset(void) 294 { 295 ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR; 296 uint32_t mcfgr = sec_in32(&sec->mcfgr); 297 uint32_t timeout = 100000; 298 299 mcfgr |= MCFGR_SWRST; 300 sec_out32(&sec->mcfgr, mcfgr); 301 302 mcfgr |= MCFGR_DMA_RST; 303 sec_out32(&sec->mcfgr, mcfgr); 304 do { 305 mcfgr = sec_in32(&sec->mcfgr); 306 } while ((mcfgr & MCFGR_DMA_RST) == MCFGR_DMA_RST && --timeout); 307 308 if (timeout == 0) 309 return -1; 310 311 timeout = 100000; 312 do { 313 mcfgr = sec_in32(&sec->mcfgr); 314 } while ((mcfgr & MCFGR_SWRST) == MCFGR_SWRST && --timeout); 315 316 if (timeout == 0) 317 return -1; 318 319 return 0; 320 } 321 322 int sec_init(void) 323 { 324 int ret = 0; 325 326 #ifdef CONFIG_PHYS_64BIT 327 ccsr_sec_t *sec = (void *)CONFIG_SYS_FSL_SEC_ADDR; 328 uint32_t mcr = sec_in32(&sec->mcfgr); 329 330 sec_out32(&sec->mcfgr, mcr | 1 << MCFGR_PS_SHIFT); 331 #endif 332 ret = jr_init(); 333 if (ret < 0) 334 return -1; 335 336 return ret; 337 } 338