[S3C] Added placeholder for 2440 nand
[qemu/mini2440.git] / hw / s3c2440_nand.c
blobbae794b98ad40c3c4f82ac32be6169c31eb48456
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 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;
20 uint16_t nfconf;
21 uint8_t nfcmd;
22 uint8_t nfaddr;
23 struct ecc_state_s 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 s3c2440_nand_reset(void * opaque)
37 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *)opaque;
38 s->nfconf = 0;
39 s->nfcmd = 0;
40 s->nfaddr = 0;
41 ecc_reset(&s->nfecc);
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;
47 int rb, shr = 0;
48 if (!s->nand)
49 return 0;
50 addr -= s->nand_base;
52 switch (addr) {
53 case S3C_NFCONF:
54 return s->nfconf;
55 case S3C_NFCMD:
56 return s->nfcmd;
57 case S3C_NFADDR:
58 return s->nfaddr;
59 case S3C_NFDATA:
60 if (s->nfconf & (1 << 15))
61 return ecc_digest(&s->nfecc, nand_getio(s->nand));
62 break;
63 case S3C_NFSTAT:
64 nand_getpins(s->nand, &rb);
65 return rb;
66 case S3C_NFECC + 2: shr += 8;
67 case S3C_NFECC + 1: shr += 8;
68 case S3C_NFECC:
69 #define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl))
70 return (~(
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) &
76 0xff;
77 #undef ECC
78 default:
79 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
80 break;
82 return 0;
85 static void s3c2440_nand_write(void *opaque, target_phys_addr_t addr,
86 uint32_t value)
88 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
89 if (!s->nand)
90 return;
91 addr -= s->nand_base;
93 switch (addr) {
94 case S3C_NFCONF:
95 s->nfconf = value & 0x9fff;
96 if (value & (1 << 12))
97 ecc_reset(&s->nfecc);
98 break;
99 case S3C_NFCMD:
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);
106 break;
107 case S3C_NFADDR:
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);
114 break;
115 case S3C_NFDATA:
116 if (s->nfconf & (1 << 15))
117 nand_setio(s->nand, ecc_digest(&s->nfecc, value & 0xff));
118 break;
119 default:
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;
127 s->nand = chip;
130 static void s3c2440_nand_setwp(void * opaque, int wp)
132 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
133 s->nfwp = wp;
136 static CPUReadMemoryFunc *s3c2440_nand_readfn[] = {
137 s3c2440_nand_read,
138 s3c2440_nand_read,
139 s3c2440_nand_read,
142 static CPUWriteMemoryFunc *s3c2440_nand_writefn[] = {
143 s3c2440_nand_write,
144 s3c2440_nand_write,
145 s3c2440_nand_write,
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);
166 return 0;
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)
177 int iomemtype;
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;