summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.c94
-rw-r--r--firmware/target/mips/ingenic_x1000/nand-x1000.h35
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
28const struct nand_chip supported_nand_chips[] = { 28static 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, 50const 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
58const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips); 54const 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
93static 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
97static bool identify_chip(struct nand_drv* drv) 106static 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;
103struct nand_drv; 101struct nand_drv;
104 102
105struct nand_chip { 103struct 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
137enum nand_readid_method {
138 NAND_READID_OPCODE,
139 NAND_READID_ADDR,
140 NAND_READID_DUMMY,
141};
142
143struct 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
144struct nand_drv { 156struct 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
180extern const struct nand_chip supported_nand_chips[]; 187extern const struct nand_chip_id supported_nand_chips[];
181extern const size_t nr_supported_nand_chips; 188extern const size_t nr_supported_nand_chips;
182 189
183/* Return the static NAND driver instance. 190/* Return the static NAND driver instance.