Add rotation of the screen with portrait option.
[qemu/mini2440.git] / hw / s3c2440_nand.c
blobd727fbb2bed954e8b74326782f07fcdc8943463a
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 NANDFlashState *nand;
21 uint16_t nfconf;
22 uint16_t nfcont;
23 uint8_t nfcmd;
24 uint32_t nfaddr;
25 ECCState nfecc;
26 ECCState nfsecc; /* spare area */
27 int nfwp;
29 uint32_t nfaddr_cur;
30 uint32_t nfsblk;
31 uint32_t nfeblk;
35 extern struct s3c_state_s *g_s3c;
37 /* NAND Flash controller */
38 #define S3C_NFCONF 0x00 /* NAND Flash Configuration register */
40 #define S3C_NFCONT 0x04 /* NAND Flash Configuration register */
41 #define S3C_NFCONT_MODE (1 << 0) /* NAND flash controller operating mode */
42 #define S3C_NFCONT_CE (1 << 1) /* NAND Flash Memory nFCE signal control 0: active) */
43 #define S3C_NFCONT_INITECC (1 << 4) /* Initialize ECC decoder/encoder(Write-only) */
44 #define S3C_NFCONT_MECCL (1 << 5) /* Lock Main data area ECC generation */
45 #define S3C_NFCONT_SECCL (1 << 6) /* Lock spare area ECC generation */
46 #define S3C_NFCONT_SLOCK (1 << 12) /* Soft Lock configuration */
47 #define S3C_NFCONT_TLOCK (1 << 13) /* Lock-tight configuration */
48 #define S3C_NFCONT_LOCK (S3C_NFCONT_SLOCK | S3C_NFCONT_TLOCK)
50 #define S3C_NFCMD 0x08 /* NAND Flash Command Set register */
51 #define S3C_NFADDR 0x0c /* NAND Flash Address Set register */
52 #define S3C_NFDATA 0x10 /* NAND Flash Data register */
54 #define S3C_NFMECCD0 0x14 /* NAND Flash ECC register : 1st and 2d ecc*/
55 #define S3C_NFMECCD1 0x18 /* NAND Flash ECC register : 3rd and 4th (unimplemented) */
56 #define S3C_NFSECCD 0x1c /* NAND Flash ECC register Spare Area */
58 #define S3C_NFSTAT 0x20 /* NAND Flash Operation Status register */
60 #define S3C_NFESTAT0 0x24 /* NAND flash ECC Status register for I/O [7:0] (unimplemented)*/
61 #define S3C_NFESTAT1 0x28 /* NAND flash ECC Status register for I/O [15:8] (unimplemented)*/
63 #define S3C_NFMECC0 0x2c /* NAND flash ECC register for data[7:0] (unimplemented)*/
64 #define S3C_NFMECC1 0x30 /* NAND flash ECC register for data[15:8] (unimplemented)*/
65 #define S3C_NFSECC 0x34 /* NAND flash ECC register for I/O [15:0] (spare area) (unimplemented)*/
67 #define S3C_NFSBLK 0x38 /* NAND flash programmable start block address (unimplemented)*/
68 #define S3C_NFEBLK 0x3c /* NAND flash programmable end block address (unimplemented)*/
70 static void s3c2440_nand_reset(void * opaque)
72 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *)opaque;
73 s->nfconf = 0x1000 |
74 (0 << 3) | /* NCON0: not an advanced flash */
75 (1 << 2) | /* GPG13: 0: 256 Word/page, 1: 512 Bytes/page */
76 (1 << 1) | /* GPG14: 0: 3 address cycle 1: 4 address cycle */
77 (0 << 2) /* GPG15: 0: 8-bit bus 1: 16-bit bus */
79 s->nfcont = 0x0384;
80 s->nfcmd = 0;
81 s->nfaddr = 0;
82 s->nfsblk = 0;
83 s->nfeblk = 0;
84 ecc_reset(&s->nfecc);
85 ecc_reset(&s->nfsecc);
88 static uint8_t dbu[16],cmd;
90 static uint32_t s3c2440_nand_read(void *opaque, target_phys_addr_t addr)
92 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
93 int rb, shr = 0;
94 if (!s->nand)
95 return 0;
97 switch (addr) {
98 case S3C_NFCONF:
99 return s->nfconf;
100 case S3C_NFCONT:
101 return s->nfcont;
102 case S3C_NFCMD:
103 return s->nfcmd;
104 case S3C_NFADDR:
105 return s->nfaddr >> 24; // last 8 bits poked
106 case S3C_NFDATA:
107 if (s->nfcont & S3C_NFCONT_MODE) {
108 uint32_t value = nand_getio(s->nand);
110 if (s->nfaddr_cur < 512) {
111 if (!(s->nfcont & S3C_NFCONT_MECCL)) {
112 value = ecc_digest(&s->nfecc, value & 0xff);
113 /* printf("ecc %02x -> %08x %08x cp %08x cnt %d\n", value, s->nfecc.lp[0], s->nfecc.lp[1], s->nfecc.cp, s->nfecc.count); */
115 } else {
116 if (!(s->nfcont & S3C_NFCONT_SECCL))
117 value = ecc_digest(&s->nfsecc, value & 0xff);
119 if (s->nfaddr_cur < 16) dbu[s->nfaddr_cur] = value;
120 s->nfaddr_cur++;
121 return value;
123 break;
124 case S3C_NFSTAT:
125 nand_getpins(s->nand, &rb);
126 return rb;
127 case S3C_NFMECCD0 + 3: shr += 8;
128 case S3C_NFMECCD0 + 2: shr += 8;
129 case S3C_NFMECCD0 + 1: shr += 8;
130 case S3C_NFMECCD0: {
131 #define ECC(shr, b, shl) ((s->nfecc.lp[b] << (shl - shr)) & (1 << shl))
132 uint32 ecc = ~(
133 ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) | ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) |
134 ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) | ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) |
135 ECC(8, 1, 16) | ECC(8, 0, 17) | ((s->nfecc.cp & 0x3f) << 18) |
136 ECC(9, 1, 28) | ECC(9, 0, 29) | ECC(10, 1, 30) | ECC(10, 0, 31)
138 /* printf("Read ECC %02x = %08x >> %d [ 0: %08x 1: %08x cnt %d ]\n", addr, ecc, shr, s->nfecc.lp[0], s->nfecc.lp[1], s->nfecc.count); */
139 ecc = (ecc >> shr) & 0xff;
140 return ecc;
141 } break;
142 case S3C_NFMECCD1 + 3:
143 case S3C_NFMECCD1 + 2:
144 case S3C_NFMECCD1 + 1:
145 case S3C_NFMECCD1:
146 /* the ecc digester is limited to 2, the s3c2440 can do 4... */
147 printf("%s: Bad register S3C_NFECCD1 NOT HANDLED\n", __FUNCTION__);
148 break;
149 #undef ECC
151 case S3C_NFSECCD + 3: shr += 8;
152 case S3C_NFSECCD + 2: shr += 8;
153 case S3C_NFSECCD + 1: shr += 8;
154 case S3C_NFSECCD:
155 #define ECC(shr, b, shl) ((s->nfsecc.lp[b] << (shl - shr)) & (1 << shl))
156 return (~(
157 ECC(0, 1, 0) | ECC(0, 0, 1) | ECC(1, 1, 2) | ECC(1, 0, 3) | ECC(2, 1, 4) | ECC(2, 0, 5) | ECC(3, 1, 6) | ECC(3, 0, 7) |
158 ECC(4, 1, 8) | ECC(4, 0, 9) | ECC(5, 1, 10) | ECC(5, 0, 11) | ECC(6, 1, 12) | ECC(6, 0, 13) | ECC(7, 1, 14) | ECC(7, 0, 15) |
159 ECC(8, 1, 16) | ECC(8, 0, 17) | ((s->nfecc.cp & 0x3f) << 18) |
160 ECC(9, 1, 28) | ECC(9, 0, 29) | ECC(10, 1, 30) | ECC(10, 0, 31)
161 ) >> shr) &
162 0xff;
163 #undef ECC
165 case S3C_NFSBLK:
166 return s->nfsblk;
167 case S3C_NFEBLK:
168 return s->nfeblk;
170 default:
171 printf("%s: Bad register 0x%lx\n", __FUNCTION__, (unsigned long)addr);
172 break;
174 return 0;
178 * 16 and 32 bits access to NFDATA. u-boot uses the 16 bits acess, and the kernel uses
179 * the 32 bits one extensively.
181 static uint32_t s3c2440_nand_read16(void *opaque, target_phys_addr_t addr)
183 uint32_t res = s3c2440_nand_read(opaque, addr);
184 if (addr == S3C_NFDATA)
185 res = (s3c2440_nand_read(opaque, addr) << 8) | (res & 0xff);
186 return res;
189 static uint32_t s3c2440_nand_read32(void *opaque, target_phys_addr_t addr)
191 uint32_t res = s3c2440_nand_read16(opaque, addr);
193 if (addr == S3C_NFDATA) {
194 res = (s3c2440_nand_read16(opaque, addr) << 16) | (res & 0xffff);
196 return res;
199 static void s3c2440_nand_write(void *opaque, target_phys_addr_t addr,
200 uint32_t value)
202 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
203 if (!s->nand)
204 return;
206 static int did_write =0;
208 switch (addr) {
209 case S3C_NFCONF:
210 s->nfconf = (s->nfconf & 0xe) | (value & 0xfff1);
211 break;
212 case S3C_NFCONT:
213 if (value & S3C_NFCONT_INITECC) {
214 ecc_reset(&s->nfecc);
215 ecc_reset(&s->nfsecc);
217 /* tight lock is sticky */
218 s->nfcont = (value & (0xffff ^ S3C_NFCONT_INITECC)) | (s->nfcont & S3C_NFCONT_TLOCK);
219 break;
220 case S3C_NFCMD:
221 s->nfcmd = value & 0xff;
222 if (s->nfcont & S3C_NFCONT_MODE) {
223 nand_setpins(s->nand, 1, 0, s->nfcont & S3C_NFCONT_CE, s->nfwp, 0);
224 nand_setio(s->nand, s->nfcmd);
225 nand_setpins(s->nand, 0, 0, s->nfcont & S3C_NFCONT_CE, s->nfwp, 0);
227 break;
228 case S3C_NFSTAT: // it's OK to write to this on the 2440
229 break;
230 case S3C_NFADDR:
231 #if 0
232 if (s->nfaddr_cur) {
233 int i;
234 printf("%08x cmd %02x : %s %d bytes : ", s->nfaddr<<1, cmd, did_write ? "wrote" : "read", s->nfaddr_cur);
235 for (i=0; i < 16 && i < s->nfaddr_cur; i++) printf("%02x ", dbu[i]);
236 printf("\n");
238 did_write = 0;
239 cmd = s->nfcmd;
240 #endif
242 s->nfaddr = (s->nfaddr >> 8) | (value << 24);
243 s->nfaddr_cur = 0;
244 if (s->nfcont & S3C_NFCONT_MODE) {
245 nand_setpins(s->nand, 0, 1, s->nfcont & S3C_NFCONT_CE, s->nfwp, 0);
246 nand_setio(s->nand, value & 0xff);
247 nand_setpins(s->nand, 0, 0, s->nfcont & S3C_NFCONT_CE, s->nfwp, 0);
249 break;
250 case S3C_NFDATA:
251 if (s->nfcont & S3C_NFCONT_MODE) {
252 if (s->nfcont & S3C_NFCONT_LOCK) {
253 if (s->nfaddr_cur < (s->nfsblk << 6) ||
254 s->nfaddr_cur > (s->nfeblk << 6)) {
255 /* TODO: ADD IRQ */
256 break;
259 if (s->nfaddr_cur < 512) {
260 if (!(s->nfcont & S3C_NFCONT_MECCL)) {
261 value = ecc_digest(&s->nfecc, value & 0xff);
262 /* printf("ecc %02x -> %08x %08x cp %08x cnt %d\n", value, s->nfecc.lp[0], s->nfecc.lp[1], s->nfecc.cp, s->nfecc.count); */
264 } else {
265 if (!(s->nfcont & S3C_NFCONT_SECCL))
266 value = ecc_digest(&s->nfsecc, value & 0xff);
268 did_write=1;
269 if (s->nfaddr_cur < 16) dbu[s->nfaddr_cur] = value;
270 s->nfaddr_cur++;
271 nand_setio(s->nand, value & 0xff);
273 break;
274 case S3C_NFSBLK:
275 s->nfsblk = value & 0xffffff;
276 /* printf("%s: S3C_NFSBLK set to 0x%x\n", __FUNCTION__, value); */
277 break;
278 case S3C_NFEBLK:
279 s->nfeblk = value & 0xffffff;
280 /* printf("%s: S3C_NFEBLK set to 0x%x\n", __FUNCTION__, value); */
281 break;
283 default:
284 printf("%s: Bad register 0x%lx=%x\n", __FUNCTION__, (unsigned long)addr, value);
289 * 16 and 32 bits access to NFDATA. u-boot uses the 16 bits acess, and the kernel uses
290 * the 32 bits one extensively.
292 static void s3c2440_nand_write16(void *opaque, target_phys_addr_t addr,
293 uint32_t value)
295 s3c2440_nand_write(opaque, addr, value);
296 if (addr == S3C_NFDATA) {
297 s3c2440_nand_write(opaque, addr, value >> 8);
301 static void s3c2440_nand_write32(void *opaque, target_phys_addr_t addr,
302 uint32_t value)
304 s3c2440_nand_write16(opaque, addr, value);
305 if (addr == S3C_NFDATA) {
306 s3c2440_nand_write16(opaque, addr, value >> 16);
310 static void s3c2440_nand_register(void * opaque, NANDFlashState *chip)
312 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
313 s->nand = chip;
316 static void s3c2440_nand_setwp(void * opaque, int wp)
318 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
319 s->nfwp = wp;
322 static CPUReadMemoryFunc *s3c2440_nand_readfn[] = {
323 s3c2440_nand_read,
324 s3c2440_nand_read16,
325 s3c2440_nand_read32,
328 static CPUWriteMemoryFunc *s3c2440_nand_writefn[] = {
329 s3c2440_nand_write,
330 s3c2440_nand_write16,
331 s3c2440_nand_write32,
334 static void s3c2440_nand_save(QEMUFile *f, void *opaque)
336 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
337 qemu_put_be16s(f, &s->nfconf);
338 qemu_put_be16s(f, &s->nfcont);
339 qemu_put_8s(f, &s->nfcmd);
340 qemu_put_be32s(f, &s->nfaddr);
341 qemu_put_be32(f, s->nfwp);
342 ecc_put(f, &s->nfecc);
345 static int s3c2440_nand_load(QEMUFile *f, void *opaque, int version_id)
347 struct s3c2440_nand_s *s = (struct s3c2440_nand_s *) opaque;
348 qemu_get_be16s(f, &s->nfconf);
349 qemu_get_be16s(f, &s->nfcont);
350 qemu_get_8s(f, &s->nfcmd);
351 qemu_get_be32s(f, &s->nfaddr);
352 s->nfwp = qemu_get_be32(f);
353 ecc_get(f, &s->nfecc);
354 return 0;
357 static const struct s3c_nand_driver_s s3c2440_nand_driver = {
358 .reset = s3c2440_nand_reset,
359 .setwp = s3c2440_nand_setwp,
360 .reg = s3c2440_nand_register
363 struct s3c_nand_driver_s * s3c2440_nand_init(void)
365 int iomemtype;
366 struct s3c2440_nand_s *nand = (struct s3c2440_nand_s *)
367 qemu_mallocz(sizeof(struct s3c2440_nand_s));
368 nand->driver = s3c2440_nand_driver;
369 nand->nand_base = 0x4e000000;
370 nand->driver.reset(nand);
371 iomemtype = cpu_register_io_memory(0, s3c2440_nand_readfn, s3c2440_nand_writefn, nand);
372 cpu_register_physical_memory(nand->nand_base, 0xffffff, iomemtype);
373 register_savevm("s3c2440_nand", 0, 0, s3c2440_nand_save, s3c2440_nand_load, nand);
374 return &nand->driver;