2 * Samsung S3C2410A RISC Microprocessor support (ARM920T based SoC).
4 * Copyright (c) 2007 OpenMoko, Inc.
5 * Author: Andrzej Zaborowski <andrew@openedhand.com>
6 * With: Michel Pollet <buserror@gmail.com>
8 * This code is licenced under the GNU GPL v2.
14 struct s3c2440_nand_s
{
15 struct s3c_nand_driver_s driver
;
17 /* NAND Flash controller */
18 target_phys_addr_t nand_base
;
19 struct nand_flash_s
*nand
;
24 struct ecc_state_s nfecc
;
28 extern struct s3c_state_s
*g_s3c
;
30 /* NAND Flash controller */
31 #define S3C_NFCONF 0x00 /* NAND Flash Configuration register */
33 #define S3C_NFCONT 0x04 /* NAND Flash Configuration register */
34 #define S3C_NFCONT_MODE (1 << 0) /* NAND flash controller operating mode */
35 #define S3C_NFCONT_CE (1 << 1) /* NAND Flash Memory nFCE signal control 0: active) */
36 #define S3C_NFCONT_INITECC (1 << 4) /* Initialize ECC decoder/encoder(Write-only) */
38 #define S3C_NFCMD 0x08 /* NAND Flash Command Set register */
39 #define S3C_NFADDR 0x0c /* NAND Flash Address Set register */
40 #define S3C_NFDATA 0x10 /* NAND Flash Data register */
41 #define S3C_NFSTAT 0x20 /* NAND Flash Operation Status register */
42 #define S3C_NFSTAT0 0x24 /* NAND Flash Operation Status register */
43 #define S3C_NFSTAT1 0x28 /* NAND Flash Operation Status register */
45 #define S3C_NFECC 0x14 /* NAND Flash ECC register */
46 #define S3C_NFECCD0 0x14 /* NAND Flash ECC register */
47 #define S3C_NFECCD1 0x18 /* NAND Flash ECC register */
48 #define S3C_NFECCD 0x1c /* NAND Flash ECC register */
50 static void s3c2440_nand_reset(void * opaque
)
52 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*)opaque
;
60 static uint32_t s3c2440_nand_read(void *opaque
, target_phys_addr_t addr
)
62 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
67 // printf("%08x - %s: %02x\n", g_s3c->env->regs[15], __FUNCTION__, (unsigned long)addr);fflush(stdout);
77 return s
->nfaddr
>> 24; // last 8 bits poked
79 if (s
->nfcont
& S3C_NFCONT_MODE
) {
80 uint32_t r1
= nand_getio(s
->nand
);
81 uint32_t res
= ecc_digest(&s
->nfecc
, r1
);
86 nand_getpins(s
->nand
, &rb
);
88 case S3C_NFECC
+ 2: shr
+= 8;
89 case S3C_NFECC
+ 1: shr
+= 8;
91 #define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl))
93 ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) |
94 ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) |
95 ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) |
96 ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) |
97 ECC(8, 1, 16) | ECC(8, 0, 17) | (s
->nfecc
.cp
<< 18)) >> shr
) &
101 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
107 static void s3c2440_nand_write(void *opaque
, target_phys_addr_t addr
,
110 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
114 //printf("%08x - %s: %02x = %lx\n", g_s3c->env->regs[15], __FUNCTION__, (unsigned long)addr, value);fflush(stdout);
118 s
->nfconf
= value
& 0xffff;
121 if (value
& S3C_NFCONT_MODE
)
122 ecc_reset(&s
->nfecc
);
123 s
->nfcont
= value
& (0xffff ^ S3C_NFCONT_INITECC
);
126 s
->nfcmd
= value
& 0xff;
127 if (s
->nfcont
& S3C_NFCONT_MODE
) {
128 nand_setpins(s
->nand
, 1, 0, s
->nfcont
& S3C_NFCONT_CE
, s
->nfwp
, 0);
129 nand_setio(s
->nand
, s
->nfcmd
);
130 nand_setpins(s
->nand
, 0, 0, s
->nfcont
& S3C_NFCONT_CE
, s
->nfwp
, 0);
133 case S3C_NFSTAT
: // it's OK to write to this on the 2440
136 s
->nfaddr
= (s
->nfaddr
>> 8) | (value
<< 24);
137 if (s
->nfcont
& S3C_NFCONT_MODE
) {
138 nand_setpins(s
->nand
, 0, 1, s
->nfcont
& S3C_NFCONT_CE
, s
->nfwp
, 0);
139 nand_setio(s
->nand
, value
& 0xff);
140 nand_setpins(s
->nand
, 0, 0, s
->nfcont
& S3C_NFCONT_CE
, s
->nfwp
, 0);
144 if (s
->nfcont
& S3C_NFCONT_MODE
)
145 nand_setio(s
->nand
, ecc_digest(&s
->nfecc
, value
& 0xff));
148 printf("%s: Bad register 0x%lx=%x\n", __FUNCTION__
, (unsigned long)addr
, value
);
152 static void s3c2440_nand_register(void * opaque
, struct nand_flash_s
*chip
)
154 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
158 static void s3c2440_nand_setwp(void * opaque
, int wp
)
160 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
164 static CPUReadMemoryFunc
*s3c2440_nand_readfn
[] = {
170 static CPUWriteMemoryFunc
*s3c2440_nand_writefn
[] = {
176 static void s3c2440_nand_save(QEMUFile
*f
, void *opaque
)
178 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
179 qemu_put_be16s(f
, &s
->nfconf
);
180 qemu_put_be16s(f
, &s
->nfcont
);
181 qemu_put_8s(f
, &s
->nfcmd
);
182 qemu_put_be32s(f
, &s
->nfaddr
);
183 qemu_put_be32(f
, s
->nfwp
);
184 ecc_put(f
, &s
->nfecc
);
187 static int s3c2440_nand_load(QEMUFile
*f
, void *opaque
, int version_id
)
189 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
190 qemu_get_be16s(f
, &s
->nfconf
);
191 qemu_get_be16s(f
, &s
->nfcont
);
192 qemu_get_8s(f
, &s
->nfcmd
);
193 qemu_get_be32s(f
, &s
->nfaddr
);
194 s
->nfwp
= qemu_get_be32(f
);
195 ecc_get(f
, &s
->nfecc
);
199 static const struct s3c_nand_driver_s s3c2440_nand_driver
= {
200 .reset
= s3c2440_nand_reset
,
201 .setwp
= s3c2440_nand_setwp
,
202 .reg
= s3c2440_nand_register
205 struct s3c_nand_driver_s
* s3c2440_nand_init(void)
208 struct s3c2440_nand_s
*nand
= (struct s3c2440_nand_s
*)
209 qemu_mallocz(sizeof(struct s3c2440_nand_s
));
210 nand
->driver
= s3c2440_nand_driver
;
211 nand
->nand_base
= 0x4e000000;
212 nand
->driver
.reset(nand
);
213 iomemtype
= cpu_register_io_memory(0, s3c2440_nand_readfn
, s3c2440_nand_writefn
, nand
);
214 cpu_register_physical_memory(nand
->nand_base
, 0xffffff, iomemtype
);
215 register_savevm("s3c2440_nand", 0, 0, s3c2440_nand_save
, s3c2440_nand_load
, nand
);
216 return &nand
->driver
;