4 * Copyright (c) 2009 yajin <yajin@vm-kernel.org>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * Gdium is a loongson 2f CPU based notebook. http://www.gdium.com/
38 #include "qemu-char.h"
40 #include "audio/audio.h"
42 #include "mips_loongson2f.h"
45 #define DEBUG /*global debug on/off */
46 #define DEBUG_BOARD_INIT (1<<0x0)
47 #define DEBUG_I2C_EMU (1<<0x1)
49 #define DEBUG_ALL (0xffffffff)
50 #define DEBUG_FLAG DEBUG_BOARD_INIT
53 #define debug_out(flag,out) {\
54 if (flag & DEBUG_FLAG) printf out; \
57 #define debug_out(flag,out)
63 #define BIOS_SIZE (512 * 1024)
64 #define BIOS_SECTOR_BITS (12)
65 #define GDIUM_SDRAM_SIZE (512*1024*1024)
67 #define SM502_DEV_NO 14
68 #define GDIUM_PCI_MEM_BASE (0x10000000)
70 #define GDIUM_GPIO_SCL 6
71 #define GDIUM_GPIO_SDA 13
82 qemu_irq
*emu_i2c_cbs
;
93 uint8_t is_slave_addr
;
103 struct sm502_s
*sm502
;
106 struct emu_i2c
*emu_i2c
;
109 static void main_cpu_reset(void *opaque
)
111 CPUState
*env
= opaque
;
118 static int is_start(struct emu_i2c
*emu_i2c
, int line
, int level
)
120 if ((line
== GDIUM_GPIO_SDA
) && (!level
) && (emu_i2c
->scl
))
126 static int is_stop(struct emu_i2c
*emu_i2c
, int line
, int level
)
128 if ((line
== GDIUM_GPIO_SDA
) && (level
) && (emu_i2c
->scl
))
134 static int one_cycle(struct emu_i2c
*emu_i2c
, int line
, int level
)
136 if ((line
== GDIUM_GPIO_SCL
) && (level
))
141 /*PMON puts the data on GPIO SDA line*/
142 static void send_bit(struct gdium_s
*s
, int line
, int level
)
144 s
->emu_i2c
->out_data
|=
145 sm502_gpio_get_pin(s
->sm502
,
146 GDIUM_GPIO_SDA
) << (s
->emu_i2c
->out_offset
);
147 s
->emu_i2c
->out_offset
--;
150 /*prepare ack to cheat pmon*/
151 static void prepare_ack(struct gdium_s
*s
)
153 /*Set SDA=0 means we received ACK from slave */
154 sm502_gpio_set_pin(s
->sm502
, GDIUM_GPIO_SDA
, 0);
157 static void recv_bit(struct gdium_s
*s
, int line
, int level
)
159 if (s
->emu_i2c
->in_offset
== 7)
161 s
->emu_i2c
->in_data
= i2c_recv(s
->emu_i2c
->emu_i2c_bus
);
165 qemu_set_irq(s
->emu_i2c
->sda_irq
,
166 (s
->emu_i2c
->in_data
>> (s
->emu_i2c
->in_offset
)) & 0x1);
167 s
->emu_i2c
->in_offset
--;
170 static void i2c_emu_cb(void *opaque
, int line
, int level
)
172 struct gdium_s
*s
= (struct gdium_s
*) opaque
;
174 if (line
== GDIUM_GPIO_SCL
)
175 s
->emu_i2c
->scl
= level
;
177 debug_out(DEBUG_I2C_EMU
,
178 ("line %s LEVEL %d \n", line
== GDIUM_GPIO_SCL
? "SCL" : "SDA",
181 /*if we are waiting ack from slave address */
182 if (s
->emu_i2c
->waiting_ack
)
184 debug_out(DEBUG_I2C_EMU
, ("waiting_ack \n"));
186 if (one_cycle(s
->emu_i2c
, line
, level
))
188 s
->emu_i2c
->waiting_ack
= 0;
193 /*it means after sending ack, pmon writes to SDA-> wants STOP */
194 if ((line
== GDIUM_GPIO_SDA
) && (s
->emu_i2c
->i2c_state
== RECV_DATA
))
196 s
->emu_i2c
->i2c_state
= IDLE
;
200 if ((s
->emu_i2c
->i2c_state
== IDLE
) || (s
->emu_i2c
->i2c_state
== SEND_DATA
))
202 /*check whether start signal */
203 if (is_start(s
->emu_i2c
, line
, level
))
205 s
->emu_i2c
->i2c_state
= SEND_DATA
;
206 /*is_slave_addr=1 means the next byte is slave addreses */
207 s
->emu_i2c
->is_slave_addr
= 1;
208 s
->emu_i2c
->i2c_state
= SEND_DATA
;
209 debug_out(DEBUG_I2C_EMU
,
210 ("I2C Start. state %d \n", s
->emu_i2c
->i2c_state
));
211 s
->emu_i2c
->out_offset
= 7;
212 s
->emu_i2c
->out_data
= 0;
213 s
->emu_i2c
->slave_addr
= 0;
218 if (is_stop(s
->emu_i2c
, line
, level
))
220 debug_out(DEBUG_I2C_EMU
, ("STOP \n"));
221 s
->emu_i2c
->i2c_state
= IDLE
;
222 i2c_end_transfer(s
->emu_i2c
->emu_i2c_bus
);
226 if (one_cycle(s
->emu_i2c
, line
, level
))
228 debug_out(DEBUG_I2C_EMU
, ("one cycle \n"));
229 switch (s
->emu_i2c
->i2c_state
)
232 debug_out(DEBUG_I2C_EMU
, ("IDLE \n"));
235 send_bit(s
, line
, level
);
236 if (s
->emu_i2c
->out_offset
< 0)
238 debug_out(DEBUG_I2C_EMU
,
239 ("slave_addr %d out data %d \n",
240 s
->emu_i2c
->slave_addr
, s
->emu_i2c
->out_data
));
241 if (s
->emu_i2c
->is_slave_addr
)
243 /*first send is slave address */
244 s
->emu_i2c
->slave_addr
= s
->emu_i2c
->out_data
;
245 i2c_start_transfer(s
->emu_i2c
->
247 s
->emu_i2c
->slave_addr
& 0xfe,
248 s
->emu_i2c
->slave_addr
& 0x1);
249 debug_out(DEBUG_I2C_EMU
,
250 ("slave_addr %d \n", s
->emu_i2c
->slave_addr
));
252 s
->emu_i2c
->is_slave_addr
= 0;
256 /*send reg address or data */
257 i2c_send(s
->emu_i2c
->emu_i2c_bus
, s
->emu_i2c
->out_data
);
259 s
->emu_i2c
->out_offset
= 7;
260 s
->emu_i2c
->out_data
= 0;
261 if (s
->emu_i2c
->slave_addr
& 0x1)
263 s
->emu_i2c
->in_offset
= 7;
264 s
->emu_i2c
->i2c_state
= RECV_DATA
;
267 s
->emu_i2c
->i2c_state
= SEND_DATA
;
268 s
->emu_i2c
->waiting_ack
= 1;
274 recv_bit(s
, line
, level
);
275 if (s
->emu_i2c
->in_offset
< 0)
276 s
->emu_i2c
->i2c_state
= SEND_ACK
;
279 debug_out(DEBUG_I2C_EMU
, ("SEND_ACK \n"));
280 s
->emu_i2c
->in_offset
= 7;
281 s
->emu_i2c
->i2c_state
= RECV_DATA
;
282 i2c_nack(s
->emu_i2c
->emu_i2c_bus
);
285 fprintf(stderr
, "unknown state %d \n", s
->emu_i2c
->i2c_state
);
293 /*gdium uses SM502 GPIO 6/13 to emulate I2C.*/
294 static void mips_gdium_i2c_emu(struct gdium_s
*s
)
296 s
->emu_i2c
->emu_i2c_cbs
= qemu_allocate_irqs(i2c_emu_cb
, s
, 32);
297 sm502_gpio_out_set(s
->sm502
, GDIUM_GPIO_SCL
,
298 s
->emu_i2c
->emu_i2c_cbs
[GDIUM_GPIO_SCL
]);
299 sm502_gpio_out_set(s
->sm502
, GDIUM_GPIO_SDA
,
300 s
->emu_i2c
->emu_i2c_cbs
[GDIUM_GPIO_SDA
]);
302 s
->emu_i2c
->i2c_state
= IDLE
;
304 s
->emu_i2c
->sda_irq
= sm502_gpio_in_get(s
->sm502
, GDIUM_GPIO_SDA
)[0];
307 /*dumped from my gdium pcb*/
308 uint8_t gdium_spd
[0x80] = {
309 0x80, 0x08, 0x08, 0x0e, 0x0a, 0x60, 0x40, 0x00, /*0x00-0x07 */
310 0x05, 0x3d, 0x50, 0x00, 0x82, 0x00, 0x00, 0x00, /*0x08-0x0f */
311 0x0c, 0x04, 0x38, 0x00, 0x04, 0x00, 0x01, 0x3d, /*0x10-0x17 */
312 0x50, 0x50, 0x60, 0x3c, 0x1e, 0x3c, 0x2d, 0x80, /*0x18-0x1f */
313 0x25, 0x37, 0x10, 0x22, 0x3c, 0x1e, 0x13, 0x00, /*0x20-0x27 */
314 0x00, 0x3c, 0x69, 0x80, 0x1e, 0x28, 0x00, 0x00, /*0x28-0x2f */
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*0x30-0x37 */
316 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb2, /*0x38-0x3f */
317 0x7f, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*0x40-0x47 */
318 0x54, 0x4a, 0x4d, 0x35, 0x33, 0x33, 0x51, 0x53, /*0x48-0x4f */
319 0x4a, 0x2d, 0x35, 0x31, 0x32, 0x4d, 0x20, 0x20, /*0x50-0x57 */
320 0x20, 0x20, 0x20, 0x00, 0x00, 0x07, 0x47, 0x00, /*0x58-0x5f */
321 0x07, 0x00, 0xb1, 0x98, 0x00, 0x00, 0x00, 0x00, /*0x60-0x67 */
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*0x68-0x6f */
323 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*0x70-0x77 */
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*0x78-0x7f */
328 void mips_gdium_init(ram_addr_t ram_size
, int vga_ram_size
,
329 const char *boot_device
,
330 const char *kernel_filename
,
331 const char *kernel_cmdline
,
332 const char *initrd_filename
, const char *cpu_model
)
335 unsigned long bios_offset
;
338 struct gdium_s
*s
= qemu_mallocz(sizeof(*s
));
340 if (cpu_model
== NULL
)
342 cpu_model
= "Loongson-2F";
344 s
->env
= cpu_init(cpu_model
);
347 fprintf(stderr
, "Unable to find CPU definition\n");
350 /*set bit 5:7 of status registerto 1.
351 * Loongson 2f does not have 32bit address space and ux/sx/kx is not used in loongson
352 * But qemu needs this. So just set these bits to 1
354 s
->env
->CP0_Status
|= 0xe0;
356 register_savevm("cpu", 0, 3, cpu_save
, cpu_load
, s
->env
);
357 qemu_register_reset(main_cpu_reset
, s
->env
);
360 if (ram_size
> (GDIUM_SDRAM_SIZE
))
363 "qemu: Too much memory for this machine: %d MB, maximum 512 MB\n",
364 ((unsigned int) ram_size
/ (1 << 20)));
367 cpu_register_physical_memory(0, ram_size
, IO_MEM_RAM
);
369 bios_offset
= ram_size
+ vga_ram_size
;
370 cpu_register_physical_memory(0x1fc00000LL
, BIOS_SIZE
,
371 bios_offset
| IO_MEM_ROM
);
373 /*sst39vf040 flash */
374 index
= drive_get_index(IF_PFLASH
, 0, 0);
378 "A flash image must be given with the " "'pflash' parameter\n");
382 debug_out(DEBUG_BOARD_INIT
, ("Register sst39vf040 size %x at "
383 "offset %08lx addr %08llx '%s' %x\n",
384 BIOS_SIZE
, bios_offset
, 0x1fc00000LL
,
385 bdrv_get_device_name(drives_table
[index
].bdrv
),
386 (BIOS_SIZE
>> BIOS_SECTOR_BITS
)));
387 pflash_cfi02_register(0x1fc00000LL
, bios_offset
, drives_table
[index
].bdrv
,
388 (1 << BIOS_SECTOR_BITS
),
389 BIOS_SIZE
>> BIOS_SECTOR_BITS
, 1, 1, 0xbf, 0xd7,
390 0x0000, 0x0000, 0x555, 0xaaa);
392 cpu_mips_irq_init_cpu(s
->env
);
393 cpu_mips_clock_init(s
->env
);
395 s
->pci_bus
= bonito_init(s
->env
);
396 s
->sm502
= sm502_init(s
->pci_bus
, SM502_DEV_NO
<< 3, 0x10000000);
397 loongson_ddr2_init();
398 loongson_addwin_init();
400 s
->emu_i2c
= qemu_mallocz(sizeof(*s
->emu_i2c
));
401 s
->emu_i2c
->emu_i2c_bus
= i2c_init_bus();
403 eeprom_buf
= qemu_mallocz(8 * 256); /* XXX: make this persistent */
404 memcpy(eeprom_buf
, gdium_spd
, sizeof(gdium_spd
));
405 smbus_eeprom_device_init(s
->emu_i2c
->emu_i2c_bus
, 0xa2, eeprom_buf
);
408 m41t80_init(s
->emu_i2c
->emu_i2c_bus
, NULL
, 0xd0);
409 /*temperature sensors */
410 stds75_init(s
->emu_i2c
->emu_i2c_bus
, NULL
, 0x90);
412 mips_gdium_i2c_emu(s
);
416 QEMUMachine mips_gdium_machine
= {
418 .desc
= "MIPS Gdium notebook",
419 .init
= mips_gdium_init
,
420 .ram_require
= VGA_RAM_SIZE
+ BIOS_SIZE
,