MINI2440: General update
[qemu/mini2440.git] / hw / s3c2410_nand.c
blobc906e58e9b23f7ad34dd965433051cb36817dc89
1 /*
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.
9 */
11 #include "s3c.h"
12 #include "hw.h"
14 struct s3c2410_nand_s {
15 struct s3c_nand_driver_s driver;
17 /* NAND Flash controller */
18 target_phys_addr_t nand_base;
19 NANDFlashState *nand;
20 uint16_t nfconf;
21 uint8_t nfcmd;
22 uint8_t nfaddr;
23 ECCState nfecc;
24 int nfwp;
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;
38 s->nfconf = 0;
39 s->nfcmd = 0;
40 s->nfaddr = 0;
41 ecc_reset(&s->nfecc);
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;
47 int rb, shr = 0;
48 if (!s->nand)
49 return 0;
51 switch (addr) {
52 case S3C_NFCONF:
53 return s->nfconf;
54 case S3C_NFCMD:
55 return s->nfcmd;
56 case S3C_NFADDR:
57 return s->nfaddr;
58 case S3C_NFDATA:
59 if (s->nfconf & (1 << 15))
60 return ecc_digest(&s->nfecc, nand_getio(s->nand));
61 break;
62 case S3C_NFSTAT:
63 nand_getpins(s->nand, &rb);
64 return rb;
65 case S3C_NFECC + 2: shr += 8;
66 case S3C_NFECC + 1: shr += 8;
67 case S3C_NFECC:
68 #define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl))
69 return (~(
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) &
75 0xff;
76 #undef ECC
77 default:
78 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
79 break;
81 return 0;
84 static void s3c2410_nand_write(void *opaque, target_phys_addr_t addr,
85 uint32_t value)
87 struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque;
88 if (!s->nand)
89 return;
91 switch (addr) {
92 case S3C_NFCONF:
93 s->nfconf = value & 0x9fff;
94 if (value & (1 << 12))
95 ecc_reset(&s->nfecc);
96 break;
97 case S3C_NFCMD:
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);
104 break;
105 case S3C_NFADDR:
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);
112 break;
113 case S3C_NFDATA:
114 if (s->nfconf & (1 << 15))
115 nand_setio(s->nand, ecc_digest(&s->nfecc, value & 0xff));
116 break;
117 default:
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;
125 s->nand = chip;
128 static void s3c2410_nand_setwp(void * opaque, int wp)
130 struct s3c2410_nand_s *s = (struct s3c2410_nand_s *) opaque;
131 s->nfwp = wp;
134 static CPUReadMemoryFunc *s3c2410_nand_readfn[] = {
135 s3c2410_nand_read,
136 s3c2410_nand_read,
137 s3c2410_nand_read,
140 static CPUWriteMemoryFunc *s3c2410_nand_writefn[] = {
141 s3c2410_nand_write,
142 s3c2410_nand_write,
143 s3c2410_nand_write,
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);
164 return 0;
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)
175 int iomemtype;
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;