diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/nand-x1000.c | 94 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_x1000/nand-x1000.h | 35 |
2 files changed, 69 insertions, 60 deletions
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c index 827a79ebce..6255597165 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c | |||
@@ -25,34 +25,30 @@ | |||
25 | #include "logf.h" | 25 | #include "logf.h" |
26 | #include <string.h> | 26 | #include <string.h> |
27 | 27 | ||
28 | const struct nand_chip supported_nand_chips[] = { | 28 | static const struct nand_chip chip_ato25d1ga = { |
29 | #if defined(FIIO_M3K) || defined(SHANLING_Q1) || defined(EROS_QN) | 29 | .log2_ppb = 6, /* 64 pages */ |
30 | { | 30 | .page_size = 2048, |
31 | /* ATO25D1GA */ | 31 | .oob_size = 64, |
32 | .mf_id = 0x9b, | 32 | .nr_blocks = 1024, |
33 | .dev_id = 0x12, | 33 | .bbm_pos = 2048, |
34 | .log2_ppb = 6, /* 64 pages */ | 34 | .clock_freq = 150000000, |
35 | .page_size = 2048, | 35 | .dev_conf = jz_orf(SFC_DEV_CONF, |
36 | .oob_size = 64, | 36 | CE_DL(1), HOLD_DL(1), WP_DL(1), |
37 | .nr_blocks = 1024, | 37 | CPHA(0), CPOL(0), |
38 | .bbm_pos = 2048, | 38 | TSH(7), TSETUP(0), THOLD(0), |
39 | .clock_freq = 150000000, | 39 | STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), |
40 | .dev_conf = jz_orf(SFC_DEV_CONF, | 40 | SMP_DELAY(1)), |
41 | CE_DL(1), HOLD_DL(1), WP_DL(1), | 41 | .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT, |
42 | CPHA(0), CPOL(0), | 42 | .cmd_page_read = NANDCMD_PAGE_READ, |
43 | TSH(7), TSETUP(0), THOLD(0), | 43 | .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE, |
44 | STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), | 44 | .cmd_block_erase = NANDCMD_BLOCK_ERASE, |
45 | SMP_DELAY(1)), | 45 | .cmd_read_cache = NANDCMD_READ_CACHE_x4, |
46 | .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT, | 46 | .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4, |
47 | .cmd_page_read = NANDCMD_PAGE_READ, | 47 | }; |
48 | .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE, | 48 | |
49 | .cmd_block_erase = NANDCMD_BLOCK_ERASE, | 49 | |
50 | .cmd_read_cache = NANDCMD_READ_CACHE_x4, | 50 | const struct nand_chip_id supported_nand_chips[] = { |
51 | .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4, | 51 | NAND_CHIP_ID(&chip_ato25d1ga, NAND_READID_ADDR, 0x9b, 0x12), |
52 | }, | ||
53 | #else | ||
54 | { 0 }, | ||
55 | #endif | ||
56 | }; | 52 | }; |
57 | 53 | ||
58 | const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips); | 54 | const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips); |
@@ -94,6 +90,19 @@ static void nand_upd_reg(struct nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t | |||
94 | nand_set_reg(drv, reg, x); | 90 | nand_set_reg(drv, reg, x); |
95 | } | 91 | } |
96 | 92 | ||
93 | static const struct nand_chip* identify_chip_method(uint8_t method, | ||
94 | const uint8_t* id_buf) | ||
95 | { | ||
96 | for (size_t i = 0; i < nr_supported_nand_chips; ++i) { | ||
97 | const struct nand_chip_id* chip_id = &supported_nand_chips[i]; | ||
98 | if (chip_id->method == method && | ||
99 | !memcmp(chip_id->id_bytes, id_buf, chip_id->num_id_bytes)) | ||
100 | return chip_id->chip; | ||
101 | } | ||
102 | |||
103 | return NULL; | ||
104 | } | ||
105 | |||
97 | static bool identify_chip(struct nand_drv* drv) | 106 | static bool identify_chip(struct nand_drv* drv) |
98 | { | 107 | { |
99 | /* Read ID command has some variations; Linux handles these 3: | 108 | /* Read ID command has some variations; Linux handles these 3: |
@@ -101,25 +110,13 @@ static bool identify_chip(struct nand_drv* drv) | |||
101 | * - 1 byte address, no dummy byte | 110 | * - 1 byte address, no dummy byte |
102 | * - no address byte, 1 byte dummy | 111 | * - no address byte, 1 byte dummy |
103 | * | 112 | * |
104 | * Currently we use the 2nd method, aka. address read ID. | 113 | * Currently we use the 2nd method, aka. address read ID, the |
114 | * other methods can be added when needed. | ||
105 | */ | 115 | */ |
106 | sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ); | 116 | sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ); |
107 | drv->mf_id = drv->scratch_buf[0]; | 117 | drv->chip = identify_chip_method(NAND_READID_ADDR, drv->scratch_buf); |
108 | drv->dev_id = drv->scratch_buf[1]; | 118 | if (drv->chip) |
109 | drv->dev_id2 = drv->scratch_buf[2]; | ||
110 | |||
111 | for(size_t i = 0; i < nr_supported_nand_chips; ++i) { | ||
112 | const struct nand_chip* chip = &supported_nand_chips[i]; | ||
113 | if(chip->mf_id != drv->mf_id || chip->dev_id != drv->dev_id) | ||
114 | continue; | ||
115 | |||
116 | if((chip->flags & NAND_CHIPFLAG_HAS_DEVID2) && | ||
117 | chip->dev_id2 != drv->dev_id2) | ||
118 | continue; | ||
119 | |||
120 | drv->chip = chip; | ||
121 | return true; | 119 | return true; |
122 | } | ||
123 | 120 | ||
124 | return false; | 121 | return false; |
125 | } | 122 | } |
@@ -164,8 +161,13 @@ int nand_open(struct nand_drv* drv) | |||
164 | 161 | ||
165 | /* Initialize the controller */ | 162 | /* Initialize the controller */ |
166 | sfc_open(); | 163 | sfc_open(); |
167 | sfc_set_dev_conf(supported_nand_chips[0].dev_conf); | 164 | sfc_set_dev_conf(jz_orf(SFC_DEV_CONF, |
168 | sfc_set_clock(supported_nand_chips[0].clock_freq); | 165 | CE_DL(1), HOLD_DL(1), WP_DL(1), |
166 | CPHA(0), CPOL(0), | ||
167 | TSH(15), TSETUP(0), THOLD(0), | ||
168 | STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), | ||
169 | SMP_DELAY(0))); | ||
170 | sfc_set_clock(X1000_EXCLK_FREQ); | ||
169 | 171 | ||
170 | /* Send the software reset command */ | 172 | /* Send the software reset command */ |
171 | sfc_exec(NANDCMD_RESET, 0, NULL, 0); | 173 | sfc_exec(NANDCMD_RESET, 0, NULL, 0); |
diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h index 227c71e3f4..2c3294cfad 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.h +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h | |||
@@ -42,10 +42,8 @@ | |||
42 | #define NAND_CHIPFLAG_QUAD 0x0001 | 42 | #define NAND_CHIPFLAG_QUAD 0x0001 |
43 | /* Chip requires QE bit set to enable quad I/O mode */ | 43 | /* Chip requires QE bit set to enable quad I/O mode */ |
44 | #define NAND_CHIPFLAG_HAS_QE_BIT 0x0002 | 44 | #define NAND_CHIPFLAG_HAS_QE_BIT 0x0002 |
45 | /* Chip has 2nd device ID byte */ | ||
46 | #define NAND_CHIPFLAG_HAS_DEVID2 0x0004 | ||
47 | /* True if the chip has on-die ECC */ | 45 | /* True if the chip has on-die ECC */ |
48 | #define NAND_CHIPFLAG_ON_DIE_ECC 0x0008 | 46 | #define NAND_CHIPFLAG_ON_DIE_ECC 0x0004 |
49 | 47 | ||
50 | /* cmd mode a d phase format has data */ | 48 | /* cmd mode a d phase format has data */ |
51 | #define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) | 49 | #define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) |
@@ -103,11 +101,6 @@ typedef uint32_t nand_page_t; | |||
103 | struct nand_drv; | 101 | struct nand_drv; |
104 | 102 | ||
105 | struct nand_chip { | 103 | struct nand_chip { |
106 | /* Manufacturer and device ID bytes */ | ||
107 | uint8_t mf_id; | ||
108 | uint8_t dev_id; | ||
109 | uint8_t dev_id2; | ||
110 | |||
111 | /* Base2 logarithm of the number of pages per block */ | 104 | /* Base2 logarithm of the number of pages per block */ |
112 | unsigned log2_ppb; | 105 | unsigned log2_ppb; |
113 | 106 | ||
@@ -141,6 +134,25 @@ struct nand_chip { | |||
141 | void(*setup_chip)(struct nand_drv* drv); | 134 | void(*setup_chip)(struct nand_drv* drv); |
142 | }; | 135 | }; |
143 | 136 | ||
137 | enum nand_readid_method { | ||
138 | NAND_READID_OPCODE, | ||
139 | NAND_READID_ADDR, | ||
140 | NAND_READID_DUMMY, | ||
141 | }; | ||
142 | |||
143 | struct nand_chip_id { | ||
144 | uint8_t method; | ||
145 | uint8_t num_id_bytes; | ||
146 | uint8_t id_bytes[4]; | ||
147 | const struct nand_chip* chip; | ||
148 | }; | ||
149 | |||
150 | #define NAND_CHIP_ID(_chip, _method, ...) \ | ||
151 | { .method = _method, \ | ||
152 | .num_id_bytes = ARRAYLEN(((uint8_t[]){__VA_ARGS__})), \ | ||
153 | .id_bytes = {__VA_ARGS__}, \ | ||
154 | .chip = _chip } | ||
155 | |||
144 | struct nand_drv { | 156 | struct nand_drv { |
145 | /* NAND access lock. Needs to be held during any operations. */ | 157 | /* NAND access lock. Needs to be held during any operations. */ |
146 | struct mutex mutex; | 158 | struct mutex mutex; |
@@ -170,14 +182,9 @@ struct nand_drv { | |||
170 | 182 | ||
171 | /* Full page size = chip->page_size + chip->oob_size */ | 183 | /* Full page size = chip->page_size + chip->oob_size */ |
172 | unsigned fpage_size; | 184 | unsigned fpage_size; |
173 | |||
174 | /* Probed mf_id / dev_id for debugging, in case identification fails. */ | ||
175 | uint8_t mf_id; | ||
176 | uint8_t dev_id; | ||
177 | uint8_t dev_id2; | ||
178 | }; | 185 | }; |
179 | 186 | ||
180 | extern const struct nand_chip supported_nand_chips[]; | 187 | extern const struct nand_chip_id supported_nand_chips[]; |
181 | extern const size_t nr_supported_nand_chips; | 188 | extern const size_t nr_supported_nand_chips; |
182 | 189 | ||
183 | /* Return the static NAND driver instance. | 190 | /* Return the static NAND driver instance. |