| | 1 | /* |
| | 2 | * E-Ten Glofiish smartphone M800 / X800 |
| | 3 | * |
| | 4 | * This code is licensed under the GNU GPL v2. |
| | 5 | */ |
| | 6 | |
| | 7 | #include "hw.h" |
| | 8 | #include "s3c.h" |
| | 9 | #include "arm-misc.h" |
| | 10 | #include "sysemu.h" |
| | 11 | #include "i2c.h" |
| | 12 | #include "qemu-timer.h" |
| | 13 | #include "devices.h" |
| | 14 | #include "audio/audio.h" |
| | 15 | #include "boards.h" |
| | 16 | #include "console.h" |
| | 17 | #include "usb.h" |
| | 18 | #include "net.h" |
| | 19 | #include "sd.h" |
| | 20 | #include "dm9000.h" |
| | 21 | #include "eeprom24c0x.h" |
| | 22 | |
| | 23 | #define GLOFIISH_GPIO_SD_DETECT S3C_GPG(7) |
| | 24 | //#define GLOFIISH_GPIO_WP_SD S3C_GPH(??) |
| | 25 | #define GLOFIISH_IRQ_SD_DETECT S3C_EINT(15) |
| | 26 | |
| | 27 | struct glofiish_s { |
| | 28 | struct s3c_state_s *cpu; |
| | 29 | unsigned int ram; |
| | 30 | const char * kernel; |
| | 31 | SDState * mmc; |
| | 32 | NANDFlashState *nand; |
| | 33 | }; |
| | 34 | |
| | 35 | |
| | 36 | static void glofiish_gpio_setup(struct glofiish_s *s) |
| | 37 | { |
| | 38 | |
| | 39 | /* Register the SD card pins to the lower SD driver */ |
| | 40 | sd_set_cb(s->mmc, |
| | 41 | 0, //s3c_gpio_in_get(s->cpu->io)[MINI2440_GPIO_WP_SD], |
| | 42 | s3c_gpio_in_get(s->cpu->io)[GLOFIISH_IRQ_SD_DETECT]); |
| | 43 | |
| | 44 | s3c_gpio_set_dat(s->cpu->io, S3C_GPG(7), 1); |
| | 45 | |
| | 46 | } |
| | 47 | |
| | 48 | static int glofiish_load_from_nand(NANDFlashState *nand, |
| | 49 | uint32_t nand_offset, uint32_t s3c_base_offset, uint32_t size) |
| | 50 | { |
| | 51 | uint8_t buffer[512]; |
| | 52 | uint32_t src = 0; |
| | 53 | int page = 0; |
| | 54 | uint32_t dst = 0; |
| | 55 | |
| | 56 | if (!nand) |
| | 57 | return 0; |
| | 58 | |
| | 59 | for (page = 0; page < (size / 512); page++, src += 512, dst += 512) { |
| | 60 | |
| | 61 | fprintf(stderr, "src: %d, dst: %d\n", src, dst); |
| | 62 | |
| | 63 | if (nand_readraw(nand, nand_offset + src, buffer, 512)) { |
| | 64 | cpu_physical_memory_write(s3c_base_offset + dst, buffer, 512); |
| | 65 | } else { |
| | 66 | fprintf(stderr, "%s: failed to load nand %d:%d\n", __FUNCTION__, |
| | 67 | nand_offset + src, 512 + 16); |
| | 68 | return 0; |
| | 69 | } |
| | 70 | } |
| | 71 | return (int) size; |
| | 72 | } |
| | 73 | |
| | 74 | static void glofiish_reset(void *opaque) |
| | 75 | { |
| | 76 | struct glofiish_s *s = (struct glofiish_s *) opaque; |
| | 77 | // uint32_t image_size; |
| | 78 | |
| | 79 | /* |
| | 80 | * Normally we would load 4 KB of nand to SRAM and jump there, but |
| | 81 | * it is not working perfectly as expected, so we cheat and load |
| | 82 | * it from nand directly relocated to 0x33f80000 and jump there |
| | 83 | */ |
| | 84 | #if 0 |
| | 85 | if (mini2440_load_from_nand(s->nand, 0, S3C_RAM_BASE | 0x03f80000, 256*1024)> 0) { |
| | 86 | fprintf(stderr, "%s: loaded default u-boot from NAND\n", __FUNCTION__); |
| | 87 | s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relocated */ |
| | 88 | } |
| | 89 | #endif |
| | 90 | |
| | 91 | if (glofiish_load_from_nand(s->nand, 0, S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE) > 0) { |
| | 92 | s->cpu->env->regs[15] = S3C_SRAM_BASE_NANDBOOT; /* start address, u-boot relocating code */ |
| | 93 | fprintf(stderr, "%s: 4KB SteppingStone loaded from NAND\n", __FUNCTION__); |
| | 94 | } |
| | 95 | fprintf(stderr, "%d %d\n", S3C_SRAM_BASE_NANDBOOT, S3C_SRAM_SIZE); |
| | 96 | #if 0 |
| | 97 | /* |
| | 98 | * if a u--boot is available as a file, we always use it |
| | 99 | */ |
| | 100 | { |
| | 101 | image_size = load_image("mini2440/u-boot.bin", phys_ram_base + 0x03f80000); |
| | 102 | if (image_size < 0) |
| | 103 | image_size = load_image("u-boot.bin", phys_ram_base + 0x03f80000); |
| | 104 | if (image_size > 0) { |
| | 105 | if (image_size & (512 -1)) /* round size to a NAND block size */ |
| | 106 | image_size = (image_size + 512) & ~(512-1); |
| | 107 | fprintf(stderr, "%s: loaded override u-boot (size %x)\n", __FUNCTION__, image_size); |
| | 108 | s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000; /* start address, u-boot already relocated */ |
| | 109 | } |
| | 110 | } |
| | 111 | /* |
| | 112 | * if a kernel was explicitly specified, we load it too |
| | 113 | */ |
| | 114 | if (s->kernel) { |
| | 115 | image_size = load_image(s->kernel, phys_ram_base + 0x02000000); |
| | 116 | if (image_size > 0) { |
| | 117 | if (image_size & (512 -1)) /* round size to a NAND block size */ |
| | 118 | image_size = (image_size + 512) & ~(512-1); |
| | 119 | fprintf(stderr, "%s: loaded %s (size %x)\n", __FUNCTION__, s->kernel, image_size); |
| | 120 | } |
| | 121 | } |
| | 122 | #endif |
| | 123 | } |
| | 124 | |
| | 125 | /* Board init. */ |
| | 126 | static struct glofiish_s *glofiish_init_common(int ram_size, |
| | 127 | const char *kernel_filename, const char *cpu_model, |
| | 128 | SDState *mmc) |
| | 129 | { |
| | 130 | struct glofiish_s *s = (struct glofiish_s *) |
| | 131 | qemu_mallocz(sizeof(struct glofiish_s)); |
| | 132 | |
| | 133 | s->ram = 0x04000000; |
| | 134 | s->kernel = kernel_filename; |
| | 135 | s->mmc = mmc; |
| | 136 | |
| | 137 | /* Setup CPU & memory */ |
| | 138 | if (ram_size < s->ram + S3C_SRAM_SIZE) { |
| | 139 | fprintf(stderr, "This platform requires %i bytes of memory (not %d)\n", |
| | 140 | s->ram + S3C_SRAM_SIZE, ram_size); |
| | 141 | exit(1); |
| | 142 | } |
| | 143 | if (cpu_model && strcmp(cpu_model, "arm920t")) { |
| | 144 | fprintf(stderr, "This platform requires an ARM920T core\n"); |
| | 145 | exit(2); |
| | 146 | } |
| | 147 | s->cpu = s3c24xx_init(S3C_CPU_2440, 12000000 /* 12 mhz */, s->ram, S3C_SRAM_BASE_NANDBOOT, s->mmc); |
| | 148 | |
| | 149 | /* Setup peripherals */ |
| | 150 | glofiish_gpio_setup(s); |
| | 151 | |
| | 152 | /* Setup initial (reset) machine state */ |
| | 153 | qemu_register_reset(glofiish_reset, s); |
| | 154 | |
| | 155 | return s; |
| | 156 | } |
| | 157 | |
| | 158 | static void glofiish_init(ram_addr_t ram_size, |
| | 159 | const char *boot_device, |
| | 160 | const char *kernel_filename, const char *kernel_cmdline, |
| | 161 | const char *initrd_filename, const char *cpu_model) |
| | 162 | { |
| | 163 | struct glofiish_s *glofiish; |
| | 164 | int sd_idx = drive_get_index(IF_SD, 0, 0); |
| | 165 | SDState *sd = 0; |
| | 166 | |
| | 167 | if (sd_idx >= 0) |
| | 168 | sd = sd_init(drives_table[sd_idx].bdrv, 1); |
| | 169 | |
| | 170 | glofiish = glofiish_init_common(ram_size, |
| | 171 | kernel_filename, cpu_model, sd); |
| | 172 | |
| | 173 | glofiish->nand = nand_init(NAND_MFR_SAMSUNG, 0xaa); |
| | 174 | glofiish->cpu->nand->reg(glofiish->cpu->nand, glofiish->nand); |
| | 175 | |
| | 176 | glofiish_reset(glofiish); |
| | 177 | } |
| | 178 | |
| | 179 | QEMUMachine glofiish_machine = { |
| | 180 | "glofiish", |
| | 181 | "E-Ten glofiish smartphone M800/X800 (S3C2442A)", |
| | 182 | .init = glofiish_init, |
| | 183 | }; |
| | 184 | |