Statistics
| Branch: | Revision:

root / hw / omap_gpmc.c @ e7b43f7e

History | View | Annotate | Download (12.3 kB)

1 f3354b0e cmchao
/*
2 f3354b0e cmchao
 * TI OMAP general purpose memory controller emulation.
3 f3354b0e cmchao
 *
4 f3354b0e cmchao
 * Copyright (C) 2007-2009 Nokia Corporation
5 f3354b0e cmchao
 * Original code written by Andrzej Zaborowski <andrew@openedhand.com>
6 f3354b0e cmchao
 * Enhancements for OMAP3 and NAND support written by Juha Riihimäki
7 f3354b0e cmchao
 *
8 f3354b0e cmchao
 * This program is free software; you can redistribute it and/or
9 f3354b0e cmchao
 * modify it under the terms of the GNU General Public License as
10 f3354b0e cmchao
 * published by the Free Software Foundation; either version 2 or
11 f3354b0e cmchao
 * (at your option) any later version of the License.
12 f3354b0e cmchao
 *
13 f3354b0e cmchao
 * This program is distributed in the hope that it will be useful,
14 f3354b0e cmchao
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 f3354b0e cmchao
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 f3354b0e cmchao
 * GNU General Public License for more details.
17 f3354b0e cmchao
 *
18 f3354b0e cmchao
 * You should have received a copy of the GNU General Public License along
19 f3354b0e cmchao
 * with this program; if not, see <http://www.gnu.org/licenses/>.
20 f3354b0e cmchao
 */
21 f3354b0e cmchao
#include "hw.h"
22 f3354b0e cmchao
#include "flash.h"
23 f3354b0e cmchao
#include "omap.h"
24 f3354b0e cmchao
25 f3354b0e cmchao
/* General-Purpose Memory Controller */
26 f3354b0e cmchao
struct omap_gpmc_s {
27 f3354b0e cmchao
    qemu_irq irq;
28 f3354b0e cmchao
29 f3354b0e cmchao
    uint8_t sysconfig;
30 f3354b0e cmchao
    uint16_t irqst;
31 f3354b0e cmchao
    uint16_t irqen;
32 f3354b0e cmchao
    uint16_t timeout;
33 f3354b0e cmchao
    uint16_t config;
34 f3354b0e cmchao
    uint32_t prefconfig[2];
35 f3354b0e cmchao
    int prefcontrol;
36 f3354b0e cmchao
    int preffifo;
37 f3354b0e cmchao
    int prefcount;
38 f3354b0e cmchao
    struct omap_gpmc_cs_file_s {
39 f3354b0e cmchao
        uint32_t config[7];
40 f3354b0e cmchao
        target_phys_addr_t base;
41 f3354b0e cmchao
        size_t size;
42 f3354b0e cmchao
        int iomemtype;
43 f3354b0e cmchao
        void (*base_update)(void *opaque, target_phys_addr_t new);
44 f3354b0e cmchao
        void (*unmap)(void *opaque);
45 f3354b0e cmchao
        void *opaque;
46 f3354b0e cmchao
    } cs_file[8];
47 f3354b0e cmchao
    int ecc_cs;
48 f3354b0e cmchao
    int ecc_ptr;
49 f3354b0e cmchao
    uint32_t ecc_cfg;
50 f3354b0e cmchao
    ECCState ecc[9];
51 f3354b0e cmchao
};
52 f3354b0e cmchao
53 f3354b0e cmchao
static void omap_gpmc_int_update(struct omap_gpmc_s *s)
54 f3354b0e cmchao
{
55 f3354b0e cmchao
    qemu_set_irq(s->irq, s->irqen & s->irqst);
56 f3354b0e cmchao
}
57 f3354b0e cmchao
58 f3354b0e cmchao
static void omap_gpmc_cs_map(struct omap_gpmc_cs_file_s *f, int base, int mask)
59 f3354b0e cmchao
{
60 f3354b0e cmchao
    /* TODO: check for overlapping regions and report access errors */
61 f3354b0e cmchao
    if ((mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf) ||
62 f3354b0e cmchao
                    (base < 0 || base >= 0x40) ||
63 f3354b0e cmchao
                    (base & 0x0f & ~mask)) {
64 f3354b0e cmchao
        fprintf(stderr, "%s: wrong cs address mapping/decoding!\n",
65 f3354b0e cmchao
                        __FUNCTION__);
66 f3354b0e cmchao
        return;
67 f3354b0e cmchao
    }
68 f3354b0e cmchao
69 f3354b0e cmchao
    if (!f->opaque)
70 f3354b0e cmchao
        return;
71 f3354b0e cmchao
72 f3354b0e cmchao
    f->base = base << 24;
73 f3354b0e cmchao
    f->size = (0x0fffffff & ~(mask << 24)) + 1;
74 f3354b0e cmchao
    /* TODO: rather than setting the size of the mapping (which should be
75 f3354b0e cmchao
     * constant), the mask should cause wrapping of the address space, so
76 f3354b0e cmchao
     * that the same memory becomes accessible at every <i>size</i> bytes
77 f3354b0e cmchao
     * starting from <i>base</i>.  */
78 f3354b0e cmchao
    if (f->iomemtype)
79 f3354b0e cmchao
        cpu_register_physical_memory(f->base, f->size, f->iomemtype);
80 f3354b0e cmchao
81 f3354b0e cmchao
    if (f->base_update)
82 f3354b0e cmchao
        f->base_update(f->opaque, f->base);
83 f3354b0e cmchao
}
84 f3354b0e cmchao
85 f3354b0e cmchao
static void omap_gpmc_cs_unmap(struct omap_gpmc_cs_file_s *f)
86 f3354b0e cmchao
{
87 f3354b0e cmchao
    if (f->size) {
88 f3354b0e cmchao
        if (f->unmap)
89 f3354b0e cmchao
            f->unmap(f->opaque);
90 f3354b0e cmchao
        if (f->iomemtype)
91 f3354b0e cmchao
            cpu_register_physical_memory(f->base, f->size, IO_MEM_UNASSIGNED);
92 f3354b0e cmchao
        f->base = 0;
93 f3354b0e cmchao
        f->size = 0;
94 f3354b0e cmchao
    }
95 f3354b0e cmchao
}
96 f3354b0e cmchao
97 f3354b0e cmchao
void omap_gpmc_reset(struct omap_gpmc_s *s)
98 f3354b0e cmchao
{
99 f3354b0e cmchao
    int i;
100 f3354b0e cmchao
101 f3354b0e cmchao
    s->sysconfig = 0;
102 f3354b0e cmchao
    s->irqst = 0;
103 f3354b0e cmchao
    s->irqen = 0;
104 f3354b0e cmchao
    omap_gpmc_int_update(s);
105 f3354b0e cmchao
    s->timeout = 0;
106 f3354b0e cmchao
    s->config = 0xa00;
107 f3354b0e cmchao
    s->prefconfig[0] = 0x00004000;
108 f3354b0e cmchao
    s->prefconfig[1] = 0x00000000;
109 f3354b0e cmchao
    s->prefcontrol = 0;
110 f3354b0e cmchao
    s->preffifo = 0;
111 f3354b0e cmchao
    s->prefcount = 0;
112 f3354b0e cmchao
    for (i = 0; i < 8; i ++) {
113 f3354b0e cmchao
        if (s->cs_file[i].config[6] & (1 << 6))                        /* CSVALID */
114 f3354b0e cmchao
            omap_gpmc_cs_unmap(s->cs_file + i);
115 f3354b0e cmchao
        s->cs_file[i].config[0] = i ? 1 << 12 : 0;
116 f3354b0e cmchao
        s->cs_file[i].config[1] = 0x101001;
117 f3354b0e cmchao
        s->cs_file[i].config[2] = 0x020201;
118 f3354b0e cmchao
        s->cs_file[i].config[3] = 0x10031003;
119 f3354b0e cmchao
        s->cs_file[i].config[4] = 0x10f1111;
120 f3354b0e cmchao
        s->cs_file[i].config[5] = 0;
121 f3354b0e cmchao
        s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
122 f3354b0e cmchao
        if (s->cs_file[i].config[6] & (1 << 6))                        /* CSVALID */
123 f3354b0e cmchao
            omap_gpmc_cs_map(&s->cs_file[i],
124 f3354b0e cmchao
                            s->cs_file[i].config[6] & 0x1f,        /* MASKADDR */
125 f3354b0e cmchao
                        (s->cs_file[i].config[6] >> 8 & 0xf));        /* BASEADDR */
126 f3354b0e cmchao
    }
127 f3354b0e cmchao
    omap_gpmc_cs_map(s->cs_file, 0, 0xf);
128 f3354b0e cmchao
    s->ecc_cs = 0;
129 f3354b0e cmchao
    s->ecc_ptr = 0;
130 f3354b0e cmchao
    s->ecc_cfg = 0x3fcff000;
131 f3354b0e cmchao
    for (i = 0; i < 9; i ++)
132 f3354b0e cmchao
        ecc_reset(&s->ecc[i]);
133 f3354b0e cmchao
}
134 f3354b0e cmchao
135 f3354b0e cmchao
static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr)
136 f3354b0e cmchao
{
137 f3354b0e cmchao
    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
138 f3354b0e cmchao
    int cs;
139 f3354b0e cmchao
    struct omap_gpmc_cs_file_s *f;
140 f3354b0e cmchao
141 f3354b0e cmchao
    switch (addr) {
142 f3354b0e cmchao
    case 0x000:        /* GPMC_REVISION */
143 f3354b0e cmchao
        return 0x20;
144 f3354b0e cmchao
145 f3354b0e cmchao
    case 0x010:        /* GPMC_SYSCONFIG */
146 f3354b0e cmchao
        return s->sysconfig;
147 f3354b0e cmchao
148 f3354b0e cmchao
    case 0x014:        /* GPMC_SYSSTATUS */
149 f3354b0e cmchao
        return 1;                                                /* RESETDONE */
150 f3354b0e cmchao
151 f3354b0e cmchao
    case 0x018:        /* GPMC_IRQSTATUS */
152 f3354b0e cmchao
        return s->irqst;
153 f3354b0e cmchao
154 f3354b0e cmchao
    case 0x01c:        /* GPMC_IRQENABLE */
155 f3354b0e cmchao
        return s->irqen;
156 f3354b0e cmchao
157 f3354b0e cmchao
    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
158 f3354b0e cmchao
        return s->timeout;
159 f3354b0e cmchao
160 f3354b0e cmchao
    case 0x044:        /* GPMC_ERR_ADDRESS */
161 f3354b0e cmchao
    case 0x048:        /* GPMC_ERR_TYPE */
162 f3354b0e cmchao
        return 0;
163 f3354b0e cmchao
164 f3354b0e cmchao
    case 0x050:        /* GPMC_CONFIG */
165 f3354b0e cmchao
        return s->config;
166 f3354b0e cmchao
167 f3354b0e cmchao
    case 0x054:        /* GPMC_STATUS */
168 f3354b0e cmchao
        return 0x001;
169 f3354b0e cmchao
170 f3354b0e cmchao
    case 0x060 ... 0x1d4:
171 f3354b0e cmchao
        cs = (addr - 0x060) / 0x30;
172 f3354b0e cmchao
        addr -= cs * 0x30;
173 f3354b0e cmchao
        f = s->cs_file + cs;
174 f3354b0e cmchao
        switch (addr) {
175 f3354b0e cmchao
            case 0x60:        /* GPMC_CONFIG1 */
176 f3354b0e cmchao
                return f->config[0];
177 f3354b0e cmchao
            case 0x64:        /* GPMC_CONFIG2 */
178 f3354b0e cmchao
                return f->config[1];
179 f3354b0e cmchao
            case 0x68:        /* GPMC_CONFIG3 */
180 f3354b0e cmchao
                return f->config[2];
181 f3354b0e cmchao
            case 0x6c:        /* GPMC_CONFIG4 */
182 f3354b0e cmchao
                return f->config[3];
183 f3354b0e cmchao
            case 0x70:        /* GPMC_CONFIG5 */
184 f3354b0e cmchao
                return f->config[4];
185 f3354b0e cmchao
            case 0x74:        /* GPMC_CONFIG6 */
186 f3354b0e cmchao
                return f->config[5];
187 f3354b0e cmchao
            case 0x78:        /* GPMC_CONFIG7 */
188 f3354b0e cmchao
                return f->config[6];
189 f3354b0e cmchao
            case 0x84:        /* GPMC_NAND_DATA */
190 f3354b0e cmchao
                return 0;
191 f3354b0e cmchao
        }
192 f3354b0e cmchao
        break;
193 f3354b0e cmchao
194 f3354b0e cmchao
    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
195 f3354b0e cmchao
        return s->prefconfig[0];
196 f3354b0e cmchao
    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
197 f3354b0e cmchao
        return s->prefconfig[1];
198 f3354b0e cmchao
    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
199 f3354b0e cmchao
        return s->prefcontrol;
200 f3354b0e cmchao
    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
201 f3354b0e cmchao
        return (s->preffifo << 24) |
202 f3354b0e cmchao
                ((s->preffifo >
203 f3354b0e cmchao
                  ((s->prefconfig[0] >> 8) & 0x7f) ? 1 : 0) << 16) |
204 f3354b0e cmchao
                s->prefcount;
205 f3354b0e cmchao
206 f3354b0e cmchao
    case 0x1f4:        /* GPMC_ECC_CONFIG */
207 f3354b0e cmchao
        return s->ecc_cs;
208 f3354b0e cmchao
    case 0x1f8:        /* GPMC_ECC_CONTROL */
209 f3354b0e cmchao
        return s->ecc_ptr;
210 f3354b0e cmchao
    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
211 f3354b0e cmchao
        return s->ecc_cfg;
212 f3354b0e cmchao
    case 0x200 ... 0x220:        /* GPMC_ECC_RESULT */
213 f3354b0e cmchao
        cs = (addr & 0x1f) >> 2;
214 f3354b0e cmchao
        /* TODO: check correctness */
215 f3354b0e cmchao
        return
216 f3354b0e cmchao
                ((s->ecc[cs].cp    &  0x07) <<  0) |
217 f3354b0e cmchao
                ((s->ecc[cs].cp    &  0x38) << 13) |
218 f3354b0e cmchao
                ((s->ecc[cs].lp[0] & 0x1ff) <<  3) |
219 f3354b0e cmchao
                ((s->ecc[cs].lp[1] & 0x1ff) << 19);
220 f3354b0e cmchao
221 f3354b0e cmchao
    case 0x230:        /* GPMC_TESTMODE_CTRL */
222 f3354b0e cmchao
        return 0;
223 f3354b0e cmchao
    case 0x234:        /* GPMC_PSA_LSB */
224 f3354b0e cmchao
    case 0x238:        /* GPMC_PSA_MSB */
225 f3354b0e cmchao
        return 0x00000000;
226 f3354b0e cmchao
    }
227 f3354b0e cmchao
228 f3354b0e cmchao
    OMAP_BAD_REG(addr);
229 f3354b0e cmchao
    return 0;
230 f3354b0e cmchao
}
231 f3354b0e cmchao
232 f3354b0e cmchao
static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
233 f3354b0e cmchao
                uint32_t value)
234 f3354b0e cmchao
{
235 f3354b0e cmchao
    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
236 f3354b0e cmchao
    int cs;
237 f3354b0e cmchao
    struct omap_gpmc_cs_file_s *f;
238 f3354b0e cmchao
239 f3354b0e cmchao
    switch (addr) {
240 f3354b0e cmchao
    case 0x000:        /* GPMC_REVISION */
241 f3354b0e cmchao
    case 0x014:        /* GPMC_SYSSTATUS */
242 f3354b0e cmchao
    case 0x054:        /* GPMC_STATUS */
243 f3354b0e cmchao
    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
244 f3354b0e cmchao
    case 0x200 ... 0x220:        /* GPMC_ECC_RESULT */
245 f3354b0e cmchao
    case 0x234:        /* GPMC_PSA_LSB */
246 f3354b0e cmchao
    case 0x238:        /* GPMC_PSA_MSB */
247 f3354b0e cmchao
        OMAP_RO_REG(addr);
248 f3354b0e cmchao
        break;
249 f3354b0e cmchao
250 f3354b0e cmchao
    case 0x010:        /* GPMC_SYSCONFIG */
251 f3354b0e cmchao
        if ((value >> 3) == 0x3)
252 f3354b0e cmchao
            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
253 f3354b0e cmchao
                            __FUNCTION__, value >> 3);
254 f3354b0e cmchao
        if (value & 2)
255 f3354b0e cmchao
            omap_gpmc_reset(s);
256 f3354b0e cmchao
        s->sysconfig = value & 0x19;
257 f3354b0e cmchao
        break;
258 f3354b0e cmchao
259 f3354b0e cmchao
    case 0x018:        /* GPMC_IRQSTATUS */
260 f3354b0e cmchao
        s->irqen = ~value;
261 f3354b0e cmchao
        omap_gpmc_int_update(s);
262 f3354b0e cmchao
        break;
263 f3354b0e cmchao
264 f3354b0e cmchao
    case 0x01c:        /* GPMC_IRQENABLE */
265 f3354b0e cmchao
        s->irqen = value & 0xf03;
266 f3354b0e cmchao
        omap_gpmc_int_update(s);
267 f3354b0e cmchao
        break;
268 f3354b0e cmchao
269 f3354b0e cmchao
    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
270 f3354b0e cmchao
        s->timeout = value & 0x1ff1;
271 f3354b0e cmchao
        break;
272 f3354b0e cmchao
273 f3354b0e cmchao
    case 0x044:        /* GPMC_ERR_ADDRESS */
274 f3354b0e cmchao
    case 0x048:        /* GPMC_ERR_TYPE */
275 f3354b0e cmchao
        break;
276 f3354b0e cmchao
277 f3354b0e cmchao
    case 0x050:        /* GPMC_CONFIG */
278 f3354b0e cmchao
        s->config = value & 0xf13;
279 f3354b0e cmchao
        break;
280 f3354b0e cmchao
281 f3354b0e cmchao
    case 0x060 ... 0x1d4:
282 f3354b0e cmchao
        cs = (addr - 0x060) / 0x30;
283 f3354b0e cmchao
        addr -= cs * 0x30;
284 f3354b0e cmchao
        f = s->cs_file + cs;
285 f3354b0e cmchao
        switch (addr) {
286 f3354b0e cmchao
            case 0x60:        /* GPMC_CONFIG1 */
287 f3354b0e cmchao
                f->config[0] = value & 0xffef3e13;
288 f3354b0e cmchao
                break;
289 f3354b0e cmchao
            case 0x64:        /* GPMC_CONFIG2 */
290 f3354b0e cmchao
                f->config[1] = value & 0x001f1f8f;
291 f3354b0e cmchao
                break;
292 f3354b0e cmchao
            case 0x68:        /* GPMC_CONFIG3 */
293 f3354b0e cmchao
                f->config[2] = value & 0x001f1f8f;
294 f3354b0e cmchao
                break;
295 f3354b0e cmchao
            case 0x6c:        /* GPMC_CONFIG4 */
296 f3354b0e cmchao
                f->config[3] = value & 0x1f8f1f8f;
297 f3354b0e cmchao
                break;
298 f3354b0e cmchao
            case 0x70:        /* GPMC_CONFIG5 */
299 f3354b0e cmchao
                f->config[4] = value & 0x0f1f1f1f;
300 f3354b0e cmchao
                break;
301 f3354b0e cmchao
            case 0x74:        /* GPMC_CONFIG6 */
302 f3354b0e cmchao
                f->config[5] = value & 0x00000fcf;
303 f3354b0e cmchao
                break;
304 f3354b0e cmchao
            case 0x78:        /* GPMC_CONFIG7 */
305 f3354b0e cmchao
                if ((f->config[6] ^ value) & 0xf7f) {
306 f3354b0e cmchao
                    if (f->config[6] & (1 << 6))                /* CSVALID */
307 f3354b0e cmchao
                        omap_gpmc_cs_unmap(f);
308 f3354b0e cmchao
                    if (value & (1 << 6))                        /* CSVALID */
309 f3354b0e cmchao
                        omap_gpmc_cs_map(f, value & 0x1f,        /* MASKADDR */
310 f3354b0e cmchao
                                        (value >> 8 & 0xf));        /* BASEADDR */
311 f3354b0e cmchao
                }
312 f3354b0e cmchao
                f->config[6] = value & 0x00000f7f;
313 f3354b0e cmchao
                break;
314 f3354b0e cmchao
            case 0x7c:        /* GPMC_NAND_COMMAND */
315 f3354b0e cmchao
            case 0x80:        /* GPMC_NAND_ADDRESS */
316 f3354b0e cmchao
            case 0x84:        /* GPMC_NAND_DATA */
317 f3354b0e cmchao
                break;
318 f3354b0e cmchao
319 f3354b0e cmchao
            default:
320 f3354b0e cmchao
                goto bad_reg;
321 f3354b0e cmchao
        }
322 f3354b0e cmchao
        break;
323 f3354b0e cmchao
324 f3354b0e cmchao
    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
325 f3354b0e cmchao
        s->prefconfig[0] = value & 0x7f8f7fbf;
326 f3354b0e cmchao
        /* TODO: update interrupts, fifos, dmas */
327 f3354b0e cmchao
        break;
328 f3354b0e cmchao
329 f3354b0e cmchao
    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
330 f3354b0e cmchao
        s->prefconfig[1] = value & 0x3fff;
331 f3354b0e cmchao
        break;
332 f3354b0e cmchao
333 f3354b0e cmchao
    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
334 f3354b0e cmchao
        s->prefcontrol = value & 1;
335 f3354b0e cmchao
        if (s->prefcontrol) {
336 f3354b0e cmchao
            if (s->prefconfig[0] & 1)
337 f3354b0e cmchao
                s->preffifo = 0x40;
338 f3354b0e cmchao
            else
339 f3354b0e cmchao
                s->preffifo = 0x00;
340 f3354b0e cmchao
        }
341 f3354b0e cmchao
        /* TODO: start */
342 f3354b0e cmchao
        break;
343 f3354b0e cmchao
344 f3354b0e cmchao
    case 0x1f4:        /* GPMC_ECC_CONFIG */
345 f3354b0e cmchao
        s->ecc_cs = 0x8f;
346 f3354b0e cmchao
        break;
347 f3354b0e cmchao
    case 0x1f8:        /* GPMC_ECC_CONTROL */
348 f3354b0e cmchao
        if (value & (1 << 8))
349 f3354b0e cmchao
            for (cs = 0; cs < 9; cs ++)
350 f3354b0e cmchao
                ecc_reset(&s->ecc[cs]);
351 f3354b0e cmchao
        s->ecc_ptr = value & 0xf;
352 f3354b0e cmchao
        if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
353 f3354b0e cmchao
            s->ecc_ptr = 0;
354 f3354b0e cmchao
            s->ecc_cs &= ~1;
355 f3354b0e cmchao
        }
356 f3354b0e cmchao
        break;
357 f3354b0e cmchao
    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
358 f3354b0e cmchao
        s->ecc_cfg = value & 0x3fcff1ff;
359 f3354b0e cmchao
        break;
360 f3354b0e cmchao
    case 0x230:        /* GPMC_TESTMODE_CTRL */
361 f3354b0e cmchao
        if (value & 7)
362 f3354b0e cmchao
            fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__);
363 f3354b0e cmchao
        break;
364 f3354b0e cmchao
365 f3354b0e cmchao
    default:
366 f3354b0e cmchao
    bad_reg:
367 f3354b0e cmchao
        OMAP_BAD_REG(addr);
368 f3354b0e cmchao
        return;
369 f3354b0e cmchao
    }
370 f3354b0e cmchao
}
371 f3354b0e cmchao
372 f3354b0e cmchao
static CPUReadMemoryFunc * const omap_gpmc_readfn[] = {
373 f3354b0e cmchao
    omap_badwidth_read32,        /* TODO */
374 f3354b0e cmchao
    omap_badwidth_read32,        /* TODO */
375 f3354b0e cmchao
    omap_gpmc_read,
376 f3354b0e cmchao
};
377 f3354b0e cmchao
378 f3354b0e cmchao
static CPUWriteMemoryFunc * const omap_gpmc_writefn[] = {
379 f3354b0e cmchao
    omap_badwidth_write32,        /* TODO */
380 f3354b0e cmchao
    omap_badwidth_write32,        /* TODO */
381 f3354b0e cmchao
    omap_gpmc_write,
382 f3354b0e cmchao
};
383 f3354b0e cmchao
384 f3354b0e cmchao
struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq)
385 f3354b0e cmchao
{
386 f3354b0e cmchao
    int iomemtype;
387 f3354b0e cmchao
    struct omap_gpmc_s *s = (struct omap_gpmc_s *)
388 f3354b0e cmchao
            qemu_mallocz(sizeof(struct omap_gpmc_s));
389 f3354b0e cmchao
390 f3354b0e cmchao
    omap_gpmc_reset(s);
391 f3354b0e cmchao
392 f3354b0e cmchao
    iomemtype = cpu_register_io_memory(omap_gpmc_readfn,
393 f3354b0e cmchao
                    omap_gpmc_writefn, s);
394 f3354b0e cmchao
    cpu_register_physical_memory(base, 0x1000, iomemtype);
395 f3354b0e cmchao
396 f3354b0e cmchao
    return s;
397 f3354b0e cmchao
}
398 f3354b0e cmchao
399 f3354b0e cmchao
void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype,
400 f3354b0e cmchao
                void (*base_upd)(void *opaque, target_phys_addr_t new),
401 f3354b0e cmchao
                void (*unmap)(void *opaque), void *opaque)
402 f3354b0e cmchao
{
403 f3354b0e cmchao
    struct omap_gpmc_cs_file_s *f;
404 f3354b0e cmchao
405 f3354b0e cmchao
    if (cs < 0 || cs >= 8) {
406 f3354b0e cmchao
        fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
407 f3354b0e cmchao
        exit(-1);
408 f3354b0e cmchao
    }
409 f3354b0e cmchao
    f = &s->cs_file[cs];
410 f3354b0e cmchao
411 f3354b0e cmchao
    f->iomemtype = iomemtype;
412 f3354b0e cmchao
    f->base_update = base_upd;
413 f3354b0e cmchao
    f->unmap = unmap;
414 f3354b0e cmchao
    f->opaque = opaque;
415 f3354b0e cmchao
416 f3354b0e cmchao
    if (f->config[6] & (1 << 6))                                /* CSVALID */
417 f3354b0e cmchao
        omap_gpmc_cs_map(f, f->config[6] & 0x1f,                /* MASKADDR */
418 f3354b0e cmchao
                        (f->config[6] >> 8 & 0xf));                /* BASEADDR */
419 f3354b0e cmchao
}