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 s3c2410_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
;
23 struct ecc_state_s nfecc
;
27 /* NAND Flash controller */
28 #define S3C_NFCONF 0x00 /* NAND Flash Configuration register */
29 #define S3C_NFCMD 0x04 /* NAND Flash Command Set register */
30 #define S3C_NFADDR 0x08 /* NAND Flash Address Set register */
31 #define S3C_NFDATA 0x0c /* NAND Flash Data register */
32 #define S3C_NFSTAT 0x10 /* NAND Flash Operation Status register */
33 #define S3C_NFECC 0x14 /* NAND Flash ECC register */
35 static void s3c2410_nand_reset(void * opaque
)
37 struct s3c2410_nand_s
*s
= (struct s3c2410_nand_s
*)opaque
;
44 static uint32_t s3c2410_nand_read(void *opaque
, target_phys_addr_t addr
)
46 struct s3c2410_nand_s
*s
= (struct s3c2410_nand_s
*) opaque
;
59 if (s
->nfconf
& (1 << 15))
60 return ecc_digest(&s
->nfecc
, nand_getio(s
->nand
));
63 nand_getpins(s
->nand
, &rb
);
65 case S3C_NFECC
+ 2: shr
+= 8;
66 case S3C_NFECC
+ 1: shr
+= 8;
68 #define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl))
70 ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) |
71 ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) |
72 ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) |
73 ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) |
74 ECC(8, 1, 16) | ECC(8, 0, 17) | (s
->nfecc
.cp
<< 18)) >> shr
) &
78 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
84 static void s3c2410_nand_write(void *opaque
, target_phys_addr_t addr
,
87 struct s3c2410_nand_s
*s
= (struct s3c2410_nand_s
*) opaque
;
93 s
->nfconf
= value
& 0x9fff;
94 if (value
& (1 << 12))
98 s
->nfcmd
= value
& 0xff;
99 if (s
->nfconf
& (1 << 15)) {
100 nand_setpins(s
->nand
, 1, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
101 nand_setio(s
->nand
, s
->nfcmd
);
102 nand_setpins(s
->nand
, 0, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
106 s
->nfaddr
= value
& 0xff;
107 if (s
->nfconf
& (1 << 15)) {
108 nand_setpins(s
->nand
, 0, 1, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
109 nand_setio(s
->nand
, s
->nfaddr
);
110 nand_setpins(s
->nand
, 0, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
114 if (s
->nfconf
& (1 << 15))
115 nand_setio(s
->nand
, ecc_digest(&s
->nfecc
, value
& 0xff));
118 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
122 static void s3c2410_nand_register(void * opaque
, struct nand_flash_s
*chip
)
124 struct s3c2410_nand_s
*s
= (struct s3c2410_nand_s
*) opaque
;
128 static void s3c2410_nand_setwp(void * opaque
, int wp
)
130 struct s3c2410_nand_s
*s
= (struct s3c2410_nand_s
*) opaque
;
134 static CPUReadMemoryFunc
*s3c2410_nand_readfn
[] = {
140 static CPUWriteMemoryFunc
*s3c2410_nand_writefn
[] = {
146 static void s3c2410_nand_save(QEMUFile
*f
, void *opaque
)
148 struct s3c2410_nand_s
*s
= (struct s3c2410_nand_s
*) opaque
;
149 qemu_put_be16s(f
, &s
->nfconf
);
150 qemu_put_8s(f
, &s
->nfcmd
);
151 qemu_put_8s(f
, &s
->nfaddr
);
152 qemu_put_be32(f
, s
->nfwp
);
153 ecc_put(f
, &s
->nfecc
);
156 static int s3c2410_nand_load(QEMUFile
*f
, void *opaque
, int version_id
)
158 struct s3c2410_nand_s
*s
= (struct s3c2410_nand_s
*) opaque
;
159 qemu_get_be16s(f
, &s
->nfconf
);
160 qemu_get_8s(f
, &s
->nfcmd
);
161 qemu_get_8s(f
, &s
->nfaddr
);
162 s
->nfwp
= qemu_get_be32(f
);
163 ecc_get(f
, &s
->nfecc
);
167 static const struct s3c_nand_driver_s s3c2410_nand_driver
= {
168 .reset
= s3c2410_nand_reset
,
169 .setwp
= s3c2410_nand_setwp
,
170 .reg
= s3c2410_nand_register
173 struct s3c_nand_driver_s
* s3c2410_nand_init(void)
176 struct s3c2410_nand_s
*nand
= (struct s3c2410_nand_s
*)
177 qemu_mallocz(sizeof(struct s3c2410_nand_s
));
178 nand
->driver
= s3c2410_nand_driver
;
179 nand
->nand_base
= 0x4e000000;
180 nand
->driver
.reset(nand
);
181 iomemtype
= cpu_register_io_memory(0, s3c2410_nand_readfn
, s3c2410_nand_writefn
, nand
);
182 cpu_register_physical_memory(nand
->nand_base
, 0xffffff, iomemtype
);
183 register_savevm("s3c2410_nand", 0, 0, s3c2410_nand_save
, s3c2410_nand_load
, nand
);
184 return &nand
->driver
;