0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 #include <linux/module.h>
0042 #include <linux/kernel.h>
0043 #include <linux/delay.h>
0044
0045 #include "hermes.h"
0046
0047
0048 #define CMD_BUSY_TIMEOUT (100)
0049 #define CMD_INIT_TIMEOUT (50000)
0050 #define CMD_COMPL_TIMEOUT (20000)
0051 #define ALLOC_COMPL_TIMEOUT (1000)
0052
0053
0054
0055
0056
0057
0058 #define HERMES_AUX_ENABLE 0x8000
0059 #define HERMES_AUX_DISABLE 0x4000
0060 #define HERMES_AUX_ENABLED 0xC000
0061 #define HERMES_AUX_DISABLED 0x0000
0062
0063 #define HERMES_AUX_PW0 0xFE01
0064 #define HERMES_AUX_PW1 0xDC23
0065 #define HERMES_AUX_PW2 0xBA45
0066
0067
0068 #define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
0069 #define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
0070 #define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
0071 #define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
0072
0073
0074
0075
0076
0077 #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
0078 printk(stuff); } while (0)
0079
0080 #undef HERMES_DEBUG
0081 #ifdef HERMES_DEBUG
0082
0083 #define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff)
0084
0085 #else
0086
0087 #define DEBUG(lvl, stuff...) do { } while (0)
0088
0089 #endif
0090
0091 static const struct hermes_ops hermes_ops_local;
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0,
0105 u16 param1, u16 param2)
0106 {
0107 int k = CMD_BUSY_TIMEOUT;
0108 u16 reg;
0109
0110
0111 reg = hermes_read_regn(hw, CMD);
0112 while ((reg & HERMES_CMD_BUSY) && k) {
0113 k--;
0114 udelay(1);
0115 reg = hermes_read_regn(hw, CMD);
0116 }
0117 if (reg & HERMES_CMD_BUSY)
0118 return -EBUSY;
0119
0120 hermes_write_regn(hw, PARAM2, param2);
0121 hermes_write_regn(hw, PARAM1, param1);
0122 hermes_write_regn(hw, PARAM0, param0);
0123 hermes_write_regn(hw, CMD, cmd);
0124
0125 return 0;
0126 }
0127
0128
0129
0130
0131
0132
0133 static int hermes_doicmd_wait(struct hermes *hw, u16 cmd,
0134 u16 parm0, u16 parm1, u16 parm2,
0135 struct hermes_response *resp)
0136 {
0137 int err = 0;
0138 int k;
0139 u16 status, reg;
0140
0141 err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
0142 if (err)
0143 return err;
0144
0145 reg = hermes_read_regn(hw, EVSTAT);
0146 k = CMD_INIT_TIMEOUT;
0147 while ((!(reg & HERMES_EV_CMD)) && k) {
0148 k--;
0149 udelay(10);
0150 reg = hermes_read_regn(hw, EVSTAT);
0151 }
0152
0153 hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
0154
0155 if (!hermes_present(hw)) {
0156 DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
0157 hw->iobase);
0158 err = -ENODEV;
0159 goto out;
0160 }
0161
0162 if (!(reg & HERMES_EV_CMD)) {
0163 printk(KERN_ERR "hermes @ %p: "
0164 "Timeout waiting for card to reset (reg=0x%04x)!\n",
0165 hw->iobase, reg);
0166 err = -ETIMEDOUT;
0167 goto out;
0168 }
0169
0170 status = hermes_read_regn(hw, STATUS);
0171 if (resp) {
0172 resp->status = status;
0173 resp->resp0 = hermes_read_regn(hw, RESP0);
0174 resp->resp1 = hermes_read_regn(hw, RESP1);
0175 resp->resp2 = hermes_read_regn(hw, RESP2);
0176 }
0177
0178 hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
0179
0180 if (status & HERMES_STATUS_RESULT)
0181 err = -EIO;
0182 out:
0183 return err;
0184 }
0185
0186 void hermes_struct_init(struct hermes *hw, void __iomem *address,
0187 int reg_spacing)
0188 {
0189 hw->iobase = address;
0190 hw->reg_spacing = reg_spacing;
0191 hw->inten = 0x0;
0192 hw->eeprom_pda = false;
0193 hw->ops = &hermes_ops_local;
0194 }
0195 EXPORT_SYMBOL(hermes_struct_init);
0196
0197 static int hermes_init(struct hermes *hw)
0198 {
0199 u16 reg;
0200 int err = 0;
0201 int k;
0202
0203
0204 hw->inten = 0x0;
0205 hermes_write_regn(hw, INTEN, 0);
0206 hermes_write_regn(hw, EVACK, 0xffff);
0207
0208
0209
0210
0211
0212
0213
0214 k = CMD_BUSY_TIMEOUT;
0215 reg = hermes_read_regn(hw, CMD);
0216 while (k && (reg & HERMES_CMD_BUSY)) {
0217 if (reg == 0xffff)
0218
0219 return -ENODEV;
0220
0221 k--;
0222 udelay(1);
0223 reg = hermes_read_regn(hw, CMD);
0224 }
0225
0226
0227
0228
0229
0230
0231
0232 reg = hermes_read_regn(hw, EVSTAT);
0233 hermes_write_regn(hw, EVACK, reg);
0234
0235
0236
0237 err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
0238
0239 return err;
0240 }
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251 static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
0252 struct hermes_response *resp)
0253 {
0254 int err;
0255 int k;
0256 u16 reg;
0257 u16 status;
0258
0259 err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
0260 if (err) {
0261 if (!hermes_present(hw)) {
0262 if (net_ratelimit())
0263 printk(KERN_WARNING "hermes @ %p: "
0264 "Card removed while issuing command "
0265 "0x%04x.\n", hw->iobase, cmd);
0266 err = -ENODEV;
0267 } else
0268 if (net_ratelimit())
0269 printk(KERN_ERR "hermes @ %p: "
0270 "Error %d issuing command 0x%04x.\n",
0271 hw->iobase, err, cmd);
0272 goto out;
0273 }
0274
0275 reg = hermes_read_regn(hw, EVSTAT);
0276 k = CMD_COMPL_TIMEOUT;
0277 while ((!(reg & HERMES_EV_CMD)) && k) {
0278 k--;
0279 udelay(10);
0280 reg = hermes_read_regn(hw, EVSTAT);
0281 }
0282
0283 if (!hermes_present(hw)) {
0284 printk(KERN_WARNING "hermes @ %p: Card removed "
0285 "while waiting for command 0x%04x completion.\n",
0286 hw->iobase, cmd);
0287 err = -ENODEV;
0288 goto out;
0289 }
0290
0291 if (!(reg & HERMES_EV_CMD)) {
0292 printk(KERN_ERR "hermes @ %p: Timeout waiting for "
0293 "command 0x%04x completion.\n", hw->iobase, cmd);
0294 err = -ETIMEDOUT;
0295 goto out;
0296 }
0297
0298 status = hermes_read_regn(hw, STATUS);
0299 if (resp) {
0300 resp->status = status;
0301 resp->resp0 = hermes_read_regn(hw, RESP0);
0302 resp->resp1 = hermes_read_regn(hw, RESP1);
0303 resp->resp2 = hermes_read_regn(hw, RESP2);
0304 }
0305
0306 hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
0307
0308 if (status & HERMES_STATUS_RESULT)
0309 err = -EIO;
0310
0311 out:
0312 return err;
0313 }
0314
0315 static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid)
0316 {
0317 int err = 0;
0318 int k;
0319 u16 reg;
0320
0321 if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))
0322 return -EINVAL;
0323
0324 err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
0325 if (err)
0326 return err;
0327
0328 reg = hermes_read_regn(hw, EVSTAT);
0329 k = ALLOC_COMPL_TIMEOUT;
0330 while ((!(reg & HERMES_EV_ALLOC)) && k) {
0331 k--;
0332 udelay(10);
0333 reg = hermes_read_regn(hw, EVSTAT);
0334 }
0335
0336 if (!hermes_present(hw)) {
0337 printk(KERN_WARNING "hermes @ %p: "
0338 "Card removed waiting for frame allocation.\n",
0339 hw->iobase);
0340 return -ENODEV;
0341 }
0342
0343 if (!(reg & HERMES_EV_ALLOC)) {
0344 printk(KERN_ERR "hermes @ %p: "
0345 "Timeout waiting for frame allocation\n",
0346 hw->iobase);
0347 return -ETIMEDOUT;
0348 }
0349
0350 *fid = hermes_read_regn(hw, ALLOCFID);
0351 hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
0352
0353 return 0;
0354 }
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365 static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset)
0366 {
0367 int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
0368 int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
0369 int k;
0370 u16 reg;
0371
0372
0373 if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2))
0374 return -EINVAL;
0375
0376 k = HERMES_BAP_BUSY_TIMEOUT;
0377 reg = hermes_read_reg(hw, oreg);
0378 while ((reg & HERMES_OFFSET_BUSY) && k) {
0379 k--;
0380 udelay(1);
0381 reg = hermes_read_reg(hw, oreg);
0382 }
0383
0384 if (reg & HERMES_OFFSET_BUSY)
0385 return -ETIMEDOUT;
0386
0387
0388 hermes_write_reg(hw, sreg, id);
0389 hermes_write_reg(hw, oreg, offset);
0390
0391
0392 k = HERMES_BAP_BUSY_TIMEOUT;
0393 reg = hermes_read_reg(hw, oreg);
0394 while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
0395 k--;
0396 udelay(1);
0397 reg = hermes_read_reg(hw, oreg);
0398 }
0399
0400 if (reg != offset) {
0401 printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
0402 "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
0403 (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
0404 reg, id, offset);
0405
0406 if (reg & HERMES_OFFSET_BUSY)
0407 return -ETIMEDOUT;
0408
0409 return -EIO;
0410 }
0411
0412 return 0;
0413 }
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424 static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len,
0425 u16 id, u16 offset)
0426 {
0427 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
0428 int err = 0;
0429
0430 if ((len < 0) || (len % 2))
0431 return -EINVAL;
0432
0433 err = hermes_bap_seek(hw, bap, id, offset);
0434 if (err)
0435 goto out;
0436
0437
0438 hermes_read_words(hw, dreg, buf, len / 2);
0439
0440 out:
0441 return err;
0442 }
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452 static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf,
0453 int len, u16 id, u16 offset)
0454 {
0455 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
0456 int err = 0;
0457
0458 if (len < 0)
0459 return -EINVAL;
0460
0461 err = hermes_bap_seek(hw, bap, id, offset);
0462 if (err)
0463 goto out;
0464
0465
0466 hermes_write_bytes(hw, dreg, buf, len);
0467
0468 out:
0469 return err;
0470 }
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480 static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid,
0481 unsigned bufsize, u16 *length, void *buf)
0482 {
0483 int err = 0;
0484 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
0485 u16 rlength, rtype;
0486 unsigned nwords;
0487
0488 if (bufsize % 2)
0489 return -EINVAL;
0490
0491 err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
0492 if (err)
0493 return err;
0494
0495 err = hermes_bap_seek(hw, bap, rid, 0);
0496 if (err)
0497 return err;
0498
0499 rlength = hermes_read_reg(hw, dreg);
0500
0501 if (!rlength)
0502 return -ENODATA;
0503
0504 rtype = hermes_read_reg(hw, dreg);
0505
0506 if (length)
0507 *length = rlength;
0508
0509 if (rtype != rid)
0510 printk(KERN_WARNING "hermes @ %p: %s(): "
0511 "rid (0x%04x) does not match type (0x%04x)\n",
0512 hw->iobase, __func__, rid, rtype);
0513 if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
0514 printk(KERN_WARNING "hermes @ %p: "
0515 "Truncating LTV record from %d to %d bytes. "
0516 "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
0517 HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
0518
0519 nwords = min((unsigned)rlength - 1, bufsize / 2);
0520 hermes_read_words(hw, dreg, buf, nwords);
0521
0522 return 0;
0523 }
0524
0525 static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid,
0526 u16 length, const void *value)
0527 {
0528 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
0529 int err = 0;
0530 unsigned count;
0531
0532 if (length == 0)
0533 return -EINVAL;
0534
0535 err = hermes_bap_seek(hw, bap, rid, 0);
0536 if (err)
0537 return err;
0538
0539 hermes_write_reg(hw, dreg, length);
0540 hermes_write_reg(hw, dreg, rid);
0541
0542 count = length - 1;
0543
0544 hermes_write_bytes(hw, dreg, value, count << 1);
0545
0546 err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
0547 rid, NULL);
0548
0549 return err;
0550 }
0551
0552
0553
0554 static inline void
0555 hermes_aux_setaddr(struct hermes *hw, u32 addr)
0556 {
0557 hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
0558 hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
0559 }
0560
0561 static inline int
0562 hermes_aux_control(struct hermes *hw, int enabled)
0563 {
0564 int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
0565 int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
0566 int i;
0567
0568
0569 if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
0570 return 0;
0571
0572 hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
0573 hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
0574 hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
0575 hermes_write_reg(hw, HERMES_CONTROL, action);
0576
0577 for (i = 0; i < 20; i++) {
0578 udelay(10);
0579 if (hermes_read_reg(hw, HERMES_CONTROL) ==
0580 desired_state)
0581 return 0;
0582 }
0583
0584 return -EBUSY;
0585 }
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596 static int hermesi_program_init(struct hermes *hw, u32 offset)
0597 {
0598 int err;
0599
0600
0601
0602
0603
0604
0605
0606 hermes_write_regn(hw, EVACK, 0xFFFF);
0607
0608
0609 err = hw->ops->init_cmd_wait(hw,
0610 0x0100 | HERMES_CMD_INIT,
0611 0, 0, 0, NULL);
0612 if (err)
0613 return err;
0614
0615 err = hw->ops->init_cmd_wait(hw,
0616 0x0000 | HERMES_CMD_INIT,
0617 0, 0, 0, NULL);
0618 if (err)
0619 return err;
0620
0621 err = hermes_aux_control(hw, 1);
0622 pr_debug("AUX enable returned %d\n", err);
0623
0624 if (err)
0625 return err;
0626
0627 pr_debug("Enabling volatile, EP 0x%08x\n", offset);
0628 err = hw->ops->init_cmd_wait(hw,
0629 HERMES_PROGRAM_ENABLE_VOLATILE,
0630 offset & 0xFFFFu,
0631 offset >> 16,
0632 0,
0633 NULL);
0634 pr_debug("PROGRAM_ENABLE returned %d\n", err);
0635
0636 return err;
0637 }
0638
0639
0640
0641
0642
0643
0644
0645 static int hermesi_program_end(struct hermes *hw)
0646 {
0647 struct hermes_response resp;
0648 int rc = 0;
0649 int err;
0650
0651 rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
0652
0653 pr_debug("PROGRAM_DISABLE returned %d, "
0654 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
0655 rc, resp.resp0, resp.resp1, resp.resp2);
0656
0657 if ((rc == 0) &&
0658 ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
0659 rc = -EIO;
0660
0661 err = hermes_aux_control(hw, 0);
0662 pr_debug("AUX disable returned %d\n", err);
0663
0664
0665 hermes_write_regn(hw, EVACK, 0xFFFF);
0666
0667
0668 (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
0669 0, 0, 0, NULL);
0670
0671 return rc ? rc : err;
0672 }
0673
0674 static int hermes_program_bytes(struct hermes *hw, const char *data,
0675 u32 addr, u32 len)
0676 {
0677
0678
0679
0680 hermes_aux_setaddr(hw, addr);
0681 hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
0682 return 0;
0683 }
0684
0685
0686 static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr,
0687 u16 pda_len)
0688 {
0689 int ret;
0690 u16 pda_size;
0691 u16 data_len = pda_len;
0692 __le16 *data = pda;
0693
0694 if (hw->eeprom_pda) {
0695
0696
0697
0698 ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
0699 if (ret)
0700 return ret;
0701 } else {
0702
0703
0704
0705 pda[0] = cpu_to_le16(pda_len - 2);
0706
0707 pda[1] = cpu_to_le16(0x0800);
0708 data_len = pda_len - 4;
0709 data = pda + 2;
0710 }
0711
0712
0713 ret = hermes_aux_control(hw, 1);
0714 pr_debug("AUX enable returned %d\n", ret);
0715 if (ret)
0716 return ret;
0717
0718
0719 hermes_aux_setaddr(hw, pda_addr);
0720 hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
0721
0722
0723 ret = hermes_aux_control(hw, 0);
0724 pr_debug("AUX disable returned %d\n", ret);
0725
0726
0727 pda_size = le16_to_cpu(pda[0]);
0728 pr_debug("Actual PDA length %d, Max allowed %d\n",
0729 pda_size, pda_len);
0730 if (pda_size > pda_len)
0731 return -EINVAL;
0732
0733 return 0;
0734 }
0735
0736 static void hermes_lock_irqsave(spinlock_t *lock,
0737 unsigned long *flags) __acquires(lock)
0738 {
0739 spin_lock_irqsave(lock, *flags);
0740 }
0741
0742 static void hermes_unlock_irqrestore(spinlock_t *lock,
0743 unsigned long *flags) __releases(lock)
0744 {
0745 spin_unlock_irqrestore(lock, *flags);
0746 }
0747
0748 static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
0749 {
0750 spin_lock_irq(lock);
0751 }
0752
0753 static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
0754 {
0755 spin_unlock_irq(lock);
0756 }
0757
0758
0759 static const struct hermes_ops hermes_ops_local = {
0760 .init = hermes_init,
0761 .cmd_wait = hermes_docmd_wait,
0762 .init_cmd_wait = hermes_doicmd_wait,
0763 .allocate = hermes_allocate,
0764 .read_ltv = hermes_read_ltv,
0765 .read_ltv_pr = hermes_read_ltv,
0766 .write_ltv = hermes_write_ltv,
0767 .bap_pread = hermes_bap_pread,
0768 .bap_pwrite = hermes_bap_pwrite,
0769 .read_pda = hermes_read_pda,
0770 .program_init = hermesi_program_init,
0771 .program_end = hermesi_program_end,
0772 .program = hermes_program_bytes,
0773 .lock_irqsave = hermes_lock_irqsave,
0774 .unlock_irqrestore = hermes_unlock_irqrestore,
0775 .lock_irq = hermes_lock_irq,
0776 .unlock_irq = hermes_unlock_irq,
0777 };