diff options
author | Mike Rapoport <mike@compulab.co.il> | 2009-02-17 06:54:47 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-03-20 14:37:44 -0400 |
commit | f271049e2010b918f83dc1c7bbd5d75f4710506a (patch) | |
tree | e39389588aa6ea62c23dffddb4f77cf40db44286 /drivers/mtd | |
parent | 82a72d108b4fbcc8f651b7c4e34c6f18a605d58d (diff) |
[MTD] [NAND] pxa3xx_nand: add ability to keep controller settings defined by OBM/bootloader
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Acked-by: Eric Miao <eric.miao@marvell.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 103 |
1 files changed, 102 insertions, 1 deletions
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ead4a7a72d44..2857a6a37b5c 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
@@ -171,7 +171,13 @@ static int use_dma = 1; | |||
171 | module_param(use_dma, bool, 0444); | 171 | module_param(use_dma, bool, 0444); |
172 | MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); | 172 | MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); |
173 | 173 | ||
174 | #ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN | 174 | /* |
175 | * Default NAND flash controller configuration setup by the | ||
176 | * bootloader. This configuration is used only when pdata->keep_config is set | ||
177 | */ | ||
178 | static struct pxa3xx_nand_timing default_timing; | ||
179 | static struct pxa3xx_nand_flash default_flash; | ||
180 | |||
175 | static struct pxa3xx_nand_cmdset smallpage_cmdset = { | 181 | static struct pxa3xx_nand_cmdset smallpage_cmdset = { |
176 | .read1 = 0x0000, | 182 | .read1 = 0x0000, |
177 | .read2 = 0x0050, | 183 | .read2 = 0x0050, |
@@ -198,6 +204,7 @@ static struct pxa3xx_nand_cmdset largepage_cmdset = { | |||
198 | .lock_status = 0x007A, | 204 | .lock_status = 0x007A, |
199 | }; | 205 | }; |
200 | 206 | ||
207 | #ifdef CONFIG_MTD_NAND_PXA3xx_BUILTIN | ||
201 | static struct pxa3xx_nand_timing samsung512MbX16_timing = { | 208 | static struct pxa3xx_nand_timing samsung512MbX16_timing = { |
202 | .tCH = 10, | 209 | .tCH = 10, |
203 | .tCS = 0, | 210 | .tCS = 0, |
@@ -297,9 +304,23 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { | |||
297 | #define NDTR1_tWHR(c) (min((c), 15) << 4) | 304 | #define NDTR1_tWHR(c) (min((c), 15) << 4) |
298 | #define NDTR1_tAR(c) (min((c), 15) << 0) | 305 | #define NDTR1_tAR(c) (min((c), 15) << 0) |
299 | 306 | ||
307 | #define tCH_NDTR0(r) (((r) >> 19) & 0x7) | ||
308 | #define tCS_NDTR0(r) (((r) >> 16) & 0x7) | ||
309 | #define tWH_NDTR0(r) (((r) >> 11) & 0x7) | ||
310 | #define tWP_NDTR0(r) (((r) >> 8) & 0x7) | ||
311 | #define tRH_NDTR0(r) (((r) >> 3) & 0x7) | ||
312 | #define tRP_NDTR0(r) (((r) >> 0) & 0x7) | ||
313 | |||
314 | #define tR_NDTR1(r) (((r) >> 16) & 0xffff) | ||
315 | #define tWHR_NDTR1(r) (((r) >> 4) & 0xf) | ||
316 | #define tAR_NDTR1(r) (((r) >> 0) & 0xf) | ||
317 | |||
300 | /* convert nano-seconds to nand flash controller clock cycles */ | 318 | /* convert nano-seconds to nand flash controller clock cycles */ |
301 | #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1) | 319 | #define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1) |
302 | 320 | ||
321 | /* convert nand flash controller clock cycles to nano-seconds */ | ||
322 | #define cycle2ns(c, clk) ((((c) + 1) * 1000000 + clk / 500) / (clk / 1000)) | ||
323 | |||
303 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, | 324 | static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, |
304 | const struct pxa3xx_nand_timing *t) | 325 | const struct pxa3xx_nand_timing *t) |
305 | { | 326 | { |
@@ -921,6 +942,82 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, | |||
921 | return 0; | 942 | return 0; |
922 | } | 943 | } |
923 | 944 | ||
945 | static void pxa3xx_nand_detect_timing(struct pxa3xx_nand_info *info, | ||
946 | struct pxa3xx_nand_timing *t) | ||
947 | { | ||
948 | unsigned long nand_clk = clk_get_rate(info->clk); | ||
949 | uint32_t ndtr0 = nand_readl(info, NDTR0CS0); | ||
950 | uint32_t ndtr1 = nand_readl(info, NDTR1CS0); | ||
951 | |||
952 | t->tCH = cycle2ns(tCH_NDTR0(ndtr0), nand_clk); | ||
953 | t->tCS = cycle2ns(tCS_NDTR0(ndtr0), nand_clk); | ||
954 | t->tWH = cycle2ns(tWH_NDTR0(ndtr0), nand_clk); | ||
955 | t->tWP = cycle2ns(tWP_NDTR0(ndtr0), nand_clk); | ||
956 | t->tRH = cycle2ns(tRH_NDTR0(ndtr0), nand_clk); | ||
957 | t->tRP = cycle2ns(tRP_NDTR0(ndtr0), nand_clk); | ||
958 | |||
959 | t->tR = cycle2ns(tR_NDTR1(ndtr1), nand_clk); | ||
960 | t->tWHR = cycle2ns(tWHR_NDTR1(ndtr1), nand_clk); | ||
961 | t->tAR = cycle2ns(tAR_NDTR1(ndtr1), nand_clk); | ||
962 | } | ||
963 | |||
964 | static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) | ||
965 | { | ||
966 | uint32_t ndcr = nand_readl(info, NDCR); | ||
967 | struct nand_flash_dev *type = NULL; | ||
968 | uint32_t id = -1; | ||
969 | int i; | ||
970 | |||
971 | default_flash.page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; | ||
972 | default_flash.page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; | ||
973 | default_flash.flash_width = ndcr & NDCR_DWIDTH_M ? 16 : 8; | ||
974 | default_flash.dfc_width = ndcr & NDCR_DWIDTH_C ? 16 : 8; | ||
975 | |||
976 | if (default_flash.page_size == 2048) | ||
977 | default_flash.cmdset = &largepage_cmdset; | ||
978 | else | ||
979 | default_flash.cmdset = &smallpage_cmdset; | ||
980 | |||
981 | /* set info fields needed to __readid */ | ||
982 | info->flash_info = &default_flash; | ||
983 | info->read_id_bytes = (default_flash.page_size == 2048) ? 4 : 2; | ||
984 | info->reg_ndcr = ndcr; | ||
985 | |||
986 | if (__readid(info, &id)) | ||
987 | return -ENODEV; | ||
988 | |||
989 | /* Lookup the flash id */ | ||
990 | id = (id >> 8) & 0xff; /* device id is byte 2 */ | ||
991 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | ||
992 | if (id == nand_flash_ids[i].id) { | ||
993 | type = &nand_flash_ids[i]; | ||
994 | break; | ||
995 | } | ||
996 | } | ||
997 | |||
998 | if (!type) | ||
999 | return -ENODEV; | ||
1000 | |||
1001 | /* fill the missing flash information */ | ||
1002 | i = __ffs(default_flash.page_per_block * default_flash.page_size); | ||
1003 | default_flash.num_blocks = type->chipsize << (20 - i); | ||
1004 | |||
1005 | info->oob_size = (default_flash.page_size == 2048) ? 64 : 16; | ||
1006 | |||
1007 | /* calculate addressing information */ | ||
1008 | info->col_addr_cycles = (default_flash.page_size == 2048) ? 2 : 1; | ||
1009 | |||
1010 | if (default_flash.num_blocks * default_flash.page_per_block > 65536) | ||
1011 | info->row_addr_cycles = 3; | ||
1012 | else | ||
1013 | info->row_addr_cycles = 2; | ||
1014 | |||
1015 | pxa3xx_nand_detect_timing(info, &default_timing); | ||
1016 | default_flash.timing = &default_timing; | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
924 | static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, | 1021 | static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, |
925 | const struct pxa3xx_nand_platform_data *pdata) | 1022 | const struct pxa3xx_nand_platform_data *pdata) |
926 | { | 1023 | { |
@@ -928,6 +1025,10 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, | |||
928 | uint32_t id = -1; | 1025 | uint32_t id = -1; |
929 | int i; | 1026 | int i; |
930 | 1027 | ||
1028 | if (pdata->keep_config) | ||
1029 | if (pxa3xx_nand_detect_config(info) == 0) | ||
1030 | return 0; | ||
1031 | |||
931 | for (i = 0; i<pdata->num_flash; ++i) { | 1032 | for (i = 0; i<pdata->num_flash; ++i) { |
932 | f = pdata->flash + i; | 1033 | f = pdata->flash + i; |
933 | 1034 | ||