diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2012-11-12 07:03:22 -0500 |
---|---|---|
committer | Artem Bityutskiy <artem.bityutskiy@linux.intel.com> | 2012-11-22 02:32:38 -0500 |
commit | 19c0921c842e0aa9ce8c540c9134fd358acc9b28 (patch) | |
tree | 73895af3c10bdc093decd73ae0cb2f8b2ebb9447 /drivers/mtd | |
parent | a5401370c520d573e9d62b3f8f34940c3b798a49 (diff) |
mtd: bcm47xxnflash: init NAND on BCM4706
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | 109 |
2 files changed, 110 insertions, 0 deletions
diff --git a/drivers/mtd/nand/bcm47xxnflash/Makefile b/drivers/mtd/nand/bcm47xxnflash/Makefile index 1d0693af6e98..4f688f9655ad 100644 --- a/drivers/mtd/nand/bcm47xxnflash/Makefile +++ b/drivers/mtd/nand/bcm47xxnflash/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | bcm47xxnflash-y += main.o | 1 | bcm47xxnflash-y += main.o |
2 | bcm47xxnflash- += ops_bcm4706.o | ||
2 | 3 | ||
3 | obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o | 4 | obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash.o |
diff --git a/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c new file mode 100644 index 000000000000..ae8a79387c27 --- /dev/null +++ b/drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c | |||
@@ -0,0 +1,109 @@ | |||
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 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/bcma/bcma.h> | ||
16 | |||
17 | #include "bcm47xxnflash.h" | ||
18 | |||
19 | /************************************************** | ||
20 | * Various helpers | ||
21 | **************************************************/ | ||
22 | |||
23 | static inline u8 bcm47xxnflash_ops_bcm4706_ns_to_cycle(u16 ns, u16 clock) | ||
24 | { | ||
25 | return ((ns * 1000 * clock) / 1000000) + 1; | ||
26 | } | ||
27 | |||
28 | /************************************************** | ||
29 | * NAND chip ops | ||
30 | **************************************************/ | ||
31 | |||
32 | /* Default nand_select_chip calls cmd_ctrl, which is not used in BCM4706 */ | ||
33 | static void bcm47xxnflash_ops_bcm4706_select_chip(struct mtd_info *mtd, | ||
34 | int chip) | ||
35 | { | ||
36 | return; | ||
37 | } | ||
38 | |||
39 | /************************************************** | ||
40 | * Init | ||
41 | **************************************************/ | ||
42 | |||
43 | int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) | ||
44 | { | ||
45 | int err; | ||
46 | u32 freq; | ||
47 | u16 clock; | ||
48 | u8 w0, w1, w2, w3, w4; | ||
49 | |||
50 | unsigned long chipsize; /* MiB */ | ||
51 | u8 tbits, col_bits, col_size, row_bits, row_bsize; | ||
52 | u32 val; | ||
53 | |||
54 | b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; | ||
55 | b47n->nand_chip.ecc.mode = NAND_ECC_NONE; /* TODO: implement ECC */ | ||
56 | |||
57 | /* Enable NAND flash access */ | ||
58 | bcma_cc_set32(b47n->cc, BCMA_CC_4706_FLASHSCFG, | ||
59 | BCMA_CC_4706_FLASHSCFG_NF1); | ||
60 | |||
61 | /* Configure wait counters */ | ||
62 | if (b47n->cc->status & BCMA_CC_CHIPST_4706_PKG_OPTION) { | ||
63 | freq = 100000000; | ||
64 | } else { | ||
65 | freq = bcma_chipco_pll_read(b47n->cc, 4); | ||
66 | freq = (freq * 0xFFF) >> 3; | ||
67 | freq = (freq * 25000000) >> 3; | ||
68 | } | ||
69 | clock = freq / 1000000; | ||
70 | w0 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(15, clock); | ||
71 | w1 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(20, clock); | ||
72 | w2 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); | ||
73 | w3 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(10, clock); | ||
74 | w4 = bcm47xxnflash_ops_bcm4706_ns_to_cycle(100, clock); | ||
75 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_WAITCNT0, | ||
76 | (w4 << 24 | w3 << 18 | w2 << 12 | w1 << 6 | w0)); | ||
77 | |||
78 | /* Scan NAND */ | ||
79 | err = nand_scan(&b47n->mtd, 1); | ||
80 | if (err) { | ||
81 | pr_err("Could not scan NAND flash: %d\n", err); | ||
82 | goto exit; | ||
83 | } | ||
84 | |||
85 | /* Configure FLASH */ | ||
86 | chipsize = b47n->nand_chip.chipsize >> 20; | ||
87 | tbits = ffs(chipsize); /* find first bit set */ | ||
88 | if (!tbits || tbits != fls(chipsize)) { | ||
89 | pr_err("Invalid flash size: 0x%lX\n", chipsize); | ||
90 | err = -ENOTSUPP; | ||
91 | goto exit; | ||
92 | } | ||
93 | tbits += 19; /* Broadcom increases *index* by 20, we increase *pos* */ | ||
94 | |||
95 | col_bits = b47n->nand_chip.page_shift + 1; | ||
96 | col_size = (col_bits + 7) / 8; | ||
97 | |||
98 | row_bits = tbits - col_bits + 1; | ||
99 | row_bsize = (row_bits + 7) / 8; | ||
100 | |||
101 | val = ((row_bsize - 1) << 6) | ((col_size - 1) << 4) | 2; | ||
102 | bcma_cc_write32(b47n->cc, BCMA_CC_NFLASH_CONF, val); | ||
103 | |||
104 | exit: | ||
105 | if (err) | ||
106 | bcma_cc_mask32(b47n->cc, BCMA_CC_4706_FLASHSCFG, | ||
107 | ~BCMA_CC_4706_FLASHSCFG_NF1); | ||
108 | return err; | ||
109 | } | ||