| 
									
										
										
										
											2007-09-16 21:08:06 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |  * ARM Integrator CP System emulation. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-04-06 16:49:48 +00:00
										 |  |  |  * Copyright (c) 2005-2007 CodeSourcery. | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |  * Written by Paul Brook | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This code is licenced under the GPL | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  | #include "sysbus.h"
 | 
					
						
							| 
									
										
										
										
											2007-11-17 17:14:51 +00:00
										 |  |  | #include "primecell.h"
 | 
					
						
							|  |  |  | #include "devices.h"
 | 
					
						
							|  |  |  | #include "sysemu.h"
 | 
					
						
							|  |  |  | #include "boards.h"
 | 
					
						
							|  |  |  | #include "arm-misc.h"
 | 
					
						
							|  |  |  | #include "net.h"
 | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     SysBusDevice busdev; | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     uint32_t memsz; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     uint32_t flash_offset; | 
					
						
							|  |  |  |     uint32_t cm_osc; | 
					
						
							|  |  |  |     uint32_t cm_ctrl; | 
					
						
							|  |  |  |     uint32_t cm_lock; | 
					
						
							|  |  |  |     uint32_t cm_auxosc; | 
					
						
							|  |  |  |     uint32_t cm_sdram; | 
					
						
							|  |  |  |     uint32_t cm_init; | 
					
						
							|  |  |  |     uint32_t cm_flags; | 
					
						
							|  |  |  |     uint32_t cm_nvflags; | 
					
						
							|  |  |  |     uint32_t int_level; | 
					
						
							|  |  |  |     uint32_t irq_enabled; | 
					
						
							|  |  |  |     uint32_t fiq_enabled; | 
					
						
							|  |  |  | } integratorcm_state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint8_t integrator_spd[128] = { | 
					
						
							|  |  |  |    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1, | 
					
						
							|  |  |  |    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset) | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     integratorcm_state *s = (integratorcm_state *)opaque; | 
					
						
							|  |  |  |     if (offset >= 0x100 && offset < 0x200) { | 
					
						
							|  |  |  |         /* CM_SPD */ | 
					
						
							|  |  |  |         if (offset >= 0x180) | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         return integrator_spd[offset >> 2]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     switch (offset >> 2) { | 
					
						
							|  |  |  |     case 0: /* CM_ID */ | 
					
						
							|  |  |  |         return 0x411a3001; | 
					
						
							|  |  |  |     case 1: /* CM_PROC */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     case 2: /* CM_OSC */ | 
					
						
							|  |  |  |         return s->cm_osc; | 
					
						
							|  |  |  |     case 3: /* CM_CTRL */ | 
					
						
							|  |  |  |         return s->cm_ctrl; | 
					
						
							|  |  |  |     case 4: /* CM_STAT */ | 
					
						
							|  |  |  |         return 0x00100000; | 
					
						
							|  |  |  |     case 5: /* CM_LOCK */ | 
					
						
							|  |  |  |         if (s->cm_lock == 0xa05f) { | 
					
						
							|  |  |  |             return 0x1a05f; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return s->cm_lock; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     case 6: /* CM_LMBUSCNT */ | 
					
						
							|  |  |  |         /* ??? High frequency timer.  */ | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("integratorcm_read: CM_LMBUSCNT"); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     case 7: /* CM_AUXOSC */ | 
					
						
							|  |  |  |         return s->cm_auxosc; | 
					
						
							|  |  |  |     case 8: /* CM_SDRAM */ | 
					
						
							|  |  |  |         return s->cm_sdram; | 
					
						
							|  |  |  |     case 9: /* CM_INIT */ | 
					
						
							|  |  |  |         return s->cm_init; | 
					
						
							|  |  |  |     case 10: /* CM_REFCT */ | 
					
						
							|  |  |  |         /* ??? High frequency timer.  */ | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("integratorcm_read: CM_REFCT"); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     case 12: /* CM_FLAGS */ | 
					
						
							|  |  |  |         return s->cm_flags; | 
					
						
							|  |  |  |     case 14: /* CM_NVFLAGS */ | 
					
						
							|  |  |  |         return s->cm_nvflags; | 
					
						
							|  |  |  |     case 16: /* CM_IRQ_STAT */ | 
					
						
							|  |  |  |         return s->int_level & s->irq_enabled; | 
					
						
							|  |  |  |     case 17: /* CM_IRQ_RSTAT */ | 
					
						
							|  |  |  |         return s->int_level; | 
					
						
							|  |  |  |     case 18: /* CM_IRQ_ENSET */ | 
					
						
							|  |  |  |         return s->irq_enabled; | 
					
						
							|  |  |  |     case 20: /* CM_SOFT_INTSET */ | 
					
						
							|  |  |  |         return s->int_level & 1; | 
					
						
							|  |  |  |     case 24: /* CM_FIQ_STAT */ | 
					
						
							|  |  |  |         return s->int_level & s->fiq_enabled; | 
					
						
							|  |  |  |     case 25: /* CM_FIQ_RSTAT */ | 
					
						
							|  |  |  |         return s->int_level; | 
					
						
							|  |  |  |     case 26: /* CM_FIQ_ENSET */ | 
					
						
							|  |  |  |         return s->fiq_enabled; | 
					
						
							|  |  |  |     case 32: /* CM_VOLTAGE_CTL0 */ | 
					
						
							|  |  |  |     case 33: /* CM_VOLTAGE_CTL1 */ | 
					
						
							|  |  |  |     case 34: /* CM_VOLTAGE_CTL2 */ | 
					
						
							|  |  |  |     case 35: /* CM_VOLTAGE_CTL3 */ | 
					
						
							|  |  |  |         /* ??? Voltage control unimplemented.  */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("integratorcm_read: Unimplemented offset 0x%x\n", | 
					
						
							|  |  |  |                  (int)offset); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void integratorcm_do_remap(integratorcm_state *s, int flash) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (flash) { | 
					
						
							|  |  |  |         cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     //??? tlb_flush (cpu_single_env, 1);
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (value & 8) { | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("Board reset\n"); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |     if ((s->cm_init ^ value) & 4) { | 
					
						
							|  |  |  |         integratorcm_do_remap(s, (value & 4) == 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((s->cm_init ^ value) & 1) { | 
					
						
							|  |  |  |         printf("Green LED %s\n", (value & 1) ? "on" : "off"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     s->cm_init = (s->cm_init & ~ 5) | (value ^ 5); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void integratorcm_update(integratorcm_state *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
 | 
					
						
							|  |  |  |        are active.  */ | 
					
						
							|  |  |  |     if (s->int_level & (s->irq_enabled | s->fiq_enabled)) | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("Core module interrupt\n"); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static void integratorcm_write(void *opaque, target_phys_addr_t offset, | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |                                uint32_t value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     integratorcm_state *s = (integratorcm_state *)opaque; | 
					
						
							|  |  |  |     switch (offset >> 2) { | 
					
						
							|  |  |  |     case 2: /* CM_OSC */ | 
					
						
							|  |  |  |         if (s->cm_lock == 0xa05f) | 
					
						
							|  |  |  |             s->cm_osc = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 3: /* CM_CTRL */ | 
					
						
							|  |  |  |         integratorcm_set_ctrl(s, value); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 5: /* CM_LOCK */ | 
					
						
							|  |  |  |         s->cm_lock = value & 0xffff; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 7: /* CM_AUXOSC */ | 
					
						
							|  |  |  |         if (s->cm_lock == 0xa05f) | 
					
						
							|  |  |  |             s->cm_auxosc = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 8: /* CM_SDRAM */ | 
					
						
							|  |  |  |         s->cm_sdram = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 9: /* CM_INIT */ | 
					
						
							|  |  |  |         /* ??? This can change the memory bus frequency.  */ | 
					
						
							|  |  |  |         s->cm_init = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 12: /* CM_FLAGSS */ | 
					
						
							|  |  |  |         s->cm_flags |= value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 13: /* CM_FLAGSC */ | 
					
						
							|  |  |  |         s->cm_flags &= ~value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 14: /* CM_NVFLAGSS */ | 
					
						
							|  |  |  |         s->cm_nvflags |= value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 15: /* CM_NVFLAGSS */ | 
					
						
							|  |  |  |         s->cm_nvflags &= ~value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 18: /* CM_IRQ_ENSET */ | 
					
						
							|  |  |  |         s->irq_enabled |= value; | 
					
						
							|  |  |  |         integratorcm_update(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 19: /* CM_IRQ_ENCLR */ | 
					
						
							|  |  |  |         s->irq_enabled &= ~value; | 
					
						
							|  |  |  |         integratorcm_update(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 20: /* CM_SOFT_INTSET */ | 
					
						
							|  |  |  |         s->int_level |= (value & 1); | 
					
						
							|  |  |  |         integratorcm_update(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 21: /* CM_SOFT_INTCLR */ | 
					
						
							|  |  |  |         s->int_level &= ~(value & 1); | 
					
						
							|  |  |  |         integratorcm_update(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 26: /* CM_FIQ_ENSET */ | 
					
						
							|  |  |  |         s->fiq_enabled |= value; | 
					
						
							|  |  |  |         integratorcm_update(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 27: /* CM_FIQ_ENCLR */ | 
					
						
							|  |  |  |         s->fiq_enabled &= ~value; | 
					
						
							|  |  |  |         integratorcm_update(s); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 32: /* CM_VOLTAGE_CTL0 */ | 
					
						
							|  |  |  |     case 33: /* CM_VOLTAGE_CTL1 */ | 
					
						
							|  |  |  |     case 34: /* CM_VOLTAGE_CTL2 */ | 
					
						
							|  |  |  |     case 35: /* CM_VOLTAGE_CTL3 */ | 
					
						
							|  |  |  |         /* ??? Voltage control unimplemented.  */ | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("integratorcm_write: Unimplemented offset 0x%x\n", | 
					
						
							|  |  |  |                  (int)offset); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Integrator/CM control registers.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-25 18:29:31 +00:00
										 |  |  | static CPUReadMemoryFunc * const integratorcm_readfn[] = { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |    integratorcm_read, | 
					
						
							|  |  |  |    integratorcm_read, | 
					
						
							|  |  |  |    integratorcm_read | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-25 18:29:31 +00:00
										 |  |  | static CPUWriteMemoryFunc * const integratorcm_writefn[] = { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |    integratorcm_write, | 
					
						
							|  |  |  |    integratorcm_write, | 
					
						
							|  |  |  |    integratorcm_write | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-14 10:36:05 +02:00
										 |  |  | static int integratorcm_init(SysBusDevice *dev) | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int iomemtype; | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     s->cm_osc = 0x01000048; | 
					
						
							|  |  |  |     /* ??? What should the high bits of this value be?  */ | 
					
						
							|  |  |  |     s->cm_auxosc = 0x0007feff; | 
					
						
							|  |  |  |     s->cm_sdram = 0x00011122; | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     if (s->memsz >= 256) { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         integrator_spd[31] = 64; | 
					
						
							|  |  |  |         s->cm_sdram |= 0x10; | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     } else if (s->memsz >= 128) { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         integrator_spd[31] = 32; | 
					
						
							|  |  |  |         s->cm_sdram |= 0x0c; | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     } else if (s->memsz >= 64) { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         integrator_spd[31] = 16; | 
					
						
							|  |  |  |         s->cm_sdram |= 0x08; | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     } else if (s->memsz >= 32) { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         integrator_spd[31] = 4; | 
					
						
							|  |  |  |         s->cm_sdram |= 0x04; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         integrator_spd[31] = 2; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); | 
					
						
							|  |  |  |     s->cm_init = 0x00000112; | 
					
						
							| 
									
										
										
										
											2008-04-24 17:59:27 +00:00
										 |  |  |     s->flash_offset = qemu_ram_alloc(0x100000); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-14 11:38:51 +03:00
										 |  |  |     iomemtype = cpu_register_io_memory(integratorcm_readfn, | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |                                        integratorcm_writefn, s); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_init_mmio(dev, 0x00800000, iomemtype); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     integratorcm_do_remap(s, 1); | 
					
						
							|  |  |  |     /* ??? Save/restore.  */ | 
					
						
							| 
									
										
										
										
											2009-08-14 10:36:05 +02:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Integrator/CP hardware emulation.  */ | 
					
						
							|  |  |  | /* Primary interrupt controller.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct icp_pic_state | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |   SysBusDevice busdev; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |   uint32_t level; | 
					
						
							|  |  |  |   uint32_t irq_enabled; | 
					
						
							|  |  |  |   uint32_t fiq_enabled; | 
					
						
							| 
									
										
										
										
											2007-04-07 18:14:41 +00:00
										 |  |  |   qemu_irq parent_irq; | 
					
						
							|  |  |  |   qemu_irq parent_fiq; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | } icp_pic_state; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void icp_pic_update(icp_pic_state *s) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-04-09 01:32:52 +00:00
										 |  |  |     uint32_t flags; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-07 18:14:41 +00:00
										 |  |  |     flags = (s->level & s->irq_enabled); | 
					
						
							|  |  |  |     qemu_set_irq(s->parent_irq, flags != 0); | 
					
						
							|  |  |  |     flags = (s->level & s->fiq_enabled); | 
					
						
							|  |  |  |     qemu_set_irq(s->parent_fiq, flags != 0); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-09 01:32:52 +00:00
										 |  |  | static void icp_pic_set_irq(void *opaque, int irq, int level) | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-12-04 18:54:21 +00:00
										 |  |  |     icp_pic_state *s = (icp_pic_state *)opaque; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     if (level) | 
					
						
							| 
									
										
										
										
											2005-12-04 18:54:21 +00:00
										 |  |  |         s->level |= 1 << irq; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2005-12-04 18:54:21 +00:00
										 |  |  |         s->level &= ~(1 << irq); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     icp_pic_update(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset) | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     icp_pic_state *s = (icp_pic_state *)opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (offset >> 2) { | 
					
						
							|  |  |  |     case 0: /* IRQ_STATUS */ | 
					
						
							|  |  |  |         return s->level & s->irq_enabled; | 
					
						
							|  |  |  |     case 1: /* IRQ_RAWSTAT */ | 
					
						
							|  |  |  |         return s->level; | 
					
						
							|  |  |  |     case 2: /* IRQ_ENABLESET */ | 
					
						
							|  |  |  |         return s->irq_enabled; | 
					
						
							|  |  |  |     case 4: /* INT_SOFTSET */ | 
					
						
							|  |  |  |         return s->level & 1; | 
					
						
							|  |  |  |     case 8: /* FRQ_STATUS */ | 
					
						
							|  |  |  |         return s->level & s->fiq_enabled; | 
					
						
							|  |  |  |     case 9: /* FRQ_RAWSTAT */ | 
					
						
							|  |  |  |         return s->level; | 
					
						
							|  |  |  |     case 10: /* FRQ_ENABLESET */ | 
					
						
							|  |  |  |         return s->fiq_enabled; | 
					
						
							|  |  |  |     case 3: /* IRQ_ENABLECLR */ | 
					
						
							|  |  |  |     case 5: /* INT_SOFTCLR */ | 
					
						
							|  |  |  |     case 11: /* FRQ_ENABLECLR */ | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2006-11-19 23:07:17 +00:00
										 |  |  |         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static void icp_pic_write(void *opaque, target_phys_addr_t offset, | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |                           uint32_t value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     icp_pic_state *s = (icp_pic_state *)opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (offset >> 2) { | 
					
						
							|  |  |  |     case 2: /* IRQ_ENABLESET */ | 
					
						
							|  |  |  |         s->irq_enabled |= value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 3: /* IRQ_ENABLECLR */ | 
					
						
							|  |  |  |         s->irq_enabled &= ~value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 4: /* INT_SOFTSET */ | 
					
						
							|  |  |  |         if (value & 1) | 
					
						
							| 
									
										
										
										
											2007-04-07 18:14:41 +00:00
										 |  |  |             icp_pic_set_irq(s, 0, 1); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 5: /* INT_SOFTCLR */ | 
					
						
							|  |  |  |         if (value & 1) | 
					
						
							| 
									
										
										
										
											2007-04-07 18:14:41 +00:00
										 |  |  |             icp_pic_set_irq(s, 0, 0); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 10: /* FRQ_ENABLESET */ | 
					
						
							|  |  |  |         s->fiq_enabled |= value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 11: /* FRQ_ENABLECLR */ | 
					
						
							|  |  |  |         s->fiq_enabled &= ~value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0: /* IRQ_STATUS */ | 
					
						
							|  |  |  |     case 1: /* IRQ_RAWSTAT */ | 
					
						
							|  |  |  |     case 8: /* FRQ_STATUS */ | 
					
						
							|  |  |  |     case 9: /* FRQ_RAWSTAT */ | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2006-11-19 23:07:17 +00:00
										 |  |  |         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     icp_pic_update(s); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-25 18:29:31 +00:00
										 |  |  | static CPUReadMemoryFunc * const icp_pic_readfn[] = { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |    icp_pic_read, | 
					
						
							|  |  |  |    icp_pic_read, | 
					
						
							|  |  |  |    icp_pic_read | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-25 18:29:31 +00:00
										 |  |  | static CPUWriteMemoryFunc * const icp_pic_writefn[] = { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |    icp_pic_write, | 
					
						
							|  |  |  |    icp_pic_write, | 
					
						
							|  |  |  |    icp_pic_write | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-14 10:36:05 +02:00
										 |  |  | static int icp_pic_init(SysBusDevice *dev) | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     int iomemtype; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-26 14:56:11 +01:00
										 |  |  |     qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_init_irq(dev, &s->parent_irq); | 
					
						
							|  |  |  |     sysbus_init_irq(dev, &s->parent_fiq); | 
					
						
							| 
									
										
										
										
											2009-06-14 11:38:51 +03:00
										 |  |  |     iomemtype = cpu_register_io_memory(icp_pic_readfn, | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |                                        icp_pic_writefn, s); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_init_mmio(dev, 0x00800000, iomemtype); | 
					
						
							| 
									
										
										
										
											2009-08-14 10:36:05 +02:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CP control registers.  */ | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset) | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     switch (offset >> 2) { | 
					
						
							|  |  |  |     case 0: /* CP_IDFIELD */ | 
					
						
							|  |  |  |         return 0x41034003; | 
					
						
							|  |  |  |     case 1: /* CP_FLASHPROG */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     case 2: /* CP_INTREG */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     case 3: /* CP_DECODE */ | 
					
						
							|  |  |  |         return 0x11; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("icp_control_read: Bad offset %x\n", (int)offset); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static void icp_control_write(void *opaque, target_phys_addr_t offset, | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |                           uint32_t value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (offset >> 2) { | 
					
						
							|  |  |  |     case 1: /* CP_FLASHPROG */ | 
					
						
							|  |  |  |     case 2: /* CP_INTREG */ | 
					
						
							|  |  |  |     case 3: /* CP_DECODE */ | 
					
						
							|  |  |  |         /* Nothing interesting implemented yet.  */ | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2009-05-08 02:35:15 +01:00
										 |  |  |         hw_error("icp_control_write: Bad offset %x\n", (int)offset); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-08-25 18:29:31 +00:00
										 |  |  | static CPUReadMemoryFunc * const icp_control_readfn[] = { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |    icp_control_read, | 
					
						
							|  |  |  |    icp_control_read, | 
					
						
							|  |  |  |    icp_control_read | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-25 18:29:31 +00:00
										 |  |  | static CPUWriteMemoryFunc * const icp_control_writefn[] = { | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |    icp_control_write, | 
					
						
							|  |  |  |    icp_control_write, | 
					
						
							|  |  |  |    icp_control_write | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void icp_control_init(uint32_t base) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int iomemtype; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-14 11:38:51 +03:00
										 |  |  |     iomemtype = cpu_register_io_memory(icp_control_readfn, | 
					
						
							| 
									
										
										
										
											2008-12-01 18:59:50 +00:00
										 |  |  |                                        icp_control_writefn, NULL); | 
					
						
							| 
									
										
										
										
											2007-06-03 15:19:33 +00:00
										 |  |  |     cpu_register_physical_memory(base, 0x00800000, iomemtype); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     /* ??? Save/restore.  */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Board init.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-14 20:27:51 +00:00
										 |  |  | static struct arm_boot_info integrator_binfo = { | 
					
						
							|  |  |  |     .loader_start = 0x0, | 
					
						
							|  |  |  |     .board_id = 0x113, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  | static void integratorcp_init(ram_addr_t ram_size, | 
					
						
							| 
									
										
										
										
											2009-01-16 19:04:14 +00:00
										 |  |  |                      const char *boot_device, | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |                      const char *kernel_filename, const char *kernel_cmdline, | 
					
						
							| 
									
										
										
										
											2007-03-08 03:04:12 +00:00
										 |  |  |                      const char *initrd_filename, const char *cpu_model) | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     CPUState *env; | 
					
						
							| 
									
										
										
										
											2009-10-01 16:12:16 -05:00
										 |  |  |     ram_addr_t ram_offset; | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     qemu_irq pic[32]; | 
					
						
							| 
									
										
										
										
											2007-04-07 18:14:41 +00:00
										 |  |  |     qemu_irq *cpu_pic; | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     DeviceState *dev; | 
					
						
							|  |  |  |     int i; | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-03-08 03:04:12 +00:00
										 |  |  |     if (!cpu_model) | 
					
						
							|  |  |  |         cpu_model = "arm926"; | 
					
						
							| 
									
										
										
										
											2007-11-10 15:15:54 +00:00
										 |  |  |     env = cpu_init(cpu_model); | 
					
						
							|  |  |  |     if (!env) { | 
					
						
							|  |  |  |         fprintf(stderr, "Unable to find CPU definition\n"); | 
					
						
							|  |  |  |         exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-04-24 17:59:27 +00:00
										 |  |  |     ram_offset = qemu_ram_alloc(ram_size); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */ | 
					
						
							| 
									
										
										
										
											2008-06-03 19:51:57 +00:00
										 |  |  |     /* ??? RAM should repeat to fill physical memory space.  */ | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     /* SDRAM at address zero*/ | 
					
						
							| 
									
										
										
										
											2008-04-24 17:59:27 +00:00
										 |  |  |     cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     /* And again at address 0x80000000 */ | 
					
						
							| 
									
										
										
										
											2008-04-24 17:59:27 +00:00
										 |  |  |     cpu_register_physical_memory(0x80000000, ram_size, ram_offset | IO_MEM_RAM); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     dev = qdev_create(NULL, "integrator_core"); | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20); | 
					
						
							| 
									
										
										
										
											2009-10-07 01:15:58 +02:00
										 |  |  |     qdev_init_nofail(dev); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-04-09 01:32:52 +00:00
										 |  |  |     cpu_pic = arm_pic_init_cpu(env); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     dev = sysbus_create_varargs("integrator_pic", 0x14000000, | 
					
						
							|  |  |  |                                 cpu_pic[ARM_PIC_CPU_IRQ], | 
					
						
							|  |  |  |                                 cpu_pic[ARM_PIC_CPU_FIQ], NULL); | 
					
						
							|  |  |  |     for (i = 0; i < 32; i++) { | 
					
						
							| 
									
										
										
										
											2009-05-26 14:56:11 +01:00
										 |  |  |         pic[i] = qdev_get_gpio_in(dev, i); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_create_simple("integrator_pic", 0xca000000, pic[26]); | 
					
						
							|  |  |  |     sysbus_create_varargs("integrator_pit", 0x13000000, | 
					
						
							|  |  |  |                           pic[5], pic[6], pic[7], NULL); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_create_simple("pl031", 0x15000000, pic[8]); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_create_simple("pl011", 0x16000000, pic[1]); | 
					
						
							|  |  |  |     sysbus_create_simple("pl011", 0x17000000, pic[2]); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  |     icp_control_init(0xcb000000); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]); | 
					
						
							|  |  |  |     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  |     sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL); | 
					
						
							| 
									
										
										
										
											2009-01-13 19:39:36 +00:00
										 |  |  |     if (nd_table[0].vlan) | 
					
						
							|  |  |  |         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     sysbus_create_simple("pl110", 0xc0000000, pic[22]); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-14 20:27:51 +00:00
										 |  |  |     integrator_binfo.ram_size = ram_size; | 
					
						
							|  |  |  |     integrator_binfo.kernel_filename = kernel_filename; | 
					
						
							|  |  |  |     integrator_binfo.kernel_cmdline = kernel_cmdline; | 
					
						
							|  |  |  |     integrator_binfo.initrd_filename = initrd_filename; | 
					
						
							|  |  |  |     arm_load_kernel(env, &integrator_binfo); | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-20 18:38:09 -05:00
										 |  |  | static QEMUMachine integratorcp_machine = { | 
					
						
							| 
									
										
										
										
											2008-10-07 20:34:35 +00:00
										 |  |  |     .name = "integratorcp", | 
					
						
							|  |  |  |     .desc = "ARM Integrator/CP (ARM926EJ-S)", | 
					
						
							|  |  |  |     .init = integratorcp_init, | 
					
						
							| 
									
										
										
										
											2009-05-21 20:41:01 -05:00
										 |  |  |     .is_default = 1, | 
					
						
							| 
									
										
										
										
											2005-11-26 10:38:39 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-20 18:38:09 -05:00
										 |  |  | static void integratorcp_machine_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qemu_register_machine(&integratorcp_machine); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | machine_init(integratorcp_machine_init); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  | static SysBusDeviceInfo core_info = { | 
					
						
							|  |  |  |     .init = integratorcm_init, | 
					
						
							|  |  |  |     .qdev.name  = "integrator_core", | 
					
						
							|  |  |  |     .qdev.size  = sizeof(integratorcm_state), | 
					
						
							|  |  |  |     .qdev.props = (Property[]) { | 
					
						
							| 
									
										
										
										
											2009-08-03 17:35:26 +02:00
										 |  |  |         DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0), | 
					
						
							|  |  |  |         DEFINE_PROP_END_OF_LIST(), | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  | static void integratorcp_register_devices(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     sysbus_register_dev("integrator_pic", sizeof(icp_pic_state), icp_pic_init); | 
					
						
							| 
									
										
										
										
											2009-07-15 13:43:31 +02:00
										 |  |  |     sysbus_register_withprop(&core_info); | 
					
						
							| 
									
										
										
										
											2009-05-14 22:35:07 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | device_init(integratorcp_register_devices) |