Merge remote-tracking branch 'qemu/master'
[qemu/ar7.git] / hw / arm / s3c24xx_nand.c
bloba2aa0f641da91961b892b7d5dd5bb8cd4fc9ed80
1 /* hw/s3c24xx_nand.c
3 * Samsung S3C24XX NAND emulation
5 * Copyright 2006, 2008 Ben Dooks, Daniel Silverstone and Vincent Sanders
7 * Copyright 2010, 2013 Stefan Weil
9 * This file is under the terms of the GNU General Public License Version 2.
12 #include "qemu/osdep.h"
13 #include "cpu.h"
14 #include "hw/hw.h"
15 #include "exec/address-spaces.h" /* get_system_memory */
17 #include "s3c24xx.h"
19 #define NFCONF 0
20 #define NFCMD 1
21 #define NFADDR 2
22 #define NFDATA 3
23 #define NFSTAT 4
24 #define NFECC 5
26 #define NFCE ((s->nand_reg[NFCONF] & 1<<11) != 0)
28 /* NAND controller state */
29 typedef struct s3c24xx_nand_state_s {
30 MemoryRegion mmio;
31 uint32_t nand_reg[13];
33 DeviceState *nand;
34 } S3C24xxNandState;
36 static void s3c24xx_nand_write(void *opaque, hwaddr addr,
37 uint64_t value, unsigned size)
39 S3C24xxNandState *s = opaque;
40 int reg = (addr & 0x1f) >> 2;
42 if ((reg != NFCONF) && ((s->nand_reg[NFCONF] & 1<<15) == 0)) {
43 return; /* Ignore the write, the nand is not enabled */
46 switch (reg) {
47 case NFCONF:
48 s->nand_reg[reg] = value;
49 if (s->nand != NULL)
50 nand_setpins(s->nand, 0, 0, NFCE, 1, 0);
51 break;
53 case NFCMD:
54 s->nand_reg[reg] = value;
55 if (s->nand != NULL) {
56 nand_setpins(s->nand, 1, 0, NFCE, 1, 0);
57 nand_setio(s->nand, value);
59 break;
61 case NFADDR:
62 s->nand_reg[reg] = value;
63 if (s->nand != NULL) {
64 nand_setpins(s->nand, 0, 1, NFCE, 1, 0);
65 nand_setio(s->nand, value);
67 break;
69 case NFDATA:
70 s->nand_reg[reg] = value;
71 if (s->nand != NULL) {
72 nand_setpins(s->nand, 0, 0, NFCE, 1, 0);
73 nand_setio(s->nand, value);
75 break;
77 default:
78 /* Do nothing because the other registers are read only */
79 break;
83 static uint64_t s3c24xx_nand_read(void *opaque, hwaddr addr,
84 unsigned size)
86 S3C24xxNandState *s = opaque;
87 int reg = (addr & 0x1f) >> 2;
88 int value = 0;
89 uint32_t ret = s->nand_reg[reg];
91 switch (reg) {
92 case NFDATA:
93 if (s->nand != NULL) {
94 nand_setpins(s->nand, 0, 0, NFCE, 1, 0);
95 value = nand_getio(s->nand);
97 ret = s->nand_reg[ret] = value;
98 break;
100 case NFSTAT:
101 if (s->nand != NULL) {
102 nand_getpins(s->nand, &value);
104 ret = s->nand_reg[reg] = value;
106 default:
107 /* The rest read-back what was written to them */
108 break;
111 return ret;
114 static const MemoryRegionOps s3c24xx_nand_ops = {
115 .read = s3c24xx_nand_read,
116 .write = s3c24xx_nand_write,
117 .endianness = DEVICE_NATIVE_ENDIAN,
118 .valid = {
119 .min_access_size = 1,
120 .max_access_size = 4
124 struct s3c24xx_nand_state_s *s3c24xx_nand_init(hwaddr base_addr)
126 S3C24xxNandState *s = g_new0(S3C24xxNandState, 1);
128 memory_region_init_io(&s->mmio, OBJECT(s),
129 &s3c24xx_nand_ops, s, "s3c24xx.nand", 0x40);
130 memory_region_add_subregion(get_system_memory(), base_addr, &s->mmio);
132 return s;
135 void
136 s3c24xx_nand_attach(S3C24xxNandState *s, DeviceState *nand)
138 if (s->nand != NULL) {
139 /* Detach current nand device */
140 /* no cmd, no addr, not enabled, write protected, no 'gnd' */
141 nand_setpins(s->nand, 0, 0, 1, 0, 0);
143 s->nand = nand;