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