ops_bcm4706.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /*
  2. * BCM47XX NAND flash driver
  3. *
  4. * Copyright (C) 2012 Rafał Miłecki <zajec5@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. */
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/slab.h>
  14. #include <linux/bcma/bcma.h>
  15. #include "bcm47xxnflash.h"
  16. /**************************************************
  17. * Various helpers
  18. **************************************************/
  19. static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock)
  20. {
  21. return ((ns * 1000 * clock) / 1000000) + 1;
  22. }
  23. /**************************************************
  24. * NAND chip ops
  25. **************************************************/
  26. /* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */
  27. static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd,
  28. int chip)
  29. {
  30. return;
  31. }
  32. /**************************************************
  33. * Init
  34. **************************************************/
  35. int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n)
  36. {
  37. int err;
  38. u32 freq;
  39. u16 clock;
  40. u8 w0, w1, w2, w3, w4;
  41. unsigned long chipsize; /* MiB */
  42. u8 tbits, col_bits, col_size, row_bits, row_bsize;
  43. u32 val;
  44. b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip;
  45. b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */
  46. /* Enable NAND flash access */
  47. bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
  48. BCMA_CC_4706_FLASHSCFG_NF1);
  49. /* Configure wait counters */
  50. if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) {
  51. freq = 100000000;
  52. } else {
  53. freq = bcma_chipco_pll_read(b47n->cc, 4);
  54. freq = (freq * 0xFFF) >> 3;
  55. freq = (freq * 25000000) >> 3;
  56. }
  57. clock = freq / 1000000;
  58. w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock);
  59. w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock);
  60. w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
  61. w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock);
  62. w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock);
  63. bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0,
  64. (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0));
  65. /* Scan NAND */
  66. err = nand_scan(&b47n->mtd, 1);
  67. if (err) {
  68. pr_err("Could not scan NAND flash: %d\n", err);
  69. goto exit;
  70. }
  71. /* Configure FLASH */
  72. chipsize = b47n->nand_chip.chipsize >> 20;
  73. tbits = ffs(chipsize); /* find first bit set */
  74. if (!tbits || tbits != fls(chipsize)) {
  75. pr_err("Invalid flash size: 0x%lX\n", chipsize);
  76. err = -ENOTSUPP;
  77. goto exit;
  78. }
  79. tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */
  80. col_bits = b47n->nand_chip.page_shift + 1;
  81. col_size = (col_bits + 7) / 8;
  82. row_bits = tbits - col_bits + 1;
  83. row_bsize = (row_bits + 7) / 8;
  84. val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2;
  85. bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val);
  86. exit:
  87. if (err)
  88. bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG,
  89. ~BCMA_CC_4706_FLASHSCFG_NF1);
  90. return err;
  91. }