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 /* NAND Flash controller */
29 #define S3C_NFCONF 0x00 /* NAND Flash Configuration register */
31 #define S3C_NFCONT 0x04 /* NAND Flash Configuration register */
32 #define S3C_NFCMD 0x08 /* NAND Flash Command Set register */
33 #define S3C_NFADDR 0x0c /* NAND Flash Address Set register */
34 #define S3C_NFDATA 0x10 /* NAND Flash Data register */
35 #define S3C_NFSTAT 0x20 /* NAND Flash Operation Status register */
36 #define S3C_NFSTAT0 0x24 /* NAND Flash Operation Status register */
37 #define S3C_NFSTAT1 0x28 /* NAND Flash Operation Status register */
39 #define S3C_NFECC 0x14 /* NAND Flash ECC register */
40 #define S3C_NFECCD0 0x14 /* NAND Flash ECC register */
41 #define S3C_NFECCD1 0x18 /* NAND Flash ECC register */
42 #define S3C_NFECCD 0x1c /* NAND Flash ECC register */
44 static void s3c2440_nand_reset(void * opaque
)
46 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*)opaque
;
47 s
->nfconf
= 0x00001000;
54 static uint32_t s3c2440_nand_read(void *opaque
, target_phys_addr_t addr
)
56 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
71 if (s
->nfcont
& (1 << 0))
72 return ecc_digest(&s
->nfecc
, nand_getio(s
->nand
));
75 nand_getpins(s
->nand
, &rb
);
77 case S3C_NFECC
+ 2: shr
+= 8;
78 case S3C_NFECC
+ 1: shr
+= 8;
80 #define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl))
82 ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) |
83 ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) |
84 ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) |
85 ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) |
86 ECC(8, 1, 16) | ECC(8, 0, 17) | (s
->nfecc
.cp
<< 18)) >> shr
) &
90 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
96 static void s3c2440_nand_write(void *opaque
, target_phys_addr_t addr
,
99 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
105 s
->nfconf
= value
& 0xffff;
108 s
->nfcont
= value
& 0xffff;
109 if (value
& (1 << 4))
110 ecc_reset(&s
->nfecc
);
113 s
->nfcmd
= value
& 0xff;
114 if (s
->nfcont
& (1 << 0)) {
115 nand_setpins(s
->nand
, 1, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
116 nand_setio(s
->nand
, s
->nfcmd
);
117 nand_setpins(s
->nand
, 0, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
121 s
->nfaddr
= value
& 0xff;
122 if (s
->nfcont
& (1 << 0)) {
123 nand_setpins(s
->nand
, 0, 1, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
124 nand_setio(s
->nand
, s
->nfaddr
);
125 nand_setpins(s
->nand
, 0, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
129 if (s
->nfcont
& (1 << 0))
130 nand_setio(s
->nand
, ecc_digest(&s
->nfecc
, value
& 0xff));
133 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
137 static void s3c2440_nand_register(void * opaque
, struct nand_flash_s
*chip
)
139 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
143 static void s3c2440_nand_setwp(void * opaque
, int wp
)
145 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
149 static CPUReadMemoryFunc
*s3c2440_nand_readfn
[] = {
155 static CPUWriteMemoryFunc
*s3c2440_nand_writefn
[] = {
161 static void s3c2440_nand_save(QEMUFile
*f
, void *opaque
)
163 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
164 qemu_put_be16s(f
, &s
->nfconf
);
165 qemu_put_8s(f
, &s
->nfcmd
);
166 qemu_put_8s(f
, &s
->nfaddr
);
167 qemu_put_be32(f
, s
->nfwp
);
168 ecc_put(f
, &s
->nfecc
);
171 static int s3c2440_nand_load(QEMUFile
*f
, void *opaque
, int version_id
)
173 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
174 qemu_get_be16s(f
, &s
->nfconf
);
175 qemu_get_8s(f
, &s
->nfcmd
);
176 qemu_get_8s(f
, &s
->nfaddr
);
177 s
->nfwp
= qemu_get_be32(f
);
178 ecc_get(f
, &s
->nfecc
);
182 static const struct s3c_nand_driver_s s3c2440_nand_driver
= {
183 .reset
= s3c2440_nand_reset
,
184 .setwp
= s3c2440_nand_setwp
,
185 .reg
= s3c2440_nand_register
188 struct s3c_nand_driver_s
* s3c2440_nand_init(void)
191 struct s3c2440_nand_s
*nand
= (struct s3c2440_nand_s
*)
192 qemu_mallocz(sizeof(struct s3c2440_nand_s
));
193 nand
->driver
= s3c2440_nand_driver
;
194 nand
->nand_base
= 0x4e000000;
195 nand
->driver
.reset(nand
);
196 iomemtype
= cpu_register_io_memory(0, s3c2440_nand_readfn
, s3c2440_nand_writefn
, nand
);
197 cpu_register_physical_memory(nand
->nand_base
, 0xffffff, iomemtype
);
198 register_savevm("s3c2440_nand", 0, 0, s3c2440_nand_save
, s3c2440_nand_load
, nand
);
199 return &nand
->driver
;