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
;
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 s3c2440_nand_reset(void * opaque
)
37 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*)opaque
;
44 static uint32_t s3c2440_nand_read(void *opaque
, target_phys_addr_t addr
)
46 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
60 if (s
->nfconf
& (1 << 15))
61 return ecc_digest(&s
->nfecc
, nand_getio(s
->nand
));
64 nand_getpins(s
->nand
, &rb
);
66 case S3C_NFECC
+ 2: shr
+= 8;
67 case S3C_NFECC
+ 1: shr
+= 8;
69 #define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl))
71 ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) |
72 ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) |
73 ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) |
74 ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) |
75 ECC(8, 1, 16) | ECC(8, 0, 17) | (s
->nfecc
.cp
<< 18)) >> shr
) &
79 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
85 static void s3c2440_nand_write(void *opaque
, target_phys_addr_t addr
,
88 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
95 s
->nfconf
= value
& 0x9fff;
96 if (value
& (1 << 12))
100 s
->nfcmd
= value
& 0xff;
101 if (s
->nfconf
& (1 << 15)) {
102 nand_setpins(s
->nand
, 1, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
103 nand_setio(s
->nand
, s
->nfcmd
);
104 nand_setpins(s
->nand
, 0, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
108 s
->nfaddr
= value
& 0xff;
109 if (s
->nfconf
& (1 << 15)) {
110 nand_setpins(s
->nand
, 0, 1, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
111 nand_setio(s
->nand
, s
->nfaddr
);
112 nand_setpins(s
->nand
, 0, 0, (s
->nfconf
>> 11) & 1, s
->nfwp
, 0);
116 if (s
->nfconf
& (1 << 15))
117 nand_setio(s
->nand
, ecc_digest(&s
->nfecc
, value
& 0xff));
120 printf("%s: Bad register 0x%lx\n", __FUNCTION__
, (unsigned long)addr
);
124 static void s3c2440_nand_register(void * opaque
, struct nand_flash_s
*chip
)
126 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
130 static void s3c2440_nand_setwp(void * opaque
, int wp
)
132 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
136 static CPUReadMemoryFunc
*s3c2440_nand_readfn
[] = {
142 static CPUWriteMemoryFunc
*s3c2440_nand_writefn
[] = {
148 static void s3c2440_nand_save(QEMUFile
*f
, void *opaque
)
150 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
151 qemu_put_be16s(f
, &s
->nfconf
);
152 qemu_put_8s(f
, &s
->nfcmd
);
153 qemu_put_8s(f
, &s
->nfaddr
);
154 qemu_put_be32(f
, s
->nfwp
);
155 ecc_put(f
, &s
->nfecc
);
158 static int s3c2440_nand_load(QEMUFile
*f
, void *opaque
, int version_id
)
160 struct s3c2440_nand_s
*s
= (struct s3c2440_nand_s
*) opaque
;
161 qemu_get_be16s(f
, &s
->nfconf
);
162 qemu_get_8s(f
, &s
->nfcmd
);
163 qemu_get_8s(f
, &s
->nfaddr
);
164 s
->nfwp
= qemu_get_be32(f
);
165 ecc_get(f
, &s
->nfecc
);
169 static const struct s3c_nand_driver_s s3c2440_nand_driver
= {
170 .reset
= s3c2440_nand_reset
,
171 .setwp
= s3c2440_nand_setwp
,
172 .reg
= s3c2440_nand_register
175 struct s3c_nand_driver_s
* s3c2440_nand_init(void)
178 struct s3c2440_nand_s
*nand
= (struct s3c2440_nand_s
*)
179 qemu_mallocz(sizeof(struct s3c2440_nand_s
));
180 nand
->driver
= s3c2440_nand_driver
;
181 nand
->nand_base
= 0x4e000000;
182 nand
->driver
.reset(nand
);
183 iomemtype
= cpu_register_io_memory(0, s3c2440_nand_readfn
, s3c2440_nand_writefn
, nand
);
184 cpu_register_physical_memory(nand
->nand_base
, 0xffffff, iomemtype
);
185 register_savevm("s3c2440_nand", 0, 0, s3c2440_nand_save
, s3c2440_nand_load
, nand
);
186 return &nand
->driver
;